How to move a limb independently (and move attached limbs with it)?

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!

I am making a recreation of the Nutcracker from Lethal Company.

  1. What is the issue? Include screenshots / videos if possible!

To recreate the Nutcracker, I need to have to torso rotate to scan the surrounding area. Basically it rotates 90 degrees every few seconds during the scanning process.

Here is an image with the lower torso colored red for readability:
image

  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?

At first I made an animation for it, but I quickly realized this would not suffice due to the other functions the Nutcracker has/does. To try and do this, I attempted to rotate the upper torso, but this just rotates the entire rig.

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!

Here is the code if it helps:

task.wait(1)

local pathfindingService = game:GetService("PathfindingService")

local Nutcracker = script.Parent
local rootPart = Nutcracker:WaitForChild("HumanoidRootPart")
local humanoid = Nutcracker:WaitForChild("Humanoid")
local playingAnim = script.PlayingAnim

local nodes = workspace:WaitForChild("Nodes")

local checkedNodes = {}
local currentNode = nil
local queuedNode
local lastNode = nil
local nodeToMove = nil
local pathfindId = 0

local range = 50
local searchPrecision = 15

local function getPath(destination)
	local path = pathfindingService:CreatePath()
	path:ComputeAsync(rootPart.Position, destination)
	return path
end

local function pathFindTo(destination)
	pathfindId += 1
	
	local currentPathfind = pathfindId
	
	local path = getPath(destination)
	
	for i,waypoint in pairs(path:GetWaypoints()) do
		if currentPathfind ~= pathfindId then
			return
		end
		humanoid:MoveTo(waypoint.Position)
		humanoid.MoveToFinished:Wait()
	end
end

local function stopPath()
	pathfindId += 1
end

local function playAnim(id)
	playingAnim.AnimationId = "rbxassetid://" .. id
	
	humanoid:LoadAnimation(playingAnim):Play()
end

local function stopAnims()
	for i,anim in humanoid:GetPlayingAnimationTracks() do
		anim:Stop()
	end
end

local function getNodeInRange()
	local selectedNode = nil
	local nodesInRange = {}
	
	for i,node in nodes:GetChildren() do
		local distance = (rootPart.Position - node.Position).Magnitude
		
		if distance < range and not table.find(checkedNodes, node) and distance > searchPrecision then
			table.insert(nodesInRange, node)
		end
	end
	
	selectedNode = nodesInRange[math.random(1, #nodesInRange)]
	
	return selectedNode
end

local function movementAi()
	local selectedNode = getNodeInRange()
	
	selectedNode.BrickColor = BrickColor.new("Really red")
	
	coroutine.wrap(pathFindTo)(selectedNode.Position)
	
	repeat task.wait() until (rootPart.Position - selectedNode.Position).Magnitude <= searchPrecision
	
	stopPath()
	
	Nutcracker.Torso:PivotTo(CFrame.new())
	
	table.insert(checkedNodes, selectedNode)
	
	selectedNode.BrickColor = BrickColor.new("Lime green")
	
	movementAi()
end

playAnim(132770303101334)

movementAi(currentNode)
1 Like

Could you explain further why do you need to rotate the torso to scan? is it only to scan the area or is it needed for visuals?

In the scanning process, the Nutcracker will raise its head to reveal an eye. This eye will activate it’s aggro phase upon seeing a player (this has not been implemented). When the Nutcracker starts scanning, it will turn 90 degrees, wait, and repeat until it is back where is started, then it will continue to march around. TLDR: It’s used to scan the area, not for visuals.

If the movement for the torso isnt needed for visuals then dont rotate the head but instead save the last cframe every rotation change and add 90 deg to it

Like first detection cframe = nutcracker head cframe, second detection cframe = first detection cframe + cframe.new(0, math.rad(90), 0) and so on

First of all, this is a great fix that I can’t believe I didn’t think of. However, after trying many variations I keep getting this error:

send the part of the code that failed

I tried several variations of this such as:

Nutcracker.Torso.CFrame = oldCFrame + CFrame.angles(math.rad(90),0,0)

and:

Nutcracker.Torso.CFrame = oldCFrame + CFrame.new(math.rad(90), math.rad(0), math.rad(0))

I also tried other variations like these, but none of them worked.

cframes dont add, you have to multiply them like so:

Nutcracker.Torso.CFrame = oldCFrame * Cframe.new(0, math.rad(90), 0)

also, CFrames work with the orientation structure of YXZ

My apologies, I haven’t worked with CFrame like this in quite a while, however I still have the problem that this accomplishes the same thing a previous attempt had done. This simply rotates the entire rig rather than the upper half of the body.

I meant to use the cframe to detect it, not to rotate the torso as it will mess up the animations.

As an example:

-- in the detect function
local lastCFrame = Nutcracker.Torso.CFrame
for i = 1, 4 do -- go through the 4 detections
    task.wait(3)
    local CFrameToDetect = i > 1 and lastCFrame.Torso.CFrame * CFrame.new(0, math.rad(90), 0) or lastCFrame -- rotate the cframe or use the current one
   detectPlayers(CFrameToDetect) --example detection function
end

I think you can do all this rotation of the torso and limbs etc hands included using the new IK control you can do runtime animation with this… give it a look its pretty cool what you can do with it at this stage

1 Like

I’m going to try both of these methods and mark one as a solution when I am done.

3 Likes

This is perfect! I’ll make sure to look more into this at some point, but from what I’m seeing while testing it it works REALLY well!

1 Like

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