Create terrible collision system and mostly finish snake example

This commit is contained in:
SeanOMik 2021-03-01 22:08:10 -06:00
parent 6c28dba5dc
commit 5984c75047
No known key found for this signature in database
GPG Key ID: CA09E5BE1F32728A
15 changed files with 471 additions and 120 deletions

1
.gitignore vendored
View File

@ -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 #
################### ###################

View File

@ -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);
} }

View File

@ -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();
} }

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;
}; };
} }

View File

@ -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;
}; };
} }

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}
}
}
}
}
}

View File

@ -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() {

13
src/random.cpp Normal file
View File

@ -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);
}
}