Rotating block on grid building system breaks stuff

So im trying to make a basic game where you can build freely, but when you rotate a block, the placement calculation code breaks entirely. Please help. urgently as possible.


(The error occured when i made the next cube, and rotated it 90 degrees to the left, this breaks for all directions too. it’s odd.)
Heres a recording, the blocks are 3 by 3 on studs. When i rotate it any direction. it messes up , and the block clips into itself, how do i fix this?

Code:

local Mouse = game.Players.LocalPlayer:GetMouse()
local CF
local Orientation  = script:FindFirstChildOfClass("Vector3Value")
local Position
local PreviewCF = CFrame.new()
local Limit = 25
local part
local X
local Y
local Z
local cooldown = false
local TS = game:GetService("TweenService")

local SurfaceVectors = {
	Top = Vector3.new(0, 1, 0),
	Bottom = Vector3.new(0, -1, 0),
	Left = Vector3.new(-1, 0, 0),
	Right = Vector3.new(1, 0, 0),
	Front = Vector3.new(0, 0, -1),
	Back = Vector3.new(0, 0, 1),
}
local GridSize = 3

local UIS = game:GetService("UserInputService")

UIS.InputBegan:Connect(function(input,gp)
	if gp then return end
	if input.KeyCode == Enum.KeyCode.R then
		if Orientation.Value.Y == 360 then
			Orientation.Value = Orientation.Value + Vector3.new(0,-270,0)
		else
			Orientation.Value = Orientation.Value + Vector3.new(0,90,0)
		end
	end
end)

UIS.InputBegan:Connect(function(input,gp)
	if gp then return end
	if input.KeyCode == Enum.KeyCode.Y then
		if Orientation.Value.Z == -360 then
			Orientation.Value = Orientation.Value + Vector3.new(0,0,270)
		else
			Orientation.Value = Orientation.Value + Vector3.new(0,0, -90)
		end
	end

end)
UIS.InputBegan:Connect(function(input,gp)
	if gp then return end
	if input.KeyCode == Enum.KeyCode.T then
		if Orientation.Value.X == 360 then
			Orientation.Value = Orientation.Value + Vector3.new(-270,0,0)
		else
			Orientation.Value = Orientation.Value + Vector3.new(90,0,0)
		end
	end
end)


script.Parent.Activated:Connect(function()
	if cooldown == false then
		cooldown = true
	local distance = (Mouse.Hit.p - script.Parent.Parent.HumanoidRootPart.Position).Magnitude
	if distance < Limit then
		local Normal = Mouse.TargetSurface
		local hitblock = Mouse.Target
			script.Parent.place:FireServer(PreviewCF)
		end
		wait(.05)
		cooldown = false
	end
end)

game:GetService("RunService").RenderStepped:Connect(function()
	local surface = Mouse.TargetSurface.Name
	local surfaceVector = SurfaceVectors[surface]
	local adjustedX = Mouse.Hit.Position.X + surfaceVector.X
	local adjustedY = Mouse.Hit.Position.Y + surfaceVector.Y
	local adjustedZ = Mouse.Hit.Position.Z + surfaceVector.Z
	print(surface)
	local xPos = math.round(adjustedX / GridSize) * GridSize 
	local yPos = math.round(adjustedY/ GridSize) * GridSize
	local zPos = math.round(adjustedZ / GridSize) * GridSize
	PreviewCF = CFrame.new(Vector3.new(xPos,yPos,zPos))*CFrame.fromEulerAnglesXYZ(math.rad(Orientation.Value.X),math.rad(Orientation.Value.Y),math.rad(Orientation.Value.Z))

end)


script.Parent.Equipped:Connect(function()
	part = game.ReplicatedStorage.Block:Clone()
	part.Transparency = .5
	part.CanCollide = false
	part.Parent = game.Workspace.Camera
	Mouse.TargetFilter = part
	while wait() do
		if part ~= nil then
			part.BillboardGui.TextLabel.Text = "("..tostring(Orientation.Value)..")"
			TS:Create(part,TweenInfo.new(0.05,Enum.EasingStyle.Linear),{CFrame = PreviewCF}):Play()
		end
	end
end)
script.Parent.Unequipped:Connect(function()
	part:Destroy()
end)

orientation’s a part of cframe you might have a race condition where when you press the rotate button it draws from the old position instead

2 Likes

could you elaborate? i dont quite understand

when you press the button to rotate the block it pulls from the old position instead of the new one

wait nevermind print out xpos ypos and zpos each time it might just change the cframe slightly enough that math.round returns a smaller value than before

1 Like


Figured this might be the problem… the surface face system doesnt work right,

