object:PivotTo(Crame.new(result.Position + result.Normal) causes object to hover

I just thought of a way to do the slant. If you performed your vertical raycast, then cast another ray that’s basically the same as the first one but oriented to the rotation of the part that the first raycast hit. So basically you cast a vertical ray and it hits the baseplate, then it performs another one based on the surface of the baseplate the first raycast hit to determine the slant of the said placed object. Maybe I’m rambling on about something pointless because I haven’t tested this so sorry if this is wrong. I also might be saying something pointless if raycasts automatically do this.

2 Likes

You can use:

object.CFrame = object.CFrame:ToWorldSpace(CFrame.new(0,0.5,0))

Or however much the object needs to be lifted off from the ground.
Use PivotTo() for models, I can provide code for that if needed.

2 Likes

thank you for that, we know how do this part. But the object still will not slant with the ground if it is placed on a hill.

Alright, I will try finding a solution. I will get on Roblox Studio in a moment.

2 Likes

thanks ! let us know if you get it working. we are still researching, but the API is incomplete, no one on youtube seems to be teaching this (as obvious as it is) and the tutorials often don’t work or aren’t clear!

We really appreciate your help!

1 Like

EDIT: I misunderstood your problem, so this might have more than what you need.

I have found a solution to both of your issues. So I will combine them into one. For the issue with the floating, use:

object.CFrame = object.CFrame:ToWorldSpace(CFrame.new(0, x, 0)

or for a model, use

model:PivotTo(model.WorldPivot:ToWorldSpace(CFrame.new(0, x, 0)))

change x to however high you need. These also might need to be tweaked based on how the object is rotated.

For the issue with the raycasting, and putting it where the raycast hits and rotating it right, do this:

object.CFrame = CFrame.new(ray.Position, ray.Position + ray.Normal)

and for models, use

model:PivotTo(CFrame.new(ray.Position, ray.Position + ray.Normal)

I would like to credit the post made by @ExcessEnergy which helped me with this.

Sorry if I did this wrong, I am pretty new to using the devforum.

1 Like

I think a better approach would be to edit the pivot point to the bottom so you can remove the + result.Normal.

1 Like

I know this solution is all over. I’m actually using it in my example above. but it doesn’t work accurately.

have you tried it, as requested?>

1 Like

My apologies for misunderstanding, I very well have tried all of the code I had provided in my previous post and it worked fine. So how exactly is the problem occurring when you use CFrame:ToWorldSpace()? With the code used, what is currently happening to the object?

1 Like

cool, thanks for explaining.

I’ll have to get you screenshots. Might not be ablet to get it til tomorrow or friday.

Thanks !

so when I do it on a slant this happens:

facing downhill, this:

this one is .almost. right, but not:

this one is .almost. right on flat ground, except “look at” rotates the front to face the ground.

the full code I’m using (also edited to first post above.)


local tool = script.Parent
local storage = game.ReplicatedStorage
local u = require(game.Workspace.Utility)
local playerService = game:GetService("Players")
tool.Activated:Connect(function()
    local char: Model = script.Parent.Parent
	local player = playerService:GetPlayerFromCharacter(char)

--untoggle	local teamTag = char:FindFirstChild("TeamTag")
    --local char = script.Parent.Parent

    local deployment = storage:WaitForChild("DeployableModels"):WaitForChild("Spikes"):Clone()
	local head = char:FindFirstChild("Head")
	local origin = (head.Position + (head.CFrame.LookVector.Unit * 5))
	--local origin = char.PrimaryPart.Position
	local direction = Vector3.new(0, -250, 0)
    
	local params = RaycastParams.new()
	params.FilterType = Enum.RaycastFilterType.Exclude
	params.FilterDescendantsInstances = {char}
	params.IgnoreWater = true

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

		local rootPart = char:WaitForChild("HumanoidRootPart")
		--
--untoggle	player:WaitForChild("DeployableUsed").Value = true
  
		deployment:PivotTo(CFrame.new(result.Position, result.Position + result.Normal))

		deployment.Orientation = Vector3.new((deployment.Orientation.X), char:FindFirstChild("HumanoidRootPart").Orientation.Y , deployment.Orientation.Z)

		
		deployment.Anchored = true

        deployment.Parent = workspace
 		--untoggle u.InsertTag(deployment, "TeamTag", teamTag.Value)
		task.wait(1)
		--tool:Destroy()
		task.wait(15)
		deployment:Destroy()

	end
end)

thanks!

do you have any screenshots of that code working?

this guy was using the same code you provide, and also gets wonky angles instead of the proper result:

just curious if you can show me an example of this working, and then maybe I can apply your workaround

hm. wait…findpartonray is deprecated…isnt it?

1 Like

Yes that’s why I tweaked it a little. Here’s an example of it in action:


Image above is before. The small 1x1x1 stud part represents the ray’s origin. It is facing towards the little red part. The little red part’s CFrame is set to the slant. The slanted part is what intercepts the ray.

Image above is after. (Don’t mind the lighting changes)

Image above is after in detail.

This is the direct code it executes to complete this.


local params = RaycastParams.new()
params.CollisionGroup = "Default"
params.FilterDescendantsInstances = {script.Parent}
params.FilterType = Enum.RaycastFilterType.Include

local ray = workspace:Raycast(script.Parent.Party.Position, script.Parent.Party.CFrame.LookVector * 100, params)

script.Parent.Part.CFrame = CFrame.new(ray.Position, ray.Position + ray.Normal)

The issue with yours is probably how the model/object is composed. Its front needs to represent the front or it will not rotate correctly. And also, with models like these, it is very recommended to set a primary part if one is not already set.

1 Like

After an hour of restless coding, I finally figured out something that half works. I modified your script and had to remove some things so it didn’t error, so you might have to add some stuff back in. Basically, GoPart is just the direction of the ray but I stink at raycasting directions so I did that to be more accurate. I recommend you add that to the tool. It’s the same CFrame as the handle but tilted to the ray’s direction.

This works for the most part it just sometimes will randomly turn left or right 90 degrees so uh… I might be able to fix that later or you can code some sort of way to make sure that doesn’t happen.

local tool = script.Parent
local storage = game.ReplicatedStorage
local playerService = game:GetService("Players")
tool.Activated:Connect(function()
	local char: Model = script.Parent.Parent
	local player = playerService:GetPlayerFromCharacter(char)

	--untoggle	local teamTag = char:FindFirstChild("TeamTag")
	--local char = script.Parent.Parent

	local deployment = storage:WaitForChild("LolPart"):Clone()
	local head = char:FindFirstChild("Head")
	local origin = (head.Position)
	--local origin = char.PrimaryPart.Position
	local direction = script.Parent.GoPart.CFrame.LookVector * 100

	local params = RaycastParams.new()
	params.FilterType = Enum.RaycastFilterType.Exclude
	params.FilterDescendantsInstances = {char}
	params.IgnoreWater = true

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

		local rootPart = char:WaitForChild("HumanoidRootPart")
		--
		--untoggle	player:WaitForChild("DeployableUsed").Value = true
		deployment:PivotTo(CFrame.new(result.Position, result.Position + result.Normal):ToWorldSpace(CFrame.new(0, 0, -deployment.Size.Z / 2)) * CFrame.Angles(math.rad(-90), math.rad(-90), 0))
		local x,y,z = script.Parent.Handle.CFrame:ToEulerAnglesXYZ()
		deployment.CFrame = deployment.CFrame * CFrame.Angles(0,y,0)
		deployment.Anchored = true

		deployment.Parent = workspace
		deployment.CanCollide = false
		deployment.CanQuery = false
		--untoggle u.InsertTag(deployment, "TeamTag", teamTag.Value)
		task.wait(1)
		--tool:Destroy()
		task.wait(15)
		--deployment:Destroy()

	end
end)
1 Like

Yoyoyoyo! This works. It does make the item hover off the ground a tiny bit, but we are jiggerin with it. We are looking at the new parts in the script, cause I want to learn how this works.

I’ll have a couple questions, hopefully you can answer them!

Thanks bro !

1 Like

Hey LG, any chance you could help us understand this a little better, as we want to use it on objects that are welded together, and other applications, too. But even after researching it (everywhere, api, youtube, forum, and of course tinkering with it ourselves) we can’t figure it out.

Especially these lines:

deployment:PivotTo(CFrame.new(result.Position, result.Position + result.Normal):ToWorldSpace(CFrame.new(0, 0, -deployment.Size.Z / 2)) * CFrame.Angles(math.rad(-90), math.rad(-90), 0))
		local x,y,z = script.Parent.Handle.CFrame:ToEulerAnglesXYZ()
		deployment.CFrame = deployment.CFrame * CFrame.Angles(0,y,0)

we understand the “pivot to” line, but what does ToWorldSpace do? especially in this application? I watched videos, and some of the videos said one thing, some other videos said the OPPOSITE… classic - the api doesn’t explain it.

Likewise, what’s “toeulerangles” do? Does it force the object to move on the world axis, as opposed to the objects local axis?

thanks much for any help. !

Certainly! Beginning of every Roblox Assistant response

ToWorldSpace basically just takes the object’s CFrame and moves it in studs based on that CFrame. (Why it’s called ToWorldSpace? Not sure, but it has to do with the complicated explanation of it) So basically, if I have a part that is facing forward and a part tilted awkwardly in every axis, and call :ToWorldSpace(CFrame.new(2,0,0)), both will move in their axis to the left two studs.

ToEulerAngles just returns a tuple (multiple variables defined at once, like when using success, error on pcall()) of the CFrame’s angles, in degrees (by default, CFrame angles are in radians). It’s pretty much the same as ToOrientation().

1 Like

Thank you for the help. Very useful - best !

1 Like

Hey we noticed something. If we want to put the deployable on something that has a Y rotation, it doesn’t work. How do I take the result.Instances Y rotation into account, so that the spike strip still is at 90 degrees to the character?

1 Like

I think we solved the problem of placing it on an object that has previously been rotated on the Y axis:

			local x,radHandleY,z = rootPart.CFrame:ToOrientation()
			local degHandleY = math.deg(radHandleY)
			local degBaseY = result.Instance.Orientation.Y --in degrees

			local degAdjustY = degHandleY - degBaseY
		if result.Instance.Orientation.Y ~= 0 and result.Instance.Orientation.Y ~= 180 and result.Instance.Orientation.Y ~= -180 then

			deployment:PivotTo(CFrame.new(result.Position, result.Position + result.Normal):ToWorldSpace(CFrame.new(0, 0,  -deployment.Size.Y/2)) * CFrame.Angles(math.rad(-90), math.rad(degAdjustY), 0))

		else
			deployment:PivotTo(CFrame.new(result.Position, result.Position + result.Normal):ToWorldSpace(CFrame.new(0, 0,  -deployment.Size.Y/2)) * CFrame.Angles(math.rad(-90), math.rad(-90), 0))
			deployment.CFrame = deployment.CFrame * CFrame.Angles(0,radHandleY,0)

		end

We don’t really know .why. it works like this. But we jiggered with it til it did.

1 Like