Create terrible collision system and mostly finish snake example
This commit is contained in:
parent
6c28dba5dc
commit
5984c75047
|
@ -7,6 +7,7 @@ out/*
|
||||||
cmake-build-cmake-build-w10-msvc-debug/*
|
cmake-build-cmake-build-w10-msvc-debug/*
|
||||||
cmake-build-debug-wsl/*
|
cmake-build-debug-wsl/*
|
||||||
build/*
|
build/*
|
||||||
|
.cache/*
|
||||||
|
|
||||||
# Compiled source #
|
# Compiled source #
|
||||||
###################
|
###################
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include <simpleengine/components/movement/movement_component.h>
|
#include <simpleengine/components/movement/movement_component.h>
|
||||||
#include <simpleengine/components/ssma_component.h>
|
#include <simpleengine/components/ssma_component.h>
|
||||||
#include <simpleengine/events/entity_event.h>
|
#include <simpleengine/events/entity_event.h>
|
||||||
#include <simpleengine/components/hitbox_component.h>
|
#include <simpleengine/components/collision_component.h>
|
||||||
#include <simpleengine/animation.h>
|
#include <simpleengine/animation.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
@ -24,7 +24,7 @@ private:
|
||||||
sf::Vector2u window_size;
|
sf::Vector2u window_size;
|
||||||
|
|
||||||
// Components:
|
// Components:
|
||||||
std::shared_ptr<simpleengine::HitboxComponent> hitbox_component;
|
std::shared_ptr<simpleengine::CollisionComponent> hitbox_component;
|
||||||
std::shared_ptr<simpleengine::SideScrollerMovementAnimationComponent> move_anim_component;
|
std::shared_ptr<simpleengine::SideScrollerMovementAnimationComponent> move_anim_component;
|
||||||
public:
|
public:
|
||||||
explicit PlayerEntity(sf::Vector2u window_size) : Entity(sprite), window_size(window_size) {
|
explicit PlayerEntity(sf::Vector2u window_size) : Entity(sprite), window_size(window_size) {
|
||||||
|
@ -42,7 +42,7 @@ public:
|
||||||
AddComponent(std::move(move_anim_component));
|
AddComponent(std::move(move_anim_component));
|
||||||
AddComponent(move_anim_component);
|
AddComponent(move_anim_component);
|
||||||
|
|
||||||
hitbox_component = std::make_shared<simpleengine::HitboxComponent>(*this, sprite,
|
hitbox_component = std::make_shared<simpleengine::CollisionComponent>(*this, sprite,
|
||||||
20.f, 12.f, sprite.getGlobalBounds().width - 40.f, sprite.getGlobalBounds().height - 15.f);
|
20.f, 12.f, sprite.getGlobalBounds().width - 40.f, sprite.getGlobalBounds().height - 15.f);
|
||||||
AddComponent(hitbox_component);
|
AddComponent(hitbox_component);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,75 +4,117 @@
|
||||||
// Email: seanomik@gmail.com
|
// Email: seanomik@gmail.com
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Rect.hpp>
|
||||||
|
#include <SFML/Graphics/RectangleShape.hpp>
|
||||||
|
#include <SFML/Graphics/Text.hpp>
|
||||||
|
#include <SFML/System/Vector2.hpp>
|
||||||
|
#include <SFML/Window/Keyboard.hpp>
|
||||||
|
#include <ios>
|
||||||
#include <simpleengine/game.h>
|
#include <simpleengine/game.h>
|
||||||
#include <simpleengine/event.h>
|
#include <simpleengine/event.h>
|
||||||
#include <simpleengine/entity.h>
|
#include <simpleengine/entity.h>
|
||||||
|
#include <simpleengine/components/collision_component.h>
|
||||||
#include <simpleengine/components/movement/movement_component.h>
|
#include <simpleengine/components/movement/movement_component.h>
|
||||||
#include <simpleengine/events/entity_event.h>
|
#include <simpleengine/events/entity_event.h>
|
||||||
|
#include <simpleengine/events/collision_handler.h>
|
||||||
|
#include <simpleengine/random.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
class SnakeMovementComponent : public simpleengine::Component {
|
class SnakeMovementComponent : public simpleengine::Component {
|
||||||
private:
|
private:
|
||||||
float movement_speed;
|
float movement_speed = 15;
|
||||||
sf::Vector2f movement_direction;
|
sf::Vector2i movement_direction;
|
||||||
std::chrono::high_resolution_clock::time_point last_movement;
|
std::chrono::high_resolution_clock::time_point last_movement;
|
||||||
|
sf::Vector2u window_size;
|
||||||
|
const sf::Vector2f& entity_pos;
|
||||||
public:
|
public:
|
||||||
explicit SnakeMovementComponent(simpleengine::Entity& owning_entity, float movement_speed) : simpleengine::Component(owning_entity), movement_speed(movement_speed) {
|
explicit SnakeMovementComponent(simpleengine::Entity& owning_entity, float movement_speed, const sf::Vector2u& window_size)
|
||||||
|
: simpleengine::Component(owning_entity), movement_speed(movement_speed), window_size(window_size), entity_pos(owning_entity.GetTransformable().getPosition()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
const sf::Vector2i& GetDirection() {
|
||||||
|
return movement_direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update(const float& delta_time) override {
|
void Update(const float& delta_time) override {
|
||||||
|
|
||||||
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) {
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) {
|
||||||
movement_direction.x = -movement_speed;
|
movement_direction.x = -15;
|
||||||
movement_direction.y = 0;
|
movement_direction.y = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) {
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) {
|
||||||
movement_direction.x = 0;
|
movement_direction.x = 0;
|
||||||
movement_direction.y = -movement_speed;
|
movement_direction.y = -15;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) {
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) {
|
||||||
movement_direction.x = movement_speed;
|
movement_direction.x = 15;
|
||||||
movement_direction.y = 0;
|
movement_direction.y = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) {
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) {
|
||||||
movement_direction.x = 0;
|
movement_direction.x = 0;
|
||||||
movement_direction.y = movement_speed;
|
movement_direction.y = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space)) {
|
||||||
|
movement_direction.x = 0;
|
||||||
|
movement_direction.y = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
long long duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - last_movement).count();
|
long long duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - last_movement).count();
|
||||||
|
|
||||||
|
// Only move every 115 ticks.
|
||||||
if (duration >= 115 && (movement_direction.x != 0 || movement_direction.y != 0)) {
|
if (duration >= 115 && (movement_direction.x != 0 || movement_direction.y != 0)) {
|
||||||
owning_entity.Move(delta_time, movement_direction.x, movement_direction.y);
|
owning_entity.Move(delta_time, movement_direction.x, movement_direction.y);
|
||||||
last_movement = std::chrono::high_resolution_clock::now();
|
last_movement = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
sf::RectangleShape& shape = dynamic_cast<sf::RectangleShape&>(owning_entity.GetTransformable());
|
||||||
|
|
||||||
|
// Wrap entity around the side of the screen.
|
||||||
|
if (entity_pos.x < 0) {
|
||||||
|
sf::Vector2f new_pos(window_size.x - shape.getSize().x, owning_entity.GetTransformable().getPosition().y);
|
||||||
|
owning_entity.GetTransformable().setPosition(new_pos);
|
||||||
|
} else if (entity_pos.x > window_size.x) {
|
||||||
|
sf::Vector2f new_pos(shape.getSize().x, owning_entity.GetTransformable().getPosition().y);
|
||||||
|
owning_entity.GetTransformable().setPosition(new_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity_pos.y < 0) {
|
||||||
|
sf::Vector2f new_pos(owning_entity.GetTransformable().getPosition().x, window_size.y - shape.getSize().y);
|
||||||
|
owning_entity.GetTransformable().setPosition(new_pos);
|
||||||
|
} else if (entity_pos.y > window_size.y) {
|
||||||
|
sf::Vector2f new_pos(owning_entity.GetTransformable().getPosition().x, shape.getSize().y);
|
||||||
|
owning_entity.GetTransformable().setPosition(new_pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SnakePlayerEntity : public simpleengine::Entity {
|
class SnakePlayerEntity;
|
||||||
|
|
||||||
|
class SnakeFoodEntity : public simpleengine::Entity {
|
||||||
private:
|
private:
|
||||||
sf::RectangleShape shape;
|
sf::RectangleShape shape;
|
||||||
float movement_speed = 15;
|
|
||||||
sf::Vector2u window_size;
|
sf::Vector2u window_size;
|
||||||
|
std::shared_ptr<SnakePlayerEntity> snake_player;
|
||||||
|
|
||||||
std::shared_ptr<SnakeMovementComponent> movement_component;
|
std::shared_ptr<simpleengine::CollisionComponent> collision_component;
|
||||||
public:
|
public:
|
||||||
explicit SnakePlayerEntity(sf::Vector2u window_size) : Entity(shape), window_size(window_size) {
|
explicit SnakeFoodEntity(sf::Vector2u window_size, std::shared_ptr<SnakePlayerEntity> snake_player)
|
||||||
shape = sf::RectangleShape(sf::Vector2f(15, 15));
|
: Entity(shape), window_size(window_size), snake_player(snake_player) {
|
||||||
shape.setFillColor(sf::Color::White);
|
//shape = sf::RectangleShape(sf::Vector2f(15, 15));
|
||||||
|
shape.setSize(sf::Vector2f(15, 15));
|
||||||
|
shape.setPosition(45, 45);
|
||||||
|
shape.setFillColor(sf::Color::Red);
|
||||||
|
|
||||||
movement_component = std::make_shared<SnakeMovementComponent>(*this, movement_speed);
|
collision_component = std::make_shared<simpleengine::CollisionComponent>(*this, shape, 0, 0, 15, 15);
|
||||||
AddComponent(movement_component);
|
AddComponent(collision_component);
|
||||||
}
|
|
||||||
|
|
||||||
~SnakePlayerEntity() override {
|
|
||||||
std::cout << "Destroying" << std::endl;
|
|
||||||
|
|
||||||
simpleengine::Entity::~Entity();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Move(const float& delta_time, const float& x, const float& y) override {
|
void Move(const float& delta_time, const float& x, const float& y) override {
|
||||||
|
@ -90,11 +132,153 @@ public:
|
||||||
void Render(sf::RenderTarget* target) override {
|
void Render(sf::RenderTarget* target) override {
|
||||||
target->draw(shape);
|
target->draw(shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Relocate() {
|
||||||
|
sf::Vector2f pos(simpleengine::random::RandomInt(0, window_size.x), simpleengine::random::RandomInt(0, window_size.y));
|
||||||
|
// Make sure its on the 15 pixel grid.
|
||||||
|
pos.x -= (int) pos.x % 15;
|
||||||
|
pos.y -= (int) pos.y % 15;
|
||||||
|
|
||||||
|
shape.setPosition(pos);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BodyPiece {
|
||||||
|
sf::RectangleShape shape;
|
||||||
|
sf::Vector2i movement_direction;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SnakePlayerEntity : public simpleengine::Entity {
|
||||||
|
private:
|
||||||
|
sf::RectangleShape head;
|
||||||
|
|
||||||
|
std::vector<BodyPiece> body;
|
||||||
|
|
||||||
|
float movement_speed = 15;
|
||||||
|
sf::Vector2u window_size;
|
||||||
|
sf::Text& score_text;
|
||||||
|
|
||||||
|
std::shared_ptr<SnakeMovementComponent> movement_component;
|
||||||
|
std::shared_ptr<simpleengine::CollisionComponent> collision_component;
|
||||||
|
|
||||||
|
bool alive = true;
|
||||||
|
public:
|
||||||
|
explicit SnakePlayerEntity(sf::Vector2u window_size, sf::Text& score_text) : Entity(head), window_size(window_size), score_text(score_text) {
|
||||||
|
head = sf::RectangleShape(sf::Vector2f(15, 15));
|
||||||
|
head.setFillColor(sf::Color(220, 220, 220));
|
||||||
|
|
||||||
|
movement_component = std::make_shared<SnakeMovementComponent>(*this, movement_speed, window_size);
|
||||||
|
AddComponent(movement_component);
|
||||||
|
|
||||||
|
collision_component = std::make_shared<simpleengine::CollisionComponent>(*this, head, 0, 0, 15, 15);
|
||||||
|
collision_component->SetOnCollide(std::bind(&SnakePlayerEntity::OnCollide, this, std::placeholders::_1));
|
||||||
|
AddComponent(collision_component);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Move(const float& delta_time, const float& x, const float& y) override {
|
||||||
|
if (alive) {
|
||||||
|
sf::FloatRect rect(head.getPosition(), head.getSize());
|
||||||
|
// Add movement to position
|
||||||
|
rect.left += x;
|
||||||
|
rect.top += y;
|
||||||
|
|
||||||
|
for (BodyPiece& piece : body) {
|
||||||
|
if (piece.movement_direction != sf::Vector2i(0, 0) && rect.intersects(piece.shape.getGlobalBounds())) {
|
||||||
|
alive = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!alive) return;
|
||||||
|
|
||||||
|
head.move(x, y);
|
||||||
|
|
||||||
|
sf::Vector2i last_movement_dir(x, y);
|
||||||
|
for (BodyPiece& piece : body) {
|
||||||
|
piece.shape.move(piece.movement_direction.x, piece.movement_direction.y);
|
||||||
|
|
||||||
|
std::swap(last_movement_dir, piece.movement_direction);
|
||||||
|
|
||||||
|
// Wrap piece around the side of the screen.
|
||||||
|
sf::Vector2f piece_pos = piece.shape.getPosition();
|
||||||
|
if (piece_pos.x < 0) {
|
||||||
|
sf::Vector2f new_pos(window_size.x - piece.shape.getSize().x, piece_pos.y);
|
||||||
|
piece.shape.setPosition(new_pos);
|
||||||
|
} else if (piece_pos.x > window_size.x) {
|
||||||
|
sf::Vector2f new_pos(piece.shape.getSize().x, piece_pos.y);
|
||||||
|
piece.shape.setPosition(new_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (piece_pos.y < 0) {
|
||||||
|
sf::Vector2f new_pos(piece_pos.x, window_size.y - piece.shape.getSize().y);
|
||||||
|
piece.shape.setPosition(new_pos);
|
||||||
|
} else if (piece_pos.y > window_size.y) {
|
||||||
|
sf::Vector2f new_pos(piece_pos.x, piece.shape.getSize().y);
|
||||||
|
piece.shape.setPosition(new_pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Move(const float& delta_time, const sf::Vector2f& offset) override {
|
||||||
|
head.move(offset * delta_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Move(const sf::Vector2f& offset) override {
|
||||||
|
head.move(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render(sf::RenderTarget* target) override {
|
||||||
|
target->draw(score_text);
|
||||||
|
target->draw(head);
|
||||||
|
|
||||||
|
for (const BodyPiece& piece : body) {
|
||||||
|
target->draw(piece.shape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnCollide(std::shared_ptr<Entity> entity) {
|
||||||
|
std::shared_ptr<SnakeFoodEntity> shared = dynamic_pointer_cast<SnakeFoodEntity>(entity);
|
||||||
|
if (shared) {
|
||||||
|
shared->Relocate();
|
||||||
|
|
||||||
|
BodyPiece piece{ sf::RectangleShape(sf::Vector2f(15, 15)), sf::Vector2i(0, 0) };
|
||||||
|
piece.shape.setFillColor(sf::Color::White);
|
||||||
|
|
||||||
|
if (body.empty()) {
|
||||||
|
piece.shape.setPosition(head.getPosition());
|
||||||
|
} else {
|
||||||
|
piece.shape.setPosition(body.back().shape.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
body.push_back(piece);
|
||||||
|
score_text.setString(std::to_string(body.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
simpleengine::Game game(500, 500, "SimpleEngine - Snake Example");
|
sf::Vector2u window_size(495, 495);
|
||||||
game.AddEvent(new simpleengine::EntityEvent(game.GetWindow(), std::make_unique<SnakePlayerEntity>(game.GetWindow()->getSize())));
|
simpleengine::Game game(window_size, "SimpleEngine - Snake Example");
|
||||||
|
|
||||||
|
sf::Font font;
|
||||||
|
if (!font.loadFromFile("arial.ttf")) {
|
||||||
|
std::cout << "Failed to find \"arial.ttf\"" << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sf::Text score_text;
|
||||||
|
score_text.setFont(font);
|
||||||
|
score_text.setString("0");
|
||||||
|
score_text.setCharacterSize(24);
|
||||||
|
score_text.setFillColor(sf::Color::Green);
|
||||||
|
score_text.setPosition(window_size.x - 50, 0);
|
||||||
|
|
||||||
|
auto snake_player = std::make_shared<SnakePlayerEntity>(window_size, score_text);
|
||||||
|
auto snake_food = std::make_shared<SnakeFoodEntity>(window_size, snake_player);
|
||||||
|
game.AddEvent(new simpleengine::EntityEvent(game.GetWindow(), snake_food));
|
||||||
|
game.AddEvent(new simpleengine::EntityEvent(game.GetWindow(), snake_player));
|
||||||
|
game.AddEvent(new simpleengine::CollisionHandler(game.GetWindow(), { snake_player, snake_food } ));
|
||||||
|
|
||||||
return game.Run();
|
return game.Run();
|
||||||
}
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
//
|
||||||
|
// Created by SeanOMik on 7/6/2020.
|
||||||
|
// Github: https://github.com/SeanOMik
|
||||||
|
// Email: seanomik@gmail.com
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SIMPLEENGINE_COLLISION_COMPONENT_H
|
||||||
|
#define SIMPLEENGINE_COLLISION_COMPONENT_H
|
||||||
|
|
||||||
|
#include "../component.h"
|
||||||
|
#include "../entity.h"
|
||||||
|
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
#include <SFML/Graphics/Transformable.hpp>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace simpleengine {
|
||||||
|
class CollisionComponent : public Component {
|
||||||
|
private:
|
||||||
|
sf::Transformable& transformable;
|
||||||
|
sf::RectangleShape hitbox;
|
||||||
|
|
||||||
|
float offset_x;
|
||||||
|
float offset_y;
|
||||||
|
std::function<void(std::shared_ptr<Entity>)> collide_function;
|
||||||
|
public:
|
||||||
|
CollisionComponent(Entity& owning_entity, sf::Transformable& transformable, float offset_x, float offset_y, float width, float height);
|
||||||
|
CollisionComponent(Entity& owning_entity, sf::Transformable& transformable, sf::Vector2f offset, sf::Vector2f size);
|
||||||
|
|
||||||
|
CollisionComponent(Entity& owning_entity, sf::Transformable& transformable, const sf::RectangleShape& hitbox, float offset_x, float offset_y);
|
||||||
|
CollisionComponent(Entity& owning_entity, sf::Transformable& transformable, const sf::RectangleShape& hitbox, sf::Vector2f offset);
|
||||||
|
|
||||||
|
sf::RectangleShape& GetHitbox();
|
||||||
|
|
||||||
|
virtual bool DoesIntersect(const sf::FloatRect& rect) const;
|
||||||
|
virtual bool DoesIntersect(const sf::RectangleShape& rect) const;
|
||||||
|
virtual bool DoesIntersect(Entity& entity) const;
|
||||||
|
|
||||||
|
void Update(const float &delta_time) override;
|
||||||
|
void Render(sf::RenderTarget *target) override;
|
||||||
|
|
||||||
|
virtual void SetOnCollide(std::function<void(std::shared_ptr<Entity>)> func);
|
||||||
|
virtual void OnCollide(std::shared_ptr<Entity> collided_entity);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //SIMPLEENGINE_COLLISION_COMPONENT_H
|
|
@ -1,35 +0,0 @@
|
||||||
//
|
|
||||||
// Created by SeanOMik on 7/6/2020.
|
|
||||||
// Github: https://github.com/SeanOMik
|
|
||||||
// Email: seanomik@gmail.com
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SIMPLEENGINE_HITBOX_COMPONENT_H
|
|
||||||
#define SIMPLEENGINE_HITBOX_COMPONENT_H
|
|
||||||
|
|
||||||
#include "../component.h"
|
|
||||||
|
|
||||||
#include <SFML/Graphics.hpp>
|
|
||||||
|
|
||||||
namespace simpleengine {
|
|
||||||
class HitboxComponent : public Component {
|
|
||||||
private:
|
|
||||||
sf::Sprite& sprite;
|
|
||||||
sf::RectangleShape hitbox;
|
|
||||||
|
|
||||||
float offset_x;
|
|
||||||
float offset_y;
|
|
||||||
public:
|
|
||||||
HitboxComponent(Entity& owning_entity, sf::Sprite& sprite, float sprite_offset_x, float sprite_offset_y,
|
|
||||||
float width, float height);
|
|
||||||
|
|
||||||
sf::RectangleShape& GetHitbox();
|
|
||||||
|
|
||||||
bool DoesIntersect(const sf::FloatRect& rect);
|
|
||||||
|
|
||||||
void Update(const float &delta_time) override;
|
|
||||||
void Render(sf::RenderTarget *target) override;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //SIMPLEENGINE_HITBOX_COMPONENT_H
|
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
#include <SFML/Graphics.hpp>
|
#include <SFML/Graphics.hpp>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <vcruntime_typeinfo.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
@ -41,8 +43,8 @@ namespace simpleengine {
|
||||||
const bool& IsGettingDestroyed() const;
|
const bool& IsGettingDestroyed() const;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool HasComponent() {
|
bool HasComponent() const {
|
||||||
for (std::shared_ptr<Component>& comp : components) {
|
for (std::shared_ptr<Component> comp : components) {
|
||||||
if (dynamic_cast<T*>(comp.get())) {
|
if (dynamic_cast<T*>(comp.get())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -51,6 +53,17 @@ namespace simpleengine {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::shared_ptr<T> GetComponent() const {
|
||||||
|
for (std::shared_ptr<Component> comp : components) {
|
||||||
|
if (dynamic_cast<T*>(comp.get())) {
|
||||||
|
return dynamic_pointer_cast<T>(comp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void UpdateComponents(const float& delta_time);
|
void UpdateComponents(const float& delta_time);
|
||||||
void RenderComponents(sf::RenderTarget* target);
|
void RenderComponents(sf::RenderTarget* target);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
//
|
||||||
|
// Created by SeanOMik on 7/3/2020.
|
||||||
|
// Github: https://github.com/SeanOMik
|
||||||
|
// Email: seanomik@gmail.com
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SIMPLEENGINE_COLLISION_HANDLER_H
|
||||||
|
#define SIMPLEENGINE_COLLISION_HANDLER_H
|
||||||
|
|
||||||
|
#include "../event.h"
|
||||||
|
#include "../entity.h"
|
||||||
|
|
||||||
|
namespace simpleengine {
|
||||||
|
class CollisionHandler : public Event {
|
||||||
|
public:
|
||||||
|
explicit CollisionHandler(sf::RenderWindow* window, std::vector<std::shared_ptr<Entity>> entities) : simpleengine::Event(window), entities(entities) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update(const float& delta_time) override;
|
||||||
|
void CheckForQuit() override { }
|
||||||
|
void Render(sf::RenderTarget* target) override { }
|
||||||
|
private:
|
||||||
|
std::vector<std::shared_ptr<Entity>> entities;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //SIMPLEENGINE_COLLISION_HANDLER_H
|
|
@ -13,7 +13,7 @@
|
||||||
namespace simpleengine {
|
namespace simpleengine {
|
||||||
class EntityEvent : public Event {
|
class EntityEvent : public Event {
|
||||||
public:
|
public:
|
||||||
explicit EntityEvent(sf::RenderWindow* window, std::unique_ptr<Entity> entity) : simpleengine::Event(window), entity(std::move(entity)) {
|
explicit EntityEvent(sf::RenderWindow* window, std::shared_ptr<Entity> entity) : simpleengine::Event(window), entity(entity) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,8 +30,12 @@ namespace simpleengine {
|
||||||
void Render(sf::RenderTarget* target) override {
|
void Render(sf::RenderTarget* target) override {
|
||||||
entity->Render(target);
|
entity->Render(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Entity> GetEntity() {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Entity> entity;
|
std::shared_ptr<Entity> entity;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,13 +14,13 @@
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include "entity.h"
|
#include "entity.h"
|
||||||
|
|
||||||
|
|
||||||
namespace simpleengine {
|
namespace simpleengine {
|
||||||
class Event;
|
class Event;
|
||||||
|
|
||||||
class Game {
|
class Game {
|
||||||
public:
|
public:
|
||||||
Game(int w, int h, const std::string& window_name);
|
Game(int w, int h, const std::string& window_name);
|
||||||
|
Game(const sf::Vector2u& window_size, const std::string& window_name);
|
||||||
virtual ~Game();
|
virtual ~Game();
|
||||||
|
|
||||||
void UpdateSFMLEvents();
|
void UpdateSFMLEvents();
|
||||||
|
@ -38,7 +38,8 @@ namespace simpleengine {
|
||||||
sf::Clock delta_time_clock; // Delta time clock
|
sf::Clock delta_time_clock; // Delta time clock
|
||||||
float delta_time; // Delta time
|
float delta_time; // Delta time
|
||||||
|
|
||||||
std::stack<Event*> events;
|
//std::stack<Event*> events;
|
||||||
|
std::vector<Event*> events;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
//
|
||||||
|
// Created by SeanOMik on 7/6/2020.
|
||||||
|
// Github: https://github.com/SeanOMik
|
||||||
|
// Email: seanomik@gmail.com
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SIMPLEENGINE_RANDOM_H
|
||||||
|
#define SIMPLEENGINE_RANDOM_H
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
namespace simpleengine {
|
||||||
|
namespace random {
|
||||||
|
int RandomInt(int min = std::numeric_limits<int>::min(), int max = std::numeric_limits<int>::max());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //SIMPLEENGINE_RANDOM_H
|
|
@ -0,0 +1,85 @@
|
||||||
|
//
|
||||||
|
// Created by SeanOMik on 7/6/2020.
|
||||||
|
// Github: https://github.com/SeanOMik
|
||||||
|
// Email: seanomik@gmail.com
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "components/collision_component.h"
|
||||||
|
#include "components/ssma_component.h"
|
||||||
|
#include "entity.h"
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Rect.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
simpleengine::CollisionComponent::CollisionComponent(Entity& owning_entity, sf::Transformable &transformable, float offset_x, float offset_y,
|
||||||
|
float width, float height) : simpleengine::CollisionComponent::CollisionComponent(owning_entity, transformable, hitbox, offset_x, offset_y) {
|
||||||
|
|
||||||
|
hitbox.setPosition(transformable.getPosition().x + offset_x, transformable.getPosition().y + offset_y);
|
||||||
|
hitbox.setSize(sf::Vector2f(width, height));
|
||||||
|
hitbox.setFillColor(sf::Color::Transparent);
|
||||||
|
hitbox.setOutlineThickness(1);
|
||||||
|
hitbox.setOutlineColor(sf::Color::Red);
|
||||||
|
}
|
||||||
|
|
||||||
|
simpleengine::CollisionComponent::CollisionComponent(Entity& owning_entity, sf::Transformable& transformable, sf::Vector2f offset, sf::Vector2f size)
|
||||||
|
: simpleengine::CollisionComponent::CollisionComponent(owning_entity, transformable, offset.x, offset.y, size.x, size.y) {
|
||||||
|
}
|
||||||
|
|
||||||
|
simpleengine::CollisionComponent::CollisionComponent(Entity& owning_entity, sf::Transformable& transformable, const sf::RectangleShape& hit,
|
||||||
|
float offset_x, float offset_y) : Component(owning_entity), transformable(transformable), hitbox(hit), offset_x(offset_x), offset_y(offset_y) {
|
||||||
|
|
||||||
|
// SSMA Component set's the sprites texture offset so we need to set
|
||||||
|
// the offset to the origin if the entity has the SSMA component.
|
||||||
|
if (owning_entity.HasComponent<simpleengine::SideScrollerMovementAnimationComponent>()) {
|
||||||
|
offset_x += dynamic_cast<sf::RectangleShape&>(transformable).getGlobalBounds().width * -0.5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simpleengine::CollisionComponent::CollisionComponent(Entity& owning_entity, sf::Transformable& transformable, const sf::RectangleShape& hit,
|
||||||
|
sf::Vector2f offset) : simpleengine::CollisionComponent::CollisionComponent(owning_entity, transformable, hit, offset.x, offset.y) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sf::RectangleShape &simpleengine::CollisionComponent::GetHitbox() {
|
||||||
|
return hitbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
sf::FloatRect CreateBounds(sf::RectangleShape rect) {
|
||||||
|
return sf::FloatRect(rect.getPosition(), rect.getSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool simpleengine::CollisionComponent::DoesIntersect(const sf::FloatRect &rect) const {
|
||||||
|
return CreateBounds(hitbox).intersects(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool simpleengine::CollisionComponent::DoesIntersect(const sf::RectangleShape &rect) const {
|
||||||
|
return CreateBounds(hitbox).intersects(CreateBounds(rect));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool simpleengine::CollisionComponent::DoesIntersect(Entity& entity) const {
|
||||||
|
std::shared_ptr<simpleengine::CollisionComponent> other_collider = entity.GetComponent<simpleengine::CollisionComponent>();
|
||||||
|
if (other_collider) {
|
||||||
|
return other_collider->DoesIntersect(hitbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void simpleengine::CollisionComponent::Update(const float &delta_time) {
|
||||||
|
hitbox.setPosition(owning_entity.GetTransformable().getPosition().x + offset_x, owning_entity.GetTransformable().getPosition().y + offset_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void simpleengine::CollisionComponent::Render(sf::RenderTarget *target) {
|
||||||
|
target->draw(hitbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
void simpleengine::CollisionComponent::SetOnCollide(std::function<void(std::shared_ptr<Entity>)> func) {
|
||||||
|
collide_function = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void simpleengine::CollisionComponent::OnCollide(std::shared_ptr<Entity> collided_entity) {
|
||||||
|
if (collide_function) {
|
||||||
|
collide_function(collided_entity);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,41 +0,0 @@
|
||||||
//
|
|
||||||
// Created by SeanOMik on 7/6/2020.
|
|
||||||
// Github: https://github.com/SeanOMik
|
|
||||||
// Email: seanomik@gmail.com
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "components/hitbox_component.h"
|
|
||||||
#include "components/ssma_component.h"
|
|
||||||
#include "entity.h"
|
|
||||||
|
|
||||||
simpleengine::HitboxComponent::HitboxComponent(Entity& owning_entity, sf::Sprite &sprite, float sprite_offset_x, float sprite_offset_y,
|
|
||||||
float width, float height) : Component(owning_entity), sprite(sprite), offset_x(sprite_offset_x), offset_y(sprite_offset_y) {
|
|
||||||
|
|
||||||
hitbox.setPosition(sprite.getPosition().x + sprite_offset_x, sprite.getPosition().y + sprite_offset_y);
|
|
||||||
hitbox.setSize(sf::Vector2f(width, height));
|
|
||||||
hitbox.setFillColor(sf::Color::Transparent);
|
|
||||||
hitbox.setOutlineThickness(1);
|
|
||||||
hitbox.setOutlineColor(sf::Color::Red);
|
|
||||||
|
|
||||||
// SSMA Component set's the sprites texture offset so we need to set
|
|
||||||
// the offset to the origin if the entity has the SSMA component.
|
|
||||||
if (owning_entity.HasComponent<simpleengine::SideScrollerMovementAnimationComponent>()) {
|
|
||||||
offset_x += sprite.getGlobalBounds().width * -0.5f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sf::RectangleShape &simpleengine::HitboxComponent::GetHitbox() {
|
|
||||||
return hitbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool simpleengine::HitboxComponent::DoesIntersect(const sf::FloatRect &rect) {
|
|
||||||
return hitbox.getGlobalBounds().intersects(rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
void simpleengine::HitboxComponent::Update(const float &delta_time) {
|
|
||||||
hitbox.setPosition(sprite.getPosition().x + offset_x, sprite.getPosition().y + offset_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void simpleengine::HitboxComponent::Render(sf::RenderTarget *target) {
|
|
||||||
target->draw(hitbox);
|
|
||||||
}
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
#include "events/collision_handler.h"
|
||||||
|
#include "components/collision_component.h"
|
||||||
|
|
||||||
|
void simpleengine::CollisionHandler::Update(const float& delta_time) {
|
||||||
|
for (std::shared_ptr<Entity> entity : entities) {
|
||||||
|
std::shared_ptr<CollisionComponent> entity_col = entity->GetComponent<simpleengine::CollisionComponent>();
|
||||||
|
|
||||||
|
if (entity_col) {
|
||||||
|
for (std::shared_ptr<Entity> two : entities) {
|
||||||
|
if (two == entity) continue;
|
||||||
|
|
||||||
|
std::shared_ptr<CollisionComponent> two_col = two->GetComponent<simpleengine::CollisionComponent>();
|
||||||
|
if (two_col) {
|
||||||
|
if (entity_col->DoesIntersect(two_col->GetHitbox())) {
|
||||||
|
entity_col->OnCollide(two);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
src/game.cpp
34
src/game.cpp
|
@ -5,6 +5,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
|
#include "entity.h"
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -14,12 +15,22 @@ simpleengine::Game::Game(int w, int h, const std::string& window_name) {
|
||||||
window = new sf::RenderWindow(sf::VideoMode(w, h), window_name);
|
window = new sf::RenderWindow(sf::VideoMode(w, h), window_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simpleengine::Game::Game(const sf::Vector2u& window_size, const std::string& window_name) : simpleengine::Game(window_size.x, window_size.y, window_name) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
simpleengine::Game::~Game() {
|
simpleengine::Game::~Game() {
|
||||||
delete window;
|
delete window;
|
||||||
|
|
||||||
while(!events.empty()) {
|
/* while(!events.empty()) {
|
||||||
delete events.top();
|
delete events.top();
|
||||||
events.pop();
|
events.pop();
|
||||||
|
} */
|
||||||
|
|
||||||
|
std::vector<Event*>::iterator it = events.begin();
|
||||||
|
while (it != events.end()) {
|
||||||
|
delete (*it);
|
||||||
|
it = events.erase(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,15 +48,16 @@ void simpleengine::Game::Update() {
|
||||||
delta_time = delta_time_clock.restart().asSeconds(); // Update delta time
|
delta_time = delta_time_clock.restart().asSeconds(); // Update delta time
|
||||||
UpdateSFMLEvents();
|
UpdateSFMLEvents();
|
||||||
|
|
||||||
if (!events.empty()) {
|
for (std::vector<Event*>::iterator it = events.begin(); it != events.end(); ) {
|
||||||
events.top()->Update(delta_time);
|
(*it)->Update(delta_time);
|
||||||
|
|
||||||
// If this state wants to stop, delete it.
|
if ((*it)->WantsToQuit()) {
|
||||||
if (events.top()->WantsToQuit()) {
|
(*it)->Quiting();
|
||||||
events.top()->Quiting();
|
|
||||||
|
|
||||||
delete events.top();
|
delete (*it);
|
||||||
events.pop();
|
it = events.erase(it);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,8 +69,8 @@ void simpleengine::Game::RenderWindow() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void simpleengine::Game::RenderItems() {
|
void simpleengine::Game::RenderItems() {
|
||||||
if (!events.empty()) {
|
for (std::vector<Event*>::iterator it = events.begin(); it != events.end(); it++) {
|
||||||
events.top()->Render(window);
|
(*it)->Render(window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +87,7 @@ int simpleengine::Game::Run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void simpleengine::Game::AddEvent(simpleengine::Event *event) {
|
void simpleengine::Game::AddEvent(simpleengine::Event *event) {
|
||||||
events.push(event);
|
events.emplace_back(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
sf::RenderWindow* simpleengine::Game::GetWindow() {
|
sf::RenderWindow* simpleengine::Game::GetWindow() {
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
#include "random.h"
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
namespace simpleengine {
|
||||||
|
int random::RandomInt(int min, int max) {
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 gen(rd());
|
||||||
|
std::uniform_int_distribution<> distr(min, max);
|
||||||
|
|
||||||
|
return distr(gen);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue