I’m not sure if this will be fixed later or if I’m missing something, but it seems to me that the video’s way of blending the two movement commands on the same tick is flawed.
Here’s a sample of my output log using the video method:
LogTemp: Warning: Tank_BP3 TMC::RDM to V(X=-0.98, Y=-0.17), facing V(X=0.27, Y=-0.96), produces turn 0.995249, throw -0.097359
LogTemp: Warning: Tank_BP3 IntendTurnRight 0.995249
LogTemp: Warning: TanKTrackRight Set throttle 0.995249
LogTemp: Warning: TanKTrackLeft Set throttle -0.995249
LogTemp: Warning: Tank_BP3 IntendMoveForward -0.097359
LogTemp: Warning: TanKTrackLeft Set throttle -0.097359
LogTemp: Warning: TanKTrackRight Set throttle -0.097359
Since the IntendMoveForward and IntendTurnRight calls both happen on the same tick, we have a strange race condition. Depending on when the total force applied to the tank is calculated and the resulting acceleration applied to the tank’s velocity relative to when the TankTrack’s force vectors are being updated, the tank may be in turn mode, or in forward mode. My guess, in my case, is that the force is accumulated either before or after both function calls (but not between), meaning that my tank is only going to move forwards and backwards (since the last function to affect the track forces was IntendMoveForward, in either case). And that’s what I observed when testing (no turning, just forward/backing). And if I change the order of the function calls, I get only turning, no forward/backing.
What I want to happen is have the throttles be set to some intermediate state between purely moving and purely turning. In other words, if the AI wants to move forward at half throttle (left 0.5, right 0.5) and turn right at half throttle (left 0.5, right -0.5), we want its tank’s left track throttle to be the average of (0.5, 0.5), which is 0.5, and right throttle to be average(0.5,-0.5), which is zero. So I wrote this function in TankMovementComponent.cpp:
void UTankMovementComponent::IntendMoveAndTurn(float Throw, float TurnRate) { //blend turn and move intentions into combined throttle commands
if (LeftTrack == nullptr || RightTrack == nullptr) {
return;
}
float LeftThrottle = (Throw + TurnRate)/2.f;
float RightThrottle = (Throw -TurnRate)/2.f;
LeftTrack->SetThrottle(LeftThrottle);
RightTrack->SetThrottle(RightThrottle);
UE_LOG(LogTemp, Warning, TEXT("%s IntendMoveAndTurn %f, %f produced %f, %f"), *GetOwner()->GetName(), Throw, TurnRate, LeftThrottle, RightThrottle);
}
And when I test this blended function, it looks a lot more like the movement in Ben’s video. Still, I don’t understand how Ben is getting his results with his code. Did anyone else have a similar experience?