Sunday, January 24, 2016

Multiplayer Card Game using WebSockets,Java Netty Server ,Cocos2d-x-HTML5 - Part 6

Game Client Source code overview


The client in this game is developed using cocos2d-x framework using its JavaScript API,
This means by using this framework we are enabling our game to be cross platform .
With the
same code base !  including the WebSocket part 

The game client game logic will be explained using the web version of Cocos2d-x.
And in the end i will show you how to compile the source code in iOS and Windows Desktop

To develop in JavaScript and HTML5 you can choose several tools.
You can use simple text editor like Vi , Notepad++ , and debug the code With
build-in Chrome Debugger . 
Or you can take the full IDE Approach as i shown in this Tutorial :Debug Cocos2d-x HTML5 Project using NetBeans IDE and Chrome browser in 10 easy steps.

The game flow is very simple:
  1. Player enter its User name.
  2. Client Send the user name to the server
  3. Server confirms the user name and send back to the client
  4. Server Updates other client about new user 
  5. Client receives the confirmation from the server 
  6. Client enter to the Game room.
  7. Client plays , send the play move to server for confirmation 
  8. Server get the play move Confirms the move 
  9. Server send back confirmation to client and updates other clients about the player move

    and on and one until the game end  
You can see the game logic diagram for better understanding the game flow



Go to the source code you previously cloned from :
https://github.com/meiry/multiplayer_cocos2dx-js_using_netty_websockets

Go to the /Client/WarCardJS directory this is where all the client side source code are in.
To run it im using simple Apache server installed locally .
then start it by going to where the index.html is.  like normal static web site .


Before we start we need to configure few things in our Cocos2d-x framework
In the project.json file we adding the additional files and modules that is part of this Game 
in our case we added the JS files which we are going to be using in our game 
and additional Cocos2d-x module.

project.json


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
{
    "project_type": "javascript",

    "debugMode" : 1,
    "showFPS" : true,
    "frameRate" : 60,
    "noCache" : false,
    "id" : "gameCanvas",
    "renderMode" : 0,
    "engineDir":"frameworks/cocos2d-html5",

    "modules" : ["cocos2d","extensions"],

    "jsList" : [
        "src/GameConfig.js",
        "src/GameScene.js",       
        "src/resource.js",
        "src/app.js",        
        "src/Player.js"
    ]
}



  1. Line 12 : New module is added called "extensions"    for advance GUI 
  2. Line 15 - 19 : The new js source files the game is using .

main.js

This file is the game bootstrap , that mean here the game starts , the first game scene Initialize
here .



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
cc.game.onStart = function(){
    if(!cc.sys.isNative && document.getElementById("cocosLoading")) //If referenced loading.js, please remove it
        document.body.removeChild(document.getElementById("cocosLoading"));

    // Pass true to enable retina display, on Android disabled by default to improve performance
    cc.view.enableRetina(cc.sys.os === cc.sys.OS_IOS ? true : false);
    // Adjust viewport meta
    cc.view.adjustViewPort(true);
    // Setup the resolution policy and design resolution size
    cc.view.setDesignResolutionSize(450, 800, cc.ResolutionPolicy.SHOW_ALL);
    // Instead of set design resolution, you can also set the real pixel resolution size
    // Uncomment the following line and delete the previous line.
    // cc.view.setRealPixelResolution(960, 640, cc.ResolutionPolicy.SHOW_ALL);
    // The game will be resized when browser size change
    cc.view.resizeWithBrowserSize(true);
    //load resources
    cc.LoaderScene.preload(g_resources, function () {
        cc.director.runScene(new LoginScene());
    }, this);
};


  1. Line 10 : set the window resolution 
  2. Line 18 : The name of our first game scene called LoginScene ,
    the screen of the LoginScene will be shown first 


app.js 

