Moving the Space Pod Using Touch

Create iOS and Android games from scratch using Cocos2d-x.

Moving the Space Pod Using Touch

This article written by, Frahaan Hussain, Arutosh Gurung, and Gareth Jones, authors of the book Cocos2d-x Game Development Essentials, will cover how to set up touch events within our game. So far, the game has had no user interaction from a gameplay perspective. This article will rectify this by adding touch controls in order to move the space pod and avoid the asteroids.

(For more resources related to this topic, see here.)

The topics that will be covered in this article are as follows:

  • Implementing touch

    • Single-touch

    • Multi-touch

  • Using touch locations

  • Moving the spaceship when touching the screen

There are two main routes to detect touch provided by Cocos2d-x:

  • Single-touch: This method detects a single-touch event at any given time, which is what will be implemented in the game as it is sufficient for most gaming circumstances

  • Multi-touch: This method provides the functionality that detects multiple touches simultaneously; this is great for pinching and zooming; for example, the Angry Birds game uses this technique

Though a single-touch will be the approach that the game will incorporate, multi-touch will also be covered in this article so that you are aware of how to use this in future games.

The general process for setting up touches

The general process of setting up touch events, be it single or multi-touch, is as follows:

  1. Declare the touch functions.

  2. Declare a listener to listen for touch events.

  3. Assign touch functions to appropriate touch events as follows:

    • When the touch has begun
    • When the touch has moved
    • When the touch has ended
  4. Implement touch functions.

  5. Add appropriate game logic/code for when touch events have occurred.

Single-touch events

Single-touch events can be detected at any given time, and for many games this is sufficient as it is for this game.

Follow these steps to implement single-touch events into a scene:

  1. Declare touch functions in the GameScene.h file as follows:

    bool onTouchBegan(cocos2d::Touch *touch, cocos2d::Event * event);
    void onTouchMoved(cocos2d::Touch *touch, cocos2d::Event * event);
    void onTouchEnded(cocos2d::Touch *touch, cocos2d::Event * event);
    void onTouchCancelled(cocos2d::Touch *touch, cocos2d::Event * event);

    This is what the GameScene.h file will look like:

    The previous functions do the following:

    1. The onTouchBegan function detects when a single-touch has occurred, and it returns a Boolean value. This should be true if the event is swallowed by the node and false indicates that it will keep on propagating.

    2. The onTouchMoved function detects when the touch moves.

    3. The onTouchEnded function detects when the touch event has ended, essentially when the user has lifted up their finger.

    4. The onTouchCancelled function detects when a touch event has ended but not by the user; for example, a system alert. The general practice is to call the onTouchEnded method to run the same code, as it can be considered the same event for most games.

  2. Declare a Boolean variable in the GameScene.h file, which will be true if the screen is being touched and false if it isn't, and also declare a float variable to keep track of the position being touched:

    bool isTouching;
    float touchPosition;

    This is how it will look in the GameScene.h file:

  3. Add the following code in the init() method of GameScene.cpp:

    auto listener = EventListenerTouchOneByOne::create();
    listener->setSwallowTouches(true);
    listener->onTouchBegan = CC_CALLBACK_2(GameScreen::onTouchBegan, this);
    listener->onTouchMoved = CC_CALLBACK_2(GameScreen::onTouchMoved, this);
    listener->onTouchEnded = CC_CALLBACK_2(GameScreen::onTouchEnded, this);
    listener->onTouchCancelled = CC_CALLBACK_2(GameScreen::onTouchCancelled, this);
    this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);
    isTouching = false;
    touchPosition = 0;

    This is how it will look in the GameScene.cpp file:

  4. There is quite a lot of new code in the previous code snippet, so let's run through it line by line:

    1. The first statement declares and initializes a listener for a single-touch

    2. The second statement prevents layers underneath from where the touch occurred by detecting the touches

    3. The third statement assigns our onTouchBegan method to the onTouchBegan listener

    4. The fourth statement assigns our onTouchMoved method to the onTouchMoved listener

    5. The fifth statement assigns our onTouchEnded method to the onTouchEnded listener

    6. The sixth statement assigns our onTouchCancelled method to the onTouchCancelled listener

    7. The seventh statement sets the touch listener to the event dispatcher so the events can be detected

    8. The eighth statement sets the isTouching variable to false as the player won't be touching the screen initially when the game starts

    9. The final statement initializes the touchPosition variable to 0

  5. Implement the touch functions inside the GameScene.cpp file:

    bool GameScreen::onTouchBegan(cocos2d::Touch *touch,
    cocos2d::Event * event)
    {
    isTouching = true;
    touchPosition = touch->getLocation().x;
    return true;
    }
    void GameScreen::onTouchMoved(cocos2d::Touch *touch,
    cocos2d::Event * event)
    {
    // not used for this game
    }
    void GameScreen::onTouchEnded(cocos2d::Touch *touch,
    cocos2d::Event * event)
    {
    isTouching = false;
    }
    void GameScreen::onTouchCancelled(cocos2d::Touch *touch,
    cocos2d::Event * event)
    {
    onTouchEnded(touch, event);
    }

    The following is what the GameScene.cpp file will look like:

  6. Let's go over the touch functions that have been implemented previously:

    1. The onTouchBegan method will set the isTouching variable to true as the user is now touching the screen and is storing the starting touch position

    2. The onTouchMoved function isn't used in this game but it has been implemented so that you are aware of the steps for implementing it (as an extra task, you can implement touch movement so that if the user moves his/her finger from one side to another direction, the space pod gets changed)

    3. The onTouchEnded method will set the isTouching variable to false as the user is no longer touching the screen

    4. The onTouchCancelled method will call the onTouchEnded method as a touch event has essentially ended

  7. If the game were to be run, the space pod wouldn't move as the movement code hasn't been implemented yet. It will be implemented within the update() method to move left when the user touches in the left half of the screen and move right when user touches in the right half of the screen. Add the following code at the end of the update() method:

    // check if the screen is being touched
    if (true == isTouching)
    {
    // check which half of the screen is being touched
    if (touchPosition < visibleSize.width / 2)
    {
    // move the space pod left
    playerSprite->setPosition().x(playerSprite-
    >getPosition().x - (0.50 * visibleSize.width * dt));
    // check to prevent the space pod from going off
    the screen (left side)
    if (playerSprite->getPosition().x <= 0 +
    (playerSprite->getContentSize().width / 2))
    {
    playerSprite->setPositionX(playerSprite-
    >getContentSize().width / 2);
    }
    }
    else
    {
    // move the space pod right
    playerSprite->setPosition().x(playerSprite-
    >getPosition().x + (0.50 * visibleSize.width * dt));
    // check to prevent the space pod from going off the
    screen (right side)
    if (playerSprite->getPosition().x >=
    visibleSize.width - (playerSprite->
    getContentSize().width / 2))
    {
    playerSprite->setPositionX(visibleSize.width -
    (playerSprite->getContentSize().width / 2));
    }
    }
    }

    The following is how this will look after adding the code:

    The preceding code performs the following steps:

    1. Checks whether the screen is being touched.

    2. Checks which side of the screen is being touched.

    3. Moves the player left or right.

    4. Checks whether the player is going off the screen and if so, stops him/her from moving.

    5. Repeats the process until the screen is no longer being touched.

This section covered how to set up single-touch events and implement them within the game to be able to move the space pod left and right.

Multi-touch events

Multi-touch is set up in a similar manner of declaring the functions and creating a listener to actively listen out for touch events.

Follow these steps to implement multi-touch into a scene:

  1. Firstly, the multi-touch feature needs to be enabled in the AppController.mm file, which is located within the ios folder. To do so, add the following code line below the viewController.view = eaglView; line:

    [eaglView setMultipleTouchEnabled: YES];

    The following is what the AppController.mm file will look like:

  2. Declare the touch functions within the game scene header file (the functions do the same thing as the single-touch equivalents but enable multiple touches that can be detected simultaneously):

    void onTouchesBegan(const std::vector<cocos2d::Touch *>
    &touches, cocos2d::Event *event);
    void onTouchesMoved(const std::vector<cocos2d::Touch *>
    &touches, cocos2d::Event *event);
    void onTouchesEnded(const std::vector<cocos2d::Touch *>
    &touches, cocos2d::Event *event);
    void onTouchesCancelled(const std::vector<cocos2d::Touch *>

    &touches, cocos2d::Event *event);

    The following is what the header file will look like:

  3. Add the following code in the init() method of the scene.cpp file to listen to the multi-touch events that will use the EventListenerTouchAllAtOnce class, which allows multiple touches to be detected at once:

    auto listener = EventListenerTouchAllAtOnce::create();
    listener->onTouchesBegan = CC_CALLBACK_2
    (GameScreen::onTouchesBegan, this);
    listener->onTouchesMoved = CC_CALLBACK_2
    (GameScreen::onTouchesMoved, this);
    listener->onTouchesEnded = CC_CALLBACK_2
    (GameScreen::onTouchesEnded, this);
    listener->onTouchesCancelled = CC_CALLBACK_2
    (GameScreen::onTouchesCancelled, this);
    this->getEventDispatcher()-
    >addEventListenerWithSceneGraphPriority(listener, this);

    The following is how this will look:

  4. Implement the following multi-touch functions inside the scene.cpp:

    void GameScreen::onTouchesBegan(const std::
    vector<cocos2d::Touch *> &touches, cocos2d::Event *event)
    {
    CCLOG("Multi-touch BEGAN");
    }
    void GameScreen::onTouchesMoved(const std::
    vector<cocos2d::Touch *> &touches, cocos2d::Event *event)
    {
    for (int i = 0; i < touches.size(); i++)
    {
    CCLOG("Touch %i: %f", i, touches[i]-
    >getLocation().x);
    }
    }
    void GameScreen::onTouchesEnded(const std::
    vector<cocos2d::Touch *> &touches, cocos2d::Event *event)
    {
    CCLOG("MULTI TOUCHES HAVE ENDED");
    }
    Moving the Space Pod Using Touch
    [ 92 ]
    void GameScreen::onTouchesCancelled(const std::
    vector<cocos2d::Touch *> &touches, cocos2d::Event *event)
    {
    CCLOG("MULTI TOUCHES HAVE BEEN CANCELLED");
    }

    The following is how this will look:

  5. The multi-touch functions just print out a log, stating that they have occurred, but when touches are moved, their respective x positions are logged.

This section covered how to implement core foundations for multi-touch events so that they can be used for features such as zooming (for example, zooming into a scene in the Clash Of Clans game) and panning. Multi-touch wasn't incorporated within the game as it wasn't needed, but this section is a good starting point to implement it in future games.

Summary

This article covered how to set up touch listeners to detect touch events for single-touch and multi-touch. We incorporated single-touch within the game to be able to move the space pod left or right, depending on which half of the screen was being touched. Multi-touch wasn't used as the game didn't require it, but its implementation was shown so that it can be used for future projects.

Resources for Article:


Further resources on this subject:


Books to Consider

comments powered by Disqus