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
withDirection
is lower thanMaxRadialVelocityInRadians
- 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!