Using Raycasting to correctly orient a part

I’m currently trying to make a sort of C4 that you can place anywhere just by clicking. I’ve already got most of it completed, but my issue now is rotating the C4 to match the object it is placed on.

This is what it looks like now;

And this is the result I’m looking for

Okay, I have some questions:

  • What is your code?
  • Are you using Mouse.Hit?
  • Does the C4 orient this way on all objects?

If so, you can just multiply the CFrame:

--append
* CFrame.Angles(math.pi/2, math.pi, math.pi/2)
1 Like

This works. Or better yet, rotate the Pivot Offset of the Model so you don’t have to correct it in code.

Going to assume one of the main issues you’re having is this:


(Where the circle is the front face)

For aligning these types of things depending on what surface you’re putting it on, you might want to do a raycast and grab the surface normal. Then getting the cross vector of the surface normal and the position it hits (or designate a relative front vector), this will give you the remaining piece for CFrame.fromMatrix (It’s the right vector) which is the core of this.

Might want to check this out.

Code base

Undesignated front vector:

local result = workspace:Raycast(origin, direction, params)

-- // Just assuming there will be a hit for demonstration
local right_vector = result.Position.Unit:Cross(result.Normal)
local cframe = CFrame.fromMatrix(result.Position, right_vector, result.Normal)

-- // you can add trivial orientation manipulation like
-- //  cframe * CFrame.Angles(math.pi * .5, 0, 0)

The result: https://gyazo.com/7430f5b078aeee72c1d820b7effe1b48.mp4

Setting the relative front vector:

local result = workspace:Raycast(origin, direction, params)

local set_front_vector = Vector3.new(0, 1, 0) -- // This will make it so it will always look up in a way
local right_vector = set_front_vector:Cross(result.Normal)
local cframe = CFrame.fromMatrix(result.Position, right_vector, result.Normal)

-- // And you can apply your rotations here and or add half the thickness of your object
-- // cframe * CFrame.Angles(math.pi * .5, 0, 0) * CFrame.new(0, part.Size.Y * .5, 0)

The result: https://gyazo.com/9c5d061a60b79813c094f6a5091a4b9b.mp4

Main issue with setting the front vector like this is that if you try to put an object on a surface where the surface normal is parallel to the provided front vector, the returned value from :Cross() will be Vector3.zero so you would need to check if the two normals are parallel with :Dot() or whatever method you see fit.

Hope this helps.

17 Likes

I am using mouse.hit, to both preview where the C4 will be placed and to place it.

A local script inside the tool handles the preview, and finding the mouse position;

local replicatedStorage = game:GetService("ReplicatedStorage")
local runService = game:GetService("RunService")

local player = game:GetService("Players").LocalPlayer

local tool = script.Parent
local lookPart = tool:WaitForChild("lookPart")
local rootPartPosition
local mousePos


-- The block of code below handles the preview
runService.Heartbeat:Connect(function()
	if tool.Parent == player.Character then
		rootPartPosition = player.Character.HumanoidRootPart.CFrame.Position
		mousePos = game.Players.LocalPlayer:GetMouse().Hit.Position
		if math.abs(mousePos.X - rootPartPosition.X) <= 10 and math.abs(mousePos.Y - rootPartPosition.Y) <= 10 and math.abs(mousePos.Z - rootPartPosition.Z) <= 10 then	
			lookPart.Color = Color3.new(0,100,0)
		else
			lookPart.Color = Color3.new(100,0,0)
		end
		lookPart	.Position = mousePos
	end
end)
tool.Equipped:Connect(function()
	lookPart.Transparency = 0.5
end)


--[[This sends the server the correct position to place the c4,
 if the mouse is close enough to the player when clicked]]
tool.Activated:Connect(function()
	rootPartPosition = player.Character.HumanoidRootPart.CFrame.Position
	mousePos = game.Players.LocalPlayer:GetMouse().Hit.Position
	if math.abs(mousePos.X - rootPartPosition.X) <= 10 and math.abs(mousePos.Y - rootPartPosition.Y) <= 10 and math.abs(mousePos.Z - rootPartPosition.Z) <= 10 then
		lookPart.Transparency = 1
		replicatedStorage.Place:FireServer(mousePos, tool)
	else return end
end)

And in server script service, a script that places the C4;

local Place = game:GetService("ReplicatedStorage").Place
local runService = game:GetService("RunService")


--(The handle is the actual C4 model)
Place.OnServerEvent:Connect(function(plr, mousepos, tool)
	tool.Parent = workspace
	tool.Handle.Anchored = true
	tool.Handle.CFrame = CFrame.new(mousepos) * CFrame.Angles(0, 0, 0)
	while tool.Parent == workspace do
		runService.Heartbeat:Wait()
	end
	tool.Handle.Anchored = false
end)

And yes, the orientation of the C4 illustrated in the video stays the same no matter where I place it. That’s what I’m trying to fix.

You can replace this condition with (mousePos - rootPartPosition).Magnitude <= 10

First of all, you want to make it not .Hit.Position, but just .Hit. Then, you change the CFrame of the lookPart instead of the position to the variable.

Then, if the C4 is still rotated, you should do what @ThanksRoBama said and edit the pivot offset. You could alternatively adjust the CFrame in the script using CFrame.Angles

could you explain why you used Position.Unit in the first example?

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.