In the movement component of the default character class, there is a bool to Orient the rotation of the character to the direction of acceleration. When this is enabled, the character does rotate, however it is abrupt and at a constant rate. I would like to manually rotate the character with an interp node for smooth rotation.
Is there a way to find the direction of acceleration manually like mentioned in the Orient Rotation to Movement setting?
The rotation while moving works great, however the character is facing the opposite direction…I am getting and setting the world rotation…should I use local?
Also, the rotation keeps resetting itself back to 0 when the character doesnt move, instead of staying where its at when it stopped.
Yeah that’s what I figured Id have to do. Although after negating the vector now It doesnt always rotate back to zero, instead it rotates to a different pint each time…sort of stutterers then offsets a bit, if that makes sense? Ill keep working with it and thanks!
Get Last Input Vector will give you the direction the player is pressing on the keyboard/controller which is closer to what you want, Get Acceleration-> Normalize will do the same thing as well. Normalized Velocity would feed an input vector if the player is moving without pressing anything on the keyboard(moving platform, flying) which will cause unwanted twirling, twirling, TWIRLING!
If you get the CharacterMovement component’s Velocity variable then you will not get any velocity when the player is moving on a moving platform.
But yeah normalized acceleration probably makes a bit more sense but of course it depends on the desired result (actually that’s what I was thinking in my original post, I just wrote velocity instead :p)
Ok…Basically I just wanted to do what Orient Rotation to Movement does, but interpolate the rotation smoothly. Ill try out these various methods to try and find one that works.
Is there a way to view what Orient Rotation to Movement does internally, so I could copy that?
Edit: I tried using the last Input vector, and that seemed to work the best, however It always returned to zero when nothing was pressed. Is there a way to keep it at its last value?
Haha! That is because it is rotating per tick, you will need to use some math with delta seconds to determine the correct amount per tick to rotate on the Yaw.
@ 60 FPS, 1.5 degrees is 90 degrees per second but at 120 FPS it’s 180 degrees, this is where delta seconds comes in. Delta Seconds make sure your floats remain constant no matter your FPS. I’m not at a computer right now so I don’t know the exact math but its Float(degrees) * Float(delta seconds) -> Yaw.
You are Rinterping so I think it already has a delta seconds input
Yeah it does have one. Ok…****…I was hoping It didn’t have to get this complicated. I’m no programmer unfortunately, so I really don’t know how to go about doing stuff.
Whats nice about using Rinterp to determine player rotation, is that its smooth. And, if the character is facing in a direction, and you tap the opposite direction but release quickly, the character will still turn all the way around to face the direction you tapped in, unlike Orient Rotation to Movement…If that makes sense.
I dont know if there is an easier way to simply find the direction of input, and Rinterp the character to face that direction, and continue to face that direction when input is released.
I had to rebuild this functionality from scratch, not to smooth out rotations (honestly, probably more easily done by changing the max rotation rate in Character movement and being done with it) but to handle special cases like orienting rotation OPPOSITE movement when walking backwards while aiming, forcing rotation-orientation to self-suspend in certain movement states, etc.
The way I did it was to Get Current Acceleration, get Rotation From XVector, break rot, make rot using (0,yaw,0) so that the character did not incorrectly orient when moving up ramps or the like, feed this to the target of an RInterpTo node, feed the Current with Get Actor Rotation, feed the output to a Set Actor Rotation, and hit it with the character’s Event Tick (remembering to connect the delta output to the InterpTo node) BUT with a branch node before it that checks to make sure CurrentAcceleration isn’t too close to 0,0,0 (in which case I simply skip the Set Actor Rotation node and hit the next node in the Tick’s path).
Works well enough for me using an interp speed of like 25, but I like snappy movement; if you want something smoother, start at around 4-6 and tweak it, that’s what I use for smooth curves when orienting rotation to surface normal when dashing, it looks good there.
Thanks! This is the best way so far. The reason I couldn’t just modify the rotation rate, is that it rotates at a constant speed, and abruptly starts and stops. I need smooth rotation that slows before it stops. (maybe adjusting the rotation rate with a curve would work?)
One thing though, that I would like, is for the Actor to rotate completely to its last target even if input is only tapped. For example, If the character is facing a direction, and the player taps the opposite direction with a keyboard or controller, the Actor would still rotate all the way around, instead of stopping when input is released…hopefully that makes sense. I tried using Get Input Last Vector, and deleting the branch, but the Actor would rotate back to zero…apparently no input means a vector of zero? Is there a way to get the input vector and ignore it when its zero?
You can ignore it with a Vector variable; if the vector = 0,0,0 (or alternately, by checking if it’s LENGTH < some number, maybe 0.75 or something), then you skip the Set node, otherwise you feed the Current Acceleration to the Set node. That way, every Tick you’re updating the rotation to match the input vector, but if the input vector isn’t defined, then the engine remembers the last defined vector rather than overriding it with 0,0,0… if that makes sense.
So if you press forward (and the camera is forward), your Input Vector is set to 1,0,0, and the engine starts rotating the character toward it; then if you release the vector, it becomes 0,0,0, and therefore the engine doesn’t SET the variable and so the engine continues rotating toward it.
Here’s the issue with what you’re trying to do, though, if you support controllers: when you release the stick, the input vector becomes something LESS than 1 before it becomes 0. So you flick the stick left, the input vector has a length of 1, then a length of 0.8, then a length of 0.5, then a length of 0.3, then finally passes the deadzone and becomes 0 again. If you aren’t allowing walking in your game, it’s easy; you ignore the vector whenever its length is less than 1 (or 0.8 or whatever). But if you allow walking with a gentle touch of the stick, the issue becomes that as the stick nears the deadzone, the angle will change, just because the mechanical stick itself doesn’t retract in an exactly linear fashion. You flick it 25 degrees left of forward, and as you release it, it might slowly become 45 or even 60 degrees left of forward as it gets closer to center because a stick is a stick and it’s subject to real-world physics. So the player’s angle won’t be as accurate as you might like.
To work around this, you’d need to do a more complicated check; you would have to skip Setting the storage Vector variable whenever its length is LESS than the last-defined value’s length… and then RESET this check when the vector is of length 0. Which, since you aren’t storing it, means you need two variables. First, you need a float, which sets itself to the length of the vector UNTIL the new vector is shorter than the last one, in which case it resets to 0, AND you need to set the vector itself whenever this isn’t true.
So, you know, fairly complex to make it work really well.
By setting a target Rotator after setting the actor rotation, and using that target rotator as the target for the RInterp, I can stop setting the rotator if input is zero, while continuing to set the rotation to the last known value. That way I can easily Rotate 180 degrees without moving hardly at all! It works really well!