This file is holding the main Scene called 
LoginScene  that Initialize  LOGIN Screen that lives inside the LoginLayer Object
This is the first file that starting the game .


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
var TEXT_INPUT_FONT_NAME = "Thonburi";
var TEXT_INPUT_FONT_SIZE = 36;
var sceneIdx = -1;
var TEXT_FIELD_ERR = 1;
var LoginLayer = cc.Layer.extend({
    sprite:null,
    size:null,
    textFieldUserName:null,
    textErorrConnectedField:null, 
    enterWorldScene:null,
    textField:null,
    ctor:function () {
        //////////////////////////////
        // 1. super init first
        this._super();
        this.size = cc.winSize;        
        return true;
    },
     onEnter:function () {
        //----start2----onEnter
        this._super();         
        var winSize = cc.director.getWinSize();
        // Create the textfield
        this.textField = new ccui.TextField();
        this.textField.setMaxLengthEnabled(true);
        this.textField.setMaxLength(30);
        this.textField.setTouchEnabled(true);
        this.textField.fontName = TEXT_INPUT_FONT_NAME;
        this.textField.fontSize = 30;
        this.textField.placeHolder = "[click here for user name]";
        this.textField.x = winSize.width / 2.0;
        this.textField.y = winSize.height / 2.0;
        this.textField.addEventListener(this.textFieldEvent, this);
        this.addChild(this.textField);
        cc.MenuItemFont.setFontSize(35);
        var menu = new cc.Menu(
            new cc.MenuItemFont("Login Game", this.loginGame, this)
            );
        menu.alignItemsVerticallyWithPadding(4);
        menu.x = this.size.width / 2;
        menu.y = this.size.height / 2 - 50;
        this.addChild(menu,5);
    },
     onExit:function () {
         this._super();    
    },
    createErrorMsg:function () {
            this.textErorrConnectedField = new cc.TextFieldTTF("Error Connecting Server try again",
                                                            TEXT_INPUT_FONT_NAME,
                                                            TEXT_INPUT_FONT_SIZE+20);
            this.textErorrConnectedField.setTag(TEXT_FIELD_ERR);            
            this.textErorrConnectedField.x = cc.winSize.width / 2;
            this.textErorrConnectedField.y = cc.winSize.height / 2 +50;
            this.addChild(this.textErorrConnectedField,2);  
    },
    
    loginGame:function (sender) {
        //remove error msg if any 
        if(this.getChildByTag(TEXT_FIELD_ERR)!==null)
        {
            this.removeChildByTag(TEXT_FIELD_ERR);
        }
        
        //check login in the server 
        var txtUserName = this.textField.getString();
        var config = {
                    event:Events.LOGIN,
                    username:txtUserName
     };
        var message = Encode(config);
        try {
            ws = new WebSocket("ws://localhost:8888/ws"); 
            ws.onopen = function() {
                    ws.send(message);
            };
            ws.onmessage = function (e) {
                console.log("app->srv.ws.onmessage():"+e.data);
                if(e.data!==null || e.data !== 'undefined')
                { 
                      var jsonFromClient = Decode(e.data);
                      if(jsonFromClient.event === Events.LOGIN_DONE)
                      {
                           enterWorldScene = new EnterWorldScene(jsonFromClient);
                           cc.director.runScene(enterWorldScene);
                      }
                }
            };
            ws.onclose = function (e) {
                    
            };
            ws.onerror = function (e) {
                  
            };
        } catch (e) {
            console.error('Sorry, the web socket at "%s" is un-available', url);
        }
    },
    onClickTrackNode:function (clicked) {
        var textField = this._trackNode;
        if (clicked) {
            textField.attachWithIME();
        } else {
            textField.detachWithIME();
        }
    },
});
var LoginScene = cc.Scene.extend({
    onEnter:function () {
        this._super();
        var layer = new LoginLayer();
        this.addChild(layer);
    }
    
});



  1. Lines 19 - 42 : Setup the Textbox and the login button 
  2. Line 37 : add listener to when the player is clicking the login button the loginGame function will be triggered.
  3. Lines 57 - 97 : The loginGame function , 
  4. Line 72 This function will open the WebSocket connection With the server .
    and wait for handshake confirmation from the server 
  5. Lines 76 -87 : the ws.onmessage callback is part of the browser WebSocket API
    and it is triggered when there is massage from the server.
  6. Lines 80 - 85 : when the massage is coming from the server first thing is the client do
    Is decode the JSON massage  , check if the event we receive are the right one in our case
    LOGIN_DONE ( as part of our protocol ) .
    If we got LOGIN_DONE it means the players was confirmed and we are ready to start the game and invoke the game scene called :"EnterWorldScene"  which holds the game logic.


     
In the next post i will teach you how the client game logic is developed:
Multiplayer Card Game using WebSockets,Java Netty Server ,Cocos2d-x-HTML5 - Part 7





11 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Thank you for your article!

    But link to seventh part of does not open and please add a link to github.

    ReplyDelete
  3. Sure !
    https://github.com/meiry/multiplayer_cocos2dx-js_using_netty_websockets

    ReplyDelete
  4. fixed the links and added the github link in the header

    ReplyDelete
  5. I'm doing a server for the game on the Unreal Engine, learning Netty by examples. I think you will be interested in this book ;)

    Multiplayer Game Programming: Architecting Networked Games (2015)

    https://kat.cr/multiplayer-game-programming-architecting-networked-games-2015-by-josh-glazer-sanjay-madhav-dr-soc-t12040097.html

    ReplyDelete
  6. Vadim it looks great !
    I will take alook

    ReplyDelete
  7. Nice post. I used to be checking continuously this blog and I am inspired! Very helpful info specially the last part. I take care of such information much. clash royale verifica

    ReplyDelete
  8. Thanks allot , im thinking about doing full game server tutorial soon
    using cluster servers , sticky session , and proxy server .
    Using Java as server and C++/HTML5 as client

    ReplyDelete
  9. Thanks for this article. I also invite you to visit this source page on how to spy on your spouse.

    ReplyDelete
  10. Hi. I am new to java and i have an idea of a card game that is played in my country. I am learning java to code that particular game. Your tutorial has given me a headway. Thank you so so much.

    ReplyDelete
  11. The object is to combine all the 52 cards in sets of 4 of a kind, such as 4 Threes, 4 Jacks, and so on, by grouping them in sets of 4 in the flower garden, and removing each set when it is completed.
    world of solitaire

    ReplyDelete