Placement System For Wall Objects

Seriouly, how can i make something like this possible?

Wall Objects placement system

Credits to MeepCity

I have already succeed making a placement system good enough for floor objects, although im stuck here now.

16 Likes

We can’t definitively figure out how MeepCity does this, but I would guess he’s using the surface normal argument provided by Workspace’s raycasting functions to rotate the resulting CFrame

^ It is really simple if you know what a surface normal is and how to raycast. There is an example on the wiki of making a crate placement system with cross product or you can just rotate it afterward or use CFrame.new(pos,pos+norm) or whatever

4 Likes

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.