Monday Snaps: Steering the Cheese

Welcome to this week's Monday Snap. We're re-creating the game Cheese Lander using the Snaps game framework. You can find earlier episodes here. Last week we put the bread and the cheese at their start positions. This week we're going to get the cheese moving. 

Games work by repeatedly updating the game engine and then re-drawing the display. In a Snaps game we use a C# loop to do this:

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

At the moment the gameLoop method just repeatedly draws the game page. The DrawGamePage method also pauses the loop so that it runs at the selected frame rate, which for our game is 60Hz. I'm going to add a call of a method to update the cheese position.

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

The cheese is controlled by the player. The idea is to land it on the bread. This is my first version of the updateCheese method.

int cheeseXSpeed = 2;
int cheeseYSpeed = 2;

void updateCheese()
{
    if (SnapsEngine.GetRightGamepad())
        cheese.Left += cheeseXSpeed;
    if (SnapsEngine.GetLeftGamepad())
        cheese.Left -= cheeseXSpeed;

    if (SnapsEngine.GetDownGamepad())
        cheese.Top += cheeseYSpeed;
    if (SnapsEngine.GetUpGamepad())
        cheese.Top -= cheeseYSpeed;
}

The SnapsEngine exposes methods that  program can use to test the state of the gamepad.  You can use the cursor keys on the keypad, a connected Xbox 360/Xbox 1 controller. Alternatively you can use the on-screen touchpad with a mouse, lightpen or finger. If any of the methods return true a speed value is used to update the position of the cheese in that axis. Remember that the Y axis goes down the page. Increasing the Y value of the cheese position will move it down the screen. 

This method lets the player move the cheese right off the screen, so perhaps we should fix that. 

if (cheese.Left < 0)
    cheese.Left = 0;
if (cheese.Right > (SnapsEngine.GameViewportWidth))
    cheese.Right = SnapsEngine.GameViewportWidth;

if (cheese.Top < 0)
    cheese.Top = 0;
if (cheese.Bottom > SnapsEngine.GameViewportHeight)
    cheese.
Bottom = SnapsEngine.GameViewportHeight;

These statements "clamp" the cheese movement so that it can't move off the screen. Add them to the updateCheese method after you have updated the cheese position.

You can now steer the cheese around the screen and land it on the bread. Unfortunately this is far too easy. So next week we'll put on our scientists white coats and add some Physics. 

And remember, the Monday Snaps are brought to you by Begin to Code With C#, available from all good booksellers. 

Happy Birthday Me

