The EnemiesThe enemies in the game aren't the smartest guys in the universe, but they get the job done. For the most part they use the more introductory AI methods, such as deterministic logic and FSMs (finite state machines). However, there are a couple of cool techniques that I used for tracking algorithms. You'll see this later in the chapter when I show you the code that makes the predator mines home in on the player's position. Anyway, take a look at how each enemy was created and implemented. The OutpostsThe model I used for the outposts was probably the most complex 3D model in the whole game. It took me hours to build the model. The bummer is that the 3D model has a ton of detail, as shown in Figures 15.7 and 15.8, but I lost all that detail when I rendered the model and shrank it down. Figure 15.7. The 3D model for an outpost.Figure 15.8. A rendered outpost.Anyway, the outposts don't do much except sit there and rotate. They have no weapons, no AI, nothing. However, they can detect damage, and when the player fires on them they will start to explode. Particles and secondary explosions will occur until the damage level of the outpost is so great that it explodes! The Predator MinesThe predator mines are the protectors of the outposts. They hold position nearby until you get within a specified range, and then they turn on and track you. The predator mines were rendered with TS4 and are shown in Figures 15.9 and 15.10. Figure 15.9. The 3D model for a predator mine.Figure 15.10. A rendered predator mine.I wasn't very happy with the final 3D model for them. Actually, I created another 3D model, shown in Figure 15.11, but it looked more like a stationary mine than something that could attack you. Figure 15.11. Another predator mine concept.In any case, the AI for the predator mine is simple. It's a finite state machine that starts off in an idle or sleep state. It's activated when you get within a specified range, based on the following define: #define MIN_MINE_ACTIVATION_DIST 250 If the player is within this range of a predator mine, it will activate and track using the vector-tracking algorithm that I described and demonstrated when I covered artificial intelligence and tracking algorithms in Chapter 12, "Making Silicon Think with Artificial Intelligence." The predator mines don't have any weapons; they simply try to track you and detonate near you, causing damage to your ship. The GunshipsThe gunships were modeled in TS4, as shown in Figures 15.12 and 15.13. They were very detailed and looked great until I shrank them down and converted them to the 256-color palette. But that's life. Figure 15.12. The 3D model for a gunship.Figure 15.13. A rendered gunship.The AI for the gunships is simple. They travel on the x-axis at a constant velocity. If they get within a specified distance to the player, they adjust their y-axis position to track the player, but at a slow rate. Hence, the player can always make a quick directional change to get away. The power of the gunships is in their heavy weapons. Each gunship is equipped with three laser cannons that can be fired independently, as shown in Figure 15.14. Figure 15.14. The turret-tracking algorithm for the gunships.The tracking algorithm for the cannons is rather cool. It works by projecting a vector in the direction that the turret is currently pointing, and another vector from the turret to the player's ship. Then the algorithm wants to minimize the distance from the head of the turret to the player's ship, so it tests both clockwise and counterclockwise rotations to see which rotation minimizes the distance and then performs the rotation that minimizes the distance. The algorithm was written without trig or any complex vector calculations, just using a distance calculation and a minimization algorithm. I came up with it by taking into consideration how people's heads track an object. We start turning in the direction of the object, and when we feel that we're looking in the right direction, we start slowing our head's rotation rate and come to a stop. But sometimes we may overshoot and have to readjust. This was the inspiration for the algorithm. Take a look here to see the source for the tracking: // first create a vector point in the direction of the turret // compute current turret vector int tdir1 = gunships[index].varsI[INDEX_GUNSHIP_TURRET]; float d1x = gunships[index].varsI[INDEX_WORLD_X] + cos_look16[tdir1]*32; float d1y = gunships[index].varsI[INDEX_WORLD_Y] + sin_look16[tdir1]*32; // compute turret vector plus one int tdir2 = gunships[index].varsI[INDEX_GUNSHIP_TURRET]+1; if (tdir2 > 15) tdir2 = 0; float d2x = gunships[index].varsI[INDEX_WORLD_X] + cos_look16[tdir2]*32; float d2y = gunships[index].varsI[INDEX_WORLD_Y] + sin_look16[tdir2]*32; // compute turret vector minus one int tdir0 = gunships[index].varsI[INDEX_GUNSHIP_TURRET]-1; if (tdir0 < 0) tdir0=15; float d0x = gunships[index].varsI[INDEX_WORLD_X] + cos_look16[tdir0]*32; float d0y = gunships[index].varsI[INDEX_WORLD_Y] + sin_look16[tdir0]*32; // now find the min dist float dist0 = Fast_Distance_2D(player_x - d0x, player_y - d0y); float dist1 = Fast_Distance_2D(player_x - d1x, player_y - d1y); float dist2 = Fast_Distance_2D(player_x - d2x, player_y - d2y); if (dist0 < dist2 && dist0 < dist1) { // the negative direction is best gunships[index].varsI[INDEX_GUNSHIP_TURRET] = tdir0; } // end if else if (dist2 < dist0 && dist2 < dist1) { // the positive direction is best gunships[index].varsI[INDEX_GUNSHIP_TURRET] = tdir2; } // end if TIP You'll notice that I am using a lot of distance calculations. However, they're based on the Fast_Distance2D() function, so they're very fast and amount to nothing more than a couple of shifts and adds. |