11. October 2014

 

 

So at this point in time we’ve covered configuring Cocos2d-x, basic graphics, mouse, touch and keyboard event handling but wouldn’t it be nice to, you know… do something?  Most games are pretty boring if they are completely static, no?  Well in this tutorial section we are going to make things a bit more interesting.  One of the ways we are going to add a bit of life to our game is using Actions, which we will cover in a second.  First we need to cover something else, the game loop.

 

Handling Updates

 

Pretty much every game ever made has a game loop, even if it’s hidden by the game engine.  A Cocos2d-x game is no exception, although it might not be immediately obvious.

What's a game loop?


A game loop is essentially the heart of a game, what causes the game to actually run. The following is a fairly typical game loop:

void gameLoop(){
   while (game != DONE){
      getInput();
      physicsEngine.stepForward();
      updateWorld();
      render();
   }
   cleanup();
}

 

As you can see, it's quite literally a loop that calls the various functions that make your game a game.  This is obviously a rather primitive example but really 90% of game loops end up looking very similar to this.

 

However, once you are using a game engine, things get slightly different.  All this stuff still happens, it’s just no longer your codes responsibility to handle it anymore.  Instead the game engine performs the loop and each step then calls back to your game code.  Consider when your game handles input events, where do those events come from?  Well chances are the game engine has a getInput() somewhere inside it, and as part of that process calls your event handlers.  Even though you don’t have to handle the games lifecycle yourself, it’s helpful to understand what’s going on behind the scenes.

 

So far in all of our examples we either handled everything in init() or in response to input event callbacks and that can only get you so far.  What happens when you want to update your game independently to input events?  One option is to update your game every time you render a frame of graphics, but this is generally not a great idea.  It’s very common to try to run graphics as fast as possible but update the game at a fixed frequency.  Plus, logically, does it really make sense to be updating stuff during a function that’s responsible for drawing graphics?  No, not really.

 

Fortunately there is a ready and much better named alternative… you guessed it, update.  The method update is part of the Node class and is easily overridden.  Let’s take a quick look at a game that handles update.  I got so sick of recreating scenes each time I created a new project, so the name might look somewhat familiar.

Also you are going to need a sprite for this sample.  Personally I am using a picture of my car… yeah, that’s it.

 

 

Veyron

 

Feel free to use whatever you want.  Now the code:

 

HelloWorld.h

#pragma once

#include "cocos2d.h"

class HelloWorld : public cocos2d::Layer
{
public:
    static cocos2d::Scene* createScene();
    virtual bool init() override;
    CREATE_FUNC(HelloWorld);

    void update(float) override;

private:
   cocos2d::Sprite* sprite;
};

 

HelloWorld.cpp

#include "HelloWorldScene.h"

USING_NS_CC;

Scene* HelloWorld::createScene()
{
    auto scene = Scene::create();
    auto layer = HelloWorld::create();
    scene->addChild(layer);
    return scene;
}

bool HelloWorld::init()
{
    if ( !Layer::init() )
    {
        return false;
    }
    
    sprite = Sprite::create("Veyron.png");
    sprite->setPosition(this->getBoundingBox().getMidX(), this->getBoundingBox().getMidY());
    this->addChild(sprite, 0);
    
    this->scheduleUpdate();
    return true;
}

void HelloWorld::update(float delta){
   auto position = sprite->getPosition();
   position.x -= 250 * delta;
   if (position.x  < 0 - (sprite->getBoundingBox().size.width / 2))
      position.x = this->getBoundingBox().getMaxX() + sprite->getBoundingBox().size.width/2;
   sprite->setPosition(position);
}

 

Now, if you run the code you get:

 

action1

 

So what’s going on here?  Well think back to that game loop example I gave earlier.  Now imagine somewhere deep inside Cocos2d-x when it performs the “updateWorld” portion, that it loops through all the the Nodes in the game and calls their update() method.  Well that’s basically exactly what happens.  The line:

 

     this->scheduleUpdate();

 

Is what tells Cocos2d-x to call the Node's update function.  We then override update to implement our logic.  The sole paramater passed to update is a float value representing the amount of time, in seconds since the last time the update function was called.  Therefore if it’s been 1/10 of a second since the last time update was called, the value passed in will be 0.1.

 

Inside the update itself, we simply change the position of our sprite until it is fully off screen on the left hand side.  At which point we move it to the right hand side and repeat the process.  The only code that is of interest here is this line:

position.x -= 250 * delta;

 

This is a pretty common technique in game dev for creating smooth animations.  What we are saying here is we want to move by 250 pixels to the left.  The problem is, we have no idea how fast our update is going to be called, so on a faster computer the car will move faster and on a slower computer it will move slower.  This is obviously not ideal.  Enter the delta value.  Since we know how long it was since the last frame, we know if we multiply our move amount by the fraction of a second each frame takes, it will perform roughly the same speed on all computers.  So, using the 0.10 value above, this means we are running 10 updates per second, so each time we will be updating by 250 * 0.10 or 25, literally a 10th of the amount we want to update.  If however this value is over one second, things will get screwy.  That said, if your game is running at less than 1FPS, you’ve got bigger problems to worry about!  So, in a nutshell, when moving on a frame by frame basis, express your units in seconds, then multiply them by the delta passed in to the update function.

 

Now remember earlier when I said it’s possible to run your updates in the render method but it wasn’t always ideal, how then do we control the frequency that our update is called?

 

Well, we can’t really as you never know how fast the computer or phone you are going to be running is.  You do however have control over the priority the updater will view your update function with.  By default when you call scheduleUpdate() your update function will be called every single frame.  If the node you are updating doesn’t actually need to be updated every frame, you are just wasting CPU power ( and battery life ).  If you have a lower priority update you can tell Cocos2d-x this using:

this->scheduleUpdateWithPriority(42);

 

The actual value passed in is simply relative to other priorities.  When Cocos is trying to decide which update’s to call, it will first call all of the update() that don’t have a priority set.  Then it will call the one with the lowest value, then the next highest, etc.  So if you have three Node with update set, one with no priority set, one with a priority of 42 and one with a priority of 13, the no priority update will be called first, then the 13 and finally the 42.  In some ways you aren’t actually setting the priority, you are setting the lack of priority! 

 

In place of overriding update() you can also use schedule and scheduleOnce to schedule any function to be called.  Either after a period of time or a number of times.  The called function needs to have the same profile as update, that is takes a single float parameter and a void return type.

 

Sometimes however instead of reacting each frame and updating your world, you just want to “fire and forget” something.  For example let’s say you want to move an object to a certain location over a certain period of time.  This is where Actions come in.

 

Using Actions

 

As just mentioned, Actions allow you to set something in motion and forget about it.  Actions are remarkably consistent in how they work, so I will only show small snippets of code for each one.  We are using the following code as our base:

 

#include "HelloWorldScene.h"

cocos2d::Scene* HelloWorld::createScene()
{
    auto scene = cocos2d::Scene::create();
    auto layer = HelloWorld::create();
    scene->addChild(layer);
    return scene;
}

bool HelloWorld::init()
{
    if ( !Layer::init() )
    {
        return false;
    }
    
    sprite = cocos2d::Sprite::create("Veyron.png");
    sprite->setPosition(this->getBoundingBox().getMidX(), this->getBoundingBox().getMidY());
    this->addChild(sprite, 0);
    
    auto listener = cocos2d::EventListenerKeyboard::create();
    listener->onKeyPressed = [=](cocos2d:: EventKeyboard::KeyCode code, cocos2d::Event * event)->void{
      // This is where our different actions are going to be implemented
      auto action = cocos2d::MoveTo::create(2, cocos2d::Vec2(0, 0));
      sprite->runAction(action);
   };

    this->_eventDispatcher->addEventListenerWithSceneGraphPriority(listener,this);
        return true;
}

 

This is also our first example of using an Action. In this case we are using the MoveTo action to move the target node to the position (0,0) over a duration of 2 seconds. You run the action on a Node using the runAction method.  Run it and press any key and you will see:

 

MoveTo

 

There are several similar actions, let’s take a look at a couple of them now.  Instead of MoveTo, there is also MoveBy, which enables you to move your node relative to it’s current position, like so:

 

   auto listener = cocos2d::EventListenerKeyboard::create();
   listener->onKeyPressed = [=](cocos2d:: EventKeyboard::KeyCode code, cocos2d::Event * event)->void{
      auto action = cocos2d::MoveBy::create(2, cocos2d::Vec2(300, 300));
      sprite->runAction(action);
   };

 

When you run this, instead of moving to a destination over a period of 2 seconds, we instead move by 300 right and 300 up over the same time period.

 

MoveBy

 

There are several similar Actions that can be used to transform and modify a Node such as RotateBy, RotateTo, ScaleTo, SkewTo, TintTo, TintBy and more.

 

In addition to transforming nodes, you can actually loop and sequence actions, to make combo’s.  Let’s take a look at an example of a sequence of several actions.  In this example we are going to perform a ScaleBy, TintTo then FadeTo back to back using the Sequence action.

 

   listener->onKeyPressed = [=](cocos2d:: EventKeyboard::KeyCode code, cocos2d::Event * event)->void{
      cocos2d::Vector<cocos2d::FiniteTimeAction*> actions;
      actions.pushBack(cocos2d::ScaleBy::create(1.5, 1.5));
      actions.pushBack(cocos2d::TintTo::create(1.5, 255, 0, 0));
      actions.pushBack(cocos2d::FadeTo::create(1.5, 30));
      
      auto sequence = cocos2d::Sequence::create(actions);

      sprite->runAction(sequence);
   };

 

And when run:

Sequence

 

There are two things to be aware of from this example. First you may notice that TintTo takes three GLubyte values to repesent the red, green and blue values of the colour, while FadeTo takes a single GLubyte value to represent that alpha or transparency.  A GLubyte is an 8bit value that ranges from 0 to 255 in value.  In all cases 255 is the fully on value, and 0 is the fully off value.  Therefore the value (255,0,0) is 100% red, 0% green, 0% blue, while the value 30 in TintTo is 30/255 or 11.7% opaque.  The second import thing to note is the use of Vector.  This is a cocos2d value type, NOT a std::vector, although ultimately behind the scenes, I believe it is still implemented using a std::vector.  This means you cant use it as a std::vector, nor can you use a std::vector where a cocos2d::Vector is expected.  This also unfortunately means you can’t use initializer lists.

 

So, that’s how you can perform a number of actions in sequence, what happens if you want to perform them all at once?  You can do that too using Spawn, which personally I think could really have a better name!  Let’s look at exactly the same example using Spawn instead.  The only difference is I increased the duration of each action to 4 seconds, mostly just to make it easier to screen capture. :)

 

   listener->onKeyPressed = [=](cocos2d:: EventKeyboard::KeyCode code, cocos2d::Event * event)->void{
      cocos2d::Vector<cocos2d::FiniteTimeAction*> actions;
      actions.pushBack(cocos2d::ScaleBy::create(4, 1.5));
      actions.pushBack(cocos2d::TintTo::create(4, 255, 0, 0));
      actions.pushBack(cocos2d::FadeTo::create(4, 30));
      
      auto parallel = cocos2d::Spawn::create(actions);

      sprite->runAction(parallel);
   };

 

And run it:

parallel

 

You also have the ability to repeat actions, both a certain number of times, or simply forever.  That is exactly what this example is going to do.  The first action moves to the right by 10 pixels every 0.2 of a second.  The second action scales the sprite up 30% every 2 seconds.  The first action will be repeated 10 times, the second forever, or until it crashes your computer that is. :)

 

   auto listener = cocos2d::EventListenerKeyboard::create();
   listener->onKeyPressed = [=](cocos2d:: EventKeyboard::KeyCode code, cocos2d::Event * event)->void{
      auto action = cocos2d::MoveBy::create(0.2, cocos2d::Vec2(10, 0));
      auto action2 = cocos2d::ScaleBy::create(2, 1.3);
      auto repeat = cocos2d::Repeat::create(action, 10);
      auto repeatForever = cocos2d::RepeatForever::create(action2);

      sprite->runAction(repeat);
      sprite->runAction(repeatForever);
   };

 

Running:

repeat

 

So far we’ve only looked at Actions inherited from ActionInterval, which are actions that happen over time.  There are also actions that happen instantly, let’s take a look at some of them now.  These actions inherit from ActionInstant.  In this example we illustrate several instant actions ( as well as a MoveTo, DelayTime and Sequence, as a bunch of instant actions doesn’t make for a great demonstration! )

 

   auto listener = cocos2d::EventListenerKeyboard::create();
   listener->onKeyPressed = [=](cocos2d:: EventKeyboard::KeyCode code, cocos2d::Event * event)->void{
      cocos2d::Vector<cocos2d::FiniteTimeAction*> actions;
      actions.pushBack(cocos2d::MoveTo::create(1, cocos2d::Vec2(0, 0)));
      actions.pushBack(cocos2d::DelayTime::create(1));
      actions.pushBack(cocos2d::Place::create(cocos2d::Vec2(
         this->getBoundingBox().getMidX(), this->getBoundingBox().getMidY())));
      actions.pushBack(cocos2d::DelayTime::create(1));
      actions.pushBack(cocos2d::FlipX::create(true));
      actions.pushBack(cocos2d::DelayTime::create(1));
      actions.pushBack(cocos2d::FlipY::create(true));
      actions.pushBack(cocos2d::DelayTime::create(1));
      actions.pushBack(cocos2d::Hide::create());
      actions.pushBack(cocos2d::DelayTime::create(1));
      actions.pushBack(cocos2d::Show::create());
      actions.pushBack(cocos2d::DelayTime::create(1));

      actions.pushBack(cocos2d::CallFunc::create([=]()->void{
         this->setColor(cocos2d::Color3B::RED);
      }));

      actions.pushBack(cocos2d::DelayTime::create(1));
      actions.pushBack(cocos2d::RemoveSelf::create(false));

      auto sequence = cocos2d::Sequence::create(actions);
      sprite->runAction(sequence);
   };

 

This code running:

Instant

 

As you can see, instant actions work almost indentically.  FlipX mirrors the Node along the X axis, FlipY does the same across the Y axis.  DelayTime we havent used yet, does exactly what it’s name says, delays for the given amount of seconds before executing the next Action.  The Place action can by thought of as a 0 duration MoveTo call, putting the Node at the specified position.

 

CallFunc and RemoveSelf are the two actions that probably require the most explanation.  CallFunc enables you to call code using an action, in this case I use a lambda that simply changes the background color of the Layer.  CallFunc is an incredibly important action and allows you to do just about anything using Actions, such as updating state, playing a sound, etc.  RemoveSelf is another handy action… it’s basically a kill switch.  When a removeSelf action is encountered, that Node is removed from it’s parent.  Passing true causing cleanup to be done.  This is incredibly handy for something like handling the lifespan of a bullet in the scene for example.

 

Setting a Layer's Background Color


You may have noticed I changed the background of the scene in the previous example using a call to setColor(). However if you try to run this code as is, you will notice it doesn't actually work. This is because, behind the scenes, I made a couple small changes. Instead of our scene inheriting from Layer we instead inherit from LayerColor, which adds, you guessed it, color information. Additionally, install of calling Layer::init() in our own init, we call LayerColor::initWithColor(). With these two changes you can now set the background color in the layer.

 


Odds and Ends

 

There are a few interesting topics that fit into this chapter but we didn’t cover yet, so I am going to shoehorn them here at the end.  One very common activity developer’s want to perform when working with Actions is to pause them.  As you can have several Actions running at once, so then, what do you do when you want to pause your game?  Thankfully it’s quite simple to accomplish using ActionManager.

 

HelloWorldScene.h

#pragma once

#include "cocos2d.h"

class HelloWorld : public cocos2d::LayerColor
{
public:
    static cocos2d::Scene* createScene();
    virtual bool init() override;
    CREATE_FUNC(HelloWorld);

private:
   cocos2d::Sprite* sprite,*sprite2;
   cocos2d::Label* label;
   bool spritePaused = false;
   cocos2d::Vector<Node*> pausedNodes;
};

 

HelloWorldScene.cpp

#include "HelloWorldScene.h"

cocos2d::Scene* HelloWorld::createScene()
{
    auto scene = cocos2d::Scene::create();
    auto layer = HelloWorld::create();
    scene->addChild(layer);
    return scene;
}

bool HelloWorld::init()
{
   if (!LayerColor::initWithColor(cocos2d::Color4B::BLACK))
    {
        return false;
    }
    
   label = cocos2d::Label::createWithSystemFont("Press space to pause all, 1 to pause left", "Arial", 30);
   label->setPosition(cocos2d::Vec2(this->getBoundingBox().getMidX(), this->getBoundingBox().getMaxY() - 20));

   sprite = cocos2d::Sprite::create("Veyron.png");
   sprite2 = cocos2d::Sprite::create("Veyron.png");
   sprite->setPosition(250, this->getBoundingBox().getMidY());
   sprite2->setPosition(700, this->getBoundingBox().getMidY());

   auto rotate = cocos2d::RotateBy::create(1, 45);
   auto rotate2 = cocos2d::RotateBy::create(1, -45);

   auto repeat1 = cocos2d::RepeatForever::create(rotate);
   auto repeat2 = cocos2d::RepeatForever::create(rotate2);

   this->addChild(label,0);
   this->addChild(sprite, 0);
   this->addChild(sprite2, 0);
    
   sprite->runAction(repeat1);
   sprite2->runAction(repeat2);
   auto listener = cocos2d::EventListenerKeyboard::create();
   listener->onKeyPressed = [=](cocos2d::EventKeyboard::KeyCode code, cocos2d::Event * event)->void{
      // On Spacebar, Pause/Unpause all actions and updates
      if (code == cocos2d::EventKeyboard::KeyCode::KEY_SPACE){
         if (pausedNodes.size()){
            cocos2d::Director::getInstance()->getActionManager()->resumeTargets(pausedNodes);
            pausedNodes.clear();
            spritePaused = false; // In case user currently has 1 pressed too
         }
         else
            pausedNodes = cocos2d::Director::getInstance()->getActionManager()->pauseAllRunningActions();
         label->setString("Spacebar pressed");
      }
      // Pause/UnPause just sprite 1
      if (code == cocos2d::EventKeyboard::KeyCode::KEY_1){
         if (spritePaused)
            sprite->resumeSchedulerAndActions();
         else
            sprite->pauseSchedulerAndActions();
         spritePaused = !spritePaused;
         label->setString("1 pressed");
      }
      
   };

   this->_eventDispatcher->addEventListenerWithSceneGraphPriority(listener,this);
   return true;
}

 

And run it:

ActionManager

 

As you can see using ActionManager you are able to pause execution of Actions, either to a single Node or all Nodes at once.  In the event of a single Node it’s simply a matter of calling pauseSchedulerAndActions and resumeSchedulerAndActions.  You can also call pause() which is also result in the Node no longer receiving events too.

 

In the event of pausing all running actions by calling getActionManager()->pauseAllRunningActions() this returns a cocos2d::Vector off all the Nodes that were paused.  When resuming, you simply pass this Vector back in a call to resumeTargets().

 

Earlier on we called scheduleUpdate() with resulted in our update method being called every frame.  However you can also schedule any kind of function using the scheduler.  Let’s take a look:

 

#include "HelloWorldScene.h"

cocos2d::Scene* HelloWorld::createScene()
{
    auto scene = cocos2d::Scene::create();
    auto layer = HelloWorld::create();
    scene->addChild(layer);
    return scene;
}


void HelloWorld::callOnce(float delta){
   cocos2d::MessageBox("Called after 10 seconds elapsed", "Message");
}

bool HelloWorld::init()
{
   if (!LayerColor::initWithColor(cocos2d::Color4B::BLACK))
    {
        return false;
    }
   
   this->scheduleOnce(schedule_selector(HelloWorld::callOnce), 10);
    return true;
}

 

This code will wait 10 seconds and then call our method callOnce().

 

So, even though the event loop is hidden away in a Cocos2d-x, there are plenty of ways you can control the action, be it using updates, scheduling functions to run or using Actions.

 

Programming , , ,

7. October 2014

 

 

In this part of the Cocos2d-x tutorial series we are going to take a look at what’s involved in handling keyboard events.  If you went through the mouse/touch tutorial, a lot of this is going to seem very familiar, as the process is quite similar.  That said, keyboard handling does have it’s own special set of problems to deal with.

Let's jump straight in to an example. Once again I assume you already know how create your own AppDelegate, if you can't, I suggest you jump back to this part first.

 

Handling Keyboard Events

 

Our first example is simply going to respond to WASD and Arrow keys to move the Cocos2d-x logo around the screen.  In this example I made no special modifications to a standard scene, so the header is unchanged from previous tutorials.

 

KeyboardScene.cpp

#include "KeyboardScene.h"

USING_NS_CC;

Scene* KeyboardScene::createScene()
{
    auto scene = Scene::create();
    
    auto layer = KeyboardScene::create();
    scene->addChild(layer);
    return scene;
}

bool KeyboardScene::init()
{
    if ( !Layer::init() )
    {
        return false;
    }
    
    auto sprite = Sprite::create("HelloWorld.png");
    sprite->setPosition(this->getContentSize().width/2, this->getContentSize().height/2);

    this->addChild(sprite, 0);

    auto eventListener = EventListenerKeyboard::create();



    eventListener->onKeyPressed = [](EventKeyboard::KeyCode keyCode, Event* event){

        Vec2 loc = event->getCurrentTarget()->getPosition();
        switch(keyCode){
            case EventKeyboard::KeyCode::KEY_LEFT_ARROW:
            case EventKeyboard::KeyCode::KEY_A:
                event->getCurrentTarget()->setPosition(--loc.x,loc.y);
                break;
            case EventKeyboard::KeyCode::KEY_RIGHT_ARROW:
            case EventKeyboard::KeyCode::KEY_D:
                event->getCurrentTarget()->setPosition(++loc.x,loc.y);
                break;
            case EventKeyboard::KeyCode::KEY_UP_ARROW:
            case EventKeyboard::KeyCode::KEY_W:
                event->getCurrentTarget()->setPosition(loc.x,++loc.y);
                break;
            case EventKeyboard::KeyCode::KEY_DOWN_ARROW:
            case EventKeyboard::KeyCode::KEY_S:
                event->getCurrentTarget()->setPosition(loc.x,--loc.y);
                break;
        }
    };

    this->_eventDispatcher->addEventListenerWithSceneGraphPriority(eventListener,sprite);

    return true;
}

 

When run, you see the logo centered and can move it around using either WASD or arrow keys.

KeyboardSS

The code works almost identically to our earlier Touch examples.  You create an EventListener, in this case a EventListenerKeyboard, implement the onKeyPressed event handler.  The first paramater passed in is the EventKeyboard::KeyCode enum, which is a value representing the key that was pressed.  The second value was the Event target, in this case our sprite.  We use the Event pointer to get the target Node and update it’s position in a direction depending on which key is pressed.  Finally we wire up our scene’s _eventDispatcher to receive events.  Nothing really unexpected here.

 

Polling the Keyboard

 

You may however ask yourself… what If I want to poll for keyboard events?  For example, what if you wanted to check to see if the spacebar was pressed at any given time?

 

Short answer is, you can’t.  Cocos2d-x is entirely event driven.

 

Long answer however is, it’s relatively easy to roll your own solution, so let’s do that now.  I’ll jump right in with the code and discuss it after.

 

KeyboardScene.h

#pragma once

#include "cocos2d.h"
#include <map>


class KeyboardScene : public cocos2d::Layer
{
public:

    static cocos2d::Scene* createScene();
    virtual bool init();

    bool isKeyPressed(cocos2d::EventKeyboard::KeyCode);
    double keyPressedDuration(cocos2d::EventKeyboard::KeyCode);

    CREATE_FUNC(KeyboardScene);

private:
    static std::map<cocos2d::EventKeyboard::KeyCode,
        std::chrono::high_resolution_clock::time_point> keys;
    cocos2d::Label * label;
public:
    virtual void update(float delta) override;
};

 

KeyboardScene.cpp

#include "KeyboardScene.h"

USING_NS_CC;

Scene* KeyboardScene::createScene()
{
    auto scene = Scene::create();
    
    KeyboardScene* layer = KeyboardScene::create();
    scene->addChild(layer);
    return scene;
}

bool KeyboardScene::init()
{
    if ( !Layer::init() )
    {
        return false;
    }

    label = cocos2d::Label::createWithSystemFont("Press the CTRL Key","Arial",32);
    label->setPosition(this->getBoundingBox().getMidX(),this->getBoundingBox().getMidY());
    addChild(label);
    auto eventListener = EventListenerKeyboard::create();



    Director::getInstance()->getOpenGLView()->setIMEKeyboardState(true);
    eventListener->onKeyPressed = [=](EventKeyboard::KeyCode keyCode, Event* event){
        // If a key already exists, do nothing as it will already have a time stamp
        // Otherwise, set's the timestamp to now
        if(keys.find(keyCode) == keys.end()){
            keys[keyCode] = std::chrono::high_resolution_clock::now();
        }
    };
    eventListener->onKeyReleased = [=](EventKeyboard::KeyCode keyCode, Event* event){
        // remove the key.  std::map.erase() doesn't care if the key doesnt exist
        keys.erase(keyCode);
    };

    this->_eventDispatcher->addEventListenerWithSceneGraphPriority(eventListener,this);

    // Let cocos know we have an update function to be called.
    // No worries, ill cover this in more detail later on
    this->scheduleUpdate();
    return true;
}

bool KeyboardScene::isKeyPressed(EventKeyboard::KeyCode code) {
    // Check if the key is currently pressed by seeing it it's in the std::map keys
    // In retrospect, keys is a terrible name for a key/value paried datatype isnt it?
    if(keys.find(code) != keys.end())
        return true;
    return false;
}

double KeyboardScene::keyPressedDuration(EventKeyboard::KeyCode code) {
    if(!isKeyPressed(EventKeyboard::KeyCode::KEY_CTRL))
        return 0;  // Not pressed, so no duration obviously

    // Return the amount of time that has elapsed between now and when the user
    // first started holding down the key in milliseconds
    // Obviously the start time is the value we hold in our std::map keys
    return std::chrono::duration_cast<std::chrono::milliseconds>
            (std::chrono::high_resolution_clock::now() - keys[code]).count();
}

void KeyboardScene::update(float delta) {
    // Register an update function that checks to see if the CTRL key is pressed
    // and if it is displays how long, otherwise tell the user to press it
    Node::update(delta);
    if(isKeyPressed(EventKeyboard::KeyCode::KEY_CTRL)) {
        std::stringstream ss;
        ss << "Control key has been pressed for " << 
            keyPressedDuration(EventKeyboard::KeyCode::KEY_CTRL) << " ms";
        label->setString(ss.str().c_str());
    }
    else
        label->setString("Press the CTRL Key");
}
// Because cocos2d-x requres createScene to be static, we need to make other non-pointer members static
std::map<cocos2d::EventKeyboard::KeyCode,
        std::chrono::high_resolution_clock::time_point> KeyboardScene::keys;

 

And when you run it:

ControlKey

 

So, what are we doing here?  Well essentially we record key events as they come in.  We have two events to work with, onKeyPressed and onKeyReleased.  When a key is pressed, we store it in a std::map, using the KeyCode as the key and the current time as the value.  When the key is released, we remove the released key from the map.  Therefore at any given time, we know which keys are pressed and for how long.  In this particular example, in the update() function ( ignore that for now, I’ll get into it later! ) we poll to see if the Control key is pressed.  If it is, we find out for how long and display a string.

 

So, even though polling isn’t built in to Cocos2d-x, it is relatively easy to add.

 

Dealing with Keyboards on Mobile Devices

 

So, what about keyboards on mobile devices?  All Android phones and iOS devices are able to display a Soft Keyboard ( the onscreen keyboard ), can we use it?  The answer is… sort of.

 

What's about physical keyboards on mobile devices?


You may be wondering, how does a physical keyboard on a mobile device work with Cocos2d-x? In the case of an iPad, the answer is, it doesn't. When I hooked up a Bluetooth Keyboard, absolutely nothing happened. The same occurred when I paired the keyboard to my Android phone. However, I do not have an Android device with a physical keyboard, such as the Asus Transformer, but my gut says it wouldn't work either. At least, not with you doing a lot of legwork that is

 

Sort of isn't really a great answer so I will go into a bit more detail.  Yes you can use the soft keyboard, but in a very limited manner.  Basically you can use it for text entry only.  Truth is though, this should be enough, as controlling a game using a soft keyboard would be a horrid experience.

 

Let’s take a look at an example using TextFieldTTF and implementing an TextFieldDelegate:

 

KeyTabletScene.h

#pragma once
#include "cocos2d.h"

class KeyTabletScene : public cocos2d::Layer, public cocos2d::TextFieldDelegate
{
public:
    virtual ~KeyTabletScene();

    virtual bool onTextFieldAttachWithIME(cocos2d::TextFieldTTF *sender) override;

    virtual bool onTextFieldDetachWithIME(cocos2d::TextFieldTTF *sender) override;

    virtual bool onTextFieldInsertText(cocos2d::TextFieldTTF *sender, const char *text, size_t nLen) override;

    virtual bool onTextFieldDeleteBackward(cocos2d::TextFieldTTF *sender, const char *delText, size_t nLen) 
override; virtual bool onVisit(cocos2d::TextFieldTTF *sender, cocos2d::Renderer *renderer, cocos2d::Mat4 const &transform, uint32_t flags) override; static cocos2d::Scene* createScene(); virtual bool init(); CREATE_FUNC(KeyTabletScene); };

 

KeyTabletScene.cpp

#include "KeyTabletScene.h"

USING_NS_CC;

Scene* KeyTabletScene::createScene()
{
    auto scene = Scene::create();
    
    auto layer = KeyTabletScene::create();
    scene->addChild(layer);

    return scene;
}

