Started to convert from catch2 to fuc2.
This commit is contained in:
parent
4deda37665
commit
b8b42d5681
10 changed files with 615 additions and 493 deletions
|
|
@ -1,4 +1,3 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
|
||||||
#include "graphics/textures.hpp"
|
#include "graphics/textures.hpp"
|
||||||
#include "algos/dinkyecs.hpp"
|
#include "algos/dinkyecs.hpp"
|
||||||
#include "game/config.hpp"
|
#include "game/config.hpp"
|
||||||
|
|
@ -10,160 +9,176 @@
|
||||||
#include "graphics/animation.hpp"
|
#include "graphics/animation.hpp"
|
||||||
#include "game/sound.hpp"
|
#include "game/sound.hpp"
|
||||||
#include "game/components.hpp"
|
#include "game/components.hpp"
|
||||||
|
#include <fuc2/testing.hpp>
|
||||||
|
|
||||||
using namespace components;
|
using namespace components;
|
||||||
using namespace textures;
|
using namespace textures;
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
using namespace animation;
|
using namespace animation;
|
||||||
|
using namespace fuc2;
|
||||||
|
|
||||||
Animation load_animation(const string& name) {
|
namespace animation_tests {
|
||||||
auto anim = animation::load("assets/animation.json", "rat_king_boss");
|
Animation load_animation(const string& name) {
|
||||||
anim.set_form("attack");
|
auto anim = animation::load("assets/animation.json", "rat_king_boss");
|
||||||
|
anim.set_form("attack");
|
||||||
|
|
||||||
anim.transform.looped = false;
|
anim.transform.looped = false;
|
||||||
|
|
||||||
for(size_t i = 0; i < anim.sequence.durations.size(); i++) {
|
for(size_t i = 0; i < anim.sequence.durations.size(); i++) {
|
||||||
anim.sequence.durations[i] = Random::uniform(1, 5);
|
anim.sequence.durations[i] = Random::uniform(1, 5);
|
||||||
}
|
|
||||||
|
|
||||||
return anim;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FAKE_RENDER() {
|
|
||||||
std::this_thread::sleep_for(Random::milliseconds(5, 32));
|
|
||||||
}
|
|
||||||
|
|
||||||
void PLAY_TEST(Animation &anim) {
|
|
||||||
REQUIRE(anim.transform.looped == false);
|
|
||||||
anim.play();
|
|
||||||
|
|
||||||
while(anim.playing) {
|
|
||||||
anim.update();
|
|
||||||
FAKE_RENDER();
|
|
||||||
}
|
|
||||||
|
|
||||||
REQUIRE(anim.playing == false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Animation is a Sheet + Sequence + Transform.
|
|
||||||
*
|
|
||||||
* A Sheet is just a grid of images with a predefined size for each cell. Arbitrary sized cells not supported.
|
|
||||||
*
|
|
||||||
* A Sequence is a list of Sheet cells _in any order_. See https://github.com/yottahmd/ganim8-lib. Sequences have a timing element for the cells, possibly a list of durations or a single duration.
|
|
||||||
*
|
|
||||||
* A Transform is combinations of scale and/or position easing/motion, shader effects, and things like if it's looped or toggled.
|
|
||||||
*
|
|
||||||
* I like the ganim8 onLoop concept, just a callback that says what to do when the animation has looped.
|
|
||||||
*/
|
|
||||||
TEST_CASE("new animation system", "[animation-new]") {
|
|
||||||
textures::init();
|
|
||||||
sound::init();
|
|
||||||
sound::mute(true);
|
|
||||||
|
|
||||||
auto anim = load_animation("rat_king_boss");
|
|
||||||
PLAY_TEST(anim);
|
|
||||||
|
|
||||||
// test that toggled works
|
|
||||||
anim.transform.toggled = true;
|
|
||||||
PLAY_TEST(anim);
|
|
||||||
REQUIRE(anim.sequence.current == anim.sequence.frames.size() - 1);
|
|
||||||
anim.transform.toggled = false;
|
|
||||||
|
|
||||||
bool onLoop_ran = false;
|
|
||||||
anim.onLoop = [&](auto& seq, auto& tr) -> bool {
|
|
||||||
seq.current = 0;
|
|
||||||
onLoop_ran = true;
|
|
||||||
return tr.looped;
|
|
||||||
};
|
|
||||||
|
|
||||||
PLAY_TEST(anim);
|
|
||||||
REQUIRE(onLoop_ran == true);
|
|
||||||
|
|
||||||
// only runs twice
|
|
||||||
anim.onLoop = [](auto& seq, auto& tr) -> bool {
|
|
||||||
if(seq.loop_count == 2) {
|
|
||||||
seq.current = 0;
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
seq.current = seq.current % seq.frame_count;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
PLAY_TEST(anim);
|
return anim;
|
||||||
REQUIRE(anim.sequence.loop_count == 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("confirm frame sequencing works", "[animation-new]") {
|
|
||||||
textures::init();
|
|
||||||
sound::init();
|
|
||||||
sound::mute(true);
|
|
||||||
|
|
||||||
auto anim = load_animation("rat_king_boss");
|
|
||||||
|
|
||||||
auto boss = textures::get_sprite("rat_king_boss");
|
|
||||||
sf::IntRect init_rect{{0,0}, {anim.sheet.frame_width, anim.sheet.frame_height}};
|
|
||||||
|
|
||||||
anim.play();
|
|
||||||
bool loop_ran = false;
|
|
||||||
|
|
||||||
// this will check that it moved to the next frame
|
|
||||||
anim.onLoop = [&](auto& seq, auto& tr) -> bool {
|
|
||||||
seq.current = 0;
|
|
||||||
loop_ran = true;
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
anim.onFrame = [&](){
|
|
||||||
anim.apply(*boss.sprite);
|
|
||||||
};
|
|
||||||
|
|
||||||
while(anim.playing) {
|
|
||||||
anim.update();
|
|
||||||
FAKE_RENDER();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
REQUIRE(loop_ran == true);
|
void FAKE_RENDER() {
|
||||||
REQUIRE(anim.playing == false);
|
std::this_thread::sleep_for(Random::milliseconds(5, 32));
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("confirm transition changes work", "[animation-new]") {
|
|
||||||
textures::init();
|
|
||||||
sound::init();
|
|
||||||
sound::mute(true);
|
|
||||||
|
|
||||||
auto sprite = *textures::get_sprite("rat_king_boss").sprite;
|
|
||||||
sf::Vector2f pos{100,100};
|
|
||||||
sprite.setPosition(pos);
|
|
||||||
auto scale = sprite.getScale();
|
|
||||||
auto anim = load_animation("rat_king_boss");
|
|
||||||
|
|
||||||
// also testing that onFrame being null means it's not run
|
|
||||||
REQUIRE(anim.onFrame == nullptr);
|
|
||||||
|
|
||||||
anim.play();
|
|
||||||
REQUIRE(anim.playing == true);
|
|
||||||
|
|
||||||
while(anim.playing) {
|
|
||||||
anim.update();
|
|
||||||
anim.motion(sprite, pos, scale);
|
|
||||||
FAKE_RENDER();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
REQUIRE(anim.playing == false);
|
void PLAY_TEST(Animation &anim) {
|
||||||
REQUIRE(pos == sf::Vector2f{100, 100});
|
CHECK(anim.transform.looped == false);
|
||||||
REQUIRE(scale != sf::Vector2f{0,0});
|
anim.play();
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("playing with delta time", "[animation-new]") {
|
while(anim.playing) {
|
||||||
animation::Timer timer;
|
anim.update();
|
||||||
timer.start();
|
FAKE_RENDER();
|
||||||
|
}
|
||||||
|
|
||||||
for(int i = 0; i < 20; i++) {
|
CHECK(anim.playing == false);
|
||||||
FAKE_RENDER();
|
|
||||||
auto [tick_count, alpha] = timer.commit();
|
|
||||||
// fmt::println("tick: {}, alpha: {}", tick_count, alpha);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Animation is a Sheet + Sequence + Transform.
|
||||||
|
*
|
||||||
|
* A Sheet is just a grid of images with a predefined size for each cell. Arbitrary sized cells not supported.
|
||||||
|
*
|
||||||
|
* A Sequence is a list of Sheet cells _in any order_. See https://github.com/yottahmd/ganim8-lib. Sequences have a timing element for the cells, possibly a list of durations or a single duration.
|
||||||
|
*
|
||||||
|
* A Transform is combinations of scale and/or position easing/motion, shader effects, and things like if it's looped or toggled.
|
||||||
|
*
|
||||||
|
* I like the ganim8 onLoop concept, just a callback that says what to do when the animation has looped.
|
||||||
|
*/
|
||||||
|
void test_new_animation_system() {
|
||||||
|
textures::init();
|
||||||
|
sound::init();
|
||||||
|
sound::mute(true);
|
||||||
|
|
||||||
|
auto anim = load_animation("rat_king_boss");
|
||||||
|
PLAY_TEST(anim);
|
||||||
|
|
||||||
|
// test that toggled works
|
||||||
|
anim.transform.toggled = true;
|
||||||
|
PLAY_TEST(anim);
|
||||||
|
CHECK(anim.sequence.current == anim.sequence.frames.size() - 1);
|
||||||
|
anim.transform.toggled = false;
|
||||||
|
|
||||||
|
bool onLoop_ran = false;
|
||||||
|
anim.onLoop = [&](auto& seq, auto& tr) -> bool {
|
||||||
|
seq.current = 0;
|
||||||
|
onLoop_ran = true;
|
||||||
|
return tr.looped;
|
||||||
|
};
|
||||||
|
|
||||||
|
PLAY_TEST(anim);
|
||||||
|
CHECK(onLoop_ran == true);
|
||||||
|
|
||||||
|
// only runs twice
|
||||||
|
anim.onLoop = [](auto& seq, auto& tr) -> bool {
|
||||||
|
if(seq.loop_count == 2) {
|
||||||
|
seq.current = 0;
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
seq.current = seq.current % seq.frame_count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PLAY_TEST(anim);
|
||||||
|
CHECK(anim.sequence.loop_count == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void test_confirm_frame_sequencing_works() {
|
||||||
|
textures::init();
|
||||||
|
sound::init();
|
||||||
|
sound::mute(true);
|
||||||
|
|
||||||
|
auto anim = load_animation("rat_king_boss");
|
||||||
|
|
||||||
|
auto boss = textures::get_sprite("rat_king_boss");
|
||||||
|
sf::IntRect init_rect{{0,0}, {anim.sheet.frame_width, anim.sheet.frame_height}};
|
||||||
|
|
||||||
|
anim.play();
|
||||||
|
bool loop_ran = false;
|
||||||
|
|
||||||
|
// this will check that it moved to the next frame
|
||||||
|
anim.onLoop = [&](auto& seq, auto& tr) -> bool {
|
||||||
|
seq.current = 0;
|
||||||
|
loop_ran = true;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
anim.onFrame = [&](){
|
||||||
|
anim.apply(*boss.sprite);
|
||||||
|
};
|
||||||
|
|
||||||
|
while(anim.playing) {
|
||||||
|
anim.update();
|
||||||
|
FAKE_RENDER();
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(loop_ran == true);
|
||||||
|
CHECK(anim.playing == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_confirm_transition_changes_work() {
|
||||||
|
textures::init();
|
||||||
|
sound::init();
|
||||||
|
sound::mute(true);
|
||||||
|
|
||||||
|
auto sprite = *textures::get_sprite("rat_king_boss").sprite;
|
||||||
|
sf::Vector2f pos{100,100};
|
||||||
|
sprite.setPosition(pos);
|
||||||
|
auto scale = sprite.getScale();
|
||||||
|
auto anim = load_animation("rat_king_boss");
|
||||||
|
|
||||||
|
// also testing that onFrame being null means it's not run
|
||||||
|
CHECK(anim.onFrame == nullptr);
|
||||||
|
|
||||||
|
anim.play();
|
||||||
|
CHECK(anim.playing == true);
|
||||||
|
|
||||||
|
while(anim.playing) {
|
||||||
|
anim.update();
|
||||||
|
anim.motion(sprite, pos, scale);
|
||||||
|
FAKE_RENDER();
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(anim.playing == false);
|
||||||
|
CHECK(pos == sf::Vector2f{100, 100});
|
||||||
|
CHECK(scale != sf::Vector2f{0,0});
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_playing_with_delta_time() {
|
||||||
|
animation::Timer timer;
|
||||||
|
timer.start();
|
||||||
|
|
||||||
|
for(int i = 0; i < 20; i++) {
|
||||||
|
FAKE_RENDER();
|
||||||
|
auto [tick_count, alpha] = timer.commit();
|
||||||
|
// fmt::println("tick: {}, alpha: {}", tick_count, alpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fuc2::Set TESTS{
|
||||||
|
.name="ai functionality",
|
||||||
|
.tests={
|
||||||
|
TEST(test_new_animation_system),
|
||||||
|
TEST(test_confirm_frame_sequencing_works),
|
||||||
|
TEST(test_confirm_transition_changes_work),
|
||||||
|
TEST(test_playing_with_delta_time),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,18 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <fuc2/testing.hpp>
|
||||||
|
|
||||||
using namespace fmt;
|
using namespace fuc2;
|
||||||
|
|
||||||
TEST_CASE("base test", "[base]") {
|
namespace base_tests {
|
||||||
REQUIRE(1 == 1);
|
void test_base_test() {
|
||||||
|
CHECK(1 == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fuc2::Set TESTS{
|
||||||
|
.name="base template",
|
||||||
|
.tests={
|
||||||
|
TEST(test_base_test),
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
203
tests/battle.cpp
203
tests/battle.cpp
|
|
@ -1,4 +1,3 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include "game/rituals.hpp"
|
#include "game/rituals.hpp"
|
||||||
|
|
@ -11,134 +10,146 @@
|
||||||
#include "game/components.hpp"
|
#include "game/components.hpp"
|
||||||
#include "ai/ai.hpp"
|
#include "ai/ai.hpp"
|
||||||
#include "graphics/palette.hpp"
|
#include "graphics/palette.hpp"
|
||||||
|
#include <fuc2/testing.hpp>
|
||||||
|
|
||||||
using namespace combat;
|
using namespace combat;
|
||||||
using namespace boss;
|
using namespace boss;
|
||||||
using namespace components;
|
using namespace components;
|
||||||
|
using namespace fuc2;
|
||||||
|
|
||||||
TEST_CASE("battle operations fantasy", "[fail]") {
|
namespace battle_tests {
|
||||||
ai::reset();
|
void test_battle_operations_fantasy() {
|
||||||
ai::init("ai");
|
ai::reset();
|
||||||
|
ai::init("ai");
|
||||||
|
|
||||||
auto ai_start = ai::load_state("Enemy::initial_state");
|
auto ai_start = ai::load_state("Enemy::initial_state");
|
||||||
auto ai_goal = ai::load_state("Enemy::final_state");
|
auto ai_goal = ai::load_state("Enemy::final_state");
|
||||||
auto host_start = ai::load_state("Host::initial_state");
|
auto host_start = ai::load_state("Host::initial_state");
|
||||||
auto host_goal = ai::load_state("Host::final_state");
|
auto host_goal = ai::load_state("Host::final_state");
|
||||||
BattleEngine battle;
|
BattleEngine battle;
|
||||||
|
|
||||||
DinkyECS::Entity host = 0;
|
DinkyECS::Entity host = 0;
|
||||||
ai::EntityAI host_ai("Host::actions", host_start, host_goal);
|
ai::EntityAI host_ai("Host::actions", host_start, host_goal);
|
||||||
components::Combat host_combat{
|
components::Combat host_combat{
|
||||||
.hp=100, .max_hp=100, .ap_delta=6, .max_ap=12, .damage=20};
|
.hp=100, .max_hp=100, .ap_delta=6, .max_ap=12, .damage=20};
|
||||||
battle.add_enemy({host, &host_ai, &host_combat, true});
|
battle.add_enemy({host, &host_ai, &host_combat, true});
|
||||||
|
|
||||||
DinkyECS::Entity axe_ranger = 1;
|
DinkyECS::Entity axe_ranger = 1;
|
||||||
ai::EntityAI axe_ai("Enemy::actions", ai_start, ai_goal);
|
ai::EntityAI axe_ai("Enemy::actions", ai_start, ai_goal);
|
||||||
components::Combat axe_combat{
|
components::Combat axe_combat{
|
||||||
.hp=20, .max_hp=20, .ap_delta=8, .max_ap=12, .damage=20};
|
.hp=20, .max_hp=20, .ap_delta=8, .max_ap=12, .damage=20};
|
||||||
battle.add_enemy({axe_ranger, &axe_ai, &axe_combat});
|
battle.add_enemy({axe_ranger, &axe_ai, &axe_combat});
|
||||||
|
|
||||||
DinkyECS::Entity rat = 2;
|
DinkyECS::Entity rat = 2;
|
||||||
ai::EntityAI rat_ai("Enemy::actions", ai_start, ai_goal);
|
ai::EntityAI rat_ai("Enemy::actions", ai_start, ai_goal);
|
||||||
components::Combat rat_combat{
|
components::Combat rat_combat{
|
||||||
.hp=10, .max_hp=10, .ap_delta=2, .max_ap=10, .damage=10};
|
.hp=10, .max_hp=10, .ap_delta=2, .max_ap=10, .damage=10};
|
||||||
battle.add_enemy({rat, &rat_ai, &rat_combat});
|
battle.add_enemy({rat, &rat_ai, &rat_combat});
|
||||||
|
|
||||||
battle.set_all("enemy_found", true);
|
battle.set_all("enemy_found", true);
|
||||||
battle.set_all("in_combat", true);
|
battle.set_all("in_combat", true);
|
||||||
battle.set_all("tough_personality", true);
|
battle.set_all("tough_personality", true);
|
||||||
battle.set_all("health_good", true);
|
battle.set_all("health_good", true);
|
||||||
|
|
||||||
battle.set(rat, "tough_personality", false);
|
battle.set(rat, "tough_personality", false);
|
||||||
battle.set(host, "have_healing", false);
|
battle.set(host, "have_healing", false);
|
||||||
battle.set(host, "tough_personality", false);
|
battle.set(host, "tough_personality", false);
|
||||||
|
|
||||||
int host_combat_loop = 0;
|
int host_combat_loop = 0;
|
||||||
for(host_combat_loop = 0; host_combat_loop < 1000; host_combat_loop++) {
|
for(host_combat_loop = 0; host_combat_loop < 1000; host_combat_loop++) {
|
||||||
if(host_combat.is_dead()) break;
|
if(host_combat.is_dead()) break;
|
||||||
battle.set(host, "health_good", host_combat.hp > 20);
|
battle.set(host, "health_good", host_combat.hp > 20);
|
||||||
|
|
||||||
battle.player_request("use_healing");
|
battle.player_request("use_healing");
|
||||||
battle.player_request("kill_enemy");
|
battle.player_request("kill_enemy");
|
||||||
|
|
||||||
battle.ap_refresh();
|
battle.ap_refresh();
|
||||||
battle.plan();
|
battle.plan();
|
||||||
int battle_count = 0;
|
int battle_count = 0;
|
||||||
|
|
||||||
for(int battle_count = 0; battle_count < 1000; battle_count++) {
|
for(int battle_count = 0; battle_count < 1000; battle_count++) {
|
||||||
auto act = battle.next();
|
auto act = battle.next();
|
||||||
if(!act) break;
|
if(!act) break;
|
||||||
|
|
||||||
auto& [enemy, wants_to, cost, enemy_state] = *act;
|
auto& [enemy, wants_to, cost, enemy_state] = *act;
|
||||||
|
|
||||||
// fmt::println(">>>>> entity: {} wants to {} cost={}; has {} HP; {} ap",
|
// fmt::println(">>>>> entity: {} wants to {} cost={}; has {} HP; {} ap",
|
||||||
// enemy.entity, wants_to,
|
// enemy.entity, wants_to,
|
||||||
// cost, enemy.combat->hp,
|
// cost, enemy.combat->hp,
|
||||||
// enemy.combat->ap);
|
// enemy.combat->ap);
|
||||||
|
|
||||||
switch(enemy_state) {
|
switch(enemy_state) {
|
||||||
case BattleHostState::agree:
|
case BattleHostState::agree:
|
||||||
// fmt::println("HOST and PLAYER requests match {}, doing it.", wants_to);
|
// fmt::println("HOST and PLAYER requests match {}, doing it.", wants_to);
|
||||||
break;
|
break;
|
||||||
case BattleHostState::disagree:
|
case BattleHostState::disagree:
|
||||||
// fmt::println("REBELIOUS ACT: {}", wants_to);
|
// fmt::println("REBELIOUS ACT: {}", wants_to);
|
||||||
battle.clear_requests();
|
battle.clear_requests();
|
||||||
REQUIRE(battle.$player_requests.size() == 0);
|
CHECK(battle.$player_requests.size() == 0);
|
||||||
break;
|
break;
|
||||||
case BattleHostState::not_host:
|
case BattleHostState::not_host:
|
||||||
if(wants_to == "kill_enemy") {
|
if(wants_to == "kill_enemy") {
|
||||||
enemy.combat->attack(host_combat);
|
enemy.combat->attack(host_combat);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BattleHostState::out_of_ap:
|
case BattleHostState::out_of_ap:
|
||||||
// fmt::println("ENEMY OUT OF AP");
|
// fmt::println("ENEMY OUT OF AP");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CHECK(!battle.next());
|
||||||
|
dbc::check(battle_count < 1000, "infinite battle loop");
|
||||||
}
|
}
|
||||||
|
|
||||||
REQUIRE(!battle.next());
|
dbc::check(host_combat_loop < 1000, "infinite host combat loop, host won't die!");
|
||||||
dbc::check(battle_count < 1000, "infinite battle loop");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dbc::check(host_combat_loop < 1000, "infinite host combat loop, host won't die!");
|
void test_boss_systems_work() {
|
||||||
}
|
components::init();
|
||||||
|
gui::Backend backend;
|
||||||
|
guecs::init(&backend);
|
||||||
|
|
||||||
TEST_CASE("boss/systems.cpp works", "[combat-battle]") {
|
ai::reset();
|
||||||
components::init();
|
ai::init("ai");
|
||||||
gui::Backend backend;
|
GameDB::init();
|
||||||
guecs::init(&backend);
|
cinematic::init();
|
||||||
|
auto host = GameDB::the_player();
|
||||||
|
|
||||||
ai::reset();
|
auto fight = System::create_bossfight();
|
||||||
ai::init("ai");
|
auto battle = System::create_battle(fight->$world, fight->$boss_id);
|
||||||
GameDB::init();
|
auto& host_combat = fight->$world->get<Combat>(host);
|
||||||
cinematic::init();
|
|
||||||
auto host = GameDB::the_player();
|
|
||||||
|
|
||||||
auto fight = System::create_bossfight();
|
System::initialize_actor_ai(*fight->$world, fight->$boss_id);
|
||||||
auto battle = System::create_battle(fight->$world, fight->$boss_id);
|
|
||||||
auto& host_combat = fight->$world->get<Combat>(host);
|
|
||||||
|
|
||||||
System::initialize_actor_ai(*fight->$world, fight->$boss_id);
|
// NEED UPDATE STATE
|
||||||
|
battle.set_all("enemy_found", true);
|
||||||
|
battle.set_all("in_combat", true);
|
||||||
|
battle.set_all("tough_personality", true);
|
||||||
|
battle.set_all("health_good", true);
|
||||||
|
|
||||||
// NEED UPDATE STATE
|
battle.ap_refresh();
|
||||||
battle.set_all("enemy_found", true);
|
|
||||||
battle.set_all("in_combat", true);
|
|
||||||
battle.set_all("tough_personality", true);
|
|
||||||
battle.set_all("health_good", true);
|
|
||||||
|
|
||||||
battle.ap_refresh();
|
battle.player_request("kill_enemy");
|
||||||
|
int pending_ap = battle.player_pending_ap();
|
||||||
|
|
||||||
battle.player_request("kill_enemy");
|
CHECK(pending_ap < host_combat.ap);
|
||||||
int pending_ap = battle.player_pending_ap();
|
|
||||||
|
|
||||||
REQUIRE(pending_ap < host_combat.ap);
|
System::plan_battle(battle, fight->$world, fight->$boss_id);
|
||||||
|
|
||||||
System::plan_battle(battle, fight->$world, fight->$boss_id);
|
while(auto action = battle.next()) {
|
||||||
|
dbc::log("ACTION!");
|
||||||
|
System::combat(*action, fight->$world, fight->$boss_id, 0);
|
||||||
|
}
|
||||||
|
|
||||||
while(auto action = battle.next()) {
|
CHECK(host_combat.ap == pending_ap);
|
||||||
dbc::log("ACTION!");
|
|
||||||
System::combat(*action, fight->$world, fight->$boss_id, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
REQUIRE(host_combat.ap == pending_ap);
|
fuc2::Set TESTS{
|
||||||
|
.name="battle tests",
|
||||||
|
.tests={
|
||||||
|
TEST(test_battle_operations_fantasy),
|
||||||
|
TEST(test_boss_systems_work),
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,17 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
|
#include <fuc2/testing.hpp>
|
||||||
|
|
||||||
TEST_CASE("view based camera system", "[camera]") {
|
using namespace fuc2;
|
||||||
REQUIRE(1 == 1);
|
|
||||||
|
namespace camera_tests {
|
||||||
|
void test_view_based_camera_system() {
|
||||||
|
CHECK(1 == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fuc2::Set TESTS{
|
||||||
|
.name="camera tests (EMPTY!)",
|
||||||
|
.tests={
|
||||||
|
TEST(test_view_based_camera_system),
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <fuc2/testing.hpp>
|
||||||
#include "game/components.hpp"
|
#include "game/components.hpp"
|
||||||
#include "algos/dinkyecs.hpp"
|
#include "algos/dinkyecs.hpp"
|
||||||
#include "game/config.hpp"
|
#include "game/config.hpp"
|
||||||
|
|
@ -7,44 +7,56 @@
|
||||||
using namespace components;
|
using namespace components;
|
||||||
using namespace DinkyECS;
|
using namespace DinkyECS;
|
||||||
|
|
||||||
TEST_CASE("confirm component loading works", "[components]") {
|
using namespace fuc2;
|
||||||
std::vector<std::string> test_list{
|
|
||||||
"assets/enemies.json", "assets/items.json", "assets/devices.json"};
|
|
||||||
|
|
||||||
components::init();
|
namespace component_tests {
|
||||||
DinkyECS::World world;
|
void test_confirm_component_loading_works() {
|
||||||
|
std::vector<std::string> test_list{
|
||||||
|
"assets/enemies.json", "assets/items.json", "assets/devices.json"};
|
||||||
|
|
||||||
for(auto test_data : test_list) {
|
components::init();
|
||||||
auto config = settings::get(test_data);
|
DinkyECS::World world;
|
||||||
auto data_list = config.json();
|
|
||||||
|
|
||||||
for(auto& [key, data] : data_list.items()) {
|
for(auto test_data : test_list) {
|
||||||
auto& components = data["components"];
|
auto config = settings::get(test_data);
|
||||||
fmt::println("TEST COMPONENT: {} from file {}", key, test_data);
|
auto data_list = config.json();
|
||||||
auto ent = world.entity();
|
|
||||||
components::configure_entity(world, ent, components);
|
|
||||||
auto tile = components::get<Tile>(components[0]);
|
|
||||||
REQUIRE(tile.display != L' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("make sure json_mods works", "[components]") {
|
for(auto& [key, data] : data_list.items()) {
|
||||||
auto config = settings::get("bosses");
|
auto& components = data["components"];
|
||||||
// this confirms that loading something with an optional
|
fmt::println("TEST COMPONENT: {} from file {}", key, test_data);
|
||||||
// field works with the json conversions in json_mods.hpp
|
auto ent = world.entity();
|
||||||
for(auto& comp_data : config["RAT_KING"]["components"]) {
|
components::configure_entity(world, ent, components);
|
||||||
if(comp_data["_type"] == "AnimatedScene") {
|
auto tile = components::get<Tile>(components[0]);
|
||||||
auto comp = components::convert<components::AnimatedScene>(comp_data);
|
CHECK(tile.display != L' ');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this then confirms everything else about the json conversion
|
void test_make_sure_json_mods_works() {
|
||||||
components::init();
|
auto config = settings::get("bosses");
|
||||||
|
// this confirms that loading something with an optional
|
||||||
|
// field works with the json conversions in json_mods.hpp
|
||||||
|
for(auto& comp_data : config["RAT_KING"]["components"]) {
|
||||||
|
if(comp_data["_type"] == "AnimatedScene") {
|
||||||
|
auto comp = components::convert<components::AnimatedScene>(comp_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DinkyECS::World world;
|
// this then confirms everything else about the json conversion
|
||||||
auto rat_king = world.entity();
|
components::init();
|
||||||
|
|
||||||
components::configure_entity(world, rat_king, config["RAT_KING"]["components"]);
|
DinkyECS::World world;
|
||||||
auto boss = world.get<AnimatedScene>(rat_king);
|
auto rat_king = world.entity();
|
||||||
|
|
||||||
|
components::configure_entity(world, rat_king, config["RAT_KING"]["components"]);
|
||||||
|
auto boss = world.get<AnimatedScene>(rat_king);
|
||||||
|
}
|
||||||
|
|
||||||
|
fuc2::Set TESTS{
|
||||||
|
.name="components",
|
||||||
|
.tests={
|
||||||
|
TEST(test_make_sure_json_mods_works),
|
||||||
|
TEST(test_confirm_component_loading_works),
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,40 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <fuc2/testing.hpp>
|
||||||
#include "game/config.hpp"
|
#include "game/config.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
TEST_CASE("confirm basic config loader ops", "[config]") {
|
using namespace fuc2;
|
||||||
settings::Config::set_base_dir("./");
|
|
||||||
auto config = settings::get("devices");
|
|
||||||
auto data_list = config.json();
|
|
||||||
auto the_keys = config.keys();
|
|
||||||
|
|
||||||
REQUIRE(the_keys.size() > 0);
|
namespace config_tests {
|
||||||
|
void test_confirm_basic_config_loader_ops() {
|
||||||
|
settings::Config::set_base_dir("./");
|
||||||
|
auto config = settings::get("devices");
|
||||||
|
auto data_list = config.json();
|
||||||
|
auto the_keys = config.keys();
|
||||||
|
|
||||||
for(auto& [key, data] : data_list.items()) {
|
CHECK(the_keys.size() > 0);
|
||||||
auto wide1 = config.wstring(key, "name");
|
|
||||||
auto& comps = data["components"];
|
|
||||||
|
|
||||||
for(auto& comp_data : comps) {
|
for(auto& [key, data] : data_list.items()) {
|
||||||
REQUIRE(comp_data.contains("_type"));
|
auto wide1 = config.wstring(key, "name");
|
||||||
|
auto& comps = data["components"];
|
||||||
|
|
||||||
|
for(auto& comp_data : comps) {
|
||||||
|
CHECK(comp_data.contains("_type"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto indexed = settings::get("tests/config_test.json");
|
||||||
|
auto& test_0 = indexed[0];
|
||||||
|
CHECK(test_0["test"] == 0);
|
||||||
|
|
||||||
|
auto& test_1 = indexed[1];
|
||||||
|
CHECK(test_1["test"] == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto indexed = settings::get("tests/config_test.json");
|
fuc2::Set TESTS{
|
||||||
auto& test_0 = indexed[0];
|
.name="config",
|
||||||
REQUIRE(test_0["test"] == 0);
|
.tests={
|
||||||
|
TEST(test_confirm_basic_config_loader_ops),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
auto& test_1 = indexed[1];
|
|
||||||
REQUIRE(test_1["test"] == 1);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,28 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <fuc2/testing.hpp>
|
||||||
#include "dbc.hpp"
|
#include "dbc.hpp"
|
||||||
|
|
||||||
using namespace dbc;
|
using namespace dbc;
|
||||||
|
|
||||||
TEST_CASE("basic feature tests", "[dbc]") {
|
namespace dbc_tests {
|
||||||
log("Logging a message.");
|
void test_basic_dbc_features() {
|
||||||
|
log("Logging a message.");
|
||||||
|
|
||||||
pre("confirm positive cases work", 1 == 1);
|
pre("confirm positive cases work", 1 == 1);
|
||||||
|
|
||||||
pre("confirm positive lambda", [&]{ return 1 == 1;});
|
pre("confirm positive lambda", [&]{ return 1 == 1;});
|
||||||
|
|
||||||
post("confirm positive post", 1 == 1);
|
post("confirm positive post", 1 == 1);
|
||||||
|
|
||||||
post("confirm postitive post with lamdba", [&]{ return 1 == 1;});
|
post("confirm postitive post with lamdba", [&]{ return 1 == 1;});
|
||||||
|
|
||||||
|
check(1 == 1, "one equals 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
fuc2::Set TESTS{
|
||||||
|
.name="dbc",
|
||||||
|
.tests={
|
||||||
|
TEST(test_basic_dbc_features),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
check(1 == 1, "one equals 1");
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <fuc2/testing.hpp>
|
||||||
#include "algos/dinkyecs.hpp"
|
#include "algos/dinkyecs.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
|
|
@ -6,207 +6,224 @@
|
||||||
using namespace fmt;
|
using namespace fmt;
|
||||||
using DinkyECS::Entity;
|
using DinkyECS::Entity;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
using namespace fuc2;
|
||||||
|
|
||||||
struct Point {
|
namespace dinkyecs_tests {
|
||||||
size_t x;
|
struct Point {
|
||||||
size_t y;
|
size_t x;
|
||||||
};
|
size_t y;
|
||||||
|
};
|
||||||
|
|
||||||
struct Player {
|
struct Player {
|
||||||
string name;
|
string name;
|
||||||
Entity eid;
|
Entity eid;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Position {
|
struct Position {
|
||||||
Point location;
|
Point location;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Motion {
|
struct Motion {
|
||||||
int dx;
|
int dx;
|
||||||
int dy;
|
int dy;
|
||||||
bool random=false;
|
bool random=false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Velocity {
|
struct Velocity {
|
||||||
double x, y;
|
double x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Gravity {
|
struct Gravity {
|
||||||
double level;
|
double level;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DaGUI {
|
struct DaGUI {
|
||||||
int event;
|
int event;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Using a function catches instances where I'm not copying
|
* Using a function catches instances where I'm not copying
|
||||||
* the data into the world.
|
* the data into the world.
|
||||||
*/
|
*/
|
||||||
void configure(DinkyECS::World &world, Entity &test) {
|
void configure(DinkyECS::World &world, Entity &test) {
|
||||||
println("---Configuring the base system.");
|
println("---Configuring the base system.");
|
||||||
Entity test2 = world.entity();
|
Entity test2 = world.entity();
|
||||||
|
|
||||||
world.set<Position>(test, {10,20});
|
world.set<Position>(test, {10,20});
|
||||||
world.set<Velocity>(test, {1,2});
|
world.set<Velocity>(test, {1,2});
|
||||||
|
|
||||||
world.set<Position>(test2, {1,1});
|
world.set<Position>(test2, {1,1});
|
||||||
world.set<Velocity>(test2, {9,19});
|
world.set<Velocity>(test2, {9,19});
|
||||||
|
|
||||||
println("---- Setting up the player as a fact in the system.");
|
println("---- Setting up the player as a fact in the system.");
|
||||||
|
|
||||||
auto player_eid = world.entity();
|
auto player_eid = world.entity();
|
||||||
Player player_info{"Zed", player_eid};
|
Player player_info{"Zed", player_eid};
|
||||||
// just set some player info as a fact with the entity id
|
// just set some player info as a fact with the entity id
|
||||||
world.set_the<Player>(player_info);
|
world.set_the<Player>(player_info);
|
||||||
|
|
||||||
world.set<Velocity>(player_eid, {0,0});
|
world.set<Velocity>(player_eid, {0,0});
|
||||||
world.set<Position>(player_eid, {0,0});
|
world.set<Position>(player_eid, {0,0});
|
||||||
|
|
||||||
auto enemy = world.entity();
|
auto enemy = world.entity();
|
||||||
world.set<Velocity>(enemy, {0,0});
|
world.set<Velocity>(enemy, {0,0});
|
||||||
world.set<Position>(enemy, {0,0});
|
world.set<Position>(enemy, {0,0});
|
||||||
|
|
||||||
println("--- Creating facts (singletons)");
|
println("--- Creating facts (singletons)");
|
||||||
world.set_the<Gravity>({0.9});
|
world.set_the<Gravity>({0.9});
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("confirm ECS system works", "[ecs]") {
|
|
||||||
DinkyECS::World world;
|
|
||||||
Entity test = world.entity();
|
|
||||||
|
|
||||||
configure(world, test);
|
|
||||||
|
|
||||||
Position &pos = world.get<Position>(test);
|
|
||||||
REQUIRE(pos.location.x == 10);
|
|
||||||
REQUIRE(pos.location.y == 20);
|
|
||||||
|
|
||||||
Velocity &vel = world.get<Velocity>(test);
|
|
||||||
REQUIRE(vel.x == 1);
|
|
||||||
REQUIRE(vel.y == 2);
|
|
||||||
|
|
||||||
world.query<Position>([](const auto &ent, auto &pos) {
|
|
||||||
REQUIRE(ent > 0);
|
|
||||||
REQUIRE(pos.location.x >= 0);
|
|
||||||
REQUIRE(pos.location.y >= 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
world.query<Velocity>([](const auto &ent, auto &vel) {
|
|
||||||
REQUIRE(ent > 0);
|
|
||||||
REQUIRE(vel.x >= 0);
|
|
||||||
REQUIRE(vel.y >= 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
println("--- Manually get the velocity in position system:");
|
|
||||||
world.query<Position>([&](const auto &ent, auto &pos) {
|
|
||||||
Velocity &vel = world.get<Velocity>(ent);
|
|
||||||
|
|
||||||
REQUIRE(ent > 0);
|
|
||||||
REQUIRE(pos.location.x >= 0);
|
|
||||||
REQUIRE(pos.location.y >= 0);
|
|
||||||
REQUIRE(ent > 0);
|
|
||||||
REQUIRE(vel.x >= 0);
|
|
||||||
REQUIRE(vel.y >= 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
println("--- Query only entities with Position and Velocity:");
|
|
||||||
world.query<Position, Velocity>([&](const auto &ent, auto &pos, auto &vel) {
|
|
||||||
Gravity &grav = world.get_the<Gravity>();
|
|
||||||
REQUIRE(grav.level <= 1.0f);
|
|
||||||
REQUIRE(grav.level > 0.5f);
|
|
||||||
REQUIRE(ent > 0);
|
|
||||||
REQUIRE(pos.location.x >= 0);
|
|
||||||
REQUIRE(pos.location.y >= 0);
|
|
||||||
REQUIRE(ent > 0);
|
|
||||||
REQUIRE(vel.x >= 0);
|
|
||||||
REQUIRE(vel.y >= 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
// now remove Velocity
|
|
||||||
REQUIRE(world.has<Velocity>(test));
|
|
||||||
world.remove<Velocity>(test);
|
|
||||||
REQUIRE_THROWS(world.get<Velocity>(test));
|
|
||||||
REQUIRE(!world.has<Velocity>(test));
|
|
||||||
|
|
||||||
println("--- After remove test, should only result in test2:");
|
|
||||||
world.query<Position, Velocity>([&](const auto &ent, auto &pos, auto &vel) {
|
|
||||||
auto &in_position = world.get<Position>(ent);
|
|
||||||
auto &in_velocity = world.get<Velocity>(ent);
|
|
||||||
REQUIRE(pos.location.x >= 0);
|
|
||||||
REQUIRE(pos.location.y >= 0);
|
|
||||||
REQUIRE(in_position.location.x == pos.location.x);
|
|
||||||
REQUIRE(in_position.location.y == pos.location.y);
|
|
||||||
REQUIRE(in_velocity.x == vel.x);
|
|
||||||
REQUIRE(in_velocity.y == vel.y);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
enum GUIEvent {
|
|
||||||
HIT, MISS
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_CASE("confirm that the event system works", "[ecs]") {
|
|
||||||
DinkyECS::World world;
|
|
||||||
DinkyECS::Entity player = world.entity();
|
|
||||||
|
|
||||||
// this confirms we can send these in a for-loop and get them out
|
|
||||||
int i = 0;
|
|
||||||
for(; i < 10; i++) {
|
|
||||||
world.send<GUIEvent>(GUIEvent::HIT, player, string{"hello"});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// just count down and should get the same number
|
void test_confirm_ECS_system_works() {
|
||||||
while(world.has_event<GUIEvent>()) {
|
DinkyECS::World world;
|
||||||
auto [event, entity, data] = world.recv<GUIEvent>();
|
Entity test = world.entity();
|
||||||
REQUIRE(event == GUIEvent::HIT);
|
|
||||||
REQUIRE(entity == player);
|
configure(world, test);
|
||||||
auto &str_data = std::any_cast<string&>(data);
|
|
||||||
REQUIRE(string{"hello"} == str_data);
|
Position &pos = world.get<Position>(test);
|
||||||
i--;
|
CHECK(pos.location.x == 10);
|
||||||
|
CHECK(pos.location.y == 20);
|
||||||
|
|
||||||
|
Velocity &vel = world.get<Velocity>(test);
|
||||||
|
CHECK(vel.x == 1);
|
||||||
|
CHECK(vel.y == 2);
|
||||||
|
|
||||||
|
world.query<Position>([](const auto &ent, auto &pos) {
|
||||||
|
CHECK(ent > 0);
|
||||||
|
CHECK(pos.location.x >= 0);
|
||||||
|
CHECK(pos.location.y >= 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
world.query<Velocity>([](const auto &ent, auto &vel) {
|
||||||
|
CHECK(ent > 0);
|
||||||
|
CHECK(vel.x >= 0);
|
||||||
|
CHECK(vel.y >= 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
println("--- Manually get the velocity in position system:");
|
||||||
|
world.query<Position>([&](const auto &ent, auto &pos) {
|
||||||
|
Velocity &vel = world.get<Velocity>(ent);
|
||||||
|
|
||||||
|
CHECK(ent > 0);
|
||||||
|
CHECK(pos.location.x >= 0);
|
||||||
|
CHECK(pos.location.y >= 0);
|
||||||
|
CHECK(ent > 0);
|
||||||
|
CHECK(vel.x >= 0);
|
||||||
|
CHECK(vel.y >= 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
println("--- Query only entities with Position and Velocity:");
|
||||||
|
world.query<Position, Velocity>([&](const auto &ent, auto &pos, auto &vel) {
|
||||||
|
Gravity &grav = world.get_the<Gravity>();
|
||||||
|
CHECK(grav.level <= 1.0f);
|
||||||
|
CHECK(grav.level > 0.5f);
|
||||||
|
CHECK(ent > 0);
|
||||||
|
CHECK(pos.location.x >= 0);
|
||||||
|
CHECK(pos.location.y >= 0);
|
||||||
|
CHECK(ent > 0);
|
||||||
|
CHECK(vel.x >= 0);
|
||||||
|
CHECK(vel.y >= 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
// now remove Velocity
|
||||||
|
CHECK(world.has<Velocity>(test));
|
||||||
|
world.remove<Velocity>(test);
|
||||||
|
|
||||||
|
BLOWS_UP([&]() {
|
||||||
|
world.get<Velocity>(test);
|
||||||
|
});
|
||||||
|
|
||||||
|
CHECK(!world.has<Velocity>(test));
|
||||||
|
|
||||||
|
println("--- After remove test, should only result in test2:");
|
||||||
|
world.query<Position, Velocity>([&](const auto &ent, auto &pos, auto &vel) {
|
||||||
|
auto &in_position = world.get<Position>(ent);
|
||||||
|
auto &in_velocity = world.get<Velocity>(ent);
|
||||||
|
CHECK(pos.location.x >= 0);
|
||||||
|
CHECK(pos.location.y >= 0);
|
||||||
|
CHECK(in_position.location.x == pos.location.x);
|
||||||
|
CHECK(in_position.location.y == pos.location.y);
|
||||||
|
CHECK(in_velocity.x == vel.x);
|
||||||
|
CHECK(in_velocity.y == vel.y);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
REQUIRE(i == 0);
|
enum GUIEvent {
|
||||||
}
|
HIT, MISS
|
||||||
|
};
|
||||||
|
|
||||||
TEST_CASE("confirm copying and constants", "[ecs-constants]") {
|
void test_confirm_that_the_event_system_works() {
|
||||||
DinkyECS::World world1;
|
DinkyECS::World world;
|
||||||
|
DinkyECS::Entity player = world.entity();
|
||||||
Player player_info{"Zed", world1.entity()};
|
|
||||||
world1.set_the<Player>(player_info);
|
// this confirms we can send these in a for-loop and get them out
|
||||||
|
int i = 0;
|
||||||
world1.set<Position>(player_info.eid, {10,10});
|
for(; i < 10; i++) {
|
||||||
world1.make_constant(player_info.eid);
|
world.send<GUIEvent>(GUIEvent::HIT, player, string{"hello"});
|
||||||
|
}
|
||||||
DinkyECS::World world2;
|
|
||||||
world1.clone_into(world2);
|
// just count down and should get the same number
|
||||||
|
while(world.has_event<GUIEvent>()) {
|
||||||
auto &test1 = world1.get<Position>(player_info.eid);
|
auto [event, entity, data] = world.recv<GUIEvent>();
|
||||||
auto &test2 = world2.get<Position>(player_info.eid);
|
CHECK(event == GUIEvent::HIT);
|
||||||
|
CHECK(entity == player);
|
||||||
REQUIRE(test2.location.x == test1.location.x);
|
auto &str_data = std::any_cast<string&>(data);
|
||||||
REQUIRE(test2.location.y == test1.location.y);
|
CHECK(string{"hello"} == str_data);
|
||||||
|
i--;
|
||||||
// check for accidental reference
|
}
|
||||||
test1.location.x = 100;
|
|
||||||
REQUIRE(test2.location.x != test1.location.x);
|
CHECK(i == 0);
|
||||||
|
}
|
||||||
// test the facts copy over
|
|
||||||
auto &player2 = world2.get_the<Player>();
|
|
||||||
REQUIRE(player2.eid == player_info.eid);
|
void test_confirm_copying_and_constants() {
|
||||||
}
|
DinkyECS::World world1;
|
||||||
|
|
||||||
TEST_CASE("can destroy all entity", "[ecs-destroy]") {
|
Player player_info{"Zed", world1.entity()};
|
||||||
DinkyECS::World world;
|
world1.set_the<Player>(player_info);
|
||||||
auto entity = world.entity();
|
|
||||||
|
world1.set<Position>(player_info.eid, {10,10});
|
||||||
world.set<Velocity>(entity, {10,10});
|
world1.make_constant(player_info.eid);
|
||||||
world.set<Gravity>(entity, {1});
|
|
||||||
world.set<Motion>(entity, {0,0});
|
DinkyECS::World world2;
|
||||||
|
world1.clone_into(world2);
|
||||||
world.destroy(entity);
|
|
||||||
|
auto &test1 = world1.get<Position>(player_info.eid);
|
||||||
REQUIRE(!world.has<Velocity>(entity));
|
auto &test2 = world2.get<Position>(player_info.eid);
|
||||||
REQUIRE(!world.has<Gravity>(entity));
|
|
||||||
REQUIRE(!world.has<Motion>(entity));
|
CHECK(test2.location.x == test1.location.x);
|
||||||
|
CHECK(test2.location.y == test1.location.y);
|
||||||
|
|
||||||
|
// check for accidental reference
|
||||||
|
test1.location.x = 100;
|
||||||
|
CHECK(test2.location.x != test1.location.x);
|
||||||
|
|
||||||
|
// test the facts copy over
|
||||||
|
auto &player2 = world2.get_the<Player>();
|
||||||
|
CHECK(player2.eid == player_info.eid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_can_destroy_all_entity() {
|
||||||
|
DinkyECS::World world;
|
||||||
|
auto entity = world.entity();
|
||||||
|
|
||||||
|
world.set<Velocity>(entity, {10,10});
|
||||||
|
world.set<Gravity>(entity, {1});
|
||||||
|
world.set<Motion>(entity, {0,0});
|
||||||
|
|
||||||
|
world.destroy(entity);
|
||||||
|
|
||||||
|
CHECK(!world.has<Velocity>(entity));
|
||||||
|
CHECK(!world.has<Gravity>(entity));
|
||||||
|
CHECK(!world.has<Motion>(entity));
|
||||||
|
}
|
||||||
|
|
||||||
|
fuc2::Set TESTS{
|
||||||
|
.name="dinkyecs",
|
||||||
|
.tests={
|
||||||
|
TEST(test_confirm_ECS_system_works),
|
||||||
|
TEST(test_confirm_that_the_event_system_works),
|
||||||
|
TEST(test_confirm_copying_and_constants),
|
||||||
|
TEST(test_can_destroy_all_entity),
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
25
tests/main.cpp
Normal file
25
tests/main.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#include <fuc2/run.hpp>
|
||||||
|
|
||||||
|
using namespace fuc2;
|
||||||
|
|
||||||
|
TEST_SET(ai_tests);
|
||||||
|
TEST_SET(animation_tests);
|
||||||
|
TEST_SET(base_tests);
|
||||||
|
TEST_SET(battle_tests);
|
||||||
|
TEST_SET(camera_tests);
|
||||||
|
TEST_SET(component_tests);
|
||||||
|
TEST_SET(config_tests);
|
||||||
|
TEST_SET(dbc_tests);
|
||||||
|
TEST_SET(dinkyecs_tests);
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
run(ai_tests::TESTS);
|
||||||
|
run(animation_tests::TESTS);
|
||||||
|
run(base_tests::TESTS);
|
||||||
|
run(battle_tests::TESTS);
|
||||||
|
run(camera_tests::TESTS);
|
||||||
|
run(component_tests::TESTS);
|
||||||
|
run(config_tests::TESTS);
|
||||||
|
run(dbc_tests::TESTS);
|
||||||
|
run(dinkyecs_tests::TESTS);
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,4 @@
|
||||||
tests = files(
|
tests = files(
|
||||||
'animation.cpp',
|
|
||||||
'base.cpp',
|
|
||||||
'battle.cpp',
|
|
||||||
'camera.cpp',
|
|
||||||
'components.cpp',
|
|
||||||
'config.cpp',
|
|
||||||
'dbc.cpp',
|
|
||||||
'dinkyecs.cpp',
|
|
||||||
'event_router.cpp',
|
'event_router.cpp',
|
||||||
'fsm.cpp',
|
'fsm.cpp',
|
||||||
'inventory.cpp',
|
'inventory.cpp',
|
||||||
|
|
@ -27,6 +19,14 @@ tests = files(
|
||||||
)
|
)
|
||||||
|
|
||||||
fuc2_tests = files(
|
fuc2_tests = files(
|
||||||
|
'dinkyecs.cpp',
|
||||||
|
'dbc.cpp',
|
||||||
'ai.cpp',
|
'ai.cpp',
|
||||||
|
'animation.cpp',
|
||||||
|
'base.cpp',
|
||||||
|
'battle.cpp',
|
||||||
|
'camera.cpp',
|
||||||
|
'components.cpp',
|
||||||
|
'config.cpp',
|
||||||
'main.cpp'
|
'main.cpp'
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue