Nội dung bài viết
Đăng ký học lập trình C++
Tại STDIO bạn được dạy nền tảng lập trình tốt nhất.
Đăng ký học
Trong các bài viết trước trong chương trình tự học lập trình games với Cocos2d-x của STDIO. Tôi và các tác giả khác đã giới thiệu các khái niệm, ví dụ về các thành phần cơ bản để giúp các lập trình viên mới bắt đầu tìm hiểu Cocos2d-x có thể lập trình game 2D. Trong bài viết này, tôi sẽ giới thiệu cho các bạn làm thế nào để có thể tạo một game mulitiplay với Cocos2d-x thông qua Socket.IO.

Giới thiệu

Trong các bài viết trước trong chương trình tự học lập trình games với Cocos2d-x của STDIO. Tôi và các tác giả khác đã giới thiệu các khái niệm, ví dụ về các thành phần cơ bản để giúp các lập trình viên mới bắt đầu tìm hiểu Cocos2d-x có thể lập trình game 2D. Trong bài viết này, tôi sẽ giới thiệu cho các bạn làm thế nào để có thể tạo một game mulitiplay với Cocos2d-x thông qua Socket.IO.

Tiền đề bài viết

Bài viết là bài viết đầu tiên nằm trong loạt bài viết Network Trong Cocos2d-x.x chương trình tự học lập trình games với Cocos2d-x của STDIO.

  • Network trong Cocos2d-x 3.x.x: Socket.IO.
  • Network trong Cocos2d-x 3.x.x: WebSockets.
  • Network trong Cocos2d-x 3.x.x: HTTPClient.

Trong bài viết này tôi sẽ giới thiệu về một ví dụ sử dụng Socket.IO trong Cocos2d-x. Tôi tin các kiến thức sẽ giúp bạn có thể tạo một game mulitiplay đơn giản, cũng như hỗ trợ bước đầu cho bạn có thể làm được một game online.

Đối tượng hướng đến

Bài viết hướng đến các bạn đọc, các lập trình viên có đam mê, yêu thích với lập trình games 2D, đặc biệt là với engine Cocos2d-x. Bạn đọc nên có những kiến thức cơ bản nhất trong Lập Trình Games Với Cocos2d-x.

Trong bài viết tôi sử dụng Cocos2d-x version 3.11 và Vistual Stdio 2013 version 12.0.21005.1, Windows 10 64-bit.

Socket.IO là gì?

Socket.IO là một thư viện JavaScript và cũng là một loại WebSocket API. Việc bạn có kiến thức cơ bản với JavaScript sẽ giúp bạn dễ dàng tiếp cận.

Sự khác biệt rõ ràng nhất giữa Socket.IO và WebSockets:

  • Socket.IO cho phép send/emit messages bằng cách xác định bằng một tên event.
  • Trong trường hợp của Socket.IO: một message từ Server sẽ đến tất cả các Client đang kết nối. Với WebSockets: Nếu muốn điều tương tự như Socket.IO tôi cần phải tạo một mảng của tất cả các kết nối và lặp qua nó để gửi message đến tất cả các client.

Ở phần 2 tôi sẽ giới thiệu cụ thể hơn về sử dụng WebSocket trong Cocos2d-x 3.x.x để từ đó bạn có thể thấy rõ cũng như tùy vào mục đích trong thiết kế trong project game của bạn để có thể sử dụng cho phù hợp.

Cấu hình

Bạn download và cài đặt NodeJS như các software khác: https://nodejs.org.

Khởi tạo project của bạn. Ở đây tôi tạo một folder có tên là STDIO_SERVER.

Để cấu hình và chạy server. Bạn có thể: sử dụng command line hoặc GitSCM.

  • Vào folder STDIO_SERVER và sử dụng command line.
  • Sử dụng GitSCM: Right mouse click và selected Git Bash Here. Bạn có thể download Git tại http://git-scm.com.

Sau khi cài đặt NodeJS cũng như khởi tạo, cài đặt các software khác. Tiếp theo tôi sẽ cài đặt Socket.IO. Có 2 cách để cài đặt:

  • Sử dụng file manifest.
  • Không sử dụng file manifest (command line/GIT).