bool KeyTabletScene::init()
{
    if ( !Layer::init() )
    {
        return false;
    }


    // Create a text field
    TextFieldTTF* textField = cocos2d::TextFieldTTF::textFieldWithPlaceHolder("Click here to type",
            cocos2d::Size(400,200),TextHAlignment::LEFT , "Arial", 42.0);
    textField->setPosition(this->getBoundingBox().getMidX(),
            this->getBoundingBox().getMaxY() - 20);
    textField->setColorSpaceHolder(Color3B::GREEN);
    textField->setDelegate(this);

    this->addChild(textField);

    // Add a touch handler to our textfield that will show a keyboard when touched
    auto touchListener = EventListenerTouchOneByOne::create();

    touchListener->onTouchBegan = [](cocos2d::Touch* touch, cocos2d::Event * event) -> bool {
        try {
            // Show the on screen keyboard
            auto textField = dynamic_cast<TextFieldTTF *>(event->getCurrentTarget());
            textField->attachWithIME();
            return true;
        }
        catch(std::bad_cast & err){
            return true;
        }
    };

    this->_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, textField);

    return true;
}

KeyTabletScene::~KeyTabletScene() {

}

bool KeyTabletScene::onTextFieldAttachWithIME(TextFieldTTF *sender) {
    return TextFieldDelegate::onTextFieldAttachWithIME(sender);
}

bool KeyTabletScene::onTextFieldDetachWithIME(TextFieldTTF *sender) {
    return TextFieldDelegate::onTextFieldDetachWithIME(sender);
}

bool KeyTabletScene::onTextFieldInsertText(TextFieldTTF *sender, const char *text, size_t nLen) {
    return TextFieldDelegate::onTextFieldInsertText(sender, text, nLen);
}

bool KeyTabletScene::onTextFieldDeleteBackward(TextFieldTTF *sender, const char *delText, size_t nLen) {
    return TextFieldDelegate::onTextFieldDeleteBackward(sender, delText, nLen);
}

bool KeyTabletScene::onVisit(TextFieldTTF *sender, Renderer *renderer, const Mat4 &transform, uint32_t flags) {
    return TextFieldDelegate::onVisit(sender, renderer, transform, flags);
}

 

And when you run it:

TabletKeyboardShot

 

Essentially when the user touches the screen, we display the onscreen keyboard with a call to attachWithIME(), the rest is handled by the textfield.

 

I have a sneaking feeling this method is going to be depreciated at some point in the future, being replaced by cocos::ui classes, but for now it works just fine.  For the record, it is actually possible to force up the onScreen keyboard by calling Director::getInstance()->getOpenGLView()->setIMEKeyboardState(true), but it seemingly pushes your scene to the background, so isn’t a viable option for controlling a game.  I was going to look into a work around but then thought, really… this is a downright stupid thing to do.  Doing anything other than text entry with a soft keyboard is just a bad idea.

 

 

Programming , ,

3. October 2014

 

 

In this part of the Cocos2d-x tutorial series we are going to look at how to handle touch and mouse events .  First you should be aware that by default Cocos2d-x treats a mouse left click as a touch, so if you only have simple input requirements and don’t require multi-touch support ( which is remarkably different to perform with a single mouse! ), you can simply implement just touch handlers.  This part is going to be code heavy, as we actually have 3 different tasks to cover here ( touch, multi-touch and mouse ), although all are very similar in overall behavior.

 

Let’s jump in with an ultra simple example.  Once again, I assume you’ve done the earlier tutorial parts and already have an AppDelegate.

 

Handle Touch/Click Events

 

TouchScene.h

#pragma once

#include "cocos2d.h"

class TouchScene : public cocos2d::Layer
{
public:
    static cocos2d::Scene* createScene();
    virtual bool init();  

    virtual bool onTouchBegan(cocos2d::Touch*, cocos2d::Event*);
    virtual void onTouchEnded(cocos2d::Touch*, cocos2d::Event*);
    virtual void onTouchMoved(cocos2d::Touch*, cocos2d::Event*);
    virtual void onTouchCancelled(cocos2d::Touch*, cocos2d::Event*);
    CREATE_FUNC(TouchScene);

private:
   cocos2d::Label* labelTouchInfo;
};

TouchScene.cpp

 

#include "TouchScene.h"

USING_NS_CC;

Scene* TouchScene::createScene()
{
    auto scene = Scene::create();
    auto layer = TouchScene::create();
    scene->addChild(layer);

   return scene;
}

bool TouchScene::init()
{
    if ( !Layer::init() )
    {
        return false;
    }
    
   labelTouchInfo = Label::createWithSystemFont("Touch or clicksomewhere to begin", "Arial", 30);

   labelTouchInfo->setPosition(Vec2(
      Director::getInstance()->getVisibleSize().width / 2,
      Director::getInstance()->getVisibleSize().height / 2));

   auto touchListener = EventListenerTouchOneByOne::create();

   touchListener->onTouchBegan = CC_CALLBACK_2(TouchScene::onTouchBegan, this);
   touchListener->onTouchEnded = CC_CALLBACK_2(TouchScene::onTouchEnded, this);
   touchListener->onTouchMoved = CC_CALLBACK_2(TouchScene::onTouchMoved, this);
   touchListener->onTouchCancelled = CC_CALLBACK_2(TouchScene::onTouchCancelled, this);

   _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
    
   this->addChild(labelTouchInfo);
   return true;
}

bool TouchScene::onTouchBegan(Touch* touch, Event* event)
{
   labelTouchInfo->setPosition(touch->getLocation());
   labelTouchInfo->setString("You Touched Here");
   return true;
}

void TouchScene::onTouchEnded(Touch* touch, Event* event)
{
   cocos2d::log("touch ended");
}

void TouchScene::onTouchMoved(Touch* touch, Event* event)
{
   cocos2d::log("touch moved");
}

void TouchScene::onTouchCancelled(Touch* touch, Event* event)
{
   cocos2d::log("touch cancelled");
}

 

Then if you run it, when you perform a touch or click:

image

 

As you can see, where you touch on the screen a text label is displayed.  Looking in the background of that screenshot you can see touch moved events are constantly being fired and logged.  Additionally touch ended events are fired when the user removes their finger ( or releases the mouse button ).

 

Now let’s take a quick look at the code.  Our header file is pretty straight forward.  In addition to the normal methods, we add a quartet of handler functions for handling the various possible touch events.  We also add a member variable for our Label used to draw the text on the screen.

 

In the cpp file, we create the scene like normal.  In init() we create an EventListener of type EventListenerTouchOneByOne, which predictably handles touches, um, one by one ( as opposed to all at once, which we will see later ).  We then map each possible event, touch began, touch end, touch cancelled and touch moved, to their corresponding function handler using the macro CC_CALLBACK_2, passing  the function to execute and the context ( or target ).  This too will make sense later, so hold on there.  One thing to watch out for here, and one point of confusion for me, onTouchBegan has a different signature than every other event, returning a bool.  I am not entirely certain why this one event is handled differently, seems like a bad idea to me personally, but there may be a good design reason I am unaware of.

 

The last thing we do is register our EventListener to receive events.  This is done with a call to Node’s protected member _eventListener.  We call addEventListenerWithSceneGraphPriority(), which basically means we want this event to be updated as much as possible.  We will see an example of setting a different priority level later on.

 

What's this CC_CALLBACK_2 black magic?


I'm generally not a big fan of macro usage in C++. I generally believe they lead programmers to eventually turn their libraries into meta-programming languages and ultimately obfuscate the underlying code in the name of clarity. This however, is one of the exceptions to the rule. CC_CALLBACK_2, and the entire CC_CALLBACK_ family is simply a wrapper around some standard C++ code, specifically a call to std::bind. Here is the actual macro code:

#define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)
#define CC_CALLBACK_1(__selector__,__target__, ...) std::bind(&__selector__,__target__, 
std::placeholders::_1, ##__VA_ARGS__)
#define CC_CALLBACK_2(__selector__,__target__, ...) std::bind(&__selector__,__target__, 
std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)
#define CC_CALLBACK_3(__selector__,__target__, ...) std::bind(&__selector__,__target__, 
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, ##__VA_ARGS__)

Basically std::bind is binding for binding parameters to a function. The std::placeholders are ultimately the number of parameters your function expects. So for example, when you call CC_CALLBACK_2, you are saying that function takes two parameters, in this case a Touch* point and an Event* pointer. Similarly CC_CALLBACK_1 would expect the provided function to take a single parameter. This kind of code is incredibly common in C++11, it's incredibly ugly, hard to read and grok and it's easy to mistype. In these cases, macro use shines. Just be aware of what it is the macro you are calling does. Each time you encounter a macro in code, I recommend you right click and "Go to Definition" or CTRL+Click if in XCode, to see what it actually does, even if it doesn't make complete sense.

 

 

In most of the touch handlers, we simply log that the event occurred.  In the event of a touch starting ( or click beginning ) we update the position of the label to where the user clicked and display the string “You Touched Here”.

 

Now let’s take a look at an example that uses lambda’s instead.  This example also goes into a bit more detail of what’s in that Touch pointer we are being passed.  The header file is basically the same, except there are no onTouch____ functions.

 

Handling Touch Events using Lambdas and dealing with Touch coordinates

 

TouchScene.cpp

#include "TouchScene.h"

USING_NS_CC;

Scene* TouchScene::createScene()
{
    auto scene = Scene::create();
    auto layer = TouchScene::create();
    scene->addChild(layer);

    return scene;
}

bool TouchScene::init()
{
    if ( !Layer::init() )
    {
        return false;
    }
    
   auto sprite = Sprite::create("HelloWorld.png");
   sprite->setPosition(Vec2(Director::getInstance()->getVisibleSize().width / 2,
      Director::getInstance()->getVisibleSize().height / 2));

    // Add a "touch" event listener to our sprite
   auto touchListener = EventListenerTouchOneByOne::create();
   touchListener->onTouchBegan = [](Touch* touch, Event* event) -> bool {

      auto bounds = event->getCurrentTarget()->getBoundingBox();

      if (bounds.containsPoint(touch->getLocation())){
         std::stringstream touchDetails;
         touchDetails << "Touched at OpenGL coordinates: " << 
            touch->getLocation().x << "," << touch->getLocation().y << std::endl <<
            "Touched at UI coordinate: " << 
            touch->getLocationInView().x << "," << touch->getLocationInView().y << std::endl <<
            "Touched at local coordinate:" <<
            event->getCurrentTarget()->convertToNodeSpace(touch->getLocation()).x << "," <<  
            event->getCurrentTarget()->convertToNodeSpace(touch->getLocation()).y << std::endl <<
            "Touch moved by:" << touch->getDelta().x << "," << touch->getDelta().y;

            MessageBox(touchDetails.str().c_str(), "Touched");
         }
      return true;
      };

   Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(touchListener,sprite);
   this->addChild(sprite, 0);
    
    return true;
}

 

Now when you run it:

image

 

In this example, the touch event will only fire if the user clicked on the Sprite in the scene.  Notice the first line in the onTouchBegan handler I call event->getCurrentTarget()?  This is where the context becomes important.  In the line:

Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(touchListener,sprite);

The second parameter, sprite, is what determines the target of the Event.  The target is passed as a Node but can be cast if required.

 

Lambda?


Lambda's are a new feature of C++ and they are probably something you will love or hate. If you come from C++ or C# you will probably find them long over due, I certainly do!
Lambda is a scary sounding expression coming from the scary looking symbol Λ. In the world of mathematics, Lambda calculus basically gives math the ability to define functions, something we as programmers can certainly appreciate. In the world of programming, it's nowhere near as scary, a lamdba expression can also be thought of as an anonymous function. In simple terms, it allows you to create a nameless function where you need it. As you can see from this example, it allows you to put event handling logic where it makes most sense, instead of spliting it out into a seperate function. It is also a godsend when you want to pass a function as a parameter, a very common task in the C++ standard libraries.
The syntax of C++ lambda's is pretty ugly, but they are certainly a valuable addition to the language. Most importantly, they can often make your code easier to express and as such, easier to comprehend and maintain. Learn to love the lamdba and the lambda will learn to love you. Maybe.

 

In this example, we use the target node to only handle clicks that happen within the bounds of our Sprite Node.  This is done by testing if the touch location is within the bounding box of the node.  If it is, we display a number of details in a message box.  Remember back in this tutorial part where I said there are multiple coordinate systems, this is a perfect example.  As you can see from the message box above, getLocation() and getLocationInView() return different values, one relative to the top left corner of the screen, while the other is relative to the bottom left corner of the screen. 

 

Sometimes as well you want to know where the click occurred relative to the node.  Such as in the sample above, the local coordinate is the position the click occurred relative to the node’s origin.    In order to calculate this location we use the helper function convertToNodeSpace().  One final thing you may notice is I registered the EventListener with Director() instead of _eventListener.  This was the old way of doing things and I did it this way for a couple reasons.  First, to show that you can.  Second, because _eventListener is a protected member, I would only have access to it if I derived my own Sprite object.

 

Now let’s take a look at a multi-touch example.

 

Dealing with Multi-touch

 

Multi-touch works pretty much the same way, just with a separate set of event handlers.  There are a few catches however.  The big one is iOS.  Out of the box, Android just works.  iOS however requires you to make a small code change to enable multitouch support.  Don’t worry, it’s a simple process. 

 

In your project, locate the directory /proj.ios_mac/ios and open the file AppController.mm.  Then add the following line:

AppControllerMM

 

Simply add the line [eaglView setMultipleTouchEnabled:YES]; somewhere after the creation of eaglView.  Now multitouch should work in your iOS application, let’s look at some code:

 

MultiTouchScene.h

#pragma once

#include "cocos2d.h"

class MultiTouch : public cocos2d::Layer
{

    public:
        static cocos2d::Scene* createScene();

        virtual bool init();
        CREATE_FUNC(MultiTouch);
    private:
        const static int MAX_TOUCHES = 5;

    protected:
        cocos2d::Label* labelTouchLocations[MAX_TOUCHES];

};

 

MultiTouchScene.cpp

#include "MultiTouchScene.h"

USING_NS_CC;

Scene* MultiTouch::createScene()
{
    auto scene = Scene::create();
    auto layer = MultiTouch::create();
    scene->addChild(layer);

    return scene;
}

bool MultiTouch::init()
{
    if ( !Layer::init() )
    {
        return false;
    }

    // Create an array of Labels to display touch locations and add them to this node, defaulted to invisible
    for(int i= 0; i < MAX_TOUCHES; ++i) {
        labelTouchLocations[i] = Label::createWithSystemFont("", "Arial", 42);
        labelTouchLocations[i]->setVisible(false);
        this->addChild(labelTouchLocations[i]);
    }

    auto eventListener = EventListenerTouchAllAtOnce::create();

    //  Create an eventListener to handle multiple touches, using a lambda, cause baby, it's C++11
    eventListener->onTouchesBegan = [=](const std::vector<Touch*>&touches, Event* event){

        // Clear all visible touches just in case there are less fingers touching than last time
        std::for_each(labelTouchLocations,labelTouchLocations+MAX_TOUCHES,[](Label* touchLabel){
            touchLabel->setVisible(false);
        });

        // For each touch in the touches vector, set a Label to display at it's location and make it visible
        for(int i = 0; i < touches.size(); ++i){
            labelTouchLocations[i]->setPosition(touches[i]->getLocation());
            labelTouchLocations[i]->setVisible(true);
            labelTouchLocations[i]->setString("Touched");
        }
    };

    _eventDispatcher->addEventListenerWithSceneGraphPriority(eventListener, this);

    return true;
}

 

Here is the code running on my iPad with multiple fingers touched:

IMG_0189

 

Granted, not the most exciting screen shot ever, but as you can see, each location the user touch, a label is printed.  Let’s take a quick look at the code and see what’s happening.  At this point, most of it should be pretty familiar, so let’s just focus on the differences.

 

First you will notice I added an array of Labels MAX_TOUCH in size.  I chose 5 as frankly, that seems to be the limit of what I could register on iPad.  I had it set to 10, but it never registered more than 5, so 5 it was!  Truth of the matter is, I can’t really imagine a control scheme that used more then 5 touches being all that useful, so 5 touches seems like a reasonable limitation, even though I’m pretty certain the hardware can handle more.

 

In our init() we start off by allocating each of our labels and setting their initial visibility to invisible.  Then we create our EventListener, this time we create an EventListenerTouchAllAtOnce because we want to, well, get all the touch events at the same time.  Instead of handling onTouchBegan, we instead handle onTouchesBegan, which takes a std::vector ( careful here, as cocos2d has it’s own vector class… the peril of using namespace abuse! ) of Touch* as well as an Event*.

 

In the event of touch(es), we first loop through all of our labels and set them to invisible.  Then for each touch in the touches vector, we move a label to that position and make it visible.  Once again we register the EventListener with our node’s _eventDispatcher.

 

So, we’ve covered touch and multi-touch, what about when you want to use the mouse?  Amazingly enough there are users out there with mice with more than a single button after all! ;)

 

Handling the Mouse

 

At this point you can probably guess the code I am about to write, as the process is remarkably similar, but let’s go through it anyways.  I wont bother with the .h file, there’s nothing special in there.

 

MouseScene.cpp

#include "MouseScene.h"

USING_NS_CC;

cocos2d::Scene* MouseScene::createScene()
{
    auto scene = Scene::create();
    auto layer = MouseScene::create();
    scene->addChild(layer);

    return scene;
}

bool MouseScene::init()
{
    if ( !Layer::init() )
    {
        return false;
    }   

   auto listener = EventListenerMouse::create();
   listener->onMouseDown = [](cocos2d::Event* event){

      try {
         EventMouse* mouseEvent = dynamic_cast<EventMouse*>(event);
         mouseEvent->getMouseButton();
         std::stringstream message;
         message << "Mouse event: Button: " << mouseEvent->getMouseButton() << "pressed at point (" <<
            mouseEvent->getLocation().x << "," << mouseEvent->getLocation().y << ")";
         MessageBox(message.str().c_str(), "Mouse Event Details");

      }
      catch (std::bad_cast& e){
         // Not sure what kind of event you passed us cocos, but it was the wrong one
         return;
      }
   };

   listener->onMouseMove = [](cocos2d::Event* event){
      // Cast Event to EventMouse for position details like above
      cocos2d::log("Mouse moved event");
   };

   listener->onMouseScroll = [](cocos2d::Event* event){
      cocos2d::log("Mouse wheel scrolled");
   };

   listener->onMouseUp = [](cocos2d::Event* event){
      cocos2d::log("Mouse button released");
   };

   _eventDispatcher->addEventListenerWithFixedPriority(listener, 1);

    return true;
}

 

Now run it, scroll the mouse wheel a couple times, click and you will see:

image

 

Yeah… not really exciting either.  As you can see, when you click a mouse the button is returned as a number.  Left button is 0, middle is 1, right is 2, etc.  The code is all very familiar except we use a EventListenerMouse this time and handle onMouseDown, onMouseUp, onMouseMove and onMouseScroll.  The only other thing of note is you need to cast the provided Event pointer to a EventMouse pointer to get access to the mouse details.

 

With the exception of gestures, that should pretty much cover all of your mouse and touch needs.  Gesture’s arent actually supported out of the box, but extensions exist.  Additionally, all mouse and touch events contain delta information as well as data on the previous touch/click, which should make rolling your own fairly simple.

 

Programming , ,

1. October 2014

 

 

Now that we have Cocos2d-x installed and configured and our project created, we are going to take a look at basic graphics operations.  This tutorial assumes you ran through the prior part and created a project already.  I am going to assume you have a working AppDelegate, so I will only focus on creating a new scene object.   The only changes you should have to make are to change your delegate to #include a different file and change the type of scene you call createScene() on.

 

Ok, let’s jump right in with with a simple example.  First we are going to need an image to draw.  Personally I am going to use this somewhat… familiar image:

 

decepticon

 

It’s 400x360, with a transparent background named decepticon.png.  Of course you can use whatever image you want.  Just be certain to add the image to the resources directory of your project.

 

