I am attempting to create a voxel / block type game where you can place and remove blocks. Currently a block is 3x3x3 studs. The “grid” to place blocks would be 3 studs since the blocks are 3x3x3.
Think minecraft (not copying it). How would I make it so I can place blocks like that?
I’ve managed to make it possible to place blocks wherever the mouse is pointing, but of course this isn’t what I really want.
mouse.Hit.Position gives a position with decimals and stuff. Not rounded at all. So you will need to round it. Now there is no default rounding function, but we do have math.floor() and we can use that to make a custom rounding function. math.floor(x) always rounds down, that doesn’t seem very usefull does it? math.floor(4.6) --> 4 But what if you add 0.5 to it? All of a sudden you get a rounding functions! math.floor(4.6+0.5) --> 5math.floor(4.2+0.5) --> 4.
This only rounds down to 1 tho, not exactly what you want. But why not just devide the number by 3, round that, and then multiply it by 3 again. Now you have something which can round numbers to the nearest 3. math.floor(x/3)*3 Fill in any number for x and you will get the rounded version back.
Add in vectors and stuff and you get this function:
local function round(vector,grid)
return vector3.new(
math.floor(vector.X/grid+.5)*grid,
math.floor(vector.Y/grid+.5)*grid,
math.floor(vector.Z/grid+.5)*grid
)
end
round(mouse.Hit.Position,3)
i’ve made something similar,try you cursor.Target.Position
script.Parent.Activated:connect(function()
if a == 1 and val.Value > 0 then
for i = 1,#blocks do
if (blocks[i].Name == cursor.Target.Name) then
v = true
end
end
if ((v) and cursor.Target.ClassName == "Part" and (script.Parent.Handle.Position - cursor.hit.p).magnitude <= 15) then
val.Value = val.Value - 1
player.PlayerGui.ScreenGui.TextBox.Text = val.Value
a = 0
if cursor.Target.Position.X + 1.5 == cursor.Hit.X then
X = math.ceil(cursor.Hit.X) -(math.ceil(cursor.Hit.X) % 3) + 3
else
X = math.ceil(cursor.Hit.X) -(math.ceil(cursor.Hit.X) % 3)
end
if ((cursor.Hit.Y%0.5) == 0) then
if cursor.Target.Position.Y + 1.5 == cursor.Hit.Y then
Y = math.ceil(cursor.Hit.Y) - (math.ceil(cursor.Hit.Y) % 3) + 3
else
Y = math.ceil(cursor.Hit.Y) - (math.ceil(cursor.Hit.Y) % 3)
end
else
Y = math.ceil(cursor.Hit.Y) - (math.ceil(cursor.Hit.Y) % 3)
end
if cursor.Target.Position.Z + 1.5 == cursor.Hit.Z then
Z = math.ceil(cursor.Hit.Z) -(math.ceil(cursor.Hit.Z) % 3) + 3
else
Z = math.ceil(cursor.Hit.Z) -(math.ceil(cursor.Hit.Z) % 3)
end
requestPartEvent:FireServer(X,Y,Z,"lucky")
a = 1
end
end
end)
script.Parent.Activated:connect(function()
if (game.ReplicatedStorage.block.Handle- cursor.hit.p).magnitude <= 15) then
if cursor.Target.Position.X + 1.5 == cursor.Hit.X then
X = math.ceil(cursor.Hit.X) -(math.ceil(cursor.Hit.X) % 3) + 3
else
X = math.ceil(cursor.Hit.X) -(math.ceil(cursor.Hit.X) % 3)
end
if ((cursor.Hit.Y%0.5) == 0) then
if cursor.Target.Position.Y + 1.5 == cursor.Hit.Y then
Y = math.ceil(cursor.Hit.Y) - (math.ceil(cursor.Hit.Y) % 3) + 3
else
Y = math.ceil(cursor.Hit.Y) - (math.ceil(cursor.Hit.Y) % 3)
end
else
Y = math.ceil(cursor.Hit.Y) - (math.ceil(cursor.Hit.Y) % 3)
end
if cursor.Target.Position.Z + 1.5 == cursor.Hit.Z then
Z = math.ceil(cursor.Hit.Z) -(math.ceil(cursor.Hit.Z) % 3) + 3
else
Z = math.ceil(cursor.Hit.Z) -(math.ceil(cursor.Hit.Z) % 3)
end
end
end
end)
this might be wrong,because its been awhile since i did something like this
Just a quick fix, you have to distribute X, Y, and Z coordinates for each component of the new Vector3:
local function round(vector,grid)
return Vector3.new(
math.floor(vector.X/grid+.5)*grid,
math.floor(vector.Y/grid+.5)*grid,
math.floor(vector.Z/grid+.5)*grid
)
end
round(mouse.Hit.Position,3)
Try getting the normal from mouse.Hit using a ray and adding that to the original position:
-- services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
local player = Players.LocalPlayer
local block = ReplicatedStorage:WaitForChild("block")
-- how far you want the player to reach
local REACH = 100
local castParams = RaycastParams.new()
mouse.Button2Down:Connect(function()
local unitRay = mouse.UnitRay
castParams.FilterDescendantsInstances = { player.Character }
-- automatically ignores the player's character
local result = Workspace:Raycast(
unitRay.Origin, unitRay.Direction * REACH,
castParams
)
if result then
local newBlock = block:Clone()
newBlock.Position = round(result.Position + result.Normal * 1.5, 3)
newBlock.Parent = Workspace
end
end)
This should be a local script, but if you want everyone to see the blocks you place, you should fire a remote to the server instead of creating the block client-side.
Sorry to stir upp this again but im working on a similiar problem and am interested.
So, the round() function. What is that? I searched up ‘round() roblox’ and the best result I got was a function returning math.floor(n + 0.5) where n is the number. But here we are passing n as a vector3??? That screws with my head. To add to that what is the second parameter for? To round it to multiples of 3? If so how would that function look?