Skip to content

136. Programming a full game (the L game)

November 10, 2013

I don’t usually finish games, but in this post, I program a full game – a fairly simple game, but it has quite a few features that may interest you, especially if you are fairly new and are interested in learning some of the nice things you can do with Codea.

First, why not try it out, here.

Feature list

Rather than just start at the top and bore you stupid by going through every part of the code, here is a list of all the features I’m going to explain. You can jump to any of them that interest you.

The L game
Game design
How long it took
Game UI
Managing the stages of the game
Board and screen layout
Drawing a shadow behind the game title
Setting up the game
Drawing instructions on the screen
Drawing the board
Making the colour of a piece “pulse”
Drawing control buttons
Handling touches
Handling button presses
Handling the drawing of the new L position

Throughout this post, I’ve also linked to some of my previous posts which explain various techniques, if you want to know more.

The L game

Edward De Bono has written a lot about thinking and creativity. He set out to create the simplest possible strategy game, and the L game is the result.

Basically, two players try to prevent each other finding a new position for their L piece. On each turn, you must first move your L piece, then if you want to, you can also move one of the dots.

There are a couple of thousand possible configurations of the board, but if you ignore rotations and mirror images, there are probably only a few hundred.

The game is a draw if played well, and will go on indefinitely.

This is a copyrighted game, so it can’t be copied for profit.

Game design

Originally, I thought I would program Codea to play against the user. This turned out to be hard because it’s difficult to figure out all the moves an L shape can make, and then the dots can be in lots of positions, too.

So I went with two human players instead. If I had gone with programming Codea to play it, I would have figured out the best way to play (not too hard), and how to rotate and/or mirror the board so I could translate any position to one of a handful of known positions.

Something I thought hard about was how to store the L positions in variables. It takes at least three sets of numbers to do this. The most compact I can think of is to store the x,y position of the square where the two L pieces meet, then have a number that stores the number of squares along the x axis (negative if they go to the left), and another number for the squares on the y axis.

In the end I just stored all four x,y square positions, because it was simpler to manage.

How long it took

About 5 days, and maybe 20 hours. It’s still not quite finished, because there is a bug or two. I probably rewrote most of it two or three times, even though I’ve been (hobby) programming for many years. Being prepared to start all over again is important, in my view.

I also tend to get a rough idea of what I want, and start programming. This means sometimes I find I overlooked something and have to go back, but I think it’s better than planning for weeks ahead – for projects this size, anyway!

Game UI

I have kept the game as simple as possible. It starts straight away with the opening position and you can begin playing. When one of you wins, you press the Restart button to play another game.

This makes it easy to draw, because I always draw the board on the screen and only a few things need to change.

One fancy thing I do is to get users to draw the position of their L shape with their finger, and then mark that position with a temporary set of squares.

I also make the user’s L piece pulse (fade in and out) to show them which piece to move.

Managing the stages of the game

Most games require some kind of “state” management, so Codea knows what to draw at any moment.

Typical stages include

  • introduction – where the app is explained
  • settings – where the user can change certain things
  • play
  • win
  • lose

It’s called state management because your app can usually only be in one of these states at any time. A single variable can hold the current state, and then you use if tests to decide what to do, based on this variable.

In this case, it’s pretty simple. The board is always on the screen, and I’m going to put instructions underneath, so I don’t need an introduction screen. I’m also just going to restart the game whenever requested, so players can figure out for themselves when they win or lose, and I don’t need a win/lost screen either. Sine I don’t have settings, this leaves only with a “play” stage.

However, I do want to vary what shows on the screen depending on the following

1. If you haven’t moved anything, I want

  • instructions on moving the L piece
  • your L piece should gently pulse, to show you what to move
  • only the Restart button should show

2. if you have moved the L piece, I want

  • instructions for moving a dot
  • the Restart, Undo and Done buttons should show

3. if you have moved the L piece and touched a dot to move it, I want

  • the same as 2 above, plus
  • the dot you touched should pulse gently

So at the top of the program, I define the stages like this

--playing stages
NONE,MOVED_L,TOUCHED_DOT,MOVED_DOT=10,11,12,13

I define them as text labels so that when I use them in my code, they make sense. If instead, I used numbers like 1,2,3, it would be easy to type the wrong number by mistake.

So now I have to be careful to define how and when the game stage changes from one to another.

Board and screen layout

I’ve kept it very simple – just a 4×4 grid, which I draw onto an image in memory at the beginning, so I can just sprite it onto the screen as a single image when Codea draws, rather than having to draw all the lines each time.

To be honest, this is hardly worth doing for a few lines, especially when this game hardly uses any graphics, but I was thinking of making the board more fancy when I did it this way.

If you haven’t done this before, learn how, because it can be very useful to pre-draw complex graphics that are not going to change.

board=image(size,size)
setContext(board) --draw to 'board' image
background(137, 194, 208, 255)
pushStyle()
stroke(45, 125, 151, 50)
strokeWidth(2)
for i=0,4 do
    line(square*i,1,square*i,square*4)
    line(1,square*i,square*4,square*i)
end
pushStyle()
setContext()

So now the board is contained in the image called board. If I were going to release this as a game, I would probably include the game title in this fixed image as well, because it never changes, but I’m just playing around here 😉

When you’re placing stuff on the screen, it pays not to hard code the numbers if you can help it. I set my board size, and then position it slightly left and above of centre (to make room for instructions below, and buttons to the right). So if the screen size is different, the board position should adapt. (I haven’t allowed for the user turning the iPad round while playing, but I would need to do that in a commercial game).

size=400 --total size of grid
--position slightly left and above of centre
offset=vec2(WIDTH/2-size/2-50,HEIGHT/2-size/2+65)

Drawing a shadow behind the game title

This is dead easy. Just draw the text twice. The first time, make it gray, and draw it a couple of pixels below and to the right. Then draw the text in the normal colour.

Setting up the game

I will need to set up the game not just at the beginning, but whenever the game restarts, so I put it in its own function.

The player details go in a table numbered 1 and 2. This makes it easy to switch between players, because if the current player number is n, then the other player is always 3-n.

The buttons are all defined relative to the offset point (where the board starts) so they will change position along with the board. See how they are named to make it easy to use them later, and how they have a show value that tells Codea whether to draw them or not.

The most interesting line is the tween at the end. More on that below.

function StartGame()
    --table holds touches, used for drawing L shape
    touches={} for i=1,4 do touches[i]={} end
    --tables to hold player data
    --pos = position of 4 squares of the L
    player={}
    player[1]={name="Blue",
          pos{vec2(2,1),vec2(2,2),vec2(2,3),vec2(3,1)},
          color=color(44, 155, 219, 255)}
    player[2]={name="Red",
          pos={vec2(2,4),vec2(3,4),vec2(3,3),vec2(3,2)},
          color=color(209, 93, 113, 255)}
    --and a table to hold a new move until  submitted
    playerN={pos={}}
    --a table for the two dots
    dot={pos={vec2(1,4),vec2(4,1)},
          color=color(84, 167, 84, 255)}
    dot2={pos={}}  --and for any dot moved (until  submitted)
    --control buttons
    buttons={}
    buttons.Restart={text="Restart",show=true,
         x=offset.x+square*4+90,y=offset.y+square*3}
    buttons.Undo={text="Undo",show=false,
         x=offset.x+square*4+90,y=offset.y+square*3-75}
    buttons.Done={text="Done",show=false,
         x=offset.x+square*4+90,y=offset.y+square*3-150}
    stage=NONE
    D_touched=nil --id of a dot when touched
    --choose a player to start with
    play=math.random(1,2)
    --start tween to vibrate player colour, see DrawBoard
    Alpha={a=255}
    tween( 2, Alpha, { a=50 },
           { easing = tween.easing.linear,
           loop = tween.loop.pingpong } )
end

Drawing instructions on the screen

I could print the drawing instructions one line at a time on the screen, but this makes it difficult to change the text without having to rearrange all the lines manually. There is a better way, as shown below – this is the help text for moving a dot.

First, I have a special function to draw the text on the screen. I’ll talk about this underneath.  Second, I use [[ and ]] instead of ”’ for the text. Double square brackets work the same as quotes, but they allow you to include line feeds and paragraphs, so I can write all my text in one go.

DrawHelpText(
[[If you want, move ONE of the dots to a blank square to make it
more difficult for your opponent.

To do this, touch a dot, then a blank square, and the dot should move.

Press the Done button when you're finished your move, or Undo to start
your move again.]])

I’ve written a special function to write the text on the screen because I have more than one help message. I can use this function for both messages, saving me from duplicating the code. This is an important reason for putting code in functions.

The function sets a special font, font size, colour, wraps the text at a certain width, and then draws it at left and below of the board. As with everything else, the position is relative to the offset variable, which is where the board starts, so if I ever change the board position, everything else will automatically move too.

function DrawHelpText(t)
    pushStyle()
    font("HelveticaNeue")
    fill(0)
    fontSize(16)
    textWrapWidth(size+offset.x+20)
    textMode(CORNER)
    local sx,sy=textSize(t)
    text(t,offset.x/2,offset.y-sy-25)
    popStyle()
end

Drawing the board

As I said above, I put the board into a custom image, so all I have to do when drawing is draw that image to the screen. I also draw the title on top.

I draw control buttons on the right, but only if their show values are true.

I draw the help text underneath depending on what stage we are at.

I draw the two L shapes and two dots on the board, and if a user has moved their piece, I draw the new position using smaller colour squares (to show it is temporary), until they press Done.

I won’t show all the code here because it’s fairly obvious.

Making the colour of a piece “pulse”

I wanted to make a player’s L piece “pulse” (fade the colour in and out) when it is their turn, to show them what to move. To do this, I need to vary the alpha value (ie the 4th item) of the colour.

The simplest way I found was to set up a tween, that continually moves the value of Alpha.a below, between an alpha of 50 and 255, as follows. The pingpong setting makes it repeat forever.

Alpha={a=255}
tween( 2, Alpha, { a=50 }, { easing = tween.easing.linear,
          loop = tween.loop.pingpong } )

Then whenever I draw the L piece for the current player (unless they’ve moved it, of course), I set the alpha for their colour to Alpha.a.

(The value of Alpha.a is moving between 50 and 255 the whole time the game is running, but I only use it when I want to, which is neat).

Drawing control buttons

You might imagine it is difficult to draw control buttons with rounded edges, but you can do it easily by drawing a line (a big fat line), like this. See the numbers in the code below and notes underneath.

function DrawButtons()
    pushStyle()
    fontSize(24)
    font("ArialRoundedMTBold")
    for i,b in pairs(buttons) do
        if b.w==nil then b.w,b.h=textSize(b.text) end [1]
        if b.show then [2]
            stroke(186, 132, 185, 255)
            strokeWidth(b.h)  [3]
            line(b.x-b.w/2,b.y,b.x+b.w/2,b.y) [4]
            fill(255)
            text(b.text,b.x,b.y)
        end
    end
    popStyle()
end

[1] The first time we draw the button, calculate the height and width needed to fit the text
[2] Only show the button if required
[3] Make the line as wide as the height of the text
[4] Draw a line where you want the text. It will have rounded ends by default

Handling button presses

So how do we manage the user pressing a button? Obviously we need some code in the touched function that tests if the touch was on a button. I wrote a GetButton function that does this and gives back the button that was pressed, if applicable – as shown below.

Note that in the GetButton function, I actually include a bigger area, around the button, because the buttons are fairly small and users have fat fingers that can easily miss.

