🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Should units actually move during the AI logic, or separately?

Started by
3 comments, last by SyncViews 4 years, 4 months ago

Currently my general logic for anything from turrets to fully mobile units is to do the movement as pay of the logic so can act of it. E.g. a simple form of the turret logic might be:

update_turret ()
{
  if (!_target || ! can_hit_target ())
    select_target();
  if (!_target) // give up
  {
    turn_towards(_idle_dir); //actually move
  }
  else
  {
    auto wanted_dir = direction(_pos, _target->pos());
    turn_towards(wanted_dir);
    if (_dir == wanted_dir) // move
      shoot();
  }
}

Where `turn_towards` considers the current and desired direction, max turn rate, etc.

For fully mobile units there are a bunch of methods mostly calling a `move_speed(speed, direction)` to try and turn and accelerate to a desired speed and direction.

This seems to work OK, but it scatters the actual movement around generally between some kind of pick target or destination logic, and deciding on shooting or other actions. And I had a few bugs because of that scattering, call the move function multiple times and break the speed limits, not call it at all on some path and it will instantly stop, both while still having a velocity value that now doesn't match. A `has_moved` flag fixes this.

So is this a good approach or am I just don't a hole with it?

I did consider having the AI just set a “desired speed” and “desired direction” and let a physics loop actually do that. But then not sure how to handle the second part of the logic. Loop over all such entities another time? But then all units including the target have moved, so things like `dir == wanted_dir` need some tolerance to account for that, and at close range change of angle due to movement could be fast higher than at longer distances.

Advertisement

SyncViews said:

Loop over all such entities another time? But then all units including the target have moved, so things like `dir == wanted_dir` need some tolerance to account for that, and at close range change of angle due to movement could be fast higher than at longer distances.

In reality if a natural I commands a tank that is what would happen. I mean you are free to run two threads (goroutines): One for ai and one for simulation of handle → turrent movement and then send data via volatile.

I do not understand the problems. We are not talking about making a game fun here, aren't we? So using reality as an argument is okay this time and in this forum?

There is hardly ever a “should” that must be answered “yes”, unless you're talking basic sanity, like “should true ≠ false?”

In other words, the answer is "nope, it's your choice”. The fun with programming is that a solution can work in one situation, and fail if you change requirements a little bit. You seem to have found relevant new requirements, the next step is what you're doing somewhat, finding a way to fold your requirements into the program.

Perhaps if you take a step back, and think what goes where from a distance may work. I can see 3 different systems at work: a) finding targets in the environment, b) turning the turret around, c) fire!

So how do these things interact with each other and with their surrounding systems?

Trying to use proper quotes on my phone is breaking and losing replies…

There is hardly ever a “should” that must be answered “yes”, unless you're talking basic sanity, like “should true ≠ false?”

In other words, the answer is "nope, it's your choice”. The fun with programming is that a solution can work in one situation, and fail if you change requirements a little bit.

Well so my concern with the current solution is if there is a bunch of well known flaws I'll find down the road. Needing the `has_mov9ve flag for example to avoid the double or no move feels like one for example.

Perhaps if you take a step back, and think what goes where from a distance may work. I can see 3 different systems at work: a) finding targets in the environment, b) turning the turret around, c) fire!

So yes deciding what to do and it actually happening feel separate, but then in real life don't think in steps anyway. E.g. where exactly should the “"shoo” go if I split them up?

If I move the `pos += vel` to it's own loop, should I also move `vel += acceleration` and similar for direction and turn rate?

One concern there is dealing with “precision movement”. Right now it is easy to have it be precise and then do a “direction == direction to target” type check, but if everything moves that will likely be false. So then what tolerance to use, at very long ranges a sniper will miss if even a few degrees off, but maybe a very small tolerance will work.

Edit:

Which having looked at coding, ends up largely similar, but with the logic split in half. Is this how it might be done of using full physics that had to happen in its own physics step?

void update_turret_before_physics ()
{
  if (!_target || ! can_hit_target ())
    select_target();
  if (!_target) // give up
  {
    _wanted_dir = _idle_dir; // turn later
  }
  else
  {
    _wanted_dir = direction(_pos, _target->pos()); // turn later
  }
}
void update_turret_after_physics()
{
    if (target && can_hit_target())
    {
        auto wanted_dir = direction(_pos, target→pos());
        if (angle_between(_dir, wanted_dir) <= tolerance)
            shoot(); // create projectile entity if ready
    }
}

This topic is closed to new replies.

Advertisement