Thursday, November 12, 2015

Collision Avoidance for Vehicles in Unreal Engine 4

Now that we can successfully select a group of vehicles and send them to a destination together, we've exposed another issue: they are blissfully unaware of each other and collide like a demolition derby.  Not a bad tactic against an enemy, but not helpful alongside your allies.

Collision Avoidance

Fernando Bevilacqua has a fantastic series on Understanding Steering Behaviors.  While his code generates forces on sprites and doesn't directly apply to our throttle/steering controls, the theory is still applicable.

One of the beautiful features of Fernando's approach is that all of his steering behaviors are cumulative and combine to create fluid motion.  We'll do the same by injecting a collision avoidance check after the vehicle calculates its navigation controls.  This means it will avoid collisions when necessary but will resume traveling toward its destination otherwise.

Based on Fernando's Collision Avoidance tutorial, we need to keep the following in mind:
  • Analyze the most threatening obstacle
  • Longer look-ahead length causes earlier reactions
  • Detect a potential collision
  • Apply an avoidance force
Fortunately, Unreal makes the first three easy to implement with LineTraceByChannel().

The scissors in Unreal's Swiss Army Knife.

Setting the End vector to some distance ahead will return a boolean if there's an obstacle.  I once again made use of GetForwardSpeed() as the look-ahead length for simplicity.  The faster the vehicle is traveling, the farther ahead it needs to check for obstacles to react to.

After experimentation, I projected two collision "sensors" on either side of the vehicle.  When only one is used, slight angle differences between nearby vehicles may not trace a hit yet still collide:

Looks almost like tracer fire from side-mounted weapons...

As for "applying an avoidance force", our limited control options of throttle or steering become a blessing in disguise as we're reduced to two options to react: slow down or turn away.

Slowing down was simple to implement: set the throttle to -1.  As soon as the obstacle is out of range, pathfinding resumes and they speed up again on their own.  While this did reduce the number of collisions, it also caused the vehicles to spread out into a long line.

Steering away was only slightly more complicated.  In this case, both sensors were necessary to decide which way to turn: away from the side closest to the detected collision.  Also an improved reduction of collisions, but they could be going too fast to avoid a collision despite turning.

So implementing both became necessary and avoided most collisions while keeping them relatively close together:

The collision counter at the top of the preview is with avoidance disabled...

Getting Unstuck

While we're injecting safety checks, there's another that's desperately needed: getting unstuck when rammed against a wall or another vehicle.

This was simply a series of branches, basically the same thing you would do actually driving:
  • If I'm not stuck, constantly reset a StuckTimer
  • If my throttle is not 0 but my velocity (nearly) is 0, then I could be stuck; watch the StuckTimer
  • If I'm still not moving after 1 second, set Throttle and Steering opposite to whatever I was doing
  • After 1 second of doing the opposite, I'm not stuck
Our AI routine still looks manageable:

Our vehicles are fairly autonomous, so the last thing to implement before "Guns!" is enemy detection.

No comments:

Post a Comment