Skip to main content

AI Controller Update - Week ending 7/11

This week I worked on improving finding cover objects. The first thing I did was to go back and tag all the cover seekable objects as such. Without this, the problem is that objects such as walls and such might be detected as cover objects as they satisfy the width and height requirements.
Then, I stuck with the sphere trace implementation where a sphere cast would be performed to find the closest cover object. I compared the tag and found the closest one. Then, I changed the implementation to use Seek rather than Arrive, as realistically one wouldn’t slow down going into cover. This also removed some visual artifacts I was having with very slow movement over small distances with Arrive. The updated code to find the best hiding spot looks like this:

if (UKismetSystemLibrary::SphereTraceMulti(
              GetWorld(),
              pOwner->GetActorLocation(),
              pOwner->GetActorLocation(),
              CoverSearchRadius,
              TQuery,
              false,
              ActorsToIgnore,
              EDrawDebugTrace::ForOneFrame,
              OutHits,
              true))
       {
              // Find closest object
              FHitResult ClosestHit;
              ClosestHit.Distance = CoverSearchRadius;
              for (auto Hit : OutHits)
              {
                     // Make sure object is not under me or over me
                     if (Hit.GetActor()->ActorHasTag(CoverTag) && Hit.Distance < ClosestHit.Distance && IsHiddenBy(Hit.GetActor()))
                     {
                           ClosestHit = Hit;
                     }
              }

              if (ClosestHit.GetActor())
              {
                     // Seek works better than Arrive here, and also it's probably better
                     // since one won't "arrive" to a hiding spot - you'll probably run
                     // full velocity there
                     return Seek(GetHidingSpot(ClosestHit.GetActor(), Target->GetActorLocation()));
              }
       }

       return Evade(Target);

Now, there are a few things to consider. The closest cover object might not actually have the closest hiding spot. In that case, should we calculate all the hiding spots of nearby objects and then get the closest hiding spot from that? Might that be a little expensive? These are all questions to be answered.
Next, I started implementing my own Pathfinding. However, this proved to be more frustrating than expected, owing to the fact that Unreal doesn’t have it’s native implementation of Navigation yet, it uses Recast/Detour, and converting back and forth between the two systems is quite a pain. In order for me to create the navigation graph myself, I would have to implement a bounding volume and point detection inside of that myself, and that seems rather out of the scope of this project.

I’m currently trying to integrate my implementation with the existing interfaces, and that is proving to be taking a long time.

Find the source code here: https://github.com/GTAddict/UnrealAIPlugin/

Comments

Popular posts from this blog

AI Controller Update - Week ending 7/4

This week, I worked on Obstacle Avoidance and a slight hint of navigation. Obstacle Avoidance Though the concept is simple enough, the execution is quite tricky. The first part is to detect obstacles in your area. We define a lookahead, which can vary based on the object’s current velocity. I’ve left it at a fixed value for now. Then we raycast forwards to find the first obstacle in our path. Next, we compute the normal from the point of impact. We steer our object away from the point in the direction of the normal. The code looks like this: bool bHit = GetWorld ()-> LineTraceSingleByChannel ( Hit , StartLocation , EndLocation , Channel , QueryParams , ResponseParam );        if ( bHit )        {               FVector PenetratedAlongHit = Hit . ImpactPoint - EndLocation ;               FVector PenetratedAlongNormal = PenetratedAlongHit . ProjectOnToNormal ( Hit . ImpactNormal );               float PenetrationDepth = PenetratedAlongNormal . Size ();

AI Controller Update - Week ending 7/18

This was another landmark week. I was finally able to get navigation meshes working with all the behaviors I’d implemented so far. To see how important this is, let’s consider an example: The follower (the smaller model) needs to get to the target position (the other character in this case). However, there is an obstacle in between. The steering algorithm doesn’t know anything about obstacles. So it will continually push the follower towards the actor, and into the obstacle. With a navmesh, we can tell the steering algorithms to follow a sequence of points in order to reach the target actor. Now, calculating this every frame is very expensive. So what do we do here? First, we raycast to the target position to see whether the follower can reach there uninterrupted. If it can, fantastic. We just ask the follower to seek to the target position. If there isn’t a direct path, we request the navmesh to provide us with a set of points that we store, and then seek to one by one. Wh

AI Controller Update - Week Ending 6/27

Now, this was a week in which some really important work was done. Last week, I wrote about the roadblocks I was facing with writing my own game engine – guaranteeing a smooth game loop, constant frame rate, and float precision. While it is quite easy to build a functional game loop, it is harder to build one that does not break under stress. Somehow my windows framework wasn’t sending regular updates to my main loop, and I spent quite a while scratching my head trying to figure it out. However, time is precious and it was running out. I had to make a decision, and make it quick. I chose to jump into Unreal and port over all my code into Unreal 4.16. Jumping to Unreal I wanted to build a follower behavior, but I also wanted to build it right. So, I made sure to have a component-based architecture from the get-go, and made sure to have the steering behaviors as Actor Components, so that they could be attached to any actor and be reused. The Actor Steering component