1

I am trying to implement a move system for a ball in Unreal Engine 5. The user can apply torque to a ball to let the ball spin in a certain direction depending on the position of the camera in a 3D game. I am having problems with implementing a good solution for the movement of the ball.

My code so far is as following down below.

void ABallie::Move(const FInputActionValue &Value)
{
    if (Controller != nullptr)
    {
        FVector2D MoveValue = Value.Get<FVector2D>();
        // GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, FString::Printf(TEXT("X: %f | Y: %f"), MoveValue.X, MoveValue.Y));

        FVector ForwardDirection = Camera->GetRightVector() * MoveValue.Y;
        ForwardDirection.Z = 0;

        FVector SideDirection = Camera->GetForwardVector() * MoveValue.X;
        SideDirection.Z = 0;

        FVector Direction = (ForwardDirection + SideDirection).GetSafeNormal(0.001);
        Direction *= TorqueStrength;

        MainBody->AddTorqueInRadians(Direction, "MainBody", true);

        if (MainBody->GetPhysicsAngularVelocityInRadians().Length() > MaxRadialVelocityInRadians)
        {
            MainBody->AddTorqueInRadians(-Direction, "MainBody", true);
        }
        GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, FString::Printf(TEXT("Velocity: %f"), MainBody->GetPhysicsAngularVelocityInRadians().Length()));
    }
}

Explanation: MoveValue tells me in a 2D vector which keys WASD the user has pressed. X ranges from 1 to -1 ("W"=1, "S"=-1) and Y ranges also from 1 to -1 ("A"=1, "D"=-1). I get the forward and right vector of the camera and multiply it accordingly to get the forward and side vector that the torque should be applied upon. Adding and normalizing the forward and side vector to get the desired direction vector. Multiplying the direction vector with TorqueStrength to give me the final torque vector, which overwrites Direction.

The crucial part is this here. It works kinda ok but it won't give control to the player to spin in one direction if the ball goes faster than the max in another direction (Going max velocity in one direction but 0 in the other won't let the player spin in the other direction whatsoever).

  • Apply the torque in the desired direction
  • Check if the angular velocity afterwards is higher than MaxRadialVelocityInRadians
  • If it is higher than MaxRadialVelocityInRadians, then "unapply" the torque by just adding the negative version of the torque vector
        FVector Direction = (ForwardDirection + SideDirection).GetSafeNormal(0.001);
        Direction *= TorqueStrength;
        MainBody->AddTorqueInRadians(Direction, "MainBody", true);

        if (MainBody->GetPhysicsAngularVelocityInRadians().Length() > MaxRadialVelocityInRadians)
        {
            MainBody->AddTorqueInRadians(-Direction, "MainBody", true);
        }

I wanted to somehow make it work in a better way and came up with this:

  • Get the current angular velocity vector of the ball AngularVelocity
  • Check if the dot product of AngularVelocity with Direction is lower than MaxRadialVelocityInRadians
  • If true, then apply the torque vector to the ball

        FVector Direction = (ForwardDirection + SideDirection).GetSafeNormal(0.001);

        FVector AngularVelocity = MainBody->GetPhysicsAngularVelocityInRadians();

        if (FVector::DotProduct(AngularVelocity, Direction) < MaxRadialVelocityInRadians)
        {
            Direction *= TorqueStrength;
            MainBody->AddTorqueInRadians(Direction, "MainBody", true);
        }

But this fails because you can get faster by looking left and right while pressing forward or tapping A and D quickly while moving forward. Example: Just pressing W to move forward to get to top speed of let's say 20 radians. Then suddenly pressing A while holding W will increase the spinning speed to 24 and decrease after 1-2 secs down to 20 again. My first solution will always keep it at 20 no matter what I try, same goes with the in-engine property to set a general max angular velocity on the object Max Angular Velocity under Physics category on the object property settings.

My whole idea with the last approach was to check if the angular velocity in the direction of which I want to apply the torque to is lower than the max angular velocity that is allowed and only apply torque if the ball is spinning slower than the max in that direction. So I attempted to do a scalar projection of the angular velocity vector onto the normalized direction vector. But yeah...

Is my conception wrong? I feel like my math is off on this one! Any help appreciated.

My goal is to achieve a max angular velocity. I could just tick the physics property "Max Angular Velocity" in the Engine on the ball and put in some value but this would also make the ball never spin faster than that max value I put in. But I want to have outside forces to still be able to make the ball spin faster than the player can by using controls, e.g. down a slope it should be possible for the ball to spin faster than the max value. It just shouldn't be possible to achieve a faster spinning velocity than the max through player input.

Thanks for the time reading through my problem!

Ilja KO
  • 1,272
  • 12
  • 26
  • Some thought before really studying in detail your code and comments.... A solid body in free space, with no forces or torques applied to it, will have a constant 3D angular momentum VECTOR. This does not mean that it rotates around a fixed axis. It may, but it can also precess like a gyroscope. You need to decide what you mean when you use the word 'spin'. – Simon Goater May 01 '23 at 08:31
  • So, for a solid object with a radially symmetrical mass distribution like a spherical ball, then you could say spin S = k|A| where A is the ball's angular momentum vector and k is a real constant. Then if you have a torque vector T, you only want to apply it if S < Smax or T.A < 0. Torque is like rate of change of angular momentum, so if T is in the opposite direction to A, then it will cause dS/dt to be negative. – Simon Goater May 01 '23 at 10:14
  • You might consider making the angular velocity decay (exponentially) rather than trying to impose a hard cap. – Davis Herring May 02 '23 at 18:28
  • @DavisHerring there is already a dampening of angular momentum happening through an in-engine physics settings. I might jsut have to live with a slightly higher spin rate or just hardcap the angular velocity – Ilja KO May 02 '23 at 21:42
  • If you tune the damping, you can get the maximum you want without an explicit cap: it behaves more realistically, and even supports larger speeds when larger forces are applied (like your slope example). That said, you can also fix the issue with being unable to change the direction when at max speed by applying the torque and then _rescaling_ the angular velocity as necessary. (This probably cheats a bit with regards to gyroscopic effects; again, damping is more realistic.) – Davis Herring May 03 '23 at 04:43
  • @DavisHerring yeah I guess you are right to play with the damping around and readjusting the force of the torque and gravity force accordingly. I could minimize that way this behaviour. This angular velocity adjustment is kinda what I want but I don't want to overcomplicate things any further. – Ilja KO May 04 '23 at 09:46
  • I also tried setting the max angular velocity setting of the engine in code, apply my torque to the ball and disable the max angular velocity again tot he standard, but this also does not work because setting the max angular velocity setting seems to be a bacth thing that is applied on every frame and not when I call it immediately. Guess its a physics engine thing that you cannot switch inbetween frames frequently and only applied post-frame to whatever last value I put it in in my method – Ilja KO May 04 '23 at 09:51

0 Answers0