Skip to content

153. Recreating the Threes game app – part 2

July 14, 2014

Now we’ll get Threes to play properly, so you can swipe to slide the tiles until you run out of space, and we will show a score.

Game states

If you haven’t heard of game states before, think about what is shown on the screen. When you start the game, there will be

  • a splash screen, then
  • a menu, then
  • the game itself, and when it’s over,
  • the final score

Each of these is drawn differently, so you need to tell Codea which one to draw, and you can do this easily with a state variable that holds a number or string.

So you could have a variable state, and if it equals 1, then we show the menu, whereas if it equals 2, we are playing, and Codea can use if tests on state to figure out what to draw.

I did it a little differently here. In the Settings function, I defined just two states (because I’m not bothering with splash screen, menus or end of game screens) in a table

states={PLAY=1,END=2}

So when I write state=states.PLAY, it is the same as writing state=1, except that anyone reading the code can see more easily what I’m doing.  That’s the only reason for doing this, to make the code readable and reduce errors.

In the draw function, I’ve included “Game Over” text that is written across the board, with this code

    if state==states.END then
        fontSize(72)
        fill(0,255,0)
        text("Game Over\nTouch to Restart",WIDTH/2,HEIGHT/2)
    end

So if state == states.END, then we draw “Game Over”.

And when people talk about “finite state machines” in game programming, this is pretty much what they mean.

Scoring

This is pretty easy. We just run through the values of each tile, and look up the score in the boardValues table.

function GetScore()
    local score=0
    for c=1,4 do
        for r=1,4 do
            score=score+boardValues[board[c][r]][3]
        end
    end
    return score
end

..so if a tile value in board[c][r]=6, then boardValues[6][3] = 9, and we add it to the score.

..and there is a little code in DrawBoard to show it on screen, which I haven’t bothered showing here.

Moving – handling swiping

To handle user swiping, I have defined these variables in Settings 

    dragXY=nil
    moves={vec2(-1,0),vec2(1,0),vec2(0,-1),vec2(0,1)}
    moveText={"Left","Right","Down","Up"}

dragXY will store the x,y start position of the swipe, and I will compare this with the position at the end of the swipe, to help me decide which direction it was in.

I’ve defined the four possible moves as one tile to the left, right, down or up (in each vec2, the first number is the x movement, sideways, and the second is the y movement, vertical). You’ll see how we use these below. I also defined a text description of each move in case I want to print it out for some reason.

Here is the touch handling. See the numbered comments and explanations underneath.

function touched(t)
    if t.state==BEGAN then --Started dragging --[1]
        if state==states.END then --[2]
            Initialise()
            state=states.PLAY
        else
            --reset movement variables  --[3]
            dragXY=vec2(t.x,t.y)
        end
    elseif t.state==ENDED and dragXY then --[4]
        local dx=math.abs(t.x-dragXY.x)  --[5]
        local dy=math.abs(t.y-dragXY.y)
        local m=nil                               --[6]
        if dx>dy then  --X movement is larger       --[7]
            if dx<cellWidth/2 then return end     --[8]
            if t.x>dragXY.x then m=vec2(1,0) else m=vec2(-1,0) end --[9]]
        else then  --Y movement is larger
            if dy<cellHeight/2 then return end
            if t.y>dragXY.y then m=vec2(0,1) else m=vec2(0,-1) end
        end
        if m then MoveCells(m) end  --[10]
        dragXY=nil
    end
end

[1] – when you first touch the screen, the touch state will be BEGAN. If you don’t know this, you may want to read up on how basic touch works.

[2] – if the game is finished, then this touch will restart it. We initialise the board tiles again, and set the game state to play.

[3] – if we are playing the game, then the player has started to swipe. Store the x,y position in dragXY

[4] – if the touch has ended, and if we have values in dragXY, then we need to process the swipe.

[5] – calculate the absolute change in x and y position

[6] – m will store the final move, start it with nothing

[7] – if x change is larger,we’ll move left or right

[8] – check if we’ve swiped at least half a tile width. If not, it doesn’t count, exit

[9] – set m based on whether the change is positive or negative

[10] – if we have a move, make it

Moving tiles

Suppose we have swiped left. The left hand column can’t go anywhere, so we look at the second column, and if has a number, and

  • if the square to the left is blank, we move the number to the left, else if
  • the total of the number and the square to the left is 3, we put 3 in the cell to the left, else if
  • the cell to the left has the same number, and both are 3 or larger, we add them together in the left hand cell

and that is what the MoveCells function does.  Of course, if the swipe is upwards, then it has to check the rows instead of columns starting from the second row and working down. At the end, it runs CheckAvailableMoves to see if there are any valid moves left. If not, it sets state = states.Ended.

I won’t go through these two functions in detail, because there is nothing clever about them, and the code is a bit messy.

Here is the code so far.

Next, we’ll try some monte carlo simulation to figure what is the best move to make. This will be the fun part.

Advertisement

From → Games

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 )

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: