Monday Snaps: Cheese Lander Game Reset

Welcome back to our weekly Snaps session, which has the ultimate aim of creating the awesome gaming experience that is Cheese Lander . Last week we got the bread, cheese and background screen drawing nicely, this week we are going to place the bread and cheese at their starting positions. So, if someone asks you "Who moved the cheese?" you can say it was you.

We're going to start with a bit of gentle re-factoring. Re-factoring is a posh word for "putting things in the place that they should have been from the start". Computer programmers are lucky in this respect. Doing "refactoring" in other professions means moving physical things around. Refactoring a brick wall is hard. But with code it's easy. What I want to do is create some methods that will deal with my game objects. To do this I'm going to have to move the game objects into the enclosing class, so that they are visible to all the methods in that class. 

public class MyProgram
{
    ImageSprite cheese, bread, background;

    void setupSprites()
    {
        SnapsEngine.StartGameEngine(fullScreen: false, framesPerSecond: 60);
        background = new ImageSprite(imageURL: "ms-appx:///Images/Background.png");
        background.Height = SnapsEngine.GameViewportHeight;
        background.Width = SnapsEngine.GameViewportWidth;

        cheese= new ImageSprite(imageURL: "ms-appx:///Images/cheese.png");
       
cheese.ScaleSpriteWidth(SnapsEngine.GameViewportWidth / 20);

        bread = new ImageSprite(imageURL: "ms-appx:///Images/bread.png");
        bread.ScaleSpriteWidth(SnapsEngine.GameViewportWidth / 8);

        SnapsEngine.AddSpriteToGame(background);
        SnapsEngine.AddSpriteToGame(bread);
        SnapsEngine.AddSpriteToGame(
cheese);
    }

    void gameLoop()
    {
        while (true)
        {
            SnapsEngine.DrawGamePage();
        }
    }

    public void StartProgram()
    {
        setupSprites();

        gameLoop();

    }
}

This is my re-factored game class. It now has two methods. One is called setupSprites, and it sets the sprites up. The other is called gameLoop. This runs the game loop (remember that a game is all about repeatedly drawing and updating. I've also renamed the ball object to cheese. It seemed the right thing to do.

Now things are all tidy I can start building up my methods that will make the game work. When the game resets (i.e. at the start of a new game) I want the bread to be placed somewhere on the bottom of the screen. The aim of the game is then to steer the cheese onto the bread. A method called resetBread would seem to make sense. If you're asking why I'm not calling it setupBread, then I hear you. The answer is that I'm being careful with my names here. setup is something that you do once in the lifetime of the program. Reset is something you do at the start of each game. This is just my standard, yours is allowed to be different, as long as you have a standard.

Moving the bread to the bottom of the screen is easy. We just set the bottom of the bread to the height of the screen:

 bread.Bottom = SnapsEngine.GameViewportHeight;

Moving the bread to a random position across the screen is a bit harder. For a start we'll need a random number. We can get random numbers from the Random class in the System namespace. I can create an instance of this in the class for the game to use:

System.Random breadRandom = new System.Random();

I'm going to use a different random number generator for each object that needs random behaviour. This is because that way I can convert any of them to produce the same sequence (simply by adding a seed):

System.Random breadRandom = new System.Random(1);

Now my bread would be placed at the same sequence of positions when the game is played. This is a good idea because it helps the player learn how the game plays, and encourages them to come back and have another go. In the case of the bread, I'll probably make it completely random.

Anyhoo, once I've got my random number generator I can place the bread somewhere random across the width of the screen:

 bread.Left = breadRandom.Next((int)(SnapsEngine.GameViewportWidth - bread.Width));

This code is a bit of a mess to be honest. The Next method of the Random class can generate an integer in a range from 0 to an upper limit. The upper limit I want is the width of the screen minus the width of the bread. I can calculate this, but Snaps graphics work with double precision numbers. So I have to convert the result of this calculation into an integer. 

void resetBread()
{
    bread.Bottom = SnapsEngine.GameViewportHeight;
    bread.Left = breadRandom.Next((int)(SnapsEngine.GameViewportWidth - bread.Width));

}

This is my resetBread method. It places the bread nicely at the bottom of the screen. I can now steal this technology (ooooh, that sounds so cool) to position the cheese at a random position on the top of the screen:

void resetCheese()
{
    cheese.Top = 0;
    cheese.Left = cheeseRandom.Next((int)(SnapsEngine.GameViewportWidth - cheese.Width));
}

After these reset behaviours I have a game screen that looks like this:

The entire program is here:

 using SnapsLibrary;

public class MyProgram
{
    ImageSprite cheese, bread, background;

    void setupSprites()
    {
        SnapsEngine.StartGameEngine(fullScreen: false, framesPerSecond: 60);
        background = new ImageSprite(imageURL: "ms-appx:///Images/Background.png");
        background.Height = SnapsEngine.GameViewportHeight;
        background.Width = SnapsEngine.GameViewportWidth;

        cheese = new ImageSprite(imageURL: "ms-appx:///Images/cheese.png");
        cheese.ScaleSpriteWidth(SnapsEngine.GameViewportWidth / 20);

        bread = new ImageSprite(imageURL: "ms-appx:///Images/bread.png");
        bread.ScaleSpriteWidth(SnapsEngine.GameViewportWidth / 8);

        SnapsEngine.AddSpriteToGame(background);
        SnapsEngine.AddSpriteToGame(bread);
        SnapsEngine.AddSpriteToGame(cheese);
    }

    System.Random breadRandom = new System.Random();

    void resetBread()
    {
        bread.Bottom = SnapsEngine.GameViewportHeight;
        bread.Left = breadRandom.Next((int)(SnapsEngine.GameViewportWidth - bread.Width));

    }
    System.Random cheeseRandom = new System.Random();

    void resetCheese()
    {
        cheese.Top = 0;
        cheese.Left = cheeseRandom.Next((int)(SnapsEngine.GameViewportWidth - cheese.Width));
    }

    void gameLoop()
    {
        while (true)
        {
            SnapsEngine.DrawGamePage();
        }
    }

    public void StartProgram()
    {
        setupSprites();

        resetBread();

        resetCheese();

        gameLoop();

    }
}

Come back next week for more. And remember that you can get the full details of gaming with Snaps from my book: