Unsure how to move a unit to a point

I've got a unit and a series of points in 3D space which approximate the path it's been given. However, I'm not sure where to go from there. The unit has certain physical constraints, like, it can only turn so fast, it can only accelerate so fast/decelerate so quickly, etc. I thought that this would be the simple part and finding the path would be the hard part, but apparently it's not. Here's the code I've written:

void Sim::Context::tick() {
auto t = 1.0f / Sim::ticks_per_sec;
std::for_each(players.begin(), players.end(), [&](std::unique_ptr<Sim::Player>& p) {
auto units = p->GetOwnedUnits();
std::for_each(units.begin(), units.end(), [&](Sim::Unit* unit) {
auto t = 1.0f / Sim::ticks_per_sec;
auto u = unit->GetVelocity();
auto a = unit->GetAcceleration();
if (u == 0 && a == 0)
return;
auto rotated_heading = Math::Vector(0, 0, 1) * unit->GetRotation();
auto bp = unit->GetBlueprint();
auto v = t * a + u;
if (v > bp->MaxVelocity) { // Do a more accurate lerp since we went over max velocity
// leerrrppppp
auto frac = (bp->MaxVelocity - u) * (t / (v - u));
auto total_increase = (u * t) + (0.5f * a * frac * frac) + (bp->MaxVelocity * (t - frac));
unit->SetPosition((rotated_heading * total_increase) + unit->GetPosition());
unit->GetOwningPlayer()->OnUnitPositionChange(unit, unit->GetPosition());
unit->SetVelocity(bp->MaxVelocity);
return;
}
auto increase_due_to_velocity = u * t;
auto increase_due_to_acceleration = 0.5f * a * t * t;
auto rotated_increase = rotated_heading * increase_due_to_acceleration;
unit->SetPosition(rotated_increase + unit->GetPosition());
unit->SetVelocity(v);
unit->GetOwningPlayer()->OnUnitPositionChange(unit, unit->GetPosition());
});
});
for(auto orderit = UnitOrders.begin();orderit != UnitOrders.end();) {
if (auto move = dynamic_cast<Move*>(orderit->second.get())) {
auto unit = orderit->first;
if (Math::Length(unit->GetPosition() - move->target) < 2) { // Close enough to target
orderit = UnitOrders.erase(orderit);
unit->SetAcceleration((-4 * unit->GetVelocity()) / (t * t)); // Let the setter implement the cap
continue;
}
auto path = GetPath(unit->GetPosition(), move->target, unit);
if (path.size() == 1) {
orderit++;
continue;
}
auto target_heading = Math::Normalize(path[1] - unit->GetPosition());
auto current_heading = Math::Normalize(Math::Vector(0, 0, 1) * unit->GetRotation());
auto axis = Math::Normalize(Math::Cross(current_heading, target_heading)); // Every path has at least two positions- a beginning and an end.
if (dot_value > 1)
dot_value = 1;
if (dot_value < -1)
dot_value = -1;
auto degrees_angle = std::acos(dot_value);
auto angle = glm::degrees(degrees_angle);
unit->SetAcceleration(unit->GetBlueprint()->MaxAcceleration);
orderit++;
continue;
}
if (std::abs(angle) > (unit->GetBlueprint()->MaxTurnRate * t)) {
angle = unit->GetBlueprint()->MaxTurnRate * t;
// Not done turning, slow down as much as possible.
unit->SetAcceleration((-4 * unit->GetVelocity()) / (t * t)); // Let the setter implement the cap
} else {
// Done turning- let's rock on.
unit->SetAcceleration(unit->GetBlueprint()->MaxAcceleration);
}
auto added_rotation = Math::RotateAxis(angle, axis);
auto total_rotation = unit->GetRotation() * added_rotation;
if (total_rotation.x != total_rotation.x)
__debugbreak();
unit->SetRotation(total_rotation);
orderit++;
}
}
}


Sometimes the units rotate to move backwards towards the target, instead of forwards.

Sometimes the units rotate to face a few degrees away from the target, backwards or forwards. The exact value of a "few" is quite variant.

The units turn to face the target, and then move towards it. This is by design, but what's not is the several-second gap in the middle- but only the first time the unit is ordered to move. After that it's perfectly responsive.

I don't really understand how this can go wrong- the logic is simple. As you can see, I split most of my processes up into many intermediate variables so that I can debug their values, but the truth is that when I look, they seem fine. For example, the target_heading and current_heading variables are equal (or close to) when the unit is facing the wrong direction, but moving in the right direction. This definitely puzzles me.

Any suggestions as to where I can look for the source of the errors?

• are you displaying the different vectors (look, goal, move vectors). in your problem space is strafing allowed, or is only rotation with forward/backward allowed? Apr 21, 2012 at 21:22
• @gardian06: Only forward movement, right now. Apr 22, 2012 at 11:57