Refactored the bossfight_ui so it will work with any description of a boss fight.

master
Zed A. Shaw 1 week ago
parent 43835da88f
commit a3f6ba3c03
  1. 14
      assets/bosses.json
  2. 5
      assets/config.json
  3. 6
      assets/devices.json
  4. 27
      assets/enemies.json
  5. 12
      assets/items.json
  6. 66
      boss_fight_ui.cpp
  7. 10
      boss_fight_ui.hpp
  8. 5
      components.hpp
  9. 6
      constants.hpp
  10. 2
      gui_fsm.cpp
  11. 2
      main.cpp
  12. 3
      save.cpp

@ -0,0 +1,14 @@
{
"RAT_KING": {
"background": "boss_fight_background",
"weapon_sound": "Sword_Hit_2",
"components": [
{"_type": "Combat", "hp": 50, "max_hp": 50, "damage": 50, "dead": false},
{"_type": "Motion", "dx": 0, "dy": 0, "random": false},
{"_type": "EnemyConfig", "hearing_distance": 3},
{"_type": "Animation", "easing": 2, "ease_rate": 0.2, "scale": 0.2, "simple": false, "frames": 2, "speed": 0.02},
{"_type": "Sprite", "name": "rat_king_boss", "width": 720, "height": 720},
{"_type": "Sound", "attack": "Marmot_Scream_1", "death": "Creature_Death_1"}
]
}
}

@ -48,11 +48,6 @@
"down_the_well": "assets/down_the_well.jpg", "down_the_well": "assets/down_the_well.jpg",
"boss_fight_background": "assets/rat_king_boss_fight_background.jpg" "boss_fight_background": "assets/rat_king_boss_fight_background.jpg"
}, },
"enemy": {
"HEARING_DISTANCE": 5
},
"player": {
},
"worldgen": { "worldgen": {
"enemy_probability": 80, "enemy_probability": 80,
"empty_room_probability": 10, "empty_room_probability": 10,

@ -14,7 +14,7 @@
{"_type": "Device", {"_type": "Device",
"config": {"test": true}, "config": {"test": true},
"events": ["Events::GUI::STAIRS_DOWN"]}, "events": ["Events::GUI::STAIRS_DOWN"]},
{"_type": "Sprite", "name": "well_down"} {"_type": "Sprite", "name": "well_down", "width": 256, "height": 256}
] ]
}, },
"STAIRS_UP": { "STAIRS_UP": {
@ -31,7 +31,7 @@
{"_type": "Device", {"_type": "Device",
"config": {"test": true}, "config": {"test": true},
"events": ["Events::GUI::STAIRS_UP"]}, "events": ["Events::GUI::STAIRS_UP"]},
{"_type": "Sprite", "name": "rope_vines_up"} {"_type": "Sprite", "name": "rope_vines_up", "width": 256, "height": 256}
] ]
}, },
"TRIPWIRE_TRAP": { "TRIPWIRE_TRAP": {
@ -47,7 +47,7 @@
{"_type": "Device", {"_type": "Device",
"config": {"test": true}, "config": {"test": true},
"events": ["Events::GUI::TRAP"]}, "events": ["Events::GUI::TRAP"]},
{"_type": "Sprite", "name": "tripwire_trap"} {"_type": "Sprite", "name": "tripwire_trap", "width": 256, "height": 256}
] ]
} }
} }

@ -21,7 +21,7 @@
{"_type": "Motion", "dx": 0, "dy": 0, "random": false}, {"_type": "Motion", "dx": 0, "dy": 0, "random": false},
{"_type": "EnemyConfig", "hearing_distance": 5}, {"_type": "EnemyConfig", "hearing_distance": 5},
{"_type": "Animation", "easing": 1, "ease_rate": 0.2, "scale": 0.1, "simple": true, "frames": 10, "speed": 0.3}, {"_type": "Animation", "easing": 1, "ease_rate": 0.2, "scale": 0.1, "simple": true, "frames": 10, "speed": 0.3},
{"_type": "Sprite", "name": "armored_knight"}, {"_type": "Sprite", "name": "armored_knight", "width": 256, "height": 256, "width": 256, "height": 256},
{"_type": "Sound", "attack": "Sword_Hit_2", "death": "Humanoid_Death_1"} {"_type": "Sound", "attack": "Sword_Hit_2", "death": "Humanoid_Death_1"}
] ]
}, },
@ -34,7 +34,7 @@
{"_type": "Combat", "hp": 40, "max_hp": 40, "damage": 10, "dead": false}, {"_type": "Combat", "hp": 40, "max_hp": 40, "damage": 10, "dead": false},
{"_type": "Motion", "dx": 0, "dy": 0, "random": true}, {"_type": "Motion", "dx": 0, "dy": 0, "random": true},
{"_type": "EnemyConfig", "hearing_distance": 5}, {"_type": "EnemyConfig", "hearing_distance": 5},
{"_type": "Sprite", "name": "axe_ranger"}, {"_type": "Sprite", "name": "axe_ranger", "width": 256, "height": 256},
{"_type": "Animation", "easing": 3, "ease_rate": 0.5, "scale": 0.1, "simple": false, "frames": 2, "speed": 0.6}, {"_type": "Animation", "easing": 3, "ease_rate": 0.5, "scale": 0.1, "simple": false, "frames": 2, "speed": 0.6},
{"_type": "Sound", "attack": "Sword_Hit_2", "death": "Ranger_1"} {"_type": "Sound", "attack": "Sword_Hit_2", "death": "Ranger_1"}
] ]
@ -48,8 +48,8 @@
{"_type": "Combat", "hp": 50, "max_hp": 50, "damage": 50, "dead": false}, {"_type": "Combat", "hp": 50, "max_hp": 50, "damage": 50, "dead": false},
{"_type": "Motion", "dx": 0, "dy": 0, "random": false}, {"_type": "Motion", "dx": 0, "dy": 0, "random": false},
{"_type": "EnemyConfig", "hearing_distance": 5}, {"_type": "EnemyConfig", "hearing_distance": 5},
{"_type": "Sprite", "name": "evil_eye"}, {"_type": "Sprite", "name": "evil_eye", "width": 256, "height": 256},
{"_type": "Animation", "easing": 3, "ease_rate": 0.1, "scale": 0.1, "simple": false, "frames": 2, "speed": 0.3}, {"_type": "Animation", "easing": 3, "ease_rate": 0.1, "scale": 0.1, "simple": false, "frames": 2, "speed": 0.1},
{"_type": "Sound", "attack": "Evil_Eye_Sound_2", "death": "Evil_Eye_Sound_1"} {"_type": "Sound", "attack": "Evil_Eye_Sound_2", "death": "Evil_Eye_Sound_1"}
] ]
}, },
@ -63,25 +63,10 @@
{"_type": "Motion", "dx": 0, "dy": 0, "random": false}, {"_type": "Motion", "dx": 0, "dy": 0, "random": false},
{"_type": "EnemyConfig", "hearing_distance": 10}, {"_type": "EnemyConfig", "hearing_distance": 10},
{"_type": "Animation", "easing": 3, "ease_rate": 0.5, "scale": 0.1, "simple": true, "frames": 10, "speed": 1.0}, {"_type": "Animation", "easing": 3, "ease_rate": 0.5, "scale": 0.1, "simple": true, "frames": 10, "speed": 1.0},
{"_type": "Sprite", "name": "rat_with_sword"}, {"_type": "Sprite", "name": "rat_with_sword", "width": 256, "height": 256},
{"_type": "Sound", "attack": "Small_Rat", "death": "Creature_Death_1"} {"_type": "Sound", "attack": "Small_Rat", "death": "Creature_Death_1"}
] ]
}, },
"RAT_KING": {
"placement": "fixed",
"components": [
{"_type": "Tile", "display": "\u08ac",
"foreground": [205, 164, 100],
"background": [30, 20, 75]
},
{"_type": "Combat", "hp": 50, "max_hp": 50, "damage": 50, "dead": false},
{"_type": "Motion", "dx": 0, "dy": 0, "random": false},
{"_type": "EnemyConfig", "hearing_distance": 3},
{"_type": "Animation", "easing": 2, "ease_rate": 0.2, "scale": 0.2, "simple": false, "frames": 2, "speed": 0.02},
{"_type": "Sprite", "name": "rat_king_boss"},
{"_type": "Sound", "attack": "Marmot_Scream_1", "death": "Creature_Death_1"}
]
},
"SPIDER_GIANT_HAIRY": { "SPIDER_GIANT_HAIRY": {
"components": [ "components": [
{"_type": "Tile", "display": "\u08ea", {"_type": "Tile", "display": "\u08ea",
@ -92,7 +77,7 @@
{"_type": "Motion", "dx": 0, "dy": 0, "random": false}, {"_type": "Motion", "dx": 0, "dy": 0, "random": false},
{"_type": "EnemyConfig", "hearing_distance": 10}, {"_type": "EnemyConfig", "hearing_distance": 10},
{"_type": "Animation", "easing": 2, "ease_rate": 0.5, "scale": 0.1, "simple": true, "frames": 10, "speed": 1.0}, {"_type": "Animation", "easing": 2, "ease_rate": 0.5, "scale": 0.1, "simple": true, "frames": 10, "speed": 1.0},
{"_type": "Sprite", "name": "hairy_spider"}, {"_type": "Sprite", "name": "hairy_spider", "width": 256, "height": 256},
{"_type": "Sound", "attack": "Spider_1", "death": "Spider_2"} {"_type": "Sound", "attack": "Spider_1", "death": "Spider_2"}
] ]
} }

@ -10,7 +10,7 @@
"foreground": [24, 120, 189], "foreground": [24, 120, 189],
"background": [230,120, 120] "background": [230,120, 120]
}, },
{"_type": "Sprite", "name": "torch_horizontal_floor"}, {"_type": "Sprite", "name": "torch_horizontal_floor", "width": 256, "height": 256},
{"_type": "Sound", "attack": "pickup", "death": "blank"} {"_type": "Sound", "attack": "pickup", "death": "blank"}
] ]
}, },
@ -25,7 +25,7 @@
"foreground": [24, 120, 189], "foreground": [24, 120, 189],
"background": [24, 120, 189] "background": [24, 120, 189]
}, },
{"_type": "Sprite", "name": "cinqueda"}, {"_type": "Sprite", "name": "cinqueda", "width": 256, "height": 256},
{"_type": "Sound", "attack": "pickup", "death": "blank"} {"_type": "Sound", "attack": "pickup", "death": "blank"}
] ]
}, },
@ -39,7 +39,7 @@
"background": [150, 100, 189] "background": [150, 100, 189]
}, },
{"_type": "Loot", "amount": 10}, {"_type": "Loot", "amount": 10},
{"_type": "Sprite", "name": "barrel_small"}, {"_type": "Sprite", "name": "barrel_small", "width": 256, "height": 256},
{"_type": "Sound", "attack": "pickup", "death": "blank"} {"_type": "Sound", "attack": "pickup", "death": "blank"}
], ],
"inventory_count": 1 "inventory_count": 1
@ -55,7 +55,7 @@
"background": [24, 205, 210] "background": [24, 205, 210]
}, },
{"_type": "LightSource", "strength": 50, "radius": 2.8}, {"_type": "LightSource", "strength": 50, "radius": 2.8},
{"_type": "Sprite", "name": "torch_pillar"}, {"_type": "Sprite", "name": "torch_pillar", "width": 256, "height": 256},
{"_type": "Sound", "attack": "pickup", "death": "blank"} {"_type": "Sound", "attack": "pickup", "death": "blank"}
] ]
}, },
@ -70,7 +70,7 @@
"background": [255, 205, 189] "background": [255, 205, 189]
}, },
{"_type": "Curative", "hp": 20}, {"_type": "Curative", "hp": 20},
{"_type": "Sprite", "name": "healing_potion_small"}, {"_type": "Sprite", "name": "healing_potion_small", "width": 256, "height": 256},
{"_type": "Sound", "attack": "pickup", "death": "blank"} {"_type": "Sound", "attack": "pickup", "death": "blank"}
] ]
}, },
@ -85,7 +85,7 @@
"background": [24, 205, 189] "background": [24, 205, 189]
}, },
{"_type": "Loot", "amount": 10}, {"_type": "Loot", "amount": 10},
{"_type": "Sprite", "name": "grave_stone"}, {"_type": "Sprite", "name": "grave_stone", "width": 256, "height": 256},
{"_type": "Sound", "attack": "pickup", "death": "blank"} {"_type": "Sound", "attack": "pickup", "death": "blank"}
] ]
} }

