Enter villains, Stage Left


Nearly every computer game has villains. For some reason, Earth is the one planet in the entire universe that every alien wants. There doesn't seem to be any shortage of life forms that want to have this world as their own. Invasion of the Slugwroths is no exception. The Slugwroths have established bases on Earth that must be cleaned out by Captain Chloride. How they managed to establish their bases in the first place is a mystery, but there you have it. What can the Captain do but load his salt shooter and embark on his solitary quest to free Earth?

Designing a Simple Slugwroth

We won't implement Captain Chloride's salt shooter; I'll keep the elimination of the Slugwroths basic for the purposes of this book. Later in this chapter I'll explain how you can set the salt shooter up yourself. To kill Slugwroths, I made them stationary until the Captain bumps them. When he does, they chase him out of the base. He kills them by making them collide with the door. This is a simple way of demonstrating the same techniques needed to create a salt shooter that kills Slugwroths.

You may be surprised to find that you already know how to implement a class for Slugwroths. Making such a class is just a variation on the techniques I demonstrated for creating Captain Chloride himself. This is very evident in the class definition, which is shown in listing 18.1.

Listing 18.1. The class that represents Slugwroths

 1   class slug : public world_object 2   { 3   public: 4       // This Slugwroth will go from one state to another 5       // depending on Captain Chloride's actions. 6       enum state 7       { 8           STATE_ASLEEP, 9           STATE_CHASING 10      }; 11 12      slug(); 13 14      std::string Type(); 15 16      bool Update( 17          invasion *theGame); 18 19      bool Render( 20          invasion *theGame); 21 22     // If something wakes me up, I will chase it! 23     void WakeUp( 24         world_object *waker); 25 26     void Kill(); 27 28    // If I walk into something, I will stop. 29    void Hit( 30        world_object &stationary); 31 32   private: 33      slug::state currState; 34      vectorf velocity; 35 36   public: 37       animated_sprite myAnims; 38   }; 

Like Captain Chloride, Slugwroths can have more than one state. They are either stationary, which I refer to as being asleep, or they are chasing the Captain. The slug class defines these two states in an enumeration on lines 610.

The slug class contains the functions you probably expect by now. Specifically, it has the Type(), Update(), and Render() functions. In addition, the class has a function to tell the Slugwroth to wake up and chase the Captain. It also contains a Kill() function that the program uses to kill the Slugwroth. The Slugwroth's animations are stored in its myAnims data member.

Warning

As with classes in chapter 17, the slug class contains a public data member. This is not how professional programs are written. I did this to simplify the code. If you do this in a game company, your coworkers may wonder how well you understand the concepts behind objectoriented programming. Seriously.


Implementing the Slugwroth Class

The functions for the slug class, which are shown in Listing 18.2, are fairly straightforward. You'll find them in the file Slug.cpp, which is in the folder Source\Chapter18\Prog_18_01.

Listing 18.2. The member functions of the slug class

 1   const float SPEED = 10.0; 2 3   const int ANIM_WALK_LEFT = 0; 4   const int ANIM_WALK_RIGHT = 1; 5 6   slug::slug() : 7       currState(STATE_ASLEEP) 8   { 9   } 10 11   bool 12   slug::Update( 13       invasion *theGame) 14   { 15       switch(currState) 16       { 17           case STATE_ASLEEP: 18               // Slugwroths are strange creatures and 19               // prefer to sleep facing to the right! 20               myAnims.CurrentAnimation(ANIM_WALK_RIGHT); 21           break; 22 23           case STATE_CHASING: 24                myAnims.CurrentAnimation(ANIM_WALK_LEFT); 25                worldPos += velocity; 26                theGame>CollisionCheck(*this); 27           break; 28 29           default: 30               ASSERT(0); //Unhandled state! 31           break; 32        } 33 34        return (true); 35   } 36 37   bool 38   slug::Render( 39       invasion *theGame) 40   { 41       bool renderOK = true; 42 43       vector screenPos; 44       theGame>WorldToScreen(worldPos, screenPos); 45       myAnims.X(screenPos.X()); 46       myAnims.Y(screenPos.Y()); 47       renderOK = myAnims.Render(); 48 49       return (renderOK); 50   } 51 52   void 53   slug::WakeUp( 54       world_object *waker) 55   { 56       // We wake up and follow whatever hit us. 57       currState = STATE_CHASING; 58       if (waker>WorldX() < WorldX()) 59       { 60           // Run to the left. 61           velocity.X(SPEED); 62       } 63       else 64       { 65           // Run to the right. 66           velocity.X(SPEED); 67       } 68   } 69 70   void 71   slug::Kill() 72   { 73      Collidable(false); 74      Visible(false); 75   } 76 77   void 78   slug::Hit( 79       world_object &stationary) 80   { 81       // We hit something. Go back to previous position. 82       worldPos = velocity; 83   } 

There are some interesting things about the way I've written the slug class. The first thing to notice is that it uses a lot of constants instead of numbers. This is always a good idea because it helps make your code more readable to others on your project.

Tip

In professional programs, it's advisable to use as many constants as you can rather than literals like numbers or strings in quotes. This makes your code more readable to other programmers who are working on the game with you. It also helps you remember why you did things the way you did. You'd be surprised how fast you can forget what literals stand for.


The constants defined on lines 14 of Listing 18.2 are not defined in a function. So which functions can access them?

If you define a constant in a .cpp file using the C++ keyword const and you define the constant outside a function, all functions in that file can see and use the constant. The constant is visible from the point it's declared to the end of the file. Functions in other files cannot access the constant.

The constructor on lines 69 of Listing 18.2 initializes the currState data member to STATE_ASLEEP. This makes the Slugwroth stay in one position until it's bumped. The change of state occurs in the Update() function, which appears on lines 1135. Update() begins by checking the current state of the Slugwroth. If it's asleep, Update() displays the Slugwroth in a frozen position facing right. If the Slugwroth is in hot pursuit of Captain Chloride, the Update() function sets the Slugwroth's velocity and performs a collision check.

Recall that the invasion::CollisionCheck() function automatically calls the Hit() function for the object it's checking. The code for the slug::Hit() function begins on line 77. All it does is prevent the Slugwroth from walking through things.

You may wonder how the Slugwroth makes the transition from being asleep to chasing the Captain. That occurs when the Captain bumps into the Slugwroth. The chloride::Hit() function, which is given in listing 18.3, calls the slug:: WakeUp() function. During each frame, slug::Update() moves the Slugwroth and checks for collisions.

Listing 18.3. The chloride::Hit() function

 1   void chloride::Hit( world_object &stationary) 2   { 3       if (stationary.Type() == "door") 4       { 5           door *theDoor = (door*)&stationary; 6 7           if (haveKey) 8           { 9               theDoor>Open( this); 10              // Hold on to the key; the door will close 11              // automatically and we might still need it. 12          } 13 14          // We hit a door. Go back to previous position 15          // and play a sound. 16          worldPos = velocity; 17 18         // Need a way to know if this is still playing 19         // and to not play it again until the current 20         // instance has finished. 21         bonkSound.Play(); 22      } 23      else if (stationary.Type() == "key") 24      { 25          key *theKey = (key*)&stationary; 26          theKey>Visible(false); 27          theKey>Collidable(false); 28          pickupSound.Play(); 29          haveKey = true; 30      } 31      else if (stationary.Type() == "slug") 32      { 33         // We hit a slug. Go back to previous position. 34         worldPos = velocity; 35 36         slug *theSlug = (slug*)&stationary; 37         theSlug>WakeUp( this); 38      } 39   } 

The chloride::Hit() function wakes the Slugwroth so that it can start chasing the Captain. New game programmers often feel that this is an odd approach to things. Shouldn't it be the slug class's job to wake up a Slugwroth when something bumps it?

While that is a logical viewpoint, it's not practical. It's hard to make objects in a game detect when they've been bumped. It's much easier to detect when they bump something. Therefore, when the Captain bumps a Slugwroth, he essentially says to the Slugwroth, "Wake up and chase me." I'll admit it's odd, but it works.

I mentioned at the beginning of this chapter that I'd make the Slugwroth die by running into the door. The door does this in its Hit() function, as shown in listing 18.4.

Listing 18.4. The door::Hit() function

 1   void door::Hit(world_object &stationary) 2   { 3       Open( &stationary); 4 5       // Slugwroths are weak! 6       if (stationary.Type() == "slug") 7       { 8            slug *theSlug = (slug*)&stationary; 9            theSlug>Kill(); 10      } 11   } 

The door can only hit something when the door itself is moving. That means the door is only partially open. Therefore, the door opens itself completely by calling its own Open() function on line 3. If the thing it hit is a Slugwroth, then the door tells the Slugwroth it's dead by calling the slug::Kill() function.

At this point, we're done adding features to Invasion of the Slugwroths. But before I end this book, let's examine how you would move forward with the game if you were actually developing it.



Creating Games in C++(c) A Step-by-Step Guide
Creating Games in C++: A Step-by-Step Guide
ISBN: 0735714347
EAN: 2147483647
Year: N/A
Pages: 148

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net