0
0
mirror of https://github.com/Nimac0/SDL_Minigame synced 2026-01-12 10:13:42 +00:00

Rewrote collision detection

This commit is contained in:
Benedikt Galbavy 2024-01-29 23:49:58 +01:00
parent 973114f351
commit fa4586f1db
23 changed files with 229 additions and 146 deletions

View File

@ -1,3 +1,5 @@
#include "Entity.h"
#include <SDL_render.h> #include <SDL_render.h>
#include <map> #include <map>
#include <string> #include <string>
@ -12,7 +14,7 @@ public:
AssetManager(Manager* manager); AssetManager(Manager* manager);
~AssetManager(); ~AssetManager();
void createProjectile(Vector2D pos, Vector2D velocity, bool source, int scale, int range, int speed, const char* texturePath); void createProjectile(Vector2D pos, Vector2D velocity, bool source, int scale, int range, int speed, const char* texturePath, TeamLabel teamLabel);
//texture management //texture management
void addTexture(std::string id, const char* path); void addTexture(std::string id, const char* path);

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "ColliderComponent.h"
#include "Constants.h" #include "Constants.h"
#include "Entity.h" #include "Entity.h"
#include "SDL_rect.h" #include "SDL_rect.h"
@ -9,6 +10,8 @@
#include <bitset> #include <bitset>
#include <initializer_list> #include <initializer_list>
#include <tuple>
#include <utility>
#include <vector> #include <vector>
class ColliderComponent; class ColliderComponent;
@ -37,13 +40,28 @@ public:
manager(mManager) { }; manager(mManager) { };
~CollisionHandler(); ~CollisionHandler();
static IntersectionBitSet getIntersection( // intersections relative to entityA
Entity* entityA,
Entity* entityB,
Vector2D posModA = Vector2D(0,0),
Vector2D posModB = Vector2D(0,0));
static IntersectionBitSet getIntersectionWithBounds( // will fail to determine direction if speed high enough to switch from no collision to full overlap in one tick
Entity* entity,
Vector2D posMod = Vector2D(0,0));
static IntersectionBitSet getIntersection(Entity* entityA, Entity* entityB); // intersections relative to entityA // temporary function, remove once game.cpp cleaned up
static IntersectionBitSet getIntersection(Entity* entityA, Entity* entityB, Vector2D posModA, Vector2D posModB); std::vector<ColliderComponent*> getColliders(
static IntersectionBitSet getIntersectionWithBounds(Entity* entity);// will fail if speed high enough to switch from no collision to full overlap in one tick std::initializer_list<GroupLabel> const& groupLabels,
static IntersectionBitSet getIntersectionWithBounds(Entity* entity, Vector2D posMod); std::initializer_list<TeamLabel> const& teamLabels = {},
bool negateTeam = false);
std::vector<ColliderComponent*> getColliders(std::initializer_list<GroupLabel> const& groupLabels); // temporary function, remove once game.cpp cleaned up template<typename T>
T getAnyIntersection(
Entity* entity,
Vector2D posMod = {},
std::initializer_list<GroupLabel> const& groupLabels = {},
std::initializer_list<TeamLabel> const& teamLabels = {},
bool negateTeam = false);
void update(); void update();
}; };

View File

@ -1,2 +1 @@
#pragma once #pragma once

7
include/Direction.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
enum class Direction
{
LEFT,
RIGHT
};

View File

@ -5,6 +5,7 @@
#include <bitset> #include <bitset>
#include <vector> #include <vector>
#include "ColliderComponent.h"
#include "ECS.h" #include "ECS.h"
#include "Constants.h" #include "Constants.h"
@ -42,7 +43,12 @@ public:
void draw() const; void draw() const;
bool isActive() const { return this->active; } bool isActive() const { return this->active; }
void destroy() { this->active = false; } void destroy() {
this->active = false;
if (this->hasComponent<ColliderComponent>()) {
this->getComponent<ColliderComponent>().removeCollision();
}
}
bool hasGroup(Group mGroup); bool hasGroup(Group mGroup);
void addGroup(Group mGroup); void addGroup(Group mGroup);

View File

@ -6,6 +6,7 @@
class AssetManager; class AssetManager;
class CollisionHandler; class CollisionHandler;
enum class TeamLabel;
class Game class Game
{ {
@ -21,19 +22,18 @@ public:
void clean(); void clean();
bool running() const; bool running() const;
static void addTile(int id, int x, int y); static void addTile(unsigned long id, int x, int y);
static SDL_Renderer* renderer; static SDL_Renderer* renderer;
static SDL_Event event; static SDL_Event event;
static CollisionHandler* collisionHandler; static CollisionHandler* collisionHandler;
static AssetManager* assets; static AssetManager* assets;
bool getWinner();
private: private:
void setWinner(TeamLabel winningTeam);
TeamLabel getWinner();
int counter = 0; int counter = 0;
bool isRunning = false; bool isRunning = false;
SDL_Window* window; SDL_Window* window;
TeamLabel winner;
//true for player1 win / false for player2 win;
bool winner;
}; };

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "Direction.h"
#include "Component.h" #include "Component.h"
class Manager; class Manager;
@ -8,22 +9,21 @@ class HealthComponent : public Component
{ {
public: public:
HealthComponent(int health, Manager* manager, bool player) : health(health), manager(manager), player(player) {} HealthComponent(int health, Direction side) : health(health), side(side) {}
~HealthComponent() {} ~HealthComponent() {}
void getDamage() { this->health--; } void modifyHealth(int health = -1);
int getHealth() { return this->health; } int getHealth() { return this->health; }
void init() override; void init() override;
void createAllHearts(); void resetHearts();
void createHeartComponents(int x); void createHeartComponents(int x);
private: private:
int health; int health;
Manager* manager; Direction side;
bool player; //true if player1 / false if player2 bool player; //true if player1 / false if player2
}; };

View File

@ -10,7 +10,7 @@ class ProjectileComponent : public Component
//can maybe be split in separate .cpp file //can maybe be split in separate .cpp file
public: public:
ProjectileComponent(int range, int speed, Vector2D velocity, bool source) : range(range), speed(speed), velocity(velocity), source(source) {} ProjectileComponent(int range, int speed, Vector2D direction, bool source) : range(range), speed(speed), direction(direction), source(source) {}
~ProjectileComponent() {} ~ProjectileComponent() {}
void init() override; void init() override;
@ -27,5 +27,5 @@ private:
const bool source; //true if from player1 / false if from player2 const bool source; //true if from player1 / false if from player2
Vector2D velocity; Vector2D direction;
}; };

View File

@ -5,15 +5,10 @@
#include "AnimationHandler.h" #include "AnimationHandler.h"
#include "Component.h" #include "Component.h"
#include "Direction.h"
class TransformComponent; class TransformComponent;
enum SpriteDirection
{
LEFT,
RIGHT
};
class SpriteComponent : public Component class SpriteComponent : public Component
{ {
public: public:
@ -43,5 +38,5 @@ public:
void update() override; void update() override;
void draw() override; void draw() override;
void playAnimation(AnimationType type); void playAnimation(AnimationType type);
void setDirection(SpriteDirection direction); void setDirection(Direction direction);
}; };

View File

@ -7,7 +7,7 @@ class TransformComponent : public Component
{ {
public: public:
Vector2D position; Vector2D position;
Vector2D velocity; Vector2D direction;
int height = 32; int height = 32;
int width = 32; int width = 32;

View File

@ -1,5 +1,8 @@
#pragma once #pragma once
#include <SDL.h>
#include <SDL_rect.h>
class Vector2D class Vector2D
{ {
public: public:
@ -18,3 +21,5 @@ public:
Vector2D& operator*(const int& i); Vector2D& operator*(const int& i);
Vector2D& zero(); Vector2D& zero();
}; };
SDL_Rect operator+(const SDL_Rect& rect, const Vector2D& vector2D);

View File

@ -1,5 +1,6 @@
#include "AssetManager.h" #include "AssetManager.h"
#include "Entity.h"
#include "TextureManager.h" #include "TextureManager.h"
#include "Components.h" #include "Components.h"
@ -15,7 +16,7 @@ SDL_Texture* AssetManager::getTexture(std::string id) {
return textures.at(id); return textures.at(id);
} }
void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, bool source, int scale, int range, int speed, const char* texturePath) { void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, bool source, int scale, int range, int speed, const char* texturePath, TeamLabel teamLabel) {
auto& projectile(man->addEntity()); auto& projectile(man->addEntity());
projectile.addComponent<TransformComponent>(pos.x, pos.y, 32, 32, scale); //32x32 is standard size for objects projectile.addComponent<TransformComponent>(pos.x, pos.y, 32, 32, scale); //32x32 is standard size for objects
@ -23,4 +24,5 @@ void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, bool source
projectile.addComponent<ProjectileComponent>(range, speed, velocity, source); projectile.addComponent<ProjectileComponent>(range, speed, velocity, source);
projectile.addComponent<ColliderComponent>("projectile", 0.6f); projectile.addComponent<ColliderComponent>("projectile", 0.6f);
projectile.addGroup((size_t)GroupLabel::PROJECTILE); projectile.addGroup((size_t)GroupLabel::PROJECTILE);
projectile.setTeam(teamLabel);
} }

