Skip to content

211. Making multiplayer games

April 21, 2015

The latest Codea release added sockets, which allow iPads to message each other and create multiplayer games. The Codea documentation doesn’t cover sockets, because they aren’t an official part of Codea – but we can use them, and this post shows how.

The code and example below were written by JakAttak , so all credit to him. I’m simply going to explain it the best way I can, so you can use it yourself.

The code comes in two parts. There is the socket “library” which does all the hard work, and then the example code that uses it. I’ll explain the example code, and if you want to know how the socket library works, you’ll find it is pretty clearly laid out.

Please note I haven’t shown all the example code below. I’ve skipped the parts that belong to the example game, so I can focus on the multi player code. You will find a link to the complete code at the end, so you can try it out.

So – let’s see how it works.

One player hosts the game, ie starts it and waits for another player to connect. So we need the option at the beginning to be the host or a guest, and some way of connecting to each other.

First, the setup function. It puts some parameter buttons on the screen so you can choose to be host or guest, and gets the game started when you make a choice.

function setup()
    --create a temporary function that will run *after* connecting
    local connectionMade = function()
        output.clear() --clear print area
        parameter.clear() --clear all parameters
        print("Connected!") --tell user the good news
        gameSetup() --set up the game
    end
    --create the multiplayer object 
    --it needs two functions given to it
    --the first one handles data sent by the other player
    --the second is the function (above) that runs when we connect
    multihandler = Multiplayer(receiveData, connectionMade)

    --now the parameters that let us choose how to start the game
    --hosting option
    parameter.action("Host Game", function()
        multihandler:hostGame()
    end)

    --guest option that finds other player for you
    parameter.action("Find and Join Game", function()
        multihandler:findGame()
    end)

    --guest option where you enter ip address and port yourself
    parameter.action("Join Game", function()
        if other_ip then
            multihandler:joinGame(other_ip, other_port)
        else
            parameter.text("other_ip", "")
            parameter.text("other_port", "")
            print("Enter host ip and port, and click Join Game")
        end
    end)
end

If you are playing on a local wifi network, the guest player should be able to just pick Find and Join Game, and Codea will find the other iPad. If you’re playing over the internet, you need to use Join Game, where you type in the ip address and port number of the other iPad. How? When you run the program and choose Host Game, it prints your ip address and port number, and then you need to share this somehow with the other user. I haven’t tested that this works.

Now you are connected, set up your game, as shown below. You can replace all this with your own code. Note how there is a “clear” parameter with a function attached, and that function clears the print area and then sends the message “clear” to the other iPad so it knows to clear its screen too. So you can send messages between you at any time using the function multihandler:sendData.

function gameSetup()
    canvas = image(WIDTH, HEIGHT)
    parameter.color("pen_col", color(0, 255, 0))
    parameter.integer("pen_size", 2, 100, 10)
    --clear screen option
    parameter.action("clear", function()
        clear() --see below
        --tell other user to clear screen, 
        --this is how to send messages
        multihandler:sendData("clear") 
    end)
    pen_touch = nil
    last_point = vec2(0, 0)
end

function clear() --start drawing again
    canvas = image(WIDTH, HEIGHT) --clear image in memory
end

If you aren’t used to seeing a function being defined in the middle of a parameter command, you can write like this if you prefer. The parameter is told to run the Restart function if it is pressed, and that function clears the screen and tells the other user to do the same.

parameter.action("clear", Restart)

--somewhere else in your code, put this function
function Restart()
    clear() 
    multihandler:sendData("clear") 
end

Now we need to write a function that receives data from the other user. We called it receiveData above, when setting up the connection, so we need to use the same name here. Note how it clears the screen if it receives the word “clear”, then it has some very strange code, which I’ll explain underneath.

function receiveData(d)
    if d == "clear" then
        clear()
    else
        local tb = loadstring("return " .. d)()
        drawPoint(tb.point, tb.last_point, tb.drawing_line, 
           tb.pen_size, tb.pen_col)
    end
end

First, you’ll see the function has one parameter d, which is a text string sent by the other user. What is in that string is up to us. In this game, it can either be the word “clear” (to restart drawing), or it can be a table of data used to do some drawing. How do we convert a table of data to a string, and back again?

Here is the line (from below, we haven’t got to it yet) that sends data to the other user.

multihandler:sendData("{ point = " .. vec2ToStr(p) .. ", 
      last_point = " .. vec2ToStr(lp) .. ", 
      drawing_line = " .. tostring(d) .. ", 
      pen_size = " .. ps .. ", 
      pen_col = " .. colToStr(pc) .. " }")

It uses some functions (vec2Str, tostring, colToStr) to convert point positions, pen details etc to strings. Two of these three functions are defined below (the other, tostring, is a built in Codea function). I won’t explain them because they are very simple.

The important thing is that the final string looks like a line of code that defines a table. It has the squiggly brackets, commas between the items, etc. If only the receiving iPad could turn it from a string back into a table.

Well, it can. The loadstring function tells Codea to take the text inside its brackets, and treat it as code, ie run it. And the text inside the brackets is the word “return” followed by the table data sent by the other iPad. So the result is a table of data, which the code above puts in a variable called tb. The next line of code uses it to draw.

You don’t have to use fancy techniques like loadstring. You can send text however you want, and read it any way you want at the other end. But loadstring is a nice trick to know.

function draw()
    background(255, 255, 255, 255)
    --update the connection
    multihandler:update()
    --if we're still connected, sprite our drawing
    if multihandler.connected then  --draw image on screen
        sprite(canvas, WIDTH/2, HEIGHT/2, WIDTH, HEIGHT)  
    else --otherwise wait to be connected
        fill(0)
        text("Waiting for connection...", WIDTH / 2, HEIGHT / 2)
    end
end

Finally, in this drawing game, any time we touch the screen, we do some drawing and we send the details to the other player.

function touched(t)
    --this code only runs if we are connected
    if multihandler.connected then
        --[drawing code skipped here]
        --this is the line we saw above
        --it sends the details of our touch to the other player
        multihandler:sendData("{ point = " .. vec2ToStr(p) .. ", 
            last_point = " .. vec2ToStr(lp) .. ", 
            drawing_line = " .. tostring(d) .. ", 
            pen_size = " .. ps .. ", 
            pen_col = " .. colToStr(pc) .. " }")
    end
end

The complete code for the example (and multiplayer socket library) is here.

In my next post, I’ll (try to) explain the socket library, without getting too technical (there is little risk of that, because I don’t understand it too well myself).
I won’t try explaining the socket library, but if you look at the code, you should find it’s well laid out for you to follow.

From → Programming

One Comment

Trackbacks & Pingbacks

  1. Index of posts | coolcodea

Leave a comment