I'm now officially and properly old. Bus passes beckon. Thank heavens I've still got my youthful good looks (although I've forgotten where I put them).

However, I've just had the most fantastic of birthdays, starting with a trip out for coffee in the morning and then a slap up Sunday Lunch at 1884 Dock Street Kitchen.  They do a roast beef that is just perfect (pro-tip, have the sausage roll snacks as starters, lovely). The meal was a surprise treat, and a great time was had by all. Particularly as a whole bunch of family members turned up, some of whom I wasn't expecting. 

So, we headed home after the meal and I reflected what a great day I'd had. And then it started all over again. The family, who's reputation for subterfuge has gone up several levels, had arranged to fill our house full of friends to do the surprise party thing, even down to the hiding of cars in distant car parks and stealthy arrangement of shoes and coats so that the big reveal was just that.  I had a great time, and we even ordered Domino's Pizza for tea. 

Thanks so much to everyone who attended. We played some games, I blew out some candles, cake was eaten and a wonderful time was had. If this is what birthdays are like when you're sixty, sign me up. 

Tons of Culture in Hull

Oh to be in Hull in the summer time. This summer is astonishing in terms of the range and quantity of goings-on in the city. We wandered up town on Saturday for lunch at Nibble (wonderful place, you should try it) and found ourselves listening to a BBC Prom being broadcast from the stage right next door. Full orchestra action. The city was also alive with a whole bunch of folk acts around the town, numerous Morris Dancers and a Gay Pride march. 

Blimey.

Splatoon 2 is wonderful

Of course I went out and got Splatoon 2 today. Very good game. I enjoyed the first one on the Wii U, and this one keeps up the standard, while adding some great new touches. We've been playing it on full screen TV and it looks lovely. The controls take a bit of getting used to, what with tipping the controller to aim, but I'm getting the hang of it slowly but surely. The single player campaign is fun, there's a new thing called Salmon Run, where a bunch of you collaborate to collect eggs while under attack from a variety of strange and nasty beasts. 

If you have a switch you should get this game.  

The return of nobody else

I was having a conversation about the internet tonight and I was reminded of something I did a while back. I setup a Twitter account called nobody else. The idea is that if you would like to disengage with the platform, just let me know your Twitter username. 

Then you'll get the message "Nobody Else is following you on Twitter", so you can shut down your account and get on with your life. 

The account is still active.  I guess you could follow nobody else too, but I really can't see the point. 

Return of the Kaossilator

The Korg Kaossilator is a nifty device for making weird sound effects. I got one quite a while back and it has provided the sounds for quite a few projects. Today I was working on Begin To Code Python and I needed a suitably awakening tone for an alarm program that I'm writing. So I dug out Mr. Kaoss.

I remember years ago that one of the marketing pitches behind Duracell batteries was that they didn't leak.

That is not the case now. Ugh. But after a thorough clean up we are back in business and making amazing sounds again. If you're interested, the sound I ended up with is here:

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:

 

 

 

 

 

 

Oresome Birthday

I stole this picture off their web site....

We had a significant birthday in the family this week. Ending in zero. No, not mine, that's next week. 

Anyhoo, as a present we organised a session at Oresome in Hull. You start with a strip of silver and finish three hours later with a really nice ring that you made yourself. It turns out that the process is more complex than you might think, and gives you a lot of respect for people who make things like this. 

It seems that the trend today is for experiences rather than just buying stuff. I reckon that this kind of thing does both. They are lovely folk at Oresome and took the trouble to make the event even more special for our lucky birthday person. And apparently you get to use a hammer, which is always good. Strongly recommended.

Bye Bye Windows Phone 8.1

Three and a half years ago I got the best phone I've ever had. A Lumia 1520 running Windows 8. Amazing screen, snappy performance, brilliant battery life, fantastic camera. And now Windows Phone 8 is dead. 

Sigh.

Ten years ago number one son was kind enough to bring me back a first generation iPhone from his travels in the US. It was the cheapest version with only 4G of storage, no 3G, no GPS, no proper email, and barely enough applications to fill the home screen. One of the first apps was a compass, that's how desperate they were to get things to put on there. And yet it was obviously the future.

I'd show mine to Microsoft folks at conferences and tell them it was going to eat their lunch and the response was usually that they knew this, but the folks upstairs didn't see it as a threat.  And anyway, how can you sell more copies of Windows and Office using a mobile phone? 

After a year version 2 of the iPhone brought 3G, GPS, an app store and proper email. I was second in the queue to get one at the O2 store. Around this time Microsoft seemed to think that the future was hexagonal menus.

I got more worried. I even emailed Steve Balmer (and, to his credit, got a response). But nothing happened. The version of Windows Mobile that was supposed to solve all problems and re-discover the high-ground was suddenly pulled and replaced with not a lot.

Finally, Windows Phone 7 came along. I loved it. A genuine attempt to move the field forward. Quite a few others loved it too. Not enough to get back the all market that Windows Mobile used to have, but enough to build a sizeable user-base. 

Then, just as Windows Phone 7 was starting to get traction (I thought), along came Windows Phone 8. This was a staggering technical achievement. We now had "full fat" windows running on a phone platform. And it worked really well. Snag was, it needed new hardware. And Windows Phone 7 owners suddenly found that they didn't own the future any more. 

And by now Android was taking over where Windows Phone should have been, picking up the 80% of the market that Apple don't tend to bother with. Microsoft hit back by making compelling, wonderful, devices like my Lumia 1520. But it was all for nothing in the end. 

I still have my Lumia 1520. It now runs Windows 10, wonderfully well. The user interface is streets ahead of my iPhone. I can't use it in real life of course, because lots of the things that I want to use on a daily basis are either unavailable or don't work properly. But I'm going to hang on to it to show people when they pull our their latest "wonder phone".

Spider-Man: Homecoming = good film

After yesterday's web picture, today finds us at the Spider-Man: Homecoming movie.

It's a good film. Probably the best Spider-Man film I've seen. Maybe it's the hyphen. But then again maybe it's Marvel, who seem to have a knack of creating slick tales with just he right amount of mayhem, slow bits, plausible (ish) baddies and plot twists. 

Everyone involved delivers and the Marvel universe is looking quite a nice place to be at the moment. 

Creating Cheese Lander in Snaps

Yes. Cheese Lander is back! I'll be using the mostly world famous game in my Monday Games Snap series to demonstrate how to make a Windows program using Snaps that will almost certainly not make you rich and famous. But it might make you poor and notorious. The aim of the game is simple. Move the bread to catch the cheese before it reaches the bottom of the screen. If you miss the cheese, you lose. If your bread is moving too fast when it hits the cheese, you lose. If I'm in a bad mood, you lose (actually this might not be the case). 

Last week we took a look at one of the Snaps sample game programs (read that before you read this). This week we're going to take that game code and move it into the "startup" program that runs when a Snaps application starts running. Then we're going to add some bread, cheese and a suitably starry background with a view to getting things moving next week. 

Open up the BeginToCodeWithCSharp sample project and take a look at the Solution Explorer in the top right hand corner:

Open the BeginToCodeWithCSharp project and then find the My Snaps Apps folder. Inside that you'll find a source file called MyProgram.cs. Open this file.

This is the StartProgram method that runs when a Snaps application starts up. It's the one that runs first because it is in a class called MyProgram and that is always the one that contains the initial StartProgram. Let's replace this StartProgram with the game code that we created last time:

public void StartProgram()
    {
        SnapsEngine.StartGameEngine(fullScreen: false, framesPerSecond: 60);

        ImageSprite ball =

                new ImageSprite(imageURL: "ms-appx:///Images/ball.png");

        SnapsEngine.AddSpriteToGame(ball);

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

Copy the above method out of this text and paste it over the StartProgram in the Visual Studio editor so that it looks like this.

Now, when we run the program we get a nice round ball in the top left hand corner:

Balls are OK, but we want cheese. I've put all the image assets for the game into a file you can download from here. The images include the cheese, the bread, the starfield background and the game message screens. Download the zip file and put the images from it somewhere (I put mine on the desktop). 

Now find the click on the cheese in your download folder and then drag it into the Images folder for the solution. 

If you do the drag correctly you'll get a warning message because the demo programs (like all my products) come with cheese pre-loaded. However, we want to use the newer cheese because it is the right way up, so click yes to overwrite:

Now we can change our program to draw cheese rather than a ball.

ImageSprite ball =

        new ImageSprite(imageURL: "ms-appx:///Images/cheese.png");

Now, when you run the program you'll see a piece of cheese, rather than a ball. Yay!

Now drag all the other images assets into the images folder.If you find that moving individual items is too much of a drag (ho ho) you can select multiple items and drag them all at once. 

Now you've got the image assets, lets add the background to the game. We can use a new ImagesSprite for that. We can call the new sprite background:

ImageSprite background =
    new ImageSprite(imageURL: "ms-appx:///Images/Background.png");
background.Height = SnapsEngine.GameViewportHeight;
background.Width = SnapsEngine.GameViewportWidth;

This creates a new sprite called background. It also sets the width and the height of the sprite to match the size of the game viewport, so that it exactly fills the screen, which is just what we want the background to do. We can add the new sprite to the game, remembering that sprites are drawn in the order that they are added to the game. So we draw the background first, and then put the cheese on top.

SnapsEngine.AddSpriteToGame(background);
SnapsEngine.AddSpriteToGame(ball);

 

The complete program looks like this:

using SnapsLibrary;

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

        ImageSprite ball =

                new ImageSprite(imageURL: "ms-appx:///Images/cheese.png");

        SnapsEngine.AddSpriteToGame(background);
        SnapsEngine.AddSpriteToGame(ball);
        while (true)
        {
            SnapsEngine.DrawGamePage();
        }
    }
}

