Skip to content

Creating Entities

Modar Nasser edited this page Sep 2, 2021 · 8 revisions

Outdated page, please refer to the examples (custom_components and parallax-platformer) or documentation

An Entity is a game object that has a defined behavior and can interact with other objects. For example : player, enemies, bullets are usually entities.

Creating an entity

In NasNas, an Entity is a class derived from ns::BaseEntity. A BaseEntity is just a ns::Drawable with a name.

// Player.hpp
#include <NasNas/NasNas>
class Player: ns::BaseEntity {
public:
    Player();
};
// Player.cpp
Player::Player() : ns::BaseEntity("Player")
{}

That's all you need to create a custom Entity !

Add Components to an Entity

There are 4 type of components, the order of update is the following :

  • Inputs Component
  • Physics Component
  • Collider Component
  • Graphic Components

Most of the time, you'll want to have more flexibility on how the Entity is updated. You can override the update method and add your own logic to the Entity :

class Player: ns::BaseEntity {
public:
    Player();
    void update() override; 
};
// Player.cpp
Player::Player() : ns::BaseEntity("Player")
{ /* add components here */}

void Player::update() {
    if (inputs()) inputs()->update();
    /* for example, apply some transformation on graphic components here */
    if (physics()) physics()->update();
    if (collider()) collider()->update();
    /* for example, add collision detection here */
    for (const auto& graphic_component : graphics())
        graphic_component->update();
}

Graphic Components

There are 2 types of graphic components :

  • ShapeComponent
  • SpriteComponent

ShapeComponent

ns::ecs::ShapeComponent is a template class that can accept sf::CircleShape, sf::RectangleShape or sf::ConvexShape as template argument. You can also use the shortcuts ns::ecs::CircleShapeComponent, ns::ecs::RectangleShapeComponent etc...

Player::Player() : ns::BaseEntity("Player") {
    // adding a circle shape component
    // first, create the shpe :
    auto circle = sf::CirlceShape(20.f);
    circle.setFillColor(sf::Color::Blue);
    // then add it as a component :
    // (second parameter is position offset of the shape relatively to the BaseEntity)  
    this->addComponent<ns::ecs::CircleShapeComponent>(circle, sf::Vector2f(0, 10));
    // now, you can access the component and modify the circle :
    this->graphics<ns::ecs::CircleShapeComponent>(0)->getDrawable().setFillColor(sf::Color::Yellow);

    // creating a 3 points convex shape
    auto convexshape = sf::ConvexShape(3);
    convexshape.setFillColor(sf::Color::Blue);
    convexshape.setPoint(0, {-5,  0});
    convexshape.setPoint(1, { 3, -3});
    convexshape.setPoint(2, { 3,  3});
    // creating the component manually, useful if you want to store it
    auto* convexcomp = new ns::ecs::ConvexShapeComponent(this, convexshape);
    // adding the component we created (we don't need to explicit the template type here)
    this->addComponent(convexcomp);
    // change the component shape fill color
    convexcomp->getDrawable().setFillColor(sf::Color::Blue);
}

SpriteComponent

To add a sprite component, you only need a Spritesheet object.

Player::Player() : ns::BaseEntity("Player") {
    // same spritesheet of the "Spritesheet and Animation" tutorial
    auto* spritesheet = new ns::Spritesheet("adventurer", ns::Res::in("sprites").getTexture("adventurer.png"));
    spritesheet->setGrid({50, 37}, 7);
    spritesheet->addAnim("idle", 0, 4, 200, sf::Vector2f(25, 35));
    spritesheet->addAnim("walk", 8, 6, 200, sf::Vector2f(25, 35));

    this->addComponent<ns::ecs::SpriteComponent>(spritesheet);
    // by default, the first Anim of the spriteshseet will play, but you can also 
    // specify directly the Anim name you want to play first
    // addComponent<ns::ecs::SpriteComponent>(spritesheet, "walk");
}

You can use ns::ecs::SpriteComponent::setAnimState and ns::ecs::SpriteComponent::getAnimStateto play an Anim or get the name of the currently played Anim.

You can also get the AnimPlayer (ns::ecs::SpriteComponent::getAnimPlayer) to stop, pause or resume the Anim.

And of course, ns::ecs::SpriteComponent::getDrawable returns the Sprite used internally.

PhysicsComponent

PhysicsComponent defines how the entity will move, by setting an acceleration, a mass and a friction (between (0.0, 0.0) and (1.0, 1.0)).

// adding a PhysicsComponent
this->addComponent<ns::ecs::PhysicsComponent>(sf::Vector2f(2.f, 2.f), 10.f, sf::Vector2f(1.f, 1.f));
// setting the X direction to 1, the Entity will start moving to the right
this->physics()->setDirectionX(1);

You can also control the direction by setting the angle :

// this will rotate the direction vector by 2 degrees
this->physics()->setDirectionAngle(physics()->getDirectionAngle()+2);

You can also specify the magnitude of the direction vector (e.g. physics()->setDirectionMagnitude(2.f)), by default equals 1.

InputsComponent

InputsComponent is used to link a Keyboard input to a function. The function will be called when the key is pressed.

this->addComponent<ns::ecs::InputsComponent>();
this->inputs()->bind(sf::Keyboard::Left, [&](){ this->physics()->setDirectionX(-1); });
this->inputs()->bind(sf::Keyboard::Right, [&](){ this->physics()->setDirectionX(1); });
this->inputs()->bind(sf::Keyboard::Up, [&](){ this->physics()->setDirectionY(-1); });
this->inputs()->bind(sf::Keyboard::Down, [&](){ this->physics()->setDirectionY(1); });

Collider Component

A collider component is just an area that follow the BaseEntity and that you can use to do collision checks with other collider components.

There are only 2 type of collisions so far : RectangleCollision and CircleCollision.

// adding a ColliderComponent, first argument is the collision type, second argument is position offset
// the origin of Collision area is always its center
this->addComponent<ns::ecs::ColliderComponent>(new ns::ecs::RectangleCollision(10, 20), sf::Vector(0, -10));

To check collision with another ColliderComponent :

if (this->collider()->getCollision().collide(other_collider->getCollision())) {
    // process the collision
}

You can also get the shape that represents the collision area : this->collider()->getCollision().getShape();. (the shape is drawn on screen if ns::Config::debug is set to true)


The ecs module offers some useful functionalities that will help creating, managing and interact with entities.

For more details, check the documentation