-
Notifications
You must be signed in to change notification settings - Fork 5
Creating Entities
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.
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 !
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();
}
There are 2 types of graphic components :
- ShapeComponent
- SpriteComponent
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);
}
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::getAnimState
to 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 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 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); });
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