I have seen people doing that, and I have tried their solutions, but none of them work for me. Could you elaborate?
You can get the normal using Workspace:RayCast then get the RaycastResult.Normal. This is a vector that points upwards/away from the ground.
https://developer.roblox.com/en-us/articles/Raycasting
Then you can set the orientation of your skateboard with this. This depends on how your skateboard works. For example, if you use a BodyGyro you would change the goal CFrame based on the normal of the ground.
I am using a BodyVelocity for skateboard propulsion. Could you please provide a code example?
How do you keep the skateboard facing upwards currently?
What do you mean? I weld the character’s HRP to the skateboard.
Oh so is it not physics based? That makes it harder to move. I guess you can adjust the weld based on the normal, but it would be hard to rotate the character too.
The character doesn’t need to be rotated. I just need the skateboard to be parallel to the ground.
You can adjust the weld then. It would probably look weird though to have the player not standing on the skateboard.
Notice in this picture how the character is rotated so it is standing nicely on the board.
I don’t think you understand what it is I’m trying to do. The weld works perfectly, I just need the skateboard oriented properly on the y-axis so it aligns with the ground. I have looked at multiple other posts on the dev forum which explain how to orient a part based on the ground normal, but none of them work for the board.
So, I believe your Humanoid is in PlatformStand, which basically makes the HumanoidRootPart always face upwards, like the character is standing, but not be affected by the charactercontroller’s physics in other ways.
This means your character can’t rotate. Your board is welded to the character, so it can’t rotate too.
To rotate the stuff, you’ll basically need to change how the constraints (welds, motor6s, etc) connect to the HumanoidRootPart, which is the part that can’t rotate b|c of the humanoid state.
So, a few steps:
- Get the ground normal
- Create a function that gets the desired position and orientation of the skateboard based on the ground normal and the position of the humanoidrootpart
- Set the .Position of the skateboard and the .Rotation of the skateboard (Position and Rotation can adjust welds, dont use CFrame)
If you want to rotate the character too, you can do the same thing with the lower torso (or upper, again, I forgot which)
Do you know what you’re using to stop the character from falling over? Are you using a Humanoid/HumanoidState or are you using physics?
The character’s HRP is welded directly to the skateboard by means of a script. The character’s Animate
script is also disabled, all animations are stopped, and a skateboard idle
animation is played. I guess I’m using physics?
I think that’s based on the HumanoidState then, it’s basically the same deal. If you were using physics you’d have something like a BodyGyro or an AlignOrientation.
Okay, does that really matter though?
That’s kind of the entire question right? To change the orientation you need to change the way you’re currently controlling the orientation.
You can also just directly set the CFrame every RenderStepped. Not sure if that would work or replicate well, but it’s easier.
I don’t think that would replicate to the server.
Can you provide a code example for converting the RaycastResult Normal to an orientation for the skateboard CFrame?
Good point, you’d need to have a value for it then set the value on the clients. Here’s what I’d do:
- Weld the skateboard to the lower torso instead of the HRP
- Have the clients run code to update the lower torsos of characters riding skateboards.
or
- Use a physics based approach.
I think it would look something like this:
local Workspace = game:GetService("Workspace")
local humanoidRootpart - set to HRP
local skateboard -- set to skateboard
local rayLength = 1
local function getGroundNormal()
local raycastResult = Workspace:Raycast(skateboard.position, skateboard.CFrame.UpVector * -1 * rayLength)
local groundNormal
if raycastResult then
groundNormal = raycastResult.Normal
else
groundNormal = Vector3.up
end
end
local function computeOrientation(normal)
humanoidRootpartCFrame = humanoidRootpart.CFrame
-- angle is based on the direction the HRP is facing
-- I honestly don't know if this is the correct formula, might have to switch some terms around
local angle = math.arctan2(humanoidRootpartCFrame.LookVector.X, humanoidRootpartCFrame.LookVector.Y)
return CFrame.fromAxisAngle(normal, angle).Orientation
end
Fair warning that math probably has an error some where. I’d program a quick test to see if it works before implementing it. I have to go do work stuff.
Wow, thanks for all your help! I’ll try this out in my script later and get back to you.