Corona Realtime Turn Based Game Tutorial
- We have created a TicTacToe game using corona.
- We will make it 2-player realtime multiplayer game using AppWarp Cloud.
- We will create realtime turn based tic tac toe game using AppWarp TurnBasedRoom API.
- TicTacToe is very simple game to know more about game Click Here.
- The user will get real-time feedback about the other user’s performance adding to the excitement of the game.
Download AppWarp Corona sample from git repository.
This repo contain SDK and sample. Open TicTacToe sample in corona simulator.
Since you will be integrating with AppWarp cloud services, you need to get your application keys from ShepHertz developer dashboard AppHq. These keys identify your application zone on ShepHertz cloud service and are required so that AppWarp cloud can segregate messages belonging to different applications.
Follow the simple steps by signing up (free) and getting your application keys mentioned at AppWarp.
Now open main.lua file in the TicTacToe project and add the values there. For example
API_KEY = "YOUR_API_KEY_HERE" SECRET_KEY = "YOUR_SECRET_KEY_HERE"
Now that we’ve got everything ready, we can run the sample and see the game in action. Since this game is two player game you will need to run this on 2 emulators/devices simultaneously to play multiplayer game.
After you tap to connect button, the game will connect to AppWarp and join a game room. Once inside the game room, the client will wait for the second player to join the room before the game will start.
Now you need to do the same from the second emulator/device. AppWarp matchmaking APIs will make this second user join the same game room and the game should begin. Since in this example we are using AppWarp Turn Based API so once both user connect one user start the game. To know more about AppWarp TurnBasedRoom Click Here. User can send his move and receive Opponent move in realtime. This in-game realtime communication is the power of AppWarp.
Game will be considered completed in these three condition
- User Left: In this case one player left the game other player will be considered as winning user as his opponent has left the game.
- Game Complete: If any user completes the game.
- Game Draw: If no space left to complete move.
- Time Over: Since this is turn based game if user doesn’t send his move in turn time(30 sec here) then this user will be considered as looser.
Starting the game
First you need to initialize the WarpClient singleton with your application keys (main.lua)
appWarpClient = require "AppWarp.WarpClient"
appWarpClient.initialize(API_KEY, SECRET_KEY)
Next you need to call the gameLoop in every frame
local function gameLoop(event) appWarpClient.Loop() end Runtime:addEventListener("enterFrame", gameLoop)
Note that AppWarp SDK provides its functionality through asynchronous APIs. This means you simply add the corresponding request listeners to the WarpClient instance to receive responses and notifications.
The file (ConnectScene.lua) has all the code we need to do this step. It will make connection requests, room requests and zone requests (to create a room if required). So we add the corresponding listeners in OnStart()
public WarpController() { ... appWarpClient.addRequestListener("onConnectDone", scene.onConnectDone) appWarpClient.addRequestListener("onDisconnectDone", scene.onDisconnectDone) appWarpClient.addRequestListener("onJoinRoomDone", scene.onJoinRoomDone) appWarpClient.addRequestListener("onCreateRoomDone", scene.onCreateRoomDone) appWarpClient.addRequestListener("onSubscribeRoomDone", scene.onSubscribeRoomDone) appWarpClient.addNotificationListener("onUserJoinedRoom", scene.onUserJoinedRoom) }
Now that the listener is setup, we can go ahead and connect. To connect to AppWarp cloud, the client needs to pass in a unique username. In the sample I will just use a random string The random username string is generated using os.clock().
appWarpClient.connectWithUserName(USER_NAME)
The result of connection is provided in the following callback
function scene.onConnectDone(resultCode) if(resultCode == WarpResponseResultCode.SUCCESS) then statusText.text = "Joining room.." appWarpClient.joinRoomInRange (1, 1, false) else statusText.text = "onConnectDone: Failed"..resultCode; end end
If its successful, we go ahead and try to join a room. To join the room, we use the JoinRoomInRange method with parameters (1,1) which request the server to put the client in a room with exactly 1 user in it. If this fails we will create a new 2 player room and join that.
function scene.onJoinRoomDone(resultCode, roomId) if(resultCode == WarpResponseResultCode.SUCCESS) then appWarpClient.subscribeRoom(roomId) elseif(resultCode == WarpResponseResultCode.RESOURCE_NOT_FOUND) then -- no room found with one user creating new room local roomPropertiesTable = {} roomPropertiesTable["result"] = "" ROOM_ADMIN = USER_NAME appWarpClient.createTurnRoom ("TicTacToeRoom", ROOM_ADMIN, 2, roomPropertiesTable, 30) else statusText.text = "onJoinRoomDone: failed"..resultCode end end
Once the room is joined (either now or after creating a new one), the client needs to subscribe it. This is required to receive notifications from the room (required in game play). These concepts are explained in details here. If room has two users then we start the game otherwise wait for other user to join this room.
appWarpClient.subscribeRoom(roomId)
function scene.onSubscribeRoomDone(resultCode, roomId) if(resultCode == WarpResponseResultCode.SUCCESS) then ROOM_ID = roomId; if(isNewRoomCreated) then waitForOtherUser() else startGame() end else statusText.text = "subscribeRoom failed" end end
Game Play
The code for the game play is in the file (GameScene.lua). If user enter on this screen this means that both user are in room. One user(RoomAdmin) get start game screen. As user tap on screen game is started. Player will has to play his game and he will also get update of other user.
To start the game call startGame() API
appWarpClient.startGame()
As the player send his move to complete game, remote player also get notification of his opponent’s moves so it can also render the movement see in (GameScene.lua)
function updateUI(i, j, t) local group = display.newGroup(); ARRAY[i][j] = t GAP = 256/3 DRAW_X = START_X + (j*GAP) + GAP/2 - OBJECT_WIDTH/2 DRAW_Y = START_Y + (i*GAP) + GAP/2 - OBJECT_WIDTH/2 if( t == "0" ) then object = display.newImage( "button_AI.png", DRAW_X, DRAW_Y ) IMAGE_ARRAY[i][j] = object elseif ( t == "X" ) then object = display.newImage( "button_exit.png", DRAW_X, DRAW_Y ) IMAGE_ARRAY[i][j] = object end end
The move are sent using sendMove() API.
appWarpClient.sendMove(i .. "/" .. j .. "#" .. "")-- here i and j are array position. "/" and "#" are used as separator statusText.text = "Move Sent"
The moves sent to the room are provided through the onMoveCompleted callback. In this callback we parse the data associated with the message and identify the sender. We react on the messages accordingly.
function scene.onMoveCompleted(sender, roomId, nextTurn, moveData) .... if(sender ~= USER_NAME) then if(string.len(moveData)>0) then i = string.sub(moveData, 0, string.find(moveData, "/")-1) j = string.sub(moveData, string.find(moveData, "/")+1, string.find(moveData, "#")-1) data = string.sub(moveData, string.find(moveData, "#")+1, string.len(moveData)) if(TYPE == "X") then updateUI(tonumber(i), tonumber(j), "0"); elseif (TYPE == "0") then updateUI(tonumber(i), tonumber(j), "X"); end .... else handleFinishGame("WIN", "TIME_OVER") end end end
Game Over
When the game finish we simply sendMove with game status. As other user receive notification it update its UI depending upon message received.
As the game finish other user get notification update the screen on GameScene.lua depending upon the data to show the reason to finish game.
function handleFinishGame(result, detail) if(isGameRunning == false) then return end if (result == "WIN") then statusText.text = "Congrats! Game Won" elseif(result == "LOOSE") then statusText.text = "Oops! Game Loose" elseif(result == "DRAW") then statusText.text = "Match Draw" end .... end
We also need to leave and unsubscribe the room as well as remove the listener and if the game is not in running mode then we also delete rooms. Since in this game we are using AppWarp dynamic rooms, its good practice to delete them once used (Empty dynamic rooms will anyway be automatically deleted after 60 minutes).
isGameRunning = false isGameOver = true appWarpClient.stopGame() appWarpClient.unsubscribeRoom(ROOM_ID); appWarpClient.leaveRoom(ROOM_ID); appWarpClient.deleteRoom(ROOM_ID); ROOM_ID = "" appWarpClient.disconnect()
The user can tap and go back to the Main Scene from here and we will restart the process. However this time we can simply start by finding a room (as we will already be connected).
In this article we saw how we can develop a multiplayer game using AppWarp Corona SDK. We saw how clients connect to AppWarp, join and play in game rooms. The integration concepts are independent of the use of corona and can be applied for any platform application as we have all supported platform SDK available for AppWarp.