I am currently scripting a building system, but currently when I try to place a floor next to a wall it ends up looking like this:
Since I guess my mouse is hitting the part it will only get the position of the centre of the part. But since I am hovering on the edge of the part like in the first picture I’d like it to place at the side of the wall, like any normal building game. Here’s an example:
Thank you for reading this, if you have any efficient suggestions, please let me know!
Are you using raycasting to determine the position of the part? If so, RaycastResult has a property called Normal which is the vector pointing directly outward (i.e. “normal”) to the surface at the raycast position. You can add a multiple of this vector to the position to offset it from the wall.
I don’t believe so. That would only get the position, not the normal vector. You can use mouse.Hit, however, to construct the ray for the raycast.
Here’s an example of what that might look like. I don’t have a code editor on me right now, so there might be some minor errors.
local MAX_RAYCAST_DISTANCE = 1000 -- set this to the maximum raycast distance
local part = nil -- whatever part you want to move
if mouse.Target == nil then
return
end
local mousePosition = mouse.Hit
local cameraPosition = workspace.CurrentCamera.CFrame.Position
local direction = (mousePosition - cameraPosition).Unit
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Include
params.FilterDescendantsInstances = { mouse.Target }
local result = workspace:Raycast(mousePosition, direction * MAX_RAYCAST_DISTANCE, params)
if result ~= nil then
local partPosition = result.Position + result.Normal * part.Size.Z / 2
part.CFrame = CFrame.lookAt(partPosition, -normal)
end
This would be in a loop or connected to an update event, of course
Thanks so much, but for some reason RayCast isn’t a child of workspace? (even though it is in the documentation lol) workspace:RayCast() Error: RayCast is not a valid member of Workspace "Workspace"
No errors, but unfortunately it in most cases only pushes it more to the direction and is super laggy for some reason, but it may be an issue on my part. Could you check my script for errors please?
local mousePosition = mouse.Hit.Position
local cameraPosition = workspace.CurrentCamera.CFrame.Position
local direction = (mousePosition - cameraPosition).Unit
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Include
params.FilterDescendantsInstances = { mouse.Target }
local result = workspace:Raycast(mousePosition, direction * 1000, params)
local partPosition = nil
if result ~= nil then
partPosition = result.Position + result.Normal * Part.Size.Z / 2
PosX = math.floor(partPosition.X / Grid + 0.5) * Grid
PosY = math.floor(partPosition.Y / Grid + 0.5) * Grid
PosZ = math.floor(partPosition.Z / Grid + 0.5) * Grid
end
Snap()
if PosX ~= nil and PosY ~= nil and PosZ ~= nil then
if buildSelected.Value == 'Floor' then
Part.Position = (Vector3.new(PosX, PosY + Part.Size.Z/2, PosZ))
else
Part.Position = (Vector3.new(PosX, PosY + Part.Size.Y/2, PosZ))
end
end
Looks like I messed up the RaycastParams, it should have been Exclude, not Include. I was able to get this to work:
local MAX_RAYCAST_DISTANCE = 1000
local SNAP_WIDTH = 2
local part = nil -- whatever part you're moving
local mousePosition = mouse.Hit.Position
local cameraPosition = workspace.CurrentCamera.CFrame.Position
local direction = (mousePosition - cameraPosition).Unit
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = { part }
local result = workspace:Raycast(cameraPosition, direction * MAX_RAYCAST_DISTANCE, params)
if result ~= nil then
local rawPosition = result.Position + result.Normal * part.Size.Z / 2
local snappedPosition = Vector3.new(
math.round(rawPosition.X / SNAP_WIDTH) * SNAP_WIDTH,
math.round(rawPosition.Y / SNAP_WIDTH) * SNAP_WIDTH,
math.round(rawPosition.Z / SNAP_WIDTH) * SNAP_WIDTH
)
part.CFrame = CFrame.lookAt(snappedPosition, snappedPosition - result.Normal)
end