Sử dụng file manifest

Sử dụng file manifest package.json (file cấu hình) có nội dung như sau:

{
                "name":"stdio_server",
                "version":"0.0.1",
                "private":"true",
                "dependencies":{
                                "socket.io":"0.9.16",
                }
}

Ở đây trong phần dependencies tôi khai báo Socket.IO version 0.9.16.Với ý kiến cá nhân tôi, tôi thấy rằng với Socket.IO version 0.9.16 thì các function của server đều hoạt động ổn định.

Ngoài ra, nếu bạn sử dụng nhiều modules khác của Socket.IO như express,... thì bạn có thể khai báo vào trong phần dependencies này.

Sau đó, sử dụng command line/GIT và lệnh sau để cấu hình cho server.

npm install

Không sử dụng file manifest

Ngoài cách sử dụng file manifest package.json. Bạn có thể sử dụng command line hoặc GIT để cài đặt SocketIO với lệnh như sau:

 npm install socket.io@0.9.16

Với 0.9.16 chính là version của socket IO. Tương tự như với các modules khác như express.

Kết quả

Sau khi cấu hình xong. Trong folder STDIO_SERVER của tôi sẽ có một folder node_modules.

Capture

Hiện thực Server

Sau khi cấu hình xong, tôi tạo một file JavaScript có tên là STDIO_SERVER.js để có thể chạy Server của mình trong folder STDIO_SERVER

var http = require('http'),
socketIO = require('socket.io'),

port = 8888,
ip = '127.0.0.1',

server = http.createServer().listen(port, ip, function(){
    console.log('Socket.IO server started at %s:%s!', ip, port);
}),

io = socketIO.listen(server);

var run = function(socket){
    console.log('connect....');

    socket.emit('hello', 'Hello from Socket.IO');
    socket.send('Hello from SocketIO');
  
    socket.on('echotest', function (data) {
        console.log(data);
    })

    socket.on('message', function(msg){
        console.log('Received: ' + msg);
    });

    socket.disconnect('disconnect', function() {
        console.log('Client disconnect');
    });
}

io.sockets.on('connection', run);

Phân tích:

Trong NodeJS, function requires() được dùng để import một module.

  • Dòng 1-11: Đoạn code này sẽ khởi động một Server HTTP,  khai báo một biến server sử dụng module http có sẵn trong Node.js và lắng nghe ở port 888 (Chờ đợi một yêu cầu kết nối từ Client). Chú ý: lúc này Server vẫn chưa làm gì cả kể có khi có một yêu cầu kết nối từ Client
  • Dòng 13: Khi một Client kết nối với Server thì sẽ function này sẽ được gọi. Lúc này Server đã bắt đầu làm việc. Socket.IO cung cấp 3 event chính là connect, message và disconnect ở cả 2 phía server và client. Một client kết nối tới Server bằng function connect(). Tôi sẽ giới thiệu ở phần client
  • Dòng 16: Gửi dữ liệu tới cho tất cả các Client đang kết nối. Với tên event là hello và nội dung là Hello from Socket.IO
  • Dòng 17: Gửi dữ liệu tới cho tất cả các Client đang kết nối. Với tên event mặc định là message và nội dung là Hello from STDIO
  • Dòng 19-21: Nhận dữ liệu từ Client với tên event là echotest và nội dung là biến data
  • Dòng 23-25: Nhận dữ liệu từ Client với tên event là message và nội dung là biến msg. Cũng tương tự như ở Server, ở phía Client cũng có functin send() nhằm gửi dữ liệu với tên event mặc định là message
  • Dòng 27-29: Khi Server đóng kết nối với Client

Run Server

Để chạy Server, tôi dùng sử dụng lệnh sau:

node STDIO_SERVER.js

Capture(1)

Client

Khởi tạo dự án của bạn.Trong bài viết này, ví dụ của tôi sẽ thực hiện trên các file có sẵn sau khi tôi khởi tạo project:

  • HelloWordScene.h
  • HelloWordScene.cpp

HelloWordScene.h

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"
#include "ui/cocosGUI.h"

#include <network/SocketIO.h>

using namespace cocos2d::network;
using namespace cocos2d::ui;

class HelloWorld : public cocos2d::Layer, public SocketIO::SIODelegate
{
public:
    static cocos2d::Scene* createScene();

    virtual bool init();
    
    // a selector callback
    void menuCloseCallback(cocos2d::Ref* pSender);
    
    // implement the "static create()" method manually

    // socket.io even\vent listener
    void onReceiveEvent(SIOClient* client, const std::string& data);
    // SIODelegate
    virtual void onConnect(SIOClient* client);
    virtual void onMessage(SIOClient* client, const std::string& data);
    virtual void onClose(SIOClient* client);
    virtual void onError(SIOClient* client, const std::string& data);

    CREATE_FUNC(HelloWorld);

protected:
private:
    int index;
    SIOClient* _client;
    TextField* editBox;
};

#endif // __HELLOWORLD_SCENE_H__

Phân tích:

  • Dòng 7: Thêm thư viện để có thể làm việc với Socket.IO
  • Dòng 12: Khởi tạo class HelloWord có kế thừa public với SocketIO::SIODelegate
  • Dòng 25-30: Các phương thức làm việc với Server. Tôi sẽ giới thiệu các bạn rõ hơn ở phần HelloWordScene.cpp
  • Dòng 37: Khai báo một SocketClient. Tôi dùng biến này để connect, gửi data và nhận data với server

HelloWorldScene.cpp

#include "HelloWorldScene.h"

USING_NS_CC;

Scene* HelloWorld::createScene()
{
    // 'scene' is an autorelease object
    auto scene = Scene::create();
    
    // 'layer' is an autorelease object
    auto layer = HelloWorld::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if ( !Layer::init() )
    {
        return false;
    }
    
    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();

	// connect to server
	_client = SocketIO::connect("http://127.0.0.1:8888", *this);
	_client->on("message", CC_CALLBACK_2(HelloWorld::onReceiveEvent, this));
	_client->emit("message", "het hon chua");
    
    return true;
}

void HelloWorld::onConnect(SIOClient* client) {
	// SocketIO::connect success
}
void HelloWorld::onMessage(SIOClient* client, const std::string& data) {
	// SocketIO::send receive
}
void HelloWorld::onClose(SIOClient* client) {
	// SocketIO::disconnect success
}
void HelloWorld::onError(SIOClient* client, const std::string& data) {
	// SocketIO::failed
}

void HelloWorld::onReceiveEvent(SIOClient* client, const std::string& data) {
	auto lbl = Label::createWithTTF(data, "fonts/Marker Felt.ttf", 24);
	lbl->setPosition(Vec2(100, 100));
	this->addChild(lbl);
};

Phân tích:

  • Dòng 34: Thiết lập tới địa chỉ "http://127.0.0.1:8888". Gửi thông điệp tới Server một connect
  • Dòng 35: Thiết lập nhận dữ liệu từ server. Khi server gửi dữ liệu tới Client. Lúc này Client sẽ thực thi phương thức HelloWord::onReceiveEvent();
  • Dòng 36: Để gửi một tin nhắn tới Server. Cũng như Server ta sử dụng function emit(eventName, args)

Build/Run

Sau khi chạy server cũng như client (project game) tôi có kết quả sau:

Capture(2)

asd

Tổng kết

Trong bài viết này, tôi đã hoàn thành việc giới thiệu về một cách tạo một Server đơn giản cũng như các function cơ bản về thao tác cơ bản giữa Client (Cocos2d-x) với Server. Từ đây, bạn có thể sử dụng Socket.IO trong các project game mulitiplayer của mình. Bạn có thể download toàn bộ mã nguồn trong bài viết này ở phía dưới đây:

SERVER_ZIP

CLIENT_ZIP

Trong bài viết tiếp theo. Tôi sẽ giới thiệu về cách sử dụng Websockets trong Cocos2d-x 3.x.x.

Tham khảo

https://nodejs.org/en/

THẢO LUẬN