Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "Level.h"
- #include "ParticleLoader.h"
- #include "ParticleManager.h"
- CLevel::CLevel()
- {
- Initialize();
- }
- CLevel::CLevel(const std::string& levelFilename, CLevelLoader* levelLoader)
- {
- Initialize();
- // Sets the level loader.
- m_LevelLoader = levelLoader;
- LoadLevel(levelFilename, ELevelFileFormat::TMX);
- }
- CLevel::~CLevel()
- {
- delete m_LevelStats;
- delete m_LevelObjectStorage;
- }
- /*
- Sets the offset of the level.
- */
- void CLevel::SetLevelOffset(TVector2 offset)
- {
- m_LevelStats->m_LevelOffset = offset;
- }
- /*
- Returns the size of the level.
- */
- TVector2 CLevel::GetLevelSize()
- {
- return m_LevelStats->m_LevelSize;
- }
- /*
- Sets the size of the level.
- */
- void CLevel::SetLevelSize(TVector2 size)
- {
- m_LevelStats->m_LevelSize = size;
- }
- /*
- Returns the object storage of the level.
- */
- SLevelObjectStorage* CLevel::GetLevelObjectStorage()
- {
- return m_LevelObjectStorage;
- }
- /*
- Sets the debug state of the level.
- */
- void CLevel::SetDebugState(bool value)
- {
- m_LevelStats->m_DebugState = value;
- }
- /*
- Sets if the offset should be clamped to level borders. Used mainly for CutScenes.
- */
- void CLevel::SetOffsetClamp(bool value)
- {
- m_LevelStats->m_LevelOffsetClampEnabled = value;
- }
- /*
- Returns the offset of the level.
- */
- TVector2 CLevel::GetLevelOffset()
- {
- if (m_LevelStats->m_LevelOffsetClampEnabled)
- {
- TVector2 offset = TVector2(m_LevelStats->m_LevelOffset);
- // Clamps the level offset to the size of the level (adjusted with the size of the viewport).
- TVector2 levelMin((-(m_LevelStats->m_LevelSize)) + TVector2(CGameWindow::GetWindowViewport()->W / CRenderer::GetResolutionRenderScale().X, CGameWindow::GetWindowViewport()->H / CRenderer::GetResolutionRenderScale().Y));
- TVector2 levelMax(0, 0);
- offset.Clamp(levelMin, levelMax);
- return offset;
- }
- return m_LevelStats->m_LevelOffset;
- }
- /*
- Initializes the level.
- */
- void CLevel::Initialize()
- {
- m_LevelStats = new SLevelStats();
- m_LevelStats->m_LevelGridColor = TColor(TColor::White);
- m_LevelStats->m_LevelGridColor.A = 80;
- m_LevelParallaxStats = new SLevelParallaxStats();
- m_LevelObjectStorage = new SLevelObjectStorage();
- // Initializes the parallax scrolling elements.
- m_LevelParallaxStats->m_ParallaxSkyColor = TColor::SkyBlue;
- AddParallaxLayer(new SLevelParallax(m_LevelParallaxStats, "Background2Large.png", new SRect(0.0f, 0.0f, 2560.0f, 960.0f), 0.8f, 0.1f, -320, -100), 0);
- AddParallaxLayer(new SLevelParallax(m_LevelParallaxStats, "Background1Large.png", new SRect(0.0f, 0.0f, 2560.0f, 960.0f), 0.7f, 0.15f, -320, -250), 1);
- AddParallaxLayer(new SLevelParallax(m_LevelParallaxStats, "Background2Large.png", new SRect(0.0f, 0.0f, 2560.0f, 960.0f), 0.6f, 0.2f, -420, -50), 2);
- }
- /*
- Returns a BoundingBox from the object.
- */
- CBoundingBox* CLevel::ObjectToBoundingBox(CLevelObjectTMX* object)
- {
- return new CBoundingBox((float)object->GetX(), (float)object->GetY(), (float)object->GetWidth(), (float)object->GetHeight());
- }
- /*
- Adds an entity to the level.
- */
- void CLevel::AddEntity(CEntity* entity, DEntityStorageType storageType, int zModifier)
- {
- // Z is used for depth sorting in the entity sets.
- entity->SetZ(m_LevelStats->m_LevelLayerZ + zModifier);
- // Adds the entity's collision box to the level's collision boxes.
- if (storageType & COLLISION)
- {
- m_LevelObjectStorage->m_BoundingBoxes.push_back(entity->GetBoundingBox());
- }
- // Adds the entity to the static entities.
- if (storageType & STATIC)
- {
- m_LevelObjectStorage->m_StaticEntities.push_back(entity);
- }
- // Adds the entity to the dynamic entities.
- if (storageType & DYNAMIC)
- {
- m_LevelObjectStorage->m_DynamicEntities.push_back(entity);
- }
- // Adds the entity to the renderable entities.
- m_LevelObjectStorage->m_Entities.push_back(entity);
- entity->SpawnEntity(this);
- }
- /*
- Removes an entity from the level.
- */
- void CLevel::RemoveEntity(CEntity* entity)
- {
- entity->KillEntity(this);
- // Pushes the entity to an array, to clear all the entities at once after
- // the updating has been done.
- m_LevelObjectStorage->m_RemovedEntities.push_back(entity);
- }
- /*
- Adds a parallax layer to the level.
- */
- void CLevel::AddParallaxLayer(SLevelParallax* parallaxLayer, int z)
- {
- // Sets the Z of the layer.
- parallaxLayer->m_LayerZ = z;
- // Adds the layer.
- m_LevelParallaxStats->m_ParallaxLayers.push_back(parallaxLayer);
- // Sorts the layer by their Z value.
- std::sort(m_LevelParallaxStats->m_ParallaxLayers.begin(), m_LevelParallaxStats->m_ParallaxLayers.end(), SLevelParallaxSort());
- }
- /*
- Deletes and clears the entities that have been removed by RemoveEntity().
- */
- void CLevel::ClearRemovedEntities()
- {
- // If there's no entities to remove.
- if (m_LevelObjectStorage->m_RemovedEntities.size() == 0)
- {
- return;
- }
- // Loops over all entities to be removed.
- for (auto entity : m_LevelObjectStorage->m_RemovedEntities)
- {
- // Finds the locations for the entity in the entity containers.
- auto entityLocation = std::find(m_LevelObjectStorage->m_Entities.begin(), m_LevelObjectStorage->m_Entities.end(), entity);
- auto entityStaticLocation = std::find(m_LevelObjectStorage->m_StaticEntities.begin(), m_LevelObjectStorage->m_StaticEntities.end(), entity);
- auto entityDynamicLocation = std::find(m_LevelObjectStorage->m_DynamicEntities.begin(), m_LevelObjectStorage->m_DynamicEntities.end(), entity);
- // Removes the entity from the general entity list if it was found.
- if (!(entityLocation == m_LevelObjectStorage->m_Entities.end()))
- {
- m_LevelObjectStorage->m_Entities.erase(entityLocation);
- }
- // Removes the entity from the static entity list if it was found.
- if (!(entityStaticLocation == m_LevelObjectStorage->m_StaticEntities.end()))
- {
- m_LevelObjectStorage->m_StaticEntities.erase(entityStaticLocation);
- }
- // Removes the entity from the dynamic entity list if it was found.
- if (!(entityDynamicLocation == m_LevelObjectStorage->m_DynamicEntities.end()))
- {
- m_LevelObjectStorage->m_DynamicEntities.erase(entityDynamicLocation);
- }
- // Finds the location of the collision box of the entity if the entity has a bounding box.
- if (entity->GetBoundingBox())
- {
- auto collisionBoxLocation = std::find(m_LevelObjectStorage->m_BoundingBoxes.begin(), m_LevelObjectStorage->m_BoundingBoxes.end(), entity->GetBoundingBox());
- // Removes the collision box if it was found.
- if (!(collisionBoxLocation == m_LevelObjectStorage->m_BoundingBoxes.end()))
- {
- m_LevelObjectStorage->m_BoundingBoxes.erase(collisionBoxLocation);
- }
- }
- // Now the entity has been removed from all containers and will be deleted.
- // (Actually there is still a pointer to it in m_RemovedEntities, but it will
- // be cleared real soon)
- delete entity;
- }
- // Clears the list as all the entities are removed above.
- m_LevelObjectStorage->m_RemovedEntities.clear();
- }
- /*
- Sorts the entities in the object storage.
- */
- void CLevel::SortLevelObjectStorage()
- {
- // Sorts the entities.
- std::sort(m_LevelObjectStorage->m_Entities.begin(), m_LevelObjectStorage->m_Entities.end(), SEntitySort());
- // Sorts the static & dynamic entities. Sorting these is not necessary, so this can be a possible performance improvement.
- // TODO: Possibly disable sorting these.
- std::sort(m_LevelObjectStorage->m_StaticEntities.begin(), m_LevelObjectStorage->m_StaticEntities.end(), SEntitySort());
- std::sort(m_LevelObjectStorage->m_DynamicEntities.begin(), m_LevelObjectStorage->m_DynamicEntities.end(), SEntitySort());
- }
- /*
- Handles events and passes them to entities.
- */
- void CLevel::EventLevel(SDL_Event* event)
- {
- // Passes the events to the entities. Only dynamic entities receive events.
- for (auto entity : m_LevelObjectStorage->m_DynamicEntities)
- {
- entity->Event(event);
- }
- }
- /*
- Updates the entities in the level. Returns true if the level end trigger has been reached.
- */
- void CLevel::UpdateLevel(float deltaTime)
- {
- // Updates the entities.
- for (auto& entity : m_LevelObjectStorage->m_DynamicEntities)
- {
- entity->Update(deltaTime, this);
- }
- // After all the entities have been updated, updates the triggers.
- for (auto trigger : m_LevelObjectStorage->m_Triggers)
- {
- // If the condition on the trigger is met, the trigger is then executed.
- if (trigger->ConditionTrigger(this))
- {
- trigger->ExecuteTrigger(this);
- }
- }
- // Clears the entities that have been removed during the frame.
- ClearRemovedEntities();
- }
- /*
- Renders the entities in the level and the parallax background levels.
- */
- void CLevel::RenderLevel(CRenderer* renderer)
- {
- // Renders the sky.
- renderer->Clear(m_LevelParallaxStats->m_ParallaxSkyColor);
- // Calculates the center of the screen to "loop" the parallax layer.
- float wrapPosition = 320.0f;
- // Renders the parallax layers to the background.
- for (auto parallaxLayer : m_LevelParallaxStats->m_ParallaxLayers)
- {
- // Calculates the position of the parallax layer.
- TVector2 parallaxOffset = GetLevelOffset() * parallaxLayer->m_ParallaxFactor;
- // Wraps the layer (as they loop in parts).
- while (abs(parallaxOffset.X) >= wrapPosition)
- {
- if (parallaxOffset.X < 0)
- {
- parallaxOffset.X += wrapPosition;
- }
- else
- {
- parallaxOffset.X -= wrapPosition;
- }
- }
- // Renders the layer.
- renderer->SetRenderBatchOffset(parallaxOffset);
- renderer->Render(parallaxLayer->m_ParallaxRenderDescription);
- }
- // Renders various debug info if the debug mode is enabled.
- if (m_LevelStats->m_DebugState)
- {
- RenderLevelGrid(renderer);
- }
- renderer->SetRenderBatchOffset(GetLevelOffset());
- // Renders the entities.
- for (auto entity : m_LevelObjectStorage->m_Entities)
- {
- renderer->Render(entity->GetRenderDescription());
- }
- if (m_LevelStats->m_DebugState)
- {
- for (auto box : m_LevelObjectStorage->m_BoundingBoxes)
- {
- renderer->RenderBox(TColor::Red, box, false, true, true);
- }
- }
- // Resets the offset.
- renderer->SetRenderBatchOffset(TVector2());
- }
- /*
- Renders the debug grid of the level.
- */
- void CLevel::RenderLevelGrid(CRenderer* renderer)
- {
- // Sets the offset.
- renderer->SetRenderBatchOffset(GetLevelOffset());
- // Renders the grid.
- for (int y = 0; y < GetLevelSize().Y; y += m_LevelStats->m_LevelTileSize)
- {
- for (int x = 0; x < GetLevelSize().X; x += m_LevelStats->m_LevelTileSize)
- {
- renderer->RenderBox(m_LevelStats->m_LevelGridColor, (float)x, (float)y, (float)m_LevelStats->m_LevelTileSize, (float)m_LevelStats->m_LevelTileSize);
- }
- }
- renderer->SetRenderBatchOffset(TVector2());
- }
- /*
- Loads the level.
- */
- void CLevel::LoadLevel(const std::string& levelFileName, ELevelFileFormat levelFileFormat)
- {
- m_LevelStats->m_LevelFileName = levelFileName;
- // Loads the level with the given format.
- switch (levelFileFormat)
- {
- // Loads .TMX files.
- case ELevelFileFormat::TMX:
- {
- // Creates a level loader for the TMX data format.
- CLevelLoaderTMX* levelLoader = new CLevelLoaderTMX(levelFileName);
- // Loads the tilesets.
- for (auto tileset : levelLoader->GetTilesets())
- {
- LoadTileset(tileset);
- }
- // Checks if the amount of layers is too big. This should never happen,
- // but you never know... This is to ensure that overlaid entities
- // are always overlaid.
- if (levelLoader->GetLayers().size() > MAX_LAYER_COUNT)
- {
- GPrint("Max Layer Amount exceeded in file: ", levelFileName);
- }
- // Loads the layers.
- for (auto layer : levelLoader->GetLayers())
- {
- // Only loads visible layers.
- if (layer->GetLayerVisible())
- {
- LoadLayer(layer);
- }
- }
- // Loads the object groups.
- for (auto objectGroup : levelLoader->GetObjectGroups())
- {
- LoadObjectGroup(objectGroup);
- }
- // Sorts the entities.
- SortLevelObjectStorage();
- // Marks the level as loaded.
- m_LevelStats->m_LevelLoaded = true;
- break;
- }
- default:
- break;
- }
- }
- /*
- Loads a layer.
- */
- void CLevel::LoadLayer(CLevelLayerTMX* layer)
- {
- // Initializes the level size if it's not calculated yet.
- if (m_LevelStats->m_LevelSize == TVector2())
- {
- m_LevelStats->m_LevelSize = TVector2(layer->GetLayerWidth(), layer->GetLayerHeight()) * (float)m_LevelStats->m_LevelTileSize;
- }
- // Tiles on the "EntityOverlay" layer should be drawn on top of everything.
- int layerAddition = layer->GetLayerName() == "EngineOverlay" ? MAX_LAYER_COUNT : 0;
- // Loads the layer data.
- for (auto tile : layer->GetLevelTileData())
- {
- // Calculates the position for the tile.
- float xTilePos = (float)tile->GetX() * (float)m_LevelStats->m_LevelTileSize;
- float yTilePos = (float)tile->GetY() * (float)m_LevelStats->m_LevelTileSize;
- // Creates the tile entity.
- CEntityTile* tileEntity = new CEntityTile(tile->GetTileID(), xTilePos, yTilePos);
- // Adds the entity.
- AddEntity(tileEntity, STATIC_NOCOLLISION, layerAddition);
- }
- // Increments the Z Count to render the entities in the correct order.
- m_LevelStats->m_LevelLayerZ++;
- }
- /*
- Loads a tileset and sets it to the tileset that all the tiles in the game will use.
- This is not foolproof, as if a level that uses a different tileset is loaded after
- this tileset, the tileset the tile uses is overridden.
- */
- void CLevel::LoadTileset(CLevelTilesetTMX* tileset)
- {
- // Loads the spritesheet.
- CSpriteSheet* tileSpriteSheet = CContentLoader::LoadSpriteSheet(tileset->GetTilesetSourcePath(), tileset->GetTileWidth(), tileset->GetTileHeight());
- // Sets the spritesheet for the tiles.
- CEntityTile::SetSpriteSheet(tileSpriteSheet);
- // Sets the tile size.
- // TODO: Doesn't support non-square tiles.
- m_LevelStats->m_LevelTileSize = tileset->GetTileWidth();
- }
- /*
- Loads an object group.
- */
- void CLevel::LoadObjectGroup(CLevelObjectGroupTMX* objectGroup)
- {
- // These names are used from the engine, and unless a use that they offer is wanted
- // the names should be avoided
- bool triggerGroup = (objectGroup->GetObjectGroupName() == "EngineTrigger");
- bool collisionGroup = (objectGroup->GetObjectGroupName() == "EngineCollision");
- // Loads the objects in the object group.
- for (auto object : objectGroup->GetObjectGroupObjectData())
- {
- // Adds triggers to the level. Triggers define different areas that can be checked against and then
- // different modifiers and methods can be executed.
- if (triggerGroup)
- {
- m_LevelObjectStorage->m_Triggers.push_back(new CTrigger(ObjectToBoundingBox(object), object->GetName()));
- }
- // Adds collision boxes to the level. These boxes are drawn in the level editor to allow
- // basically tessellation of small collision boxes into bigger ones..
- else if (collisionGroup)
- {
- m_LevelObjectStorage->m_BoundingBoxes.push_back(ObjectToBoundingBox(object));
- }
- // Passes all objects to the level loader (if one exists).
- if (m_LevelLoader)
- {
- // Loads the entity.
- m_LevelLoader->LoadEntity(this, object, objectGroup);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment