I’m working on a fun project that involves character movement + ArcRotateCamera rotation around them. I’m using setTarget and limited alpha/beta to restrict movement. Here’s an example of what I have so far:
The two things I’m combating right now involve:
Inverting the camera rotation when using the keyboard. When I press left arrow the character goes right and press right character goes left. I’ve tried changing invertRotation to true but that doesn’t seem to help. I was wondering if this can be done with the natural input controls so I don’t have to write more logic?
In the example after walking with the keyboard I switch to mouse. Currently I am binding a click action to have the user walk but when I rotate left/right with the mouse the camera rotates (obviously) around the character. I’m trying to figure out how to rotate the character so that they are always with their back to the camera. This creates a sort of 3rd party camera.
If I can get those two solved I can probably stage a copy for everyone to play around with. If anyone has suggestions on the best approach, I’d be quite grateful.
The first thing I think you’ll need to consider is to change the relationship between input, camera, and character movement.
You want the character to move while the camera follows it, not the other way around, right? Have you tried the FollowCamera yet for this type of thing?
You might want to check that you aren’t overlapping inputs unintentionally; reset or unset the camera’s control keys or disable keyboard input for the camera entirely might do the trick. Detaching camera control on mouse click is an option too if that works better with your UX.
Making a “camera dolly” from a transform node and parenting the camera to it can help in situations where the camera is translating and rotating at the same time as well.
Cool project! The advice I’m about to give might not make your life easier in the short term, so please take that into account when considering it; but for a use case like this, I wouldn’t recommend using ArcRotateCamera. Instead, what I would recommend doing is using a FreeCamera or UniversalCamera, not attaching the default controls, then creating the control scheme yourself.
The reasoning is that, while camera controls in general aren’t that hard to do, getting the “feel” right for a particular scenario is largely a matter of tweaking and fiddling. If the “feel” isn’t right out-of-the-box from a provided camera mechanism, the camera’s built-in behaviors are likely to get in the way of the fiddling more than they will help it, so the relatively small investment to create a bespoke mechanism will pay big dividends in the longer term because (1) you’ll understand completely how it operates and (2) you’ll be able to change it very freely to suit your needs.
For your specific case, then, I’d recommend starting with the following approach:
Create a TransformNode hierarchy where the camera (which is distant from the character and looking in) is parented to a TransformNode which is in the character, which TransformNode is itself parented (possibly indirectly) to the character. This will allow you to quickly recover some aspects of the ArcRotateCamera functionality (the parenting to the on-character TransformNode will act as a lever) without being beholding to the ArcRotateCamera's specific set of built-in behaviors.
Decide how you want the camera and the character to be related. If you truly want the camera to be always behind the character, then just rotate the character, not the camera, and disallow the camera’s parent TransformNode from rotating in Y. This will cause the camera to automatically “move” to stay rotationally locked to the character without you having to do any additional special handling.
As you want to change the feel, having complete control over the camera’s behavior may matter more or less depending on the decisions you make. 3rd person character cameras often have complex relationships with the character (don’t turn the character if the camera turns unless the character is moving, and don’t turn the camera if the character starts moving until a few seconds have passed unless the player is already directing the camera to face in a different direction, allow the camera to be slightly “left behind” as the character accelerates but catch up later to make things feel springy, etc.), and the easiest way to effect those kinds of behaviors precisely will be to maintain direct control on the relationship between the camera and the character.
Again, the value of this depends on how far you want to take it; so if FollowCamera or ArcFollowCamera suit your needs out of the box, those are probably great choices. However, if you start needing to customize the behavior of the camera to get the effect you’re looking for, cameras with extensive built-in behaviors may start sort of fighting you on that effort, so it could be worthwhile (and not too difficult) to consider tackling it from the ground up.
Yeah I was concerned the suggestions would be to use FollowCamera. I did attempt going down that path but there’s more camera trickery that I had to juggle and settled on the fact that ArcRotateCamera would give me 80% of what I needed. So switching right now would be painful. I have a few crazy camera movements between contexts ie. birds eye view of the world then back down to the character. There’s a few other weird ones.
What I was hoping would be the solution is on re-render of the frame always map the rotation of the character in the direction of the camera. That would solve my following issue? Perhaps something like avatar.update = () => { // modify character angle to camera }
The only issue is I’m not sure how to calculate the rotation of the character based on the camera alpha/beta? I believe I have to convert the Eular angle of the camera?
So yeah #2 is certainly the solution I was aiming for. The problem is I’m having trouble deciding how to articulate the character alongside the camera. I know I can assert the rotation angle on the meshes .update() callback but I’m not sure how to calculate the cameras pointed direction.
I’m actually going to close off this question and repost it with a more obvious title, I realized that I didn’t do a very good job of expressing the actual issue which might discourage answers. I also managed to solve the first issue with the camera rotation. I just needed to bind the proper keys like so: