treballant en sistema de portes i claus
This commit is contained in:
@@ -69,6 +69,8 @@ set(APP_SOURCES
|
|||||||
source/game/entities/enemy.cpp
|
source/game/entities/enemy.cpp
|
||||||
source/game/entities/path_enemy.cpp
|
source/game/entities/path_enemy.cpp
|
||||||
source/game/entities/item.cpp
|
source/game/entities/item.cpp
|
||||||
|
source/game/entities/key.cpp
|
||||||
|
source/game/entities/door.cpp
|
||||||
source/game/entities/moving_platform.cpp
|
source/game/entities/moving_platform.cpp
|
||||||
source/game/entities/player.cpp
|
source/game/entities/player.cpp
|
||||||
|
|
||||||
@@ -81,8 +83,13 @@ set(APP_SOURCES
|
|||||||
source/game/gameplay/tile_collider.cpp
|
source/game/gameplay/tile_collider.cpp
|
||||||
source/game/gameplay/enemy_manager.cpp
|
source/game/gameplay/enemy_manager.cpp
|
||||||
source/game/gameplay/item_manager.cpp
|
source/game/gameplay/item_manager.cpp
|
||||||
|
source/game/gameplay/key_manager.cpp
|
||||||
|
source/game/gameplay/door_manager.cpp
|
||||||
source/game/gameplay/platform_manager.cpp
|
source/game/gameplay/platform_manager.cpp
|
||||||
source/game/gameplay/item_tracker.cpp
|
source/game/gameplay/item_tracker.cpp
|
||||||
|
source/game/gameplay/key_tracker.cpp
|
||||||
|
source/game/gameplay/door_tracker.cpp
|
||||||
|
source/game/gameplay/inventory.cpp
|
||||||
source/game/gameplay/room_loader.cpp
|
source/game/gameplay/room_loader.cpp
|
||||||
source/game/gameplay/room_tracker.cpp
|
source/game/gameplay/room_tracker.cpp
|
||||||
source/game/gameplay/room.cpp
|
source/game/gameplay/room.cpp
|
||||||
|
|||||||
@@ -218,6 +218,20 @@ assets:
|
|||||||
BITMAP:
|
BITMAP:
|
||||||
- ${PREFIX}/data/items/items.gif
|
- ${PREFIX}/data/items/items.gif
|
||||||
|
|
||||||
|
# KEYS
|
||||||
|
keys:
|
||||||
|
ANIMATION:
|
||||||
|
- ${PREFIX}/data/keys/key1.yaml
|
||||||
|
BITMAP:
|
||||||
|
- ${PREFIX}/data/keys/key1.gif
|
||||||
|
|
||||||
|
# DOORS
|
||||||
|
doors:
|
||||||
|
ANIMATION:
|
||||||
|
- ${PREFIX}/data/doors/door1.yaml
|
||||||
|
BITMAP:
|
||||||
|
- ${PREFIX}/data/doors/door1.gif
|
||||||
|
|
||||||
# MUSIC
|
# MUSIC
|
||||||
music:
|
music:
|
||||||
MUSIC:
|
MUSIC:
|
||||||
|
|||||||
BIN
data/doors/door1.gif
Normal file
BIN
data/doors/door1.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 501 B |
16
data/doors/door1.yaml
Normal file
16
data/doors/door1.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# door1 animation
|
||||||
|
tileSetFile: door1.gif
|
||||||
|
frameWidth: 8
|
||||||
|
frameHeight: 32
|
||||||
|
|
||||||
|
animations:
|
||||||
|
- name: closed
|
||||||
|
frames: [0]
|
||||||
|
|
||||||
|
- name: opening
|
||||||
|
speed: 0.08
|
||||||
|
loopFrom: -1
|
||||||
|
frames: [1, 2, 3, 4, 5, 6, 7, 8]
|
||||||
|
|
||||||
|
- name: opened
|
||||||
|
frames: [9]
|
||||||
BIN
data/keys/key1.gif
Normal file
BIN
data/keys/key1.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 281 B |
8
data/keys/key1.yaml
Normal file
8
data/keys/key1.yaml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# key1 animation
|
||||||
|
tileSetFile: key1.gif
|
||||||
|
frameWidth: 16
|
||||||
|
frameHeight: 16
|
||||||
|
|
||||||
|
animations:
|
||||||
|
- name: default
|
||||||
|
frames: [0]
|
||||||
@@ -27,13 +27,13 @@ tilemap:
|
|||||||
- [169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169]
|
- [169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169]
|
||||||
- [169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 33, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
- [169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 33, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
||||||
- [169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
- [169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
||||||
- [33, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, 116, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
- [33, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, 169, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
||||||
- [33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 116, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
- [33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 169, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
||||||
- [33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 116, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
- [33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 169, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
||||||
- [7, 7, 7, 7, 7, 7, 7, 7, 8, -1, -1, -1, -1, -1, -1, -1, 116, 137, 138, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
- [7, 7, 7, 7, 7, 7, 7, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
||||||
- [33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 116, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
- [33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
||||||
- [33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 116, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
- [33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
||||||
- [33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 116, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
- [33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
||||||
- [7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 534, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
- [7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 534, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
||||||
- [26, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 186, 534, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
- [26, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 186, 534, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
||||||
- [26, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 186, 186, 534, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
- [26, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 186, 186, 534, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
||||||
@@ -53,13 +53,19 @@ tilemap:
|
|||||||
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
- [1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
- [1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
- [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
- [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 3, 0, 0, 0, 0, 0, 0]
|
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 3, 0, 0, 0, 0, 0, 0]
|
||||||
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 3, 0, 0, 0, 0, 0]
|
- [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 3, 0, 0, 0, 0, 0]
|
||||||
- [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
|
- [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
|
||||||
|
|
||||||
|
# Puertas en esta habitación
|
||||||
|
doors:
|
||||||
|
- animation: door1.yaml
|
||||||
|
id: "1"
|
||||||
|
position: {x: 16, y: 11}
|
||||||
@@ -84,3 +84,9 @@ items:
|
|||||||
position: {x: 13, y: 11}
|
position: {x: 13, y: 11}
|
||||||
counter: 1
|
counter: 1
|
||||||
|
|
||||||
|
# Llaves en esta habitación
|
||||||
|
keys:
|
||||||
|
- animation: key1.yaml
|
||||||
|
id: "1"
|
||||||
|
position: {x: 15, y: 13}
|
||||||
|
|
||||||
|
|||||||
@@ -912,19 +912,27 @@ auto MapEditor::pointInRect(float px, float py, const SDL_FRect& rect) -> bool {
|
|||||||
|
|
||||||
auto MapEditor::entityCount(EntityType type) const -> int {
|
auto MapEditor::entityCount(EntityType type) const -> int {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EntityType::ENEMY: return room_->getEnemyManager()->getCount();
|
case EntityType::ENEMY:
|
||||||
case EntityType::ITEM: return room_->getItemManager()->getCount();
|
return room_->getEnemyManager()->getCount();
|
||||||
case EntityType::PLATFORM: return room_->getPlatformManager()->getCount();
|
case EntityType::ITEM:
|
||||||
default: return 0;
|
return room_->getItemManager()->getCount();
|
||||||
|
case EntityType::PLATFORM:
|
||||||
|
return room_->getPlatformManager()->getCount();
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto MapEditor::entityRect(EntityType type, int index) -> SDL_FRect {
|
auto MapEditor::entityRect(EntityType type, int index) -> SDL_FRect {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EntityType::ENEMY: return room_->getEnemyManager()->getEnemy(index)->getRect();
|
case EntityType::ENEMY:
|
||||||
case EntityType::ITEM: return room_->getItemManager()->getItem(index)->getCollider();
|
return room_->getEnemyManager()->getEnemy(index)->getRect();
|
||||||
case EntityType::PLATFORM: return room_->getPlatformManager()->getPlatform(index)->getRect();
|
case EntityType::ITEM:
|
||||||
default: return {};
|
return room_->getItemManager()->getItem(index)->getCollider();
|
||||||
|
case EntityType::PLATFORM:
|
||||||
|
return room_->getPlatformManager()->getPlatform(index)->getRect();
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -938,37 +946,49 @@ auto MapEditor::entityBoundaries(EntityType type, int index) const -> BoundaryDa
|
|||||||
const auto& e = room_data_.enemies[index];
|
const auto& e = room_data_.enemies[index];
|
||||||
return {e.x1, e.y1, e.x2, e.y2};
|
return {e.x1, e.y1, e.x2, e.y2};
|
||||||
}
|
}
|
||||||
default: return {};
|
default:
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto MapEditor::entityPosition(EntityType type, int index) const -> std::pair<float, float> {
|
auto MapEditor::entityPosition(EntityType type, int index) const -> std::pair<float, float> {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EntityType::ENEMY: return {room_data_.enemies[index].x, room_data_.enemies[index].y};
|
case EntityType::ENEMY:
|
||||||
case EntityType::ITEM: return {room_data_.items[index].x, room_data_.items[index].y};
|
return {room_data_.enemies[index].x, room_data_.enemies[index].y};
|
||||||
|
case EntityType::ITEM:
|
||||||
|
return {room_data_.items[index].x, room_data_.items[index].y};
|
||||||
case EntityType::PLATFORM: {
|
case EntityType::PLATFORM: {
|
||||||
const auto& path = room_data_.platforms[index].path;
|
const auto& path = room_data_.platforms[index].path;
|
||||||
return path.empty() ? std::pair{0.0F, 0.0F} : std::pair{path[0].x, path[0].y};
|
return path.empty() ? std::pair{0.0F, 0.0F} : std::pair{path[0].x, path[0].y};
|
||||||
}
|
}
|
||||||
default: return {0.0F, 0.0F};
|
default:
|
||||||
|
return {0.0F, 0.0F};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto MapEditor::entityDataCount(EntityType type) const -> int {
|
auto MapEditor::entityDataCount(EntityType type) const -> int {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EntityType::ENEMY: return static_cast<int>(room_data_.enemies.size());
|
case EntityType::ENEMY:
|
||||||
case EntityType::ITEM: return static_cast<int>(room_data_.items.size());
|
return static_cast<int>(room_data_.enemies.size());
|
||||||
case EntityType::PLATFORM: return static_cast<int>(room_data_.platforms.size());
|
case EntityType::ITEM:
|
||||||
default: return 0;
|
return static_cast<int>(room_data_.items.size());
|
||||||
|
case EntityType::PLATFORM:
|
||||||
|
return static_cast<int>(room_data_.platforms.size());
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto MapEditor::entityLabel(EntityType type) -> const char* {
|
auto MapEditor::entityLabel(EntityType type) -> const char* {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EntityType::ENEMY: return "enemy";
|
case EntityType::ENEMY:
|
||||||
case EntityType::ITEM: return "item";
|
return "enemy";
|
||||||
case EntityType::PLATFORM: return "platform";
|
case EntityType::ITEM:
|
||||||
default: return "none";
|
return "item";
|
||||||
|
case EntityType::PLATFORM:
|
||||||
|
return "platform";
|
||||||
|
default:
|
||||||
|
return "none";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1226,10 +1246,14 @@ void MapEditor::updateStatusBarInfo() { // NOLINT(readability-function-cognitiv
|
|||||||
// Devuelve las propiedades válidas de SET según la selección actual
|
// Devuelve las propiedades válidas de SET según la selección actual
|
||||||
auto MapEditor::getSetCompletions() const -> std::vector<std::string> {
|
auto MapEditor::getSetCompletions() const -> std::vector<std::string> {
|
||||||
switch (selection_.type) {
|
switch (selection_.type) {
|
||||||
case EntityType::ENEMY: return {"ANIMATION", "VX", "VY", "FLIP", "MIRROR"};
|
case EntityType::ENEMY:
|
||||||
case EntityType::ITEM: return {"TILE", "COUNTER"};
|
return {"ANIMATION", "VX", "VY", "FLIP", "MIRROR"};
|
||||||
case EntityType::PLATFORM: return {"ANIMATION", "SPEED", "LOOP", "EASING"};
|
case EntityType::ITEM:
|
||||||
default: return {"ITEMCOLOR1", "ITEMCOLOR2", "CONVEYOR", "TILESET", "UP", "DOWN", "LEFT", "RIGHT"};
|
return {"TILE", "COUNTER"};
|
||||||
|
case EntityType::PLATFORM:
|
||||||
|
return {"ANIMATION", "SPEED", "LOOP", "EASING"};
|
||||||
|
default:
|
||||||
|
return {"ITEMCOLOR1", "ITEMCOLOR2", "CONVEYOR", "TILESET", "UP", "DOWN", "LEFT", "RIGHT"};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1935,8 +1959,7 @@ auto MapEditor::addPlatform() -> std::string {
|
|||||||
constexpr float ROUTE_HALF = 2.0F * Tile::SIZE;
|
constexpr float ROUTE_HALF = 2.0F * Tile::SIZE;
|
||||||
new_platform.path = {
|
new_platform.path = {
|
||||||
{CENTER_X - ROUTE_HALF, CENTER_Y, 0.0F},
|
{CENTER_X - ROUTE_HALF, CENTER_Y, 0.0F},
|
||||||
{CENTER_X + ROUTE_HALF, CENTER_Y, 0.0F}
|
{CENTER_X + ROUTE_HALF, CENTER_Y, 0.0F}};
|
||||||
};
|
|
||||||
|
|
||||||
room_data_.platforms.push_back(new_platform);
|
room_data_.platforms.push_back(new_platform);
|
||||||
room_->getPlatformManager()->addPlatform(std::make_shared<MovingPlatform>(new_platform));
|
room_->getPlatformManager()->addPlatform(std::make_shared<MovingPlatform>(new_platform));
|
||||||
|
|||||||
@@ -21,13 +21,19 @@
|
|||||||
class EditorStatusBar;
|
class EditorStatusBar;
|
||||||
|
|
||||||
// Tipo de entidad editable en el editor
|
// Tipo de entidad editable en el editor
|
||||||
enum class EntityType { NONE, ENEMY, ITEM, PLATFORM };
|
enum class EntityType { NONE,
|
||||||
|
ENEMY,
|
||||||
|
ITEM,
|
||||||
|
PLATFORM };
|
||||||
|
|
||||||
// Seleccion unificada: una sola entidad seleccionada a la vez
|
// Seleccion unificada: una sola entidad seleccionada a la vez
|
||||||
struct Selection {
|
struct Selection {
|
||||||
EntityType type{EntityType::NONE};
|
EntityType type{EntityType::NONE};
|
||||||
int index{-1};
|
int index{-1};
|
||||||
void clear() { type = EntityType::NONE; index = -1; }
|
void clear() {
|
||||||
|
type = EntityType::NONE;
|
||||||
|
index = -1;
|
||||||
|
}
|
||||||
[[nodiscard]] auto isNone() const -> bool { return type == EntityType::NONE; }
|
[[nodiscard]] auto isNone() const -> bool { return type == EntityType::NONE; }
|
||||||
[[nodiscard]] auto is(EntityType t) const -> bool { return type == t && index >= 0; }
|
[[nodiscard]] auto is(EntityType t) const -> bool { return type == t && index >= 0; }
|
||||||
};
|
};
|
||||||
@@ -140,7 +146,9 @@ class MapEditor {
|
|||||||
static auto pointInRect(float px, float py, const SDL_FRect& rect) -> bool;
|
static auto pointInRect(float px, float py, const SDL_FRect& rect) -> bool;
|
||||||
|
|
||||||
// Entity helpers: acceso abstracto a datos de entidad por tipo
|
// Entity helpers: acceso abstracto a datos de entidad por tipo
|
||||||
struct BoundaryData { int x1, y1, x2, y2; };
|
struct BoundaryData {
|
||||||
|
int x1, y1, x2, y2;
|
||||||
|
};
|
||||||
auto entityCount(EntityType type) const -> int;
|
auto entityCount(EntityType type) const -> int;
|
||||||
auto entityRect(EntityType type, int index) -> SDL_FRect;
|
auto entityRect(EntityType type, int index) -> SDL_FRect;
|
||||||
static auto entityHasBoundaries(EntityType type) -> bool;
|
static auto entityHasBoundaries(EntityType type) -> bool;
|
||||||
|
|||||||
65
source/game/entities/door.cpp
Normal file
65
source/game/entities/door.cpp
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#include "game/entities/door.hpp"
|
||||||
|
|
||||||
|
#include "core/rendering/sprite/animated_sprite.hpp" // Para AnimatedSprite
|
||||||
|
#include "core/resources/resource_cache.hpp" // Para Resource
|
||||||
|
|
||||||
|
// Constructor: carga la animación y posiciona la puerta. Si start_opened es
|
||||||
|
// true, la puerta se crea ya abierta (estado OPENED, animación "opened"); en
|
||||||
|
// caso contrario, se crea cerrada (estado CLOSED, animación "closed").
|
||||||
|
Door::Door(const Data& data, bool start_opened)
|
||||||
|
: sprite_(std::make_shared<AnimatedSprite>(Resource::Cache::get()->getAnimationData(data.animation_path))),
|
||||||
|
id_(data.id),
|
||||||
|
state_(start_opened ? State::OPENED : State::CLOSED) {
|
||||||
|
sprite_->setPosX(data.x);
|
||||||
|
sprite_->setPosY(data.y);
|
||||||
|
sprite_->setCurrentAnimation(start_opened ? "opened" : "closed");
|
||||||
|
collider_ = sprite_->getRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pinta la puerta en pantalla
|
||||||
|
void Door::render() {
|
||||||
|
sprite_->render();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avanza la animación. Solo OPENING anima de verdad; CLOSED y OPENED son
|
||||||
|
// frames estáticos. Cuando la animación de OPENING termina, transiciona a
|
||||||
|
// OPENED, fija el frame final y marca just_opened_ para que el DoorManager
|
||||||
|
// libere los tiles de colisión.
|
||||||
|
void Door::update(float delta_time) {
|
||||||
|
if (is_paused_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state_ == State::OPENING) {
|
||||||
|
sprite_->animate(delta_time);
|
||||||
|
if (sprite_->animationIsCompleted()) {
|
||||||
|
state_ = State::OPENED;
|
||||||
|
sprite_->setCurrentAnimation("opened");
|
||||||
|
just_opened_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Posición actual (para registrar el estado abierto en DoorTracker)
|
||||||
|
auto Door::getPos() const -> SDL_FPoint {
|
||||||
|
return SDL_FPoint{.x = sprite_->getX(), .y = sprite_->getY()};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transición CLOSED → OPENING: cambia el estado y arranca la animación de apertura
|
||||||
|
void Door::startOpening() {
|
||||||
|
if (state_ != State::CLOSED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state_ = State::OPENING;
|
||||||
|
sprite_->setCurrentAnimation("opening");
|
||||||
|
sprite_->resetAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flag one-shot: devuelve true exactamente una vez después de transicionar a OPENED
|
||||||
|
auto Door::justOpened() -> bool {
|
||||||
|
if (just_opened_) {
|
||||||
|
just_opened_ = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
62
source/game/entities/door.hpp
Normal file
62
source/game/entities/door.hpp
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#include <memory> // Para shared_ptr
|
||||||
|
#include <string> // Para string
|
||||||
|
|
||||||
|
class AnimatedSprite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Puerta que actúa como muro hasta que se abre con la llave correcta
|
||||||
|
*
|
||||||
|
* Entidad de 8x32 px (1 columna × 4 filas de tiles) con tres animaciones:
|
||||||
|
* - "closed": estado inicial bloqueante (frame estático)
|
||||||
|
* - "opening": animación de transición que se reproduce una sola vez
|
||||||
|
* - "opened": estado final no bloqueante (frame estático)
|
||||||
|
*
|
||||||
|
* El comportamiento de "muro" se implementa marcando los 4 tiles que ocupa
|
||||||
|
* la puerta como WALL en el CollisionMap (lo gestiona el DoorManager). Cuando
|
||||||
|
* la puerta termina de abrirse, los tiles vuelven a EMPTY y el jugador puede
|
||||||
|
* pasar.
|
||||||
|
*/
|
||||||
|
class Door {
|
||||||
|
public:
|
||||||
|
enum class State : int {
|
||||||
|
CLOSED = 0,
|
||||||
|
OPENING = 1,
|
||||||
|
OPENED = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Data {
|
||||||
|
std::string animation_path; // Ruta al fichero de animación (ej. "door1.yaml")
|
||||||
|
std::string id; // Identificador que coincide con el id de la llave que la abre
|
||||||
|
float x{0.0F}; // Posición X en píxeles (alineada al grid de 8 px)
|
||||||
|
float y{0.0F}; // Posición Y en píxeles (alineada al grid de 8 px)
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit Door(const Data& data, bool start_opened);
|
||||||
|
~Door() = default;
|
||||||
|
|
||||||
|
void render(); // Pinta la puerta en pantalla
|
||||||
|
void update(float delta_time); // Avanza la animación; si OPENING termina → OPENED
|
||||||
|
|
||||||
|
auto getCollider() -> SDL_FRect& { return collider_; } // Rectángulo de colisión (8x32)
|
||||||
|
[[nodiscard]] auto getPos() const -> SDL_FPoint; // Posición en píxeles
|
||||||
|
[[nodiscard]] auto getId() const -> const std::string& { return id_; } // Identificador
|
||||||
|
[[nodiscard]] auto getState() const -> State { return state_; } // Estado actual
|
||||||
|
[[nodiscard]] auto isBlocking() const -> bool { return state_ != State::OPENED; } // True si bloquea al jugador
|
||||||
|
|
||||||
|
void startOpening(); // Transición CLOSED → OPENING
|
||||||
|
auto justOpened() -> bool; // Flag one-shot consumido por el manager
|
||||||
|
|
||||||
|
void setPaused(bool paused) { is_paused_ = paused; } // Pausa/despausa la animación
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<AnimatedSprite> sprite_; // Sprite animado de la puerta
|
||||||
|
SDL_FRect collider_{}; // Rectángulo de colisión
|
||||||
|
std::string id_; // Identificador
|
||||||
|
State state_{State::CLOSED}; // Estado actual
|
||||||
|
bool just_opened_{false}; // Flag one-shot: la puerta acaba de transicionar a OPENED
|
||||||
|
bool is_paused_{false}; // Indica si la puerta está pausada
|
||||||
|
};
|
||||||
32
source/game/entities/key.cpp
Normal file
32
source/game/entities/key.cpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#include "game/entities/key.hpp"
|
||||||
|
|
||||||
|
#include "core/rendering/sprite/animated_sprite.hpp" // Para AnimatedSprite
|
||||||
|
#include "core/resources/resource_cache.hpp" // Para Resource
|
||||||
|
|
||||||
|
// Constructor: carga la animación, posiciona el sprite y crea el collider
|
||||||
|
Key::Key(const Data& data)
|
||||||
|
: sprite_(std::make_shared<AnimatedSprite>(Resource::Cache::get()->getAnimationData(data.animation_path))),
|
||||||
|
id_(data.id) {
|
||||||
|
sprite_->setPosX(data.x);
|
||||||
|
sprite_->setPosY(data.y);
|
||||||
|
sprite_->setCurrentAnimation("default");
|
||||||
|
collider_ = sprite_->getRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pinta la llave en pantalla
|
||||||
|
void Key::render() {
|
||||||
|
sprite_->render();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avanza la animación de la llave
|
||||||
|
void Key::update(float delta_time) {
|
||||||
|
if (is_paused_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sprite_->animate(delta_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Posición actual (para registrar pickup en KeyTracker)
|
||||||
|
auto Key::getPos() const -> SDL_FPoint {
|
||||||
|
return SDL_FPoint{.x = sprite_->getX(), .y = sprite_->getY()};
|
||||||
|
}
|
||||||
44
source/game/entities/key.hpp
Normal file
44
source/game/entities/key.hpp
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#include <memory> // Para shared_ptr
|
||||||
|
#include <string> // Para string
|
||||||
|
|
||||||
|
class AnimatedSprite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Llave coleccionable
|
||||||
|
*
|
||||||
|
* Entidad de 16x16 px con una animación "default". Al ser recogida por el
|
||||||
|
* jugador, su identificador (id_) se añade al Inventory global y la llave
|
||||||
|
* desaparece de la habitación. Una llave puede abrir todas las puertas con
|
||||||
|
* el mismo id; no se consume al usarse.
|
||||||
|
*/
|
||||||
|
class Key {
|
||||||
|
public:
|
||||||
|
struct Data {
|
||||||
|
std::string animation_path; // Ruta al fichero de animación (ej. "key1.yaml")
|
||||||
|
std::string id; // Identificador que abre las puertas con el mismo id
|
||||||
|
float x{0.0F}; // Posición X en píxeles
|
||||||
|
float y{0.0F}; // Posición Y en píxeles
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit Key(const Data& data);
|
||||||
|
~Key() = default;
|
||||||
|
|
||||||
|
void render(); // Pinta la llave en pantalla
|
||||||
|
void update(float delta_time); // Avanza la animación
|
||||||
|
|
||||||
|
auto getCollider() -> SDL_FRect& { return collider_; } // Rectángulo de colisión
|
||||||
|
[[nodiscard]] auto getPos() const -> SDL_FPoint; // Posición actual (para tracker)
|
||||||
|
[[nodiscard]] auto getId() const -> const std::string& { return id_; } // Identificador de la llave
|
||||||
|
|
||||||
|
void setPaused(bool paused) { is_paused_ = paused; } // Pausa/despausa la animación
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<AnimatedSprite> sprite_; // Sprite animado de la llave
|
||||||
|
SDL_FRect collider_{}; // Rectángulo de colisión
|
||||||
|
std::string id_; // Identificador
|
||||||
|
bool is_paused_{false}; // Indica si la llave está pausada
|
||||||
|
};
|
||||||
@@ -16,7 +16,8 @@ struct Waypoint {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Modo de recorrido de la ruta
|
// Modo de recorrido de la ruta
|
||||||
enum class LoopMode { PINGPONG, CIRCULAR };
|
enum class LoopMode { PINGPONG,
|
||||||
|
CIRCULAR };
|
||||||
|
|
||||||
// Tipo de función de easing
|
// Tipo de función de easing
|
||||||
using EasingFunc = float (*)(float);
|
using EasingFunc = float (*)(float);
|
||||||
|
|||||||
@@ -25,9 +25,12 @@ void CollisionMap::buildExtendedCenter() {
|
|||||||
|
|
||||||
// Copia una región rectangular de src (MW×MH) al mapa extendido
|
// Copia una región rectangular de src (MW×MH) al mapa extendido
|
||||||
void CollisionMap::copyRegion(const std::vector<int>& src,
|
void CollisionMap::copyRegion(const std::vector<int>& src,
|
||||||
int src_col, int src_row,
|
int src_col,
|
||||||
int dst_col, int dst_row,
|
int src_row,
|
||||||
int cols, int rows) {
|
int dst_col,
|
||||||
|
int dst_row,
|
||||||
|
int cols,
|
||||||
|
int rows) {
|
||||||
for (int r = 0; r < rows; ++r) {
|
for (int r = 0; r < rows; ++r) {
|
||||||
for (int c = 0; c < cols; ++c) {
|
for (int c = 0; c < cols; ++c) {
|
||||||
extended_tile_map_[((dst_row + r) * EW) + (dst_col + c)] =
|
extended_tile_map_[((dst_row + r) * EW) + (dst_col + c)] =
|
||||||
@@ -78,7 +81,6 @@ void CollisionMap::updateBorders(const AdjacentData& adj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
void CollisionMap::setCollisionTile(int index, int value) {
|
void CollisionMap::setCollisionTile(int index, int value) {
|
||||||
if (index >= 0 && index < static_cast<int>(collision_tile_map_.size())) {
|
if (index >= 0 && index < static_cast<int>(collision_tile_map_.size())) {
|
||||||
collision_tile_map_[index] = value;
|
collision_tile_map_[index] = value;
|
||||||
@@ -88,4 +90,3 @@ void CollisionMap::setCollisionTile(int index, int value) {
|
|||||||
extended_tile_map_[((row + B) * EW) + (col + B)] = value;
|
extended_tile_map_[((row + B) * EW) + (col + B)] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -43,8 +43,11 @@ class CollisionMap {
|
|||||||
[[nodiscard]] auto getConveyorBeltDirection() const -> int { return conveyor_belt_direction_; }
|
[[nodiscard]] auto getConveyorBeltDirection() const -> int { return conveyor_belt_direction_; }
|
||||||
[[nodiscard]] auto getCollisionTileMap() const -> const std::vector<int>& { return collision_tile_map_; }
|
[[nodiscard]] auto getCollisionTileMap() const -> const std::vector<int>& { return collision_tile_map_; }
|
||||||
|
|
||||||
#ifdef _DEBUG
|
// Modifica un tile del mapa de colisiones (original + extendido) en runtime.
|
||||||
|
// Lo usan: el editor de mapas (debug) y el DoorManager para mostrar/ocultar muros de puertas.
|
||||||
void setCollisionTile(int index, int value);
|
void setCollisionTile(int index, int value);
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
void setConveyorBeltDirection(int direction) { conveyor_belt_direction_ = direction; }
|
void setConveyorBeltDirection(int direction) { conveyor_belt_direction_ = direction; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -65,7 +68,10 @@ class CollisionMap {
|
|||||||
|
|
||||||
// Copia una región rectangular de un tilemap fuente (MW×MH) al mapa extendido.
|
// Copia una región rectangular de un tilemap fuente (MW×MH) al mapa extendido.
|
||||||
void copyRegion(const std::vector<int>& src,
|
void copyRegion(const std::vector<int>& src,
|
||||||
int src_col, int src_row,
|
int src_col,
|
||||||
int dst_col, int dst_row,
|
int src_row,
|
||||||
int cols, int rows);
|
int dst_col,
|
||||||
|
int dst_row,
|
||||||
|
int cols,
|
||||||
|
int rows);
|
||||||
};
|
};
|
||||||
|
|||||||
92
source/game/gameplay/door_manager.cpp
Normal file
92
source/game/gameplay/door_manager.cpp
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#include "door_manager.hpp"
|
||||||
|
|
||||||
|
#include <utility> // Para std::move
|
||||||
|
|
||||||
|
#include "game/entities/door.hpp" // Para Door
|
||||||
|
#include "game/gameplay/collision_map.hpp" // Para CollisionMap
|
||||||
|
#include "game/gameplay/door_tracker.hpp" // Para DoorTracker
|
||||||
|
#include "game/gameplay/inventory.hpp" // Para Inventory
|
||||||
|
#include "game/gameplay/tile_collider.hpp" // Para TileCollider::Tile
|
||||||
|
#include "utils/defines.hpp" // Para Map::WIDTH, Tile::SIZE
|
||||||
|
#include "utils/utils.hpp" // Para checkCollision
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
DoorManager::DoorManager(std::string room_id, CollisionMap* collision_map)
|
||||||
|
: room_id_(std::move(room_id)),
|
||||||
|
collision_map_(collision_map) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Añade una puerta. Si está bloqueante (CLOSED), pinta sus 4 tiles como WALL
|
||||||
|
// en el CollisionMap. Si ya está OPENED (porque venía persistida del
|
||||||
|
// DoorTracker), no se tocan los tiles.
|
||||||
|
void DoorManager::addDoor(std::shared_ptr<Door> door) { // NOLINT(readability-identifier-naming)
|
||||||
|
if (door->isBlocking()) {
|
||||||
|
writeDoorTiles(*door, static_cast<int>(TileCollider::Tile::WALL));
|
||||||
|
}
|
||||||
|
doors_.push_back(std::move(door));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Elimina todas las puertas
|
||||||
|
void DoorManager::clear() {
|
||||||
|
doors_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actualiza animaciones y procesa transiciones a OPENED
|
||||||
|
void DoorManager::update(float delta_time) {
|
||||||
|
for (const auto& door : doors_) {
|
||||||
|
door->update(delta_time);
|
||||||
|
|
||||||
|
// Si la puerta acaba de transicionar a OPENED, liberar los tiles y persistir
|
||||||
|
if (door->justOpened()) {
|
||||||
|
writeDoorTiles(*door, static_cast<int>(TileCollider::Tile::EMPTY));
|
||||||
|
DoorTracker::get()->addDoor(room_id_, door->getPos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renderiza todas las puertas
|
||||||
|
void DoorManager::render() {
|
||||||
|
for (const auto& door : doors_) {
|
||||||
|
door->render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pausa/despausa todas las puertas
|
||||||
|
void DoorManager::setPaused(bool paused) {
|
||||||
|
for (const auto& door : doors_) {
|
||||||
|
door->setPaused(paused);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intenta abrir las puertas cercanas al jugador
|
||||||
|
void DoorManager::tryUnlock(const SDL_FRect& player_rect) {
|
||||||
|
// Infla el rect del jugador 1 px en cada lado para detectar contacto
|
||||||
|
const SDL_FRect INFLATED = {
|
||||||
|
.x = player_rect.x - 1.0F,
|
||||||
|
.y = player_rect.y - 1.0F,
|
||||||
|
.w = player_rect.w + 2.0F,
|
||||||
|
.h = player_rect.h + 2.0F,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto& door : doors_) {
|
||||||
|
if (door->getState() != Door::State::CLOSED) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (::checkCollision(INFLATED, door->getCollider()) && Inventory::get()->hasKey(door->getId())) {
|
||||||
|
door->startOpening();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setea las 4 celdas que ocupa la puerta (1 col × 4 filas) al valor indicado
|
||||||
|
void DoorManager::writeDoorTiles(const Door& door, int tile_value) {
|
||||||
|
// Convertir posición en píxeles a coordenadas de tile
|
||||||
|
const SDL_FPoint POS = door.getPos();
|
||||||
|
const int COL = static_cast<int>(POS.x) / Tile::SIZE;
|
||||||
|
const int ROW = static_cast<int>(POS.y) / Tile::SIZE;
|
||||||
|
|
||||||
|
for (int i = 0; i < DOOR_TILES_HEIGHT; ++i) {
|
||||||
|
const int INDEX = ((ROW + i) * Map::WIDTH) + COL;
|
||||||
|
collision_map_->setCollisionTile(INDEX, tile_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
69
source/game/gameplay/door_manager.hpp
Normal file
69
source/game/gameplay/door_manager.hpp
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#include <memory> // Para shared_ptr
|
||||||
|
#include <string> // Para string
|
||||||
|
#include <vector> // Para vector
|
||||||
|
|
||||||
|
#include "game/entities/door.hpp" // Para Door, Door::Data
|
||||||
|
|
||||||
|
class CollisionMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gestor de puertas de una habitación
|
||||||
|
*
|
||||||
|
* Responsabilidades:
|
||||||
|
* - Almacenar y gestionar la colección de puertas
|
||||||
|
* - Actualizar y renderizar todas las puertas
|
||||||
|
* - Detectar contacto del jugador con puertas cerradas y disparar la apertura
|
||||||
|
* si tiene la llave correspondiente (consultando el Inventory global)
|
||||||
|
* - Sincronizar el estado bloqueante con el CollisionMap: cuando una puerta
|
||||||
|
* está CLOSED u OPENING, sus 4 tiles son WALL; cuando pasa a OPENED, se
|
||||||
|
* ponen a EMPTY
|
||||||
|
* - Persistir el estado abierto en DoorTracker
|
||||||
|
*/
|
||||||
|
class DoorManager {
|
||||||
|
public:
|
||||||
|
DoorManager(std::string room_id, CollisionMap* collision_map);
|
||||||
|
~DoorManager() = default;
|
||||||
|
|
||||||
|
// Prohibir copia y movimiento para evitar duplicación accidental
|
||||||
|
DoorManager(const DoorManager&) = delete;
|
||||||
|
auto operator=(const DoorManager&) -> DoorManager& = delete;
|
||||||
|
DoorManager(DoorManager&&) = delete;
|
||||||
|
auto operator=(DoorManager&&) -> DoorManager& = delete;
|
||||||
|
|
||||||
|
// Gestión de puertas
|
||||||
|
void addDoor(std::shared_ptr<Door> door); // Añade una puerta y aplica WALLs si está cerrada
|
||||||
|
void clear(); // Elimina todas las puertas
|
||||||
|
|
||||||
|
// Actualización y renderizado
|
||||||
|
void update(float delta_time); // Actualiza animaciones y procesa transiciones a OPENED
|
||||||
|
void render(); // Renderiza todas las puertas
|
||||||
|
|
||||||
|
// Estado
|
||||||
|
void setPaused(bool paused); // Pausa/despausa todas las puertas
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Intenta abrir las puertas cercanas al jugador si tiene la llave
|
||||||
|
*
|
||||||
|
* Infla el rectángulo del jugador en 1 px para detectar contacto
|
||||||
|
* (las puertas cerradas son muros sólidos, así que el jugador queda
|
||||||
|
* adyacente sin solapar). Para cada puerta CLOSED que solape el rect
|
||||||
|
* inflado, si el Inventory contiene la llave correspondiente, llama a
|
||||||
|
* door->startOpening().
|
||||||
|
*
|
||||||
|
* @param player_rect Rectángulo de colisión del jugador
|
||||||
|
*/
|
||||||
|
void tryUnlock(const SDL_FRect& player_rect);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr int DOOR_TILES_HEIGHT = 4; // Una puerta ocupa 4 tiles verticalmente
|
||||||
|
|
||||||
|
void writeDoorTiles(const Door& door, int tile_value); // Setea las 4 celdas en el CollisionMap
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<Door>> doors_; // Colección de puertas
|
||||||
|
std::string room_id_; // Identificador de la habitación
|
||||||
|
CollisionMap* collision_map_; // Referencia no propietaria al CollisionMap de la Room
|
||||||
|
};
|
||||||
74
source/game/gameplay/door_tracker.cpp
Normal file
74
source/game/gameplay/door_tracker.cpp
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include "game/gameplay/door_tracker.hpp"
|
||||||
|
|
||||||
|
// [SINGLETON]
|
||||||
|
DoorTracker* DoorTracker::door_tracker = nullptr;
|
||||||
|
|
||||||
|
// [SINGLETON] Crearemos el objeto con esta función estática
|
||||||
|
void DoorTracker::init() {
|
||||||
|
DoorTracker::door_tracker = new DoorTracker();
|
||||||
|
}
|
||||||
|
|
||||||
|
// [SINGLETON] Destruiremos el objeto con esta función estática
|
||||||
|
void DoorTracker::destroy() {
|
||||||
|
delete DoorTracker::door_tracker;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||||
|
auto DoorTracker::get() -> DoorTracker* {
|
||||||
|
return DoorTracker::door_tracker;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comprueba si la puerta ya está abierta
|
||||||
|
auto DoorTracker::hasBeenOpened(const std::string& name, SDL_FPoint pos) -> bool {
|
||||||
|
if (const int INDEX = findByName(name); INDEX != NOT_FOUND) {
|
||||||
|
if (findByPos(INDEX, pos) != NOT_FOUND) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marca la puerta como abierta
|
||||||
|
void DoorTracker::addDoor(const std::string& name, SDL_FPoint pos) {
|
||||||
|
if (!hasBeenOpened(name, pos)) {
|
||||||
|
if (const int INDEX = findByName(name); INDEX != NOT_FOUND) {
|
||||||
|
doors_.at(INDEX).pos.push_back(pos);
|
||||||
|
} else {
|
||||||
|
doors_.emplace_back(name, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vacía el tracker
|
||||||
|
void DoorTracker::clear() {
|
||||||
|
doors_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Busca una entrada en la lista por nombre
|
||||||
|
auto DoorTracker::findByName(const std::string& name) -> int {
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (const auto& door : doors_) {
|
||||||
|
if (door.name == name) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Busca una entrada en la lista por posición
|
||||||
|
auto DoorTracker::findByPos(int index, SDL_FPoint pos) -> int {
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (const auto& door : doors_[index].pos) {
|
||||||
|
if ((door.x == pos.x) && (door.y == pos.y)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NOT_FOUND;
|
||||||
|
}
|
||||||
58
source/game/gameplay/door_tracker.hpp
Normal file
58
source/game/gameplay/door_tracker.hpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#include <string> // Para string, basic_string
|
||||||
|
#include <utility>
|
||||||
|
#include <vector> // Para vector
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tracker global de puertas abiertas (singleton)
|
||||||
|
*
|
||||||
|
* Mantiene un registro por habitación de las posiciones de las puertas que
|
||||||
|
* ya han sido abiertas, de modo que al volver a entrar a una habitación las
|
||||||
|
* puertas ya abiertas se reconstruyen directamente en estado OPENED.
|
||||||
|
* Mismo patrón que ItemTracker.
|
||||||
|
*/
|
||||||
|
class DoorTracker {
|
||||||
|
public:
|
||||||
|
// Gestión singleton
|
||||||
|
static void init(); // Inicialización
|
||||||
|
static void destroy(); // Destrucción
|
||||||
|
static auto get() -> DoorTracker*; // Acceso al singleton
|
||||||
|
|
||||||
|
// Gestión de puertas abiertas
|
||||||
|
auto hasBeenOpened(const std::string& name, SDL_FPoint pos) -> bool; // Comprueba si la puerta ya está abierta
|
||||||
|
void addDoor(const std::string& name, SDL_FPoint pos); // Marca la puerta como abierta
|
||||||
|
void clear(); // Vacía el tracker (reset de partida)
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Tipos anidados privados
|
||||||
|
struct Data {
|
||||||
|
std::string name; // Nombre de la habitación
|
||||||
|
std::vector<SDL_FPoint> pos; // Lista de posiciones de puertas abiertas
|
||||||
|
|
||||||
|
// Constructor para facilitar creación con posición inicial
|
||||||
|
Data(std::string name, const SDL_FPoint& position)
|
||||||
|
: name(std::move(name)) {
|
||||||
|
pos.push_back(position);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constantes privadas
|
||||||
|
static constexpr int NOT_FOUND = -1; // Valor de retorno cuando no se encuentra un elemento
|
||||||
|
|
||||||
|
// Constantes singleton
|
||||||
|
static DoorTracker* door_tracker; // [SINGLETON] Objeto privado
|
||||||
|
|
||||||
|
// Métodos privados
|
||||||
|
auto findByName(const std::string& name) -> int; // Busca una entrada en la lista por nombre
|
||||||
|
auto findByPos(int index, SDL_FPoint pos) -> int; // Busca una entrada en la lista por posición
|
||||||
|
|
||||||
|
// Constructor y destructor privados [SINGLETON]
|
||||||
|
DoorTracker() = default;
|
||||||
|
~DoorTracker() = default;
|
||||||
|
|
||||||
|
// Variables miembro
|
||||||
|
std::vector<Data> doors_; // Lista de puertas abiertas por habitación
|
||||||
|
};
|
||||||
34
source/game/gameplay/inventory.cpp
Normal file
34
source/game/gameplay/inventory.cpp
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#include "game/gameplay/inventory.hpp"
|
||||||
|
|
||||||
|
// [SINGLETON]
|
||||||
|
Inventory* Inventory::inventory = nullptr;
|
||||||
|
|
||||||
|
// [SINGLETON] Crearemos el objeto con esta función estática
|
||||||
|
void Inventory::init() {
|
||||||
|
Inventory::inventory = new Inventory();
|
||||||
|
}
|
||||||
|
|
||||||
|
// [SINGLETON] Destruiremos el objeto con esta función estática
|
||||||
|
void Inventory::destroy() {
|
||||||
|
delete Inventory::inventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||||
|
auto Inventory::get() -> Inventory* {
|
||||||
|
return Inventory::inventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Añade una llave al inventario
|
||||||
|
void Inventory::addKey(const std::string& key_id) {
|
||||||
|
keys_.insert(key_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comprueba si el inventario contiene una llave
|
||||||
|
auto Inventory::hasKey(const std::string& key_id) const -> bool {
|
||||||
|
return keys_.contains(key_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vacía el inventario
|
||||||
|
void Inventory::clear() {
|
||||||
|
keys_.clear();
|
||||||
|
}
|
||||||
34
source/game/gameplay/inventory.hpp
Normal file
34
source/game/gameplay/inventory.hpp
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <set> // Para set
|
||||||
|
#include <string> // Para string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Inventario global del jugador (singleton)
|
||||||
|
*
|
||||||
|
* Mantiene el conjunto de identificadores de llaves recogidas durante la partida.
|
||||||
|
* Persiste entre habitaciones y entre muertes (igual que ItemTracker).
|
||||||
|
*/
|
||||||
|
class Inventory {
|
||||||
|
public:
|
||||||
|
// Gestión singleton
|
||||||
|
static void init(); // Inicialización
|
||||||
|
static void destroy(); // Destrucción
|
||||||
|
static auto get() -> Inventory*; // Acceso al singleton
|
||||||
|
|
||||||
|
// Gestión de llaves
|
||||||
|
void addKey(const std::string& key_id); // Añade una llave al inventario
|
||||||
|
[[nodiscard]] auto hasKey(const std::string& key_id) const -> bool; // Comprueba si tiene una llave
|
||||||
|
void clear(); // Vacía el inventario (reset de partida)
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Constantes singleton
|
||||||
|
static Inventory* inventory; // [SINGLETON] Objeto privado
|
||||||
|
|
||||||
|
// Constructor y destructor privados [SINGLETON]
|
||||||
|
Inventory() = default;
|
||||||
|
~Inventory() = default;
|
||||||
|
|
||||||
|
// Variables miembro
|
||||||
|
std::set<std::string> keys_; // Conjunto de identificadores de llaves recogidas
|
||||||
|
};
|
||||||
69
source/game/gameplay/key_manager.cpp
Normal file
69
source/game/gameplay/key_manager.cpp
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#include "key_manager.hpp"
|
||||||
|
|
||||||
|
#include <utility> // Para std::move
|
||||||
|
|
||||||
|
#include "core/audio/audio.hpp" // Para Audio
|
||||||
|
#include "game/defaults.hpp" // Para Defaults::Sound::Files
|
||||||
|
#include "game/entities/key.hpp" // Para Key
|
||||||
|
#include "game/gameplay/inventory.hpp" // Para Inventory
|
||||||
|
#include "game/gameplay/key_tracker.hpp" // Para KeyTracker
|
||||||
|
#include "utils/utils.hpp" // Para checkCollision
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
KeyManager::KeyManager(std::string room_id)
|
||||||
|
: room_id_(std::move(room_id)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Añade una llave a la colección
|
||||||
|
void KeyManager::addKey(std::shared_ptr<Key> key) { // NOLINT(readability-identifier-naming)
|
||||||
|
keys_.push_back(std::move(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Elimina todas las llaves
|
||||||
|
void KeyManager::clear() {
|
||||||
|
keys_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actualiza todas las llaves
|
||||||
|
void KeyManager::update(float delta_time) {
|
||||||
|
for (const auto& key : keys_) {
|
||||||
|
key->update(delta_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renderiza todas las llaves
|
||||||
|
void KeyManager::render() {
|
||||||
|
for (const auto& key : keys_) {
|
||||||
|
key->render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pausa/despausa todas las llaves
|
||||||
|
void KeyManager::setPaused(bool paused) {
|
||||||
|
for (const auto& key : keys_) {
|
||||||
|
key->setPaused(paused);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comprueba si hay colisión con alguna llave
|
||||||
|
auto KeyManager::checkCollision(SDL_FRect& rect) -> bool {
|
||||||
|
for (int i = 0; i < static_cast<int>(keys_.size()); ++i) {
|
||||||
|
if (::checkCollision(rect, keys_.at(i)->getCollider())) {
|
||||||
|
// Añade el id de la llave al Inventory global
|
||||||
|
Inventory::get()->addKey(keys_.at(i)->getId());
|
||||||
|
|
||||||
|
// Registra la posición en KeyTracker (para no respawnear)
|
||||||
|
KeyTracker::get()->addKey(room_id_, keys_.at(i)->getPos());
|
||||||
|
|
||||||
|
// Elimina la llave de la colección
|
||||||
|
keys_.erase(keys_.begin() + i);
|
||||||
|
|
||||||
|
// Reproduce el sonido de pickup (reutiliza el sonido de item)
|
||||||
|
Audio::get()->playSound(Defaults::Sound::Files::ITEM, Audio::Group::GAME);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
59
source/game/gameplay/key_manager.hpp
Normal file
59
source/game/gameplay/key_manager.hpp
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#include <memory> // Para shared_ptr
|
||||||
|
#include <string> // Para string
|
||||||
|
#include <vector> // Para vector
|
||||||
|
|
||||||
|
#include "game/entities/key.hpp" // Para Key, Key::Data
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gestor de llaves de una habitación
|
||||||
|
*
|
||||||
|
* Responsabilidades:
|
||||||
|
* - Almacenar y gestionar la colección de llaves
|
||||||
|
* - Actualizar y renderizar todas las llaves
|
||||||
|
* - Detectar colisiones con el jugador y gestionar pickup
|
||||||
|
* - Integración con Inventory (singleton global) y KeyTracker (persistencia por room)
|
||||||
|
*/
|
||||||
|
class KeyManager {
|
||||||
|
public:
|
||||||
|
explicit KeyManager(std::string room_id);
|
||||||
|
~KeyManager() = default;
|
||||||
|
|
||||||
|
// Prohibir copia y movimiento para evitar duplicación accidental
|
||||||
|
KeyManager(const KeyManager&) = delete;
|
||||||
|
auto operator=(const KeyManager&) -> KeyManager& = delete;
|
||||||
|
KeyManager(KeyManager&&) = delete;
|
||||||
|
auto operator=(KeyManager&&) -> KeyManager& = delete;
|
||||||
|
|
||||||
|
// Gestión de llaves
|
||||||
|
void addKey(std::shared_ptr<Key> key); // Añade una llave a la colección
|
||||||
|
void clear(); // Elimina todas las llaves
|
||||||
|
|
||||||
|
// Actualización y renderizado
|
||||||
|
void update(float delta_time); // Actualiza todas las llaves
|
||||||
|
void render(); // Renderiza todas las llaves
|
||||||
|
|
||||||
|
// Estado
|
||||||
|
void setPaused(bool paused); // Pausa/despausa todas las llaves
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Comprueba si hay colisión con alguna llave
|
||||||
|
*
|
||||||
|
* Si hay colisión:
|
||||||
|
* - Añade el id de la llave al Inventory global
|
||||||
|
* - Registra la posición en KeyTracker (para no respawnear)
|
||||||
|
* - Elimina la llave de la colección
|
||||||
|
* - Reproduce el sonido de pickup
|
||||||
|
*
|
||||||
|
* @param rect Rectángulo de colisión
|
||||||
|
* @return true si hubo colisión, false en caso contrario
|
||||||
|
*/
|
||||||
|
auto checkCollision(SDL_FRect& rect) -> bool;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::shared_ptr<Key>> keys_; // Colección de llaves
|
||||||
|
std::string room_id_; // Identificador de la habitación
|
||||||
|
};
|
||||||
74
source/game/gameplay/key_tracker.cpp
Normal file
74
source/game/gameplay/key_tracker.cpp
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include "game/gameplay/key_tracker.hpp"
|
||||||
|
|
||||||
|
// [SINGLETON]
|
||||||
|
KeyTracker* KeyTracker::key_tracker = nullptr;
|
||||||
|
|
||||||
|
// [SINGLETON] Crearemos el objeto con esta función estática
|
||||||
|
void KeyTracker::init() {
|
||||||
|
KeyTracker::key_tracker = new KeyTracker();
|
||||||
|
}
|
||||||
|
|
||||||
|
// [SINGLETON] Destruiremos el objeto con esta función estática
|
||||||
|
void KeyTracker::destroy() {
|
||||||
|
delete KeyTracker::key_tracker;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||||
|
auto KeyTracker::get() -> KeyTracker* {
|
||||||
|
return KeyTracker::key_tracker;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comprueba si la llave ya ha sido cogida
|
||||||
|
auto KeyTracker::hasBeenPicked(const std::string& name, SDL_FPoint pos) -> bool {
|
||||||
|
if (const int INDEX = findByName(name); INDEX != NOT_FOUND) {
|
||||||
|
if (findByPos(INDEX, pos) != NOT_FOUND) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Añade la llave a la lista de llaves recogidas
|
||||||
|
void KeyTracker::addKey(const std::string& name, SDL_FPoint pos) {
|
||||||
|
if (!hasBeenPicked(name, pos)) {
|
||||||
|
if (const int INDEX = findByName(name); INDEX != NOT_FOUND) {
|
||||||
|
keys_.at(INDEX).pos.push_back(pos);
|
||||||
|
} else {
|
||||||
|
keys_.emplace_back(name, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vacía el tracker
|
||||||
|
void KeyTracker::clear() {
|
||||||
|
keys_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Busca una entrada en la lista por nombre
|
||||||
|
auto KeyTracker::findByName(const std::string& name) -> int {
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (const auto& key : keys_) {
|
||||||
|
if (key.name == name) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Busca una entrada en la lista por posición
|
||||||
|
auto KeyTracker::findByPos(int index, SDL_FPoint pos) -> int {
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (const auto& key : keys_[index].pos) {
|
||||||
|
if ((key.x == pos.x) && (key.y == pos.y)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NOT_FOUND;
|
||||||
|
}
|
||||||
57
source/game/gameplay/key_tracker.hpp
Normal file
57
source/game/gameplay/key_tracker.hpp
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#include <string> // Para string, basic_string
|
||||||
|
#include <utility>
|
||||||
|
#include <vector> // Para vector
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tracker global de llaves recogidas (singleton)
|
||||||
|
*
|
||||||
|
* Mantiene un registro por habitación de las posiciones de las llaves recogidas,
|
||||||
|
* de modo que al volver a entrar a una habitación las llaves ya cogidas no
|
||||||
|
* vuelvan a aparecer. Mismo patrón que ItemTracker.
|
||||||
|
*/
|
||||||
|
class KeyTracker {
|
||||||
|
public:
|
||||||
|
// Gestión singleton
|
||||||
|
static void init(); // Inicialización
|
||||||
|
static void destroy(); // Destrucción
|
||||||
|
static auto get() -> KeyTracker*; // Acceso al singleton
|
||||||
|
|
||||||
|
// Gestión de llaves recogidas
|
||||||
|
auto hasBeenPicked(const std::string& name, SDL_FPoint pos) -> bool; // Comprueba si la llave ya ha sido cogida
|
||||||
|
void addKey(const std::string& name, SDL_FPoint pos); // Añade la llave a la lista
|
||||||
|
void clear(); // Vacía el tracker (reset de partida)
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Tipos anidados privados
|
||||||
|
struct Data {
|
||||||
|
std::string name; // Nombre de la habitación
|
||||||
|
std::vector<SDL_FPoint> pos; // Lista de posiciones de llaves cogidas
|
||||||
|
|
||||||
|
// Constructor para facilitar creación con posición inicial
|
||||||
|
Data(std::string name, const SDL_FPoint& position)
|
||||||
|
: name(std::move(name)) {
|
||||||
|
pos.push_back(position);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constantes privadas
|
||||||
|
static constexpr int NOT_FOUND = -1; // Valor de retorno cuando no se encuentra un elemento
|
||||||
|
|
||||||
|
// Constantes singleton
|
||||||
|
static KeyTracker* key_tracker; // [SINGLETON] Objeto privado
|
||||||
|
|
||||||
|
// Métodos privados
|
||||||
|
auto findByName(const std::string& name) -> int; // Busca una entrada en la lista por nombre
|
||||||
|
auto findByPos(int index, SDL_FPoint pos) -> int; // Busca una entrada en la lista por posición
|
||||||
|
|
||||||
|
// Constructor y destructor privados [SINGLETON]
|
||||||
|
KeyTracker() = default;
|
||||||
|
~KeyTracker() = default;
|
||||||
|
|
||||||
|
// Variables miembro
|
||||||
|
std::vector<Data> keys_; // Lista de llaves recogidas por habitación
|
||||||
|
};
|
||||||
@@ -6,9 +6,13 @@
|
|||||||
#include "core/resources/resource_cache.hpp" // Para Resource
|
#include "core/resources/resource_cache.hpp" // Para Resource
|
||||||
#include "game/defaults.hpp" // Para Defaults::Game
|
#include "game/defaults.hpp" // Para Defaults::Game
|
||||||
#include "game/gameplay/collision_map.hpp" // Para CollisionMap
|
#include "game/gameplay/collision_map.hpp" // Para CollisionMap
|
||||||
|
#include "game/gameplay/door_manager.hpp" // Para DoorManager
|
||||||
|
#include "game/gameplay/door_tracker.hpp" // Para DoorTracker
|
||||||
#include "game/gameplay/enemy_manager.hpp" // Para EnemyManager
|
#include "game/gameplay/enemy_manager.hpp" // Para EnemyManager
|
||||||
#include "game/gameplay/item_manager.hpp" // Para ItemManager
|
#include "game/gameplay/item_manager.hpp" // Para ItemManager
|
||||||
#include "game/gameplay/item_tracker.hpp" // Para ItemTracker
|
#include "game/gameplay/item_tracker.hpp" // Para ItemTracker
|
||||||
|
#include "game/gameplay/key_manager.hpp" // Para KeyManager
|
||||||
|
#include "game/gameplay/key_tracker.hpp" // Para KeyTracker
|
||||||
#include "game/gameplay/platform_manager.hpp" // Para PlatformManager
|
#include "game/gameplay/platform_manager.hpp" // Para PlatformManager
|
||||||
#include "game/gameplay/room_loader.hpp" // Para RoomLoader
|
#include "game/gameplay/room_loader.hpp" // Para RoomLoader
|
||||||
#include "game/gameplay/scoreboard.hpp" // Para Scoreboard::Data
|
#include "game/gameplay/scoreboard.hpp" // Para Scoreboard::Data
|
||||||
@@ -21,18 +25,27 @@ Room::Room(const std::string& room_path, std::shared_ptr<Scoreboard::Data> data)
|
|||||||
: data_(std::move(data)) {
|
: data_(std::move(data)) {
|
||||||
auto room = Resource::Cache::get()->getRoom(room_path);
|
auto room = Resource::Cache::get()->getRoom(room_path);
|
||||||
|
|
||||||
// Crea los managers de enemigos, items y plataformas
|
// Crea los managers de enemigos, items, plataformas y llaves
|
||||||
enemy_manager_ = std::make_unique<EnemyManager>();
|
enemy_manager_ = std::make_unique<EnemyManager>();
|
||||||
item_manager_ = std::make_unique<ItemManager>(room->number, data_);
|
item_manager_ = std::make_unique<ItemManager>(room->number, data_);
|
||||||
platform_manager_ = std::make_unique<PlatformManager>();
|
platform_manager_ = std::make_unique<PlatformManager>();
|
||||||
|
key_manager_ = std::make_unique<KeyManager>(room->number);
|
||||||
|
|
||||||
initializeRoom(*room);
|
// Crea el mapa de colisiones desde el collision_tile_map (debe ir antes
|
||||||
// Crea el mapa de colisiones desde el collision_tile_map
|
// del DoorManager porque éste lo necesita para mutar tiles dinámicamente)
|
||||||
collision_map_ = std::make_unique<CollisionMap>(room->collision_tile_map, conveyor_belt_direction_);
|
collision_map_ = std::make_unique<CollisionMap>(room->collision_tile_map, conveyor_belt_direction_);
|
||||||
|
|
||||||
// Crea el renderizador del tilemap (necesita tile_map_, tile_set_width_, surface_, bg_color_, conveyor_belt_direction_)
|
// Crea el manager de puertas (necesita el CollisionMap para sincronizar muros)
|
||||||
|
door_manager_ = std::make_unique<DoorManager>(room->number, collision_map_.get());
|
||||||
|
|
||||||
|
initializeRoom(*room);
|
||||||
|
|
||||||
|
// Crea el renderizador del tilemap (necesita tile_map_, tile_set_width_, surface_, bg_color_, conveyor_belt_direction_).
|
||||||
|
// Se inicializa con el collision tile map ya modificado por las puertas (que han marcado sus
|
||||||
|
// celdas como WALL en el collision_map_, pero el renderer solo lo usa para detectar superficies
|
||||||
|
// de dibujo, no para colisión, así que pasamos la versión actualizada del collision_map_).
|
||||||
tilemap_renderer_ = std::make_unique<TilemapRenderer>(tile_map_, tile_set_width_, surface_, bg_color_, conveyor_belt_direction_);
|
tilemap_renderer_ = std::make_unique<TilemapRenderer>(tile_map_, tile_set_width_, surface_, bg_color_, conveyor_belt_direction_);
|
||||||
tilemap_renderer_->initialize(room->collision_tile_map);
|
tilemap_renderer_->initialize(collision_map_->getCollisionTileMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
@@ -79,6 +92,23 @@ void Room::initializeRoom(const Data& room) {
|
|||||||
item_manager_->addItem(std::make_shared<Item>(item_copy));
|
item_manager_->addItem(std::make_shared<Item>(item_copy));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Crear las llaves usando el manager (saltar las ya recogidas)
|
||||||
|
for (const auto& key_data : room.keys) {
|
||||||
|
const SDL_FPoint KEY_POS{.x = key_data.x, .y = key_data.y};
|
||||||
|
if (!KeyTracker::get()->hasBeenPicked(room.number, KEY_POS)) {
|
||||||
|
key_manager_->addKey(std::make_shared<Key>(key_data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crear las puertas usando el manager. Las que ya hayan sido abiertas
|
||||||
|
// antes (DoorTracker) se construyen directamente en estado OPENED y no
|
||||||
|
// pintan WALLs en el collision_map_.
|
||||||
|
for (const auto& door_data : room.doors) {
|
||||||
|
const SDL_FPoint DOOR_POS{.x = door_data.x, .y = door_data.y};
|
||||||
|
const bool ALREADY_OPENED = DoorTracker::get()->hasBeenOpened(room.number, DOOR_POS);
|
||||||
|
door_manager_->addDoor(std::make_shared<Door>(door_data, ALREADY_OPENED));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dibuja el mapa en pantalla
|
// Dibuja el mapa en pantalla
|
||||||
@@ -101,6 +131,16 @@ void Room::renderItems() {
|
|||||||
item_manager_->render();
|
item_manager_->render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dibuja las llaves en pantalla
|
||||||
|
void Room::renderKeys() {
|
||||||
|
key_manager_->render();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dibuja las puertas en pantalla
|
||||||
|
void Room::renderDoors() {
|
||||||
|
door_manager_->render();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
// Redibuja el mapa (para actualizar modo debug)
|
// Redibuja el mapa (para actualizar modo debug)
|
||||||
void Room::redrawMap() {
|
void Room::redrawMap() {
|
||||||
@@ -202,6 +242,12 @@ void Room::update(float delta_time) { // NOLINT(readability-make-member-functio
|
|||||||
|
|
||||||
// Actualiza los items usando el manager
|
// Actualiza los items usando el manager
|
||||||
item_manager_->update(delta_time);
|
item_manager_->update(delta_time);
|
||||||
|
|
||||||
|
// Actualiza las llaves usando el manager
|
||||||
|
key_manager_->update(delta_time);
|
||||||
|
|
||||||
|
// Actualiza las puertas usando el manager (procesa transiciones a OPENED)
|
||||||
|
door_manager_->update(delta_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pone el mapa en modo pausa
|
// Pone el mapa en modo pausa
|
||||||
@@ -209,6 +255,8 @@ void Room::setPaused(bool value) {
|
|||||||
is_paused_ = value;
|
is_paused_ = value;
|
||||||
tilemap_renderer_->setPaused(value);
|
tilemap_renderer_->setPaused(value);
|
||||||
item_manager_->setPaused(value);
|
item_manager_->setPaused(value);
|
||||||
|
key_manager_->setPaused(value);
|
||||||
|
door_manager_->setPaused(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Room::getTileCollider() const -> const TileCollider& {
|
auto Room::getTileCollider() const -> const TileCollider& {
|
||||||
@@ -247,6 +295,14 @@ auto Room::itemCollision(SDL_FRect& rect) -> bool {
|
|||||||
return item_manager_->checkCollision(rect);
|
return item_manager_->checkCollision(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Room::keyCollision(SDL_FRect& rect) -> bool {
|
||||||
|
return key_manager_->checkCollision(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Room::tryUnlockDoors(const SDL_FRect& player_rect) {
|
||||||
|
door_manager_->tryUnlock(player_rect);
|
||||||
|
}
|
||||||
|
|
||||||
auto Room::checkPlayerOnPlatform(const SDL_FRect& player_collider, float player_vy) -> MovingPlatform* {
|
auto Room::checkPlayerOnPlatform(const SDL_FRect& player_collider, float player_vy) -> MovingPlatform* {
|
||||||
return platform_manager_->checkPlayerOnPlatform(player_collider, player_vy);
|
return platform_manager_->checkPlayerOnPlatform(player_collider, player_vy);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,10 @@
|
|||||||
#include <vector> // Para vector
|
#include <vector> // Para vector
|
||||||
|
|
||||||
#include "game/defaults.hpp" // Para Defaults::Game::Room
|
#include "game/defaults.hpp" // Para Defaults::Game::Room
|
||||||
|
#include "game/entities/door.hpp" // Para Door::Data
|
||||||
#include "game/entities/enemy.hpp" // Para EnemyData
|
#include "game/entities/enemy.hpp" // Para EnemyData
|
||||||
#include "game/entities/item.hpp" // Para ItemData
|
#include "game/entities/item.hpp" // Para ItemData
|
||||||
|
#include "game/entities/key.hpp" // Para Key::Data
|
||||||
#include "game/entities/moving_platform.hpp" // Para MovingPlatform::Data
|
#include "game/entities/moving_platform.hpp" // Para MovingPlatform::Data
|
||||||
#include "game/gameplay/collision_map.hpp" // Para CollisionMap::AdjacentData
|
#include "game/gameplay/collision_map.hpp" // Para CollisionMap::AdjacentData
|
||||||
#include "game/gameplay/scoreboard.hpp" // Para Scoreboard::Data
|
#include "game/gameplay/scoreboard.hpp" // Para Scoreboard::Data
|
||||||
@@ -17,6 +19,8 @@ class Surface;
|
|||||||
class EnemyManager;
|
class EnemyManager;
|
||||||
class ItemManager;
|
class ItemManager;
|
||||||
class PlatformManager;
|
class PlatformManager;
|
||||||
|
class KeyManager;
|
||||||
|
class DoorManager;
|
||||||
class TileCollider;
|
class TileCollider;
|
||||||
class TilemapRenderer;
|
class TilemapRenderer;
|
||||||
|
|
||||||
@@ -47,6 +51,8 @@ class Room {
|
|||||||
std::vector<Enemy::Data> enemies;
|
std::vector<Enemy::Data> enemies;
|
||||||
std::vector<Item::Data> items;
|
std::vector<Item::Data> items;
|
||||||
std::vector<MovingPlatform::Data> platforms;
|
std::vector<MovingPlatform::Data> platforms;
|
||||||
|
std::vector<Key::Data> keys;
|
||||||
|
std::vector<Door::Data> doors;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constructor y destructor
|
// Constructor y destructor
|
||||||
@@ -60,6 +66,8 @@ class Room {
|
|||||||
void renderEnemies();
|
void renderEnemies();
|
||||||
void renderPlatforms();
|
void renderPlatforms();
|
||||||
void renderItems();
|
void renderItems();
|
||||||
|
void renderKeys();
|
||||||
|
void renderDoors();
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
void redrawMap();
|
void redrawMap();
|
||||||
void updateEditorMode(float delta_time);
|
void updateEditorMode(float delta_time);
|
||||||
@@ -67,6 +75,8 @@ class Room {
|
|||||||
auto getEnemyManager() -> EnemyManager* { return enemy_manager_.get(); }
|
auto getEnemyManager() -> EnemyManager* { return enemy_manager_.get(); }
|
||||||
auto getItemManager() -> ItemManager* { return item_manager_.get(); }
|
auto getItemManager() -> ItemManager* { return item_manager_.get(); }
|
||||||
auto getPlatformManager() -> PlatformManager* { return platform_manager_.get(); }
|
auto getPlatformManager() -> PlatformManager* { return platform_manager_.get(); }
|
||||||
|
auto getKeyManager() -> KeyManager* { return key_manager_.get(); }
|
||||||
|
auto getDoorManager() -> DoorManager* { return door_manager_.get(); }
|
||||||
void setItemColors(Uint8 color1, Uint8 color2);
|
void setItemColors(Uint8 color1, Uint8 color2);
|
||||||
void setTile(int index, int tile_value);
|
void setTile(int index, int tile_value);
|
||||||
void setCollisionTile(int index, int value);
|
void setCollisionTile(int index, int value);
|
||||||
@@ -80,6 +90,8 @@ class Room {
|
|||||||
auto getRoom(Border border) -> std::string;
|
auto getRoom(Border border) -> std::string;
|
||||||
auto enemyCollision(SDL_FRect& rect) -> bool;
|
auto enemyCollision(SDL_FRect& rect) -> bool;
|
||||||
auto itemCollision(SDL_FRect& rect) -> bool;
|
auto itemCollision(SDL_FRect& rect) -> bool;
|
||||||
|
auto keyCollision(SDL_FRect& rect) -> bool;
|
||||||
|
void tryUnlockDoors(const SDL_FRect& player_rect);
|
||||||
auto checkPlayerOnPlatform(const SDL_FRect& player_collider, float player_vy) -> MovingPlatform*;
|
auto checkPlayerOnPlatform(const SDL_FRect& player_collider, float player_vy) -> MovingPlatform*;
|
||||||
void setPaused(bool value);
|
void setPaused(bool value);
|
||||||
[[nodiscard]] auto getConveyorBeltDirection() const -> int { return conveyor_belt_direction_; }
|
[[nodiscard]] auto getConveyorBeltDirection() const -> int { return conveyor_belt_direction_; }
|
||||||
@@ -98,6 +110,8 @@ class Room {
|
|||||||
std::unique_ptr<EnemyManager> enemy_manager_;
|
std::unique_ptr<EnemyManager> enemy_manager_;
|
||||||
std::unique_ptr<ItemManager> item_manager_;
|
std::unique_ptr<ItemManager> item_manager_;
|
||||||
std::unique_ptr<PlatformManager> platform_manager_;
|
std::unique_ptr<PlatformManager> platform_manager_;
|
||||||
|
std::unique_ptr<KeyManager> key_manager_;
|
||||||
|
std::unique_ptr<DoorManager> door_manager_;
|
||||||
std::unique_ptr<CollisionMap> collision_map_;
|
std::unique_ptr<CollisionMap> collision_map_;
|
||||||
std::unique_ptr<TilemapRenderer> tilemap_renderer_;
|
std::unique_ptr<TilemapRenderer> tilemap_renderer_;
|
||||||
std::shared_ptr<Surface> surface_;
|
std::shared_ptr<Surface> surface_;
|
||||||
|
|||||||
@@ -382,6 +382,86 @@ void RoomLoader::parsePlatforms(const fkyaml::node& yaml, Room::Data& room, bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parsea los datos de una llave individual
|
||||||
|
auto RoomLoader::parseKeyData(const fkyaml::node& key_node) -> Key::Data { // NOLINT(readability-convert-member-functions-to-static)
|
||||||
|
Key::Data key;
|
||||||
|
|
||||||
|
if (key_node.contains("animation")) {
|
||||||
|
key.animation_path = key_node["animation"].get_value<std::string>();
|
||||||
|
}
|
||||||
|
if (key_node.contains("id")) {
|
||||||
|
key.id = key_node["id"].get_value<std::string>();
|
||||||
|
}
|
||||||
|
if (key_node.contains("position")) {
|
||||||
|
const auto& pos = key_node["position"];
|
||||||
|
if (pos.contains("x")) {
|
||||||
|
key.x = pos["x"].get_value<float>() * Tile::SIZE;
|
||||||
|
}
|
||||||
|
if (pos.contains("y")) {
|
||||||
|
key.y = pos["y"].get_value<float>() * Tile::SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parsea la lista de llaves de la habitación
|
||||||
|
void RoomLoader::parseKeys(const fkyaml::node& yaml, Room::Data& room, bool verbose) { // NOLINT(readability-convert-member-functions-to-static)
|
||||||
|
if (!yaml.contains("keys") || yaml["keys"].is_null()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& keys_node = yaml["keys"];
|
||||||
|
|
||||||
|
for (const auto& key_node : keys_node) {
|
||||||
|
room.keys.push_back(parseKeyData(key_node));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
std::cout << "Loaded " << room.keys.size() << " keys\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parsea los datos de una puerta individual
|
||||||
|
auto RoomLoader::parseDoorData(const fkyaml::node& door_node) -> Door::Data { // NOLINT(readability-convert-member-functions-to-static)
|
||||||
|
Door::Data door;
|
||||||
|
|
||||||
|
if (door_node.contains("animation")) {
|
||||||
|
door.animation_path = door_node["animation"].get_value<std::string>();
|
||||||
|
}
|
||||||
|
if (door_node.contains("id")) {
|
||||||
|
door.id = door_node["id"].get_value<std::string>();
|
||||||
|
}
|
||||||
|
if (door_node.contains("position")) {
|
||||||
|
const auto& pos = door_node["position"];
|
||||||
|
if (pos.contains("x")) {
|
||||||
|
door.x = pos["x"].get_value<float>() * Tile::SIZE;
|
||||||
|
}
|
||||||
|
if (pos.contains("y")) {
|
||||||
|
door.y = pos["y"].get_value<float>() * Tile::SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return door;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parsea la lista de puertas de la habitación
|
||||||
|
void RoomLoader::parseDoors(const fkyaml::node& yaml, Room::Data& room, bool verbose) { // NOLINT(readability-convert-member-functions-to-static)
|
||||||
|
if (!yaml.contains("doors") || yaml["doors"].is_null()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& doors_node = yaml["doors"];
|
||||||
|
|
||||||
|
for (const auto& door_node : doors_node) {
|
||||||
|
room.doors.push_back(parseDoorData(door_node));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
std::cout << "Loaded " << room.doors.size() << " doors\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
// Carga una habitación desde un string YAML (para el editor de mapas, evita el resource pack)
|
// Carga una habitación desde un string YAML (para el editor de mapas, evita el resource pack)
|
||||||
auto RoomLoader::loadFromString(const std::string& yaml_content, const std::string& file_name) -> Room::Data {
|
auto RoomLoader::loadFromString(const std::string& yaml_content, const std::string& file_name) -> Room::Data {
|
||||||
@@ -393,6 +473,8 @@ auto RoomLoader::loadFromString(const std::string& yaml_content, const std::stri
|
|||||||
parseEnemies(yaml, room, false);
|
parseEnemies(yaml, room, false);
|
||||||
parseItems(yaml, room, false);
|
parseItems(yaml, room, false);
|
||||||
parsePlatforms(yaml, room, false);
|
parsePlatforms(yaml, room, false);
|
||||||
|
parseKeys(yaml, room, false);
|
||||||
|
parseDoors(yaml, room, false);
|
||||||
} catch (const fkyaml::exception& e) {
|
} catch (const fkyaml::exception& e) {
|
||||||
std::cerr << "YAML parsing error in " << file_name << ": " << e.what() << '\n';
|
std::cerr << "YAML parsing error in " << file_name << ": " << e.what() << '\n';
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
@@ -428,6 +510,8 @@ auto RoomLoader::loadYAML(const std::string& file_path, bool verbose) -> Room::D
|
|||||||
parseEnemies(yaml, room, verbose);
|
parseEnemies(yaml, room, verbose);
|
||||||
parseItems(yaml, room, verbose);
|
parseItems(yaml, room, verbose);
|
||||||
parsePlatforms(yaml, room, verbose);
|
parsePlatforms(yaml, room, verbose);
|
||||||
|
parseKeys(yaml, room, verbose);
|
||||||
|
parseDoors(yaml, room, verbose);
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
std::cout << "Room loaded successfully: " << FILE_NAME << '\n';
|
std::cout << "Room loaded successfully: " << FILE_NAME << '\n';
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
#include <vector> // Para vector
|
#include <vector> // Para vector
|
||||||
|
|
||||||
#include "external/fkyaml_node.hpp" // Para fkyaml::node
|
#include "external/fkyaml_node.hpp" // Para fkyaml::node
|
||||||
|
#include "game/entities/door.hpp" // Para Door::Data
|
||||||
#include "game/entities/enemy.hpp" // Para Enemy::Data
|
#include "game/entities/enemy.hpp" // Para Enemy::Data
|
||||||
#include "game/entities/item.hpp" // Para Item::Data
|
#include "game/entities/item.hpp" // Para Item::Data
|
||||||
|
#include "game/entities/key.hpp" // Para Key::Data
|
||||||
#include "game/entities/moving_platform.hpp" // Para MovingPlatform::Data
|
#include "game/entities/moving_platform.hpp" // Para MovingPlatform::Data
|
||||||
#include "game/gameplay/room.hpp" // Para Room::Data
|
#include "game/gameplay/room.hpp" // Para Room::Data
|
||||||
|
|
||||||
@@ -137,4 +139,24 @@ class RoomLoader {
|
|||||||
|
|
||||||
static void parsePlatforms(const fkyaml::node& yaml, Room::Data& room, bool verbose);
|
static void parsePlatforms(const fkyaml::node& yaml, Room::Data& room, bool verbose);
|
||||||
static auto parsePlatformData(const fkyaml::node& platform_node) -> MovingPlatform::Data;
|
static auto parsePlatformData(const fkyaml::node& platform_node) -> MovingPlatform::Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parsea la lista de llaves de la habitación
|
||||||
|
*/
|
||||||
|
static void parseKeys(const fkyaml::node& yaml, Room::Data& room, bool verbose);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parsea los datos de una llave individual
|
||||||
|
*/
|
||||||
|
static auto parseKeyData(const fkyaml::node& key_node) -> Key::Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parsea la lista de puertas de la habitación
|
||||||
|
*/
|
||||||
|
static void parseDoors(const fkyaml::node& yaml, Room::Data& room, bool verbose);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parsea los datos de una puerta individual
|
||||||
|
*/
|
||||||
|
static auto parseDoorData(const fkyaml::node& door_node) -> Door::Data;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,10 @@
|
|||||||
#include "utils/defines.hpp"
|
#include "utils/defines.hpp"
|
||||||
|
|
||||||
TileCollider::TileCollider(const std::vector<int>& extended_tile_map, int width, int height, int border_px)
|
TileCollider::TileCollider(const std::vector<int>& extended_tile_map, int width, int height, int border_px)
|
||||||
: width_(width), height_(height), border_px_(border_px), tile_map_(extended_tile_map) {}
|
: width_(width),
|
||||||
|
height_(height),
|
||||||
|
border_px_(border_px),
|
||||||
|
tile_map_(extended_tile_map) {}
|
||||||
|
|
||||||
// --- Queries básicas ---
|
// --- Queries básicas ---
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,10 @@
|
|||||||
#include "game/defaults.hpp" // Para Defaults::Game
|
#include "game/defaults.hpp" // Para Defaults::Game
|
||||||
#include "game/entities/moving_platform.hpp" // Para MovingPlatform
|
#include "game/entities/moving_platform.hpp" // Para MovingPlatform
|
||||||
#include "game/game_control.hpp" // Para GameControl
|
#include "game/game_control.hpp" // Para GameControl
|
||||||
|
#include "game/gameplay/door_tracker.hpp" // Para DoorTracker
|
||||||
|
#include "game/gameplay/inventory.hpp" // Para Inventory
|
||||||
#include "game/gameplay/item_tracker.hpp" // Para ItemTracker
|
#include "game/gameplay/item_tracker.hpp" // Para ItemTracker
|
||||||
|
#include "game/gameplay/key_tracker.hpp" // Para KeyTracker
|
||||||
#include "game/gameplay/room.hpp" // Para Room, RoomData
|
#include "game/gameplay/room.hpp" // Para Room, RoomData
|
||||||
#include "game/gameplay/room_tracker.hpp" // Para RoomTracker
|
#include "game/gameplay/room_tracker.hpp" // Para RoomTracker
|
||||||
#include "game/gameplay/scoreboard.hpp" // Para Scoreboard::Data, Scoreboard
|
#include "game/gameplay/scoreboard.hpp" // Para Scoreboard::Data, Scoreboard
|
||||||
@@ -66,6 +69,9 @@ Game::Game(Mode mode)
|
|||||||
|
|
||||||
// Crea objetos e inicializa variables
|
// Crea objetos e inicializa variables
|
||||||
ItemTracker::init();
|
ItemTracker::init();
|
||||||
|
KeyTracker::init();
|
||||||
|
DoorTracker::init();
|
||||||
|
Inventory::init();
|
||||||
demoInit();
|
demoInit();
|
||||||
room_ = getOrCreateRoom(current_room_);
|
room_ = getOrCreateRoom(current_room_);
|
||||||
initPlayer(spawn_data_, room_);
|
initPlayer(spawn_data_, room_);
|
||||||
@@ -164,6 +170,9 @@ Game::~Game() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ItemTracker::destroy();
|
ItemTracker::destroy();
|
||||||
|
KeyTracker::destroy();
|
||||||
|
DoorTracker::destroy();
|
||||||
|
Inventory::destroy();
|
||||||
|
|
||||||
if (Console::get() != nullptr) { Console::get()->on_toggle = nullptr; }
|
if (Console::get() != nullptr) { Console::get()->on_toggle = nullptr; }
|
||||||
|
|
||||||
@@ -325,6 +334,8 @@ void Game::updatePlaying(float delta_time) {
|
|||||||
#endif
|
#endif
|
||||||
checkPlayerIsOnBorder();
|
checkPlayerIsOnBorder();
|
||||||
checkPlayerAndItems();
|
checkPlayerAndItems();
|
||||||
|
checkPlayerAndKeys();
|
||||||
|
room_->tryUnlockDoors(player_->getCollider());
|
||||||
checkPlayerAndEnemies();
|
checkPlayerAndEnemies();
|
||||||
checkIfPlayerIsAlive();
|
checkIfPlayerIsAlive();
|
||||||
|
|
||||||
@@ -507,6 +518,8 @@ void Game::renderPlaying() {
|
|||||||
transition_old_room_->renderPlatforms();
|
transition_old_room_->renderPlatforms();
|
||||||
transition_old_room_->renderEnemies();
|
transition_old_room_->renderEnemies();
|
||||||
transition_old_room_->renderItems();
|
transition_old_room_->renderItems();
|
||||||
|
transition_old_room_->renderKeys();
|
||||||
|
transition_old_room_->renderDoors();
|
||||||
|
|
||||||
// Renderizar habitación entrante + jugador con su offset
|
// Renderizar habitación entrante + jugador con su offset
|
||||||
Screen::get()->setRenderOffset(new_ox, new_oy);
|
Screen::get()->setRenderOffset(new_ox, new_oy);
|
||||||
@@ -514,6 +527,8 @@ void Game::renderPlaying() {
|
|||||||
room_->renderPlatforms();
|
room_->renderPlatforms();
|
||||||
room_->renderEnemies();
|
room_->renderEnemies();
|
||||||
room_->renderItems();
|
room_->renderItems();
|
||||||
|
room_->renderKeys();
|
||||||
|
room_->renderDoors();
|
||||||
if (mode_ == Mode::GAME) {
|
if (mode_ == Mode::GAME) {
|
||||||
player_->render();
|
player_->render();
|
||||||
}
|
}
|
||||||
@@ -527,6 +542,8 @@ void Game::renderPlaying() {
|
|||||||
room_->renderPlatforms();
|
room_->renderPlatforms();
|
||||||
room_->renderEnemies();
|
room_->renderEnemies();
|
||||||
room_->renderItems();
|
room_->renderItems();
|
||||||
|
room_->renderKeys();
|
||||||
|
room_->renderDoors();
|
||||||
if (mode_ == Mode::GAME) {
|
if (mode_ == Mode::GAME) {
|
||||||
player_->render();
|
player_->render();
|
||||||
}
|
}
|
||||||
@@ -569,6 +586,8 @@ void Game::renderFadeToEnding() {
|
|||||||
room_->renderMap();
|
room_->renderMap();
|
||||||
room_->renderEnemies();
|
room_->renderEnemies();
|
||||||
room_->renderItems();
|
room_->renderItems();
|
||||||
|
room_->renderKeys();
|
||||||
|
room_->renderDoors();
|
||||||
player_->render(); // Player congelado pero visible
|
player_->render(); // Player congelado pero visible
|
||||||
scoreboard_->render();
|
scoreboard_->render();
|
||||||
|
|
||||||
@@ -935,6 +954,10 @@ void Game::checkPlayerAndPlatforms() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Comprueba las colisiones del jugador con los objetos
|
// Comprueba las colisiones del jugador con los objetos
|
||||||
|
void Game::checkPlayerAndKeys() {
|
||||||
|
room_->keyCollision(player_->getCollider());
|
||||||
|
}
|
||||||
|
|
||||||
void Game::checkPlayerAndItems() {
|
void Game::checkPlayerAndItems() {
|
||||||
room_->itemCollision(player_->getCollider());
|
room_->itemCollision(player_->getCollider());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ class Game {
|
|||||||
auto checkPlayerAndEnemies() -> bool; // Comprueba las colisiones del jugador con los enemigos
|
auto checkPlayerAndEnemies() -> bool; // Comprueba las colisiones del jugador con los enemigos
|
||||||
void checkPlayerAndPlatforms(); // Comprueba si el jugador está sobre una plataforma móvil
|
void checkPlayerAndPlatforms(); // Comprueba si el jugador está sobre una plataforma móvil
|
||||||
void checkPlayerAndItems(); // Comprueba las colisiones del jugador con los objetos
|
void checkPlayerAndItems(); // Comprueba las colisiones del jugador con los objetos
|
||||||
|
void checkPlayerAndKeys(); // Comprueba las colisiones del jugador con las llaves
|
||||||
void checkIfPlayerIsAlive(); // Comprueba si el jugador esta vivo
|
void checkIfPlayerIsAlive(); // Comprueba si el jugador esta vivo
|
||||||
void killPlayer(); // Mata al jugador
|
void killPlayer(); // Mata al jugador
|
||||||
void togglePause(); // Pone el juego en pausa
|
void togglePause(); // Pone el juego en pausa
|
||||||
|
|||||||
@@ -741,10 +741,14 @@ static auto cmdSet(const std::vector<std::string>& args) -> std::string {
|
|||||||
if (args.size() < 2) { return "usage: set <property> <value>"; }
|
if (args.size() < 2) { return "usage: set <property> <value>"; }
|
||||||
|
|
||||||
switch (MapEditor::get()->getSelectionType()) {
|
switch (MapEditor::get()->getSelectionType()) {
|
||||||
case EntityType::ENEMY: return MapEditor::get()->setEnemyProperty(args[0], args[1]);
|
case EntityType::ENEMY:
|
||||||
case EntityType::ITEM: return MapEditor::get()->setItemProperty(args[0], args[1]);
|
return MapEditor::get()->setEnemyProperty(args[0], args[1]);
|
||||||
case EntityType::PLATFORM: return MapEditor::get()->setPlatformProperty(args[0], args[1]);
|
case EntityType::ITEM:
|
||||||
default: return MapEditor::get()->setRoomProperty(args[0], args[1]);
|
return MapEditor::get()->setItemProperty(args[0], args[1]);
|
||||||
|
case EntityType::PLATFORM:
|
||||||
|
return MapEditor::get()->setPlatformProperty(args[0], args[1]);
|
||||||
|
default:
|
||||||
|
return MapEditor::get()->setRoomProperty(args[0], args[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user