image

 

Ok, now the code to display it.

 

GraphicsScene.h

#pragma once

#include "cocos2d.h"

class GraphicsScene : public cocos2d::Layer
{
public:
    static cocos2d::Scene* createScene();
    virtual bool init();  
    CREATE_FUNC(GraphicsScene);
};

 

GraphicsScene.cpp

#include "GraphicsScene.h"

USING_NS_CC;

Scene* GraphicsScene::createScene()
{
    auto scene = Scene::create();
    auto layer = GraphicsScene::create();
   scene->addChild(layer);
    
    return scene;
}

bool GraphicsScene::init()
{
    if ( !Layer::init() )
    {
        return false;
    }
    
    auto sprite = Sprite::create("decepticon.png");
    sprite->setPosition(0, 0);
   
    this->addChild(sprite, 0);
    
    return true;
}

 

Now when you run this code:

image

 

Hmmm, probably not exactly what you expected to happen, but hey, congratulations, you just rendered your first sprite!

 

So, what exactly is happening here?  Well after we created our sprite we called:

sprite->setPosition(0, 0);

This is telling the sprite to position itself at the pixel location (0,0).  There are two things we can take away from the results.

 

1- The position (0,0) is at the bottom left corner of the screen.

2- By default, the position of a sprite is relative to it’s own center point.

 

Which way is up?

 

One of the most confusing things when working in 2D graphics is dealing with all the various coordinate systems.  There are two major approaches to dealing with locations in 2D, having the location (0,0) at the top left of the screen and having the location (0,0) at the bottom left of the screen.  This point is referred to as the Origin.  It is common for UI systems, the most famous of which being Windows, to set the origin at the top left of the screen.  It is also most common for graphics files to store their image data starting from the top left pixel, but by no means is this universal.  On the other hand OpenGL and most mathematicians treat the bottom left corner of the screen as the origin.  If you stop and think about it, this approach makes a great deal of sense.

Think back to your high school math lessons ( unless of course you are in high school, in which case pay attention to your math lessons! ) and you will no doubt have encountered this graphic.

cartPlane

This is a graphic of the Cartesian plane and it is pretty much the foundation of algebra.  As you can clearly see, the positive quadrant ( the quarter of that graph with both positive x and y values ) is in the top right corner.  Quite clearly then, to a mathematician the value (0,0) is at the bottom left corner of the top right quadrant.

 

There are merits to both approaches of course, otherwise there would be only one way of doing things!

 

This will of course lead to some annoying situations, where one API for example delivers touch coordinates in UI space, relative to the top left corner, or when you load a texture that is inverted to what you actually wanted.

 

Fortunately, Cocos2d-x provides functionality to make these annoyances a little bit less annoying.  Just be aware going forward, that coordinate systems can and do change!  Also be aware, unlike some frameworks, Cocos2d-x does *NOT* allow you to change the coordinate system.  The origin in Cocos2d-x is always at the bottom left corner.

 

Sometimes positioning relative to the middle can be ideal, especially when dealing with rotations.  However, sometimes you want to position relative to another point, generally using the top left or bottom left corner.  This is especially true if for example you want to, say… align the feet of a sprite to the top of a platform.  Changing the way a sprite ( or any Node ) is positioned is extremely simple in Cocos2d-x.  This is done using something called an Anchor Point.  Simply change the code like so:

 

   auto sprite = Sprite::create("decepticon.png");
   sprite->setAnchorPoint(Vec2(0, 0));
   sprite->setPosition(0, 0);

 

And presto!

image

 

Now our sprite is positioned relative to it’s bottom left corner.  However, setAnchorPoint() might not take the parameters you expect it to.  Yes, you are passing it in x and y coordinates that represent the location on the sprite to perform transforms relative to.  However, we are dealing with yet another coordinate system here, sometimes referred to as Normalized Device Coordinates (NDC).  These values are represented by two numbers, one for x and one for y, from 0 to 1, and they are a position within the sprite.

 

Sprite?

 

If you are new to game programming, the expression "sprite" might be new to you.   The expression was termed way back in 1981 by a Texas Instruments engineer describing the functionality of the TMS9918 chip.  Essentially a sprite was a bitmap image with hardware support to be movable.  Early game hardware could handle a few sprites, often used to represent the player and enemies in the world.  In real world examples, in Super Mario Brothers, Mario, the mushrooms, coins and such would be sprites.

These days, “Sprite” is basically a bitmap image ( or portion of a bitmap, we’ll see this later ) along with positional information.  These days the concept of hardware sprites doesn’t really exist anymore.

 

I am making this sound entirely more complicated than it actually is.  Just be aware the value (0,0) is the bottom left corner of the sprite, (1,1) is the top right of the sprite and (0.5,0.5) would be the mid point of the sprite.  These coordinate system is extremely common in computer graphics and is used heavily in shaders.  You may have heard of UV coordinates, for positioning textures on 3D objects.  UV coordinates are expressed this way. 

 

Therefore, if you want to position the sprite using it’s mid point, you would instead do:

sprite->setAnchorPoint(Vec2(0.5, 0.5));

 

Another important concept to be aware of is a sprite’s positioning is relative to it’s parent.  Up until now our sprite’s parent was our layer, let’s look at an example with a different Node as a parent.  This time, we are going to introduce another sprite, this one using this image:

autobot

 

 

It’s a 200x180 transparent image named autobot.png.  Once again, add it to the resources folder of your project.  Now let’s change our code slightly:

bool GraphicsScene::init()
{
    if ( !Layer::init() )
    {
        return false;
    }
    
    auto sprite = Sprite::create("decepticon.png");
    auto sprite2 = Sprite::create("autobot.png");
    sprite->setAnchorPoint(Vec2(0.0,0.0));
    sprite2->setAnchorPoint(Vec2(0.0, 0.0));

    sprite->addChild(sprite2);
   
    sprite->setPosition(100, 100);
    sprite2->setPosition(0, 0);
   
    this->addChild(sprite, 0);
    
    return true;
}

 

And when we run this code:

image

 

There’s a couple very important things being shown here.  Until this point, we’ve simply added our Sprite to our Layer, but you can actually parent any Node to any other Node object.  As you can see, both Sprite and Layer inherit from Node, and Node’s form the backbone of a very important concept called a scene graph. 

 

One very important part of this relationship is the child’s position is relative to it’s parent.  Therefore sprite2’s (0,0) position is relative to the origin of sprite1 ( not the anchor, origin and anchor are not the same thing and only anchors can be changed ), so moving sprite2 also moves sprite1.  This is a great way to create hierarchies of nodes, for example you could make a tank out of a sprite for it’s base and another representing it’s turret.  You could then move the base of the tank and the turret would move with it, but the turret itself could rotate independently.

Scenegraph

 

A scenegraph is a pretty simple concept. It's basically the data structure used to hold the contents of your game. In Cocos2d-x, the scene graph is simply a tree of Node dervived objects. There exists Scene node that is pretty much an empty node with the intention of adding other nodes to it. You then add various nodes to it, nodes to those nodes, etc. An overview of how you can use this system in Cocos2d-x is available here.

 

So what do you do when you want to get a node’s position in the world, not relative to it’s parent?  Fortunately Node has that functionality built in:

Vec2 worldPosition = sprite2->convertToWorldSpace(sprite2->getPosition());

 

worldPosition’s value would be (100,100).  There is also an equivalent function for getting a world space coordinate in node space.

 

So, in summary:

  • The world is composed of Node objects, including Scene, Sprite and Layer
  • The screen origin is at the bottom left corner of the screen, always
  • Nodes are positioned, scaled and rotated relative to their anchor point
  • The default anchor point of a sprite is (0.5,0.5), which is it’s mid point
  • Anchor points are defined with a value from (0,0) to (1,1), with (0,0) being bottom left corner and (1,1) being the top right
  • Nodes can have other nodes as children.  When the parent moves, the child moves with it
  • Child node’s origin is the bottom left corner of their parent
  • Anchor point and origin are not the same thing
  • Sprites can only have other sprites as children ( EDIT – No longer true!  There can however be some performance ramifications. Will discuss later )

 

So that covers the basics of dealing with graphics.  Now that we know how to position and parent nodes, next time we will look at something a bit more advanced.

 

Programming , ,

8. August 2014

 

I write a great many tutorials targeting newer developers and as a direct result I am exposed to a fair number of programming related questions.  I don’t mind in the least by the way, it’s why I run this site.

 

However, I notice one very common thread among those questions…

 

They often could have been solved with just a few minutes in the debugger.

 

Then it dawned on me.  Lots of newer programmers likely don’t know all that much about debugging.  Many are probably resorting to printing to the console to see how their program works.  For good reason too…  if you pick up say… a C++ book, it’s about the language, not the tooling.  Of course, there are dedicated books such as Beginning Visual C++ 2013 or the Eclipse IDE: Pocket Guide, but these tend not to be books beginners start with.  Hell, for someone just starting out, figuring out where the language begins and the IDE ends is challenging enough!

 

Which is all a shame, as basic debugging skills will make your life a hell of a lot easier.  Not only will it make solving problems much easier, but it will help a great deal in understanding how your language works.  Plus the most tragic part of all, it’s actually very simple and often incredibly consistent across tools and programming languages.

 

So, if you have no prior debugging experience, give me 20 minutes of your time.  I guarantee you it will be worthwhile, or your money back!

 

 

I am going to use a couple different languages/IDEs int this tutorial, but as you will see, the process is remarkably similar regardless to what language you use.  I am primarily going to start with Visual Studio, then illustrate how you can perform similar actions in other environments.  First a quick glossary of terms you are going to hear.

 

 

Glossary of terms

 

These are a few of the terms we are going to be covering during this tutorial.  Don’t worry over much if the following descriptions don’t make a lot of sense, it should be clearer by the time you finish.

 

Breakpoint

This one is critical, these are instructions that tell your code HEY, STOP RUNNING, I WANT TO LOOK AT SOMETHING HERE!  We will be using breakpoints extensively.  You can generally add/remove/enable/disable breakpoints.

 

Watch

