Auxiliary class-Breakout game

Source: Internet
Author: User
Breakout games

Good. This chapter has talked about many helper classes, and it is time to use them. Here I will skip the concept phase of the game. breakout is basically just a scaled-down version of the pong game. It only has a single player mode and faces a wall block. Initially, the breakout game was invented by Nolan Bushnell and Steve Wozniak and released by Atari in 1976. In earlier versions, pong games were just a black and white game, but to make it even more exciting, A transparent stripe is mounted to the display to color the bricks (3-13 ).


Figure 3-13

In fact, you will share a similar path by reusing some Pong components and the auxiliary classes learned in this chapter. Breakout is a more complex game than Pong; it has many level levels and has considerable room for improvement. For example, arkanoid is a clone of breakout. In 1980s, many games were based on this idea. They added weapons and better graphic effects, and many different levels where bricks are placed.

As seen in 3-14, the breakoutgame class is constructed in a similar way as the Pong class in the previous chapter. Sprite processing is ignored because the spritehelper class is used now. Some other internal methods and calls are also replaced by some helper classes. For example, the startlevel method generates a new random level value based on the current level value. Here you will use the randomhelper class to generate these random values.


Figure 3-14

Note that many test methods can be seen in this class. In the next chapter, we will make some similar improvements to the helper classes. In the next chapter, we will introduce the basegame class and the testgame class of the class for processing the game class, especially the unit test class, which becomes simpler and more organized.

Take a look at Figure 3-15 and have a quick overview of the breakout game to be developed in the next few pages. It is quite interesting and certainly more playable than pong games. In any case, pong games are only interesting when two people play. Audio.


Figure 3-15

Unit Test in breakout

Copy/pasteCodeBefore using new helper classes and creating new game elements, consider the game and the problems you may encounter. Of course, you can move on and implement the game, but it may be much more difficult in the future, such as detection collision, which is the most difficult part of the game. Unit testing helps you solve the problem by at least providing a simple way to check all the basic parts of the game, help you organize code, and force you to write only what you really need. Just as before, start with the most intuitive part of the game, test it, and add more unit tests until you have completed them, finally, combine everything and test the final game.

The following is an overview of the key points of unit testing in breakout games. More in this chapter is a completeSource code. You do not have the testgame class, so you still have to use the same unit test that you used in the previous chapter. Check the next chapter for a better way to perform static unit testing. You only have three unit tests, but they will be used and modified many times, as I did when implementing the game.

    • Testsounds-It's just a quick test to check all the new sound files in the project. Press space, ALT, control, and shift to play the sound. I added a small pause before playing the next sound, which makes it easier to hear clearly. This test is used to check the xact project created for this game.

    • Testgamesprites-This test was initially used to test the spritehelper class, but later all the code was moved to the draw method of the game class. This test is also used to initialize all bricks in the game; this part of the code is moved to the constructor and will be shown at the end of this chapter. This tells you that the complex test at the end is not important, because the test now only has four lines of code, the focus is to use the test to make it easier for you to write a game. Whenever necessary, you can copy/paste useful parts of unit testing into your code. Static unit tests do not need to be as complete as a helper dynamic unit test, because you only use them when building and testing a game. When the game is running, you no longer need these static unit tests unless the test part of the game is needed later.

    • Testballcollisions-As with the collision detection ball in the previous chapter, it is the most useful unit test. Here, you need to check whether a collision occurs on the screen edge and the ball board as expected. To do this, you only need some minor changes. Then there is a more complex brick collision code, which will be described in detail later. You may even come up with more ways to detect collisions. If you like, you can also improve the game. For example, it makes sense to launch a ball behind a brick wall and see if it can correctly break all bricks.

Breakout level

Because you need to use a lot of ready-made things in pong games, you can skip similar or identical code. For now, you should pay attention to the new variables:

 ///  // how many block columns and rows are displayed? ///  const int numofcolumns = 14, numofrows = 12; //  // current paddle positions, 0 means left, 1 means right. ///  float paddleposition = 0.5f; //  // level we are in and the current score. ///  int level = 0, score =-1; //  // all blocks of the current play field. if they are // All cleared, we advance to the next level. ///  bool [,] blocks = new bool [numofcolumns, numofrows]; //  // block positions for each block we have, initialized in initialize (). ///  vector2 [,] blockpositions = new vector2 [numofcolumns, numofrows]; //  // bounding boxes for each of the blocks, also precalculated and // checked each frame if the ball collides with one of the blocks. ///  boundingbox [,] blockboxes = new boundingbox [numofcolumns, numofrows]; 

