• Examples (HTML5)
• Examples (iOS)
• Examples (Android)
• Examples (C++)
Server API Documentation

 

» SpaceWar

» Overview

The SpaceWar example is a tribute to to the homonymous game developed in the 60s, one of the earliest computer games in history! The purpose of this example is to showcase the capabilities of SmartFoxServer 2X MMO Rooms in a realtime game featuring flying starships, weapon shots, collisions... with the possibility of having thousands of them in the same Room.

This example is the Cocos2d-x porting of its Flash counterpart. The two versions of the game share the same server-side Extension, which contains the core logic of the game, and a similar approach in client development. Also, the game flow and basic concepts like clients synchronization and Room configuration (but not only) are the same for the two versions. For this reason we strongly recommend that you read the in-depth Flash tutorial to learn the multiplayer programming techniques used in the Cocos2d-x version too.

The next paragraphs will describe the project setup, provide build instructions and draw your attention on a few steps of the development process specific to Cocos2d-x. Again, you should read the Flash tutorial for an extended explanation of the core game logic.
Also check the comments to methods and properties in the source code for additional informations and possible code optimizations.

>> DOWNLOAD the source files <<

» Target platforms

The game can be built for the following target platforms:

The Android version of the game can be built on both Windows (Visual Studio) and macOS (Xcode) development environments. The iOS and Windows versions require macOS and Windows respectively.
For your reference, the game was coded and tested both on Windows 10 and macOS Sierra 10.12.1.

» Client dependencies

The following libraries and development kits must be installed in the development environment; click on the download links for your environment. Also please follow the instructions below when provided:

» Project structure

The game project is actually split into two separate projects, for the client and the server Extension. They can be found in /client and /server folders respectively.

The client structure is split into:

» Server Extension

The game features a server-side Extension, as mentioned in the overview. We provide both the pre-compiled version (in the /server/deploy folder) and its source code (in the /server/source folder).

In order to deploy the pre-compiled Extension follow these steps:

  1. copy the SpaceWar folder from the /server/deploy/extensions folder to your SFS2X installation folder, under /SFS2X/extensions;
  2. copy the SpaceWar.zone.xml file (containing the Zone configuration) from the /server/deploy/zones folder to your SFS2X installation folder, under /SFS2X/zones.

In order to access the Extension code, create and setup a new project in your Java IDE of choice as described in the Writing a basic Extension document. Copy the content of the /source/src folder to your project's source folder.

» Client build

» SFS2X C++ API

Compile the SmartFoxServer 2X C++ API saved in the /client/sfs-api folder following the instructions provided in the official documentation for the target platform.

» iOS

  1. Open the Xcode project contained in the /client/client/SpaceWar/proj.ios_mac folder.
  2. Change the bundle identifier into whichever you want.
  3. Press Build.
  4. Run the game on the device.

NOTE
The Boost C++ library was built without the i386 flag, so the project cannot run on the iOS emulator.

» Android

  1. Follow the instruction on How to start a new game in the Cocos2d-x documentation. After the setup you should have ANT_ROOT, NDK_ROOT and ANDROID_SDK_ROOT in the environment variables. Make sure these variables point to the right Apache Ant and Android NDK versions as mentioned above.
  2. Make sure your Android SDK contains android-25. You can check it in the /platforms folder inside the Android SDK installation folder.
  3. Navigate to the /client/client/SpaceWar folder.
  4. Execute this command: $cocos run -p android.

» Windows

  1. Open the Visual Studio solution contained in the /client/client/SpaceWar/proj.win32 folder.
  2. Right click on the SmartfoxClientApi project and choose Properties.
  3. In General category, change the value of Output Directory to $(SolutionDir)$(Configuration).win32\ for both Debug and Release modes.
  4. Under Linker → General category, add $(SolutionDir)$(Configuration).win32\ path to Additional Library Directories, for both Debug and Release modes.
  5. Right click on the zlibvc project and choose Properties.
  6. In General category, change the value of Output Directory to $(SolutionDir)$(Configuration).win32\ for both Debug and Release modes.
  7. Build the project.

