How do I replicate Real Arm movements to Fake Arms (ViewModel)?

Edit:
Currently I’m trying to make a Fake Arm, where it replicates what the real character arm does.

game:GetService("RunService").RenderStepped:Connect(function()
    part:SetPrimaryPartCFrame(workspace.CurrentCamera.CFrame * CFrame.new(0,0,-3))
end)

This is my ViewModel:

How do I replicate the real arm’s movement to the Fake Arm? CFrame has been already use to force the arm to follow the camera though.

14 Likes

Completely independent and seperate animations for the character.

No, I want both of them to use the same animation.

1 Like

You’d probably have to replicate the CFrame. However, I highly do not recommend that, as the arms in EgoMoose’s tutorial do not bend.

1 Like

But in the First place, how do I attach the arms to the Camera first? I know it’s Mentioned in Ego’s tutorial but I’m still confused.

1 Like

I would personnally just use model:SetPrimaryPartCFrame(workspace.CurrentCamera.CFrame)

2 Likes

Then how do I replicate moves of the Real Arm?

First of all, I do not recommend SetPrimaryPartCFrame because the function is known to have issues since forever and it isn’t really the best option. I suggest you instead create your view model as follows:

  • Construct your View Model including a root, Humanoid (pseudo humanoid) and the arms. The root can be a HumanoidRootPart and a Head, or one or the other. I recommend a pseudo HumanoidRootPart.

  • Weld all the respective parts to your model’s root using Motor6D EXPLICITLY.

  • Have your code set the CFrame of the root part to the Camera’s CFrame plus some. Your view model’s arms will automatically move around as well.

    • If you have a head, compensate for the half that is in front of the Z plane. If you have a HumanoidRootPart, put it slightly below the camera.
  • For anything that the character does, replicate it to the root. For example, you can fetch the animation the character is playing and put it back on the view model.[1]

[1] Crude untested code

local realHumanoid = Character.Humanoid
local pseudoHumanoid = viewModel.RenderHumanoid

-- https://developer.roblox.com/en-us/api-reference/event/Humanoid/AnimationPlayed
realHumanoid.AnimationPlayed:Connect(function (track)
    local viewAnim = pseudoHumanoid:LoadAnimation(track.Animation)
    local viewAnimStop do
        viewAnimStop = track.Stopped:Connect(function ()
            viewAnim:Stop()
            viewAnimStop:Disconnect()
        end)
    end
    viewAnim:Play()
end)

The above code is just an example and I don’t quite recommend it. Typed it on mobile and didn’t test it. There could easily be many better ways to handle this, but off the fly this is what I could think of. The code mainly serves to bring light to Humanoid.AnimationPlayed which you could potentially use to your advantage in this scenario.

Another option can be to set the Transform of the limb motors in the view model to match those in the character right after your CFrame set operation in RenderStepped.

8 Likes

Thanks for your detailed explanation!

The animation didn’t play? I named the Fake arms into Left Arm and Right Arm, which is suppose to work?
I tried to print AnimationPlayed on both humanoids, and they both works and print the PlayedAnimation though.

I forgot to mention, but I already did this in the first place:
image

char:WaitForChild("Humanoid").AnimationPlayed:Connect(function(track)
	print(track)
	local ViewAnim = VM.Humanoid:LoadAnimation(track.Animation)
	   local viewAnimStop do
        viewAnimStop = track.Stopped:Connect(function ()
            ViewAnim:Stop()
            viewAnimStop:Disconnect()
        end)
    end
    ViewAnim:Play()
end)

Plus, how do I accurately position the fake arm? Do I attempt different CFrame values?

This might be a better way to perform it, can you explain a little bit more with examples if possible? Thanks!

2 Likes

For animations to work, you need to have Motor6Ds and part names explicitly the same. In your case, LMR needs to become Left Shoulder, for example. Animations are hard-coded internally to associate a CFrame to a Motor6D name. I believe hierarchy also matters, which means the motors need to be under a Torso part rather than in each arm. Don’t know the accuracy of that though.

In terms of positioning the fake arms, you don’t - at least not with code. If your pseudo limbs are welded to your view model root, you ONLY change the CFrame of the root. The welds will automatically take care of accurately moving the limbs around as needed.

In terms of the Transform method, animations internally use the Transform property of Motor6Ds to function. I have no clue if it’d work but it’d cut out the need to use the animation workaround and anything associated if so (ergo ignore first paragraph). In your RenderStepped function, you simply need to set the Transform of a pseudo limb’s Motor6D to that of the real limb’s.

viewModel["Left Arm"]["Left Shoulder"].Transform = character["Left Arm"]["Left Shoulder"].Transform

Something like that. This is hard-coded, I didn’t really consider abstraction.

2 Likes

My Pseudo arms are welded to the “RootPart” by Motor6D, but the RootPart’s CFrame is set to
(workspace.CurrentCamera.CFrame * CFrame.new(0,0,-3)
It should not?

1 Like

Yeah, don’t touch Z (depth) values. You should instead look towards Y (height) values. 1-2 down should give you the result you want. Play around with the numbers a bit until you find something you like.

1 Like

Which is what I’m using right now and I do not find it efficient.

Weld the fake arms to their respective arms?

1 Like

But it’s already CFrame’d to the Camera though?

Using WeldConstraint, yes. (I don’t know if it works with other types of Joints)

You could also simply set LocalTransparencyModifier = 0 to the character’s arms when entering first person.

EDIT: I read your thread again, so you want the arms to point to the camera?

You can modify the CFrame of the shoulders of the arms with the camera.Changed event, using the Mouse position.

I tried, and that’s the reason I don’t use TransparencyModifier:

How exactly?

You can create a WeldConstraint to attach the fake arm with the real arm, but that won’t help you if you want to follow the camera.

I could easily be missing something, but if you are still looking for other options, have your tried AlignOrientation with Responsiveness = 200?

Otherwise replicate arm CFrame plus a position offset would still seem to be the most straightforward and responsive approach. It’s not clear to me that you have in fact tried combining multiple CFrame operations together. Again, it’s likely I’m missing something.

If you just want the visual representation to appear on the client camera, another method could be the Viewport Portal approach in a ScreenGui where you see all or just specified parts of the avatar in the Viewport.