This one is incredibly well named.  Basically these are variables you’ve said you want to keep a watch on the value of.

 

Local

Think of these like Watch expressions the IDE automatically made for you.  Basically every variable in local scope will be listed as a local.  Not all IDEs do this, but most do.

 

Expression Evaluation

This is powerful.  Basically you can type some code and see what result it returns, while your code is running.  Generally you do this once a breakpoint has been hit causing your code to pause and your debugger to be shown.

 

Call Stack

This is the hierarchy of function calls you are currently in.  For example, if you called myFunc() from main(), your callstack would look like

myFunc()

main().

 

Don’t worry, this should make sense shortly.

 

 

C++ and Visual Studio Debugger

 

I am going to start with Visual Studio/Visual C++ then show other platforms later on.  Once again, most of the process you see here is applicable to other environments.

 

Let’s start with this ultra simple code example:

void someFunction(int & inValue)
{
    inValue = 43;
}

int main(int argc, char ** argv)
{
    int i = 42;
    someFunction(i);
    return 0;
}

 

The code is extremely simple. We create a simple int, assign it a value, then pass it into a function that will assign it a different value. Now time to do some basic debugging.

 

The first thing you need to do is start debugging.  In Visual Studio, there are a couple ways to do this.  First thing, in C++, you need to tell it that you are building for debugging.  You see, when you make a debug build a few different things happen.  There are little bits of information added to your code that make the debugger work.  There are some other changes too, like memory being zeroed out, but those are beyond what we are talking about here.  The take away is, you need to build for debugging, then run the debugger, although generally this task is one and the same for you the developer. 

 

From the Visual Studio toolbar, you can do both:

image

Or, you can run from the Debug menu:

image

 

As you can see, F5 is also an option.  It’s worth noting, debug code generally runs a bit slower and bigger, so when you are finished development, you want to compile for release.

 

Ok, so that’s how we start the debugger, but in this code sample, it will simply start, run, then finish.  That’s not very exciting.

 

 

Enter the breakpoint!

 

Ok, now we are going to enter the wonderful world of breakpoints, your new best friends.  Let’s start by setting a breakpoint on our first line, where we declare i.  There are a number of ways of setting a breakpoint.  In the IDE you can right click the line of code you want to break on then select Breakpoint –> Insert Breakpoint, like so:

image

 

… for the sake of this tutorial, please just ignore Tracepoints, at least for now.

 

You can also set a breakpoint in the Debug menu, using Toggle Breakpoint, or by hitting F9:

image

 

The line of code you just set a breakpoint on should now have a red bullet in the margin:

 

image

 

Go ahead and press F5 to debug your program.  Things will go much differently this time, your code will stop executing on the line with the breakpoint.  You can hover your mouse over a variable to see it’s value:

 

image

 

In this case, you will see that the value is gibberish.  This is because i hasn’t been assigned yet.  Notice the little yellow arrow on the left hand side?  This is the line of code you are currently executing.

image

 

Stepping over the corpses of your vanquished foes

 

 

Now we need to navigate in the debugger.  This is done using a couple simple commands:

 

image

 

Step Into, Step Over and Step Out.  These are also available in the toolbar:

image

As you can see, you can also use the hotkey F11 and F10.  These keys change from program to program... if they didn’t, that would just make life too easy, wouldn’t it?

 

Now as to what these do…

Step Into, steps into the currently running line of code.  For example, if you are on a function, it will step into that function.  I will show this in a second.

Step Over jumps to the next line of code in the same scope.  Step out, jumps up on the callstack.  Again, I will explain this in a second. 

 

So what we want to do now is Step Over, and now it should look like this:

image

 

The little yellow arrow will now have advanced to the next line of code.  Notice now if we hover over the value of i, it is now 42 like we would have expected.  That is because the line of code has now executed.  This is a very important thing to realize… the line of code your breakpoint stopped on hasn’t executed yet.  So if you want to see what value is assigned to a variable, you generally want to set the breakpoint to the next line of code.

 

Now we want to “Step Into” the current line of code.  That is, we want to see what happens when someFunction() executes.  If we chose “Step Over”, we would jump to the next line ( return 0; ).  There is another important thing to realize here… even if you Step Over some code, it is still being run like normal, it just isn’t showing you it in the debugger.  That said, we want to see someFunction() in action, so choose Step Into or choose this icon:

 

image

 

Now the line of code jumps to the beginning of someFunction():

 

image

 

You can hover over parameters to see their value:

image

 

You can continue stepping in and over code like normal, or if you are done looking at someFunction ( or some other function someFunction calls ), you can choose Step Out to jump up on the callstack.

 

image

 

 

Callstack me, maybe?  No, I didn’t just make that pun did I?

 

 

Callstack… there’s that word again.  Now that we are actually in a bit of a call stack, let’s take a look at what I mean.

 

In Visual Studio, make sure the CallStack window is being shown.  This is controlled using Debug->Window->CallStack or CTRL + ALT + C like so:

image

 

A window like the following should appear:

image

 

The key to the name is “STACK”.  Think about it like a stack of plates at a cafeteria.  Each time a function is called, it’s like putting a plate on the stack.  The bottom most plate/function is the oldest, while the top most is the newest.  In this case, the call stack tells us that on line 9, in the function main, we called someFunction() and are currently running on line 2.  Speaking of “lines”, you have the option of toggling them on or off in Visual Studio ( and most other IDEs ).

 

The process of toggling line numbers on/off, isn’t incredibly straight forward.  That said, line numbers can be incredibly handy, so lets do it.  First select the menu Tools->Options…

image

 

Then in the resulting dialog on the left hand side scroll down until you find Text Editor->C/C++->General, then click the checkbox next to Line Numbers.  Obviously if you are using Visual Studio and a language other than C++, you need to pick the appropriate language:

 

image

 

Now line numbers will be displayed next to your code:

image

 

Ok… back to the callstack.  Double clicking an entry in the callstack brings you to that line of code.  In this trivial example, the utility is questionable.  However, when working with a real project, where the callstack might span multiple source files, it becomes a very quick and easy way to jump between source files and for seeing how you ended up where you are.  This obviously is a hell of a lot more useful when someFunction() is possible called from thousands of different locations for example.

 

 

Locals, no more witty titles after that last witless one…

 

Now let’s take a look at locals, a concept I mentioned earlier.  This is basically all the local ( non-global ) functions in the current scope.  While debugging inside someFunction, like so:

 

image

 

Open up the locals window.  Like before it can be toggled using the menu Debug->Windows->Locals:

 

image

 

Now you will have a new window, like so:

 

image

 

This is a list of all variables in the local scope.  Inside someFunction() there is only one value, it’s parameter inValue.  Here you can see that the current value is 42 and it’s data type is int reference.  As you step through someFunction, as values chance, they will be updated in the locals window. 

 

Step out of someFunction ( Shift + F11, or using the icon or menus listed above ), and you will see the locals change to those of main():

 

image

 

 

Now you see something somewhat unique to C and C++ ( and other languages with direct memory management ).  The value passed in, argv, is a pointer to a pointer of type char.  This is to say, it points to a pointer that points to the memory address of a char data type.  If that is greek to you at this point, don’t worry about it.  You will notice though that the locals window has done a couple very cool things.

 

First, you see a hex value:

 

image

 

 

This is the actual address of the pointer in memory.  After all, that is what pointers actually are, locations in memory.  This is incredibly useful in debugging, even if you yourself don’t use pointers, code you depend on might.  Look out for values like 0x0000000 or 0xFFFFFFFF.  If you look at the value of a pointer and it’s one of those values, your object wasn’t allocated or has been deleted.  These are some of the most common bugs you will find in C++ code.

 

The other neat thing that visual studio did was this:

 

image

 

The debugger was actually smart enough to go look at the data actually stored at the memory address this pointer points at.  Very handy.  You may also notice the triangle to the left of argv.  This is because there is more information available.  We will see this a bit more later.

 

 

Ok, now what?

 

So… what do you do once you have found what you were looking for?  You have a couple options.  Here they are from the debug toolbar:

 

image

 

Or using the following commands from the Debug menu:

 

image

 

One thing to keep in mind, when your programming is running, the options and menu’s available in Visual Studio are different.  For example, if you want to create a new project, you need to Stop Debugging before the menu options are even available.

 

 

Playing God with your Program

 

Ok, let’s rewind a bit and go back to the locals menu.  This time we are going to use a slightly different code example.

 

#include <iostream>
#include <string>

class MyClass{
public:
    int myInt;
    std::string myString;

    MyClass() :
        myInt(4), 
        myString("Hello World"), 
        myPrivateInt(5)
    {
    }

private:
    int myPrivateInt;
};
int main(int argc, char** argv)
{
    MyClass myClass;
    std::cout << myClass.myString;
    return 0;
}

 

Now let’s try setting a breakpoint on the final line of main, like so:

 

image

 

If you run this code, you will see:

 

image

 

You will have to ALT+TAB over to it, since debugger has given focus to Visual Studio.

 

Now lets look at some of the funky things you can do to a running program.  Now let’s set another breakpoint, this one on the cout line.  Remember, the code on the line you’ve breakpointed hasn’t been run yet!

 

image

 

Now restart or debug your program again.  It will hit the first breakpoint right away.  Now go look at the locals window again:

 

image

 

As you can see, data types composed of other data types, like myClass can be expanded to show all the other values that compose it.  Now let’s do something kinda neat.

 

You can change the values of a program as it is running.  Sorta…  For basic data types, it’s extremely straight forward.  For example, to change the value of myInt while debugging, simply right click it in the locals window and select Edit Value, like so:

 

image

 

You can now change the value:

 

image

 

From this point on ( during this debug session ), that value is now 42.  Of course, if the value is changed in code, it will of course be updated.  This allows you to tweak values interactively and see how it will affect your program’s execution.

 

With objects however, it is slightly more complicated.  In the previous case, we edited myInt which is a member of myClass.  But we couldn’t simply edit MyClass directly, as the debugger has no idea how.  Therefore you can’t just right click myString and select edit.  The debugger simply doesn’t know how to edit this data type ( this isn’t true for non-C++ languages ).  You can however modify the values that make up the string, like so:

 

