Two Part Custom Character Independent Y-Axis Rotation Towards Cursor

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!
    For a custom character, I want the top part (the gray block) to rotate on the y axis towards the cursor independently of the bottom part.

  2. What is the issue? Include screenshots / videos if possible!
    Both the top and the bottom part rotate at the same time.

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I’ve tried placing the top part in workspace and connecting it to the bottom part via hinge and weld constraint, as well as anchoring the bottom part to see if the top part can even rotate independently(anchoring did nothing).

After that, you should include more details if you have any. Try to make your topic as descriptive as possible, so that it’s easier for people to help you!
The strange thing is that when I use a script to rotate the top part constantly, it works just fine, but when I try to make to rotate towards the cursor, the entire thing rotates.

Here is the local script (under StarterCharacterScripts) that I’m using to rotate towards cursor:

wait(1) 

Player = game.Players.LocalPlayer
local Character = Player.Character
local Root = Character:WaitForChild("toppie")

local Mouse = Player:GetMouse()
local RunService = game:GetService("RunService")

RunService.RenderStepped:Connect(function()
	local RootPos, MousePos = Root.Position, Mouse.Hit.Position

	Root.CFrame = CFrame.new(RootPos, Vector3.new(MousePos.X, RootPos.Y, MousePos.Z))
end)

Here’s what the starterCharacter looked like when using the script above:
image
Notice how the top and the bottom are fused.

Here is the local script I used to make the top part spin like a top:

wait(1)
Player = game.Players.LocalPlayer
local Character = Player.Character
local Root = Character.toppie

local SpinObject = Character.toppie

while true do
	SpinObject.Orientation += Vector3.new(0,15,0)
	task.wait(0.01)
end

Here’s what it looked like when I simply ask it to spin in circles using the script above:
image
Notice how the top and bottom aren’t fused.

In a broader context, I’m trying to make a mech game where you can rotate the top part independently from the bottom legs.
Please do not ask people to write entire scripts or design entire systems for you. If you can’t answer the three questions above, you should probably pick a different category.

1 Like

You need to adjust the Weld CFrame, but it must be converted from world to object space.

Sorry if I’m being stupid, but how do you do that? Is it purely in code? I don’t see that property in the properties tab for the weldConstraint.

You need to replace your WeldConstraint with a Weld. WeldConstraints don’t support CFrame manipulation.

Alright, I have a weld. What’s next? :v
I’m guessing converting to object space is next. Do I use ToObjectSpace()?
If so, how would I do that for this script?

wait(1)

local Player = game.Players.LocalPlayer
local Character = Player.Character
local Root = Character:WaitForChild("toppie")

local Mouse = Player:GetMouse()
local RunService = game:GetService("RunService")

RunService.RenderStepped:Connect(function()
    local RootPos, MousePos = Root.Position, Mouse.Hit.Position
    
    -- Convert the Mouse position to the local space of the "toppie" part
    local LocalMousePos = Root:WorldToPartSpace(MousePos)

    -- Set the CFrame of "toppie" using the local Mouse position
    Root.CFrame = CFrame.new(RootPos, Vector3.new(LocalMousePos.X, RootPos.Y, LocalMousePos.Z))
end)

Yes, you use ToObjectSpace.

yourCFrameThatYouWantInObjectSpace:ToObjectSpace(Root.CFrame)

I’m getting an error stating that there is no such thing as a CFrame for welds.
" CFrame is not a valid member of Weld"
Here is the code I used:

wait(1) 

Player = game.Players.LocalPlayer
local Character = Player.Character
local Root = Character:WaitForChild("toppie")
local weld = Root:WaitForChild("Weld")

local Mouse = Player:GetMouse()
local RunService = game:GetService("RunService")

RunService.RenderStepped:Connect(function()
	local RootPos, MousePos = Root.Position, Mouse.Hit.Position
	--print(Mouse.Hit.Position)
	weld.CFrame:ToObjectSpace(Root.CFrame)
	Root.CFrame = CFrame.new(RootPos, Vector3.new(MousePos.X, RootPos.Y, MousePos.Z))
end)

The weld I used is a child of the top part (“toppie”)

Sorry if I’m being dumb. That’s what I think you meant when you said adjust the weld’s CFrame.

Nevermind! The solution I found actually doesn’t use CFrames, but rather orientation. I’m also now using weldConstraints.
Thank you for your time, @SubtotalAnt8185

Here is the script that is working for me:

wait(1)

local Player = game.Players.LocalPlayer
local Character = Player.Character
local Root = Character:WaitForChild("toppie")

local Mouse = Player:GetMouse()
local RunService = game:GetService("RunService")

local lastMousePosition = Mouse.Hit.Position

RunService.RenderStepped:Connect(function()
	local MousePos = Mouse.Hit.Position
	local lookDirection = (MousePos - Root.Position).unit

	local newRotationY = math.atan2(-lookDirection.X, -lookDirection.Z)

	Root.Orientation = Vector3.new(0, math.deg(newRotationY), 0)

	lastMousePosition = MousePos
end)

I meant C0, since it is a CFrame. I don’t recommend WeldConstraints because if the position is changed manually (like a teleport script), it will break.

Holy biscuit! It works a lot better! Thank you so very much! :DDD

Now to figure out how to prevent it from messing up all the meshes’ orientations

Edit: Ok…it’s getting really fking annoying. If I adjust it when it’s welded, it further messes things up. How do I prevent it from moving upon welding in the first place?

Here’s what it does to my custom starter character:

There’s usually an original C0 that is applied to the weld, so you can read from it and apply it as an offset.

--near the top of the script
local originalC0 = weld.C0

--when you change the c0
weld.C0 = yourTargetC0 * originalC0
--you need the '* originalC0' part
1 Like

Wow thanks! That worked splendidly!

EDIT: NEVERMIND. It didn’t work. It was just my eyes playing tricks on me.
Here’s what I have for the code:

local Player = game.Players.LocalPlayer
local Character = Player.Character
local Root = Character:WaitForChild("top"):WaitForChild("topConnection")

local weld = Root:WaitForChild("Weld")
local weldO = weld.C0

local Mouse = Player:GetMouse()
local RunService = game:GetService("RunService")

local lastMousePosition = Mouse.Hit.Position
wait(5)
RunService.RenderStepped:Connect(function()
	local MousePos = Mouse.Hit.Position
	local lookDirection = (MousePos - Root.Position).unit

	local newRotationY = math.atan2(-lookDirection.X, -lookDirection.Z)

	Root.Orientation = Vector3.new(0, math.deg(newRotationY), 0)
	weld.C0 = Vector3.new(0, math.deg(newRotationY), 0) * weldO
	lastMousePosition = MousePos
end)

ANOTHER EDIT: I did it successfully by manually editing the C0 of the weld under the properties tab. Thank you for your time and patience, @SubtotalAnt8185

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