local SurfaceVectors = {
	Top = Vector3.new(0, 1, 0),
	Bottom = Vector3.new(0, -1, 0),
	Left = Vector3.new(-1, 0, 0),
	Right = Vector3.new(1, 0, 0),
	Front = Vector3.new(0, 0, -1),
	Back = Vector3.new(0, 0, 1),
}


game:GetService("RunService").RenderStepped:Connect(function()
	local surface = Mouse.TargetSurface.Name
	local surfaceVector = SurfaceVectors[surface]
	local adjustedX = Mouse.Hit.Position.X + surfaceVector.X
	local adjustedY = Mouse.Hit.Position.Y + surfaceVector.Y
	local adjustedZ = Mouse.Hit.Position.Z + surfaceVector.Z
	print(surface)
	local xPos = math.round(adjustedX / GridSize) * GridSize 
	local yPos = math.round(adjustedY/ GridSize) * GridSize
	local zPos = math.round(adjustedZ / GridSize) * GridSize
	PreviewCF = CFrame.new(Vector3.new(xPos,yPos,zPos))*CFrame.fromEulerAnglesXYZ(math.rad(Orientation.Value.X),math.rad(Orientation.Value.Y),math.rad(Orientation.Value.Z))

end)

IF there was a way to make work on all directions ,thatd be nice, acause it only works on one axis currently

you’ll have to convert the position to object space then convert it back into world space

1 Like

how do i do so, i remember messing with object space and world space and i got very frustrated

originCFrame:ToWorldSpace(originCFrame:ToObjectSpace(originCFrame) + Offset);

something like this I’m really tired right now but essentially you add the offset to the originCF’s object space then convert it back to world space using origin CFrame, if you just add it to the world space it won’t work when rotated because it doesn’t face the same way

1 Like

im still so confused sorry, just write the code or something

local m_hit_x = Mouse.Hit.Position.X;
local m_hit_y = Mouse.Hit.Position.Y;
local m_hit_z = Mouse.Hit.Position.Z;

local cf_position = CFrame.new(Vector3.new(m_hit_X,m_hit_Y,m_hit_Z));
local cf_to_object_space = cf_position:ToObjectSpace(cf_position) + surfaceVector;
local offset = cf_position:ToWorldSpace(cf_to_object_space);

--// change xPos, yPos, zPos to use offset.X, offset.Y, offhit.Z 

PreviewCF = CFrame.new(Vector3.new(xPos,yPos,zPos))*CFrame.fromEulerAnglesXYZ(math.rad(Orientation.Value.X),math.rad(Orientation.Value.Y),math.rad(Orientation.Value.Z))

1 Like


Tried putting that in, unfortunately didnt work, any possible code fixes? sorry for the late respond time, I was out sick.

P.S thank you for helping me

	local surface = Mouse.TargetSurface.Name
	local surfaceVector = SurfaceVectors[surface]


	local m_hit_x = Mouse.Hit.Position.X;
	local m_hit_y = Mouse.Hit.Position.Y;
	local m_hit_z = Mouse.Hit.Position.Z;
	local adjustedZ = Mouse.Hit.Position.Z + surfaceVector.Z

	local cf_position = CFrame.new(Vector3.new(m_hit_x,m_hit_y,m_hit_z));
	local cf_to_object_space = cf_position:ToObjectSpace(cf_position + surfaceVector);

	local offset = cf_position:ToWorldSpace(cf_to_object_space);
	local xPos = math.round(offset.X / GridSize) * GridSize 
	local yPos = math.round(offset.Y / GridSize) * GridSize
	local zPos = math.round(offset.Z / GridSize) * GridSize
	--// change xPos, yPos, zPos to use offset.X, offset.Y, offhit.Z 

	PreviewCF = CFrame.new(Vector3.new(xPos,yPos,zPos))*CFrame.fromEulerAnglesXYZ(math.rad(Orientation.Value.X),math.rad(Orientation.Value.Y),math.rad(Orientation.Value.Z))

The issue is likely due to how you’re using Mouse.TargetSurface.Name. When a block is rotated, the surface on its (side) is no longer the one which would be there if it was not rotated. This makes your surfaceVector wrong and thus your block is offseted incorrectly. You should instead try finding the unrotated surface name of the block (as in, what surface you would have hit if the target was not rotated).

any idea on how i would rotate the vector, accordingly to the blocks orientation?

Not really

You could just simulate it ig

like you see theres 3 rotations on X and 2 on Y, for the ones on X you change the value of (surface1) to that of (surface2) and (surface2) to (surface3) and so on for 3 times, and then the one for Y, in which you might instead be doing it for like (surface1) to (surface5) because rotating on Y axis would have different surfaces that are considered “next to” (surface1) than on the X axis.