Run this and we'll see some cheese against a starry backdrop. But the cheese looks a bit big for the screen. Now it turns out that a recent meeting of the International Standards Organisation for Cheese Related Gaming has standardised cheese and bread sizes for the cheese landing games as a twentieth of the width of the screen and an eighth of the width of the screen respectively. Fortunately the Snaps framework provides a method that will scale a sprite and retain it's aspect ratio:

ball.ScaleSpriteWidth(SnapsEngine.GameViewportWidth / 20);

Add the statement to scale your cheese, and then add the bread sprite and scale that too. This will put bread and cheese on the screen. Next week we'll make them move about a bit. 

See the Lego Batman Movie

The Lego Batman movie is way, way better than it needs to be. Hanging off two solid franchises (the clue's in the name) it could confidently expect to make a fortune just by showing up. At least for one episode at least. 

However, it is very, very, good. Just the right balance of action, story and knowing self-reference to keep everyone happy. I don't think I've laughed out loud at a film so many times for a while.

Very strongly recommended.

Reckitt Benckiser at c4di

David Keel of c4di explains what we are about

Spent an afternoon talking about robots and chatbots. In other words, a good afternoon. We had folks from Reckitt Benckiser over to talk about a new partnership with c4di. We were showing off stuff what we had made and I brought along a few Hull Pixelbots. 

Another satisfice Hull Pixelbot customer...

I really love it when I show someone a bit of tech and they go "Oh, so that means we could use this for......." That's a big chunk of what c4di is all about, and there was a lot of it about this afternoon.

Then we went straight into a Hardware meetup. It was great to see everyone come along, Ross brought his beautifully made Hull Pixelbots and we had a good natter about how to control them. 

Great stuff. 

Hull Pixelbot Rumble at c4di today (Thursday)

Finally, a blog post that isn't a thinly disguised plug for one of my books....

Anyhoo, today I'm plugging the Hardware Meetup at c4di tomorrow (Thursday). Ross is going to bring his robots, I'm going to bring some of mine, and we are going to do some robot things that might include rumbling.

You're welcome to come along and marvel. Sign up here. The meetups are in the ground floor of the awesome c4di building. We start at 6:00 pm and go on until 8:00 or until we run out of things to talk about (which usually means a bit later..)

If you've any interest in hardware (computer or otherwise) then it would be great to see you.