@ -3,45 +3,56 @@
#include "sound.hpp" #include "sound.hpp"
namespace gui { namespace gui {
BossFightUI::BossFightUI(GameLevel level) BossFightUI::BossFightUI(GameLevel level, std::string boss_name)
: $level(level) : $level(level),
$config($level.world->get_the<components::GameConfig>()),
$boss_name(boss_name)
{ {
$status.position(0, 0, 300, SCREEN_HEIGHT); $status.position(0, 0, BOSS_VIEW_X, SCREEN_HEIGHT);
$status.layout( $status.layout(
"[main_status]" "[main_status]"
"[(150)status_3|(150)status_4]" "[(150)status_3|(150)status_4]"
"[(150)status_5|(150)status_6]" "[(150)status_5|(150)status_6]"
"[(150)status_7|(150)status_8]" "[(150)status_7|(150)status_8]");
);
$overlay.position(BOSS_VIEW_X, BOSS_VIEW_Y,
BOSS_VIEW_WIDTH, BOSS_VIEW_HEIGHT);
$overlay.position(300, 0, SCREEN_WIDTH - 300, SCREEN_HEIGHT);
$overlay.layout("[overlay_1|overlay_2|overlay_4]" $overlay.layout("[overlay_1|overlay_2|overlay_4]"
"[overlay_5|overlay_6|overlay_8]" "[overlay_5|overlay_6|overlay_8]"
"[overlay_9|overlay_10|overlay_12]" "[overlay_9|overlay_10|overlay_12]"
"[overlay_13|overlay_14|overlay_16]"); "[overlay_13|overlay_14|overlay_16]");
$boss_background = textures::get("boss_fight_background"); $sounds = components::get<components::Sound>($config.bosses[boss_name]);
auto bg_bounds = $boss_background.sprite->getLocalBounds(); $weapon_hit_sound = $config.bosses[$boss_name]["weapon_sound"];
$boss_background.sprite->setPosition({300, 0}); }
$boss_image = textures::get("rat_king_boss"); void BossFightUI::configure_sprite() {
sf::IntRect frame_rect{{0,0},{720,720}}; auto& boss = $config.bosses[$boss_name];
$sprite_config = components::get<components::Sprite>(boss);
$animation = components::get<components::Animation>(boss);
$animation.texture_width = $sprite_config.width;
$boss_image = textures::get($sprite_config.name);
sf::IntRect frame_rect{{0,0},{$sprite_config.width,$sprite_config.height}};
$boss_image.sprite->setTextureRect(frame_rect); $boss_image.sprite->setTextureRect(frame_rect);
$boss_image.sprite->setScale($scale); $boss_image.sprite->setScale($scale);
auto bounds = $boss_image.sprite->getLocalBounds(); auto bounds = $boss_image.sprite->getLocalBounds();
auto bg_bounds = $boss_background.sprite->getLocalBounds();
float x_diff = bg_bounds.size.x / 2; float x_diff = bg_bounds.size.x / 2;
$boss_image.sprite->setOrigin({bounds.size.x / 2, bounds.size.y / 2}); $boss_image.sprite->setOrigin({bounds.size.x / 2, bounds.size.y / 2});
$boss_image.sprite->setPosition({300.0f + x_diff, bounds.size.y / 2}); $boss_image.sprite->setPosition({float(BOSS_VIEW_X) + x_diff, bounds.size.y / 2});
} }
void BossFightUI::init() { void BossFightUI::configure_background() {
auto& config = $level.world->get_the<components::GameConfig>(); auto& boss = $config.bosses[$boss_name];
$sounds = components::get<components::Sound>(config.enemies["RAT_KING"]); $boss_background = textures::get(boss["background"]);
$animation = components::get<components::Animation>(config.enemies["RAT_KING"]); $boss_background.sprite->setPosition({BOSS_VIEW_X, BOSS_VIEW_Y});
$animation.texture_width = 720;
$status.world().set_the<Background>({$status.$parser}); $status.world().set_the<Background>({$status.$parser});
}
void BossFightUI::configure_gui() {
for(auto& [name, cell] : $status.cells()) { for(auto& [name, cell] : $status.cells()) {
auto button = $status.entity(name); auto button = $status.entity(name);
$status.set<Rectangle>(button, {}); $status.set<Rectangle>(button, {});
@ -66,8 +77,15 @@ namespace gui {
$overlay.init(); $overlay.init();
} }
void BossFightUI::init() {
// background must come first
configure_background();
configure_sprite();
configure_gui();
}
void BossFightUI::bounce_boss(sf::RenderWindow& window) { void BossFightUI::bounce_boss(sf::RenderWindow& window) {
sf::IntRect frame_rect{{0,0},{720,720}}; sf::IntRect frame_rect{{0,0},{$sprite_config.width,$sprite_config.height}};
auto scale = $scale; auto scale = $scale;
$animation.step(scale, frame_rect); $animation.step(scale, frame_rect);
$boss_image.sprite->setScale(scale); $boss_image.sprite->setScale(scale);
@ -76,8 +94,8 @@ namespace gui {
sound::play($sounds.attack); sound::play($sounds.attack);
} }
if(!sound::playing("Sword_Hit_2") && $animation.subframe > 1.2 && $animation.subframe < 1.5) { if(!sound::playing($weapon_hit_sound) && $animation.subframe > 1.2 && $animation.subframe < 1.5) {
sound::play("Sword_Hit_2"); sound::play($weapon_hit_sound);
} }
$boss_image.sprite->setTextureRect(frame_rect); $boss_image.sprite->setTextureRect(frame_rect);

@ -4,6 +4,7 @@
#include <SFML/Graphics/Font.hpp> #include <SFML/Graphics/Font.hpp>
#include "guecs.hpp" #include "guecs.hpp"
#include "textures.hpp" #include "textures.hpp"
#include "components.hpp"
#include <SFML/System/Clock.hpp> #include <SFML/System/Clock.hpp>
// aspect ratio of art is 3/2 so 1.5 // aspect ratio of art is 3/2 so 1.5
@ -22,15 +23,19 @@ namespace gui {
int $boss_hp = 10; int $boss_hp = 10;
bool $boss_hit = false; bool $boss_hit = false;
sf::Vector2f $scale{0.8, 0.8}; sf::Vector2f $scale{0.8, 0.8};
std::string $weapon_hit_sound;
components::Sprite $sprite_config;
components::Sound $sounds; components::Sound $sounds;
components::Animation $animation; components::Animation $animation;
GameLevel $level; GameLevel $level;
components::GameConfig& $config;
std::string $boss_name;
guecs::UI $status; guecs::UI $status;
guecs::UI $overlay; guecs::UI $overlay;
textures::SpriteTexture $boss_image; textures::SpriteTexture $boss_image;
textures::SpriteTexture $boss_background; textures::SpriteTexture $boss_background;
BossFightUI(GameLevel level); BossFightUI(GameLevel level, std::string boss_name);
void init(); void init();
void render(sf::RenderWindow& window); void render(sf::RenderWindow& window);
@ -38,5 +43,8 @@ namespace gui {
void bounce_boss(sf::RenderWindow& window); void bounce_boss(sf::RenderWindow& window);
bool boss_dead() { return $boss_hp < 0; } bool boss_dead() { return $boss_hp < 0; }
void update_level(GameLevel& level); void update_level(GameLevel& level);
void configure_sprite();
void configure_background();
void configure_gui();
}; };
} }

@ -46,6 +46,7 @@ namespace components {
Config items; Config items;
Config tiles; Config tiles;
Config devices; Config devices;
Config bosses;
}; };
struct EnemyConfig { struct EnemyConfig {
@ -91,6 +92,8 @@ namespace components {
struct Sprite { struct Sprite {
string name; string name;
int width;
int height;
}; };
struct Sound { struct Sound {
@ -118,7 +121,7 @@ namespace components {
template <typename T> struct NameOf; template <typename T> struct NameOf;
ENROLL_COMPONENT(Tile, display, foreground, background); ENROLL_COMPONENT(Tile, display, foreground, background);
ENROLL_COMPONENT(Sprite, name); ENROLL_COMPONENT(Sprite, name, width, height);
ENROLL_COMPONENT(Curative, hp); ENROLL_COMPONENT(Curative, hp);
ENROLL_COMPONENT(LightSource, strength, radius); ENROLL_COMPONENT(LightSource, strength, radius);
ENROLL_COMPONENT(Weapon, damage); ENROLL_COMPONENT(Weapon, damage);

@ -11,6 +11,12 @@ constexpr const int SCREEN_WIDTH=1280;
constexpr const int SCREEN_HEIGHT=720; constexpr const int SCREEN_HEIGHT=720;
constexpr const int RAY_VIEW_X=(SCREEN_WIDTH - RAY_VIEW_WIDTH); constexpr const int RAY_VIEW_X=(SCREEN_WIDTH - RAY_VIEW_WIDTH);
constexpr const int RAY_VIEW_Y=0; constexpr const int RAY_VIEW_Y=0;
constexpr const int BOSS_VIEW_WIDTH=1080;
constexpr const int BOSS_VIEW_HEIGHT=SCREEN_HEIGHT;
constexpr const int BOSS_VIEW_X=SCREEN_WIDTH - BOSS_VIEW_WIDTH;
constexpr const int BOSS_VIEW_Y=0;
constexpr const bool VSYNC=false; constexpr const bool VSYNC=false;
constexpr const int FRAME_LIMIT=60; constexpr const int FRAME_LIMIT=60;
constexpr const int NUM_SPRITES=1; constexpr const int NUM_SPRITES=1;

@ -20,7 +20,7 @@ namespace gui {
$map_ui($level), $map_ui($level),
$combat_ui($level), $combat_ui($level),
$status_ui($level), $status_ui($level),
$boss_fight_ui($level), $boss_fight_ui($level, "RAT_KING"),
$font{FONT_FILE_NAME} $font{FONT_FILE_NAME}
{ {
} }

@ -6,7 +6,7 @@
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
textures::init(); textures::init();
sound::init(); sound::init();
sound::mute(false); sound::mute(true);
gui::FSM main; gui::FSM main;
main.event(gui::Event::STARTED); main.event(gui::Event::STARTED);
Autowalker walker(main); Autowalker walker(main);

@ -35,8 +35,9 @@ void save::load_configs(DinkyECS::World &world) {
Config items("./assets/items.json"); Config items("./assets/items.json");
Config tiles("./assets/tiles.json"); Config tiles("./assets/tiles.json");
Config devices("./assets/devices.json"); Config devices("./assets/devices.json");
Config bosses("./assets/bosses.json");
world.set_the<GameConfig>({ world.set_the<GameConfig>({
game, enemies, items, tiles, devices game, enemies, items, tiles, devices, bosses
}); });
} }

Loading…
Cancel
Save