Moving Circle

Learn how to move a circle with your controller

Source Code

Moving Circle Scene

We have learned a lot so far, let’s use that knowledge to build a little Scene with a circle moving around. This may not seem like a huge thing, but imagine the circle as a nice-looking character in your future RPG Game. We will use a gamepad to control the circle (our player), if you don’t have a gamepad you can adjust the code and use your keyboard instead.

Let’s start by create a new Scene called CircleScene and provide it to the Engine

class CircleScene : public ng::Scene
{
    public:
        typedef std::unique_ptr<CircleScene> Ptr;
        CircleScene()
        {
            setSceneName("Circle Scene v0.2");
        }
};
int main()
{
    //create new Engine instance
    ng::Engine engine(1080, 720, 60);
        //provide Scene to Engine
        engine.setScene(CircleScene::Ptr(new CircleScene()));
    //run the Engine
    engine.run();
    return 0;
}

Gamepad and Player Struct

Our Scene will have two attributes :

  • The gamepad named mGamepadOne.
  • The player represented by a structure named mPlayer.
The player structure contains the circle (the visual of our player) and other information we’ll need : the player position, the player speed and some booleans indicating in which direction the player is currently moving. For a real game, you would create a complete Player class, but for this tutorial, a simple struct will be enough.
class CircleScene : public ng::Scene
{
    private:
        //controller
        ng::Gamepad         mGamepadOne;
        //player
        struct player
        {
            sf::CircleShape     circle;
            sf::Vector2f        position;
            bool                isMovingLeft    = false;
            bool                isMovingRight   = false;
            bool                isMovingUp      = false;
            bool                isMovingDown    = false;
            float               speed           = 200.f;
        } mPlayer;
    public:
        typedef std::unique_ptr Ptr;
        CircleScene()
        {
            setSceneName("Circle Scene v0.2");
        }
};

Init Method

For the initialization of our game, we configure the Gamepad and Player.

  • We give the Gamepad the Id ONE and the mapping of our PS4 controller
  • The player is configured to be a green circle with a radius of 50. The initial position of the circle (player) is the center of the screen.
void init()
{
    //setup game controller
    mGamepadOne.setId(ng::Gamepad::ONE);
    mGamepadOne.setButtonMapping(ng::JSPs4ButtonMapping);
    mGamepadOne.setAxisMapping(ng::JSPs4AxisMapping);
    getRenderWindow().setJoystickThreshold(ng::Gamepad::AXIS_SENSIVITY);
    //step the player
        //circle shape
    mPlayer.circle.setRadius(50.f);
    mPlayer.circle.setOrigin(50.f, 50.f);
    mPlayer.circle.setFillColor(sf::Color::Green);
        //position the player at the middle of the screen
    mPlayer.position.x = getSceneResolution().x/2.f;
    mPlayer.position.y = getSceneResolution().y/2.f;
    mPlayer.circle.setPosition(mPlayer.position);
}

Render Method

The rendering is pretty straightforward, we draw the player (circle) using the render window method draw. At this point, you can compile your code and see the green circle in the middle of your game screen.

void render()
{
    //draw the player
    getRenderWindow().draw(mPlayer.circle);
}

Joystick Axes Callback

We’re going to use the Left Analog to move the player. With our improved Game Engine we only need to override the callback onJoystickAxis() and write the appropriate code. We use a threshold of 10 floats when measuring the analog position. This value is arbitrary we could use 0 floats, feel free to experiment with any value.

Inside this callback, we only update the booleans isMovingLeft, isMovingRight, isMovingUp and isMovingDown. For example, if you move the Left Analog to the Right, when the position of the Analog goes beyond 10 floats we set isMovingRight at True, and when the position drop below 10 floats isMovingRight returns to False.

The actual position of the player (circle) is computed later inside the method Update.

void onJoystickAxis(const unsigned int& joystickId, const sf::Joystick::Axis& axis, const float& position)
{
    if(mGamepadOne.getId() == joystickId)
    {
        ng::JSAxis jsAxis = mGamepadOne.getAxis(axis);
        if(jsAxis == ng::JSAxis::LeftAnalogX)
        {
            mPlayer.isMovingRight   = position > 10.f;
            mPlayer.isMovingLeft    = position < -10.f;
        }
        else if(jsAxis == ng::JSAxis::LeftAnalogY)
        {
           mPlayer.isMovingUp       = position < -10.f;
           mPlayer.isMovingDown     = position > 10.f;
        }
    }
}

Update Method

Inside the update method, we compute the new position of the Player using a simple formula : Distance = Time x Speed.

  • The time is provided through the variable timeStep which should be exactly 1/60.f seconds (our engine runs at 60FPS)
  • The speed of our player is 200 floats, which means that the player moves 200 pixels per second.
void update(const sf::Time& timeStep)
{
    //compute new position
    if(mPlayer.isMovingLeft)
        mPlayer.position.x -= timeStep.asSeconds() * mPlayer.speed;
    else if(mPlayer.isMovingRight)
        mPlayer.position.x += timeStep.asSeconds() * mPlayer.speed;
    if(mPlayer.isMovingUp)
        mPlayer.position.y -= timeStep.asSeconds() * mPlayer.speed;
    else if(mPlayer.isMovingDown)
        mPlayer.position.y += timeStep.asSeconds() * mPlayer.speed;
    //update position
    mPlayer.circle.setPosition(mPlayer.position);
}

The last touch : Changing the Player Color

Before we finish, let’s do something amusing. We’ll use the Right Analog to change the color of the player, imagine that you’re changing your player weapon in your awesome RPG game. When the Right Analog is moved Left we set the player color to Red and when it’s moved Right we set the color to Blue. When the analog is pressed down (Button R3) we return the color to green.

void update(const sf::Time& timeStep)
{
    //.. move the player here
    //change player color
    if(mGamepadOne.isButtonPressed(ng::JSButton::RightAnalogLeft))
    {
        mPlayer.circle.setFillColor(sf::Color::Red);
    }
    else if(mGamepadOne.isButtonPressed(ng::JSButton::RightAnalogRight))
    {
        mPlayer.circle.setFillColor(sf::Color::Blue);
    }
    else if(mGamepadOne.isButtonPressed(ng::JSButton::R3))
    {
        mPlayer.circle.setFillColor(sf::Color::Green);
    }
}

Final Result