mirror of
https://github.com/Nimac0/SDL_Minigame
synced 2026-01-13 02:43:41 +00:00
Compare commits
No commits in common. "e493960fe0c1107662df6446f2f8a12cae27f681" and "5a1e7986d3bfc36947fbe52567720791b788f6e6" have entirely different histories.
e493960fe0
...
5a1e7986d3
@ -24,7 +24,7 @@ public:
|
|||||||
AssetManager(Manager* manager);
|
AssetManager(Manager* manager);
|
||||||
~AssetManager();
|
~AssetManager();
|
||||||
|
|
||||||
void createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, const char* texturePath, Entity* owner);
|
void createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, const char* texturePath, Entity::TeamLabel teamLabel);
|
||||||
void createPowerup(Vector2D pos, std::function<void (Entity*)> pickupFunc, std::string texturePath);
|
void createPowerup(Vector2D pos, std::function<void (Entity*)> pickupFunc, std::string texturePath);
|
||||||
|
|
||||||
Vector2D calculateSpawnPosition();
|
Vector2D calculateSpawnPosition();
|
||||||
|
|||||||
@ -44,14 +44,16 @@ public:
|
|||||||
// temporary function, remove once game.cpp cleaned up
|
// temporary function, remove once game.cpp cleaned up
|
||||||
std::vector<ColliderComponent*> getColliders(
|
std::vector<ColliderComponent*> getColliders(
|
||||||
std::initializer_list<Entity::GroupLabel> const& groupLabels,
|
std::initializer_list<Entity::GroupLabel> const& groupLabels,
|
||||||
std::initializer_list<Entity*> const& excludedEntities = {});
|
std::initializer_list<Entity::TeamLabel> const& teamLabels = {},
|
||||||
|
bool negateTeam = false);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T getAnyIntersection(
|
T getAnyIntersection(
|
||||||
Entity* entity,
|
Entity* entity,
|
||||||
Vector2D posMod = {},
|
Vector2D posMod = {},
|
||||||
std::initializer_list<Entity::GroupLabel> const& groupLabels = {},
|
std::initializer_list<Entity::GroupLabel> const& groupLabels = {},
|
||||||
std::initializer_list<Entity*> const& excludedEntities = {});
|
std::initializer_list<Entity::TeamLabel> const& teamLabels = {},
|
||||||
|
bool negateTeam = false);
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
};
|
};
|
||||||
@ -3,6 +3,7 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
using Group = std::size_t;
|
using Group = std::size_t;
|
||||||
|
using Team = std::size_t;
|
||||||
|
|
||||||
constexpr int CHARACTER_COUNT = 4;
|
constexpr int CHARACTER_COUNT = 4;
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
// TODO: remove here if possible
|
// TODO: remove here if possible
|
||||||
// temporary fix: addComponent function template doesnt know TransformComponent -> error undefined type
|
// temporary fix: addComponent function template doesnt know TransformComponent -> error undefined type
|
||||||
|
// #include "KeyboardController.h"
|
||||||
#include "InputComponent.h"
|
#include "InputComponent.h"
|
||||||
#include "TransformComponent.h"
|
#include "TransformComponent.h"
|
||||||
#include "SpriteComponent.h"
|
#include "SpriteComponent.h"
|
||||||
@ -38,6 +39,13 @@ public:
|
|||||||
POWERUPS
|
POWERUPS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class TeamLabel
|
||||||
|
{
|
||||||
|
NONE, //!< No team
|
||||||
|
BLUE, //!< Team blue
|
||||||
|
RED //!< Team red
|
||||||
|
};
|
||||||
|
|
||||||
explicit Entity(Manager& mManager) :
|
explicit Entity(Manager& mManager) :
|
||||||
manager(mManager) { };
|
manager(mManager) { };
|
||||||
|
|
||||||
@ -57,6 +65,9 @@ public:
|
|||||||
void delGroup(Group mGroup);
|
void delGroup(Group mGroup);
|
||||||
std::bitset<MAX_GROUPS> getGroupBitSet();
|
std::bitset<MAX_GROUPS> getGroupBitSet();
|
||||||
|
|
||||||
|
void setTeam(TeamLabel teamLabel);
|
||||||
|
TeamLabel getTeam();
|
||||||
|
|
||||||
Manager& getManager() { return manager; };
|
Manager& getManager() { return manager; };
|
||||||
|
|
||||||
template <typename T> bool hasComponent() const
|
template <typename T> bool hasComponent() const
|
||||||
@ -92,4 +103,5 @@ private:
|
|||||||
ComponentArray componentArray = {};
|
ComponentArray componentArray = {};
|
||||||
ComponentBitSet componentBitSet;
|
ComponentBitSet componentBitSet;
|
||||||
GroupBitSet groupBitSet;
|
GroupBitSet groupBitSet;
|
||||||
|
TeamLabel teamLabel;
|
||||||
};
|
};
|
||||||
@ -20,6 +20,18 @@ public:
|
|||||||
return factory;
|
return factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*Game* get() {
|
||||||
|
assert(this->gameInstance != nullptr);
|
||||||
|
return this->gameInstance;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*Game* create(GameInternal* gameInternal) {
|
||||||
|
Game* game = this->gameInstance == nullptr ? this->creator() : this->gameInstance; // TODO: error handling
|
||||||
|
game->gameInternal = gameInternal;
|
||||||
|
this->gameInstance = game;
|
||||||
|
return game;
|
||||||
|
}*/
|
||||||
|
|
||||||
void registerClass(CreateFunc createFunc) {
|
void registerClass(CreateFunc createFunc) {
|
||||||
this->creatorFunc = createFunc;
|
this->creatorFunc = createFunc;
|
||||||
}
|
}
|
||||||
@ -37,3 +49,11 @@ public:
|
|||||||
private:
|
private:
|
||||||
CreateFunc creatorFunc = nullptr;
|
CreateFunc creatorFunc = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
#define REGISTER_GAME(className) \
|
||||||
|
static bool registered_##className = []() { \
|
||||||
|
GameFactory::instance().registerClass(#className, []() -> Game* { return new className; }); \
|
||||||
|
return true; \
|
||||||
|
}();
|
||||||
|
*/
|
||||||
|
|||||||
@ -26,14 +26,14 @@ public:
|
|||||||
~GameInternal();
|
~GameInternal();
|
||||||
|
|
||||||
void init(const char* title, int xpos, int ypos, int width, int height, bool fullscreen);
|
void init(const char* title, int xpos, int ypos, int width, int height, bool fullscreen);
|
||||||
|
void selectCharacters(const char* &playerSprite, const char* &enemySprite);
|
||||||
|
|
||||||
void handleEvents();
|
void handleEvents();
|
||||||
void update();
|
void update();
|
||||||
void render();
|
void render();
|
||||||
void clean();
|
void clean();
|
||||||
bool isRunning() const;
|
bool isRunning() const;
|
||||||
void setRunning(bool running); // TODO: should be private/not accesible for game dev
|
void setRunning(bool running);
|
||||||
void stopGame();
|
|
||||||
|
|
||||||
/* static */ SDL_Renderer* renderer = nullptr;
|
/* static */ SDL_Renderer* renderer = nullptr;
|
||||||
/* static */ SDL_Event event;
|
/* static */ SDL_Event event;
|
||||||
@ -54,12 +54,15 @@ public:
|
|||||||
// end moved globals
|
// end moved globals
|
||||||
|
|
||||||
void refreshPlayers();
|
void refreshPlayers();
|
||||||
|
Entity::TeamLabel getWinner() const;
|
||||||
|
void setWinner(Entity::TeamLabel winningTeam);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Game* gameInstance;
|
Game* gameInstance;
|
||||||
|
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
bool running = true;
|
bool running = false;
|
||||||
SDL_Window* window;
|
SDL_Window* window;
|
||||||
|
Entity::TeamLabel winner;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "Direction.h"
|
#include "Direction.h"
|
||||||
#include "Component.h"
|
#include "Component.h"
|
||||||
|
|
||||||
@ -12,7 +10,7 @@ class HealthComponent : public Component
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
HealthComponent(int health) : health(health) {}
|
HealthComponent(int health, Direction side, std::string healthTexture) : health(health), side(side), healthTexture(healthTexture) {}
|
||||||
~HealthComponent() {}
|
~HealthComponent() {}
|
||||||
|
|
||||||
void modifyHealth(int health = -1);
|
void modifyHealth(int health = -1);
|
||||||
@ -28,4 +26,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
int health;
|
int health;
|
||||||
|
Direction side;
|
||||||
|
std::string healthTexture;
|
||||||
};
|
};
|
||||||
@ -96,6 +96,7 @@ public:
|
|||||||
void init() override;
|
void init() override;
|
||||||
void update() override;
|
void update() override;
|
||||||
|
|
||||||
|
// void pollEvents();
|
||||||
bool isKeyDown(Key key);
|
bool isKeyDown(Key key);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -22,6 +22,9 @@ public:
|
|||||||
void addToGroup(Entity* mEntity, Group mGroup);
|
void addToGroup(Entity* mEntity, Group mGroup);
|
||||||
std::vector<Entity*>& getGroup(Group mGroup);
|
std::vector<Entity*>& getGroup(Group mGroup);
|
||||||
|
|
||||||
|
void addToTeam(Entity* mEntity, Team mTeam);
|
||||||
|
std::vector<Entity*>& getTeam(Team mTeam);
|
||||||
|
|
||||||
std::vector<Entity*> getAll();
|
std::vector<Entity*> getAll();
|
||||||
|
|
||||||
Entity& addEntity();
|
Entity& addEntity();
|
||||||
@ -32,4 +35,5 @@ private:
|
|||||||
GameInternal* game;
|
GameInternal* game;
|
||||||
std::vector<std::unique_ptr<Entity>> entities;
|
std::vector<std::unique_ptr<Entity>> entities;
|
||||||
std::array<std::vector<Entity*>, MAX_GROUPS> entitiesByGroup;
|
std::array<std::vector<Entity*>, MAX_GROUPS> entitiesByGroup;
|
||||||
|
std::array<std::vector<Entity*>, MAX_TEAMS> entitiesByTeam;
|
||||||
};
|
};
|
||||||
28
include/PopupWindow.h
Normal file
28
include/PopupWindow.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <SDL_ttf.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "Entity.h"
|
||||||
|
|
||||||
|
class GameInternal;
|
||||||
|
|
||||||
|
class PopupWindow {
|
||||||
|
|
||||||
|
public:
|
||||||
|
PopupWindow(const char* title, const std::string& message);
|
||||||
|
~PopupWindow();
|
||||||
|
|
||||||
|
void handleWinnerEvents();
|
||||||
|
bool shouldContinue() const;
|
||||||
|
|
||||||
|
bool interacted;
|
||||||
|
|
||||||
|
void renderWinnerPopup(Entity::TeamLabel winner);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SDL_Renderer* renderer;
|
||||||
|
SDL_Window* window;
|
||||||
|
SDL_Texture* texture;
|
||||||
|
bool continueGame;
|
||||||
|
};
|
||||||
@ -11,8 +11,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 direction, Entity* owner)
|
ProjectileComponent(int range, int speed, Vector2D direction) : range(range), speed(speed), direction(direction) {}
|
||||||
: range(range), speed(speed), direction(direction), owner(owner) {}
|
|
||||||
~ProjectileComponent() {}
|
~ProjectileComponent() {}
|
||||||
|
|
||||||
void init() override;
|
void init() override;
|
||||||
@ -25,7 +24,5 @@ private:
|
|||||||
int speed = 0;
|
int speed = 0;
|
||||||
int distance = 0;
|
int distance = 0;
|
||||||
|
|
||||||
Entity* owner = nullptr;
|
|
||||||
|
|
||||||
Vector2D direction;
|
Vector2D direction;
|
||||||
};
|
};
|
||||||
@ -7,7 +7,7 @@
|
|||||||
class TransformComponent : public Component
|
class TransformComponent : public Component
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Vector2D position; // TODO: change to int to save CPU time -> possibly subpixel coordinates
|
Vector2D position; // TODO: change to int to safe CPU time -> possibly subpixel coordinates
|
||||||
Vector2D direction;
|
Vector2D direction;
|
||||||
|
|
||||||
int height = 32;
|
int height = 32;
|
||||||
|
|||||||
@ -46,14 +46,15 @@ Mix_Music* AssetManager::getMusic(std::string id)
|
|||||||
return music.at(id);
|
return music.at(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, const char* texturePath, Entity* owner) {
|
void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, const char* texturePath, Entity::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
|
||||||
projectile.addComponent<SpriteComponent>(texturePath);
|
projectile.addComponent<SpriteComponent>(texturePath);
|
||||||
projectile.addComponent<ProjectileComponent>(range, speed, velocity, owner);
|
projectile.addComponent<ProjectileComponent>(range, speed, velocity);
|
||||||
projectile.addComponent<ColliderComponent>("projectile", 0.6f);
|
projectile.addComponent<ColliderComponent>("projectile", 0.6f);
|
||||||
projectile.addGroup((size_t)Entity::GroupLabel::PROJECTILE);
|
projectile.addGroup((size_t)Entity::GroupLabel::PROJECTILE);
|
||||||
|
projectile.setTeam(teamLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetManager::createPowerup(Vector2D pos, std::function<void (Entity*)> pickupFunc, std::string texturePath) {
|
void AssetManager::createPowerup(Vector2D pos, std::function<void (Entity*)> pickupFunc, std::string texturePath) {
|
||||||
|
|||||||
@ -31,6 +31,7 @@ void ColliderComponent::init()
|
|||||||
}
|
}
|
||||||
|
|
||||||
transform = &entity->getComponent<TransformComponent>();
|
transform = &entity->getComponent<TransformComponent>();
|
||||||
|
//Game::collisionHandler->add(this);
|
||||||
this->update();
|
this->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -87,7 +87,8 @@ IntersectionBitSet CollisionHandler::getIntersectionWithBounds(Entity* entity, V
|
|||||||
|
|
||||||
std::vector<ColliderComponent*> CollisionHandler::getColliders(
|
std::vector<ColliderComponent*> CollisionHandler::getColliders(
|
||||||
std::initializer_list<Entity::GroupLabel> const& groupLabels,
|
std::initializer_list<Entity::GroupLabel> const& groupLabels,
|
||||||
std::initializer_list<Entity*> const& excludedEntities)
|
std::initializer_list<Entity::TeamLabel> const& teamLabels,
|
||||||
|
bool negateTeam)
|
||||||
{
|
{
|
||||||
std::vector<ColliderComponent*> colliders;
|
std::vector<ColliderComponent*> colliders;
|
||||||
|
|
||||||
@ -96,11 +97,16 @@ std::vector<ColliderComponent*> CollisionHandler::getColliders(
|
|||||||
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 (std::ranges::find(excludedEntities, entity) != excludedEntities.end())
|
if (teamBitSet.any() && negateTeam != (teamBitSet.test((size_t) entity->getTeam())))
|
||||||
continue;
|
continue;
|
||||||
if (!entity->hasComponent<ColliderComponent>())
|
if (!entity->hasComponent<ColliderComponent>())
|
||||||
continue;
|
continue;
|
||||||
colliders.emplace_back(&entity->getComponent<ColliderComponent>());
|
colliders.emplace_back(&entity->getComponent<ColliderComponent>());
|
||||||
@ -114,10 +120,11 @@ IntersectionBitSet CollisionHandler::getAnyIntersection<IntersectionBitSet>(
|
|||||||
Entity* entity,
|
Entity* entity,
|
||||||
Vector2D posMod,
|
Vector2D posMod,
|
||||||
std::initializer_list<Entity::GroupLabel> const& groupLabels,
|
std::initializer_list<Entity::GroupLabel> const& groupLabels,
|
||||||
std::initializer_list<Entity*> const& excludedEntities)
|
std::initializer_list<Entity::TeamLabel> const& teamLabels,
|
||||||
|
bool negateTeam)
|
||||||
{
|
{
|
||||||
IntersectionBitSet intersections;
|
IntersectionBitSet intersections;
|
||||||
for (auto& collider : getColliders(groupLabels, excludedEntities)) {
|
for (auto& collider : getColliders(groupLabels, teamLabels)) {
|
||||||
intersections |= getIntersection(entity, collider->entity, posMod);
|
intersections |= getIntersection(entity, collider->entity, posMod);
|
||||||
}
|
}
|
||||||
return intersections;
|
return intersections;
|
||||||
@ -128,9 +135,10 @@ Entity* CollisionHandler::getAnyIntersection<Entity*>(
|
|||||||
Entity* entity,
|
Entity* entity,
|
||||||
Vector2D posMod,
|
Vector2D posMod,
|
||||||
std::initializer_list<Entity::GroupLabel> const& groupLabels,
|
std::initializer_list<Entity::GroupLabel> const& groupLabels,
|
||||||
std::initializer_list<Entity*> const& excludedEntities)
|
std::initializer_list<Entity::TeamLabel> const& teamLabels,
|
||||||
|
bool negateTeam)
|
||||||
{
|
{
|
||||||
for (auto& collider : getColliders(groupLabels, excludedEntities)) {
|
for (auto& collider : getColliders(groupLabels, teamLabels)) {
|
||||||
SDL_Rect rect = entity->getComponent<ColliderComponent>().collider + posMod;
|
SDL_Rect rect = entity->getComponent<ColliderComponent>().collider + posMod;
|
||||||
if (SDL_HasIntersection(&rect, &collider->collider)) {
|
if (SDL_HasIntersection(&rect, &collider->collider)) {
|
||||||
return collider->entity;
|
return collider->entity;
|
||||||
|
|||||||
@ -34,3 +34,14 @@ std::bitset<MAX_GROUPS> Entity::getGroupBitSet()
|
|||||||
{
|
{
|
||||||
return groupBitSet;
|
return groupBitSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Entity::setTeam(Entity::TeamLabel teamLabel)
|
||||||
|
{
|
||||||
|
this->teamLabel = teamLabel;
|
||||||
|
manager.addToTeam(this, (size_t) teamLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity::TeamLabel Entity::getTeam()
|
||||||
|
{
|
||||||
|
return teamLabel;
|
||||||
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include "CollisionHandler.h"
|
#include "CollisionHandler.h"
|
||||||
#include "AssetManager.h"
|
#include "AssetManager.h"
|
||||||
#include "SoundManager.h"
|
#include "SoundManager.h"
|
||||||
|
// #include "KeyboardController.h"
|
||||||
#include "TileComponent.h"
|
#include "TileComponent.h"
|
||||||
#include "Direction.h"
|
#include "Direction.h"
|
||||||
#include "Entity.h"
|
#include "Entity.h"
|
||||||
@ -23,6 +24,8 @@ GameInternal::GameInternal() :
|
|||||||
projectiles(manager.getGroup((size_t)Entity::GroupLabel::PROJECTILE)),
|
projectiles(manager.getGroup((size_t)Entity::GroupLabel::PROJECTILE)),
|
||||||
hearts(manager.getGroup((size_t)Entity::GroupLabel::HEARTS)),
|
hearts(manager.getGroup((size_t)Entity::GroupLabel::HEARTS)),
|
||||||
powerups(manager.getGroup((size_t)Entity::GroupLabel::POWERUPS))
|
powerups(manager.getGroup((size_t)Entity::GroupLabel::POWERUPS))
|
||||||
|
//player1(manager.addEntity()),
|
||||||
|
//player2(manager.addEntity())
|
||||||
{};
|
{};
|
||||||
|
|
||||||
GameInternal::~GameInternal() = default;
|
GameInternal::~GameInternal() = default;
|
||||||
@ -129,10 +132,25 @@ void GameInternal::init(const char* title, int xpos, int ypos, int width, int he
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// engine::init(); // temporarily moved down to access groups at engine init call
|
||||||
|
|
||||||
|
// character selection
|
||||||
|
const char* player1Sprite;
|
||||||
|
const char* player2Sprite;
|
||||||
|
|
||||||
|
selectCharacters(player1Sprite, player2Sprite);
|
||||||
if (this->isRunning() == false) return;
|
if (this->isRunning() == false) return;
|
||||||
|
|
||||||
map = new Map();
|
map = new Map();
|
||||||
|
|
||||||
|
|
||||||
|
//adding textures to the library in AssetManager
|
||||||
|
|
||||||
|
/*
|
||||||
|
assets->addTexture("player1", "assets/chicken_neutral_knight.png");
|
||||||
|
assets->addTexture("player2", "assets/chicken_neutral.png");
|
||||||
|
assets->addTexture("egg", "assets/egg.png");
|
||||||
|
*/
|
||||||
// loading sounds
|
// loading sounds
|
||||||
// assets->addSoundEffect("throw_egg", "assets/sound/throw_egg.wav");
|
// assets->addSoundEffect("throw_egg", "assets/sound/throw_egg.wav");
|
||||||
// assets->addSoundEffect("steps", "assets/sound/steps.wav");
|
// assets->addSoundEffect("steps", "assets/sound/steps.wav");
|
||||||
@ -140,10 +158,127 @@ void GameInternal::init(const char* title, int xpos, int ypos, int width, int he
|
|||||||
// loading music
|
// loading music
|
||||||
// assets->addMusic("background_music", "assets/sound/background_music.mp3");
|
// assets->addMusic("background_music", "assets/sound/background_music.mp3");
|
||||||
|
|
||||||
|
//ecs implementation
|
||||||
|
|
||||||
|
// player1.setTeam(Entity::TeamLabel::BLUE);
|
||||||
|
// player1.addComponent<TransformComponent>(80,80,2); //posx, posy, scale
|
||||||
|
// player1.addComponent<SpriteComponent>(player1Sprite, 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(2, 0));//custom keycontrols can be added
|
||||||
|
// player1.addComponent<ColliderComponent>("player", 0.8f); //adds tag (for further use, reference tag)
|
||||||
|
// player1.addComponent<HealthComponent>(5, Direction::LEFT, "assets/heart.png");
|
||||||
|
// player1.addComponent<StatEffectsComponent>();
|
||||||
|
// player1.addGroup((size_t) Entity::GroupLabel::PLAYERS); //tell programm what group it belongs to for rendering order
|
||||||
|
|
||||||
|
|
||||||
|
// player2.setTeam(Entity::TeamLabel::RED);
|
||||||
|
// player2.addComponent<TransformComponent>(600, 500, 2);
|
||||||
|
// player2.addComponent<SpriteComponent>(player2Sprite, true);
|
||||||
|
// player2.addComponent<KeyboardController>(SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT, SDL_SCANCODE_RCTRL, Vector2D(-2, 0));
|
||||||
|
// player2.addComponent<ColliderComponent>("enemy", 0.8f);
|
||||||
|
// player2.addComponent<HealthComponent>(5, Direction::RIGHT, "assets/heart.png");
|
||||||
|
// player2.addComponent<StatEffectsComponent>();
|
||||||
|
// player2.addGroup((size_t) Entity::GroupLabel::PLAYERS);
|
||||||
|
|
||||||
this->gameInstance = GameFactory::instance().create(this);
|
this->gameInstance = GameFactory::instance().create(this);
|
||||||
this->gameInstance->init();
|
this->gameInstance->init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameInternal::selectCharacters(const char* &playerSprite, const char* &enemySprite)
|
||||||
|
{
|
||||||
|
// TODO: move this whereever it makes sense (maybe game as a member)
|
||||||
|
std::map<int, std::pair<const char*, const char*>> characterSprites;
|
||||||
|
characterSprites[0] = std::make_pair("assets/chicken_neutral_knight.png", "assets/chicken_knight_spritesheet.png");
|
||||||
|
characterSprites[1] = std::make_pair("assets/chicken_neutral.png", "assets/chicken_spritesheet.png");
|
||||||
|
characterSprites[2] = std::make_pair("assets/chicken_neutral_wizard.png", "assets/chicken_wizard_spritesheet.png");
|
||||||
|
characterSprites[3] = std::make_pair("assets/chicken_neutral_mlady.png", "assets/chicken_mlady_spritesheet.png");
|
||||||
|
|
||||||
|
SDL_Rect playerCharacterRects[CHARACTER_COUNT];
|
||||||
|
SDL_Rect enemyCharacterRects[CHARACTER_COUNT];
|
||||||
|
SDL_Texture* characterTextures[CHARACTER_COUNT];
|
||||||
|
|
||||||
|
int playerSelection = 0;
|
||||||
|
int enemySelection = 0;
|
||||||
|
|
||||||
|
// load textures
|
||||||
|
for (int i = 0; i < CHARACTER_COUNT; ++i)
|
||||||
|
{
|
||||||
|
characterTextures[i] = IMG_LoadTexture(renderer, characterSprites.find(i)->second.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up initial positions for character rects
|
||||||
|
for (int i = 0; i < CHARACTER_COUNT; ++i)
|
||||||
|
{
|
||||||
|
playerCharacterRects[i] = { 134 + (i % 2) * 118, 272 + ((i >= 2) ? 114 : 0), 64, 64 };
|
||||||
|
enemyCharacterRects[i] = { 485 + (i % 2) * 118, 273 + ((i >= 2) ? 114 : 0), 64, 64 };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasQuit = false;
|
||||||
|
|
||||||
|
while (!hasQuit)
|
||||||
|
{
|
||||||
|
SDL_PollEvent(&event);
|
||||||
|
|
||||||
|
if (event.type == SDL_QUIT)
|
||||||
|
{
|
||||||
|
hasQuit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == SDL_KEYDOWN)
|
||||||
|
{
|
||||||
|
if (event.key.keysym.scancode == SDL_SCANCODE_RETURN)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (event.key.keysym.scancode)
|
||||||
|
{
|
||||||
|
case SDL_SCANCODE_A:
|
||||||
|
playerSelection = (playerSelection - 1 + CHARACTER_COUNT) % CHARACTER_COUNT;
|
||||||
|
break;
|
||||||
|
case SDL_SCANCODE_D:
|
||||||
|
playerSelection = (playerSelection + 1) % CHARACTER_COUNT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_SCANCODE_LEFT:
|
||||||
|
enemySelection = (enemySelection - 1 + CHARACTER_COUNT) % CHARACTER_COUNT;
|
||||||
|
break;
|
||||||
|
case SDL_SCANCODE_RIGHT:
|
||||||
|
enemySelection = (enemySelection + 1) % CHARACTER_COUNT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Texture* backgroundTexture = GameInternal::textureManager->loadTexture("assets/characterSelection.png");
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
SDL_RenderCopy(renderer, backgroundTexture, NULL, NULL);
|
||||||
|
|
||||||
|
for (int i = 0; i < CHARACTER_COUNT; ++i)
|
||||||
|
{
|
||||||
|
SDL_RenderCopy(renderer, characterTextures[i], nullptr, &playerCharacterRects[i]);
|
||||||
|
SDL_RenderCopy(renderer, characterTextures[i], nullptr, &enemyCharacterRects[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
|
||||||
|
SDL_RenderDrawRect(renderer, &playerCharacterRects[playerSelection]);
|
||||||
|
SDL_RenderDrawRect(renderer, &enemyCharacterRects[enemySelection]);
|
||||||
|
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasQuit)
|
||||||
|
{
|
||||||
|
this->setRunning(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
playerSprite = characterSprites.find(playerSelection)->second.second;
|
||||||
|
enemySprite = characterSprites.find(enemySelection)->second.second;
|
||||||
|
this->setRunning(true);
|
||||||
|
}
|
||||||
|
|
||||||
void GameInternal::handleEvents()
|
void GameInternal::handleEvents()
|
||||||
{
|
{
|
||||||
SDL_PollEvent(&event);
|
SDL_PollEvent(&event);
|
||||||
@ -201,13 +336,35 @@ bool GameInternal::isRunning() const
|
|||||||
return running;
|
return running;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameInternal::setRunning(bool running) //TODO: might be depracted
|
void GameInternal::setRunning(bool running)
|
||||||
{
|
{
|
||||||
this->running = running;
|
this->running = running;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameInternal::stopGame()
|
void GameInternal::setWinner(Entity::TeamLabel winningTeam)
|
||||||
{
|
{
|
||||||
this->running = false;
|
this->winner = winningTeam;
|
||||||
|
this->setRunning(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Entity::TeamLabel GameInternal::getWinner() const
|
||||||
|
{
|
||||||
|
return this->winner;
|
||||||
|
}
|
||||||
|
|
||||||
|
//void Game::refreshPlayers() {
|
||||||
|
//
|
||||||
|
// for(auto& p : projectiles) {
|
||||||
|
// p->destroy();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// player1.getComponent<TransformComponent>().position = Vector2D(80, 80);
|
||||||
|
// player2.getComponent<TransformComponent>().position = Vector2D(600, 500);
|
||||||
|
//
|
||||||
|
// player1.getComponent<HealthComponent>().setHealth(5);
|
||||||
|
// player2.getComponent<HealthComponent>().setHealth(5);
|
||||||
|
//
|
||||||
|
// isRunning = true;
|
||||||
|
//
|
||||||
|
// update();
|
||||||
|
//}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ GameObject::GameObject(const char* texturesheet, int x, int y)
|
|||||||
// seems not to be used, and was using deprecated functionality
|
// seems not to be used, and was using deprecated functionality
|
||||||
SDL_SetError("GameObject not implemented");
|
SDL_SetError("GameObject not implemented");
|
||||||
|
|
||||||
|
// this->objTexture = Game::textureManager->loadTexture(texturesheet);
|
||||||
this->xPos = x;
|
this->xPos = x;
|
||||||
this->yPos = y;
|
this->yPos = y;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,14 +6,58 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
void HealthComponent::init()
|
void HealthComponent::init()
|
||||||
{}
|
{
|
||||||
|
refreshHearts();
|
||||||
|
}
|
||||||
|
|
||||||
void HealthComponent::modifyHealth(int health)
|
void HealthComponent::modifyHealth(int health)
|
||||||
{
|
{
|
||||||
this->health += health;
|
this->health += health;
|
||||||
|
this->refreshHearts();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HealthComponent::setHealth(int health)
|
void HealthComponent::setHealth(int health)
|
||||||
{
|
{
|
||||||
this->health = health;
|
this->health = health;
|
||||||
|
this->refreshHearts();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HealthComponent::refreshHearts()
|
||||||
|
{
|
||||||
|
// clear hearts if exist
|
||||||
|
for (auto& heart : this->entity->getManager().getGroup((size_t) Entity::GroupLabel::HEARTS)) {
|
||||||
|
if (heart->getTeam() == this->entity->getTeam()) {
|
||||||
|
heart->destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int x; //starting position for first health icon
|
||||||
|
|
||||||
|
if(side == Direction::LEFT) {
|
||||||
|
x = 10;
|
||||||
|
} else {
|
||||||
|
x = 730;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < health; i++) {
|
||||||
|
|
||||||
|
//checks for player side
|
||||||
|
if (side == Direction::LEFT) {
|
||||||
|
createHeartComponents(x);
|
||||||
|
x += 50;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
createHeartComponents(x);
|
||||||
|
x -= 50;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HealthComponent::createHeartComponents(int x)
|
||||||
|
{
|
||||||
|
auto& heart(this->entity->getManager().addEntity());
|
||||||
|
heart.addComponent<TransformComponent>(x,5,2);
|
||||||
|
heart.addComponent<SpriteComponent>(this->healthTexture.data());
|
||||||
|
heart.addGroup((size_t)Entity::GroupLabel::HEARTS);
|
||||||
|
heart.setTeam(this->entity->getTeam());
|
||||||
}
|
}
|
||||||
@ -8,7 +8,11 @@ InputComponent::InputComponent()
|
|||||||
|
|
||||||
InputComponent::~InputComponent() = default;
|
InputComponent::~InputComponent() = default;
|
||||||
|
|
||||||
void InputComponent::init(){}
|
void InputComponent::init()
|
||||||
|
{
|
||||||
|
// m_keyStates = SDL_GetKeyboardState(NULL);
|
||||||
|
// InitKeyMappings();
|
||||||
|
}
|
||||||
|
|
||||||
void InputComponent::update()
|
void InputComponent::update()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -24,6 +24,17 @@ void Manager::refresh()
|
|||||||
}), std::end(v));
|
}), std::end(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto i(0u); i < MAX_TEAMS; i++)
|
||||||
|
{
|
||||||
|
auto& v(entitiesByTeam[i]);
|
||||||
|
v.erase(
|
||||||
|
std::remove_if(std::begin(v), std::end(v),
|
||||||
|
[i](Entity* mEntity)
|
||||||
|
{
|
||||||
|
return !mEntity->isActive() || (size_t)(mEntity->getTeam()) != i;
|
||||||
|
}), std::end(v));
|
||||||
|
}
|
||||||
|
|
||||||
entities.erase(std::remove_if(std::begin(entities), std::end(entities),
|
entities.erase(std::remove_if(std::begin(entities), std::end(entities),
|
||||||
[](const std::unique_ptr<Entity>& mEntity)
|
[](const std::unique_ptr<Entity>& mEntity)
|
||||||
{
|
{
|
||||||
@ -47,6 +58,16 @@ std::vector<Entity*>& Manager::getGroup(Group mGroup)
|
|||||||
return entitiesByGroup.at(mGroup);
|
return entitiesByGroup.at(mGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Manager::addToTeam(Entity* mEntity, Team mTeam)
|
||||||
|
{
|
||||||
|
entitiesByTeam.at(mTeam).emplace_back(mEntity); //
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Entity*>& Manager::getTeam(Team mTeam)
|
||||||
|
{
|
||||||
|
return entitiesByTeam.at(mTeam);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<Entity*> Manager::getAll()
|
std::vector<Entity*> Manager::getAll()
|
||||||
{
|
{
|
||||||
std::vector<Entity*> entity_vec;
|
std::vector<Entity*> entity_vec;
|
||||||
|
|||||||
85
src/PopupWindow.cpp
Normal file
85
src/PopupWindow.cpp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <SDL_image.h>
|
||||||
|
|
||||||
|
#include "Entity.h"
|
||||||
|
#include "PopupWindow.h"
|
||||||
|
#include "TextureManager.h"
|
||||||
|
#include "GameInternal.h"
|
||||||
|
|
||||||
|
PopupWindow::PopupWindow(const char* title, const std::string &message) :
|
||||||
|
continueGame(false), interacted(false) {
|
||||||
|
this->window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 400, 250, 0);
|
||||||
|
//font = TTF_OpenFont("assets/Trajan.ttf", 24); // Change the path and size as needed
|
||||||
|
|
||||||
|
this->renderer = SDL_CreateRenderer(window, -1, 0);
|
||||||
|
SDL_SetRenderDrawColor(this->renderer, 255, 255, 255, 255);
|
||||||
|
|
||||||
|
//SDL_Surface* surface = TTF_RenderText_Blended(font, message.c_str(), {255, 255, 255});
|
||||||
|
//texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||||
|
|
||||||
|
//SDL_FreeSurface(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
PopupWindow::~PopupWindow() {
|
||||||
|
SDL_DestroyTexture(this->texture);
|
||||||
|
SDL_DestroyRenderer(this->renderer);
|
||||||
|
SDL_DestroyWindow(this->window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupWindow::handleWinnerEvents() {
|
||||||
|
|
||||||
|
SDL_Event e;
|
||||||
|
|
||||||
|
while (SDL_PollEvent(&e))
|
||||||
|
{
|
||||||
|
if (e.type == SDL_QUIT)
|
||||||
|
{
|
||||||
|
continueGame = false;
|
||||||
|
interacted = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(e.type != SDL_KEYDOWN)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (e.key.keysym.sym) {
|
||||||
|
|
||||||
|
case SDLK_q: {
|
||||||
|
continueGame = false;
|
||||||
|
interacted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDLK_c: {
|
||||||
|
continueGame = true;
|
||||||
|
interacted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PopupWindow::shouldContinue() const {
|
||||||
|
return continueGame;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupWindow::renderWinnerPopup(Entity::TeamLabel winner) {
|
||||||
|
|
||||||
|
SDL_RenderClear(this->renderer);
|
||||||
|
|
||||||
|
//Maybe use texture manager (changes need to be made that it does not use game::renderer automatically, but receives one instead)
|
||||||
|
this->texture = winner == Entity::TeamLabel::BLUE ?
|
||||||
|
IMG_LoadTexture(this->renderer, "assets/Player1Victory.png") :
|
||||||
|
IMG_LoadTexture(this->renderer, "assets/Player2Victory.png");
|
||||||
|
|
||||||
|
SDL_RenderCopy(this->renderer, this->texture, NULL, NULL);
|
||||||
|
|
||||||
|
SDL_RenderPresent(this->renderer);
|
||||||
|
|
||||||
|
//Error handling for debugging
|
||||||
|
const char* sdlError = SDL_GetError();
|
||||||
|
if (*sdlError != '\0') {
|
||||||
|
std::cerr << "SDL Error: " << sdlError << std::endl;
|
||||||
|
SDL_ClearError();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -18,7 +18,9 @@ void PowerupComponent::update()
|
|||||||
if ((player = this->entity->getManager().getGame()->collisionHandler->getAnyIntersection<Entity*>(
|
if ((player = this->entity->getManager().getGame()->collisionHandler->getAnyIntersection<Entity*>(
|
||||||
entity,
|
entity,
|
||||||
Vector2D(0, 0),
|
Vector2D(0, 0),
|
||||||
{ Entity::GroupLabel::PLAYERS })) != nullptr)
|
{ Entity::GroupLabel::PLAYERS },
|
||||||
|
{},
|
||||||
|
true)) != nullptr)
|
||||||
{
|
{
|
||||||
(this->pickupFunc)(player);
|
(this->pickupFunc)(player);
|
||||||
this->entity->destroy();
|
this->entity->destroy();
|
||||||
|
|||||||
@ -36,7 +36,8 @@ void ProjectileComponent::update()
|
|||||||
entity,
|
entity,
|
||||||
Vector2D(0,0),
|
Vector2D(0,0),
|
||||||
{Entity::GroupLabel::PLAYERS},
|
{Entity::GroupLabel::PLAYERS},
|
||||||
{this->owner})) != nullptr) {
|
{entity->getTeam()},
|
||||||
|
true)) != nullptr) {
|
||||||
player->getComponent<HealthComponent>().modifyHealth();
|
player->getComponent<HealthComponent>().modifyHealth();
|
||||||
this->entity->destroy();
|
this->entity->destroy();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,7 +32,10 @@ SpriteComponent::SpriteComponent(
|
|||||||
this->texturePath = path;
|
this->texturePath = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpriteComponent::~SpriteComponent() {}
|
SpriteComponent::~SpriteComponent()
|
||||||
|
{
|
||||||
|
// SDL_DestroyTexture(this->texture);
|
||||||
|
}
|
||||||
|
|
||||||
void SpriteComponent::setTexture(const char* path)
|
void SpriteComponent::setTexture(const char* path)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -52,6 +52,8 @@ void TransformComponent::init()
|
|||||||
|
|
||||||
void TransformComponent::update()
|
void TransformComponent::update()
|
||||||
{
|
{
|
||||||
|
// if(velocity.x != 0 && velocity.y != 0)
|
||||||
|
|
||||||
float multiplier = direction.x != 0 && direction.y != 0 ? 0.707 : 1; // normalizes vector; only works if directions are in increments of 45°
|
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(
|
||||||
direction.x * this->getSpeed() * multiplier,
|
direction.x * this->getSpeed() * multiplier,
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include "Entity.h"
|
#include "Entity.h"
|
||||||
#include "GameInternal.h"
|
#include "GameInternal.h"
|
||||||
#include "Constants.h"
|
#include "Constants.h"
|
||||||
|
#include "PopupWindow.h"
|
||||||
|
|
||||||
GameInternal* game = nullptr;
|
GameInternal* game = nullptr;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user