Making the Door Open and Close


Creating a door that opens and closes is somewhat harder than picking up keys. You might ask why. Go ahead, ask.

That's a good question. The answer is that it's harder because it involves working in more than two dimensions.

Is this the part where I tell you all about 3D programming? In a word, no. Although it takes more than two dimensions to get Captain Chloride to walk through a door, it takes fewer than three.

Huh?

For years, game programmers have used a technique they call 2.5D programming. It's not 2D programming, but it's also not 3D programming. If you run Program 17.2 on the CD, you'll see 2.5D programming in action. When Captain Chloride, who is twodimensional, walks through the open door, he walks in front of the back part of the wall and behind the front part of the wall. All objects in the scene are 2D; however, they are arranged in layers.

Adventures in Two and a Half Dimensions

In 2D programming, the entire scene is painted on the background. This is how things worked in Program 17.1. The image of the door was part of the background. The program just puts a bounding rectangle at the door's position so that Captain Chloride has something to bump into.

To get Captain Chloride to walk through the doorway in a way that looks real, the game has to layer parts of the scene on top of each other. Figures 17.1, 17.2, and 17.3 illustrate what I mean.

Figure 17.1. The Background


Figure 17.1 shows part of the background for Program 17.2. Notice that part of the wall has been cut away. All parts of the scenery remaining in the background are things that Captain Chloride walks in front of. This background goes in a layer underneath the image of the Captain. In other words, the program first renders the background and then renders the Captain. Next it draws the door's image, which is a sprite. Figure 17.2 shows the door's image.

Figure 17.2. The door


Figure 17.2 shows the door with its transparent color. As I mentioned, the door is rendered as a sprite in the same layer as Captain Chloride. Making the door open is just a matter of sliding the sprite upward.

As the Captain walks through the open door, he walks behind the front part of the wall, which you can see in Figure 17.3.

Figure 17.3. The front piece of the wall.


The game draws the front part of the wall in a layer that's in front of Captain Chloride. As a result, the Captain appears to walk through the hole in the wall left when the door opens.

Tricky, don't you think?

Layering 2D images on top of each other in this manner extends 2D programming so that things appear more realistic. It's called 2.5D programming because it involves more than two dimensions and fewer than three.

Two and a Half Dimensional Programming in Action

Programmers have many ways of adding two and a half dimensions to their games. Because there are many approaches, I did not add direct support for 2.5D programming in LlamaWorks2D. I didn't want to limit you to one approach.

There are two techniques for 2.5D programming that are particularly common. Some programmers just make everything a generic sprite and order things in their scenes so that everything is drawn correctly from back to front. Others divide their scenes into distinct layers and assign sprites into the layers.

For beginners, the first technique is easiest. I demonstrate it in Program 17.1. As you move into more advanced programming and your games become more complex, I suggest you try the second technique, which I demonstrate in Program 17.2.

As a first step in implementing layered 2.5D programming, I created an object for the game called scene_sprite. This class is shown in Listing 17.8.

Listing 17.8. The scene_sprite class

 1   class scene_sprite : sprite 2   { 3   public: 4       bool scene_sprite::Render( 5          invasion *theGame); 6 7       void WorldX(float x); 8       float WorldX(); 9 10      void WorldY(float y); 11      float WorldY(); 12 13   private: 14      vectorf worldPos; 15   }; 

The scene_sprite class is a special class for sprites that Captain Chloride can't interact with in any way. The only thing you can do with a scene_sprite object is render it. The XML level file for Program 17.2 contains some XML tags that allocate the front piece of the wall as a scene scene_sprite object and position it correctly in the scene. It covers the back part of the wall, which is part of the background. It also covers the door when the door slides up.

With the scene_sprite class implemented, you can now divide the scene into distinct layers. Instead of having one Render() function like most visible objects in the game, the chloride_level class can now use two. Listing 17.9 gives the code for them.

Listing 17.9. The chloride_level class's rendering functions

 1   bool chloride_level:: RenderBackground( 2       invasion *theGame) 3   { 4       bool renderOK = true; 5 6       scene_sprite *theBackground = 7           (scene_sprite*)allObjects[BACKGROUND]; 8       renderOK = theBackground>Render( theGame); 9 10      return (renderOK); 11   } 12 13 14   bool chloride_level::RenderForeground( 15       invasion *theGame) 16   { 17       bool renderOK = true; 18 19       scene_sprite *theWallFront = 20           (scene_sprite*)allObjects[WALLFRONT]; 21       renderOK = theWallFront>Render( theGame); 22 23       return (renderOK); 24   } 

Recall that under the rules of LlamaWorks2D, the game class normally calls the level class's rendering function. Because Program 17.2 implements layered 2.5D scenery, the invasion::RenderFrame() function first calls the chloride_level::RenderBackground() function. As the function name implies, this renders everything in the background behind the moving objects in the level.

The next step is for the invasion::RenderFrame() function to render everything between the background and foreground. I'll show how this is done shortly.

Finally, invasion::RenderFrame() must call the chloride_level::RenderForeground() function. As Listing 17.9 shows, RenderForeground() renders the front piece of the wall.

The code for the invasion::RenderFrame() function appears in Listing 17.10. As you can see, it performs its rendering in the three distinct layers that I've described.

Listing 17.10. The invasion::RenderFrame() function

 1   bool invasion::RenderFrame() 2   { 3       bool renderOK = currentLevel.RenderBackground(this); 4 5       world_object *oneObject = worldObjects; 6       while( oneObject) 7       { 8           if (renderOK) 9           { 10              if (oneObject>Visible()) 11              { 12                  renderOK = oneObject>Render(this); 13              } 14          } 15          oneObject = oneObject>next; 16      } 17 18      if (renderOK) 19      { 20          renderOK = currentLevel.RenderForeground(this); 21      } 22 23      return (renderOK); 24   } 

As you read Listing 17.10, the RenderFrame() function uses the fact that all of the objects between the background and the foreground are in the linked list. That's because the linked list contains all of the objects that interact with one another. It's precisely those objects that occur between the background and the foreground. Therefore, the RenderFrame() function moves through the linked list and renders each object it finds there.

By calling chloride_level::RenderBackground(), rendering everything in the linked list, and then calling chloride_level::RenderForeground(), the invasion::RenderFrame() function divides everything in the scene into distinct layers.



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