Placement System For Wall Objects

https://gyazo.com/de7bb26e9f372bc9a6fad86c35a69f57

It only works on some angled objects and not on walls and stuff (90 degree angled objects)

Still not doing what i want as you see… :confused:

1 Like

Then just dont use cross product?? again the surface normal is a directional vector so you can just make it look toward it like my second statement.

Okay, here are some really really unexpected weird results…:

And here is the simplest code evr for this:

local mouse = game:GetService("Players").LocalPlayer:GetMouse();
local moveModel = game:GetService("Workspace"):WaitForChild("Wood Crate");
 
-- don't detect the model we're moving
mouse.TargetFilter = moveModel;
 
function placeAtMouse()
	-- make sure the mouse is pointing at something
	if mouse.Target then
		-- where we cast our ray from (shifted slightly up so the ray will hit the surface we're hovering)
		local origin = mouse.Hit.p + Vector3.new(0, 0.1, 0);
 
		-- cast our ray and get our normal, which is a unit vector
		local ray = Ray.new(origin, Vector3.new(0, -1, 0));
		local hit, pos, normal = game:GetService("Workspace"):FindPartOnRay(ray, moveModel);
		moveModel:SetPrimaryPartCFrame(CFrame.new(pos,pos+normal*15) * CFrame.Angles(-math.rad(90),0,0))
		print (moveModel:GetPrimaryPartCFrame().p)
	end;
end;
 
-- check every frame
game:GetService("RunService").RenderStepped:connect(function()
	placeAtMouse();
end);

Explain me the weird vector 3 printing when mouse is on the sides of the big part (say wall)
It seriously dissapears when pointing to ‘walls’

1 Like

Because the ray is not going toward any walls… why are you not shooting the ray in the direction of the mouse from the camera??? a ray straight down isnt supposed to hit vertical walls.

2 Likes

Oh well, i was just editing the script of egoo’s from his article and…have not noticed what kind of ray i was actually firing .-.

Hey, WE just figured it out my dear :slight_smile:

Code:

local mouse = game:GetService("Players").LocalPlayer:GetMouse();
local moveModel = game:GetService("Workspace"):WaitForChild("Wood Crate");
 
-- don't detect the model we're moving
mouse.TargetFilter = moveModel;
 
function placeAtMouse()
	-- make sure the mouse is pointing at something
	if mouse.Target then
		-- cast our ray and get our normal, which is a unit vector
		local unitRay  = workspace.CurrentCamera:ScreenPointToRay(mouse.X, mouse.Y, 1) --origin, Vector3.new(0, -1, 0));
		local ray = Ray.new(unitRay.Origin, unitRay.Direction * 1000)
		local hit, pos, normal = game:GetService("Workspace"):FindPartOnRay(ray, moveModel); print (normal)
		moveModel:SetPrimaryPartCFrame(CFrame.new(pos,pos+normal*15) * CFrame.Angles(-math.rad(90),0,0))
	end;
end;
 
-- check every frame
game:GetService("RunService").RenderStepped:connect(function()
	placeAtMouse();
end);
22 Likes

Huge thanks to you ! :heart:

This thread is actually really useful! Thank you soo much for posting the code you used! :slight_smile:

5 Likes

Sorry I’m late to the party! There is a little known Dragger service to allow the easy implementation of dragger systems. This is the service used by the RbxStamper library. Why write your own version when you could use a tried and tested service?

Unfortunately the Dragger class only supports a grid size of 1.

1 Like

A game I’m working on uses a similar placement system to the one in your video. I’ve adapted your code to use the same math as mine, hopefully it’s helpful. :slight_smile:

local mouse = game:GetService("Players").LocalPlayer:GetMouse();
local moveModel = game:GetService("Workspace"):WaitForChild("Wood Crate");
local player = game.Players.LocalPlayer
 
-- don't detect the model we're moving
mouse.TargetFilter = moveModel;

local rotation = 0 -- in radians
 
function placeAtMouse()
	-- make sure the mouse is pointing at something
	if mouse.Target then
		
		-- where we cast our ray from (shifted slightly up so the ray will hit the surface we're hovering)
		local origin = mouse.Hit.p + Vector3.new(0, 0.1, 0);
 		
		-- cast our ray and get our normal, which is a unit vector
		local unitRay  = workspace.CurrentCamera:ScreenPointToRay(mouse.X, mouse.Y, 1) --origin, Vector3.new(0, -1, 0));
		local ray = Ray.new(unitRay.Origin, unitRay.Direction * 1000)
		local hit, pos, normal = workspace:FindPartOnRay(ray, moveModel)
		
		--============================= New code I've added =============================--
		
		local front = normal
		local crossVector = (normal.Y > 0.8) and (pos-player.Character.HumanoidRootPart.Position).Unit or Vector3.new(0,1,0)
		
		local right = front:Cross(crossVector)
		local top = front:Cross(-right)
		local back = -front
		local cf = CFrame.new(pos.X, pos.Y, pos.Z, right.X, top.X, back.X, right.Y, top.Y, back.Y, right.Z, top.Z, back.Z)
		moveModel:SetPrimaryPartCFrame(cf * CFrame.Angles(0,0,rotation))
		
	end;
end;
 
-- check every frame
game:GetService("RunService").RenderStepped:connect(function()
	placeAtMouse();
end);

One difference is that I choose to rotate the object towards the player when placing an object on a horizontal surface, but this is easy to adjust.

Feel free to ask any questions

4 Likes

I am really grateful for your support guys on this problem but, as i already have said before, i actually managed to achieve my goal. Thanks to YOU!

5 Likes

To indicate your problem as solved, click the checkbox icon on the bottom of the post that solved it (near the like button) and the topic won’t attract new answers. It also recognizes their effort by marking it as the solution.

1 Like

I know you did this a really long time ago, but what I was just wondering(if you remember) what the use of multiplying by 15 was in the line :
moveModel:SetPrimaryPartCFrame(CFrame.new(pos,pos+normal*15) * CFrame.Angles(-math.rad(90),0,0))

It is actually not necessary, the code would work without it too

1 Like

Is the dragging UI button an SurfaceGui?

This is very late, but I got the code working, but how would I snap this to a grid. And also, show the entire model when placing instead of leaking half of it into the wall. This is confusing for me because you didn’t use Mouse.Hit anywhere inside the code.

I think the dragger UI button is a custom mouse icon when hitting the part.

Use math.clamp to snap to a grid
And use maybe region3 or raycast or both combined to detect when the model youre moving is touching a wall, stop movig it (so it wouldnt go inside the wall)

2 Likes

You can try with this (I didn’t tested it)

local position = CFrame.lookAt(position, position+normal) + (Model.PrimaryPart.Size * Normal / 2)

Adds the model size divided by 2 and multiplies it by the normal face (e.g. Vector3.new(-1, 0, 0), the script will only add the not 0 value)

1 Like