First, you define the number of columns of bricks and the maximum number of bricks you can have. At the first level, no bricks are filled, and only 10% of the maximum number of bricks is used. Playing on the board is easier than playing on Pong because you only have one player. Then save the level and score of the current game. These are new content. In pong games, each player has only three balls. If all the balls are lost, the game is over. In breakout, a player starts from level 1 until the player finally loses the ball and can continuously upgrade up. There is no high score or any game font, so the level and score are directly updated on the title bar of the window.

Next, define all bricks. The most important array is blocks, which will tell you which bricks are currently used. Blocks is initialized before each level starts. However, blockpositions and blockboxes are initialized only once in the game class constructor. blockpositions are used to determine the central position of the bricks to be rendered, blockboxes is the bounding box used to determine the collision detection of bricks ). Note that neither these arrays nor positional values use the screen coordinate system. All location data is saved in the format of 0-1: 0 indicates the left or top, and 1 indicates the right or bottom. This method makes the game independent of resolution and makes rendering and Collision Detection easier.

The level is generated in the startlevel method. This method is called at the beginning of the game and each upgrade:

 void startlevel () {// randomize levels, but make it more harder each level for (INT y = 0; y 
  

In the first for loop, you just refill the value of the entire brick array at the level. In Level 1, the level value is set to 0 and only 10% bricks are filled. The randomhelper. getrandomint (10) method returns a value in the range of 0-9, so that the probability of being less than 1 is only 10%. In Level 1, this probability increases to 20% until you reach level 10 or higher, that is, 100%. In fact, there is no upper limit for the game. You can keep playing as long as you want to play it.

Then, you can clear the bricks from the bottom three lines to make it easier for the game to start. In Level 3, only two rows are removed. In Level 5, only one row is removed until level 7 uses all rows.

Unlike Pong, the speed vector of the ball at the beginning of the new game. The ball stays on the ball Board until the user presses the space or a key. Then the ball moves toward a random position, and the ball moves back and forth between the brick wall, the screen boundary, and the ball Board until all the bricks are broken and the players pass through, or the player fails to get the ball.

Finally, update the title bar of the window to display the number of levels and scores that players have reached so far. In this very simple game, each time a player breaks a brick, he gets only one point. It is great to score 100 points. But as I said before, there are no limits on games. Try to get a higher score to experience the joy of the game.

Game loop

In Pong, the game loop is very simple, mainly including user input and collision detection code. Breakout is a little more complicated, because you have to deal with the two States of the ball. One is that the ball stays on the ball board, waiting for the user to press the Space key; the other is that the game is in progress, the collision between the ball and the boundary of the screen, the ball board, and each brick must be detected.

Most of the Code in the update method looks like in the previous chapter; the Code for processing the second player is deleted, and some new code is added at the bottom:

// Game not started yet? Then put ball on paddle. if (pressspacetostart) {ballposition = new vector2 (paddleposition, 0.95f-0.035f); // handle space if (Keyboard. iskeydown (keys. space) | gamepad. buttons. A = buttonstate. pressed) {startnewball ();} // If} // ifelse {// check collisions checkballcollisions (movefactorpersecond ); // update Ball Position and bounce off the borders ballposition + = ballspeedvector * movefactorp Ersecond * ballspeedmultiplicator; // ball lost? If (ballposition. y> 0.985f) {// play sound soundbank. playcue ("pongballlost"); // game over, reset to level 0 level = 0; startlevel (); // show lost message lostgame = true ;} // If // check if all blocks are killed and if we won this level bool allblockskilled = true; For (INT y = 0; y <numofrows; y ++) for (INT x = 0; x <numofcolumns; X ++) if (blocks [x, y]) {allblockskilled = false; break ;} // For if // we won, start next level if (allblockskilled = true) {// play sound soundbank. playcue ("breakoutvictory"); lostgame = false; level ++; startlevel () ;}// if} // else

First, check whether the ball is not started. If the position of the ball is not changed, place it in the center of the player's ball board. Then check whether the Space key or key A is pressed to start the ball at the same time (you only need to randomize the value of ballspeedvector and the ball is directed to the brick wall ).

The most important method is checkballcollisions, which will be checked later. Then update the ball as in pong game and check whether the ball is not received. If the player does not receive the ball, the game ends, and the player can start again from level 1.

Finally, check whether all bricks are broken and the levels are completed. If all the bricks are broken, play the winning sound and start the next level. A "You won!" message appears on the screen !" (See the draw method). Press the Space key to enter the next level.

Draw game

Thanks to the spritehelper class, the draw method of breakout games has become concise:

Protected override void draw (gametime) {// render background. render (); spritehelper. drawsprites (width, height); // render all game graphics paddle. rendercentered (paddleposition, 0.95f); ball. rendercentered (ballposition); // render all blocks for (INT y = 0; y <numofrows; y ++) for (INT x = 0; x <numofcolumns; X ++) if (blocks [x, y]) block. rendercentered (blockpositions [x, y]); If (pressspacetostart & score> = 0) {If (lostgame) youlost. rendercentered (0.5f, 0.65f, 2); else youwon. rendercentered (0.5f, 0.65f, 2);} // If // draw all sprites on the screen spritehelper. drawsprites (width, height); base. draw (gametime);} // draw (gametime)

Starts from rendering the background. You do not need to clear the background because the background texture fills the entire background. To ensure that all game elements are rendered on the background, you need to draw the background immediately before rendering other game genie.

Next, draw the ball and ball, because the rendercentered method in the spritehelper helper class is used, this operation is very simple, the operation is as follows: (this method has three overloaded versions, as long as you use the most convenient)

Public void rendercentered (float X, float y, float scale) {render (New rectangle (INT) (x * 1024-scale * gfxrect. width/2), (INT) (y * 768-scale * gfxrect. height/2), (INT) (scale * gfxrect. width), (INT) (scale * gfxrect. height);} // rendercentered (x, y) Public void rendercentered (float X, float y) {rendercentered (X, Y, 1 );} // rendercentered (x, y) Public void rendercentered (vector2 POS) {rendercentered (POS. x, POS. y);} // rendercentered (POS)

The rendercentered method receives a vector2-type parameter, or two float-type parameters x and y in the format of 0-1 (the format you used in the game) zoom back to the 1024x768 resolution. Then, the draw method of the spritehelper class scales everything from the 1024x768 resolution to the current screen resolution. This may sound complicated, but it is easy to use.

Next, all the bricks in this level will be rendered, thanks to the fact that the positions of the bricks have been computed in the game constructor. Let's take a look at the code, which is about how to initialize the brick position on the top of the screen:

// Init all blocks, set positions and bounding boxesfor (INT y = 0; y <numofrows; y ++) for (INT x = 0; x <numofcolumns; X ++) {blockpositions [x, y] = new vector2 (0.05f + 0.9f * x/(float) (numofcolumns-1), 0.066f + 0.5f * Y/(float) (numofrows-1); vector3 Pos = new vector3 (blockpositions [x, y], 0); vector3 blocksize = new vector3 (gameblockrect. x/1024366f, gameblockrect. y/768, 0); blockboxes [x, y] = new boundingbox (POS-blocksize/2, POS + blocksize/2);} //

The boundary box variable blockboxes is used for collision detection, which will be discussed later. Location calculation is not a big deal. The X coordinate ranges from 0.05 to 0.95, which is based on the number of columns you own (if you remember correctly, it is 14 columns ). You can also try to change the value of the constant numofcolumns to 20, so there will be more bricks in the scenario.

Finally, if the player upgrades or loses, the corresponding message will be rendered on the screen. Then, call the drawsprites method of the spritehelper class to render all game elements and output them to the screen. Let's see how bricks, balls, and game information are rendered in the unit test. I started from the unit test before I realized the game.

Collision Detection

Breakout collision detection is a little more complex than pong games that detect rackets and screen borders. The most complicated part is that the ball correctly rebounded when hitting the bricks. For the complete detection code, see the source code in this chapter.

Like the previous game, there is also a ball with a bounding box, a screen boundary, and a ball board. Bricks are new elements. To detect each collision, you must detect all bricks at each frame. 3-16 is an example of a collision between bricks in the game:


Figure 3-16

Let's take a closer look at the basic collision code of bricks. The collision detection of screen boundary and ball board is very similar to that in pong games, and can be checked using testballcollisions unit tests. To detect the collision of bricks, you need to traverse all bricks repeatedly and check whether the ball boundary box has collided with the boundary boxes of these bricks. The actual game code is a little more complicated, because it needs to detect which side hits the boundary box and which direction the ball must rebound, but the rest of the code and the main idea are still the same.

 
// Ball hits any block? For (INT y = 0; y <numofrows; y ++) for (INT x = 0; x <numofcolumns; X ++) if (blocks [x, y]) {// collision check if (ballbox. intersects (blockboxes [x, y]) {// kill block blocks [x, y] = false; // Add score ++; // update title window. title = "xnabreakout-level" + (LEVEL + 1) + "-Score" + score; // play sound soundbank. playcue ("breakoutblockkill"); // bounce ball back ballspeedvector =-ballspeedvector; // go outta here, only handle 1 block at a time break ;} // If} // For if

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.