View File

@ -28,6 +28,7 @@ void ColliderComponent::init()
transform = &entity->getComponent<TransformComponent>(); transform = &entity->getComponent<TransformComponent>();
//Game::collisionHandler->add(this); //Game::collisionHandler->add(this);
this->update();
} }
void ColliderComponent::update() void ColliderComponent::update()

View File

@ -11,11 +11,6 @@
#include <cstdio> #include <cstdio>
#include <memory> #include <memory>
IntersectionBitSet CollisionHandler::getIntersection(Entity* entityA, Entity* entityB)
{
return getIntersection(entityA, entityB, Vector2D(0,0), Vector2D(0,0));
}
IntersectionBitSet CollisionHandler::getIntersection(Entity* entityA, Entity* entityB, Vector2D posModA, Vector2D posModB) IntersectionBitSet CollisionHandler::getIntersection(Entity* entityA, Entity* entityB, Vector2D posModA, Vector2D posModB)
{ {
if (!entityA->hasComponent<ColliderComponent>() || if (!entityA->hasComponent<ColliderComponent>() ||
@ -60,11 +55,6 @@ IntersectionBitSet CollisionHandler::getIntersection(Entity* entityA, Entity* en
return intersections; return intersections;
} }
IntersectionBitSet CollisionHandler::getIntersectionWithBounds(Entity* entity)
{
return getIntersectionWithBounds(entity, Vector2D(0,0));
}
IntersectionBitSet CollisionHandler::getIntersectionWithBounds(Entity* entity, Vector2D posMod) IntersectionBitSet CollisionHandler::getIntersectionWithBounds(Entity* entity, Vector2D posMod)
{ {
if (!entity->hasComponent<ColliderComponent>()) if (!entity->hasComponent<ColliderComponent>())
@ -76,8 +66,9 @@ IntersectionBitSet CollisionHandler::getIntersectionWithBounds(Entity* entity, V
// all 4 directions and both sides to allow checking for fully out of bounds // all 4 directions and both sides to allow checking for fully out of bounds
if (collider->x + posMod.x < 0 || if (collider->x + posMod.x < 0 ||
collider->x + posMod.x > SCREEN_SIZE_WIDTH) collider->x + posMod.x > SCREEN_SIZE_WIDTH) {
intersections.set((size_t) direction::LEFT); intersections.set((size_t) direction::LEFT);
}
if (collider->x + collider->w + posMod.x < 0 || if (collider->x + collider->w + posMod.x < 0 ||
collider->x + collider->w + posMod.x > SCREEN_SIZE_WIDTH) collider->x + collider->w + posMod.x > SCREEN_SIZE_WIDTH)
@ -94,7 +85,10 @@ IntersectionBitSet CollisionHandler::getIntersectionWithBounds(Entity* entity, V
return intersections; return intersections;
} }
std::vector<ColliderComponent*> CollisionHandler::getColliders(std::initializer_list<GroupLabel> const& groupLabels) std::vector<ColliderComponent*> CollisionHandler::getColliders(
std::initializer_list<GroupLabel> const& groupLabels,
std::initializer_list<TeamLabel> const& teamLabels,
bool negateTeam)
{ {
std::vector<ColliderComponent*> colliders; std::vector<ColliderComponent*> colliders;
@ -103,9 +97,16 @@ std::vector<ColliderComponent*> CollisionHandler::getColliders(std::initializer_
groupBitSet.set((size_t) groupLabel); groupBitSet.set((size_t) groupLabel);
} }
std::bitset<MAX_TEAMS> teamBitSet;
for (auto& teamLabel : teamLabels) {
teamBitSet.set((size_t) teamLabel);
}
for (auto& entity : manager.getAll()) { for (auto& entity : manager.getAll()) {
if ((groupBitSet & entity->getGroupBitSet()).none()) if ((groupBitSet & entity->getGroupBitSet()).none())
continue; continue;
if (teamBitSet.any() && negateTeam != (teamBitSet.test((size_t) entity->getTeam())))
continue;
if (!entity->hasComponent<ColliderComponent>()) if (!entity->hasComponent<ColliderComponent>())
continue; continue;
colliders.emplace_back(&entity->getComponent<ColliderComponent>()); colliders.emplace_back(&entity->getComponent<ColliderComponent>());
@ -113,3 +114,35 @@ std::vector<ColliderComponent*> CollisionHandler::getColliders(std::initializer_
return colliders; return colliders;
} }
template<>
IntersectionBitSet CollisionHandler::getAnyIntersection<IntersectionBitSet>(
Entity* entity,
Vector2D posMod,
std::initializer_list<GroupLabel> const& groupLabels,
std::initializer_list<TeamLabel> const& teamLabels,
bool negateTeam)
{
IntersectionBitSet intersections;
for (auto& collider : getColliders(groupLabels, teamLabels)) {
intersections |= getIntersection(entity, collider->entity, posMod);
}
return intersections;
};
template<>
Entity* CollisionHandler::getAnyIntersection<Entity*>(
Entity* entity,
Vector2D posMod,
std::initializer_list<GroupLabel> const& groupLabels,
std::initializer_list<TeamLabel> const& teamLabels,
bool negateTeam)
{
for (auto& collider : getColliders(groupLabels, teamLabels)) {
SDL_Rect rect = entity->getComponent<ColliderComponent>().collider + posMod;
if (SDL_HasIntersection(&rect, &collider->collider)) {
return collider->entity;
}
}
return nullptr;
};

View File

@ -37,7 +37,7 @@ std::bitset<MAX_GROUPS> Entity::getGroupBitSet()
void Entity::setTeam(TeamLabel teamLabel) void Entity::setTeam(TeamLabel teamLabel)
{ {
teamLabel = teamLabel; this->teamLabel = teamLabel;
manager.addToTeam(this, (size_t) teamLabel); manager.addToTeam(this, (size_t) teamLabel);
} }

View File

@ -4,7 +4,9 @@
#include "Components.h" #include "Components.h"
#include "AssetManager.h" #include "AssetManager.h"
#include "Direction.h"
#include "Entity.h" #include "Entity.h"
#include "HealthComponent.h"
#include "Map.h" #include "Map.h"
#include "TextureManager.h" #include "TextureManager.h"
@ -113,27 +115,28 @@ void Game::init(const char* title, int xpos, int ypos, int width, int height, bo
//ecs implementation //ecs implementation
player1.setTeam(TeamLabel::BLUE);
player1.addComponent<TransformComponent>(80,80,2); //posx, posy, scale player1.addComponent<TransformComponent>(80,80,2); //posx, posy, scale
player1.addComponent<SpriteComponent>("assets/chicken_knight_spritesheet.png", true); //adds sprite (32x32px), path needed player1.addComponent<SpriteComponent>("assets/chicken_knight_spritesheet.png", true); //adds sprite (32x32px), path needed
player1.addComponent<KeyboardController>(SDL_SCANCODE_W, SDL_SCANCODE_S, SDL_SCANCODE_A, SDL_SCANCODE_D, SDL_SCANCODE_E, Vector2D(1, 0));//custom keycontrols can be added player1.addComponent<KeyboardController>(SDL_SCANCODE_W, SDL_SCANCODE_S, SDL_SCANCODE_A, SDL_SCANCODE_D, SDL_SCANCODE_E, Vector2D(1, 0));//custom keycontrols can be added
player1.addComponent<ColliderComponent>("player", 0.8f); //adds tag (for further use, reference tag) player1.addComponent<ColliderComponent>("player", 0.8f); //adds tag (for further use, reference tag)
player1.addComponent<HealthComponent>(5, &manager, true); player1.addComponent<HealthComponent>(5, Direction::LEFT);
player1.addGroup((size_t) GroupLabel::PLAYERS); //tell programm what group it belongs to for rendering order player1.addGroup((size_t) GroupLabel::PLAYERS); //tell programm what group it belongs to for rendering order
player1.setTeam(TeamLabel::BLUE);
player2.setTeam(TeamLabel::RED);
player2.addComponent<TransformComponent>(600, 500, 2); player2.addComponent<TransformComponent>(600, 500, 2);
player2.addComponent<SpriteComponent>("assets/chicken_spritesheet.png", true); player2.addComponent<SpriteComponent>("assets/chicken_spritesheet.png", true);
player2.addComponent<KeyboardController>(SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT, SDL_SCANCODE_RCTRL, Vector2D(-1, 0)); player2.addComponent<KeyboardController>(SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT, SDL_SCANCODE_RCTRL, Vector2D(-1, 0));
player2.addComponent<ColliderComponent>("enemy", 0.8f); player2.addComponent<ColliderComponent>("enemy", 0.8f);
player2.addComponent<HealthComponent>(5, &manager, false); player2.addComponent<HealthComponent>(5, Direction::RIGHT);
player2.addGroup((size_t) GroupLabel::PLAYERS); player2.addGroup((size_t) GroupLabel::PLAYERS);
player2.setTeam(TeamLabel::RED);
} }
auto& tiles(manager.getGroup((size_t)GroupLabel::MAPTILES)); auto& tiles(manager.getGroup((size_t)GroupLabel::MAPTILES));
auto& players(manager.getGroup((size_t)GroupLabel::PLAYERS)); auto& players(manager.getGroup((size_t)GroupLabel::PLAYERS));
auto& enemies(manager.getGroup((size_t)GroupLabel::PLAYERS));
auto& projectiles(manager.getGroup((size_t)GroupLabel::PROJECTILE)); auto& projectiles(manager.getGroup((size_t)GroupLabel::PROJECTILE));
auto& hearts(manager.getGroup((size_t)GroupLabel::HEARTS)); auto& hearts(manager.getGroup((size_t)GroupLabel::HEARTS));
@ -159,50 +162,10 @@ void Game::update()
manager.refresh(); manager.refresh();
manager.update(); manager.update();
//checking if projectiles hit player1 or player2 // needs to be in game.cpp to have access to internal functions
for (auto& p : projectiles) { for (auto& player : manager.getGroup((size_t) GroupLabel::PLAYERS)) {
if(SDL_HasIntersection(&player2.getComponent<ColliderComponent>().collider, &p->getComponent<ColliderComponent>().collider) if (player->getComponent<HealthComponent>().getHealth() <= 0) {
&& (p->getComponent<ColliderComponent>().hasCollision) && !p->getComponent<ProjectileComponent>().getSource()) { this->setWinner(player->getTeam());
//std::cout << "Enemy hit!";
p->getComponent<ColliderComponent>().removeCollision();
p->destroy();
player2.getComponent<HealthComponent>().getDamage();
//display updated health | pretty scuffed but works ig
for(auto h : hearts)
h->destroy();
player1.getComponent<HealthComponent>().createAllHearts();
player2.getComponent<HealthComponent>().createAllHearts();
if(player2.getComponent<HealthComponent>().getHealth() < 1) {
std::cout << "Player1 wins!" << std::endl;
winner = true;
isRunning = false;
}
}
if(SDL_HasIntersection(&player1.getComponent<ColliderComponent>().collider, &p->getComponent<ColliderComponent>().collider)
&& (p->getComponent<ColliderComponent>().hasCollision) && p->getComponent<ProjectileComponent>().getSource()) {
//std::cout << "Player hit!";
p->getComponent<ColliderComponent>().removeCollision();
p->destroy();
player1.getComponent<HealthComponent>().getDamage();
//display updated health
for(auto h : hearts)
h->destroy();
player1.getComponent<HealthComponent>().createAllHearts();
player2.getComponent<HealthComponent>().createAllHearts();
if(player1.getComponent<HealthComponent>().getHealth() < 1) {
std::cout << "Player2 wins!" << std::endl;
winner = false;
isRunning = false;
}
} }
} }
} }
@ -218,10 +181,6 @@ void Game::render()
{ {
p->draw(); p->draw();
} }
for (auto& e : enemies)
{
e->draw();
}
for (auto& p : projectiles) for (auto& p : projectiles)
p->draw(); p->draw();
@ -239,7 +198,7 @@ void Game::clean()
std::cout << "Game Cleaned!" << std::endl; std::cout << "Game Cleaned!" << std::endl;
} }
void Game::addTile(int id, int x, int y) void Game::addTile(unsigned long id, int x, int y)
{ {
auto& tile(manager.addEntity()); auto& tile(manager.addEntity());
tile.addComponent<TileComponent>(x, y, TILE_SIZE, TILE_SIZE, id); tile.addComponent<TileComponent>(x, y, TILE_SIZE, TILE_SIZE, id);
@ -252,6 +211,13 @@ bool Game::running() const
return isRunning; return isRunning;
} }
bool Game::getWinner() { void Game::setWinner(TeamLabel winningTeam)
{
this->winner = winningTeam;
this->isRunning = false;
}
TeamLabel Game::getWinner()
{
return this->winner; return this->winner;
} }

View File

@ -1,17 +1,34 @@
#include "HealthComponent.h" #include "HealthComponent.h"
#include "Components.h" #include "Components.h"
#include "Direction.h"
#include "Entity.h"
#include "Game.h"
#include <cstdio>
void HealthComponent::init() void HealthComponent::init()
{ {
createAllHearts(); resetHearts();
} }
void HealthComponent::createAllHearts() void HealthComponent::modifyHealth(int health)
{ {
this->health += health;
this->resetHearts();
}
void HealthComponent::resetHearts()
{
// clear hearts if exist
for (auto& heart : this->entity->getManager().getGroup((size_t) GroupLabel::HEARTS)) {
if (heart->getTeam() == this->entity->getTeam()) {
heart->destroy();
}
}
int x; //starting position for first health icon int x; //starting position for first health icon
if(player) { if(side == Direction::LEFT) {
x = 10; x = 10;
} else { } else {
x = 730; x = 730;
@ -20,7 +37,7 @@ void HealthComponent::createAllHearts()
for(int i = 0; i < health; i++) { for(int i = 0; i < health; i++) {
//checks for player side //checks for player side
if(player) { if (side == Direction::LEFT) {
createHeartComponents(x); createHeartComponents(x);
x += 50; x += 50;
continue; continue;
@ -33,8 +50,9 @@ void HealthComponent::createAllHearts()
void HealthComponent::createHeartComponents(int x) void HealthComponent::createHeartComponents(int x)
{ {
auto& heart(manager->addEntity()); auto& heart(this->entity->getManager().addEntity());
heart.addComponent<TransformComponent>(x,5,2); heart.addComponent<TransformComponent>(x,5,2);
heart.addComponent<SpriteComponent>("assets/heart.png"); heart.addComponent<SpriteComponent>("assets/heart.png");
heart.addGroup((size_t)GroupLabel::HEARTS); heart.addGroup((size_t)GroupLabel::HEARTS);
heart.setTeam(this->entity->getTeam());
} }

View File

@ -23,27 +23,27 @@ void KeyboardController::init()
void KeyboardController::update() void KeyboardController::update()
{ {
transform->velocity.x = 0; transform->direction.x = 0;
transform->velocity.y = 0; transform->direction.y = 0;
sprite->playAnimation(IDLE); sprite->playAnimation(IDLE);
if (keystates[this->up]) { if (keystates[this->up]) {
transform->velocity.y = -1; transform->direction.y = -1;
sprite->playAnimation(WALK); sprite->playAnimation(WALK);
} }
if (keystates[this->left]) { if (keystates[this->left]) {
transform->velocity.x = -1; transform->direction.x = -1;
sprite->playAnimation(WALK); sprite->playAnimation(WALK);
sprite->setDirection(LEFT); sprite->setDirection(Direction::LEFT);
} }
if (keystates[this->down]) { if (keystates[this->down]) {
transform->velocity.y = 1; transform->direction.y = 1;
sprite->playAnimation(WALK); sprite->playAnimation(WALK);
} }
if (keystates[this->right]) { if (keystates[this->right]) {
transform->velocity.x = 1; transform->direction.x = 1;
sprite->playAnimation(WALK); sprite->playAnimation(WALK);
sprite->setDirection(RIGHT); sprite->setDirection(Direction::RIGHT);
} }
if (keystates[this->fire]) { if (keystates[this->fire]) {
@ -57,14 +57,14 @@ void KeyboardController::update()
//checks player source via the firing velocity //checks player source via the firing velocity
//TODO: adding actual projectile textures //TODO: adding actual projectile textures
if (fireVelocity.x > 0) { if (fireVelocity.x > 0) {
sprite->setDirection(RIGHT); sprite->setDirection(Direction::RIGHT);
Game::assets->createProjectile(Vector2D(player->position.x, player->position.y), fireVelocity, Game::assets->createProjectile(Vector2D(player->position.x, player->position.y), fireVelocity,
false, 1, 180, 1, "assets/egg.png"); false, 1, 180, 1, "assets/egg.png", this->entity->getTeam());
} }
else { else {
sprite->setDirection(LEFT); sprite->setDirection(Direction::LEFT);
Game::assets->createProjectile(Vector2D(player->position.x, player->position.y), fireVelocity, Game::assets->createProjectile(Vector2D(player->position.x, player->position.y), fireVelocity,
true, 1, 180, 1, "assets/egg.png"); true, 1, 180, 1, "assets/egg.png", this->entity->getTeam());
} }
lastFireTime = currentTicks; lastFireTime = currentTicks;

View File

@ -50,22 +50,22 @@ void Manager::update()
void Manager::addToGroup(Entity* mEntity, Group mGroup) void Manager::addToGroup(Entity* mEntity, Group mGroup)
{ {
entitiesByGroup[mGroup].emplace_back(mEntity); entitiesByGroup.at(mGroup).emplace_back(mEntity);
} }
std::vector<Entity*>& Manager::getGroup(Group mGroup) std::vector<Entity*>& Manager::getGroup(Group mGroup)
{ {
return entitiesByGroup[mGroup]; return entitiesByGroup.at(mGroup);
} }
void Manager::addToTeam(Entity* mEntity, Team mTeam) void Manager::addToTeam(Entity* mEntity, Team mTeam)
{ {
entitiesByTeam[mTeam].emplace_back(mEntity); entitiesByTeam.at(mTeam).emplace_back(mEntity); //
} }
std::vector<Entity*>& Manager::getTeam(Team mTeam) std::vector<Entity*>& Manager::getTeam(Team mTeam)
{ {
return entitiesByTeam[mTeam]; return entitiesByTeam.at(mTeam);
} }
std::vector<Entity*> Manager::getAll() std::vector<Entity*> Manager::getAll()

View File

@ -1,21 +1,44 @@
#include "ProjectileComponent.h" #include "ProjectileComponent.h"
#include "CollisionHandler.h"
#include "Components.h" #include "Components.h"
#include "Entity.h"
#include "Game.h"
#include "HealthComponent.h"
#include "Vector2D.h"
#include <cassert>
#include <cstdio>
void ProjectileComponent::init() void ProjectileComponent::init()
{ {
transformComponent = &entity->getComponent<TransformComponent>(); transformComponent = &entity->getComponent<TransformComponent>();
transformComponent->direction = direction;
} }
void ProjectileComponent::update() void ProjectileComponent::update()
{ {
transformComponent->velocity = velocity;
distance += speed; distance += speed;
IntersectionBitSet boundsIntersection = Game::collisionHandler->getIntersectionWithBounds(entity);
if ((boundsIntersection | IntersectionBitSet("1100")).all() || (boundsIntersection | IntersectionBitSet("0011")).all()) {
this->entity->destroy();
std::cout << "out of bounds" << std::endl;
}
if (distance > range) { if (distance > range) {
entity->destroy(); this->entity->destroy();
entity->getComponent<ColliderComponent>().removeCollision(); std::cout << "out of range" << std::endl;
//std::cout << "out of range" << std::endl; }
Entity* player;
if ((player = Game::collisionHandler->getAnyIntersection<Entity*>(
entity,
Vector2D(0,0),
{GroupLabel::PLAYERS},
{entity->getTeam()},
true)) != nullptr) {
player->getComponent<HealthComponent>().modifyHealth();
this->entity->destroy();
} }
} }

View File

@ -2,6 +2,7 @@
#include <SDL_timer.h> #include <SDL_timer.h>
#include "Direction.h"
#include "TextureManager.h" #include "TextureManager.h"
#include "Entity.h" #include "Entity.h"
#include "TransformComponent.h" #include "TransformComponent.h"
@ -71,9 +72,9 @@ void SpriteComponent::playAnimation(AnimationType type)
this->speed = animations.at(type)->speed; this->speed = animations.at(type)->speed;
} }
void SpriteComponent::setDirection(SpriteDirection direction) void SpriteComponent::setDirection(Direction direction)
{ {
if (direction == RIGHT) { if (direction == Direction::RIGHT) {
this->flipped = true; this->flipped = true;
return; return;
} }

View File

@ -6,6 +6,8 @@
#include "Entity.h" #include "Entity.h"
#include "Game.h" #include "Game.h"
#include "Vector2D.h" #include "Vector2D.h"
#include <cstdio>
#include <initializer_list>
#include <iostream> #include <iostream>
TransformComponent::TransformComponent() TransformComponent::TransformComponent()
@ -43,33 +45,29 @@ TransformComponent::TransformComponent(float x, float y, int w, int h, int scale
void TransformComponent::init() void TransformComponent::init()
{ {
velocity.zero(); direction.zero();
} }
void TransformComponent::update() void TransformComponent::update()
{ {
// if(velocity.x != 0 && velocity.y != 0) // if(velocity.x != 0 && velocity.y != 0)
float multiplier = velocity.x != 0 && velocity.y != 0 ? 0.707 : 1; //normalizes vector float multiplier = direction.x != 0 && direction.y != 0 ? 0.707 : 1; // normalizes vector; only works if directions are in increments of 45°
Vector2D positionChange( Vector2D positionChange(
velocity.x * speed * multiplier, direction.x * speed * multiplier,
velocity.y * speed * multiplier direction.y * speed * multiplier
); );
// TODO: move to separate functions // TODO: move to separate functions
if (this->entity->hasGroup((size_t) GroupLabel::PLAYERS)) { if (this->entity->hasGroup((size_t) GroupLabel::PLAYERS)) {
IntersectionBitSet intersectionsX = CollisionHandler::getIntersectionWithBounds(entity, positionChange); IntersectionBitSet intersections =
for (auto& collider : Game::collisionHandler->getColliders({GroupLabel::MAPTILES, GroupLabel::COLLIDERS})) { (CollisionHandler::getIntersectionWithBounds(entity, Vector2D(positionChange.x, 0)) |
intersectionsX |= CollisionHandler::getIntersection(entity, collider->entity, Vector2D(positionChange.x, 0), Vector2D(0, 0)); (Game::collisionHandler->getAnyIntersection<IntersectionBitSet>(entity, Vector2D(positionChange.x, 0), {GroupLabel::MAPTILES, GroupLabel::COLLIDERS})) &
} IntersectionBitSet("0011")) |
(CollisionHandler::getIntersectionWithBounds(entity, Vector2D(0, positionChange.y)) |
IntersectionBitSet intersectionsY = CollisionHandler::getIntersectionWithBounds(entity, positionChange); (Game::collisionHandler->getAnyIntersection<IntersectionBitSet>(entity, Vector2D(0, positionChange.y), {GroupLabel::MAPTILES, GroupLabel::COLLIDERS})) &
for (auto& collider : Game::collisionHandler->getColliders({GroupLabel::MAPTILES, GroupLabel::COLLIDERS})) { IntersectionBitSet("1100"));
intersectionsY |= CollisionHandler::getIntersection(entity, collider->entity, Vector2D(0, positionChange.y), Vector2D(0, 0));
}
IntersectionBitSet intersections = (intersectionsX & IntersectionBitSet("0011")) | (intersectionsY & IntersectionBitSet("1100"));
if (intersections.test((size_t) direction::LEFT) || intersections.test((size_t) direction::RIGHT)) if (intersections.test((size_t) direction::LEFT) || intersections.test((size_t) direction::RIGHT))
positionChange.x = 0; positionChange.x = 0;

View File

@ -1,4 +1,5 @@
#include "Vector2D.h" #include "Vector2D.h"
#include "SDL_rect.h"
Vector2D::Vector2D() Vector2D::Vector2D()
{ {
@ -56,3 +57,11 @@ Vector2D& Vector2D::zero()
return *this; return *this;
} }
SDL_Rect operator+(const SDL_Rect& rect, const Vector2D& vector2D)
{
SDL_Rect newRect = rect;
newRect.x += vector2D.x;
newRect.y += vector2D.y;
return newRect;
}