» Client highlights

» Sprites

All game objects in SpaceWar use the Sprite class for presentation. If this is new to you, please read this guide in the cocos2d-x documentation. In our project we created the following template function inside GameItem.cpp:

template <class T> 
T* createGameItem(const std::string& filename) {
        T *sprite = new (std::nothrow) T();
        if (sprite && sprite->initWithFile(filename)) {
            sprite->autorelease();
            return sprite;
        }
        CC_SAFE_DELETE(sprite);
        return NULL;
}

Starship.cpp uses this function to create the game's starships based on the type received from the server:

Starship* Starship::createShip(std::string type) {
    if (!strcmp(type.c_str(), "Astro"))
        return createGameItem<Starship>("ship_astro_0001.png");
    if (!strcmp(type.c_str(), "Raptor"))
        return createGameItem<Starship>("ship_raptor_0001.png");
    if (!strcmp(type.c_str(), "Viking"))
        return createGameItem<Starship>("ship_viking_0001.png");
}

» Animation

We use animations in bullets' explosions. If the animation concept is new to you, please read this guide in the cocos2d-x documentation. In order to optimize the animations, caching and reusing them, the AnimationCache class is used. The following code in the init function of GameScene.cpp does that:
if (!AnimationCache::getInstance()->getAnimation("exp")) {
    char* str = new char[100];
    Vector<SpriteFrame*> animFrames(11);
    for (int i = 1; i < 12; i++) {
        if (i < 10)
        	sprintf(str, "explosion_000%d.png", i);
        else
        	sprintf(str, "explosion_00%d.png", i);
        animFrames.pushBack(Sprite::create(str)->getSpriteFrame());
    }
    delete[]str;
    auto animation = Animation::createWithSpriteFrames(animFrames, 0.45f / 11);
    AnimationCache::getInstance()->addAnimation(animation, "exp");
}

After caching the animation with AnimationCache, we can retrieve and use it later in the WeaponShot class:

Animation* animation = AnimationCache::getInstance()->getAnimation("exp");
runAction(Sequence::createWithTwoActions(Animate::create(animation), RemoveSelf::create()));

We use the RemoveSelf class to remove the bullet from the stage after the explosion animation is completed.

» Input

In the desktop game, the player can use LEFT_ARROW and RIGHT_ARROW to rotate the ship, UP_ARROW for thrust and SPACE to shoot.
On mobile devices, we added some UI buttons to show overlay controls; also, we need to enable multi-touch feature in Cocos2d-x. Please read this article to learn how to do it.

To show the on-screen controls, the following code is added to GameScene.h to identify the target platform:

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
    #define SHOW_BUTTONS
#endif

In the desktop game, in order to handle user's input we need the EventListenerKeyboard class. This is implemented in GameScene.cpp's init function:

auto listener = EventListenerKeyboard::create();
listener->onKeyPressed = CC_CALLBACK_2(GameScene::onKeyPressed, this);
listener->onKeyReleased = CC_CALLBACK_2(GameScene::onKeyReleased, this);

_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);

On mobile platforms, we add the UI buttons using the Cocos2d-x approach, like in this example for left rotation button:

leftBtn = cocos2d::ui::Button::create("Left_Button_Normal.png", "Left_Button_Pressed.png", "Left_Button_Pressed.png");
leftBtn->setTitleText("");
leftBtn->setAnchorPoint(cocos2d::Vec2(1.0f, 0.5f));
leftBtn->addTouchEventListener([&](Ref* sender, ui::Widget::TouchEventType type) {
    switch (type) {
        case ui::Widget::TouchEventType::BEGAN:
            isLeftBtnPressed = true;
            break;
        case ui::Widget::TouchEventType::ENDED:
        case ui::Widget::TouchEventType::CANCELED:
            isLeftBtnPressed = false;
            break;
    }
});
leftBtn->setPosition(Vec2(149, 150));
addChild(leftBtn);

» More resources

You can learn more about the MMO Room features by consulting the following resources: