Remember that, when tweaking one particular game mode, it saves time to have the Pop program start up in the game mode that you want to play with. The way to control this is to edit the CPopDoc constructor in popdoc.cpp . Do it now, it'll save you a lot of clicking later on. So make your startup game be cGameAirhockey or, if you've taken the trouble to make new files and change the names , cGameBasketball .
Exercise 16.1: Better hitting and other tweaks
It feels a bit cumbersome hitting the puck with the player. It would probably be easier if you make the player smaller. Try using a setRadius call in its constructor to make it smaller. In doing this you reduce the mass of the player (normally equal to the density times the radius cubed), so to keep this up, increase the density as well, using a setDensity call.
It would be nice have a sound effect when you hit the ball. You can do this by overriding the player's collide method similar to the way in which we override it in the Gamestub code, though here all we want to do is make a noise when colliding with the puck and not change health or score in the collide .
It might be better to have the game world a little bigger.
Make sure you have the maximum speeds and the frictions tweaked to good values.
Exercise 16.2: More players
How about giving your game another opponent , call it, say, * _phockeyrobot2 . See how this works. You should initialize them to start at different positions, and to go to different positions in any reset calls, otherwise they may stay on top of each other.
Really it would be better to have the teammates' behaviors be quite different. One could guard the goal, say, while the other pressed forward. One way to do this would be to have the phockeyrobot2 be an instance of a different class called, say, cCritterHockeyRobot2 , perhaps a child class of cCritterHockeyRobot and to give it a different update method. Another approach might be to make the robots' behavior depend on a nicely packaged set of parameters; rather than having several separate parameters, we could encapsulate them in a cRobotParam helper class.
In any case, as you add players, you will probably want to make the _border larger so the hockey robots have more room. Can you have more than two of them? How about adding some hockey robots to your own team?
Let's do a series of exercises to turn the Airhockey game into a Basketball game. You can either change the Airhockey game, or if you want to keep that one around, you can copy the gameairhockey.* files to gamebasketball.* files, adding the new files to the project, and then going through and changing the various capitalization forms of 'airhockey' to ' basketball ' in the two files as was discussed in Exercise 3.7: Renaming a game.
For the purposes of the following exercises, we'll assume you took the easier route and are working directly on the Airhockey game.
Exercise 16.3: Position the goals like baskets
Change the cGameAirhockey::cGameAirhockey constructor code. Make _border have a larger y size than before. And position the two cCritterHockeyGoal objects so that they're higher up, horizontal, and with their open sides facing up.
Exercise 16.4: Another kind of basket
If the wall-type baskets are too hard to get a ball into, make a new kind of Basket class which overrides its collide method to use a contains(pcritter) call so as to only report a collision when the pcritter is entirely inside it. So as to let this Basket control the collisions, give it a higher _collidepriority than the puck or ball. Test to see which kind of basket makes for better game play, that is, play poised at the interesting border between too easy and too hard.
Exercise 16.5: Add gravity and friction
Now add gravity and friction so that it's harder to hit the ball up into the goals. See how the game works if you give your player a cListenerCar or cListenerSpaceship , so that it's sensitive to the gravity (the other kinds of listeners zero out any forces acting on the player). The following lines have been tested to good effect in another game.
setMaxspeed(40.0); /* For Scooter and Car to be able to WHACK the balls. */ setListener(new cListenerSpaceship()); //Or use ...Car()); setListenerAcceleration(80.0); /* So Car or Spaceship can overcome gravity. */ addForce(new cForceGravity()); /* Uses default gravity strength 25. Gravity won't affect player using cListenerCursor, but will with cListenerCar. */ addForce(new cForceDrag(2.5)); /* Stronger than default friction strength 0.5. Have such big friction to make player less hyper. */ setBounciness(0.9); /* Not 1.0 means it loses a bit of energy with each bounce. */ setRadius(cCritter::PLAYERRADIUS/2.0); /* Lets make radius half as big so it can dig under guys better. But then we better make the density 8 times as big, so that its volume mass stays the same. */ setDensity(8.0 * density());
Also be sure to use something like setBounciness(0.9) on the puck, otherwise it bounces around too much.
How does the robot player perform with gravity? Change its update method to make it play better.
Exercise 16.6: Basketball
Now try having more players as discussed in Exercise 16.2. You may find it frustrating to try and hit the basketball just with a spherical player. What if you have your player inherit from cCritterWall ? You could then either always adjust the wall to be at right angles to the current direction of motion, or you could create a richer kind of listener that lets you rotate the wall. A good combination might be to use the mouse to move the player and to use the left and right mouse buttons or Left and Right Arrow keys to rotate the player.
Exercise 16.7: Make a tennis game
Make a player that is a child of cCritterWall and which hits things like a paddle. Give it a listener that makes it possible to rotate the paddle with the Arrow keys or with left/right mouse clicks. Put a short vertical wall in the middle for a net.