image

 

As you can see, myString is of type std::basic_string, which is composed of an array of character values that make up the string.  So we can edit the character values to say… lower case our string.

 

image

 

Once again, Visual Studio is smart enough to understand the datatype.  So we could either enter the value ‘w’ or the ascii code 119.  Now if you continue execution of your program it will automatically run to the next breakpoint.  And if you look at the output, you should see:

 

image

 

One very important thing to note here… all of these changes are temporary.  They only last as long as the current debugging session.  The next time you run your program, it will run like normal.

 

 

I’m sick of these damned breakpoints

 

In that last example, when we selected Continue, we jumped to the next breakpoint, like so:

 

image

 

As you add more and more breakpoints to your code, they can make stepping through it incredibly annoying.  So, what can we do about that?

 

Well the first thing we can do is disable it.  Right click the red dot and select Disable Breakpoint, or select the line and hit CTRL + F9

 

image

 

And the breakpoint will be disabled.  Now it will show up as a hollow circle:

 

image

 

This allows you to re-enable it later, but until you do, the debugger will completely ignore the breakpoint.  You can re-enable it the same way you disabled it.  Right clicking and selecting enable, or by hitting CTRL + F9.

 

 

You can also remove a breakpoint complete in a couple ways.  First you single left click the red dot, and it will be removed.  The F9 key will also toggle a breakpoint on and off completely.  You can also right click and select Delete Breakpoint ( see shot above ).

 

Sometimes you want to remove or disable/enable them all at once.  You can do this using the debug menu:

image

 

Breakpoints are your friend, learn to love them!

 

I’m Watching You!

 

Now we are going to look at two final concepts, watches and expressions.  Let’s start with watches.

Until this point, we’ve only been able to look at variables declared in the local scope.  That’s all well and good, but what happens when we want to watch a value declared in a different scope?  Don’t worry, the debugger’s got you covered!

 

Consider this simple code example and breakpoint:

 

image

 

At this point in execution, your locals will look like:

 

image

That said, stringInADifferentScope has already been declared and allocated… how would you look at this value?

 

Well, there are two ways.  As you may be able to guess from the preamble, they are watches and expressions.  A watch is a variable you are keeping an eye on, even if its not currently local.  You can set a watch while debugging code by right clicking the variable and selecting Add Watch:

 

image

 

Now you can look at watches in the watch window using the menu Debug->Windows->Watch->Watch 1 ( or CTRL+ALT+W then 1 ).  You can have up to 4 sets of Watch windows in Visual Studio.  Now you can inspect the value of watched variables at any time:

 

image

If you watch a variable that isn’t in scope, it tells you:

 

image

 

When the variable notInScope comes back in scope, it’s value can be retrieved by hitting the refresh icon.

 

The other option is Evaluate Expression, which is called QuickWatch in Visual Studio.  It’s an incredibly cool feature.  You can invoke QuickWatch while debugging by right clicking and selecting QuickWatch…  or by pressing Shift + F9.

 

image

 

This opens a dialog that allows you to enter whatever value you want into the Expression tab, then press Re-Evaluate and it will look up the value:

 

image

 

The Add Watch button allows you to add the selected Expression to the watch window we just saw.

 

The cool thing about this you can actually call some functions on your object and get the results:

 

image

 

 

On One Condition

 

Back to breakpoints for a second, then I am done I promise.

Consider the following code sample:

 

image

 

This is a very common bug scenario, but you really don’t want to run through the debugger 100K times do you?  Generally with these kinds of errors, its only the last couple of iterations you want to look at.  Fortunately we have something called a conditional breakpoint.  This, as the name suggests, will only break if a certain condition is met.

 

Add a breakpoint like normal.  Add it to the line inside of the loop.  Now right click the red dot and selection Condition…

 

image

 

Now you can set the condition you will break on.

 

image

 

The breakpoint icon will now have a white plus in it:

 

image

 

Next time you run the code, it will only trip when the condition is hit:

 

image

 

Unfortunately, in Visual Studio, conditional breakpoints can make your code ungodly slow, so only use them when absolutely required.  In other languages and IDEs, this isn’t always the case.  I honestly think this is a bug in Visual Studio, as the above code should not require several seconds to evaluate, even with the additional overhead. 

 

 

One of the keys to happiness is a bad memory

 

One other thing that can be incredibly useful, especially in C++ is to look at a location in memory.  This functionality isn’t always available, depending on the language you are using.  In Visual C++, it’s incredibly easy and useful.  In the previous example, we filled an array of char with 100K exclamation marks ( at least, once we remove the = sign from <= :) ).  Let’s say we wanted to look at memory for data.

 

In the Debug->Windows menu, select Memory->Memory 1

image

 

A window will open up like this:

image

 

That is showing what’s in memory, starting at the address 0x00287764.  What you want is the address of the variable data.  In the address box enter the value &data.  (For non-C++ programmers reading this, & is the address of operator, which returns the memory location of a variable ). 

 

Now you will see:

 

image

 

As you can see, data is located at 0x006D781C and is full of exclamation marks ( shown on the right ), which is represented by ascii character code 21 ( as shown on the left ).  Looking at memory can often help you find nasty bugs.

 

 

Debugging in other languages/IDEs

 

The instructions above were obviously C++ and Visual Studio related, but you will find other than the windows looking a bit different, some slightly different names and different hot keys, the process is almost identical.  Instead of going through the same process for every language, I will instead point out where all of these things are located or what they are called.

 

 

 

Java in Eclipse

 

Starting/Stopping:

Just like in Visual Studio, there is both a debug and run mode.  In order to debug in Eclipse you need to run using debug.  There is a menu option available:

image

You can also right click your project in the Package Explorer and select Debug As->Java Application.

image

 

Or using the Debug icon in the toolbar:

image

 

When you debug in Eclipse, you will be prompted to open in Debug perspective:

image

 

A perspective is simply a collection of windows and toolbars to accomplish a given task… such as debugging.  You can switch between perspectives using the top bar:

image

Or using the menu Window->Open Perspective.

 

 

Setting a Breakpoint:

You can set a breakpoint in a number of ways in Eclipse.  In a source window, you can right click the side column and select Toggle Breakpoint ( or CTRL+SHIFT+B ).  This adds a breakpoint, or removes on if there is one currently added.

image

You can also toggle a breakpoint using the Run menu:

image

 

Step Into/Step Over/Step Out:

While running in Debug perspective, you can perform stepping using the toolbar:

image

You can also resume and stop your program using this toolbar.  The icons are Step In, Stop Over and Step Out, from left to right.

 

You can also step using the Run Menu:

image

You can also use F5/F6/F7 to control stepping.

 

Watch Window

In Eclipse, Locals and Watch are in the same view, “Variables”. 

image

 

Variables should be available automatically when you launch into Debug perspective.  However you can also open It using the menu Window->Show View->Variables.  Or Alt+Shift+Q, then V.

 

image

 

Local Window:

See above.

 

Evaluate Expression:

Evaluate expression is called “Expressions” in Eclipse and is available using the same menu you used to open Variables.

image

Once again, you can dynamically execute code and see the results using Expressions.

 

Conditional Breakpoints

To set a conditional breakpoint in Eclipse, add a breakpoint like normal.  Then right click the dot and select Breakpoint Properties:

image

Then in the resulting dialog, check condition and enter your condition logic in the box below:

image

 

 

JavaScript in Chrome

 

Starting/Stopping:

In Chrome ( and other browsers, IE, Opera, Safari and Firefox are all very similar in functionality ), there is no such thing as debug or release, unless I suppose you count minified code.  Simply set a breakpoint in your JavaScript and refresh the page.  You will however have to open Developer Tools to be able to set a breakpoint.  Do this by clicking the Chrome menu button, selecting Tools->Developer Tools

image

 

Or as you can see above, press F12 or Ctrl + Shift + I.  Memorize that key combo, trust me…

 

Setting a Breakpoint:

To set a breakpoint, in the go to a source file:

image

 

Then in the source listing, right click on the left column and select Add Breakpoint:

image

… bet you can guess how to set a Conditional Breakpoint… ;)

You can also toggle a breakpoint using CTRL + B.

 

Step Into/Step Over/Step Out:

Step Over: F10

Step Into: F11

Step Out: Shift + F11

 

Or you can use the toolbar:

image

 

 

Watch Window

Window is located on the right hand side of the developer tools and is called Watch Expressions:

image

 

Expressions and Watches are combined into the same interface.  You can simply add a new one by clicking the + icon, then type code accordingly:

image

 

Local Window:

Called Scope Variables in Chrome.  Located in same area:

image

 

Evaluate Expression:

See watch above.

 

Conditional Breakpoints:

Just like adding a regular breakpoint, but instead choose Conditional Breakpoint.

image

Then type your conditional logic code:

image

 

WebStorm / JavaScript

 

Ok.. I’m just being lazy here.  I remember I already wrote an article about debugging in WebStorm… recycling is good, no? ;)

 

Debugging your app in WebStorm

 

It actually covers 100% of what we just talked about above, except of course the memory view, as it isn’t applicable.

 

Ok, Done talking now

 

As you can see, across tools the experience is very similar.  Some IDEs are worse ( Xcode… ), some are very limited ( Haxe in FlashDevelop ), but generally the process is almost always exactly the same.  Of course, I only looked at a couple IDEs but you will find the experience very consistent in several different IDEs.  It’s mostly a matter of learning a few new hotkeys and window locations.

 

One area that is massively different in command line debuggers, such as gdb.  You are still doing basically the same things, just no nice UI layer over top.  A discussion of gdb debugging is way beyond the scope of this document and there’s tons of information out there.  Heck, there are books written on the subject!

 

Hopefully that process was useful to you.  A while back I posted an example where the debugger saved my ass if you want to see this actual process in action.  Debugging should be a part of your development process, it will make your life a hell of a lot easier, and your hair a hell of a lot less white.

 

Let me know if that wasn’t very clear, this tutorial may actually require a step by step video companion to go along with it.  If so, please let me know.

Programming , , , ,

Month List

DisqusCommentsSummary