TicTacToe-game

TicTacToe Multiplayer Windows Game Demo

We will use the classic Tic Tac Toe Windows Phone game developed using AppWarp as an example. Lets download and browse through the source code and walk through some of the key concepts in building this simple game.

First of all we add a Windows Phone Application project. It adds App.xaml and MainPage.xaml by default. We write one more xaml page JoinPage.xaml. Let us describe all important files for comprehension of code flow.

Global Context

GlobalContext.cs

  1. It keeps a reference of the SDK singleton handy for later use.
    public class GlobalContext
        {
            public static String localUsername;
            public static String API_KEY = "Put your API Key here";
            public static String SECRET_KEY = "Put your Secret Key here";
            // Game room id used in this tutorial. 
            // NOTE* replace with your room's id that you created from 
            // App HQ dashboard (http://apphq.shephertz.com).
            public static String GameRoomId = "Put your Room Id here";       
            internal static bool PlayerIsFirst = false;
            public static WarpClient warpClient;
            public static ConnectionListener conListenObj;
            public static RoomReqListener roomReqListenerObj;
            public static NotificationListener notificationListenerObj;
        }
    

Home Screen Of Game

JoinPage.xaml

  1. This is Home page of Game.
  2. User click on Join Game on this page and settings related to game are updated.

    JoinGame TicTacToe game

  3. It initializes the SDK with your applications credentials.

    public JoinPage()
            {    
                InitializeComponent();
                // Initialize the SDK with your applications credentials that you received
                // after creating the app from http://apphq.shephertz.com
                WarpClient.initialize(GlobalContext.API_KEY, GlobalContext.SECRET_KEY);           
                // Keep a reference of the SDK singleton handy for later use.
                GlobalContext.warpClient = WarpClient.GetInstance();
            }
    
  4. Initiate the connection ,create and add listener objects to receive callback events for the APIs used.

    private void joinButton_Click(object sender, RoutedEventArgs e)
            {
                if (string.IsNullOrWhiteSpace(txtUserName.Text))
                    MessageBox.Show("Please Specifiy user name");
                else
                {
                    // Initiate the connection
                    // Create and add listener objects to receive callback events for the APIs used
                    GlobalContext.conListenObj = new ConnectionListener(this);
                    GlobalContext.roomReqListenerObj = new RoomReqListener(this);
                    GlobalContext.warpClient.AddConnectionRequestListener(GlobalContext.conListenObj);
                    GlobalContext.warpClient.AddRoomRequestListener(GlobalContext.roomReqListenerObj);
                    GlobalContext.localUsername = txtUserName.Text;
                    WarpClient.GetInstance().Connect(GlobalContext.localUsername);
                }
            }
    
  5. After getting the success status of the Connect operation in the onConnectDone callback of the ConnectionListener we Join Room.

    public class ConnectionListener : com.shephertz.app42.gaming.multiplayer.client.listener.ConnectionRequestListener
        {
            private JoinPage _page;
            public ConnectionListener(JoinPage result)
            {
                _page = result;
            }
            public void onConnectDone(ConnectEvent eventObj)
            {
                if (eventObj.getResult() == WarpResponseResultCode.SUCCESS)
                {
                    // Successfully connected to the server. Lets go ahead and join the room.
                    WarpClient.GetInstance().JoinRoom(GlobalContext.GameRoomId); 
                }
                else
                {
                    _page.showResult("connection failed");
                }
            }
            public void onDisconnectDone(ConnectEvent eventObj)
            {
                if (eventObj.getResult() == WarpResponseResultCode.SUCCESS)
                {
                    _page.showResult("disconnection success");
                }
                else
                {
                    _page.showResult("diconnection failed");
                }
            }
        }
    
  6. After getting the success status of the Join Room operation in the onJoinRoomDone callback of the RoomReqListener we use SubscribeRoom method.

  7. After getting the success status of the SubscribeRoom operation in the onSubscribeRoomDone callback of the RoomReqListener we use GetLiveRoomInfo method. We get GetLiveRoomInfo’s callback in same listener and decide if user is first or second after getting the No. of users in Room from callback info.Note: We have already creted a room from AppHq which is having Maximum No Of User = 2. We can create room according to our Game requirement.

  8. In the last we move to Game Page (MainPage.xaml).

    public class RoomReqListener : com.shephertz.app42.gaming.multiplayer.client.listener.RoomRequestListener
        {
            private JoinPage _page;
            public RoomReqListener(JoinPage page)
            {
                _page = page;
            }
            public void onSubscribeRoomDone(RoomEvent eventObj)
            {
                if (eventObj.getResult() == WarpResponseResultCode.SUCCESS)
                {
                    WarpClient.GetInstance().GetLiveRoomInfo(GlobalContext.GameRoomId);
                }
            }
            public void onUnSubscribeRoomDone(RoomEvent eventObj)
            {
                if (eventObj.getResult() == WarpResponseResultCode.SUCCESS)
                {
                    _page.showResult("Yay! UnSubscribe room :)");
                }
            }
            public void onJoinRoomDone(RoomEvent eventObj)
            {
                if (eventObj.getResult() == WarpResponseResultCode.SUCCESS)
                {
                    WarpClient.GetInstance().SubscribeRoom(GlobalContext.GameRoomId);
                }
                else
                {
                    Deployment.Current.Dispatcher.BeginInvoke(() =>
                    {
                        MessageBox.Show("There are alredy 2 user wait for some time");
                    });
                }
            }
            public void onLeaveRoomDone(RoomEvent eventObj)
            {
                if (eventObj.getResult() == WarpResponseResultCode.SUCCESS)
                {
                    _page.showResult("Yay! Leave room :)");
                }
            }
            public void onGetLiveRoomInfoDone(LiveRoomInfoEvent eventObj)
            {
                if (eventObj.getResult() == WarpResponseResultCode.SUCCESS && (eventObj.getJoinedUsers() != null))
                {
                    if (eventObj.getJoinedUsers().Length == 1)
                    {
                        GlobalContext.PlayerIsFirst = true;
                    }
                    else
                    {
                        GlobalContext.PlayerIsFirst = false;
                    }
                    // navigate to game play screen
                    _page.moveToPlayScreen();
                }            
            }
            public void onSetCustomRoomDataDone(LiveRoomInfoEvent eventObj)
            {
            }
            public void onUpdatePropertyDone(LiveRoomInfoEvent lifeLiveRoomInfoEvent)
            {
            }
        }
    

