Animating the character to look where the camera is pointing

How do many popular roleplay games achieve this?

What I am noticing is that animations are being played over the look animations, so I doubt that these are being done with standard animations.

Are the Motor6D C0’s being messed with? If so, how is this replicated so efficiently and smoothly?

Or is it Motor6D.Transform? Is that even feasible to update the animations of 125 characters at once on RenderStepped?

3 Likes

I believe the method is to CFrame body parts manually in a RenderStepped event. From my personal experience this method doesnt require an animation.

1 Like

Does this not have performance implications for MeepCity’s mobile-friendly 125-player servers?

1 Like

That’s correct, no animation is required, only CFraming methods(which I really want to know what’s behind it). Pretty sure it somehow obtains the ‘camera angle’(or which way it points forward) and mix up the CFrame smoothly to it.

Not sure how that is achieved, further information is requested soon.

Otherwise I think there are something else than CFrame. I need to know what’s behind it. To be honest I don’t really have an idea of what the mechanics are.

EDIT: Animations combined with CFrame, basically. So following parts are manipulated:

  • LowerTorso
  • Head
1 Like

By “CFraming” I’m guessing you’re talking about Motor6D.Transform…

I’m still quite dubious. MeepCity animates at least the Head, the UpperTorso, and the LowerTorso.
125 players * 3 joints * 60 FPS
That’s 22500 CFrames being updated per second on my desktop.

On mobile, at 20 FPS, that’s 7500 updates per second.

The look animations seem to be updating consistently at quite a distance, and are not throttling their update rates very much. I’d imagine this would need to be server-side and not client-side.

That most definitely will I’d say. One of the commissions I was hired to do had an unrelated system that fired a RemoteEvent every RenderStepped event to update the character to face a certain way.


EDIT I just realized this is made for a custom rig and is inapt.


Here’s an old script I modified to fit this thread from said commission:

local Camera = game.Workspace.CurrentCamera
local Character = LocalPlayer.Character or LocalPlayer.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid")
local UpperTorso = Character:WaitForChild("Torso")
local Head = Character:WaitForChild("Head")
local Head6D = UpperTorso:FindFirstChild("Head")
local HeadBaseC0 = UpperTorso:WaitForChild("Head").C0
local UpdateSpeed = 0.9
local HorizontalFactor = 0.6
local VerticalFactor = 0.6 

HeadCFrameUpdate = function()
    local AimPoint = (Camera.CFrame * CFrame.new( 0, 0, -4000)).p
    local Distance = (Head.CFrame.p - AimPoint).magnitude
    local Difference = Head.CFrame.Y - AimPoint.Y
    
    if not Head6D then
        warn("Head6D does not exist.")
    else
        local UpdatedC0 =  HeadBaseC0 * CFrame.Angles(-(math.atan(Difference / Distance) * VerticalFactor),
            (((Head.CFrame.p - AimPoint).Unit):Cross( UpperTorso.CFrame.lookVector)).Y * HorizontalFactor,0)
        
        local Lerp = Head6D.C0:lerp(UpdatedC0, UpdateSpeed/2)
        
        Head6D.C0 = Lerp
        
        OrientateHead:FireServer(Head6D, Lerp) -- Lerp's head server-side so it's visible to other players.
    end
end;

game:GetService("RunService").RenderStepped:Connect(function()
    HeadCFrameUpdate()
end)

Feel free to look through it to understand what it’s doing. As I said this is old so there’s probably a wayy better alternative to this.

1 Like

I’m seeing some very dubious code and suggestions posted in this thread. You definitely do not want to do this without animation objects, and you definitely don’t want to set C0/C1 directly. Use Motor6D.Transform for this. I’m curious why this isn’t more widely known as being the best solution judging from the posts above. If you set C0/C1 directly at RenderStepped, this leads to a lot of unnecessary replication, and creating your own custom animations is just overkill for something like this and doesn’t allow for rapid iteration.

You would replicate the viewing angles to the server for each client, and then the server would broadcast the viewing angles of all players to all clients every so often, and then each client can locally tween each character’s neck motor (via Motor6D.Transform).

EDIT: we do this here in the Aquaman event game as written above: https://www.roblox.com/games/2056459358/City-of-Rolantis

8 Likes

This code sample is from a game gun system a good while ago and made by another programmer who, judging by the rest of his code, didn’t really know good practices too well. The code is not a suggestion for how to tackle the problem, rather an example to help understand what’s being done.

Trust me, this is really a bad idea. The server and client communicate at 20-30Hz, and you would be sending the updated C0/C1 over each network tick for each client and also broadcasted to each client. You can do with much fewer updates (i.e. 2-3 times a second, and then tweening the Transform to the desired value), which is why you would manually send over the angles. Note also that you do not get tweening for free when you take the C0/C1 approach, you’d see other character stuttering at 20-30Hz from your end. This is not a good solution.

Motor6D.Transform lets you apply the transformation on top of any animation locally easily without needing to read the current CFrame of the parts that the motor is connected to.

1 Like

Would this be done in a RenderStepped event aswell?

No, you are meant to manipulate Transform on Stepped. That signal happens right after the internal animation update step.

2 Likes

Alright, well I’ve run some tests on Transform, and it seems to be fairly decent on mobile, especially if you have a maximum render distance for Transform changes.

1 Like