In the first part of the sample the Player class was derived from the GameObject class. This may have seemed unnecessary at the time but what it lets us do now is store a List of GameObject's in the Game class. The Update() and Draw() methods of Player are declared in GameObject as virtual so we don't actually need a reference to a Player object to call the methods. Polymorphism lets us call those methods through the base class. So long as we override these methods where appropriate when creating new objects derived from GameObject then they can be added to our list of GameObject's and updated and drawn correctly.
We now declare a 'List<GameObject> objects' variable in the Game class. So long as an object is derived from GameObject we can add it to the list by using the Add() method, ie. objects.Add(new Player()). Instead of calling player.Draw() and player.Update() in the Game class we loop round all the objects in the 'objects' variable and call their Draw() and Update() methods.
In XNA there is a class called DrawableGameComponent which you can derive your game objects from. It provides Draw() and Update() methods which you can override and will be called at the appropriate time to draw and update the object. This would prevent looping through the objects in the Game class and save a bit of code, so why haven't I done this? The honest answer is that I prefer having more control over the objects.
If we were to pause the game then we'd still want to call the Draw() methods on objects but not the Update() methods. While there is an 'enabled' flag in GameComponent (the class DrawableGameComponent is derived from) you'd have to go through all the objects and set this flag when the user pauses and unpauses. Not a great hassle but I prefer having a flag in the class which maintains the list of objects so I can just skip the step where I update all the objects. This also proved useful when developing Shuggy and I wanted everything to run twice as fast if the user held the action button in certain levels. Using this system I can simply call Update() twice on every object for every call to Game.Update() making all objects move twice for every time they're drawn.
The Update() method has been changed to return a type defined in GameObject, 'UpdateAction'. For now the only purpose of this will be to let the caller know if the object should be deleted. A flag has been added to the GameObject which will cause the appropriate value to be returned by Update() to delete the object.
A method called Hit() has been added which lets two GameObjects be checked against each other to see if they have collided. This just checks against the rectangular boundary of each object. The Player object calls this method on all objects and if a collision is found it calls another virtual method, HitPlayer(). This lets objects easily react if the player has hit them. The method returns a value of 'HitAction' type which can effectively pass a message back to the player object about what happened as a result of the collision. For now the only interesting value that can be passed back is one indicating the player is hurt, ie. he hit an enemy.
Finally, a 'depth' variable has been added that determines the rendering order for objects. This is the same value that gets passed straight down to the SpriteBatch.Draw() call. The value defaults to 0.5f but objects can be moved backwards or forwards in the rendering order by changing the value in their constructor.
The HitPlayer() method is overridden so that we can set the 'Delete' flag in the coin object ensuring that it will be removed from the object list making it appear to get collected.
The Update() method is overridden to allow the Blob to move. Like the player object, we update the 'vector' variable and call the Move() method within GameObject. We can be sure this method does the appropriate collision detection and returns a value indicating if the object collided with a wall in any given direction.
A variable called 'right' is used to remember if the Blob was heading left or right. If this is true then we fix the X component of the vector to a fixed value. If it's false then we set it to minus the same fixed value. After calling the GameObject.Move() method we check if the Blob hit something going either left or right and invert the 'right' variable so it starts heading the other way.
Every frame we increase the Y component of the vector by a fixed amount to simulate gravity. We don't need to worry about setting this to zero when the Blob hits something because the GameObject.Move() method will do this for us.
In order to jump we must be sure that we're on a solid surface. We can do this easily by checking if the GameObject.Move() method returned a value of Direction.Down indicating we'd hit an object below us. This will happen every frame because the object is continually being pulled downwards into the floor by gravity. If this is the case then we will randomly jump every now and then by checking if a random number between 0 and 127 happens to come out at 64. This means the Blob will jump roughly once every 128 frames. The actual jump is started by setting the Y component of the vector to a larger negative value.