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

unmanaged scenes first impl

This commit is contained in:
Benedikt Galbavy 2025-01-06 22:31:54 +01:00
parent 7c50c8d1fb
commit 0bfe720a4a
13 changed files with 376 additions and 125 deletions

View File

@ -24,8 +24,8 @@ public:
AssetManager(Manager* manager);
~AssetManager();
void createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, float speed, Textures textureEnum, Entity* owner);
void createPowerup(Vector2D pos, std::function<void (Entity*)> pickupFunc, Textures texture);
Entity* createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, float speed, Textures textureEnum, Entity* owner);
Entity* createPowerup(Vector2D pos, std::function<void (Entity*)> pickupFunc, Textures texture);
Vector2D calculateSpawnPosition();
PowerupType calculateType();

View File

@ -24,6 +24,7 @@ public:
void init() override;
void update(uint_fast16_t diffTime) override;
void removeCollision();
void addCollision();
void handleCollision(Vector2D& characterPos, SDL_Rect& characterCollider, SDL_Rect& componentCollider);
};

View File

@ -5,6 +5,8 @@
#include <bitset>
#include <vector>
#include "VEGO.h"
#include "ColliderComponent.h"
#include "ECS.h"
#include "Constants.h"
@ -64,12 +66,10 @@ public:
bool isActive() const { return this->active; } //!< \sa destroy()
//! Mark for destruction for Manager::refresh() and disables collision
//! \sa ColliderComponent
void destroy() {
this->active = false;
if (this->hasComponent<ColliderComponent>()) {
this->getComponent<ColliderComponent>().removeCollision();
}
}
void destroy();
//! Reactivate an entity and reenables collision
//! \sa ColliderComponent
void reactivate();
bool hasGroup(Group mGroup); //!< \sa GroupLabel
void addGroup(Group mGroup); //!< \sa GroupLabel

View File

@ -7,9 +7,10 @@
#include <vector>
#include "Constants.h"
#include "Entity.h"
class GameInternal;
class Entity;
/*!
*
* \brief Is responsible for managing all entities
@ -38,8 +39,14 @@ public:
GameInternal* getGame() { return this->game; };
std::shared_ptr<Entity> getShared(Entity* entity);
std::weak_ptr<Entity> getWeak(Entity* entity);
// this function is ugly af and should not be merged
void addExistingEntity(std::shared_ptr<Entity> entity);
private:
GameInternal* game;
std::vector<std::unique_ptr<Entity>> entities;
std::vector<std::shared_ptr<Entity>> entities;
std::array<std::vector<Entity*>, MAX_GROUPS> entitiesByGroup;
};

View File

@ -1,5 +1,6 @@
#pragma once
#include "Entity.h"
#include <functional>
#include <optional>
#include <string>
@ -22,6 +23,7 @@ public:
*/
Map(const char* path);
void generateTiles(); //!< Generates the map based on the loaded definition
void removeTiles(); //!< Removes all tiles previously generated
private:
// struct required for initialisation
struct MapData {
@ -42,10 +44,13 @@ private:
tmx::Map map;
Map::MapData mapData;
std::vector<std::function<void()>> tileConstructors;
std::vector<std::function<Entity*()>> tileConstructors;
std::vector<Entity*> tiles;
void loadTileLayer(const tmx::TileLayer& layer);
static void addTile(float x, float y, const tmx::Vector2u& mapTileSize, int u, int v, int zIndex, std::string texturePath, bool hasCollision);
// created tile is returned so it can be removed later
static Entity* addTile(float x, float y, const tmx::Vector2u& mapTileSize, int u, int v, int zIndex, std::string texturePath, bool hasCollision);
template<typename T>
static std::optional<T> getLayerProperty(const std::vector<tmx::Property>& properties, std::string propertyName) { return std::nullopt; };

63
include/Scene.h Normal file
View File

@ -0,0 +1,63 @@
#pragma once
#include "Entity.h"
#include "Map.h"
#include <functional>
#include <memory>
#include <vector>
class Scene {
public:
/**
* @brief Adds an Entity limited to the scene
* @details Adds an Entity, that is limited to the scene only. The entity will be destroyed with the seen, and should not be accessed afterward. For Entities that need to be reset to a specific position when loading a scene, use addInitFunc. Entities will respawn with the same parameters each time the scene is initialized.
* @param[in] entityDefinition Function to define the entity. The function will only be called when the scene will be initialized
*/
void addEntity(std::function<Entity*()> entityDefinition);
/**
* @brief Adds an Entity limited to this cycle of the scene
* @details Adds an Entity, that is limited to the scene only. The entity will be destroyed with the seen, and should not be accessed afterward. For Entities that need to be reset to a specific position when loading a scene, use addInitFunc. Entities will only spawn once.
* @param[in] entityDefinition Function to define the entity. The function will only be called when the scene will be initialized
*/
void addTemporaryEntity(std::function<Entity*()> entityDefinition);
/**
* @brief Adds a function to be executed on init of the scene.
*
* @param[in] initFunc The initialize function
*/
void addInitFunc(std::function<void()> initFunc);
/**
* @brief Adds a function to be executed on update of the scene.
*
* @param[in] updateFunc The update function
*/
void addUpdateFunc(std::function<void(uint_fast16_t diffTime)> updateFunc);
/**
* @brief Adds a function to be executed on reset of the scene.
*
* @param[in] resetFunc The reset function
*/
void addResetFunc(std::function<void()> resetFunc);
void addMap(Map* map);
void addMap(const char* path);
void init();
void update(uint_fast16_t diffTime);
void reset();
bool isActive() { return this->active; };
private:
std::vector<std::shared_ptr<Entity>> entities;
std::vector<std::weak_ptr<Entity>> tempEntities;
std::vector<std::function<Entity*()>> entityFuncs;
std::vector<std::function<Entity*()>> tempEntityFuncs;
std::vector<std::function<void()>> initFuncs;
std::vector<std::function<void(uint_fast16_t diffTime)>> updateFuncs;
std::vector<std::function<void()>> resetFuncs;
std::unique_ptr<Map> map_unique; // only used if map is constructed by scene
Map* map = nullptr;
bool active = false;
};

View File

@ -1,3 +1,5 @@
#pragma once
#include "GameInternal.h"
namespace vego {

View File

@ -41,7 +41,7 @@ Mix_Music* AssetManager::getMusic(std::string id)
return music.at(id);
}
void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, float speed, Textures textureEnum, Entity* owner) {
Entity* AssetManager::createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, float speed, Textures textureEnum, Entity* owner) {
auto& projectile(man->addEntity());
projectile.addComponent<TransformComponent>(pos.x, pos.y, 32, 32, scale); //32x32 is standard size for objects
@ -49,9 +49,11 @@ void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, int scale,
projectile.addComponent<ProjectileComponent>(range, speed, velocity, owner);
projectile.addComponent<ColliderComponent>("projectile", 0.6f);
projectile.addGroup((size_t)Entity::GroupLabel::PROJECTILE);
return &projectile;
}
void AssetManager::createPowerup(Vector2D pos, std::function<void (Entity*)> pickupFunc, Textures texture) {
Entity* AssetManager::createPowerup(Vector2D pos, std::function<void (Entity*)> pickupFunc, Textures texture) {
auto& powerups(man->addEntity());
powerups.addComponent<TransformComponent>(pos.x, pos.y, 32, 32, 1); //32x32 is standard size for objects
@ -66,6 +68,8 @@ void AssetManager::createPowerup(Vector2D pos, std::function<void (Entity*)> pic
powerups.addComponent<ColliderComponent>("powerup", 0.6f);
powerups.addComponent<PowerupComponent>(pickupFunc);
powerups.addGroup((size_t)Entity::GroupLabel::POWERUPS);
return &powerups;
}
Vector2D AssetManager::calculateSpawnPosition()

View File

@ -49,6 +49,11 @@ void ColliderComponent::removeCollision()
this->hasCollision = false;
}
void ColliderComponent::addCollision()
{
this->hasCollision = true;
}
void ColliderComponent::handleCollision(Vector2D& entityPos, SDL_Rect& entityCollider, SDL_Rect& componentCollider)
{
// collision to right of character

View File

@ -2,6 +2,9 @@
#include "Manager.h"
#include "Component.h"
#include "VEGO.h"
#include <cstddef>
void Entity::update(uint_fast16_t diffTime) const
@ -29,3 +32,23 @@ std::bitset<MAX_GROUPS> Entity::getGroupBitSet()
{
return groupBitSet;
}
void Entity::destroy() {
this->active = false;
if (this->hasComponent<ColliderComponent>()) {
this->getComponent<ColliderComponent>().removeCollision();
}
if (this->hasComponent<SpriteComponent>()) {
VEGO_Game().renderManager.remove(&this->getComponent<SpriteComponent>());
}
}
void Entity::reactivate() {
this->active = true;
if (this->hasComponent<ColliderComponent>()) {
this->getComponent<ColliderComponent>().addCollision();
}
if (this->hasComponent<SpriteComponent>()) {
VEGO_Game().renderManager.add(&this->getComponent<SpriteComponent>());
}
}

View File

@ -1,6 +1,10 @@
#include "Manager.h"
#include <algorithm>
#include <iterator>
#include <memory>
#include <numeric>
#include <ranges>
#include <vector>
#include "Constants.h"
@ -20,7 +24,7 @@ void Manager::refresh()
}
entities.erase(std::remove_if(std::begin(entities), std::end(entities),
[](const std::unique_ptr<Entity>& mEntity)
[](const std::shared_ptr<Entity>& mEntity)
{
return !mEntity->isActive();
}),
@ -54,7 +58,32 @@ std::vector<Entity*> Manager::getAll()
Entity& Manager::addEntity()
{
Entity* e = new Entity(*this);
std::unique_ptr<Entity> uPtr{ e };
entities.emplace_back(std::move(uPtr));
entities.emplace_back(e);
return *e;
}
void Manager::addExistingEntity(std::shared_ptr<Entity> entity)
{
entities.emplace_back(entity);
std::ranges::for_each(std::views::iota(0ul, MAX_GROUPS), [&entity, this](auto i) {
if (entity->hasGroup(i)) {
this->entitiesByGroup.at(i).emplace_back(entity.get());
}
});
}
std::shared_ptr<Entity> Manager::getShared(Entity* entity)
{
auto entityPtr = std::find_if(std::begin(entities), std::end(entities), [&entity](const auto& entityPtr) {
return entity == entityPtr.get();
});
return std::shared_ptr<Entity>(*entityPtr); // careful, error if find_if returns end
}
std::weak_ptr<Entity> Manager::getWeak(Entity* entity)
{
auto entityPtr = std::find_if(std::begin(entities), std::end(entities), [&entity](const auto& entityPtr) {
return entity == entityPtr.get();
});
return *entityPtr; // careful, error if find_if returns end
}

View File

@ -20,6 +20,7 @@
#include <tmxlite/Types.hpp>
#include "ColliderComponent.h"
#include "Entity.h"
#include "GameInternal.h"
#include "SpriteComponent.h"
#include "TextureManager.h"
@ -148,9 +149,9 @@ void Map::loadTileLayer(const tmx::TileLayer& layer)
const float tilePosY = (static_cast<float>(y) * this->mapData.mapTileSize->y);
// return tile data as a function to spawn said tile
return std::function<void()>(
return std::function<Entity*()>(
[tilePosX, tilePosY, capture0 = *this->mapData.mapTileSize, u, v, zIndex, capture1 = data.texturePath, collision] {
Map::addTile(tilePosX, tilePosY, capture0, u, v, zIndex, capture1, collision);
return Map::addTile(tilePosX, tilePosY, capture0, u, v, zIndex, capture1, collision);
}
);
});
@ -162,7 +163,7 @@ void Map::loadTileLayer(const tmx::TileLayer& layer)
this->tileConstructors.insert(this->tileConstructors.end(), tileConstructorRange.begin(), tileConstructorRange.end());
}
void Map::addTile(float x, float y, const tmx::Vector2u& mapTileSize, int u, int v, int zIndex, std::string texturePath, bool hasCollision)
Entity* Map::addTile(float x, float y, const tmx::Vector2u& mapTileSize, int u, int v, int zIndex, std::string texturePath, bool hasCollision)
{
auto& tile(VEGO_Game().manager.addEntity());
@ -175,11 +176,20 @@ void Map::addTile(float x, float y, const tmx::Vector2u& mapTileSize, int u, int
tile.addComponent<ColliderComponent>("hello I am a collider of a tile!");
tile.addGroup((size_t)Entity::GroupLabel::MAPTILES);
}
return &tile;
}
void Map::generateTiles()
{
std::ranges::for_each(this->tileConstructors, [](auto& function) {
function();
this->tiles = std::views::transform(this->tileConstructors, [](auto& function) {
return function();
}) | std::ranges::to<std::vector<Entity*>>();
}
void Map::removeTiles()
{
std::ranges::for_each(this->tiles, [](const auto& tile) {
tile->destroy();
});
}

102
src/Scene.cpp Normal file
View File

@ -0,0 +1,102 @@
#include "Scene.h"
#include "Entity.h"
#include "Map.h"
#include <algorithm>
#include <memory>
#include <ranges>
#include <vector>
#include <VEGO.h>
void Scene::addEntity(std::function<Entity*()> entityDefinition)
{
this->entityFuncs.push_back(entityDefinition);
if (this->active) {
this->entities.emplace_back(VEGO_Game().manager.getWeak(entityDefinition()));
}
}
void Scene::addTemporaryEntity(std::function<Entity*()> entityDefinition)
{
if (this->active) {
this->tempEntities.push_back(VEGO_Game().manager.getWeak(entityDefinition()));
return;
}
this->tempEntityFuncs.push_back(entityDefinition);
}
void Scene::addInitFunc(std::function<void()> initFunc)
{
this->initFuncs.push_back(initFunc);
}
void Scene::addUpdateFunc(std::function<void(uint_fast16_t diffTime)> updateFunc)
{
this->updateFuncs.push_back(updateFunc);
}
void Scene::addResetFunc(std::function<void()> resetFunc)
{
this->resetFuncs.push_back(resetFunc);
}
void Scene::init()
{
this->map->generateTiles();
std::ranges::for_each(this->initFuncs, [](const auto& func) {
func();
});
std::ranges::for_each(this->entities, [](auto entity) {
entity->reactivate();
VEGO_Game().manager.addExistingEntity(entity);
});
std::ranges::for_each(this->entityFuncs, [this](const auto& func) {
this->entities.emplace_back(VEGO_Game().manager.getShared(func()));
});
std::ranges::for_each(this->tempEntityFuncs, [this](const auto& func) {
this->tempEntities.emplace_back(VEGO_Game().manager.getWeak(func()));
});
this->active = true;
}
void Scene::update(uint_fast16_t diffTime)
{
std::ranges::for_each(this->updateFuncs, [diffTime](const auto& func) {
func(diffTime);
});
}
void Scene::reset()
{
this->active = false;
std::ranges::for_each(this->entities, [](const auto& entity) {
entity->destroy();
});
std::ranges::for_each(this->tempEntities, [](const auto& entity) {
if (!entity.expired())
entity.lock()->destroy();
});
this->tempEntities.clear();
std::ranges::for_each(this->resetFuncs, [](const auto& func) {
func();
});
if (this->map) {
this->map->removeTiles();
}
}
void Scene::addMap(Map* map)
{
this->map = map;
}
void Scene::addMap(const char* path)
{
this->map_unique = std::unique_ptr<Map>(new Map(path));
this->addMap(this->map_unique.get());
}