Game Activity

MainPage.xaml

  1. It contains all Game logic like Game Initialization ,Game End ,Game Over and Winner Of Game. Game is played on this page.
  2. When any player move by tapping a text block we use SendUpdatePeers method provided by Appwarp
    WarpClient.GetInstance().SendUpdatePeers(MoveMessage.buildMessageBytes(tapped, myPiece));
    

    MoveMessage is gameplay message class. Objects of this class represent actions of the user and are used to serialize/deserialize JSON exchanged between users in the room.

    public class MoveMessage
        {
            public String sender;
            public String TextBoxName;
            public String piece;
            public String type;
            public static MoveMessage buildMessage(byte[] update)
            {
                JObject jsonObj = JObject.Parse(System.Text.Encoding.UTF8.GetString(update, 0, update.Length));
                MoveMessage msg = new MoveMessage();
                msg.sender = jsonObj["sender"].ToString();
                msg.type = jsonObj["type"].ToString();
                if(msg.type == "move")
                {
                    msg.TextBoxName = jsonObj["TextBoxName"].ToString();
                    msg.piece = jsonObj["piece"].ToString();
                }
                return msg;
            }
            public static byte[] buildMessageBytes(TextBlock tb, String piece)
            {
                JObject moveObj = new JObject();
                moveObj.Add("TextBoxName", tb.Name);
                moveObj.Add("sender", GlobalContext.localUsername);
                moveObj.Add("piece", piece);
                moveObj.Add("type", "move");
                return System.Text.Encoding.UTF8.GetBytes(moveObj.ToString());
            }
            public static byte[] buildNewGameMessageBytes()
            {
                JObject moveObj = new JObject();
                moveObj.Add("sender", GlobalContext.localUsername);
                moveObj.Add("type", "new");
                return System.Text.Encoding.UTF8.GetBytes(moveObj.ToString());
            }
        }
    

    GameOver TicTacToe game

BasePage

BasePage.cs

  • It exposes dependency properties for all settings that can be used in data binding by all xaml pages.

View Source Code