Sniff is a "Scratch-like" programming language that's designed to help Scratchers move gently from Scratch to more conventional languages. They can start writing programs, without having to learn a new language because Sniff is based on Scratch. They learn a little more about variables, compiling, syntax errors (!), and they can have fun controlling real hardware while they're doing it.

Wednesday, 29 July 2015

Sniff Games (part 2): Catch the Flowers

A few years ago Blackberry had a promotion for developers to try and get them to support their Playbook tablet - write an App, and submit it to their App store and they'd send you a free Playbook. At the time the Playbook was decent hardware and was pretty cheap, so I bought one wrote a simple game, give it away on the app store, and got a second playbook free. I planned use them for more serious dev work and port some of my other code to them.

The app I wrote to get a free Playbook was a fun little game called "Catch The Flowers". My daughter was off school feeling unwell (she was probably in year R or maybe year 1), and to pass the time we designed the game, and she drew the artwork on the side of an old cardboard box. I just photographed it and used it with the minimum of editing and tidying. This is a great approach, as the hand-drawn images capture the fun of the game far better than digitaly produced images could.

As we've been developing a sprite system for Sniff it seemed like a good idea to revisit the game and port (i.e. rewrite) it to run in Sniff on something other than an old unsupported tablet.

The aim of the game is to collect flowers - petals fall from the sky, and you catch them one at a time. When you catch 5 they make a flower which appears in the bottom left. The problem is that each flower needs to be a single colour. There are 4 colours of petals and once you start catching one type you need to complete the flower in that colour - mixing the colours costs you a life (and the petals in the current flower). White are the most common flower, and Pink the rarest, so collecting a whole flower of Pink is much harder, and scores accordingly. When you collect a whole flower an extra  falling petal is added to the game - you might think this makes it easier but when the number of petals increase it gets harder to avoid the wrong colours.

Most of the code to write this is similar to the previous game examples where we make a sprite device, and move it around based on the keys that are pressed. We set up the Princess and Background sprites, just we have previously. However the petals, completed flowers and the lives remaining need a bit more attention.

We use a miniPrincess sprite to indicate lives remaining. This is has a smaller version of the princess artwork as a costume and is normally hidden:

make miniPrincess sprite device 

.set fileData to "Images/PrincessS.bmp"
.tell miniPrincess to "load costume"
.tell miniPrincess to "set unhittable"

..set spriteX to 30
..set spriteY to 440
..tell miniPrincess to "move to"
..tell miniPrincess to "show"
..repeat lives
...tell miniPrincess to "draw"
...set spriteX to 60
...set spriteY to 0
...tell miniPrincess to "move by"
..tell miniPrincess to "hide"

After we've drawn the main sprite list we call "draw" on the sprite ourselves to stamp the  required number of princesses to indicate the number of remaining lives. We use a similar approach to drawing the completed flowers, and the flower that's being collected.

The real interesting aspect of the game however is the main falling petals. So far we've created sprites when we write the code by making a sprite device. However sometimes we can't do that - we don't know how many petals are going to be falling, as the number increases as you progress through the game. Technically we need to "dynamically allocate" sprites - make them when we run the game, rather than fixing them into the code.

Fortunately if you've followed so far (and written some games using static sprites) then this is a pretty small step... Every sprite has an id: you can perform any operation you would normally perform on a sprite using "tell" by asking the spriteManager to do it for you:

.tell mySprite to "draw"

is the same as:

.tell mySprite to "get id"
.say [spriteID]
.tell spriteManager to "draw"

Every sprite has an ID, which you can get by telling to to "get id". We can then perform operations using the spriteID and the spriteManager rather than the sprite itself. This might seem like a waste of time, but it has a couple of advantages.

make petals list of numbers

when makePetal
.tell spriteManager to "make sprite"
.add spriteID to petals
.set fileData to "Images/LeafW.bmp"
.tell spriteManager to "load costume"
.set fileData to "Images/LeafY.bmp"
.tell spriteManager to "load costume"
.set fileData to "Images/LeafR.bmp"
.tell spriteManager to "load costume"
.set fileData to "Images/LeafP.bmp"
.tell spriteManager to "load costume"

Now we can use "make sprite" on the spriteManager to get a new sprite that doesn't have a name like a regular sprite. It just has a number. We can make as many of these as we need, whenever we need them. Though conceptually its a bit trickier (get up to speed with regular static sprites first!), we can do some neat things which make some stuff a lot easier:

when animatePetals
.make counter number
..repeat length of petals using counter
...set spriteID to item counter of petals
...set spriteX to 0
...set spriteY to -10
...tell spriteManager to "move by"

We've got all the spriteID's in a list called petals, so we can tell them all to move down 10 pixels. We use the same mechanism to check the petal to see if its hit the princess (only the princesss is "hittable"). The main game mechanic happens when we find that a petal has hit the princess:

...tell spriteManager to "check touching"
...if spriteHit
....set spriteID to item counter of petals 
....tell spriteManager to "get costume"
....if petalsCollected=0
.....set collectedColor to spriteValue
....if spriteValue=collectedColor
.....change petalsCollected by 1
.....if petalsCollected=5
......add collectedColor to levelColors
......set petalsCollected to 0
......broadcast makePetal and wait
.....change lives by -1
.....if lives=0
......tell princess to "hide"
......tell princess to "set unhittable"
.....set petalsCollected to 0
....set petalIndex to counter
....broadcast resetPetal and wait

We check the petals colour (by getting its costume). If its the first petal in the flower then we use that colour. If not, we check that its the right colour. If it is then we record we've got one more. If we've collected 5, then we record we've completed a flower. If we've collected the wrong colour petal, then reset the flower, and subtract a life.

This whole block of code is quite dense, but it does fairly clearly sumarise the game logic!

As I got up to speed with what passed for the Playbook "Native Dev Kit", it was pretty clear that the Playbook SDK really wasn't ready for serious work. Blackberry didn't provide any code for displaying UI elements. They did however promise that Blackberry OS 10 was coming in a few months which would fix all of that.... So I waited, in pretty good faith, until 18 months later they announced that they couldn't be bothered to support the hardware we'd bought or the claims they'd made when we bought it...

Catch The Flowers was the only think I ever wrote for Playbook. It was a big hit with the family who loved the drawings (and sound effects!), so I'm really pleased to bring it back to a wider audience:

Artwork and concepts by Anya (age 5)
Sound Design by Alex (Age 3)
Coding by Ian (Age withheld by request)

[slight aside: you might notice that in this post "tell" commands look a little different: Perviously we've used camelCase - whichIsWhereYouUseCapsToSeperateWords rather than spaces. You can still do that if you want to, but as of the next release (R20), we'll support the more kid friendly all lower case with spaces, so we've used that here]

1 comment:

  1. The Casino Directory | JtmHub
    The Casino Directory is a complete directory for casino and sportsbook operators in septcasino Ireland and Portugal. Jtm's comprehensive directory provides you with more than 150