--in the touched function
--see if a button was touched
local b=GetButton(touch.x,touch.y)
--if we did touch a button, handle it
if b then HandleButton(b) end

--this function checks if a button was pressed
--for each button, check if touch is within the
--button area. If so, return the button.
function GetButton(x,y)
    for i,b in pairs(buttons) do
        if math.abs(x-b.x)<b.w and
           math.abs(y-b.y-b.h/2)<b.h
           and b.show==true then return b end
    end
    return nil
end

function HandleButton(b)
    if b==buttons.Restart then
        StartGame()
    elseif b==buttons.Undo then
        playerN.pos={}
        dot2={}
        D_touched=nil
        ChangeStage(NONE)
    elseif b==buttons.Done then  --finish move
        --TO DO - store move to allow move rollbacks
        for i=1,4 do --store new position
            player[play].pos[i]=playerN.pos[i]
        end
        playerN.pos={} --clear
        --move dot if applicable
        if dot2.id then dot.pos[dot2.id]=dot2.pos end
        dot2.id=nil dot2.pos={} D_touched=nil
        ChangeStage(NONE)
        --switch player
        play=3-play
    end
end

The code below handles a button press. It is given the button that was pressed, and depending what that was, it restarts the game, undoes the current move, or finalises the current move.

I’ve removed some of the code to make it clearer, but notice how naming the buttons makes the code clearer, and also – at the end – how easy it is to switch players when they are numbered 1 and 2.

function HandleButton(b)
    if b==buttons.Restart then
        StartGame()
    elseif b==buttons.Undo then
        --code to restart move goes here
    elseif b==buttons.Done then  --finish move
        --code to finish move goes here
        --switch player
        play=3-play
    end
end

Handling touches

This is the most important and difficult part of the program.

It’s important to figure out what each touch is for – drawing an L? Picking a dot, or picking a square to put in ? Pressing a button? The stage variable can give us the answer most of the time.

The trickiest bit is drawing an L, because it needs to cover 4 squares that make an L, and a player might start drawing, lift their finger and start drawing again.

So I use the fact that each touch is given a unique id number, which allows me to track the number of squares covered by a single (moving) touch, like this. See the notes underneath.

if stage<MOVED_L and p then --p is the touch x,y
    if id~=touch.id then --this is a new touch
        id=touch.id -store the id
        touches={} --make a new table for touches
        nTouches=0
    end
    local v=GetSquare(touch.x,touch.y)
    local u=v.x*10+v.y [1]
    if touches[u]==nil then nTouches=nTouches+1 end
    touches[u]=v
    if nTouches==4 then MoveL() end  [2]
end

[1] I want to count the number of different squares touched, but the finger will make several touches in each square. How do I only count (and store details of) each square once?

What I do is make a number that is unique to each square, by simply multiplying the column value (x above, 1-4) by 10 and adding the row value (y above, 1-4). I use this as the key for an item in the touches table, and store the x,y position (v above).

This means that if I add the same square several times because my finger touches it, that I will keep setting the same table entry with the same key and value, so it will only get set once.

I also keep a variable nTouches that keeps track of the total number of touches in my table. nTouches gets increased if I add an item to the table and it wasn’t there already (ie I only do this once for each square).

When I reach 4 squares touched, I run the MoveL function, below.

Handling the drawing of the new L position

What is the best way to check if an L drawing is valid? These are my rules.

  • it mustn’t include any of the opponent’s L squares or dot squares
  • it must be different from the current L position
  • if you count how many of its squares are in each row and each column, then take the greatest of each, then one column (or row) should have three squares, and one row (or column) should have two squares
  • the row/column with two squares must not be in the same column/row as the middle of the the three columns/rows (I used the average of the three positions to get the middle one easily)

There is probably a much simpler way I haven’t thought of, but luckily the game is so simple that this doesn’t need to be terribly fast.

Advertisements

From → Games, Graphics

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: