You can write your topic however you want, but you need to answer these questions:
What do you want to achieve? Keep it simple and clear!
a 5x5 grid building system
What is the issue? Include screenshots / videos if possible!
when I place blocks aiming my mouse at another block instead of putting the block next to that side of the other block it places it randomly
What solutions have you tried so far? Did you look for solutions on the Developer Hub?
After that, you should include more details if you have any. Try to make your topic as descriptive as possible, so that it’s easier for people to help you!
I know it’s because of the offset system in case there’s another block where i’m trying to click but it should just place it next to that side instead of registering as trying to put it in the same place, and I also can’t think of something that could fix it.
server script:
local Tool = script.Parent
local RESET_SECONDS = 0.05
local debounce = false
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local camera = workspace.CurrentCamera
function MouseRaycast()
local mousePosition = UserInputService:GetMouseLocation()
local mouseray = camera:ViewportPointToRay(mousePosition.X,mousePosition.Y)
local raycastresult = workspace:Raycast(mouseray.Origin,mouseray.Direction * 2000)
return raycastresult
end
local position = nil
local placeevent = script:WaitForChild("RemoteEvent")
RunService.RenderStepped:connect(function()
local result = MouseRaycast()
if result and result.Position then
position = result.Position
end
end)
Tool.Activated:connect(function()
local Players = game:GetService("Players")
if not debounce and position then
debounce = true
script.Parent.Handle.Call:Play()
placeevent:FireServer(position)
if script.Parent.Left.Value == 0 then
script.Del:FireServer()
end
script.Parent.Left.Value-=1
script.Parent.ToolTip = script.Parent.Left.Value .. " sand blocks"
--You can also use Math.Random() to calculate your spawns to a random set of values for the Vector3.new() Values
wait(RESET_SECONDS)
debounce = false
end
end)
place event:
local occupiedPositions = {}
script.Parent.OnServerEvent:Connect(function(plr, position)
local function round(num)
local divided = num / 5
local rounded = 5 * math.floor(divided)
return rounded
end
local blockSize = Vector3.new(5, 5, 5) -- Adjust according to your block size
local roundedPosition = Vector3.new(round(position.X), round(position.Y), round(position.Z))
-- Check if the rounded position is occupied
while occupiedPositions[roundedPosition] do
roundedPosition = roundedPosition + (Vector3.new(math.random(-1,1),1,math.random(-1,1))*5) -- Adjust the position
end
-- Mark the position as occupied
occupiedPositions[roundedPosition] = true
local noob1 = game.ServerStorage.Blocks.SandBlock:Clone() -- Cloning
noob1.Parent = workspace -- Parent
noob1.Position = roundedPosition
end)
It’s hard to explain but I hope it’s understandable
Try changing the code so that instead of placing it at where the raycast hits, it places it at the position of the block it hits with a given offset based on the normal of the face which it hits. I found this to work well when making a building system for an old project.
Here is what the code may look like:
local Position = RayCast.Instance.Position
local GridSize = 5
local Normal = RayCast.Normal
local Offset = Vector3.new(Normal.X*GridSize, Normal.Y*GridSize, Normal.Z*GridSize)
local NewPosition = Position + Offset
You would have to use an if statement to check for RayCast.Instance and to check that it is a BasePart as it can also return Terrain.
The normal is the surface which the raycast hits. For example the top surface would have a normal id of (0, 1, 0) to represent that face of the object. On cubes/cuboids, there are 6 possible normals for each of the faces; however, on meshes, there are often more as it may have more faces at different angles compared to a simple cube.
wait hold on, it doesn’t work, i’m trying to use the normal but it’s erroring and I don’t know why
local script:
local Tool = script.Parent
local RESET_SECONDS = 0.05
local debounce = false
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local camera = workspace.CurrentCamera
function MouseRaycast()
local mousePosition = UserInputService:GetMouseLocation()
local mouseray = camera:ViewportPointToRay(mousePosition.X,mousePosition.Y)
local raycastresult = workspace:Raycast(mouseray.Origin,mouseray.Direction * 2000)
local norm = raycastresult.Normal
return raycastresult, norm
end
local position = nil
local normie = nil
local placeevent = script:WaitForChild("RemoteEvent")
RunService.RenderStepped:connect(function()
local result = MouseRaycast()
if result and result.Position then
position = result.Position
local normie = result.Normal
end
end)
Tool.Activated:connect(function()
local Players = game:GetService("Players")
if not debounce and position then
debounce = true
script.Parent.Handle.Call:Play()
placeevent:FireServer(position, normie)
if script.Parent.Left.Value == 0 then
script.Del:FireServer()
end
script.Parent.Left.Value-=1
script.Parent.ToolTip = script.Parent.Left.Value .. " sand blocks"
--You can also use Math.Random() to calculate your spawns to a random set of values for the Vector3.new() Values
wait(RESET_SECONDS)
debounce = false
end
end)
place event:
local occupiedPositions = {}
script.Parent.OnServerEvent:Connect(function(plr,position,normal)
local function round(num)
local divided = num / 5
local rounded = 5 * math.floor(divided)
return rounded
end
local blockSize = Vector3.new(5, 5, 5) -- Adjust according to your block size
local roundedPosition = Vector3.new(round(position.X), round(position.Y), round(position.Z))
-- Check if the rounded position is occupied
while occupiedPositions[roundedPosition] do
roundedPosition = roundedPosition + normal
end
-- Mark the position as occupied
occupiedPositions[roundedPosition] = true
local noob1 = game.ServerStorage.Blocks.SandBlock:Clone() -- Cloning
noob1.Parent = workspace -- Parent
noob1.Position = roundedPosition
end)
I changed them a bit and it doesn’t work as intended
You would need to multiply the x, y and z values by the block size as this will change the normal; for example, from (0, 1, 0) to (0, 5, 0) as this would change the offset to fit in the grid.