diff options
205 files changed, 7498 insertions, 614 deletions
diff --git a/.gitmodules b/.gitmodules index 6e2ae88..8155600 100644 --- a/.gitmodules +++ b/.gitmodules @@ -30,6 +30,3 @@ path = lib/fontconfig url = https://gitlab.freedesktop.org/fontconfig/fontconfig.git shallow = true -[submodule "lib/segvcatch/lib"] - path = lib/segvcatch/lib - url = https://github.com/Plaristote/segvcatch diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index a149487..a94beca 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -3,8 +3,7 @@ cmake_minimum_required(VERSION 3.28) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 20) set(CMAKE_EXPORT_COMPILE_COMMANDS 1) -set(CMAKE_BUILD_TYPE Debug) - +set(CMAKE_BUILD_TYPE Release) project(game C CXX) add_subdirectory(../src crepe) @@ -12,10 +11,109 @@ add_subdirectory(../src crepe) add_executable(main) target_sources(main PUBLIC + # enemy + enemy/BattleScript.cpp + enemy/EnemyPool.cpp + enemy/EnemyBulletScript.cpp + enemy/EnemyBulletSubScene.cpp + enemy/EnemyBulletPool.cpp + enemy/EnemySubScene.cpp + enemy/EnemyScript.cpp + + #background + background/AquariumSubScene.cpp + background/AquariumScript.cpp + background/BackgroundSubScene.cpp + background/ForestParallaxScript.cpp + background/ForestSubScene.cpp + background/HallwaySubScene.cpp + background/StartSubScene.cpp + background/HallwayScript.cpp + + # mainscenes + GameScene.cpp + menus/shop/ShopMenuScene.cpp + menus/shop/ShopLoadScript.cpp + menus/shop/ButtonBuySelectBubbleScript.cpp + menus/shop/ButtonBuySelectBulletScript.cpp + menus/mainmenu/MainMenuScene.cpp + PreviewScene.cpp + main.cpp + + # missile + missile/MissilePool.cpp + missile/MissileScript.cpp + missile/MissileSubScene.cpp + missile/AlertSubScene.cpp + missile/AlertScript.cpp + missile/SpawnEvent.cpp + + #scheduling + scheduler/ObjectsScheduler.cpp + + # Preview + preview/SmokeSubScene.cpp + preview/NpcSubScene.cpp + preview/NpcScript.cpp + preview/PrevPlayerSubScene.cpp + preview/PrevPlayerScript.cpp + preview/PreviewStopRecSubScript.cpp + preview/PreviewStartRecSubScript.cpp + preview/PreviewReplaySubScript.cpp + + # scripts GameScene.cpp MoveCameraManualyScript.cpp StartGameScript.cpp - main.cpp + QuitScript.cpp + + # player + player/PlayerScript.cpp + player/PlayerSubScene.cpp + player/PlayerBulletPool.cpp + player/PlayerBulletScript.cpp + player/PlayerBulletSubScene.cpp + player/PlayerEndScript.cpp + player/PlayerAudioScript.cpp + + # workers + workers/WorkersSubScene.cpp + workers/WorkerScript.cpp + workers/PanicFromPlayerScript.cpp + workers/CollisionScript.cpp + + # menus + menus/BannerSubScene.cpp + menus/ButtonSubScene.cpp + menus/IButtonScript.cpp + menus/ButtonSetShopSubScript.cpp + menus/ButtonSetMainMenuSubScript.cpp + menus/ButtonReplaySubScript.cpp + menus/ButtonNextMainMenuSubScript.cpp + menus/FloatingWindowSubScene.cpp + menus/IFloatingWindowScript.cpp + menus/ButtonShowCreditsSubScript.cpp + menus/mainmenu/ButtonTransitionPreviewSubScript.cpp + menus/mainmenu/ITransitionScript.cpp + menus/mainmenu/TransitionStartSubScript.cpp + menus/mainmenu/CreditsSubScene.cpp + menus/mainmenu/CreditsSubScript.cpp + menus/endgame/EndGameSubScene.cpp + menus/endgame/EndGameSubScript.cpp + + # coins + coins/CoinSubScene.cpp + coins/CoinPoolSubScene.cpp + coins/CoinSystemScript.cpp + coins/CoinScript.cpp + + # hud + hud/HudSubScene.cpp + hud/HudScript.cpp + hud/SpeedScript.cpp + + #random + Random.cpp ) add_subdirectory(background) diff --git a/game/Config.h b/game/Config.h index 350cd02..fc1a561 100644 --- a/game/Config.h +++ b/game/Config.h @@ -1,22 +1,16 @@ #pragma once -#include <crepe/api/Config.h> - -static const crepe::Config ENGINE_CONFIG { - .log { - .level = crepe::Log::Level::DEBUG, - }, - .window_settings { - .window_title = "Jetpack joyride clone", - }, -}; +#include "types.h" static constexpr int SORT_IN_LAY_BACK_BACKGROUND = 3; // For all scenes static constexpr int SORT_IN_LAY_BACKGROUND = 4; // For all scenes static constexpr int SORT_IN_LAY_FORE_BACKGROUND = 5; // For all scenes static constexpr int SORT_IN_LAY_PARTICLES_BACKGROUND = 6; // For all scenes +static constexpr int SORT_IN_LAY_COINS = 7; // Only for GameScene static constexpr int SORT_IN_LAY_OBSTACLES = 8; // Only for GameScene +static constexpr int SORT_IN_LAY_WORKERS_BACK = 9; // Only for GameScene static constexpr int SORT_IN_LAY_PLAYER = 10; // Only for GameScene +static constexpr int SORT_IN_LAY_WORKERS_FRONT = 12; // Only for GameScene static constexpr int SORT_IN_LAY_PARTICLES_FOREGROUND = 15; // Only for GameScene static constexpr int COLL_LAY_BOT_TOP = 1; // Only for GameScene @@ -24,9 +18,43 @@ static constexpr int COLL_LAY_BOT_LOW = 2; // Only for GameScene static constexpr int COLL_LAY_BOT_HIGH = 3; // Only for GameScene static constexpr int COLL_LAY_PLAYER = 4; // Only for GameScene static constexpr int COLL_LAY_WALL_FRAGS = 5; // Only for GameScene +static constexpr int COLL_LAY_ZAPPER = 6; // Only for GameScene +static constexpr int COLL_LAY_LASER = 7; // Only for GameScene +static constexpr int COLL_LAY_MISSILE = 8; // Only for GameScene +static constexpr int COLL_LAY_BULLET = 9; // Only for GameScene +static constexpr int COLL_LAY_ENEMY = 10; // Only for GameScene +static constexpr int COLL_LAY_PLAYER_BULLET = 11; // Only for GameScene -static constexpr int GAME_HEIGHT = 800; // In game units +static constexpr float GAME_HEIGHT = 800; // In game units +static constexpr float HALLWAY_HEIGHT = 475; // In game units -static constexpr int VIEWPORT_X = 1100; // In game units +static constexpr float VIEWPORT_X = 1100; // In game units // 'GAME_HEIGHT' (below) should be replaced by '500' when game development is finished -static constexpr int VIEWPORT_Y = GAME_HEIGHT; // In game units +static constexpr float VIEWPORT_Y = 500; // In game units + +// Font settings +static constexpr const char * FONT = "Jetpackia"; +static constexpr crepe::vec2 FONTOFFSET = {0, 0}; + +// Amount of coins in game +static constexpr const char * TOTAL_COINS_GAME = "total_coins_game"; + +// Amount of coins in current run +static constexpr const char * TOTAL_COINS_RUN = "total_coins_run"; + +// Distance +static constexpr const char * DISTANCE_GAME = "distance_game"; +static constexpr const char * DISTANCE_RUN = "distance_run"; + +// Player config +static constexpr const char * PLAYER_NAME = "player"; +static constexpr int PLAYER_SPEED = 7500; // In game units +static constexpr float PLAYER_GRAVITY_SCALE = 3; // factor +static constexpr float PLAYER_HELP_KICK_SCALE = 0.2; // factor +static constexpr float PLAYER_HELP_KICK_MAX = 0.3; // factor + +static constexpr const char * CAMERA_NAME = "camera"; +// Jetpack particles +static constexpr const char * JETPACK_PARTICLES = "jetpack_particles"; + +static constexpr bool DISABLE_REPLAY = false; diff --git a/game/EngineConfig.h b/game/EngineConfig.h new file mode 100644 index 0000000..6a03a14 --- /dev/null +++ b/game/EngineConfig.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Config.h" + +#include <crepe/api/Config.h> + +static const crepe::Config ENGINE_CONFIG { + .log { + .level = crepe::Log::Level::DEBUG, + }, + .physics { + // this division factor is now the amount of seconds it approximately takes to naturally + // fall from the ceiling to floor + .gravity = HALLWAY_HEIGHT / 0.5, + }, + .window_settings { + .window_title = "Jetpack joyride clone", + }, +}; diff --git a/game/Events.h b/game/Events.h new file mode 100644 index 0000000..cf0be68 --- /dev/null +++ b/game/Events.h @@ -0,0 +1,5 @@ +#pragma once + +#include "api/Event.h" + +struct EndGameEvent : public crepe::Event {}; diff --git a/game/GameScene.cpp b/game/GameScene.cpp index 90a8b58..7803c9d 100644 --- a/game/GameScene.cpp +++ b/game/GameScene.cpp @@ -1,6 +1,33 @@ +#include "GameScene.h" +#include "Config.h" +#include "StartGameScript.h" +#include "coins/CoinPoolSubScene.h" +#include "coins/CoinSystemScript.h" + +#include "background/BackgroundSubScene.h" +#include "enemy/BattleScript.h" +#include "enemy/EnemyBulletPool.h" +#include "enemy/EnemyBulletSubScene.h" +#include "enemy/EnemyPool.h" +#include "enemy/EnemySubScene.h" +#include "hud/HudScript.h" +#include "hud/HudSubScene.h" +#include "hud/SpeedScript.h" +#include "menus/endgame/EndGameSubScene.h" +#include "missile/MissilePool.h" +#include "missile/SpawnEvent.h" +#include "player/PlayerBulletPool.h" +#include "player/PlayerBulletSubScene.h" +#include "player/PlayerSubScene.h" +#include "prefab/ZapperPoolSubScene.h" +#include "scheduler/ObjectsScheduler.h" +#include "workers/WorkersSubScene.h" + #include <cmath> +#include <crepe/api/AI.h> #include <crepe/api/Animator.h> #include <crepe/api/Asset.h> +#include <crepe/api/AudioSource.h> #include <crepe/api/BehaviorScript.h> #include <crepe/api/BoxCollider.h> #include <crepe/api/Camera.h> @@ -14,34 +41,38 @@ #include <crepe/api/Transform.h> #include <crepe/types.h> -#include "GameScene.h" -#include "Config.h" -#include "MoveCameraManualyScript.h" -#include "StartGameScript.h" - -#include "background/BackgroundSubScene.h" -#include "prefab/PlayerObject.h" -#include "prefab/ZapperObject.h" - using namespace crepe; using namespace std; void GameScene::load_scene() { - logf(Log::DEBUG, "Loading (main) GameScene..."); - BackgroundSubScene background(*this); - GameObject camera = new_object("camera", "camera", vec2(650, 0)); + GameObject camera = new_object(CAMERA_NAME, "camera", vec2(650, 0)); camera.add_component<Camera>( ivec2(990, 720), vec2(VIEWPORT_X, VIEWPORT_Y), Camera::Data { - .bg_color = Color::RED, + .bg_color = Color::BLACK, } ); - camera.add_component<BehaviorScript>().set_script<MoveCameraManualyScript>(); - camera.add_component<Rigidbody>(Rigidbody::Data {}); + //camera.add_component<BehaviorScript>().set_script<MoveCameraManualyScript>(); + camera.add_component<BehaviorScript>().set_script<CoinSystemScript>(); + camera.add_component<BehaviorScript>().set_script<HudScript>(); + camera.add_component<BehaviorScript>().set_script<SpeedScript>(); + camera.add_component<BehaviorScript>().set_script<BattleScript>(); + camera.add_component<BehaviorScript>().set_script<MissileSpawnEventHandler>(); + camera.add_component<BehaviorScript>().set_script<ObjectsScheduler>(); - PlayerObject {new_object("player", "player", vec2(-100, 200))}; + camera.add_component<Rigidbody>(Rigidbody::Data {}); + AI & enemy_path_1 = camera.add_component<AI>(400); + enemy_path_1.make_oval_path(100, 100, camera.transform.position, 1.5708, true); + AI & enemy_path_2 = camera.add_component<AI>(400); + enemy_path_2.make_oval_path(100, 100, {0, 0}, 1.5708, true); + AI & enemy_path_3 = camera.add_component<AI>(400); + enemy_path_3.make_oval_path(100, 100, {0, 0}, 1.5708, true); + // camer.add_component<AI> + PlayerSubScene player(*this); + MissilePool missile_pool(*this); + WorkersSubScene workers(*this); GameObject floor = new_object("floor", "game_world", vec2(0, 325)); floor.add_component<Rigidbody>(Rigidbody::Data { @@ -67,10 +98,33 @@ void GameScene::load_scene() { }); ceiling.add_component<BoxCollider>(vec2(INFINITY, 200)); - ZapperObject {new_object("zapper", "zapper", vec2(800, 0))}; + ZapperPoolSubScene {*this}; GameObject start_game_script = new_object("start_game_script", "script", vec2(0, 0)); start_game_script.add_component<BehaviorScript>().set_script<StartGameScript>(); + + //create coin pool + CoinPoolSubScene coin_system; + coin_system.create_coins(*this); + EnemyBulletPool enemy_bullet_pool; + enemy_bullet_pool.create_bullets(*this); + PlayerBulletPool player_bullet_pool; + player_bullet_pool.create_bullets(*this); + EnemyPool enemy_pool; + enemy_pool.create_enemies(*this); + HudSubScene hud; + hud.create(*this); + + GameObject background_music = new_object("background_music", "audio", vec2(0, 0)); + Asset background_music_asset {"asset/music/level.ogg"}; + background_music.add_component<AudioSource>(background_music_asset); + + GameObject boom_audio = new_object("boom_audio", "audio", vec2(0, 0)); + Asset boom_audio_asset {"asset/sfx/window_smash.ogg"}; + boom_audio.add_component<AudioSource>(boom_audio_asset); + + EndGameSubScene endgamewindow; + endgamewindow.create(*this); } string GameScene::get_name() const { return "scene1"; } diff --git a/game/PreviewScene.cpp b/game/PreviewScene.cpp new file mode 100644 index 0000000..d9801a7 --- /dev/null +++ b/game/PreviewScene.cpp @@ -0,0 +1,175 @@ +#include "PreviewScene.h" + +#include "Config.h" +#include "background/BackgroundSubScene.h" +#include "hud/HudScript.h" +#include "hud/HudSubScene.h" +#include "hud/SpeedScript.h" +#include "menus/ButtonSubScene.h" +#include "missile/MissilePool.h" +#include "missile/SpawnEvent.h" +#include "preview/NpcSubScene.h" +#include "preview/PrevPlayerSubScene.h" +#include "preview/SmokeSubScene.h" + +#include "missile/MissileSubScene.h" + +#include <cmath> +#include <crepe/api/Animator.h> +#include <crepe/api/Asset.h> +#include <crepe/api/AudioSource.h> +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/BoxCollider.h> +#include <crepe/api/Camera.h> +#include <crepe/api/Color.h> +#include <crepe/api/Event.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/ParticleEmitter.h> +#include <crepe/api/Rigidbody.h> +#include <crepe/api/Script.h> +#include <crepe/api/Sprite.h> +#include <crepe/api/Transform.h> + +#include <crepe/ValueBroker.h> +#include <crepe/manager/SaveManager.h> +#include <crepe/types.h> +#include <iostream> + +using namespace crepe; +using namespace std; + +void PreviewScene::load_scene() { + + BackgroundSubScene background(*this); + + GameObject camera = new_object("camera", "camera", vec2(650, 0)); + camera.add_component<Camera>( + ivec2(990, 720), vec2(VIEWPORT_X, VIEWPORT_Y), + Camera::Data { + .bg_color = Color::RED, + } + ); + camera.add_component<Rigidbody>(Rigidbody::Data {}); + camera.add_component<BehaviorScript>().set_script<MissileSpawnEventHandler>(); + camera.add_component<BehaviorScript>().set_script<HudScript>(); + camera.add_component<BehaviorScript>().set_script<SpeedScript>(); + + GameObject floor = new_object("floor", "game_world", vec2(0, 325)); + floor.add_component<Rigidbody>(Rigidbody::Data { + .body_type = Rigidbody::BodyType::STATIC, + .collision_layer = COLL_LAY_BOT_TOP, + }); + floor.add_component<BoxCollider>(vec2(INFINITY, 200)); + GameObject floor_low = new_object("floor_low", "game_world", vec2(0, 350)); + floor_low.add_component<Rigidbody>(Rigidbody::Data { + .body_type = Rigidbody::BodyType::STATIC, + .collision_layer = COLL_LAY_BOT_LOW, + }); + floor_low.add_component<BoxCollider>(vec2(INFINITY, 200)); + GameObject floor_high = new_object("floor_high", "game_world", vec2(0, 300)); + floor_high.add_component<Rigidbody>(Rigidbody::Data { + .body_type = Rigidbody::BodyType::STATIC, + .collision_layer = COLL_LAY_BOT_HIGH, + }); + GameObject ceiling = new_object("ceiling", "game_world", vec2(0, -325)); + ceiling.add_component<Rigidbody>(Rigidbody::Data { + .body_type = Rigidbody::BodyType::STATIC, + .collision_layer = COLL_LAY_BOT_TOP, + }); + ceiling.add_component<BoxCollider>(vec2(INFINITY, 200)); + GameObject world = this->new_object("world", "TAG", vec2 {0, 0}, 0, 1); + + world.add_component<Rigidbody>(Rigidbody::Data { + .body_type = Rigidbody::BodyType::STATIC, + .collision_layers = {0}, + }); + + PrevPlayerSubScene player(*this); + NpcSubScene npc(*this); + SmokeSubScene smoke(*this); + MissilePool mpool(*this); + + HudSubScene hud; + hud.create(*this); + + const float Y_POS_BUTTONS = -220; + const float X_POS_BUTTONS = -150; + const float X_POS_BUTTONS_SPACING = 145; + ButtonSubScene button; + button.create( + *this, + ButtonSubScene::Data { + .text = "BACK", + .text_width = 60, + .position = {X_POS_BUTTONS, Y_POS_BUTTONS}, + .script_type = ButtonSubScene::ScriptSelect::NEXT, + .button_type = ButtonSubScene::ButtonSelect::BACK, + .scale = 0.6, + .worldspace = false, + .tag = "Next button", + .sorting_layer_offset = 20, + } + ); + + button.create( + *this, + ButtonSubScene::Data { + .text = "START REC", + .text_width = 130, + .position = {X_POS_BUTTONS + X_POS_BUTTONS_SPACING, Y_POS_BUTTONS}, + .script_type = ButtonSubScene::ScriptSelect::PREVIEW_START, + .button_type = ButtonSubScene::ButtonSelect::LARGE, + .scale = 0.6, + .worldspace = false, + .tag = "Next button", + .sorting_layer_offset = 20, + .btn_side_color = ButtonSubScene::ButtonSideColor::YELLOW, + } + ); + + button.create( + *this, + ButtonSubScene::Data { + .text = "STOP REC", + .text_width = 120, + .position = {X_POS_BUTTONS + X_POS_BUTTONS_SPACING * 2, Y_POS_BUTTONS}, + .script_type = ButtonSubScene::ScriptSelect::PREVIEW_STOP, + .button_type = ButtonSubScene::ButtonSelect::LARGE, + .scale = 0.6, + .worldspace = false, + .tag = "Next button", + .sorting_layer_offset = 20, + .btn_side_color = ButtonSubScene::ButtonSideColor::BLUE, + } + ); + + button.create( + *this, + ButtonSubScene::Data { + .text = "REPLAY", + .text_width = 90, + .position = {X_POS_BUTTONS + X_POS_BUTTONS_SPACING * 3, Y_POS_BUTTONS}, + .script_type = ButtonSubScene::ScriptSelect::PREVIEW_REPLAY, + .button_type = ButtonSubScene::ButtonSelect::LARGE, + .scale = 0.6, + .worldspace = false, + .tag = "Next button", + .sorting_layer_offset = 20, + .btn_side_color = ButtonSubScene::ButtonSideColor::ORANGE, + } + ); + + /* + + for (int i = 0; i < 200; ++i) { + int row = i / 10; + int col = i % 10; + float x = col * 25 + i; + float y = row * 25 - 400; + GameObject game_coin = this->new_object("coin", "coin", vec2 {x, y}, 0, 1); + Coin coin(game_coin, vec2 {0, 0}); + } + */ +} + +string PreviewScene::get_name() const { return "preview scene"; } diff --git a/game/PreviewScene.h b/game/PreviewScene.h new file mode 100644 index 0000000..afe911e --- /dev/null +++ b/game/PreviewScene.h @@ -0,0 +1,11 @@ +#pragma once + +#include <crepe/api/Scene.h> +#include <string> + +class PreviewScene : public crepe::Scene { +public: + void load_scene(); + + std::string get_name() const; +}; diff --git a/game/QuitScript.cpp b/game/QuitScript.cpp new file mode 100644 index 0000000..0c9f55a --- /dev/null +++ b/game/QuitScript.cpp @@ -0,0 +1,21 @@ + + +#include "QuitScript.h" + +#include <crepe/api/Event.h> +#include <crepe/api/KeyCodes.h> + +using namespace crepe; + +bool QuitScript::on_event(const KeyPressEvent & ev) { + if (Keycode::ESCAPE == ev.key) { + trigger_event<ShutDownEvent>(ShutDownEvent {}); + } + return false; +} + +void QuitScript::init() { + subscribe<KeyPressEvent>([this](const KeyPressEvent & ev) -> bool { + return this->on_event(ev); + }); +} diff --git a/game/QuitScript.h b/game/QuitScript.h new file mode 100644 index 0000000..b79a744 --- /dev/null +++ b/game/QuitScript.h @@ -0,0 +1,11 @@ +#pragma once + +#include <crepe/api/Script.h> + +class QuitScript : public crepe::Script { +private: + bool on_event(const crepe::KeyPressEvent & ev); + +public: + void init(); +}; diff --git a/game/Random.cpp b/game/Random.cpp new file mode 100644 index 0000000..64cf1f3 --- /dev/null +++ b/game/Random.cpp @@ -0,0 +1,29 @@ +#include <cstdlib> + +#include "Random.h" + +float Random::f(float upper, float lower) { + float range = upper - lower; + float x = ((float) rand() / (float) (RAND_MAX)) * range; + return x + lower; +} + +double Random::d(double upper, double lower) { + double range = upper - lower; + double x = ((double) rand() / (double) (RAND_MAX)) * range; + return x + lower; +} + +int Random::i(int upper, int lower) { + int range = upper - lower; + int x = rand() % range; + return x + lower; +} + +unsigned Random::u(unsigned upper, unsigned lower) { + unsigned range = upper - lower; + unsigned x = rand() % range; + return x + lower; +} + +bool Random::b() { return rand() % 2; } diff --git a/game/Random.h b/game/Random.h new file mode 100644 index 0000000..94f98d2 --- /dev/null +++ b/game/Random.h @@ -0,0 +1,10 @@ +#pragma once + +class Random { +public: + static float f(float upper = 1.0, float lower = 0.0); + static double d(double upper = 1.0, double lower = 0.0); + static int i(int upper, int lower = 0); + static unsigned u(unsigned upper, unsigned lower = 0); + static bool b(); +}; diff --git a/game/StartGameScript.cpp b/game/StartGameScript.cpp index 1196d47..48055af 100644 --- a/game/StartGameScript.cpp +++ b/game/StartGameScript.cpp @@ -1,6 +1,9 @@ #include "StartGameScript.h" +#include "Config.h" +#include "api/BehaviorScript.h" #include <crepe/api/Animator.h> +#include <crepe/api/AudioSource.h> #include <crepe/api/ParticleEmitter.h> #include <crepe/api/Sprite.h> @@ -9,7 +12,6 @@ using namespace std; void StartGameScript::fixed_update(crepe::duration_t dt) { Transform & player_transform = this->get_components_by_name<Transform>("player").front(); - // Create hole in wall and activate panic lamp if (player_transform.position.x > 75 && !this->created_hole) { Sprite & lamp_sprite = this->get_components_by_name<Sprite>("start_end").back(); @@ -33,6 +35,14 @@ void StartGameScript::fixed_update(crepe::duration_t dt) { emitter.active = true; } + AudioSource & boom_audio + = this->get_components_by_name<AudioSource>("boom_audio").front(); + boom_audio.play(); + + BehaviorScript & player_audio_script + = this->get_components_by_name<BehaviorScript>("player_audio").front(); + player_audio_script.active = true; + this->created_hole = true; } @@ -40,17 +50,21 @@ void StartGameScript::fixed_update(crepe::duration_t dt) { if (player_transform.position.x > 275 && !this->took_jetpack) { Animator & jetpack_stand_anim = this->get_components_by_name<Animator>("start_begin").back(); - // jetpack_stand_anim.next_anim(); + jetpack_stand_anim.next_anim(); Sprite & jetpack_sprite = this->get_components_by_name<Sprite>("player").back(); jetpack_sprite.active = true; + AudioSource & background_music + = this->get_components_by_name<AudioSource>("background_music").front(); + background_music.play(true); + this->took_jetpack = true; } // Start camera movement, enable player jumping and disable this script if (player_transform.position.x > 500) { Rigidbody & rb = this->get_components_by_name<Rigidbody>("camera").front(); - rb.data.linear_velocity = vec2(100, 0); + rb.data.linear_velocity = vec2(PLAYER_SPEED * dt.count(), 0); BehaviorScript & player_script = this->get_components_by_name<BehaviorScript>("player").front(); player_script.active = true; diff --git a/game/background/AquariumScript.cpp b/game/background/AquariumScript.cpp new file mode 100644 index 0000000..e698e3a --- /dev/null +++ b/game/background/AquariumScript.cpp @@ -0,0 +1,26 @@ +#include "AquariumScript.h" + +#include "../Config.h" + +#include <crepe/api/Animator.h> +#include <crepe/api/Sprite.h> +#include <crepe/api/Transform.h> +#include <crepe/types.h> + +using namespace crepe; +using namespace std; + +void AquariumScript::fixed_update(crepe::duration_t dt) { + Transform & trans_cam = this->get_components_by_name<Transform>("camera").front(); + + float cam_left_x = trans_cam.position.x - VIEWPORT_X / 2; + + if (cam_left_x > this->start_x + this->lenght) { + //Move whole background 12000 to the right + RefVector<Transform> trans = this->get_components_by_tag<Transform>("background_aqua"); + for (Transform & tran : trans) { + tran.position.x += 12000; + } + this->start_x += 12000; + } +} diff --git a/game/background/AquariumScript.h b/game/background/AquariumScript.h new file mode 100644 index 0000000..b068628 --- /dev/null +++ b/game/background/AquariumScript.h @@ -0,0 +1,12 @@ +#pragma once + +#include <crepe/api/Script.h> + +class AquariumScript : public crepe::Script { +public: + void fixed_update(crepe::duration_t dt); + +private: + float start_x = 10200; + const float lenght = 3000; +}; diff --git a/game/background/AquariumSubScene.cpp b/game/background/AquariumSubScene.cpp index 8d5202a..2a07daf 100644 --- a/game/background/AquariumSubScene.cpp +++ b/game/background/AquariumSubScene.cpp @@ -4,6 +4,7 @@ #include <crepe/api/Animator.h> #include <crepe/api/GameObject.h> +#include <crepe/api/ParticleEmitter.h> #include <crepe/api/Scene.h> #include <crepe/api/Sprite.h> #include <crepe/types.h> @@ -15,7 +16,7 @@ float AquariumSubScene::create(Scene & scn, float begin_x) { this->add_background(scn, begin_x); GameObject aquarium_begin - = scn.new_object("aquarium_begin", "background", vec2(begin_x, 0)); + = scn.new_object("aquarium_begin", "background_aqua", vec2(begin_x, 0)); Asset aquarium_begin_asset {"asset/background/aquarium/glassTubeFG_1_TVOS.png"}; aquarium_begin.add_component<Sprite>( aquarium_begin_asset, @@ -28,7 +29,7 @@ float AquariumSubScene::create(Scene & scn, float begin_x) { begin_x += 600; GameObject aquarium_middle_1 - = scn.new_object("aquarium_middle", "background", vec2(begin_x, 0)); + = scn.new_object("aquarium_middle", "background_aqua", vec2(begin_x, 0)); Asset aquarium_middle_1_asset {"asset/background/aquarium/glassTubeFG_3_TVOS.png"}; aquarium_middle_1.add_component<Sprite>( aquarium_middle_1_asset, @@ -41,9 +42,12 @@ float AquariumSubScene::create(Scene & scn, float begin_x) { begin_x += 400; this->add_background(scn, begin_x - 200); + this->add_bubbles(aquarium_middle_1, vec2(-400, 300), 2, 0.7f); + this->add_bubbles(aquarium_middle_1, vec2(-100, 300), 4, 1.0f); + this->add_bubbles(aquarium_middle_1, vec2(500, 300), 4, 0.9f); GameObject aquarium_middle_2 - = scn.new_object("aquarium_middle", "background", vec2(begin_x, 0)); + = scn.new_object("aquarium_middle", "background_aqua", vec2(begin_x, 0)); Asset aquarium_middle_2_asset {"asset/background/aquarium/glassTubeFG_3_TVOS.png"}; aquarium_middle_2.add_component<Sprite>( aquarium_middle_2_asset, @@ -55,8 +59,10 @@ float AquariumSubScene::create(Scene & scn, float begin_x) { ); begin_x += 400; + this->add_bubbles(aquarium_middle_2, vec2(300, 300), 2, 0.6f); + GameObject aquarium_middle_3 - = scn.new_object("aquarium_middle", "background", vec2(begin_x, 0)); + = scn.new_object("aquarium_middle", "background_aqua", vec2(begin_x, 0)); Asset aquarium_middle_3_asset {"asset/background/aquarium/glassTubeFG_3_TVOS.png"}; aquarium_middle_3.add_component<Sprite>( aquarium_middle_3_asset, @@ -71,7 +77,7 @@ float AquariumSubScene::create(Scene & scn, float begin_x) { this->add_background(scn, begin_x - 200); GameObject aquarium_middle_4 - = scn.new_object("aquarium_middle", "background", vec2(begin_x, 0)); + = scn.new_object("aquarium_middle", "background_aqua", vec2(begin_x, 0)); Asset aquarium_middle_4_asset {"asset/background/aquarium/glassTubeFG_3_TVOS.png"}; aquarium_middle_4.add_component<Sprite>( aquarium_middle_4_asset, @@ -84,8 +90,11 @@ float AquariumSubScene::create(Scene & scn, float begin_x) { begin_x += 600; this->add_background(scn, begin_x); + this->add_bubbles(aquarium_middle_4, vec2(175, 300), 4, 1.0f); + this->add_bubbles(aquarium_middle_4, vec2(200, 300), 4, 0.7f); - GameObject aquarium_end = scn.new_object("aquarium_end", "background", vec2(begin_x, 0)); + GameObject aquarium_end + = scn.new_object("aquarium_end", "background_aqua", vec2(begin_x, 0)); Asset aquarium_end_asset {"asset/background/aquarium/glassTubeFG_2_TVOS.png"}; aquarium_end.add_component<Sprite>( aquarium_end_asset, @@ -101,13 +110,13 @@ float AquariumSubScene::create(Scene & scn, float begin_x) { } void AquariumSubScene::add_background(Scene & scn, float begin_x) { - GameObject bg_1 = scn.new_object("aquarium_bg_1", "aquarium_background", vec2(begin_x, 0)); + GameObject bg_1 = scn.new_object("aquarium_bg_1", "background_aqua", vec2(begin_x, 0)); Asset bg_1_1_asset {"asset/background/aquarium/AquariumBG1_1_TVOS.png"}; bg_1.add_component<Sprite>( bg_1_1_asset, Sprite::Data { .sorting_in_layer = SORT_IN_LAY_BACK_BACKGROUND, - .order_in_layer = 2, + .order_in_layer = 5, .size = vec2(0, 400), .position_offset = vec2(-200, 100), } @@ -117,18 +126,18 @@ void AquariumSubScene::add_background(Scene & scn, float begin_x) { bg_1_2_asset, Sprite::Data { .sorting_in_layer = SORT_IN_LAY_BACK_BACKGROUND, - .order_in_layer = 2, + .order_in_layer = 5, .size = vec2(0, 400), .position_offset = vec2(200, 100), } ); - GameObject bg_2 = scn.new_object("aquarium_bg_2", "aquarium_background", vec2(begin_x, 0)); + GameObject bg_2 = scn.new_object("aquarium_bg_2", "background_aqua", vec2(begin_x, 0)); Asset bg_2_1_asset {"asset/background/aquarium/AquariumBG2_1_TVOS.png"}; bg_2.add_component<Sprite>( bg_2_1_asset, Sprite::Data { .sorting_in_layer = SORT_IN_LAY_BACK_BACKGROUND, - .order_in_layer = 1, + .order_in_layer = 3, .size = vec2(0, 400), .position_offset = vec2(200, -50), } @@ -138,18 +147,18 @@ void AquariumSubScene::add_background(Scene & scn, float begin_x) { bg_2_2_asset, Sprite::Data { .sorting_in_layer = SORT_IN_LAY_BACK_BACKGROUND, - .order_in_layer = 1, + .order_in_layer = 3, .size = vec2(0, 400), .position_offset = vec2(-200, -50), } ); - GameObject bg_3 = scn.new_object("aquarium_bg_3", "aquarium_background", vec2(begin_x, 0)); + GameObject bg_3 = scn.new_object("aquarium_bg_3", "background_aqua", vec2(begin_x, 0)); Asset bg_3_1_asset {"asset/background/aquarium/AquariumBG3_1_TVOS.png"}; bg_3.add_component<Sprite>( bg_3_1_asset, Sprite::Data { .sorting_in_layer = SORT_IN_LAY_BACK_BACKGROUND, - .order_in_layer = 0, + .order_in_layer = 1, .size = vec2(0, 400), .position_offset = vec2(200, -200), } @@ -159,9 +168,58 @@ void AquariumSubScene::add_background(Scene & scn, float begin_x) { bg_3_2_asset, Sprite::Data { .sorting_in_layer = SORT_IN_LAY_BACK_BACKGROUND, - .order_in_layer = 0, + .order_in_layer = 1, .size = vec2(0, 400), .position_offset = vec2(-200, -200), } ); } + +void AquariumSubScene::add_bubbles( + GameObject & obj, vec2 offset, int order_in_layer, float scale +) { + Sprite & sprite = obj.add_component<Sprite>( + Asset {"asset/background/aquarium/bubble.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_BACK_BACKGROUND, + .order_in_layer = order_in_layer, + .size = vec2(0, 12.5), + .scale_offset = scale, + } + ); + obj.add_component<ParticleEmitter>( + sprite, + ParticleEmitter::Data { + .offset = offset, + .max_particles = 20, + .emission_rate = 1.2, + .min_speed = 50, + .max_speed = 100, + .min_angle = 265, + .max_angle = 275, + .force_over_time = vec2(0, -50), + } + ); + Sprite & sprite_small = obj.add_component<Sprite>( + Asset {"asset/background/aquarium/bubble.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_BACK_BACKGROUND, + .order_in_layer = order_in_layer, + .size = vec2(0, 7.5), + .scale_offset = scale, + } + ); + obj.add_component<ParticleEmitter>( + sprite_small, + ParticleEmitter::Data { + .offset = offset, + .max_particles = 20, + .emission_rate = 0.8, + .min_speed = 50, + .max_speed = 100, + .min_angle = 265, + .max_angle = 275, + .force_over_time = vec2(0, -50), + } + ); +} diff --git a/game/background/AquariumSubScene.h b/game/background/AquariumSubScene.h index 2a188bc..9dbb04e 100644 --- a/game/background/AquariumSubScene.h +++ b/game/background/AquariumSubScene.h @@ -1,8 +1,11 @@ #pragma once +#include <crepe/types.h> + namespace crepe { class Scene; -} +class GameObject; +} // namespace crepe class AquariumSubScene { public: @@ -10,4 +13,6 @@ public: private: void add_background(crepe::Scene & scn, float begin_x); + void + add_bubbles(crepe::GameObject & obj, crepe::vec2 offset, int order_in_layer, float scale); }; diff --git a/game/background/BackgroundSubScene.cpp b/game/background/BackgroundSubScene.cpp index 6fdc598..4bbd977 100644 --- a/game/background/BackgroundSubScene.cpp +++ b/game/background/BackgroundSubScene.cpp @@ -1,10 +1,14 @@ #include "BackgroundSubScene.h" +#include "AquariumScript.h" #include "AquariumSubScene.h" #include "ForestSubScene.h" +#include "HallwayScript.h" #include "HallwaySubScene.h" #include "StartSubScene.h" +#include <crepe/api/BehaviorScript.h> #include <crepe/api/Color.h> +#include <crepe/api/Scene.h> using namespace crepe; using namespace std; @@ -23,15 +27,11 @@ BackgroundSubScene::BackgroundSubScene(Scene & scn) { begin_x = forest.create(scn, begin_x, "1"); - begin_x = hallway.create(scn, begin_x, 2, Color::MAGENTA); + begin_x += 3000; begin_x = aquarium.create(scn, begin_x); - begin_x = hallway.create(scn, begin_x, 3, Color::CYAN); - - begin_x = forest.create(scn, begin_x, "2"); - - begin_x = hallway.create(scn, begin_x, 4, Color::GREEN); - - begin_x = aquarium.create(scn, begin_x); + GameObject scripts = scn.new_object("scrips_background", "background"); + scripts.add_component<BehaviorScript>().set_script<HallwayScript>(); + scripts.add_component<BehaviorScript>().set_script<AquariumScript>(); } diff --git a/game/background/ForestParallaxScript.cpp b/game/background/ForestParallaxScript.cpp index c72f85d..7470da2 100644 --- a/game/background/ForestParallaxScript.cpp +++ b/game/background/ForestParallaxScript.cpp @@ -1,5 +1,7 @@ #include "ForestParallaxScript.h" +#include "../Config.h" + using namespace crepe; using namespace std; @@ -26,4 +28,28 @@ void ForestParallaxScript::fixed_update(crepe::duration_t dt) { t.position.x = begin_x - 400; } } + + //Move whole background 12000 to the right + Transform & trans_cam = this->get_components_by_name<Transform>("camera").front(); + + float cam_left_x = trans_cam.position.x - VIEWPORT_X / 2; + + if (cam_left_x > this->start_x + this->lenght) { + //Move whole background 12000 to the right + RefVector<Transform> trans + = this->get_components_by_tag<Transform>("background_forest"); + for (Transform & tran : trans) { + tran.position.x += 12000; + } + this->start_x += 12000; + + RefVector<Transform> trans_back + = this->get_components_by_tag<Transform>("forest_background"); + for (Transform & tran : trans_back) { + tran.position.x += 12000; + } + + begin_x += 12000; + end_x += 12000; + } } diff --git a/game/background/ForestParallaxScript.h b/game/background/ForestParallaxScript.h index a65a684..d45fdd9 100644 --- a/game/background/ForestParallaxScript.h +++ b/game/background/ForestParallaxScript.h @@ -9,7 +9,9 @@ public: void fixed_update(crepe::duration_t dt); private: - const float begin_x; - const float end_x; + float begin_x; + float end_x; const std::string name; + float start_x = 4200; + const float lenght = 3000; }; diff --git a/game/background/ForestSubScene.cpp b/game/background/ForestSubScene.cpp index a807a36..83e48dd 100644 --- a/game/background/ForestSubScene.cpp +++ b/game/background/ForestSubScene.cpp @@ -15,14 +15,14 @@ using namespace crepe; using namespace std; float ForestSubScene::create(Scene & scn, float begin_x, std::string unique_bg_name) { - GameObject script = scn.new_object("forest_script", "background"); + GameObject script = scn.new_object("forest_script", "background_forest"); script.add_component<BehaviorScript>().set_script<ForestParallaxScript>( begin_x - 400, begin_x + 3000 + 400, unique_bg_name ); this->add_background(scn, begin_x, unique_bg_name); - GameObject begin = scn.new_object("forest_begin", "background", vec2(begin_x, 0)); + GameObject begin = scn.new_object("forest_begin", "background_forest", vec2(begin_x, 0)); Asset begin_asset {"asset/background/forest/forestFG_1_TVOS.png"}; begin.add_component<Sprite>( begin_asset, @@ -36,7 +36,8 @@ float ForestSubScene::create(Scene & scn, float begin_x, std::string unique_bg_n this->add_background(scn, begin_x, unique_bg_name); - GameObject middle_1 = scn.new_object("forest_middle", "background", vec2(begin_x, 0)); + GameObject middle_1 + = scn.new_object("forest_middle", "background_forest", vec2(begin_x, 0)); Asset middle_1_asset {"asset/background/forest/forestFG_3_TVOS.png"}; middle_1.add_component<Sprite>( middle_1_asset, @@ -50,7 +51,8 @@ float ForestSubScene::create(Scene & scn, float begin_x, std::string unique_bg_n this->add_background(scn, begin_x, unique_bg_name); - GameObject middle_2 = scn.new_object("forest_middle", "background", vec2(begin_x, 0)); + GameObject middle_2 + = scn.new_object("forest_middle", "background_forest", vec2(begin_x, 0)); Asset middle_2_asset {"asset/background/forest/forestFG_3_TVOS.png"}; middle_2.add_component<Sprite>( middle_2_asset, @@ -64,7 +66,7 @@ float ForestSubScene::create(Scene & scn, float begin_x, std::string unique_bg_n this->add_background(scn, begin_x, unique_bg_name); - GameObject end = scn.new_object("forest_end", "background", vec2(begin_x, 0)); + GameObject end = scn.new_object("forest_end", "background_forest", vec2(begin_x, 0)); Asset end_asset {"asset/background/forest/forestFG_2_TVOS.png"}; end.add_component<Sprite>( end_asset, diff --git a/game/background/HallwayScript.cpp b/game/background/HallwayScript.cpp new file mode 100644 index 0000000..a5bb94c --- /dev/null +++ b/game/background/HallwayScript.cpp @@ -0,0 +1,70 @@ +#include "HallwayScript.h" + +#include "../Config.h" + +#include <crepe/api/Animator.h> +#include <crepe/api/Sprite.h> +#include <crepe/api/Transform.h> +#include <crepe/types.h> + +using namespace crepe; +using namespace std; + +void HallwayScript::fixed_update(crepe::duration_t dt) { + Transform & trans_cam = this->get_components_by_name<Transform>("camera").front(); + + float cam_left_x = trans_cam.position.x - VIEWPORT_X / 2; + + if (cam_left_x > this->start_x + this->lenght) { + //Move whole background 6000 to the right + RefVector<Transform> trans = this->get_components_by_tag<Transform>("background_hall"); + for (Transform & tran : trans) { + tran.position.x += 6000; + } + this->start_x += 6000; + + //Change sector number + Animator & anim = this->get_components_by_name<Animator>("hallway_begin").front(); + int column = (current_sector - 1) / 4; + int row = (current_sector - 1) % 4; + anim.set_anim(column); + for (int i = 0; i < row; i++) { + anim.next_anim(); + } + RefVector<Sprite> sprites = this->get_components_by_name<Sprite>("hallway_begin"); + switch (current_sector % 7) { + case 0: + sprites[1].get().data.color = Color::YELLOW; + sprites[2].get().data.color = Color::YELLOW; + break; + case 1: + sprites[1].get().data.color = Color::MAGENTA; + sprites[2].get().data.color = Color::MAGENTA; + break; + case 2: + sprites[1].get().data.color = Color::CYAN; + sprites[2].get().data.color = Color::CYAN; + break; + case 3: + sprites[1].get().data.color = Color::GREEN; + sprites[2].get().data.color = Color::GREEN; + break; + case 4: + sprites[1].get().data.color = Color::RED; + sprites[2].get().data.color = Color::RED; + break; + case 5: + sprites[1].get().data.color = Color::BLUE; + sprites[2].get().data.color = Color::BLUE; + break; + case 6: + sprites[1].get().data.color = Color::WHITE; + sprites[2].get().data.color = Color::WHITE; + break; + } + current_sector++; + if (current_sector > 16) { + current_sector = 1; + } + } +} diff --git a/game/background/HallwayScript.h b/game/background/HallwayScript.h new file mode 100644 index 0000000..04b2933 --- /dev/null +++ b/game/background/HallwayScript.h @@ -0,0 +1,13 @@ +#pragma once + +#include <crepe/api/Script.h> + +class HallwayScript : public crepe::Script { +public: + void fixed_update(crepe::duration_t dt); + +private: + float start_x = 1200; + const float lenght = 3000; + int current_sector = 2; +}; diff --git a/game/background/HallwaySubScene.cpp b/game/background/HallwaySubScene.cpp index 9a6654a..31af2d5 100644 --- a/game/background/HallwaySubScene.cpp +++ b/game/background/HallwaySubScene.cpp @@ -14,7 +14,7 @@ using namespace std; float HallwaySubScene::create( Scene & scn, float begin_x, unsigned int sector_num, Color sector_color ) { - GameObject begin = scn.new_object("hallway_begin", "background", vec2(begin_x, 0)); + GameObject begin = scn.new_object("hallway_begin", "background_hall", vec2(begin_x, 0)); Asset begin_asset {"asset/background/hallway/hallway1FG_1_TVOS.png"}; begin.add_component<Sprite>( begin_asset, @@ -30,7 +30,8 @@ float HallwaySubScene::create( this->add_lamp(begin, vec2(330, -120), 11); this->add_lamp(begin, vec2(430, -120), 9); - GameObject middle_1 = scn.new_object("hallway_middle", "background", vec2(begin_x, 0)); + GameObject middle_1 + = scn.new_object("hallway_middle", "background_hall", vec2(begin_x, 0)); Asset middle_asset {"asset/background/hallway/hallway1FG_2_TVOS.png"}; middle_1.add_component<Sprite>( middle_asset, @@ -42,7 +43,8 @@ float HallwaySubScene::create( ); begin_x += 600; - GameObject middle_2 = scn.new_object("hallway_middle", "background", vec2(begin_x, 0)); + GameObject middle_2 + = scn.new_object("hallway_middle", "background_hall", vec2(begin_x, 0)); Asset middle_asset_2 {"asset/background/hallway/hallway1FG_2_TVOS.png"}; middle_2.add_component<Sprite>( middle_asset_2, @@ -54,7 +56,8 @@ float HallwaySubScene::create( ); begin_x += 200; - GameObject middle_3 = scn.new_object("hallway_middle", "background", vec2(begin_x, 0)); + GameObject middle_3 + = scn.new_object("hallway_middle", "background_hall", vec2(begin_x, 0)); Asset middle_asset_3 {"asset/background/hallway/hallway1FG_2_TVOS.png"}; middle_3.add_component<Sprite>( middle_asset_3, @@ -68,7 +71,8 @@ float HallwaySubScene::create( this->add_lamp(middle_3, vec2(0, -120)); - GameObject middle_4 = scn.new_object("hallway_middle", "background", vec2(begin_x, 0)); + GameObject middle_4 + = scn.new_object("hallway_middle", "background_hall", vec2(begin_x, 0)); Asset middle_asset_4 {"asset/background/hallway/hallway1FG_2_TVOS.png"}; middle_4.add_component<Sprite>( middle_asset_4, @@ -80,7 +84,7 @@ float HallwaySubScene::create( ); begin_x += 600; - GameObject end = scn.new_object("hallway_end", "background", vec2(begin_x, 0)); + GameObject end = scn.new_object("hallway_end", "background_hall", vec2(begin_x, 0)); Asset end_asset {"asset/background/hallway/hallway1FG_1_TVOS.png"}; end.add_component<Sprite>( end_asset, @@ -153,6 +157,11 @@ void HallwaySubScene::add_sector_number( Animator & sector_num_anim = obj.add_component<Animator>( sector_num_sprite, ivec2(256, 128), uvec2(4, 4), Animator::Data {} ); - sector_num_anim.data.frame++; + int column = (sector_num - 1) / 4; + int row = (sector_num - 1) % 4; + sector_num_anim.set_anim(column); + for (int i = 0; i < row; i++) { + sector_num_anim.next_anim(); + } sector_num_anim.pause(); } diff --git a/game/background/StartSubScene.cpp b/game/background/StartSubScene.cpp index d68287b..d2d30ea 100644 --- a/game/background/StartSubScene.cpp +++ b/game/background/StartSubScene.cpp @@ -199,8 +199,8 @@ void StartSubScene::create_wall_fragments(crepe::Scene & scn, float begin_x) { ); frag_1_sprite.active = false; Rigidbody & frag_1_rb = frag_1.add_component<Rigidbody>(Rigidbody::Data { - .gravity_scale = 10, - .linear_velocity = vec2(400, 400), + .gravity_scale = 1.0, + .linear_velocity = vec2(400, -400), .linear_velocity_coefficient = vec2(0.5, 0.6), .angular_velocity = 500, .angular_velocity_coefficient = 0.55, @@ -223,8 +223,8 @@ void StartSubScene::create_wall_fragments(crepe::Scene & scn, float begin_x) { ); frag_2_sprite.active = false; Rigidbody & frag_2_rb = frag_2.add_component<Rigidbody>(Rigidbody::Data { - .gravity_scale = 20, - .linear_velocity = vec2(400, 400), + .gravity_scale = 1.0, + .linear_velocity = vec2(400, -400), .linear_velocity_coefficient = vec2(0.35, 0.4), .angular_velocity = 400, .angular_velocity_coefficient = 0.55, @@ -247,8 +247,8 @@ void StartSubScene::create_wall_fragments(crepe::Scene & scn, float begin_x) { ); frag_3_sprite.active = false; Rigidbody & frag_3_rb = frag_3.add_component<Rigidbody>(Rigidbody::Data { - .gravity_scale = 30, - .linear_velocity = vec2(400, 400), + .gravity_scale = 1.0, + .linear_velocity = vec2(400, -400), .linear_velocity_coefficient = vec2(0.3, 0.3), .angular_velocity = 300, .angular_velocity_coefficient = 0.55, @@ -271,8 +271,8 @@ void StartSubScene::create_wall_fragments(crepe::Scene & scn, float begin_x) { ); frag_4_sprite.active = false; Rigidbody & frag_4_rb = frag_4.add_component<Rigidbody>(Rigidbody::Data { - .gravity_scale = 40, - .linear_velocity = vec2(700, 400), + .gravity_scale = 1.0, + .linear_velocity = vec2(700, -400), .linear_velocity_coefficient = vec2(0.2, 0.2), .angular_velocity = 200, .angular_velocity_coefficient = 0.55, @@ -295,8 +295,8 @@ void StartSubScene::create_wall_fragments(crepe::Scene & scn, float begin_x) { ); frag_5_sprite.active = false; Rigidbody & frag_5_rb = frag_5.add_component<Rigidbody>(Rigidbody::Data { - .gravity_scale = 50, - .linear_velocity = vec2(600, 800), + .gravity_scale = 1.0, + .linear_velocity = vec2(600, -800), .linear_velocity_coefficient = vec2(0.25, 0.15), .angular_velocity = 100, .angular_velocity_coefficient = 0.55, @@ -319,8 +319,8 @@ void StartSubScene::create_wall_fragments(crepe::Scene & scn, float begin_x) { ); frag_6_sprite.active = false; Rigidbody & frag_6_rb = frag_6.add_component<Rigidbody>(Rigidbody::Data { - .gravity_scale = 30, - .linear_velocity = vec2(300, 800), + .gravity_scale = 1.0, + .linear_velocity = vec2(300, -800), .linear_velocity_coefficient = vec2(0.35, 0.25), .angular_velocity = 100, .angular_velocity_coefficient = 0.55, @@ -343,8 +343,8 @@ void StartSubScene::create_wall_fragments(crepe::Scene & scn, float begin_x) { ); frag_7_sprite.active = false; Rigidbody & frag_7_rb = frag_7.add_component<Rigidbody>(Rigidbody::Data { - .gravity_scale = 20, - .linear_velocity = vec2(400, 500), + .gravity_scale = 1.0, + .linear_velocity = vec2(400, -500), .linear_velocity_coefficient = vec2(0.45, 0.6), .angular_velocity = 800, .angular_velocity_coefficient = 0.55, @@ -367,8 +367,8 @@ void StartSubScene::create_wall_fragments(crepe::Scene & scn, float begin_x) { ); frag_8_sprite.active = false; Rigidbody & frag_8_rb = frag_8.add_component<Rigidbody>(Rigidbody::Data { - .gravity_scale = 30, - .linear_velocity = vec2(400, 400), + .gravity_scale = 1.0, + .linear_velocity = vec2(400, -400), .linear_velocity_coefficient = vec2(0.5, 0.6), .angular_velocity = 500, .angular_velocity_coefficient = 0.55, @@ -391,8 +391,8 @@ void StartSubScene::create_wall_fragments(crepe::Scene & scn, float begin_x) { ); frag_9_sprite.active = false; Rigidbody & frag_9_rb = frag_9.add_component<Rigidbody>(Rigidbody::Data { - .gravity_scale = 40, - .linear_velocity = vec2(200, 400), + .gravity_scale = 1.0, + .linear_velocity = vec2(200, -400), .linear_velocity_coefficient = vec2(0.5, 0.25), .angular_velocity = 500, .angular_velocity_coefficient = 0.55, @@ -415,8 +415,8 @@ void StartSubScene::create_wall_fragments(crepe::Scene & scn, float begin_x) { ); frag_10_sprite.active = false; Rigidbody & frag_10_rb = frag_10.add_component<Rigidbody>(Rigidbody::Data { - .gravity_scale = 50, - .linear_velocity = vec2(400, 900), + .gravity_scale = 1.0, + .linear_velocity = vec2(400, -900), .linear_velocity_coefficient = vec2(0.35, 0.4), .angular_velocity = 300, .angular_velocity_coefficient = 0.55, @@ -439,8 +439,8 @@ void StartSubScene::create_wall_fragments(crepe::Scene & scn, float begin_x) { ); frag_11_sprite.active = false; Rigidbody & frag_11_rb = frag_11.add_component<Rigidbody>(Rigidbody::Data { - .gravity_scale = 60, - .linear_velocity = vec2(600, 800), + .gravity_scale = 1.0, + .linear_velocity = vec2(600, -800), .linear_velocity_coefficient = vec2(0.3, 0.3), .angular_velocity = 200, .angular_velocity_coefficient = 0.55, @@ -463,8 +463,8 @@ void StartSubScene::create_wall_fragments(crepe::Scene & scn, float begin_x) { ); frag_12_sprite.active = false; Rigidbody & frag_12_rb = frag_12.add_component<Rigidbody>(Rigidbody::Data { - .gravity_scale = 70, - .linear_velocity = vec2(500, 800), + .gravity_scale = 1.0, + .linear_velocity = vec2(500, -800), .linear_velocity_coefficient = vec2(0.25, 0.15), .angular_velocity = 100, .angular_velocity_coefficient = 0.55, diff --git a/game/coins/CoinPoolSubScene.cpp b/game/coins/CoinPoolSubScene.cpp new file mode 100644 index 0000000..f8b5b70 --- /dev/null +++ b/game/coins/CoinPoolSubScene.cpp @@ -0,0 +1,13 @@ +#include "CoinPoolSubScene.h" +#include "CoinSubScene.h" + +using namespace crepe; +using namespace std; + +void CoinPoolSubScene::create_coins(crepe::Scene & scn) { + int amount = 0; + CoinSubScene coin; + while (amount < this->MAXIMUM_AMOUNT) { + amount = coin.create(scn, amount); + } +} diff --git a/game/coins/CoinPoolSubScene.h b/game/coins/CoinPoolSubScene.h new file mode 100644 index 0000000..07626d6 --- /dev/null +++ b/game/coins/CoinPoolSubScene.h @@ -0,0 +1,11 @@ +#pragma once + +#include <crepe/api/Scene.h> + +class CoinPoolSubScene { +public: + void create_coins(crepe::Scene & scn); + +private: + static constexpr int MAXIMUM_AMOUNT = 100; +}; diff --git a/game/coins/CoinScript.cpp b/game/coins/CoinScript.cpp new file mode 100644 index 0000000..514f4de --- /dev/null +++ b/game/coins/CoinScript.cpp @@ -0,0 +1,71 @@ +#include "CoinScript.h" + +#include "manager/SaveManager.h" + +#include "../Config.h" +#include "../hud/HudScript.h" + +#include <crepe/api/Animator.h> +#include <crepe/api/AudioSource.h> +#include <crepe/api/CircleCollider.h> +#include <crepe/api/Sprite.h> + +using namespace crepe; +using namespace std; + +bool CoinScript::on_collision(const CollisionEvent & collisionData) { + if (collisionData.info.other.metadata.tag != "coin") return false; + if (!this->get_components_by_name<Sprite>(collisionData.info.other.metadata.name) + .front() + .get() + .active) + return false; + this->get_components_by_name<Sprite>(collisionData.info.other.metadata.name) + .front() + .get() + .active + = false; + this->get_components_by_name<CircleCollider>(collisionData.info.other.metadata.name) + .front() + .get() + .active + = false; + this->amount++; + + AudioSource & audio = this->get_components_by_id<AudioSource>( + collisionData.info.other.metadata.game_object_id + ) + .front(); + audio.play(); + + this->get_components_by_name<Sprite>(collisionData.info.other.metadata.name) + .back() + .get() + .active + = true; + this->get_components_by_name<Animator>(collisionData.info.other.metadata.name) + .back() + .get() + .active + = true; + + return false; +} + +void CoinScript::init() { + this->subscribe<CollisionEvent>([this](const CollisionEvent & ev) -> bool { + return this->on_collision(ev); + }); +} + +void CoinScript::fixed_update(crepe::duration_t dt) { + this->trigger_event(GetCoinEvent { + .amount_of_coins = this->amount, + }); +} + +bool CoinScript::save() { + SaveManager & savemgr = this->get_save_manager(); + savemgr.set(TOTAL_COINS_RUN, this->amount); + return false; +} diff --git a/game/coins/CoinScript.h b/game/coins/CoinScript.h new file mode 100644 index 0000000..5718025 --- /dev/null +++ b/game/coins/CoinScript.h @@ -0,0 +1,14 @@ +#pragma once + +#include "api/Script.h" + +class CoinScript : public crepe::Script { +public: + void init() override; + void fixed_update(crepe::duration_t dt) override; + bool on_collision(const crepe::CollisionEvent & collisionData); + bool save(); + +private: + int amount = 0; +}; diff --git a/game/coins/CoinSubScene.cpp b/game/coins/CoinSubScene.cpp new file mode 100644 index 0000000..d154819 --- /dev/null +++ b/game/coins/CoinSubScene.cpp @@ -0,0 +1,64 @@ +#include "CoinSubScene.h" + +#include "../Config.h" + +#include <crepe/api/Animator.h> +#include <crepe/api/AudioSource.h> +#include <crepe/api/CircleCollider.h> +#include <crepe/api/Rigidbody.h> +#include <crepe/api/Scene.h> + +using namespace crepe; +using namespace std; + +int CoinSubScene::create(Scene & scn, int coin_counter) { + vec2 size = {20, 20}; + + string unique_name = "coin_" + to_string(coin_counter++); + + GameObject coin = scn.new_object(unique_name.c_str(), "coin", vec2 {650, 0}, 0, 1); + coin.add_component<Rigidbody>(Rigidbody::Data { + .body_type = Rigidbody::BodyType::KINEMATIC, + .kinematic_collision = false, + .collision_layers = {COLL_LAY_PLAYER}, + }); + coin.add_component<CircleCollider>((size.x / 2) - 3).active = false; + crepe::OptionalRef<crepe::Sprite> coin_sprite = coin.add_component<Sprite>( + Asset {"asset/coin/coin1_TVOS.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_COINS, + .order_in_layer = 0, + .size = size, + } + ); + coin_sprite->active = false; + coin.add_component<Animator>( + coin_sprite, ivec2 {32, 32}, uvec2 {8, 1}, + Animator::Data { + .fps = 15, + .looping = true, + } + ); + coin.add_component<AudioSource>(Asset {"asset/sfx/coin_pickup_1.ogg"}).volume = 3; + + Sprite & pick_up = coin.add_component<Sprite>( + Asset {"asset/coin/coinCollect1_TVOS.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_COINS, + .order_in_layer = 1, + .size = size * 2, + } + ); + pick_up.active = false; + coin.add_component<Animator>( + pick_up, ivec2 {64, 64}, uvec2 {5, 1}, + Animator::Data { + .fps = 5, + .looping = false, + } + ) + .active + = false; + + return coin_counter; +} diff --git a/game/coins/CoinSubScene.h b/game/coins/CoinSubScene.h new file mode 100644 index 0000000..7a1c60a --- /dev/null +++ b/game/coins/CoinSubScene.h @@ -0,0 +1,12 @@ +#pragma once + +#include <crepe/api/GameObject.h> + +namespace crepe { +class Scene; +} + +class CoinSubScene { +public: + int create(crepe::Scene & scn, int coin_counter); +}; diff --git a/game/coins/CoinSystemScript.cpp b/game/coins/CoinSystemScript.cpp new file mode 100644 index 0000000..f9816c9 --- /dev/null +++ b/game/coins/CoinSystemScript.cpp @@ -0,0 +1,258 @@ +#include "CoinSystemScript.h" + +#include <random> + +#include <crepe/api/CircleCollider.h> +#include <crepe/api/Metadata.h> +#include <crepe/api/Sprite.h> +#include <crepe/api/Transform.h> + +using namespace crepe; +using namespace std; + +void CoinSystemScript::init() { engine.seed(rd()); } + +void CoinSystemScript::add_location(const crepe::vec2 & location) { + coin_locations.push_back(CoinData(location)); +} + +float CoinSystemScript::preset_1(const vec2 & begin_position) { + vec2 top = {begin_position.x, begin_position.y - (this->ROW_OFFSET_1)}; + vec2 bottom = {begin_position.x, begin_position.y + (this->ROW_OFFSET_1)}; + + // Add locations for the top row + for (int i = 0; i < COLUM_AMOUNT_1; ++i) { + add_location(top); + top.x += this->COLUM_OFFSET_1; + } + + // Add locations for the bottom row + bottom.x += this->COLUM_OFFSET_1 * COLUM_AMOUNT_1; + for (int i = 0; i < COLUM_AMOUNT_1; ++i) { + add_location(bottom); + bottom.x += this->COLUM_OFFSET_1; + } + + // Add locations for the next set of the top row + top.x += this->COLUM_OFFSET_1 * COLUM_AMOUNT_1; + for (int i = 0; i < COLUM_AMOUNT_1; ++i) { + add_location(top); + top.x += this->COLUM_OFFSET_1; + } + + // Add locations for the next set of the bottom row + bottom.x += this->COLUM_OFFSET_1 * COLUM_AMOUNT_1; + for (int i = 0; i < COLUM_AMOUNT_1; ++i) { + add_location(bottom); + bottom.x += this->COLUM_OFFSET_1; + } + + return bottom.x - begin_position.x; +} + +float CoinSystemScript::preset_2(const vec2 & begin_position) { + vec2 top + = {begin_position.x + this->COLUM_OFFSET_2, begin_position.y - this->ROW_OFFSET_2}; + vec2 middle = begin_position; + vec2 bottom + = {begin_position.x + this->COLUM_OFFSET_2, begin_position.y + this->ROW_OFFSET_2}; + + // Add locations for the next set of the bottom row + for (int i = 0; i < COLUM_AMOUNT_2 - 2; ++i) { + add_location(bottom); + bottom.x += this->COLUM_OFFSET_2; + } + + // Add locations for the next set of the middle row + for (int i = 0; i < COLUM_AMOUNT_2; ++i) { + add_location(middle); + middle.x += this->COLUM_OFFSET_2; + } + + // Add locations for the next set of the top row + for (int i = 0; i < COLUM_AMOUNT_2 - 2; ++i) { + add_location(top); + top.x += this->COLUM_OFFSET_2; + } + + return middle.x - begin_position.x; +} + +float CoinSystemScript::preset_3(const vec2 & begin_position) { + vec2 location = {begin_position.x, begin_position.y - (this->ROW_OFFSET_3)}; + + // Add locations for the top row + for (int i = 0; i < COLUM_AMOUNT_3; ++i) { + add_location(location); + location.x += this->COLUM_OFFSET_3; + } + + // Add locations for the bottom row + location.y += this->ROW_OFFSET_3; + location.x += this->COLUM_OFFSET_3; + for (int i = 0; i < COLUM_AMOUNT_3; ++i) { + add_location(location); + location.x += this->COLUM_OFFSET_3; + } + + // Add locations for the next set of the top row + location.y += this->ROW_OFFSET_3; + location.x += this->COLUM_OFFSET_3; + for (int i = 0; i < COLUM_AMOUNT_3; ++i) { + add_location(location); + location.x += this->COLUM_OFFSET_3; + } + + return location.x - begin_position.x; +} + +float CoinSystemScript::preset_4(const vec2 & begin_position) { + vec2 location = {begin_position.x, begin_position.y + (this->ROW_OFFSET_4)}; + + // Add locations for the top row + for (int i = 0; i < COLUM_AMOUNT_4; ++i) { + add_location(location); + location.x += this->COLUM_OFFSET_4; + } + + // Add locations for the bottom row + location.y -= this->ROW_OFFSET_4; + location.x += this->COLUM_OFFSET_4; + for (int i = 0; i < COLUM_AMOUNT_4; ++i) { + add_location(location); + location.x += this->COLUM_OFFSET_4; + } + + // Add locations for the next set of the top row + location.y -= this->ROW_OFFSET_4; + location.x += this->COLUM_OFFSET_4; + for (int i = 0; i < COLUM_AMOUNT_4; ++i) { + add_location(location); + location.x += this->COLUM_OFFSET_4; + } + + return location.x - begin_position.x; +} + +float CoinSystemScript::preset_5(const vec2 & begin_position) { + vec2 location = {begin_position.x, begin_position.y - ROW_OFFSET_5 / 2}; + for (int i = 0; i < COLUM_AMOUNT_5; ++i) { + add_location(location); + location.x += this->COLUM_OFFSET_5; + } + return location.x - begin_position.x; +} + +void CoinSystemScript::frame_update(crepe::duration_t dt) { + this->despawn_coins(); + this->generate_locations(); + this->spawn_coins(); +} + +void CoinSystemScript::despawn_coins() { + // Get the current x-position of the CoinSystem's Transform component + float position = this->get_component<Transform>().position.x; + + // Retrieve all active coin sprites tagged as "coin" + RefVector<Sprite> coin_sprites = this->get_components_by_tag<Sprite>("coin"); + + for (Sprite & coin_sprite : coin_sprites) { + if (!coin_sprite.active) continue; // Skip inactive sprites + + // Retrieve the corresponding Transform, Metadata, and CircleCollider components + Transform & coin_transform + = this->get_components_by_id<Transform>(coin_sprite.game_object_id).front().get(); + Metadata & coin_metadata + = this->get_components_by_id<Metadata>(coin_sprite.game_object_id).front().get(); + CircleCollider & coin_collider + = this->get_components_by_id<CircleCollider>(coin_sprite.game_object_id) + .front() + .get(); + + // Check if the coin is out of bounds based on DESPAWN_DISTANCE + if (coin_transform.position.x < position - this->DESPAWN_DISTANCE) { + // Find the coin in the coin_locations vector using its name + auto it = std::find_if( + coin_locations.begin(), coin_locations.end(), + [&coin_metadata](const CoinData & data) { + return data.name == coin_metadata.name; + } + ); + + // If a match is found, erase it from coin_locations + if (it != coin_locations.end()) { + coin_locations.erase(it); + coin_sprite.active = false; + coin_collider.active = false; + } + } + } +} + +void CoinSystemScript::spawn_coins() { + // Get the current x-position of the CoinSystem's Transform component + float position = this->get_component<Transform>().position.x; + + // Iterate through the list of coin locations + for (auto & coin : coin_locations) { + // Skip this coin if it is already active + if (coin.active) continue; + // Skip this coin if it is not within the defined spawn area + if (coin.start_location.x < this->SPAWN_DISTANCE + position + || coin.start_location.x > this->SPAWN_AREA + this->SPAWN_DISTANCE + position) + continue; + + // Retrieve all sprites tagged as "coin" + RefVector<Sprite> coin_sprites = this->get_components_by_tag<Sprite>("coin"); + + // Check for an available (inactive) coin sprite + for (Sprite & coin_sprite : coin_sprites) { + // Skip this sprite if it is already active + if (coin_sprite.active) continue; + if (coin_sprite.data.order_in_layer == 1) { + coin_sprite.active = false; + continue; + } + + // Found an available (inactive) coin sprite + // Retrieve its associated components + Transform & coin_transform + = this->get_components_by_id<Transform>(coin_sprite.game_object_id) + .front() + .get(); + Metadata & coin_metadata + = this->get_components_by_id<Metadata>(coin_sprite.game_object_id) + .front() + .get(); + CircleCollider & coin_collider + = this->get_components_by_id<CircleCollider>(coin_sprite.game_object_id) + .front() + .get(); + + // Assign data and set active + coin.name = coin_metadata.name; + coin.active = true; + coin_sprite.active = true; + coin_collider.active = true; + coin_transform.position = coin.start_location; + + // Break out of the inner loop since we've assigned this coin to an available sprite + break; + } + } +} + +void CoinSystemScript::generate_locations() { + float position = this->get_component<Transform>().position.x; + if (position + SPAWN_DISTANCE + SYSTEM_POSITION_OFFSET < this->system_position) return; + + std::discrete_distribution<int> dist(weights.begin(), weights.end()); + int selected_index = dist(engine); + + std::uniform_real_distribution<float> space_dist(SPAWN_SPACING_MIN, SPAWN_SPACING_MAX); + float spacing = space_dist(engine); + + // Call the corresponding function and return the new x position + this->system_position += functions[selected_index]({this->system_position, 0}); + this->system_position += spacing; +} diff --git a/game/coins/CoinSystemScript.h b/game/coins/CoinSystemScript.h new file mode 100644 index 0000000..5c94273 --- /dev/null +++ b/game/coins/CoinSystemScript.h @@ -0,0 +1,107 @@ +#pragma once + +#include <random> +#include <string> + +#include <crepe/api/CircleCollider.h> +#include <crepe/api/Script.h> +#include <crepe/api/Sprite.h> +#include <crepe/api/Transform.h> +#include <crepe/types.h> + +class CoinSystemScript : public crepe::Script { +private: + struct CoinData { + crepe::vec2 start_location = {0, 0}; + std::string name = ""; + bool active = false; + CoinData(crepe::vec2 start_location) + : start_location(start_location), + name(""), + active(false) {} + }; + +public: + CoinSystemScript() {}; + void init() override; + void frame_update(crepe::duration_t dt) override; + +private: + void add_location(const crepe::vec2 & location); + void despawn_coins(); + void spawn_coins(); + void generate_locations(); + float preset_1(const crepe::vec2 & begin_position); + float preset_2(const crepe::vec2 & begin_position); + float preset_3(const crepe::vec2 & begin_position); + float preset_4(const crepe::vec2 & begin_position); + float preset_5(const crepe::vec2 & begin_position); + +private: + std::vector<std::function<float(const crepe::vec2 &)>> functions + = {[this](const crepe::vec2 & pos) { return preset_1(pos); }, + [this](const crepe::vec2 & pos) { return preset_2(pos); }, + [this](const crepe::vec2 & pos) { return preset_3(pos); }, + [this](const crepe::vec2 & pos) { return preset_4(pos); }, + [this](const crepe::vec2 & pos) { return preset_5(pos); }}; + std::vector<int> weights = {20, 20, 20, 20, 20}; + std::random_device rd; + std::default_random_engine engine; + float system_position = 1400; + static constexpr float SYSTEM_POSITION_OFFSET = 200; + +private: + static constexpr float SPAWN_SPACING_MIN = 400; + static constexpr float SPAWN_SPACING_MAX = 1000; + static constexpr float SPAWN_DISTANCE = 600; + static constexpr float DESPAWN_DISTANCE = 600; + static constexpr float SPAWN_AREA = 50; + std::vector<CoinData> coin_locations; + +private: + // preset one settings + // ***** ***** + // + // + // + // ***** ***** + static constexpr float ROW_OFFSET_1 = 100; + static constexpr float COLUM_OFFSET_1 = 25; + static constexpr int COLUM_AMOUNT_1 = 5; + +private: + // preset two settings + // + // ******** + // ********** + // ******** + // + static constexpr float ROW_OFFSET_2 = 25; + static constexpr float COLUM_OFFSET_2 = 25; + static constexpr int COLUM_AMOUNT_2 = 10; + // preset three settings + // *** + // + // *** + // + // *** + static constexpr float ROW_OFFSET_3 = 100; + static constexpr float COLUM_OFFSET_3 = 25; + static constexpr int COLUM_AMOUNT_3 = 3; + // preset four settings + // *** + // + // *** + // + // *** + static constexpr float ROW_OFFSET_4 = 100; + static constexpr float COLUM_OFFSET_4 = 25; + static constexpr int COLUM_AMOUNT_4 = 3; + // preset five settings + // + // *** + // + static constexpr float ROW_OFFSET_5 = 25; + static constexpr float COLUM_OFFSET_5 = 25; + static constexpr int COLUM_AMOUNT_5 = 3; +}; diff --git a/game/enemy/BattleScript.cpp b/game/enemy/BattleScript.cpp new file mode 100644 index 0000000..6d96ef6 --- /dev/null +++ b/game/enemy/BattleScript.cpp @@ -0,0 +1,51 @@ +#include "BattleScript.h" +#include "EnemyScript.h" +#include <crepe/api/AI.h> +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/Metadata.h> +using namespace std; +using namespace crepe; + +BattleScript::BattleScript() { engine.seed(rd()); } +void BattleScript::init() { + std::uniform_int_distribution<int> dist(2, 10); + int random_enemy_amount = dist(this->engine); + // this->create_battle(random_enemy_amount); + this->subscribe<BattleStartEvent>([this](const BattleStartEvent & e) -> bool { + return this->create_battle(e); + }); +} +void BattleScript::fixed_update(duration_t dt) { + if (!battle_active) return; + bool enemies_alive = false; + RefVector<BehaviorScript> enemy_scripts + = this->get_components_by_tag<BehaviorScript>("enemy"); + + for (BehaviorScript & script : enemy_scripts) { + if (script.active) { + enemies_alive = true; + } + } + if (!enemies_alive) { + this->battle_active = false; + this->trigger_event<BattleWonEvent>(); + } +} +bool BattleScript::create_battle(const BattleStartEvent & e) { + this->battle_active = true; + RefVector<BehaviorScript> enemy_scripts + = this->get_components_by_tag<BehaviorScript>("enemy"); + std::uniform_real_distribution<float> dist(10, 30); + for (int i = 0; i < e.num_enemies; i++) { + BehaviorScript & script = enemy_scripts[i]; + script.active = true; + this->queue_event<SpawnEnemyEvent>( + SpawnEnemyEvent { + .speed = dist(engine), + .column = i, + }, + script.game_object_id + ); + } + return false; +} diff --git a/game/enemy/BattleScript.h b/game/enemy/BattleScript.h new file mode 100644 index 0000000..ddd0be1 --- /dev/null +++ b/game/enemy/BattleScript.h @@ -0,0 +1,24 @@ +#pragma once + +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/Event.h> +#include <crepe/api/Script.h> +#include <random> +struct BattleWonEvent : public crepe::Event {}; + +struct BattleStartEvent : public crepe::Event { +public: + int num_enemies = 0; +}; +class BattleScript : public crepe::Script { +public: + BattleScript(); + void init() override; + void fixed_update(crepe::duration_t dt) override; + +private: + bool battle_active = false; + std::random_device rd; + std::default_random_engine engine; + bool create_battle(const BattleStartEvent & e); +}; diff --git a/game/enemy/EnemyBulletPool.cpp b/game/enemy/EnemyBulletPool.cpp new file mode 100644 index 0000000..3ee4816 --- /dev/null +++ b/game/enemy/EnemyBulletPool.cpp @@ -0,0 +1,11 @@ +#include "EnemyBulletPool.h" +#include "EnemyBulletSubScene.h" +using namespace std; + +void EnemyBulletPool::create_bullets(crepe::Scene & scn) { + EnemyBulletSubScene bullet; + int amount = 0; + while (amount < this->MAXIMUM_AMOUNT) { + amount = bullet.create(scn, amount); + } +} diff --git a/game/enemy/EnemyBulletPool.h b/game/enemy/EnemyBulletPool.h new file mode 100644 index 0000000..ee53fc4 --- /dev/null +++ b/game/enemy/EnemyBulletPool.h @@ -0,0 +1,11 @@ +#pragma once + +#include <crepe/api/Scene.h> + +class EnemyBulletPool { +public: + void create_bullets(crepe::Scene & scn); + +private: + static constexpr int MAXIMUM_AMOUNT = 20; +}; diff --git a/game/enemy/EnemyBulletScript.cpp b/game/enemy/EnemyBulletScript.cpp new file mode 100644 index 0000000..65c0c23 --- /dev/null +++ b/game/enemy/EnemyBulletScript.cpp @@ -0,0 +1,40 @@ +#include "EnemyBulletScript.h" +#include <crepe/api/Camera.h> +#include <crepe/api/Metadata.h> +#include <crepe/api/Rigidbody.h> +#include <iostream> + +#include "EnemyConfig.h" +using namespace crepe; +using namespace std; +void EnemyBulletScript::init() { + this->subscribe<CollisionEvent>([this](const CollisionEvent & e) -> bool { + return this->on_collide(e); + }); +} +void EnemyBulletScript::fixed_update(crepe::duration_t dt) { + Transform & transform = this->get_component<Transform>(); + Camera & camera = this->get_components_by_name<Camera>("camera").front(); + Transform & cam_transform = this->get_components_by_name<Transform>("camera").front(); + Rigidbody & bullet_body = this->get_component<Rigidbody>(); + //move + transform.position.x += bullet_body.data.linear_velocity.x * dt.count(); + vec2 half_screen = camera.viewport_size / 2; + float despawn_location = cam_transform.position.x - half_screen.x - 50; + if (transform.position.x < despawn_location) { + this->despawn_bullet(); + } +} + +void EnemyBulletScript::despawn_bullet() { + Transform & transform = this->get_component<Transform>(); + Rigidbody & bullet_body = this->get_component<Rigidbody>(); + bullet_body.active = false; + transform.position = ENEMY_BULLET_POOL_LOCATION; +} + +bool EnemyBulletScript::on_collide(const CollisionEvent & e) { + //cout << "collision happened with " << e.info.other.metadata.tag << endl; + this->despawn_bullet(); + return false; +} diff --git a/game/enemy/EnemyBulletScript.h b/game/enemy/EnemyBulletScript.h new file mode 100644 index 0000000..7dab751 --- /dev/null +++ b/game/enemy/EnemyBulletScript.h @@ -0,0 +1,11 @@ +#pragma once +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/Script.h> + +class EnemyBulletScript : public crepe::Script { +public: + void init() override; + void fixed_update(crepe::duration_t dt) override; + bool on_collide(const crepe::CollisionEvent & e); + void despawn_bullet(); +}; diff --git a/game/enemy/EnemyBulletSubScene.cpp b/game/enemy/EnemyBulletSubScene.cpp new file mode 100644 index 0000000..ad2ca9d --- /dev/null +++ b/game/enemy/EnemyBulletSubScene.cpp @@ -0,0 +1,51 @@ +#include <string> + +#include "../Config.h" +#include "EnemyConfig.h" +#include <crepe/api/AI.h> +#include <crepe/api/Animator.h> +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/BoxCollider.h> +#include <crepe/api/CircleCollider.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/Rigidbody.h> +#include <crepe/api/Scene.h> +#include <crepe/api/Sprite.h> + +#include "../Random.h" +#include "EnemyBulletScript.h" +#include "EnemyBulletSubScene.h" +#include "EnemyScript.h" +using namespace crepe; +using namespace std; +int EnemyBulletSubScene::create(Scene & scn, int counter) { + string unique_name = "enemy_bullet_" + to_string(counter++); + GameObject bullet = scn.new_object( + unique_name.c_str(), "enemy_bullet", ENEMY_BULLET_POOL_LOCATION, 0, 1 + ); + + Rigidbody & bullet_body = bullet.add_component<Rigidbody>(Rigidbody::Data { + .gravity_scale = 0, + .body_type = Rigidbody::BodyType::KINEMATIC, + + .linear_velocity = vec2 {-250, 0}, + .kinematic_collision = false, + .collision_layers = {COLL_LAY_MISSILE, COLL_LAY_ZAPPER}, + .collision_layer = COLL_LAY_BULLET + }); + bullet_body.active = false; + BoxCollider & bullet_collider = bullet.add_component<BoxCollider>(vec2(60, 30)); + //bullet_collider.active = false; + Asset bullet_asset {"asset/other_effects/effect_smgbullet_x2.png"}; + Sprite & bullet_sprite = bullet.add_component<Sprite>( + bullet_asset, + Sprite::Data { + .flip = {true, false}, + .sorting_in_layer = SORT_IN_LAY_OBSTACLES, + .order_in_layer = 1, + .size = vec2(60, 0), + } + ); + bullet.add_component<BehaviorScript>().set_script<EnemyBulletScript>(); + return counter; +} diff --git a/game/enemy/EnemyBulletSubScene.h b/game/enemy/EnemyBulletSubScene.h new file mode 100644 index 0000000..ac78ad9 --- /dev/null +++ b/game/enemy/EnemyBulletSubScene.h @@ -0,0 +1,10 @@ +#pragma once + +namespace crepe { +class Scene; +} + +class EnemyBulletSubScene { +public: + int create(crepe::Scene & scn, int counter); +}; diff --git a/game/enemy/EnemyConfig.h b/game/enemy/EnemyConfig.h new file mode 100644 index 0000000..f7b660a --- /dev/null +++ b/game/enemy/EnemyConfig.h @@ -0,0 +1,7 @@ +#pragma once +#include <crepe/types.h> + +//button config +// static constexpr crepe::vec2 PLAYER_BULLET_POOL_LOCATION = {0, -850}; +static constexpr crepe::vec2 ENEMY_BULLET_POOL_LOCATION = {0, -750}; +static constexpr crepe::vec2 ENEMY_POOL_LOCATION = {0, -650}; diff --git a/game/enemy/EnemyPool.cpp b/game/enemy/EnemyPool.cpp new file mode 100644 index 0000000..a7179bf --- /dev/null +++ b/game/enemy/EnemyPool.cpp @@ -0,0 +1,10 @@ +#include "EnemyPool.h" +#include "EnemySubScene.h" +using namespace std; +void EnemyPool::create_enemies(crepe::Scene & scn) { + EnemySubScene enemy; + int amount = 0; + while (amount < this->MAXIMUM_AMOUNT) { + amount = enemy.create(scn, amount); + } +} diff --git a/game/enemy/EnemyPool.h b/game/enemy/EnemyPool.h new file mode 100644 index 0000000..f4d6765 --- /dev/null +++ b/game/enemy/EnemyPool.h @@ -0,0 +1,11 @@ +#pragma once + +#include <crepe/api/Scene.h> + +class EnemyPool { +public: + void create_enemies(crepe::Scene & scn); + +private: + static constexpr int MAXIMUM_AMOUNT = 10; +}; diff --git a/game/enemy/EnemyScript.cpp b/game/enemy/EnemyScript.cpp new file mode 100644 index 0000000..5c03539 --- /dev/null +++ b/game/enemy/EnemyScript.cpp @@ -0,0 +1,122 @@ +#include "EnemyScript.h" +#include "../Config.h" +#include "../Random.h" +#include "EnemyConfig.h" +#include <crepe/api/AI.h> +#include <crepe/api/Animator.h> +#include <crepe/api/AudioSource.h> +#include <crepe/api/BoxCollider.h> +#include <crepe/api/ParticleEmitter.h> +#include <crepe/api/Rigidbody.h> +#include <crepe/api/Transform.h> +#include <crepe/types.h> +#include <random> +using namespace crepe; +using namespace std; +EnemyScript::EnemyScript() { + engine.seed(rd()); + this->last_fired = std::chrono::steady_clock::now(); + this->shot_delay = std::chrono::duration<float>(3 + Random::f(1, 0)); +} +void EnemyScript::init() { + Metadata & meta = this->get_component<Metadata>(); + this->subscribe<SpawnEnemyEvent>( + [this](const SpawnEnemyEvent & e) -> bool { return this->spawn_enemy(e); }, + meta.game_object_id + ); + this->subscribe<CollisionEvent>([this](const CollisionEvent & e) -> bool { + return this->on_collide(e); + }); +}; +void EnemyScript::fixed_update(duration_t dt) { + if (this->alive) { + return; + } + Transform & transform = this->get_component<Transform>(); + Transform & player_transform = this->get_components_by_name<Transform>("player").front(); + Rigidbody & enemy_body = this->get_component<Rigidbody>(); + AI & ai_component = this->get_component<AI>(); + + //transform.position += enemy_body.data.linear_velocity * dt.count(); + float direction_to_player_y = player_transform.position.y - transform.position.y; + float distance_to_player_y = std::abs(direction_to_player_y); + + float adjustment_speed = speed * (distance_to_player_y / MAX_DISTANCE); + + adjustment_speed = std::clamp(adjustment_speed, MIN_SPEED, MAX_SPEED); + // Move the path nodes on the Y-axis + for (vec2 & path_node : ai_component.path) { + path_node.y += (direction_to_player_y > 0 ? 1 : -1) * adjustment_speed * dt.count(); + } + //bullet fire logic: + auto now = std::chrono::steady_clock::now(); + std::chrono::duration<float> elapsed = now - last_fired; + if (elapsed > shot_delay) { + this->shoot(transform.position, 0); + last_fired = now; + this->shot_delay = std::chrono::duration<float>(Random::f(4, 1)); + } +} +bool EnemyScript::spawn_enemy(const SpawnEnemyEvent & e) { + this->speed = e.speed; + AI & ai_component = this->get_component<AI>(); + Transform & transform = this->get_component<Transform>(); + Camera & camera = this->get_components_by_name<Camera>("camera").front(); + Transform & cam_transform = this->get_components_by_name<Transform>("camera").front(); + + vec2 half_screen = camera.viewport_size / 2; + float x_value = cam_transform.position.x + half_screen.x - 50 * (1 + e.column); + uniform_real_distribution<float> dist( + cam_transform.position.y - half_screen.y + 100, + cam_transform.position.y + half_screen.y - 100 + ); + float random_height = dist(engine); + vec2 spawn_location + = {cam_transform.position.x + camera.viewport_size.x / 2 + 100, random_height}; + transform.position = spawn_location; + ai_component.path.clear(); + ai_component.make_oval_path(10, 10, vec2 {x_value, random_height}, 1.5708, true); + ai_component.active = true; + this->last_fired = std::chrono::steady_clock::now(); + return false; +} + +bool EnemyScript::on_collide(const CollisionEvent & e) { + if (e.info.other.metadata.tag == "player_bullet") { + this->despawn_enemy(); + } + Animator & body_animator = this->get_components<Animator>().front(); + body_animator.data.col = 2; + //body_animator.play(); + BehaviorScript & enemy_script = this->get_component<BehaviorScript>(); + enemy_script.active = false; + return false; +} +void EnemyScript::despawn_enemy() { + Transform & transform = this->get_component<Transform>(); + transform.position = ENEMY_POOL_LOCATION; + AI & ai_component = this->get_component<AI>(); + // Rigidbody& enemy_body + ai_component.active = false; +} +void EnemyScript::shoot(const vec2 & location, float angle) { + RefVector<Transform> bullet_transforms + = this->get_components_by_tag<Transform>("enemy_bullet"); + + for (Transform & bullet_pos : bullet_transforms) { + if (bullet_pos.position.x == 0 && bullet_pos.position.y == -750) { + + bullet_pos.position = location; + bullet_pos.position.x -= 20; + Rigidbody & bullet_body + = this->get_components_by_id<Rigidbody>(bullet_pos.game_object_id).front(); + BoxCollider bullet_collider + = this->get_components_by_id<BoxCollider>(bullet_pos.game_object_id).front(); + bullet_collider.active = true; + bullet_body.active = true; + AudioSource & audio = this->get_component<AudioSource>(); + audio.play(); + return; + } + } +} diff --git a/game/enemy/EnemyScript.h b/game/enemy/EnemyScript.h new file mode 100644 index 0000000..42ecac4 --- /dev/null +++ b/game/enemy/EnemyScript.h @@ -0,0 +1,31 @@ +#pragma once +#include <chrono> +#include <crepe/api/Camera.h> +#include <crepe/api/Event.h> +#include <crepe/api/Script.h> +#include <random> +struct SpawnEnemyEvent : public crepe::Event { + float speed = 0; + int column = 0; +}; +class EnemyScript : public crepe::Script { +public: + EnemyScript(); + void init() override; + void fixed_update(crepe::duration_t dt) override; + void shoot(const crepe::vec2 & position, float angle); + bool on_collide(const crepe::CollisionEvent & collisionData); + void despawn_enemy(); + bool spawn_enemy(const SpawnEnemyEvent & e); + +private: + std::random_device rd; + std::default_random_engine engine; + bool alive = false; + float speed = 50; + const float MIN_SPEED = 10; + const float MAX_SPEED = 130; + const float MAX_DISTANCE = 100; + std::chrono::time_point<std::chrono::steady_clock> last_fired; + std::chrono::duration<float> shot_delay = std::chrono::duration<float>(0); +}; diff --git a/game/enemy/EnemySubScene.cpp b/game/enemy/EnemySubScene.cpp new file mode 100644 index 0000000..607b9a9 --- /dev/null +++ b/game/enemy/EnemySubScene.cpp @@ -0,0 +1,101 @@ +#include <string> + +#include <crepe/api/AI.h> +#include <crepe/api/Animator.h> +#include <crepe/api/AudioSource.h> +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/BoxCollider.h> +#include <crepe/api/CircleCollider.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/Rigidbody.h> +#include <crepe/api/Scene.h> +#include <crepe/api/Sprite.h> + +#include "../Config.h" +#include "EnemyConfig.h" +#include "EnemyScript.h" +#include "EnemySubScene.h" +using namespace crepe; +using namespace std; +//#TODO add sound +int EnemySubScene::create(Scene & scn, int enemy_counter) { + + string unique_name = "enemy_" + to_string(enemy_counter++); + GameObject enemy = scn.new_object(unique_name.c_str(), "enemy", ENEMY_POOL_LOCATION, 0, 1); + + enemy.add_component<Rigidbody>(Rigidbody::Data { + .gravity_scale = 0, + .body_type = Rigidbody::BodyType::DYNAMIC, + .max_linear_velocity = 400, + .collision_layers = {COLL_LAY_BOT_TOP, COLL_LAY_PLAYER_BULLET}, + .collision_layer = COLL_LAY_ENEMY, + + }); + Asset enemy_body_asset {"asset/workers/worker2Body.png"}; + enemy.add_component<BoxCollider>(vec2(50, 50)); + Sprite & enemy_body_sprite = enemy.add_component<Sprite>( + enemy_body_asset, + Sprite::Data { + .flip = {true, false}, + .sorting_in_layer = SORT_IN_LAY_WORKERS_FRONT, + .order_in_layer = 0, + .size = vec2(0, 50), + } + ); + Animator & body_animator = enemy.add_component<Animator>( + enemy_body_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = 5, + .col = 1, + .row = 0, + .looping = false, + } + ); + body_animator.pause(); + enemy.add_component<BoxCollider>(vec2(40, 60), vec2(-20, 0)); + Asset enemy_head_asset {"asset/workers/worker2Head.png"}; + Sprite & enemy_head_sprite = enemy.add_component<Sprite>( + enemy_head_asset, + Sprite::Data { + .flip = {true, false}, + .sorting_in_layer = SORT_IN_LAY_WORKERS_FRONT, + .order_in_layer = 1, + .size = vec2(0, 50), + .position_offset = vec2(0, -20), + } + ); + enemy.add_component<Animator>( + enemy_head_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = 5, + .looping = true, + } + ); + enemy.add_component<CircleCollider>(25, vec2(0, -20)); + Asset enemy_jetpack_asset {"asset/barry/jetpackDefault.png"}; + Sprite & enemy_jetpack_sprite = enemy.add_component<Sprite>( + enemy_jetpack_asset, + Sprite::Data { + .flip = {true, false}, + .sorting_in_layer = SORT_IN_LAY_WORKERS_FRONT, + .order_in_layer = 2, + .size = vec2(0, 60), + .position_offset = vec2(20, 0), + } + ); + enemy_jetpack_sprite.active = true; + enemy.add_component<Animator>( + enemy_jetpack_sprite, ivec2(32, 44), uvec2(4, 4), + Animator::Data { + .fps = 5, + .looping = true, + } + ); + enemy.add_component<AudioSource>(Asset("asset/sfx/bike_gun_2.ogg")).volume = 0.1; + AI & ai_component = enemy.add_component<AI>(3000); + ai_component.path_follow_on(); + BehaviorScript & enemy_script + = enemy.add_component<BehaviorScript>().set_script<EnemyScript>(); + enemy_script.active = false; + return enemy_counter; +} diff --git a/game/enemy/EnemySubScene.h b/game/enemy/EnemySubScene.h new file mode 100644 index 0000000..3899250 --- /dev/null +++ b/game/enemy/EnemySubScene.h @@ -0,0 +1,10 @@ +#pragma once + +namespace crepe { +class Scene; +} + +class EnemySubScene { +public: + int create(crepe::Scene & scn, int enemy_counter); +}; diff --git a/game/hud/HudConfig.h b/game/hud/HudConfig.h new file mode 100644 index 0000000..facc298 --- /dev/null +++ b/game/hud/HudConfig.h @@ -0,0 +1,33 @@ +#pragma once +#include <crepe/types.h> + +static constexpr crepe::vec2 TOP_LEFT = {-530, -230}; +static constexpr const char * HUD_DISTANCE = "hud_distance"; +static constexpr const char * HUD_BEST = "hud_best"; +static constexpr const char * HUD_COINS = "hud_coins"; +static constexpr const char * HUD_FPS = "hud_fps"; + +// Distance +static constexpr const char * DISTANCE_PLACEHOLDER = "0000m"; +static constexpr const char * DISTANCE_UNIT = "m"; +static constexpr int DISTANCE_LENGTH = 5; +static constexpr float DISTANCE_CHAR_WIDTH = 12; +static constexpr float STEP_SIZE_DISTANCE = 100; + +// BEST +static constexpr const char * BEST = "BEST:"; +static constexpr int BEST_LENGTH = 5; +static constexpr float BEST_CHAR_WIDTH = 10; +static constexpr crepe::vec2 BEST_OFFSET = {0, 25}; + +// COINS +static constexpr const char * COINS = "0000"; +static constexpr int COINS_LENGTH = 4; +static constexpr float COINS_CHAR_WIDTH = 10; +static constexpr crepe::vec2 COINS_OFFSET = {0, 50}; + +// FPS +static constexpr const char * FPS = "00"; +static constexpr int FPS_LENGTH = 2; +static constexpr float FPS_CHAR_WIDTH = 10; +static constexpr crepe::vec2 FPS_OFFSET = {1030, 0}; diff --git a/game/hud/HudScript.cpp b/game/hud/HudScript.cpp new file mode 100644 index 0000000..e4aeae7 --- /dev/null +++ b/game/hud/HudScript.cpp @@ -0,0 +1,98 @@ +#include "HudScript.h" +#include "HudConfig.h" + +#include "../Config.h" +#include "../Events.h" +#include "api/KeyCodes.h" +#include "menus/endgame/EndGameSubScript.h" + +#include <climits> + +#include <crepe/api/Text.h> +#include <crepe/api/Transform.h> +#include <crepe/manager/SaveManager.h> + +using namespace crepe; +using namespace std; + +void HudScript::init() { + savemgr = &this->get_save_manager(); + savemgr->set(TOTAL_COINS_RUN, 0); + Text & txt = this->get_components_by_name<Text>(HUD_BEST).front(); + string record + = BEST + to_string(savemgr->get<int>(DISTANCE_GAME, 0).get()) + DISTANCE_UNIT; + txt.text = record; + txt.dimensions = {BEST_CHAR_WIDTH * record.size(), (BEST_CHAR_WIDTH) * 2}; + txt.offset + = TOP_LEFT + FONTOFFSET + BEST_OFFSET + vec2 {record.size() * BEST_CHAR_WIDTH / 2, 0}; + + this->subscribe<GetCoinEvent>([this](const GetCoinEvent e) -> bool { + return this->get_coin(e); + }); + this->subscribe<KeyPressEvent>([this](const KeyPressEvent & ev) -> bool { + return this->toggle_fps(ev); + }); + this->subscribe<EndGameEvent>([this](const EndGameEvent e) -> bool { + return this->save(); + }); +} + +bool HudScript::toggle_fps(crepe::KeyPressEvent ev) { + if (ev.key != Keycode::D1) return false; + Text & txt_fps = this->get_components_by_name<Text>(HUD_FPS).front(); + this->show_fps = !this->show_fps; + if (this->show_fps) { + txt_fps.active = true; + } else { + txt_fps.active = false; + } + return true; +} + +void HudScript::frame_update(crepe::duration_t dt) { + + // Distance + Text & txt_dt = this->get_components_by_name<Text>(HUD_DISTANCE).front(); + Transform & tf = this->get_components_by_name<Transform>(PLAYER_NAME).front(); + string distance + = to_string(static_cast<int>(tf.position.x / STEP_SIZE_DISTANCE)) + DISTANCE_UNIT; + this->distance_st = distance; + txt_dt.text = distance; + txt_dt.dimensions = {DISTANCE_CHAR_WIDTH * distance.size(), (DISTANCE_CHAR_WIDTH) * 2}; + txt_dt.offset + = TOP_LEFT + FONTOFFSET + vec2 {distance.size() * DISTANCE_CHAR_WIDTH / 2, 0}; + + // Coins + Text & txt_co = this->get_components_by_name<Text>(HUD_COINS).front(); + string amount_of_coins = to_string(this->coin_amount); + this->coin_amount_st = amount_of_coins; + txt_co.text = amount_of_coins; + txt_co.dimensions = {COINS_CHAR_WIDTH * amount_of_coins.size(), (COINS_CHAR_WIDTH) * 2}; + txt_co.offset = TOP_LEFT + FONTOFFSET + COINS_OFFSET + + vec2 {amount_of_coins.size() * COINS_CHAR_WIDTH / 2, 0}; + + // FPS + Text & txt_fps = this->get_components_by_name<Text>(HUD_FPS).front(); + float fps = this->get_loop_timer().get_fps(); + string fps_amount = to_string(this->get_loop_timer().get_fps()); + txt_fps.text = fps_amount; + txt_fps.dimensions = {FPS_CHAR_WIDTH * fps_amount.size(), (FPS_CHAR_WIDTH) * 2}; + txt_fps.offset = TOP_LEFT + FONTOFFSET + FPS_OFFSET + + vec2 {fps_amount.size() * FPS_CHAR_WIDTH / 2, 0}; + if (fps >= 30) txt_fps.data.text_color = Color::YELLOW; + if (fps >= 50) txt_fps.data.text_color = Color::GREEN; + if (fps < 30) txt_fps.data.text_color = Color::RED; +} + +bool HudScript::get_coin(const GetCoinEvent e) { + this->coin_amount = e.amount_of_coins; + return true; +} + +bool HudScript::save() { + SaveManager & savemgr = this->get_save_manager(); + savemgr.set(TOTAL_COINS_RUN, this->coin_amount); + savemgr.set(DISTANCE_RUN, this->distance_st); + this->trigger_event<ShowScoreEvent>(); + return false; +} diff --git a/game/hud/HudScript.h b/game/hud/HudScript.h new file mode 100644 index 0000000..2b789db --- /dev/null +++ b/game/hud/HudScript.h @@ -0,0 +1,25 @@ +#pragma once + +#include <crepe/api/Event.h> +#include <crepe/api/Script.h> +#include <crepe/manager/SaveManager.h> + +struct GetCoinEvent : public crepe::Event { + int amount_of_coins; +}; + +class HudScript : public crepe::Script { +public: + void init() override; + void frame_update(crepe::duration_t dt) override; + bool get_coin(const GetCoinEvent e); + bool toggle_fps(crepe::KeyPressEvent ev); + bool save(); + +private: + crepe::SaveManager * savemgr; + bool show_fps = false; + int coin_amount = 0; + std::string coin_amount_st = ""; + std::string distance_st = ""; +}; diff --git a/game/hud/HudSubScene.cpp b/game/hud/HudSubScene.cpp new file mode 100644 index 0000000..dcc07b4 --- /dev/null +++ b/game/hud/HudSubScene.cpp @@ -0,0 +1,68 @@ +#include "HudSubScene.h" +#include "HudConfig.h" + +#include "../Config.h" + +#include <crepe/api/GameObject.h> +#include <crepe/api/Text.h> + +using namespace crepe; +using namespace std; + +void HudSubScene::create(Scene & scn) { + + // Distance + GameObject hud_dis = scn.new_object(HUD_DISTANCE); + + crepe::vec2 size_distance + = {DISTANCE_CHAR_WIDTH * DISTANCE_LENGTH, (DISTANCE_CHAR_WIDTH) * 2}; + hud_dis.add_component<Text>( + size_distance, FONT, + Text::Data { + .world_space = false, + .text_color = Color::WHITE, + }, + TOP_LEFT + FONTOFFSET + vec2 {DISTANCE_LENGTH * DISTANCE_CHAR_WIDTH / 2, 0}, + DISTANCE_PLACEHOLDER + ); + + // Best + GameObject hud_best = scn.new_object(HUD_BEST); + crepe::vec2 size_best = {BEST_CHAR_WIDTH * BEST_LENGTH, (BEST_CHAR_WIDTH) * 2}; + hud_best.add_component<Text>( + size_best, FONT, + Text::Data { + .world_space = false, + .text_color = Color::GREY, + }, + TOP_LEFT + FONTOFFSET + BEST_OFFSET + vec2 {BEST_LENGTH * BEST_CHAR_WIDTH / 2, 0}, BEST + ); + + // Coins + GameObject hud_coin = scn.new_object(HUD_COINS); + crepe::vec2 size_coin = {COINS_CHAR_WIDTH * COINS_LENGTH, (COINS_CHAR_WIDTH) * 2}; + hud_coin.add_component<Text>( + size_coin, FONT, + Text::Data { + .world_space = false, + .text_color = Color::GOLD, + }, + TOP_LEFT + FONTOFFSET + COINS_OFFSET + vec2 {COINS_LENGTH * COINS_CHAR_WIDTH / 2, 0}, + COINS + ); + + // Fps + GameObject hud_fps = scn.new_object(HUD_FPS); + crepe::vec2 size_fps = {FPS_CHAR_WIDTH * FPS_LENGTH, (FPS_CHAR_WIDTH) * 2}; + hud_fps + .add_component<Text>( + size_fps, FONT, + Text::Data { + .world_space = false, + .text_color = Color::GREEN, + }, + TOP_LEFT + FONTOFFSET + FPS_OFFSET + vec2 {FPS_LENGTH * FPS_CHAR_WIDTH / 2, 0}, FPS + ) + .active + = false; +} diff --git a/game/hud/HudSubScene.h b/game/hud/HudSubScene.h new file mode 100644 index 0000000..0cd368e --- /dev/null +++ b/game/hud/HudSubScene.h @@ -0,0 +1,8 @@ +#pragma once + +#include <crepe/api/Scene.h> + +class HudSubScene { +public: + void create(crepe::Scene & scn); +}; diff --git a/game/hud/SpeedScript.cpp b/game/hud/SpeedScript.cpp new file mode 100644 index 0000000..2ced47a --- /dev/null +++ b/game/hud/SpeedScript.cpp @@ -0,0 +1,42 @@ +#include "SpeedScript.h" + +#include "../Events.h" +#include "api/BehaviorScript.h" +#include <crepe/api/Event.h> +#include <crepe/api/KeyCodes.h> +#include <crepe/manager/LoopTimerManager.h> + +using namespace crepe; +using namespace std; + +void SpeedScript::init() { + this->subscribe<KeyPressEvent>([this](const KeyPressEvent & ev) -> bool { + if (ev.key != Keycode::HOME) return false; + LoopTimerManager & lp = this->get_loop_timer(); + this->toggle = !this->toggle; + if (this->toggle) { + this->timescale = lp.get_time_scale(); + lp.set_time_scale(0); + } else { + lp.set_time_scale(this->timescale); + } + + return true; + }); + this->subscribe<EndGameEvent>([this](const EndGameEvent e) { + this->get_component<BehaviorScript>().active = false; + return false; + }); +} + +void SpeedScript::fixed_update(crepe::duration_t dt) { + LoopTimerManager & lp = this->get_loop_timer(); + if (this->get_key_state(Keycode::PAGE_UP)) { + if (lp.get_time_scale() >= 2) return; + lp.set_time_scale(lp.get_time_scale() + 0.1); + } + if (this->get_key_state(Keycode::PAGE_DOWN)) { + if (lp.get_time_scale() <= 0.5) return; + lp.set_time_scale(lp.get_time_scale() - 0.1); + } +} diff --git a/game/hud/SpeedScript.h b/game/hud/SpeedScript.h new file mode 100644 index 0000000..b40f7cc --- /dev/null +++ b/game/hud/SpeedScript.h @@ -0,0 +1,15 @@ +#pragma once + +#include <crepe/api/Script.h> +#include <crepe/manager/SaveManager.h> + +class SpeedScript : public crepe::Script { +public: + void init() override; + void fixed_update(crepe::duration_t dt) override; + +private: + crepe::SaveManager * savemgr; + bool toggle = false; + float timescale = 1; +}; diff --git a/game/main.cpp b/game/main.cpp index 2198f73..c9ad8c1 100644 --- a/game/main.cpp +++ b/game/main.cpp @@ -1,16 +1,26 @@ +#include <cstdlib> + #include <crepe/api/Engine.h> #include <crepe/api/Script.h> -#include "Config.h" +#include "EngineConfig.h" #include "GameScene.h" +#include "PreviewScene.h" +#include "menus/mainmenu/MainMenuScene.h" +#include "menus/shop/ShopMenuScene.h" using namespace crepe; int main() { + srand(time(NULL)); + Config::get_instance() = ENGINE_CONFIG; Engine gameloop; + gameloop.add_scene<MainMenuScene>(); + gameloop.add_scene<ShopMenuScene>(); gameloop.add_scene<GameScene>(); + gameloop.add_scene<PreviewScene>(); return gameloop.main(); } diff --git a/game/menus/BannerSubScene.cpp b/game/menus/BannerSubScene.cpp new file mode 100644 index 0000000..006a829 --- /dev/null +++ b/game/menus/BannerSubScene.cpp @@ -0,0 +1,49 @@ +#include "BannerSubScene.h" +#include "MenusConfig.h" + +#include "../Config.h" + +#include <crepe/api/Scene.h> +#include <crepe/api/Sprite.h> +#include <crepe/api/Text.h> + +using namespace crepe; +using namespace std; + +void BannerSubScene::create(Scene & scn, const Data & data) { + GameObject menu_banner = scn.new_object("menu_banner", "", {0, -414}); + menu_banner.add_component<Sprite>( + Asset("asset/ui/settings_container/top_middle_setting.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1, + .size = {1100, 88}, + } + ); + menu_banner.add_component<Sprite>( + Asset("asset/ui/settings_container/top_2_middle_setting.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1, + .size = {1100, 66}, + .position_offset {0, 77}, + } + ); + menu_banner.add_component<Sprite>( + Asset("asset/ui/settings_container/banner_bottom.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1, + .size = {1100, 7}, + .position_offset {0, 113}, + } + ); + crepe::vec2 size + = {data.banner_title_width, (data.banner_title_width / data.banner_title.size()) * 2}; + + menu_banner.add_component<Text>( + size, FONT, + Text::Data { + .world_space = true, + .text_color = Color::WHITE, + }, + data.banner_title_offset + FONTOFFSET, data.banner_title + ); +} diff --git a/game/menus/BannerSubScene.h b/game/menus/BannerSubScene.h new file mode 100644 index 0000000..c194dfc --- /dev/null +++ b/game/menus/BannerSubScene.h @@ -0,0 +1,20 @@ +#pragma once + +#include <crepe/api/GameObject.h> +#include <crepe/types.h> + +namespace crepe { +class Scene; +} + +class BannerSubScene { +public: + struct Data { + const std::string & banner_title = "NODATA"; + const float banner_title_width = 100; + const crepe::vec2 & banner_title_offset = {0, 0}; + }; + +public: + void create(crepe::Scene & scn, const Data & data); +}; diff --git a/game/menus/ButtonNextMainMenuSubScript.cpp b/game/menus/ButtonNextMainMenuSubScript.cpp new file mode 100644 index 0000000..63a2777 --- /dev/null +++ b/game/menus/ButtonNextMainMenuSubScript.cpp @@ -0,0 +1,44 @@ +#include "ButtonNextMainMenuSubScript.h" +#include "ButtonReplaySubScript.h" +#include "MenusConfig.h" +#include "ValueBroker.h" + +#include "manager/SaveManager.h" + +#include "../Config.h" + +#include <crepe/api/AudioSource.h> +#include <crepe/types.h> + +using namespace crepe; +using namespace std; + +void ButtonNextMainMenuSubScript::init() { + IButtonScript::init(); + this->subscribe<ButtonPressEvent>([this](const ButtonPressEvent & e) { + return this->on_button_press(e); + }); +} + +bool ButtonNextMainMenuSubScript::on_button_press(const ButtonPressEvent & e) { + RefVector<AudioSource> audios + = this->get_components_by_name<AudioSource>("background_music"); + + for (AudioSource & audio : audios) { + audio.stop(); + } + + this->trigger_event<DeleteRecordingEvent>(); + SaveManager & savemgr = this->get_save_manager(); + + ValueBroker<int> coins = savemgr.get<int>(TOTAL_COINS_RUN, 0); + ValueBroker<int> coins_game = savemgr.get<int>(TOTAL_COINS_GAME, 0); + savemgr.set(TOTAL_COINS_GAME, coins_game.get() + coins.get()); + + ValueBroker<int> distance = savemgr.get<int>(DISTANCE_RUN, 0); + ValueBroker<int> distance_game = savemgr.get<int>(DISTANCE_GAME, 0); + if (distance.get() > distance_game.get()) savemgr.set(DISTANCE_GAME, distance.get()); + + this->set_next_scene(MAINMENU_SCENE); + return false; +} diff --git a/game/menus/ButtonNextMainMenuSubScript.h b/game/menus/ButtonNextMainMenuSubScript.h new file mode 100644 index 0000000..3bc3f52 --- /dev/null +++ b/game/menus/ButtonNextMainMenuSubScript.h @@ -0,0 +1,14 @@ +#pragma once + +#include "IButtonScript.h" + +#include <crepe/api/Script.h> + +class ButtonNextMainMenuSubScript : public IButtonScript { +public: + void init() override; + bool on_button_press(const crepe::ButtonPressEvent & e); + +protected: + bool transition = false; +}; diff --git a/game/menus/ButtonReplaySubScript.cpp b/game/menus/ButtonReplaySubScript.cpp new file mode 100644 index 0000000..01cccbf --- /dev/null +++ b/game/menus/ButtonReplaySubScript.cpp @@ -0,0 +1,43 @@ +#include "ButtonReplaySubScript.h" +#include "Config.h" +#include "MenusConfig.h" + +#include "../Events.h" +#include <crepe/api/AudioSource.h> +#include <crepe/types.h> + +using namespace crepe; +using namespace std; + +void ButtonReplaySubScript::init() { + IButtonScript::init(); + this->subscribe<ButtonPressEvent>([this](const ButtonPressEvent & e) { + return this->on_button_press(e); + }); + this->subscribe<EndGameEvent>([this](const EndGameEvent & e) { + return this->set_recording(); + }); + this->subscribe<DeleteRecordingEvent>([this](const DeleteRecordingEvent & e) { + return this->delete_recording(); + }); + if (DISABLE_REPLAY) return; + replay.record_start(); +} + +bool ButtonReplaySubScript::on_button_press(const ButtonPressEvent & e) { + if (DISABLE_REPLAY) return false; + replay.play(this->recording); + return false; +} + +bool ButtonReplaySubScript::set_recording() { + if (DISABLE_REPLAY) return false; + this->recording = replay.record_end(); + return false; +} + +bool ButtonReplaySubScript::delete_recording() { + if (DISABLE_REPLAY) return false; + replay.release(this->recording); + return false; +} diff --git a/game/menus/ButtonReplaySubScript.h b/game/menus/ButtonReplaySubScript.h new file mode 100644 index 0000000..3eb8aa9 --- /dev/null +++ b/game/menus/ButtonReplaySubScript.h @@ -0,0 +1,21 @@ +#pragma once + +#include "IButtonScript.h" + +#include <crepe/api/Script.h> + +struct DeleteRecordingEvent : public crepe::Event {}; + +class ButtonReplaySubScript : public IButtonScript { +public: + void init() override; + bool on_button_press(const crepe::ButtonPressEvent & e); + +private: + crepe::recording_t recording = 0; + bool set_recording(); + bool delete_recording(); + +protected: + bool transition = false; +}; diff --git a/game/menus/ButtonSetMainMenuSubScript.cpp b/game/menus/ButtonSetMainMenuSubScript.cpp new file mode 100644 index 0000000..1c6bcb2 --- /dev/null +++ b/game/menus/ButtonSetMainMenuSubScript.cpp @@ -0,0 +1,23 @@ +#include "ButtonSetMainMenuSubScript.h" +#include "MenusConfig.h" + +#include <crepe/api/AudioSource.h> +#include <crepe/types.h> + +using namespace crepe; +using namespace std; + +void ButtonSetMainMenuSubScript::init() { + IButtonScript::init(); + this->subscribe<ButtonPressEvent>([this](const ButtonPressEvent & e) { + return this->on_button_press(e); + }); +} + +bool ButtonSetMainMenuSubScript::on_button_press(const ButtonPressEvent & e) { + RefVector<AudioSource> audios + = this->get_components_by_name<AudioSource>("background_music"); + + this->set_next_scene(MAINMENU_SCENE); + return false; +} diff --git a/game/menus/ButtonSetMainMenuSubScript.h b/game/menus/ButtonSetMainMenuSubScript.h new file mode 100644 index 0000000..2fb2634 --- /dev/null +++ b/game/menus/ButtonSetMainMenuSubScript.h @@ -0,0 +1,14 @@ +#pragma once + +#include "IButtonScript.h" + +#include <crepe/api/Script.h> + +class ButtonSetMainMenuSubScript : public IButtonScript { +public: + void init() override; + bool on_button_press(const crepe::ButtonPressEvent & e); + +protected: + bool transition = false; +}; diff --git a/game/menus/ButtonSetShopSubScript.cpp b/game/menus/ButtonSetShopSubScript.cpp new file mode 100644 index 0000000..4f395eb --- /dev/null +++ b/game/menus/ButtonSetShopSubScript.cpp @@ -0,0 +1,17 @@ +#include "ButtonSetShopSubScript.h" +#include "MenusConfig.h" + +using namespace crepe; +using namespace std; + +void ButtonSetShopSubScript::init() { + IButtonScript::init(); + this->subscribe<ButtonPressEvent>([this](const ButtonPressEvent & e) { + return this->on_button_press(e); + }); +} + +bool ButtonSetShopSubScript::on_button_press(const ButtonPressEvent & e) { + this->set_next_scene(SHOP_SCENE); + return false; +} diff --git a/game/menus/ButtonSetShopSubScript.h b/game/menus/ButtonSetShopSubScript.h new file mode 100644 index 0000000..4017a4c --- /dev/null +++ b/game/menus/ButtonSetShopSubScript.h @@ -0,0 +1,14 @@ +#pragma once + +#include "IButtonScript.h" + +#include <crepe/api/Script.h> + +class ButtonSetShopSubScript : public IButtonScript { +public: + void init() override; + bool on_button_press(const crepe::ButtonPressEvent & e); + +protected: + bool transition = false; +}; diff --git a/game/menus/ButtonShowCreditsSubScript.cpp b/game/menus/ButtonShowCreditsSubScript.cpp new file mode 100644 index 0000000..ec0e980 --- /dev/null +++ b/game/menus/ButtonShowCreditsSubScript.cpp @@ -0,0 +1,20 @@ +#include "ButtonShowCreditsSubScript.h" +#include "MenusConfig.h" +#include "mainmenu/CreditsSubScript.h" +#include <crepe/api/AudioSource.h> +#include <crepe/types.h> + +using namespace crepe; +using namespace std; + +void ButtonShowCreditsSubScript::init() { + IButtonScript::init(); + this->subscribe<ButtonPressEvent>([this](const ButtonPressEvent & e) { + return this->on_button_press(e); + }); +} + +bool ButtonShowCreditsSubScript::on_button_press(const ButtonPressEvent & e) { + this->trigger_event<ShowCreditsEvent>(); + return false; +} diff --git a/game/menus/ButtonShowCreditsSubScript.h b/game/menus/ButtonShowCreditsSubScript.h new file mode 100644 index 0000000..3c73c44 --- /dev/null +++ b/game/menus/ButtonShowCreditsSubScript.h @@ -0,0 +1,14 @@ +#pragma once + +#include "IButtonScript.h" + +#include <crepe/api/Script.h> + +class ButtonShowCreditsSubScript : public IButtonScript { +public: + void init() override; + bool on_button_press(const crepe::ButtonPressEvent & e); + +protected: + bool transition = false; +}; diff --git a/game/menus/ButtonSubScene.cpp b/game/menus/ButtonSubScene.cpp new file mode 100644 index 0000000..1fe6b03 --- /dev/null +++ b/game/menus/ButtonSubScene.cpp @@ -0,0 +1,266 @@ +#include "ButtonSubScene.h" +#include "ButtonNextMainMenuSubScript.h" +#include "ButtonReplaySubScript.h" +#include "ButtonSetMainMenuSubScript.h" +#include "ButtonSetShopSubScript.h" +#include "ButtonShowCreditsSubScript.h" +#include "IButtonScript.h" +#include "MenusConfig.h" + +#include "../preview/PreviewReplaySubScript.h" +#include "../preview/PreviewStartRecSubScript.h" +#include "../preview/PreviewStopRecSubScript.h" +#include "api/Asset.h" +#include "mainmenu/ButtonTransitionPreviewSubScript.h" + +#include "../Config.h" +#include "mainmenu/CreditsSubScript.h" +#include "menus/shop/ButtonBuySelectBubbleScript.h" +#include "menus/shop/ButtonBuySelectBulletScript.h" + +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/Button.h> +#include <crepe/api/Color.h> +#include <crepe/api/Scene.h> +#include <crepe/api/Sprite.h> +#include <crepe/api/Text.h> + +using namespace crepe; +using namespace std; + +void ButtonSubScene::create(Scene & scn, const Data & data) { + GameObject button_object + = scn.new_object("button", data.tag, data.position, 0, data.scale); + this->set_button_overlay(button_object, data); + this->btn_text(button_object, data); + this->set_script(button_object, data); + this->set_icon(button_object, data); +} + +void ButtonSubScene::btn_text(crepe::GameObject & button_object, const Data & data) { + + crepe::vec2 size = {data.text_width, (data.text_width / data.text.size()) * 2}; + button_object.add_component<Text>( + size, FONT, + Text::Data { + .world_space = data.worldspace, + .text_color = Color::WHITE, + }, + data.text_offset + FONTOFFSET, data.text + ); +} + +void ButtonSubScene::set_script(crepe::GameObject & button_object, const Data & data) { + switch (data.script_type) { + case ScriptSelect::PREVIEW: + button_object.add_component<BehaviorScript>() + .set_script<ButtonTransitionPreviewSubScript>(); + break; + case ScriptSelect::SHOP: + button_object.add_component<BehaviorScript>().set_script<ButtonSetShopSubScript>(); + break; + case ScriptSelect::MAINMENU: + button_object.add_component<BehaviorScript>() + .set_script<ButtonSetMainMenuSubScript>(); + break; + case ScriptSelect::NEXT: + button_object.add_component<BehaviorScript>() + .set_script<ButtonNextMainMenuSubScript>(); + break; + case ScriptSelect::REPLAY: + button_object.add_component<BehaviorScript>().set_script<ButtonReplaySubScript>(); + break; + case ScriptSelect::CREDITS_BACK: + button_object.add_component<BehaviorScript>().set_script<CreditsSubScript>(data.tag + ); + break; + case ScriptSelect::CREDITS_SHOW: + button_object.add_component<BehaviorScript>() + .set_script<ButtonShowCreditsSubScript>(); + break; + case ScriptSelect::PREVIEW_REPLAY: + button_object.add_component<BehaviorScript>().set_script<PreviewReplaySubScript>(); + break; + case ScriptSelect::PREVIEW_START: + button_object.add_component<BehaviorScript>().set_script<PreviewStartRecSubScript>( + ); + break; + case ScriptSelect::PREVIEW_STOP: + button_object.add_component<BehaviorScript>().set_script<PreviewStopRecSubScript>( + ); + break; + case ScriptSelect::SHOP_BULLET: + button_object.add_component<BehaviorScript>() + .set_script<ButtonBuySelectBulletScript>(); + break; + case ScriptSelect::SHOP_BUBBLE: + button_object.add_component<BehaviorScript>() + .set_script<ButtonBuySelectBubbleScript>(); + break; + case ScriptSelect::NONE: + button_object.add_component<BehaviorScript>().set_script<IButtonScript>(); + break; + } +} + +void ButtonSubScene::set_icon(crepe::GameObject & button_object, const Data & data) { + switch (data.icon_type) { + case IconSelect::SHOP: + button_object.add_component<Sprite>( + Asset("asset/ui/buttonCoinsSmall.png"), + Sprite::Data { + .sorting_in_layer + = STARTING_SORTING_IN_LAYER + 3 + data.sorting_layer_offset, + .size = ICON_SIZE, + .position_offset = data.icon_offset, + .world_space = data.worldspace, + } + ); + break; + case IconSelect::COINS: + button_object.add_component<Sprite>( + Asset("asset/ui/buttonCoinsSmall.png"), + Sprite::Data { + .sorting_in_layer + = STARTING_SORTING_IN_LAYER + 3 + data.sorting_layer_offset, + .size = ICON_SIZE, + .position_offset = data.icon_offset, + .world_space = data.worldspace, + } + ); + break; + case IconSelect::NONE: + break; + } +} + +void ButtonSubScene::set_button_overlay(crepe::GameObject & button_object, const Data & data) { + switch (data.button_type) { + case ButtonSelect::LARGE: + this->large_btn_overlay(button_object, data); + break; + case ButtonSelect::BACK: + this->back_btn_overlay(button_object, data); + break; + case ButtonSelect::NEXT: + this->next_btn_overlay(button_object, data); + break; + } +} + +void ButtonSubScene::large_btn_overlay(crepe::GameObject & button_object, const Data & data) { + button_object.add_component<Sprite>( + Asset("asset/ui/buttonBacking.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1 + data.sorting_layer_offset, + .size = LARGE_OVERLAY_SIZE, + .world_space = data.worldspace, + } + ); + button_object.add_component<Button>(LARGE_OVERLAY_SIZE, Button::Data {}); + if (!data.color_side) return; + this->btn_color_side(button_object, SIDE_PANEL_OFFSET, data); +} + +void ButtonSubScene::back_btn_overlay(crepe::GameObject & button_object, const Data & data) { + button_object.add_component<Sprite>( + Asset("asset/ui/backbuttonright.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1 + data.sorting_layer_offset, + .size = SMALL_OVERLAY_SIZE_RIGHT, + .position_offset = {20, 0}, + .world_space = data.worldspace, + } + ); + button_object.add_component<Sprite>( + Asset("asset/ui/backbuttonleft.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1 + data.sorting_layer_offset, + .size = SMALL_OVERLAY_SIZE_LEFT, + .position_offset = {-80, 0}, + .world_space = data.worldspace, + } + ); + button_object.add_component<Button>( + vec2 { + SMALL_OVERLAY_SIZE_LEFT.x + SMALL_OVERLAY_SIZE_RIGHT.x, SMALL_OVERLAY_SIZE_LEFT.y + }, + Button::Data {} + ); +} + +void ButtonSubScene::next_btn_overlay(crepe::GameObject & button_object, const Data & data) { + button_object.add_component<Sprite>( + Asset("asset/ui/backbuttonright.png"), + Sprite::Data { + .flip = {true, false}, + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1 + data.sorting_layer_offset, + .size = SMALL_OVERLAY_SIZE_RIGHT, + .position_offset = {-20, 0}, + .world_space = data.worldspace, + } + ); + button_object.add_component<Sprite>( + Asset("asset/ui/backbuttonleft.png"), + Sprite::Data { + .flip = {true, false}, + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1 + data.sorting_layer_offset, + .size = SMALL_OVERLAY_SIZE_LEFT, + .position_offset = {80, 0}, + .world_space = data.worldspace, + } + ); + button_object.add_component<Button>( + vec2 { + SMALL_OVERLAY_SIZE_LEFT.x + SMALL_OVERLAY_SIZE_RIGHT.x, SMALL_OVERLAY_SIZE_LEFT.y + }, + Button::Data {} + ); +} + +void ButtonSubScene::btn_color_side( + crepe::GameObject & button_object, const vec2 & offset, const Data & data +) { + Asset * selected; + Asset blue = Asset("asset/ui/buttonSmallBlue.png"); + Asset orange = Asset("asset/ui/buttonSmallOrange.png"); + Asset purple = Asset("asset/ui/buttonSmallPurple.png"); + Asset yellow = Asset("asset/ui/buttonSmallYellow.png"); + switch (data.btn_side_color) { + case ButtonSideColor::BLUE: + selected = &blue; + break; + case ButtonSideColor::ORANGE: + selected = &orange; + break; + case ButtonSideColor::PURPLE: + selected = &purple; + break; + case ButtonSideColor::YELLOW: + selected = &yellow; + break; + case ButtonSideColor::NONE: + selected = &blue; + break; + } + + button_object.add_component<Sprite>( + *selected, + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 2 + data.sorting_layer_offset, + .size = SIDE_PANEL_SIZE, + .position_offset = offset, + .world_space = data.worldspace, + } + ); + button_object.add_component<Sprite>( + *selected, + Sprite::Data { + .flip = {true, false}, + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 2 + data.sorting_layer_offset, + .size = SIDE_PANEL_SIZE, + .position_offset = {-offset.x, offset.y}, + .world_space = data.worldspace, + } + ); +} diff --git a/game/menus/ButtonSubScene.h b/game/menus/ButtonSubScene.h new file mode 100644 index 0000000..d4c7223 --- /dev/null +++ b/game/menus/ButtonSubScene.h @@ -0,0 +1,84 @@ +#pragma once + +#include <crepe/api/GameObject.h> + +#include <string> + +namespace crepe { +class Scene; +} + +class ButtonSubScene { +public: + //script enum + enum class ScriptSelect { + PREVIEW, + SHOP, + MAINMENU, + NEXT, + REPLAY, + CREDITS_SHOW, + CREDITS_BACK, + PREVIEW_START, + PREVIEW_STOP, + PREVIEW_REPLAY, + SHOP_BULLET, + SHOP_BUBBLE, + NONE, + }; + //icon enum + enum class IconSelect { + SHOP, + COINS, + NONE, + }; + //icon enum + enum class ButtonSelect { + BACK, + NEXT, + LARGE, + }; + + enum class ButtonSideColor { + BLUE, + ORANGE, + PURPLE, + YELLOW, + NONE, + }; + //data struct + struct Data { + const std::string & text = "NODATA"; + const crepe::vec2 & text_offset = {0, 0}; + const float text_width = 200; + const crepe::vec2 & icon_offset = {0, 0}; + const IconSelect icon_type = IconSelect::NONE; + const crepe::vec2 & position = {0, 0}; + const ScriptSelect script_type = ScriptSelect::NONE; + const ButtonSelect button_type = ButtonSelect::LARGE; + const float scale = 1; + const bool worldspace = true; + const bool color_side = true; + const std::string & tag = ""; + const int sorting_layer_offset = 0; + const ButtonSideColor btn_side_color = ButtonSideColor::NONE; + }; + +public: + void create(crepe::Scene & scn, const Data & data); + +private: + void large_btn_overlay(crepe::GameObject & button_object, const Data & data); + void back_btn_overlay(crepe::GameObject & button_object, const Data & data); + void next_btn_overlay(crepe::GameObject & button_object, const Data & data); + void btn_color_side( + crepe::GameObject & button_object, const crepe::vec2 & offset, const Data & data + ); + void btn_text(crepe::GameObject & button_object, const Data & data); + void set_script(crepe::GameObject & button_object, const Data & data); + void set_icon(crepe::GameObject & button_object, const Data & data); + void set_button_overlay(crepe::GameObject & button_object, const Data & data); + +private: + static constexpr crepe::vec2 SIDE_PANEL_OFFSET = {113, 0}; +}; diff --git a/game/menus/FloatingWindowSubScene.cpp b/game/menus/FloatingWindowSubScene.cpp new file mode 100644 index 0000000..4420bfa --- /dev/null +++ b/game/menus/FloatingWindowSubScene.cpp @@ -0,0 +1,220 @@ + +#include "FloatingWindowSubScene.h" +#include "MenusConfig.h" + +#include <crepe/api/Camera.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/Scene.h> +#include <crepe/api/Sprite.h> +#include <crepe/types.h> + +using namespace crepe; +using namespace std; + +void FloatingWindowSubScene::create(Scene & scn, const Data & data) { + const vec2 SIZE = {data.width, data.width * 0.75f}; + const vec2 POSITION_CORRECTION = vec2 {0, -SIZE.y / 2} + data.offset; + const float THICKNESS_BANNER = 34; + const float MIDDLE_OFFSET_FACTOR_TICKNESS = 0.83; + const float MIDDLE_OFFSET_FACTOR_OFFSET = 1.2; + const float MIDDLE_OFFSET_FACTOR_MIDDLE_WIDTH = 0.86; + const float MIDDLE_OFFSET_OFFSET_ADDITION = -0.5; + const float BOTTOM_OFFSET_X = 3; + const float BOTTOM_OFFSET_Y = -3; + + GameObject floatingwindow = scn.new_object("FloatingWindow", data.group_tag); + + // Top_middle + floatingwindow.add_component<Sprite>( + Asset("asset/ui/settings_container/top_middle_setting.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 8, + .size = {SIZE.x, THICKNESS_BANNER}, + .position_offset = POSITION_CORRECTION + vec2 {0, 0}, + .world_space = false, + } + ); + + // Top_Left + floatingwindow.add_component<Sprite>( + Asset("asset/ui/settings_container/top_left_setting.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 8, + .size = {THICKNESS_BANNER, THICKNESS_BANNER}, + .position_offset + = POSITION_CORRECTION + vec2 {-SIZE.x / 2 - THICKNESS_BANNER / 2, 0}, + .world_space = false, + } + ); + + // Top_Right + floatingwindow.add_component<Sprite>( + Asset("asset/ui/settings_container/top_right_setting.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 8, + .size = {THICKNESS_BANNER, THICKNESS_BANNER}, + .position_offset + = POSITION_CORRECTION + vec2 {SIZE.x / 2 + THICKNESS_BANNER / 2, 0}, + .world_space = false, + } + ); + + // Top_middle_2 + floatingwindow.add_component<Sprite>( + Asset("asset/ui/settings_container/top_2_middle_setting.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 8, + .size = {SIZE.x, THICKNESS_BANNER}, + .position_offset = POSITION_CORRECTION + vec2 {0, THICKNESS_BANNER}, + .world_space = false, + } + ); + + // Top_Left_2 + floatingwindow.add_component<Sprite>( + Asset("asset/ui/settings_container/top_2_left_setting.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 8, + .size = {THICKNESS_BANNER, THICKNESS_BANNER}, + .position_offset = POSITION_CORRECTION + + vec2 {-SIZE.x / 2 - THICKNESS_BANNER / 2, THICKNESS_BANNER}, + .world_space = false, + } + ); + + // Top_Right_2 + floatingwindow.add_component<Sprite>( + Asset("asset/ui/settings_container/top_2_right_setting.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 8, + .size = {THICKNESS_BANNER, THICKNESS_BANNER}, + .position_offset + = POSITION_CORRECTION + vec2 {SIZE.x / 2 + THICKNESS_BANNER / 2, THICKNESS_BANNER}, + .world_space = false, + } + ); + + // Top_middle_3 + floatingwindow.add_component<Sprite>( + Asset("asset/ui/settings_container/top_3_middle_setting.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 8, + .size = {SIZE.x, THICKNESS_BANNER}, + .position_offset = POSITION_CORRECTION + vec2 {0, THICKNESS_BANNER * 2}, + .world_space = false, + } + ); + + // Top_Left_3 + floatingwindow.add_component<Sprite>( + Asset("asset/ui/settings_container/top_3_left_setting.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 8, + .size = {THICKNESS_BANNER, THICKNESS_BANNER}, + .position_offset + = POSITION_CORRECTION + + vec2 {-SIZE.x / 2 - THICKNESS_BANNER / 2, THICKNESS_BANNER * 2}, + .world_space = false, + } + ); + + // Top_Right_3 + floatingwindow.add_component<Sprite>( + Asset("asset/ui/settings_container/top_3_right_setting.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 8, + .size = {THICKNESS_BANNER, THICKNESS_BANNER}, + .position_offset + = POSITION_CORRECTION + + vec2 {SIZE.x / 2 + THICKNESS_BANNER / 2, THICKNESS_BANNER * 2}, + .world_space = false, + } + ); + + // Middle_Mid + floatingwindow.add_component<Sprite>( + Asset("asset/ui/settings_container/middle_mid_setting.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 7, + .size + = {SIZE.x * MIDDLE_OFFSET_FACTOR_OFFSET * MIDDLE_OFFSET_FACTOR_MIDDLE_WIDTH + + data.width_middle_offset, + SIZE.y}, + .position_offset + = POSITION_CORRECTION + + vec2 {0, THICKNESS_BANNER * 3 + SIZE.y / 2 - THICKNESS_BANNER / 2}, + .world_space = false, + } + ); + + // Middle_Left + floatingwindow.add_component<Sprite>( + Asset("asset/ui/settings_container/middle_left_setting.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 8, + .size = {THICKNESS_BANNER * MIDDLE_OFFSET_FACTOR_TICKNESS, SIZE.y}, + .position_offset + = POSITION_CORRECTION + + vec2 {-SIZE.x / 2 - THICKNESS_BANNER / 2 * MIDDLE_OFFSET_FACTOR_OFFSET - MIDDLE_OFFSET_OFFSET_ADDITION, THICKNESS_BANNER * 3 + SIZE.y / 2 - THICKNESS_BANNER / 2}, + .world_space = false, + } + ); + + // Middle_Right + floatingwindow.add_component<Sprite>( + Asset("asset/ui/settings_container/middle_right_setting.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 8, + .size = {THICKNESS_BANNER * MIDDLE_OFFSET_FACTOR_TICKNESS, SIZE.y}, + .position_offset + = POSITION_CORRECTION + + vec2 {SIZE.x / 2 + THICKNESS_BANNER / 2 * MIDDLE_OFFSET_FACTOR_OFFSET + MIDDLE_OFFSET_OFFSET_ADDITION, THICKNESS_BANNER * 3 + SIZE.y / 2 - THICKNESS_BANNER / 2}, + .world_space = false, + } + ); + + // Bot_Middle + floatingwindow.add_component<Sprite>( + Asset("asset/ui/settings_container/bot_middle_setting.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 7, + .size + = {SIZE.x * MIDDLE_OFFSET_FACTOR_OFFSET * MIDDLE_OFFSET_FACTOR_MIDDLE_WIDTH + + data.width_middle_offset, + THICKNESS_BANNER * MIDDLE_OFFSET_FACTOR_TICKNESS}, + .position_offset + = POSITION_CORRECTION + vec2 {0, THICKNESS_BANNER * 3 + SIZE.y + BOTTOM_OFFSET_Y}, + .world_space = false, + } + ); + + // Bot_Left + floatingwindow.add_component<Sprite>( + Asset("asset/ui/settings_container/bot_left_setting.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 8, + .size + = {THICKNESS_BANNER * MIDDLE_OFFSET_FACTOR_TICKNESS, + THICKNESS_BANNER * MIDDLE_OFFSET_FACTOR_TICKNESS}, + .position_offset + = POSITION_CORRECTION + + vec2 {-SIZE.x / 2 - THICKNESS_BANNER / 2 - BOTTOM_OFFSET_X, THICKNESS_BANNER * 3 + SIZE.y + BOTTOM_OFFSET_Y}, + .world_space = false, + } + ); + + // Bot_Right + floatingwindow.add_component<Sprite>( + Asset("asset/ui/settings_container/bot_right_setting.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 8, + .size + = {THICKNESS_BANNER * MIDDLE_OFFSET_FACTOR_TICKNESS, + THICKNESS_BANNER * MIDDLE_OFFSET_FACTOR_TICKNESS}, + .position_offset + = POSITION_CORRECTION + + vec2 {SIZE.x / 2 + THICKNESS_BANNER / 2 + BOTTOM_OFFSET_X, THICKNESS_BANNER * 3 + SIZE.y + BOTTOM_OFFSET_Y}, + .world_space = false, + } + ); +} diff --git a/game/menus/FloatingWindowSubScene.h b/game/menus/FloatingWindowSubScene.h new file mode 100644 index 0000000..7b9de96 --- /dev/null +++ b/game/menus/FloatingWindowSubScene.h @@ -0,0 +1,17 @@ +#pragma once + +#include <crepe/api/Scene.h> +#include <crepe/types.h> + +class FloatingWindowSubScene { +public: + struct Data { + const std::string group_tag = ""; + float width = 200; + crepe::vec2 offset = {0, 0}; + float width_middle_offset = 0; + }; + +public: + void create(crepe::Scene & scn, const Data & data); +}; diff --git a/game/menus/IButtonScript.cpp b/game/menus/IButtonScript.cpp new file mode 100644 index 0000000..34efbd0 --- /dev/null +++ b/game/menus/IButtonScript.cpp @@ -0,0 +1,32 @@ +#include "IButtonScript.h" + +#include "system/InputSystem.h" + +#include <crepe/api/Sprite.h> +#include <crepe/types.h> + +using namespace crepe; +using namespace std; + +void IButtonScript::init() { + this->subscribe<ButtonExitEvent>([this](const ButtonExitEvent & e) { + return this->on_button_exit(e); + }); + this->subscribe<ButtonEnterEvent>([this](const ButtonEnterEvent & e) { + return this->on_button_enter(e); + }); +} +bool IButtonScript::on_button_exit(const ButtonExitEvent & e) { + RefVector<Sprite> sprites = this->get_components<Sprite>(); + for (Sprite & sprite : sprites) { + sprite.data.color = Color {255, 255, 255, 255}; + } + return false; +} +bool IButtonScript::on_button_enter(const ButtonEnterEvent & e) { + RefVector<Sprite> sprites = this->get_components<Sprite>(); + for (Sprite & sprite : sprites) { + sprite.data.color = Color {200, 200, 200, 255}; + } + return false; +} diff --git a/game/menus/IButtonScript.h b/game/menus/IButtonScript.h new file mode 100644 index 0000000..e45375b --- /dev/null +++ b/game/menus/IButtonScript.h @@ -0,0 +1,10 @@ +#pragma once + +#include <crepe/api/Script.h> + +class IButtonScript : public virtual crepe::Script { +public: + virtual void init(); + virtual bool on_button_exit(const crepe::ButtonExitEvent & e); + virtual bool on_button_enter(const crepe::ButtonEnterEvent & e); +}; diff --git a/game/menus/IFloatingWindowScript.cpp b/game/menus/IFloatingWindowScript.cpp new file mode 100644 index 0000000..4b538ef --- /dev/null +++ b/game/menus/IFloatingWindowScript.cpp @@ -0,0 +1,22 @@ +#include "IFloatingWindowScript.h" + +#include <crepe/api/Sprite.h> +#include <crepe/types.h> + +using namespace crepe; + +void IFloatingWindowScript::init() { this->disable_all_sprites(); } + +void IFloatingWindowScript::disable_all_sprites() { + RefVector<Sprite> sprites = this->get_components_by_tag<Sprite>(this->tag); + for (Sprite & sprite : sprites) { + sprite.active = false; + } +} + +void IFloatingWindowScript::enable_all_sprites() { + RefVector<Sprite> sprites = this->get_components_by_tag<Sprite>(this->tag); + for (Sprite & sprite : sprites) { + sprite.active = true; + } +} diff --git a/game/menus/IFloatingWindowScript.h b/game/menus/IFloatingWindowScript.h new file mode 100644 index 0000000..e39378f --- /dev/null +++ b/game/menus/IFloatingWindowScript.h @@ -0,0 +1,15 @@ +#pragma once + +#include <crepe/api/Script.h> + +#include <string> + +class IFloatingWindowScript : public virtual crepe::Script { +public: + virtual void init(); + void disable_all_sprites(); + void enable_all_sprites(); + +protected: + std::string tag = ""; +}; diff --git a/game/menus/MenusConfig.h b/game/menus/MenusConfig.h new file mode 100644 index 0000000..3e357a5 --- /dev/null +++ b/game/menus/MenusConfig.h @@ -0,0 +1,16 @@ +#pragma once +#include <crepe/types.h> + +//generic menu config +static constexpr int STARTING_SORTING_IN_LAYER = 7; +//Scene names +static constexpr const char * START_SCENE = "scene1"; +static constexpr const char * PREVIEW_SCENE = "preview scene"; +static constexpr const char * SHOP_SCENE = "shopmenu"; +static constexpr const char * MAINMENU_SCENE = "mainmenu"; +//button config +static constexpr crepe::vec2 LARGE_OVERLAY_SIZE = {250, 100}; +static constexpr crepe::vec2 SMALL_OVERLAY_SIZE_RIGHT = {150, 100}; +static constexpr crepe::vec2 SMALL_OVERLAY_SIZE_LEFT = {50, 100}; +static constexpr crepe::vec2 SIDE_PANEL_SIZE = {50, 150}; +static constexpr crepe::vec2 ICON_SIZE = {50, 50}; diff --git a/game/menus/endgame/EndGameSubScene.cpp b/game/menus/endgame/EndGameSubScene.cpp new file mode 100644 index 0000000..b33072a --- /dev/null +++ b/game/menus/endgame/EndGameSubScene.cpp @@ -0,0 +1,127 @@ + +#include "EndGameSubScene.h" +#include "EndGameSubScript.h" + +#include "../../Config.h" +#include "../ButtonSubScene.h" +#include "../FloatingWindowSubScene.h" + +#include <string> + +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/Text.h> +#include <crepe/types.h> + +using namespace crepe; +using namespace std; + +void EndGameSubScene::create(Scene & scn) { + + const std::string TAG = "end_game_tag"; + GameObject script = scn.new_object("script"); + script.add_component<BehaviorScript>().set_script<EndGameSubScript>(TAG); + + // Window + FloatingWindowSubScene window; + window.create( + scn, + FloatingWindowSubScene::Data { + .group_tag = TAG, + .width = 500, + .offset = {0, -50}, + .width_middle_offset = -2, + } + ); + + // Titel + const string TITEL_STRING = "GAME OVER"; + GameObject titel = scn.new_object("titel", TAG); + crepe::vec2 size = {200, (200.0f / TITEL_STRING.size()) * 2}; + titel.add_component<Text>( + size, FONT, + Text::Data { + .world_space = false, + .text_color = Color::WHITE, + }, + vec2 {0, -207} + FONTOFFSET, TITEL_STRING + ); + + const float Y_SPACING = 50; + const float Y_OFFSET = -100; + + // Gold gathered + const string GOLD_STRING = "gold:0"; + GameObject gold = scn.new_object("gold_endgame", TAG); + crepe::vec2 size_gold = {200, (200.0f / GOLD_STRING.size()) * 2}; + gold.add_component<Text>( + size_gold, FONT, + Text::Data { + .world_space = false, + .text_color = Color::GOLD, + }, + vec2 {0, Y_OFFSET} + FONTOFFSET, GOLD_STRING + ); + + // Distance + const string DISTANCE_STRING = "0M"; + GameObject distance = scn.new_object("distance_endgame", TAG); + crepe::vec2 size_distance = {200, (200.0f / DISTANCE_STRING.size()) * 2}; + distance.add_component<Text>( + size_distance, FONT, + Text::Data { + .world_space = false, + .text_color = Color::WHITE, + }, + vec2 {0, Y_SPACING + Y_OFFSET} + FONTOFFSET, DISTANCE_STRING + ); + + // Highscore + const string HIGHSCORE_STRING = "NEW HIGHSCORE"; + GameObject highscore = scn.new_object("highscore_endgame", "highscore_tag_end"); + crepe::vec2 size_highscore = {200, (200.0f / HIGHSCORE_STRING.size()) * 2}; + highscore + .add_component<Text>( + size_highscore, FONT, + Text::Data { + .world_space = false, + .text_color = Color::WHITE, + }, + vec2 {0, Y_SPACING * 2 + Y_OFFSET} + FONTOFFSET, HIGHSCORE_STRING + ) + .active + = false; + + // Buttons + vec2 button_position = {190, 190}; + ButtonSubScene button; + button.create( + scn, + ButtonSubScene::Data { + .text = "NEXT", + .text_width = 100, + .position = button_position, + .script_type = ButtonSubScene::ScriptSelect::NEXT, + .button_type = ButtonSubScene::ButtonSelect::NEXT, + .scale = 0.6, + .worldspace = false, + .tag = TAG, + .sorting_layer_offset = 20, + } + ); + + button.create( + scn, + ButtonSubScene::Data { + .text = "REPLAY", + .text_width = 150, + .position = {-button_position.x, button_position.y}, + .script_type = ButtonSubScene::ScriptSelect::REPLAY, + .button_type = ButtonSubScene::ButtonSelect::BACK, + .scale = 0.6, + .worldspace = false, + .tag = TAG, + .sorting_layer_offset = 20, + } + ); +} diff --git a/game/menus/endgame/EndGameSubScene.h b/game/menus/endgame/EndGameSubScene.h new file mode 100644 index 0000000..204f3b7 --- /dev/null +++ b/game/menus/endgame/EndGameSubScene.h @@ -0,0 +1,9 @@ +#pragma once + +#include <crepe/api/Scene.h> + +class EndGameSubScene { + +public: + void create(crepe::Scene & scn); +}; diff --git a/game/menus/endgame/EndGameSubScript.cpp b/game/menus/endgame/EndGameSubScript.cpp new file mode 100644 index 0000000..6793f3e --- /dev/null +++ b/game/menus/endgame/EndGameSubScript.cpp @@ -0,0 +1,101 @@ +#include "EndGameSubScript.h" + +#include "../../Config.h" +#include "../../Events.h" +#include "../ButtonReplaySubScript.h" +#include "../IFloatingWindowScript.h" +#include "ValueBroker.h" +#include "manager/SaveManager.h" + +#include <string> + +#include <crepe/api/Button.h> +#include <crepe/api/Sprite.h> +#include <crepe/api/Text.h> +#include <crepe/types.h> + +using namespace crepe; + +EndGameSubScript::EndGameSubScript(const std::string & tag) { this->tag = tag; } + +void EndGameSubScript::init() { + this->disable_all(); + this->subscribe<EndGameEvent>([this](const EndGameEvent e) { return this->enable_all(); }); + this->subscribe<EndGameEvent>([this](const EndGameEvent e) { + return this->reset_timescale(); + }); + this->subscribe<ShowScoreEvent>([this](const ShowScoreEvent e) { + return this->showscore(); + }); +} + +bool EndGameSubScript::disable_all() { + IFloatingWindowScript::disable_all_sprites(); + RefVector<Button> buttons = this->get_components_by_tag<Button>(this->tag); + for (Button & button : buttons) { + button.active = false; + } + RefVector<Text> texts = this->get_components_by_tag<Text>(this->tag); + for (Text & text : texts) { + text.active = false; + } + return false; +} + +bool EndGameSubScript::enable_all() { + IFloatingWindowScript::enable_all_sprites(); + RefVector<Button> buttons = this->get_components_by_tag<Button>(this->tag); + for (Button & button : buttons) { + button.active = true; + } + RefVector<Text> texts = this->get_components_by_tag<Text>(this->tag); + for (Text & text : texts) { + text.active = true; + } + return false; +} + +bool EndGameSubScript::reset_timescale() { + this->get_loop_timer().set_time_scale(1); + return false; +} + +bool EndGameSubScript::showscore() { + // Gather text + Text & coins_text = this->get_components_by_name<Text>("gold_endgame").front().get(); + Text & distance_text + = this->get_components_by_name<Text>("distance_endgame").front().get(); + Text & highscore_text + = this->get_components_by_name<Text>("highscore_endgame").front().get(); + highscore_text.active = false; + + // Gather saved data + SaveManager & savemgr = this->get_save_manager(); + ValueBroker<std::string> coins = savemgr.get<std::string>(TOTAL_COINS_RUN, "0"); + ValueBroker<std::string> distance = savemgr.get<std::string>(DISTANCE_RUN, "0"); + int distance_run = savemgr.get<int>(DISTANCE_RUN, 0).get(); + int distance_game = savemgr.get<int>(DISTANCE_GAME, 0).get(); + + // Show highscore + if (distance_run > distance_game) highscore_text.active = true; + + const float CHAR_SIZE_DIS = 20; + // Show distance + std::string distance_string = "DISTANCE:" + distance.get(); + distance_text.text = distance_string; + crepe::vec2 size_distance + = {CHAR_SIZE_DIS * distance_string.size(), + (CHAR_SIZE_DIS * distance_string.size() / distance_string.size()) * 2}; + distance_text.dimensions = size_distance; + + const float CHAR_SIZE_COIN = 16; + // Show coins + std::string coins_string = "Coins:" + coins.get(); + coins_text.text = coins_string; + crepe::vec2 size_coins + = {CHAR_SIZE_COIN * coins_string.size(), + (CHAR_SIZE_COIN * coins_string.size() / coins_string.size()) * 2}; + coins_text.dimensions = size_coins; + + return false; +} diff --git a/game/menus/endgame/EndGameSubScript.h b/game/menus/endgame/EndGameSubScript.h new file mode 100644 index 0000000..c25f6ca --- /dev/null +++ b/game/menus/endgame/EndGameSubScript.h @@ -0,0 +1,18 @@ +#pragma once + +#include "../IFloatingWindowScript.h" + +#include <crepe/api/Event.h> +#include <crepe/api/Script.h> + +struct ShowScoreEvent : public crepe::Event {}; + +class EndGameSubScript : public IFloatingWindowScript { +public: + EndGameSubScript(const std::string & tag); + void init() override; + bool disable_all(); + bool enable_all(); + bool reset_timescale(); + bool showscore(); +}; diff --git a/game/menus/mainmenu/ButtonTransitionPreviewSubScript.cpp b/game/menus/mainmenu/ButtonTransitionPreviewSubScript.cpp new file mode 100644 index 0000000..4c4dfc1 --- /dev/null +++ b/game/menus/mainmenu/ButtonTransitionPreviewSubScript.cpp @@ -0,0 +1,23 @@ +#include "ButtonTransitionPreviewSubScript.h" + +#include "../MenusConfig.h" + +using namespace crepe; +using namespace std; + +void ButtonTransitionPreviewSubScript::init() { + IButtonScript::init(); + this->subscribe<ButtonPressEvent>([this](const ButtonPressEvent & e) { + return this->on_button_press(e); + }); +} + +bool ButtonTransitionPreviewSubScript::on_button_press(const ButtonPressEvent & e) { + if (!this->transition) this->transition = true; + return false; +} + +const char * ButtonTransitionPreviewSubScript::get_scene_name() const { + // Provide the next scene defined in MainMenuConfig + return PREVIEW_SCENE; +} diff --git a/game/menus/mainmenu/ButtonTransitionPreviewSubScript.h b/game/menus/mainmenu/ButtonTransitionPreviewSubScript.h new file mode 100644 index 0000000..d6d8149 --- /dev/null +++ b/game/menus/mainmenu/ButtonTransitionPreviewSubScript.h @@ -0,0 +1,12 @@ +#pragma once + +#include "ITransitionScript.h" + +#include "../IButtonScript.h" + +class ButtonTransitionPreviewSubScript : public ITransitionScript, public IButtonScript { +public: + void init() override; + bool on_button_press(const crepe::ButtonPressEvent & e); + const char * get_scene_name() const override; +}; diff --git a/game/menus/mainmenu/CreditsSubScene.cpp b/game/menus/mainmenu/CreditsSubScene.cpp new file mode 100644 index 0000000..65576ee --- /dev/null +++ b/game/menus/mainmenu/CreditsSubScene.cpp @@ -0,0 +1,132 @@ + +#include "CreditsSubScene.h" +#include "CreditsSubScript.h" + +#include "../../Config.h" +#include "../ButtonSubScene.h" +#include "../FloatingWindowSubScene.h" + +#include <string> + +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/Text.h> +#include <crepe/types.h> + +using namespace crepe; +using namespace std; + +void CreditsSubScene::create(Scene & scn) { + + const std::string TAG = "credits_tag"; + GameObject script = scn.new_object("script"); + script.add_component<BehaviorScript>().set_script<CreditsSubScript>(TAG); + + // Window + FloatingWindowSubScene window; + window.create( + scn, + FloatingWindowSubScene::Data { + .group_tag = TAG, + .width = 500, + .offset = {150, -50}, + .width_middle_offset = -2, + } + ); + + // Titel + const string TITEL_STRING = "Credits"; + GameObject titel = scn.new_object("titel", TAG); + crepe::vec2 size = {200, (200.0f / TITEL_STRING.size()) * 2}; + titel.add_component<Text>( + size, FONT, + Text::Data { + .world_space = false, + .text_color = Color::WHITE, + }, + vec2 {150, -207} + FONTOFFSET, TITEL_STRING + ); + + // Buttons + vec2 button_position = {190, 190}; + ButtonSubScene button; + button.create( + scn, + ButtonSubScene::Data { + .text = "Back", + .text_width = 150, + .position = {-button_position.x + 150, button_position.y}, + .script_type = ButtonSubScene::ScriptSelect::CREDITS_BACK, + .button_type = ButtonSubScene::ButtonSelect::BACK, + .scale = 0.6, + .worldspace = false, + .tag = TAG, + .sorting_layer_offset = 20, + } + ); + + const float SIZE_CHAR_NAMES = 10; + const float Y_OFFSET_NAMES_BEGIN = 100; + const float Y_OFFSET_NAMES = 30; + const string LOEK = "Loek Le Blansch"; + crepe::vec2 size_loek + = {LOEK.size() * SIZE_CHAR_NAMES, (LOEK.size() * SIZE_CHAR_NAMES / LOEK.size()) * 2}; + titel.add_component<Text>( + size_loek, FONT, + Text::Data { + .world_space = false, + .text_color = Color::WHITE, + }, + vec2 {150, -207 + Y_OFFSET_NAMES + Y_OFFSET_NAMES_BEGIN} + FONTOFFSET, LOEK + ); + + const string WOUTER = "Wouter Boerenkamps"; + crepe::vec2 size_wouter + = {WOUTER.size() * SIZE_CHAR_NAMES, + (WOUTER.size() * SIZE_CHAR_NAMES / WOUTER.size()) * 2}; + titel.add_component<Text>( + size_wouter, FONT, + Text::Data { + .world_space = false, + .text_color = Color::WHITE, + }, + vec2 {150, -207 + Y_OFFSET_NAMES * 2 + Y_OFFSET_NAMES_BEGIN} + FONTOFFSET, WOUTER + ); + + const string JARO = "Jaro Rutjes"; + crepe::vec2 size_jaro + = {JARO.size() * SIZE_CHAR_NAMES, (JARO.size() * SIZE_CHAR_NAMES / JARO.size()) * 2}; + titel.add_component<Text>( + size_jaro, FONT, + Text::Data { + .world_space = false, + .text_color = Color::WHITE, + }, + vec2 {150, -207 + Y_OFFSET_NAMES * 3 + Y_OFFSET_NAMES_BEGIN} + FONTOFFSET, JARO + ); + + const string MAX = "Max Smits"; + crepe::vec2 size_max + = {MAX.size() * SIZE_CHAR_NAMES, (MAX.size() * SIZE_CHAR_NAMES / MAX.size()) * 2}; + titel.add_component<Text>( + size_max, FONT, + Text::Data { + .world_space = false, + .text_color = Color::WHITE, + }, + vec2 {150, -207 + Y_OFFSET_NAMES * 4 + Y_OFFSET_NAMES_BEGIN} + FONTOFFSET, MAX + ); + + const string NIELS = "Niels Stunnebrink"; + crepe::vec2 size_niels + = {NIELS.size() * SIZE_CHAR_NAMES, (NIELS.size() * SIZE_CHAR_NAMES / NIELS.size()) * 2 + }; + titel.add_component<Text>( + size_niels, FONT, + Text::Data { + .world_space = false, + .text_color = Color::WHITE, + }, + vec2 {150, -207 + Y_OFFSET_NAMES * 5 + Y_OFFSET_NAMES_BEGIN} + FONTOFFSET, NIELS + ); +} diff --git a/game/menus/mainmenu/CreditsSubScene.h b/game/menus/mainmenu/CreditsSubScene.h new file mode 100644 index 0000000..e7ff735 --- /dev/null +++ b/game/menus/mainmenu/CreditsSubScene.h @@ -0,0 +1,9 @@ +#pragma once + +#include <crepe/api/Scene.h> + +class CreditsSubScene { + +public: + void create(crepe::Scene & scn); +}; diff --git a/game/menus/mainmenu/CreditsSubScript.cpp b/game/menus/mainmenu/CreditsSubScript.cpp new file mode 100644 index 0000000..4224dc8 --- /dev/null +++ b/game/menus/mainmenu/CreditsSubScript.cpp @@ -0,0 +1,58 @@ +#include "CreditsSubScript.h" + +#include "../../Events.h" +#include "../ButtonReplaySubScript.h" +#include "../IFloatingWindowScript.h" + +#include <string> + +#include <crepe/api/Button.h> +#include <crepe/api/Sprite.h> +#include <crepe/api/Text.h> +#include <crepe/types.h> + +using namespace crepe; + +CreditsSubScript::CreditsSubScript(const std::string & tag) { this->tag = tag; } + +void CreditsSubScript::init() { + IButtonScript::init(); + this->subscribe<ButtonPressEvent>([this](const ButtonPressEvent & e) { + return this->on_button_press(e); + }); + this->subscribe<ShowCreditsEvent>([this](const ShowCreditsEvent & e) { + this->enable_all(); + return false; + }); + this->disable_all(); +} + +bool CreditsSubScript::disable_all() { + IFloatingWindowScript::disable_all_sprites(); + RefVector<Button> buttons = this->get_components_by_tag<Button>(this->tag); + for (Button & button : buttons) { + button.active = false; + } + RefVector<Text> texts = this->get_components_by_tag<Text>(this->tag); + for (Text & text : texts) { + text.active = false; + } + return false; +} + +bool CreditsSubScript::enable_all() { + IFloatingWindowScript::enable_all_sprites(); + RefVector<Button> buttons = this->get_components_by_tag<Button>(this->tag); + for (Button & button : buttons) { + button.active = true; + } + RefVector<Text> texts = this->get_components_by_tag<Text>(this->tag); + for (Text & text : texts) { + text.active = true; + } + return false; +} + +bool CreditsSubScript::on_button_press(const ButtonPressEvent & e) { + return this->disable_all(); +} diff --git a/game/menus/mainmenu/CreditsSubScript.h b/game/menus/mainmenu/CreditsSubScript.h new file mode 100644 index 0000000..81f941a --- /dev/null +++ b/game/menus/mainmenu/CreditsSubScript.h @@ -0,0 +1,18 @@ +#pragma once + +#include "../IButtonScript.h" +#include "../IFloatingWindowScript.h" + +#include <crepe/api/Event.h> +#include <crepe/api/Script.h> + +struct ShowCreditsEvent : public crepe::Event {}; + +class CreditsSubScript : public IFloatingWindowScript, public IButtonScript { +public: + CreditsSubScript(const std::string & tag); + void init() override; + bool disable_all(); + bool enable_all(); + bool on_button_press(const crepe::ButtonPressEvent & e); +}; diff --git a/game/menus/mainmenu/ITransitionScript.cpp b/game/menus/mainmenu/ITransitionScript.cpp new file mode 100644 index 0000000..54b0875 --- /dev/null +++ b/game/menus/mainmenu/ITransitionScript.cpp @@ -0,0 +1,30 @@ +#include "ITransitionScript.h" +#include "MainMenuConfig.h" + +#include "../../Config.h" +#include "../MenusConfig.h" + +#include <crepe/api/Camera.h> +#include <crepe/api/Transform.h> +#include <crepe/types.h> + +using namespace crepe; +using namespace std; + +void ITransitionScript::frame_update(crepe::duration_t delta_time) { + if (this->transition) { + // cout << "transition:" << velocity << std::endl; + Transform & cam = this->get_components_by_name<Transform>(CAMERA_NAME).front(); + RefVector<Transform> info_tf = this->get_components_by_tag<Transform>(MENU_INFO_TAG); + for (Transform & tf : info_tf) { + tf.position.y -= VELOCITY_INFO_UP * delta_time.count(); + } + if (velocity < VELOCITY_MAX && cam.position.x < SLOW_DOWN) + velocity += VELOCITY_STEP * delta_time.count(); + else if (velocity > 20) velocity -= VELOCITY_STEP * delta_time.count(); + if (cam.position.x < END) cam.position.x += (velocity * delta_time.count()); + if (cam.position.x >= END) { + this->set_next_scene(this->get_scene_name()); + } + } +} diff --git a/game/menus/mainmenu/ITransitionScript.h b/game/menus/mainmenu/ITransitionScript.h new file mode 100644 index 0000000..9a2ef90 --- /dev/null +++ b/game/menus/mainmenu/ITransitionScript.h @@ -0,0 +1,15 @@ +#pragma once + +#include <crepe/api/Script.h> + +class ITransitionScript : public virtual crepe::Script { +public: + void frame_update(crepe::duration_t delta_time) override; + virtual const char * get_scene_name() const = 0; + +private: + float velocity = 20; + +protected: + bool transition = false; +}; diff --git a/game/menus/mainmenu/MainMenuConfig.h b/game/menus/mainmenu/MainMenuConfig.h new file mode 100644 index 0000000..f4ca5a6 --- /dev/null +++ b/game/menus/mainmenu/MainMenuConfig.h @@ -0,0 +1,19 @@ +#pragma once +#include <crepe/types.h> + +//main menu config +static constexpr float STARTMAP_OFFSET = 50; +static constexpr crepe::vec2 MENU_OFFSET = {0, 0}; +static constexpr float MENU_BUTTON_SPACING = 10; +static constexpr const char * MENU_BUTTON_NAME = "menu_button_background"; +static constexpr crepe::vec2 MENU_OFFSET_BUTTON = {-400, -200}; +static constexpr crepe::vec2 MENU_OFFSET_BUTTON_BACKGROUND = {-400, 0}; +static constexpr const char * MENU_INFO_TAG = "menu_info"; +static constexpr crepe::vec2 MENU_OFFSET_INFO = {350, -365}; +static constexpr crepe::vec2 MENU_OFFSET_INFO_BACKGROUND = {350, -365}; //375 +//Moving to new scene (Start and Preview) +static constexpr float SLOW_DOWN = 200; +static constexpr float END = 300; +static constexpr float VELOCITY_MAX = 200; +static constexpr float VELOCITY_STEP = 200; +static constexpr float VELOCITY_INFO_UP = 40; diff --git a/game/menus/mainmenu/MainMenuScene.cpp b/game/menus/mainmenu/MainMenuScene.cpp new file mode 100644 index 0000000..c5d2030 --- /dev/null +++ b/game/menus/mainmenu/MainMenuScene.cpp @@ -0,0 +1,137 @@ + +#include "MainMenuScene.h" +#include "CreditsSubScene.h" +#include "MainMenuConfig.h" +#include "QuitScript.h" +#include "TransitionStartSubScript.h" + +#include "../ButtonSubScene.h" +#include "../MenusConfig.h" + +#include "../../Config.h" +#include "../../background/HallwaySubScene.h" +#include "../../background/StartSubScene.h" + +#include "../endgame/EndGameSubScene.h" + +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/Camera.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/Sprite.h> +#include <crepe/manager/SaveManager.h> + +using namespace crepe; +using namespace std; + +void MainMenuScene::load_scene() { + ButtonSubScene button; + + GameObject camera_object = this->new_object(CAMERA_NAME); + camera_object.add_component<Camera>( + ivec2(990, 720), vec2(1100, 800), + Camera::Data { + .bg_color = Color::BLACK, + } + ); + camera_object.add_component<BehaviorScript>().set_script<TransitionStartSubScript>(); + camera_object.add_component<BehaviorScript>().set_script<QuitScript>(); + + //Button menu + GameObject menu_button = this->new_object(MENU_BUTTON_NAME, MENU_BUTTON_NAME, MENU_OFFSET); + menu_button.add_component<Sprite>( + Asset("asset/ui/background.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 0, + .size = {300, 860}, + .position_offset = MENU_OFFSET_BUTTON_BACKGROUND, + } + ); + + vec2 pos_btn = MENU_OFFSET_BUTTON; + + //Preview btn + button.create( + *this, + ButtonSubScene::Data { + .text = "PREVIEW", + .text_width = 200, + .position = pos_btn, + .script_type = ButtonSubScene::ScriptSelect::PREVIEW, + .btn_side_color = ButtonSubScene::ButtonSideColor::PURPLE, + } + ); + + //Shop btn + pos_btn.y += MENU_BUTTON_SPACING + LARGE_OVERLAY_SIZE.y; + button.create( + *this, + ButtonSubScene::Data { + .text = "SHOP", + .text_offset = {-20, 0}, + .text_width = 110, + .icon_offset = {60, 0}, + .icon_type = ButtonSubScene::IconSelect::SHOP, + .position = pos_btn, + .script_type = ButtonSubScene::ScriptSelect::SHOP, + .btn_side_color = ButtonSubScene::ButtonSideColor::ORANGE, + } + ); + + //Credits btn + pos_btn.y += MENU_BUTTON_SPACING + LARGE_OVERLAY_SIZE.y; + button.create( + *this, + ButtonSubScene::Data { + .text = "CREDITS", + .text_offset = {0, 0}, + .text_width = 200, + .position = pos_btn, + .script_type = ButtonSubScene::ScriptSelect::CREDITS_SHOW, + .btn_side_color = ButtonSubScene::ButtonSideColor::BLUE, + } + ); + + //Start of map + StartSubScene start; + HallwaySubScene hallway; + float begin_x = start.create(*this, STARTMAP_OFFSET); + begin_x = hallway.create(*this, begin_x, 1, Color::YELLOW); + + //INFO menu + GameObject menu_info + = this->new_object("MENU_INFO_BACKGROUND", MENU_INFO_TAG, MENU_OFFSET); + menu_info.add_component<Sprite>( + Asset("asset/ui/itemsButtonBlankDark.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 0, + .size = {250, 80}, + .position_offset = MENU_OFFSET_INFO, + .world_space = false, + } + ); + SaveManager & savemgr = this->get_save_manager(); + string number = std::to_string(savemgr.get<int>(TOTAL_COINS_GAME, 0).get()); + float amount_number = static_cast<float>(number.size()); + // savemgr.set(COIN_GAME_AMOUNT, amount); + button.create( + *this, + ButtonSubScene::Data { + .text = number, + .text_offset = {-10 - (amount_number - 1) * 10, 0}, + .text_width = amount_number * 20, + .icon_offset = {60, 0}, + .icon_type = ButtonSubScene::IconSelect::COINS, + .position = MENU_OFFSET_INFO, + .script_type = ButtonSubScene::ScriptSelect::SHOP, + .scale = 0.6, + .worldspace = false, + .color_side = false, + .tag = MENU_INFO_TAG, + } + ); + + CreditsSubScene creditscene; + creditscene.create(*this); +} + +string MainMenuScene::get_name() const { return MAINMENU_SCENE; } diff --git a/game/menus/mainmenu/MainMenuScene.h b/game/menus/mainmenu/MainMenuScene.h new file mode 100644 index 0000000..1eea90e --- /dev/null +++ b/game/menus/mainmenu/MainMenuScene.h @@ -0,0 +1,10 @@ +#pragma once + +#include <crepe/api/Scene.h> +#include <string> + +class MainMenuScene : public crepe::Scene { +public: + void load_scene(); + std::string get_name() const; +}; diff --git a/game/menus/mainmenu/TransitionStartSubScript.cpp b/game/menus/mainmenu/TransitionStartSubScript.cpp new file mode 100644 index 0000000..f737f7f --- /dev/null +++ b/game/menus/mainmenu/TransitionStartSubScript.cpp @@ -0,0 +1,16 @@ +#include "TransitionStartSubScript.h" + +#include "../MenusConfig.h" + +using namespace crepe; +using namespace std; + +void TransitionStartSubScript::fixed_update(crepe::duration_t dt) { + if (this->get_key_state(Keycode::SPACE) && this->transition == false) + this->transition = true; +} + +const char * TransitionStartSubScript::get_scene_name() const { + // Provide the next scene defined in MainMenuConfig + return START_SCENE; +} diff --git a/game/menus/mainmenu/TransitionStartSubScript.h b/game/menus/mainmenu/TransitionStartSubScript.h new file mode 100644 index 0000000..f9862ea --- /dev/null +++ b/game/menus/mainmenu/TransitionStartSubScript.h @@ -0,0 +1,9 @@ +#pragma once + +#include "ITransitionScript.h" + +class TransitionStartSubScript : public ITransitionScript { +public: + void fixed_update(crepe::duration_t dt) override; + const char * get_scene_name() const override; +}; diff --git a/game/menus/shop/ButtonBuySelectBubbleScript.cpp b/game/menus/shop/ButtonBuySelectBubbleScript.cpp new file mode 100644 index 0000000..741afde --- /dev/null +++ b/game/menus/shop/ButtonBuySelectBubbleScript.cpp @@ -0,0 +1,34 @@ +#include "ButtonBuySelectBubbleScript.h" +#include "../MenusConfig.h" +#include "Config.h" +#include "ValueBroker.h" +#include "manager/SaveManager.h" +#include "menus/shop/Shopconfig.h" + +using namespace crepe; +using namespace std; + +void ButtonBuySelectBubbleScript::init() { + IButtonScript::init(); + this->subscribe<ButtonPressEvent>([this](const ButtonPressEvent & e) { + return this->on_button_press(e); + }); +} + +bool ButtonBuySelectBubbleScript::on_button_press(const ButtonPressEvent & e) { + SaveManager & save = this->get_save_manager(); + ValueBroker<int> buy_bullet = save.get<int>(BUY_BUBBLE_SAVE, 0); + if (!buy_bullet.get()) { + ValueBroker<int> coins = save.get<int>(TOTAL_COINS_GAME, 0); + if (coins.get() >= 1000) { + int coin = coins.get(); + coin -= 1000; + save.set(TOTAL_COINS_GAME, coin); + save.set(BUY_BUBBLE_SAVE, 1); + } + } else { + save.set(JETPACK_PARTICLES, 1); + } + this->trigger_event<ShopUpdate>(); + return false; +} diff --git a/game/menus/shop/ButtonBuySelectBubbleScript.h b/game/menus/shop/ButtonBuySelectBubbleScript.h new file mode 100644 index 0000000..ce276ef --- /dev/null +++ b/game/menus/shop/ButtonBuySelectBubbleScript.h @@ -0,0 +1,14 @@ +#pragma once + +#include "../IButtonScript.h" + +#include <crepe/api/Script.h> + +class ButtonBuySelectBubbleScript : public IButtonScript { +public: + void init() override; + bool on_button_press(const crepe::ButtonPressEvent & e); + +protected: + bool transition = false; +}; diff --git a/game/menus/shop/ButtonBuySelectBulletScript.cpp b/game/menus/shop/ButtonBuySelectBulletScript.cpp new file mode 100644 index 0000000..d30849c --- /dev/null +++ b/game/menus/shop/ButtonBuySelectBulletScript.cpp @@ -0,0 +1,34 @@ +#include "ButtonBuySelectBulletScript.h" +#include "../MenusConfig.h" +#include "Config.h" +#include "ValueBroker.h" +#include "manager/SaveManager.h" +#include "menus/shop/Shopconfig.h" + +using namespace crepe; +using namespace std; + +void ButtonBuySelectBulletScript::init() { + IButtonScript::init(); + this->subscribe<ButtonPressEvent>([this](const ButtonPressEvent & e) { + return this->on_button_press(e); + }); +} + +bool ButtonBuySelectBulletScript::on_button_press(const ButtonPressEvent & e) { + SaveManager & save = this->get_save_manager(); + ValueBroker<int> buy_bullet = save.get<int>(BUY_BULLET_SAVE, 0); + if (!buy_bullet.get()) { + ValueBroker<int> coins = save.get<int>(TOTAL_COINS_GAME, 0); + if (coins.get() >= 0) { + int coin = coins.get(); + coin -= 0; + save.set(TOTAL_COINS_GAME, coin); + save.set(BUY_BULLET_SAVE, 1); + } + } else { + save.set(JETPACK_PARTICLES, 0); + } + this->trigger_event<ShopUpdate>(); + return false; +} diff --git a/game/menus/shop/ButtonBuySelectBulletScript.h b/game/menus/shop/ButtonBuySelectBulletScript.h new file mode 100644 index 0000000..86de0ac --- /dev/null +++ b/game/menus/shop/ButtonBuySelectBulletScript.h @@ -0,0 +1,14 @@ +#pragma once + +#include "../IButtonScript.h" + +#include <crepe/api/Script.h> + +class ButtonBuySelectBulletScript : public IButtonScript { +public: + void init() override; + bool on_button_press(const crepe::ButtonPressEvent & e); + +protected: + bool transition = false; +}; diff --git a/game/menus/shop/ShopLoadScript.cpp b/game/menus/shop/ShopLoadScript.cpp new file mode 100644 index 0000000..a545fe2 --- /dev/null +++ b/game/menus/shop/ShopLoadScript.cpp @@ -0,0 +1,126 @@ +#include "ShopLoadScript.h" +#include "Shopconfig.h" +#include "api/Button.h" +#include "api/Sprite.h" +#include "api/Text.h" +#include "manager/SaveManager.h" +#include <crepe/ValueBroker.h> + +using namespace crepe; +using namespace std; + +void ShopLoadScript::init() { + this->update(); + this->subscribe<ShopUpdate>([this](const ShopUpdate e) { return this->update(); }); +} + +bool ShopLoadScript::update() { + SaveManager & save = this->get_save_manager(); + ValueBroker<int> buy_bullet = save.get<int>(BUY_BULLET_SAVE, 0); + ValueBroker<int> buy_bubble = save.get<int>(BUY_BUBBLE_SAVE, 0); + + if (buy_bullet.get()) { + auto sprites = this->get_components_by_tag<Sprite>(BUY_BULLET); + for (auto sprite : sprites) { + sprite.get().active = false; + } + auto buttons = this->get_components_by_tag<Button>(BUY_BULLET); + for (auto btn : buttons) { + btn.get().active = false; + } + auto texts = this->get_components_by_tag<Text>(BUY_BULLET); + for (auto txt : texts) { + txt.get().active = false; + } + auto sprites1 = this->get_components_by_tag<Sprite>(SELECT_BULLET); + for (auto sprite : sprites1) { + sprite.get().active = true; + } + auto buttons1 = this->get_components_by_tag<Button>(SELECT_BULLET); + for (auto btn : buttons1) { + btn.get().active = true; + } + auto texts1 = this->get_components_by_tag<Text>(SELECT_BULLET); + for (auto txt : texts1) { + txt.get().active = true; + } + } else { + auto sprites = this->get_components_by_tag<Sprite>(SELECT_BULLET); + for (auto sprite : sprites) { + sprite.get().active = false; + } + auto buttons = this->get_components_by_tag<Button>(SELECT_BULLET); + for (auto btn : buttons) { + btn.get().active = false; + } + auto texts = this->get_components_by_tag<Text>(SELECT_BULLET); + for (auto txt : texts) { + txt.get().active = false; + } + auto sprites1 = this->get_components_by_tag<Sprite>(BUY_BULLET); + for (auto sprite : sprites1) { + sprite.get().active = true; + } + auto buttons1 = this->get_components_by_tag<Button>(BUY_BULLET); + for (auto btn : buttons1) { + btn.get().active = true; + } + auto texts1 = this->get_components_by_tag<Text>(BUY_BULLET); + for (auto txt : texts1) { + txt.get().active = true; + } + } + + if (buy_bubble.get()) { + auto sprites = this->get_components_by_tag<Sprite>(BUY_BUBBLE); + for (auto sprite : sprites) { + sprite.get().active = false; + } + auto buttons = this->get_components_by_tag<Button>(BUY_BUBBLE); + for (auto btn : buttons) { + btn.get().active = false; + } + auto texts = this->get_components_by_tag<Text>(BUY_BUBBLE); + for (auto txt : texts) { + txt.get().active = false; + } + auto sprites1 = this->get_components_by_tag<Sprite>(SELECT_BUBBLE); + for (auto sprite : sprites1) { + sprite.get().active = true; + } + auto buttons1 = this->get_components_by_tag<Button>(SELECT_BUBBLE); + for (auto btn : buttons1) { + btn.get().active = true; + } + auto texts1 = this->get_components_by_tag<Text>(SELECT_BUBBLE); + for (auto txt : texts1) { + txt.get().active = true; + } + } else { + auto sprites = this->get_components_by_tag<Sprite>(SELECT_BUBBLE); + for (auto sprite : sprites) { + sprite.get().active = false; + } + auto buttons = this->get_components_by_tag<Button>(SELECT_BUBBLE); + for (auto btn : buttons) { + btn.get().active = false; + } + auto texts = this->get_components_by_tag<Text>(SELECT_BUBBLE); + for (auto txt : texts) { + txt.get().active = false; + } + auto sprites1 = this->get_components_by_tag<Sprite>(BUY_BUBBLE); + for (auto sprite : sprites1) { + sprite.get().active = true; + } + auto buttons1 = this->get_components_by_tag<Button>(BUY_BUBBLE); + for (auto btn : buttons1) { + btn.get().active = true; + } + auto texts1 = this->get_components_by_tag<Text>(BUY_BUBBLE); + for (auto txt : texts1) { + txt.get().active = true; + } + } + return false; +} diff --git a/game/menus/shop/ShopLoadScript.h b/game/menus/shop/ShopLoadScript.h new file mode 100644 index 0000000..b17bf1c --- /dev/null +++ b/game/menus/shop/ShopLoadScript.h @@ -0,0 +1,10 @@ +#pragma once + +#include <crepe/api/Script.h> +#include <crepe/manager/SaveManager.h> + +class ShopLoadScript : public crepe::Script { +public: + void init() override; + bool update(); +}; diff --git a/game/menus/shop/ShopMenuScene.cpp b/game/menus/shop/ShopMenuScene.cpp new file mode 100644 index 0000000..641352c --- /dev/null +++ b/game/menus/shop/ShopMenuScene.cpp @@ -0,0 +1,216 @@ + +#include "ShopMenuScene.h" + +#include "../../Config.h" +#include "../ButtonSubScene.h" +#include "../MenusConfig.h" +#include "api/BehaviorScript.h" +#include "menus/BannerSubScene.h" +#include "menus/shop/ShopLoadScript.h" +#include "types.h" + +#include "Shopconfig.h" +#include <crepe/api/Camera.h> +#include <crepe/api/Sprite.h> +#include <crepe/api/Text.h> + +using namespace crepe; +using namespace std; + +void ShopMenuScene::load_scene() { + GameObject camera_object = this->new_object(CAMERA_NAME); + camera_object.add_component<Camera>( + ivec2(990, 720), vec2(1100, 800), + Camera::Data { + .bg_color = Color::RED, + } + ); + BannerSubScene banner; + banner.create( + *this, + { + .banner_title = "SHOP", + .banner_title_width = 200, + .banner_title_offset = {0, 65}, + } + ); + GameObject menu_background = this->new_object("menu_background"); + menu_background.add_component<Sprite>( + Asset("asset/ui/background.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 0, + .size = {1100, 860}, + .position_offset {0}, + } + ); + menu_background.add_component<BehaviorScript>().set_script<ShopLoadScript>(); + + ButtonSubScene button; + button.create( + *this, + ButtonSubScene::Data { + .text = "BACK", + .text_width = 115, + .position = {-400, -350}, + .script_type = ButtonSubScene::ScriptSelect::MAINMENU, + .button_type = ButtonSubScene::ButtonSelect::BACK, + .scale = 0.8 + } + ); + + const float CHAR_SIZE = 16; + const float CHAR_SIZE_COIN = 16; + crepe::vec2 size; + + GameObject shop_item_bullet = this->new_object("bullet", "shop_item", vec2(-100, 0)); + shop_item_bullet.add_component<Sprite>( + Asset("asset/other_effects/effect_rocketmgshell_TVOS.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1, + .size = {0, 100}, + .position_offset = {0, 0}, + } + ); + + const string BULLETS_STRING = "BULLETS"; + size + = {CHAR_SIZE * BULLETS_STRING.size(), + (CHAR_SIZE * BULLETS_STRING.size() / BULLETS_STRING.size()) * 2}; + + shop_item_bullet.add_component<Text>( + size, FONT, + Text::Data { + .world_space = true, + .text_color = Color::WHITE, + }, + vec2 {0, -75}, BULLETS_STRING + ); + shop_item_bullet.add_component<Sprite>( + Asset("asset/ui/buttonCoinsSmall.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1, + .size = {0, 45}, + .position_offset = {25, 75}, + } + ); + + const string BULLETS_GOLD_STRING = "0"; + size + = {CHAR_SIZE_COIN * BULLETS_GOLD_STRING.size(), + (CHAR_SIZE_COIN * BULLETS_GOLD_STRING.size() / BULLETS_GOLD_STRING.size()) * 2}; + shop_item_bullet.add_component<Text>( + size, FONT, + Text::Data { + .world_space = true, + .text_color = Color::GOLD, + }, + vec2 {-5, 75}, BULLETS_GOLD_STRING + ); + + GameObject shop_item_bubble = this->new_object("bubble", "shop_item", vec2(100, 0)); + shop_item_bubble.add_component<Sprite>( + Asset("asset/background/aquarium/bubble.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1, + .size = {0, 100}, + .position_offset = {0, 0}, + } + ); + + const string BUBBLE_STRING = "BUBBLE"; + size + = {CHAR_SIZE * BUBBLE_STRING.size(), + (CHAR_SIZE * BUBBLE_STRING.size() / BUBBLE_STRING.size()) * 2}; + shop_item_bubble.add_component<Text>( + size, FONT, + Text::Data { + .world_space = true, + .text_color = Color::WHITE, + }, + vec2 {0, -75}, BUBBLE_STRING + ); + shop_item_bubble.add_component<Sprite>( + Asset("asset/ui/buttonCoinsSmall.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1, + .size = {0, 45}, + .position_offset = {45, 75}, + } + ); + + const string BUBBLE_GOLD_STRING = "1000"; + size + = {CHAR_SIZE_COIN * BUBBLE_GOLD_STRING.size(), + (CHAR_SIZE_COIN * BUBBLE_GOLD_STRING.size() / BUBBLE_GOLD_STRING.size()) * 2}; + shop_item_bubble.add_component<Text>( + size, FONT, + Text::Data { + .world_space = true, + .text_color = Color::GOLD, + }, + vec2 {-10, 75}, BUBBLE_GOLD_STRING + ); + + button.create( + *this, + ButtonSubScene::Data { + .text = "BUY", + .text_width = 100, + .position = vec2(-100, 120), + .script_type = ButtonSubScene::ScriptSelect::SHOP_BULLET, + .button_type = ButtonSubScene::ButtonSelect::LARGE, + .scale = 0.4, + .tag = BUY_BULLET, + .sorting_layer_offset = 20, + .btn_side_color = ButtonSubScene::ButtonSideColor::PURPLE + + } + ); + + button.create( + *this, + ButtonSubScene::Data { + .text = "BUY", + .text_width = 100, + .position = vec2(100, 120), + .script_type = ButtonSubScene::ScriptSelect::SHOP_BUBBLE, + .button_type = ButtonSubScene::ButtonSelect::LARGE, + .scale = 0.4, + .tag = BUY_BUBBLE, + .sorting_layer_offset = 20, + .btn_side_color = ButtonSubScene::ButtonSideColor::PURPLE + } + ); + + button.create( + *this, + ButtonSubScene::Data { + .text = "SELECT", + .text_width = 100, + .position = vec2(-100, 120), + .script_type = ButtonSubScene::ScriptSelect::SHOP_BULLET, + .button_type = ButtonSubScene::ButtonSelect::LARGE, + .scale = 0.4, + .tag = SELECT_BULLET, + .sorting_layer_offset = 20, + .btn_side_color = ButtonSubScene::ButtonSideColor::PURPLE + } + ); + + button.create( + *this, + ButtonSubScene::Data { + .text = "SELECT", + .text_width = 100, + .position = vec2(100, 120), + .script_type = ButtonSubScene::ScriptSelect::SHOP_BUBBLE, + .button_type = ButtonSubScene::ButtonSelect::LARGE, + .scale = 0.4, + .tag = SELECT_BUBBLE, + .sorting_layer_offset = 20, + .btn_side_color = ButtonSubScene::ButtonSideColor::PURPLE + } + ); +} + +string ShopMenuScene::get_name() const { return SHOP_SCENE; } diff --git a/game/menus/shop/ShopMenuScene.h b/game/menus/shop/ShopMenuScene.h new file mode 100644 index 0000000..34c05ff --- /dev/null +++ b/game/menus/shop/ShopMenuScene.h @@ -0,0 +1,12 @@ +#pragma once + +#include <string> + +#include <crepe/api/Scene.h> + +class ShopMenuScene : public crepe::Scene { +public: + void load_scene(); + + std::string get_name() const; +}; diff --git a/game/menus/shop/Shopconfig.h b/game/menus/shop/Shopconfig.h new file mode 100644 index 0000000..a686242 --- /dev/null +++ b/game/menus/shop/Shopconfig.h @@ -0,0 +1,14 @@ +#pragma once +#include "api/Event.h" + +//tags +static constexpr const char * BUY_BULLET = "BUY_BULLET"; +static constexpr const char * SELECT_BULLET = "SELECT_BULLET"; +static constexpr const char * BUY_BUBBLE = "BUY_BUBBLE"; +static constexpr const char * SELECT_BUBBLE = "SELECT_BUBBLE"; + +//save_data +static constexpr const char * BUY_BULLET_SAVE = "BUY_BULLET_SAVE"; +static constexpr const char * BUY_BUBBLE_SAVE = "BUY_BUBBLE_SAVE"; + +struct ShopUpdate : public crepe::Event {}; diff --git a/game/missile/AlertScript.cpp b/game/missile/AlertScript.cpp new file mode 100644 index 0000000..24b4af9 --- /dev/null +++ b/game/missile/AlertScript.cpp @@ -0,0 +1,38 @@ +#include "AlertScript.h" +#include "../Config.h" + +#include <crepe/api/CircleCollider.h> +#include <crepe/api/Sprite.h> +#include <crepe/api/Transform.h> + +using namespace crepe; + +void AlertScript::fixed_update(crepe::duration_t dt) { + const auto & cam = this->get_components_by_name<Transform>("camera").front().get(); + //missile transform + const auto & this_transform = this->get_component<Transform>(); + auto missile_transforms = this->get_components_by_name<Transform>("missile"); + const auto & this_collider = this->get_component<CircleCollider>(); + + auto alert_sprites = this->get_components_by_name<Sprite>("missile_alert"); + auto alert_transforms = this->get_components_by_name<Transform>("missile_alert"); + + int idx = 0; + for (int i = 0; i < missile_transforms.size(); i++) { + const auto & missile_transform = missile_transforms[i].get(); + if (this_transform.game_object_id == missile_transform.game_object_id) { + idx = i; + break; + } + } + + auto & alert_transform = alert_transforms[idx].get(); + alert_transform.position.x = cam.position.x + (VIEWPORT_X / 2 - 100); + alert_transform.position.y = this_transform.position.y; + + // check if transform is in camera view + if (this_transform.position.x > cam.position.x - (VIEWPORT_X / 2) + && this_transform.position.x < cam.position.x + (VIEWPORT_X / 2)) { + alert_sprites[idx].get().active = false; + } +} diff --git a/game/missile/AlertScript.h b/game/missile/AlertScript.h new file mode 100644 index 0000000..5b0b3a1 --- /dev/null +++ b/game/missile/AlertScript.h @@ -0,0 +1,11 @@ +#pragma once + +#include <crepe/api/Script.h> + +class AlertScript : public crepe::Script { +private: + bool has_alert = false; + +public: + void fixed_update(crepe::duration_t dt); +}; diff --git a/game/missile/AlertSubScene.cpp b/game/missile/AlertSubScene.cpp new file mode 100644 index 0000000..5bce5ac --- /dev/null +++ b/game/missile/AlertSubScene.cpp @@ -0,0 +1,33 @@ +#include "AlertSubScene.h" +#include "../Config.h" + +#include <crepe/api/Animator.h> +#include <crepe/api/Scene.h> +#include <crepe/api/Sprite.h> + +using namespace crepe; + +MissileAlert::MissileAlert(Scene & scn) { + GameObject alert = scn.new_object("missile_alert", "missile_alert", {0, 0}, 0, 1); + + Asset missile_alert_ss {"asset/obstacles/missile/missileAlert.png"}; + + auto & missile_alert_sprite = alert.add_component<Sprite>( + missile_alert_ss, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_OBSTACLES, + .size = {0, 100}, + } + ); + + auto & missile_alert_anim = alert.add_component<Animator>( + missile_alert_sprite, ivec2 {64, 64}, uvec2 {4, 2}, + Animator::Data { + .fps = 15, + .looping = true, + } + ); + + missile_alert_anim.set_anim(1); + missile_alert_sprite.active = false; +} diff --git a/game/missile/AlertSubScene.h b/game/missile/AlertSubScene.h new file mode 100644 index 0000000..8ea288f --- /dev/null +++ b/game/missile/AlertSubScene.h @@ -0,0 +1,8 @@ +#pragma once + +#include <crepe/api/Scene.h> + +class MissileAlert { +public: + MissileAlert(crepe::Scene & scn); +}; diff --git a/game/missile/MissilePool.cpp b/game/missile/MissilePool.cpp new file mode 100644 index 0000000..23f03c9 --- /dev/null +++ b/game/missile/MissilePool.cpp @@ -0,0 +1,18 @@ +#include "MissilePool.h" +#include "MissileSubScene.h" +#include "missile/AlertSubScene.h" + +#include <crepe/api/Scene.h> + +using namespace std; +using namespace crepe; + +MissilePool::MissilePool(Scene & scn) { + int amount = 0; + MissileSubScene missile; + while (amount < this->MAX_MISSILE_COUNT) { + MissileAlert alert(scn); + missile.create(scn); + amount++; + } +} diff --git a/game/missile/MissilePool.h b/game/missile/MissilePool.h new file mode 100644 index 0000000..296701e --- /dev/null +++ b/game/missile/MissilePool.h @@ -0,0 +1,11 @@ +#pragma once + +#include <crepe/api/Scene.h> + +class MissilePool { +public: + MissilePool(crepe::Scene & scn); + +private: + static constexpr unsigned int MAX_MISSILE_COUNT = 5; +}; diff --git a/game/missile/MissileScript.cpp b/game/missile/MissileScript.cpp new file mode 100644 index 0000000..bcc4f5b --- /dev/null +++ b/game/missile/MissileScript.cpp @@ -0,0 +1,110 @@ +#include "MissileScript.h" +#include "../Config.h" +#include <cmath> + +#include <crepe/api/AI.h> +#include <crepe/api/Animator.h> +#include <crepe/api/AudioSource.h> +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/CircleCollider.h> +#include <crepe/api/KeyCodes.h> +#include <crepe/api/Rigidbody.h> +#include <crepe/api/Sprite.h> +#include <crepe/api/Transform.h> +#include <crepe/system/CollisionSystem.h> +#include <crepe/types.h> + +using namespace std; +using namespace crepe; + +void MissileScript::init() { + subscribe<CollisionEvent>([this](const CollisionEvent & ev) -> bool { + return this->on_collision(ev); + }); + this->seeking_disabled = false; +} +void MissileScript::kill_missile() { + auto animations = this->get_components<Animator>(); + auto sprites = this->get_components<Sprite>(); + auto collider = this->get_component<CircleCollider>(); + auto & fly_sound = this->get_components<AudioSource>().front().get(); + auto & this_script = this->get_components<BehaviorScript>().front().get(); + + animations[0].get().active = false; + animations[1].get().active = false; + animations[2].get().active = true; + sprites[0].get().active = false; + sprites[1].get().active = false; + sprites[2].get().active = true; + collider.active = false; + this_script.active = false; + this->seeking_disabled = false; + + fly_sound.stop(); +} +void MissileScript::activate() { + auto anim = this->get_components<Animator>(); + auto sprites = this->get_components<Sprite>(); + + anim[0].get().active = true; + anim[1].get().active = true; + anim[2].get().stop(); + //anim[3].get().active = true; + + sprites[0].get().active = true; + sprites[1].get().active = true; + sprites[2].get().active = false; + //sprites[3].get().active = true; +} + +bool MissileScript::on_collision(const CollisionEvent & ev) { + auto & explosion_sound = this->get_components<AudioSource>().back().get(); + + this->kill_missile(); + explosion_sound.play(); + + return false; +} + +bool MissileScript::is_in_x_range(const Transform & missile, const Transform & player) { + return fabs(missile.position.x - player.position.x) <= this->X_RANGE; +} + +void MissileScript::fixed_update(crepe::duration_t dt) { + auto & explosion_anim = this->get_components<Animator>().back().get(); + auto & missile = this->get_component<Transform>(); + auto & m_ai = this->get_component<AI>(); + + const auto & player = this->get_components_by_name<Transform>("player").front().get(); + const auto & cam = this->get_components_by_name<Transform>("camera").front().get(); + const auto & velocity = this->get_component<Rigidbody>().data.linear_velocity; + + if (missile.position.x < (cam.position.x - VIEWPORT_X / 1.8)) { + this->kill_missile(); + return; + } + + // check if animation is at the end + if (explosion_anim.data.row == 7) { + this->activate(); + this->seeking_disabled = false; + } + + if (this->seeking_disabled) { + m_ai.seek_off(); + } else { + m_ai.seek_target = player.position; + m_ai.seek_on(); + + if (is_in_x_range(missile, player)) { + this->seeking_disabled = true; + m_ai.seek_off(); + } + } + + vec2 angle_pos = velocity; + float angle = atan2(angle_pos.y, angle_pos.x) * (180 / M_PI); + + missile.rotation = angle; + missile.position += velocity * dt.count(); +} diff --git a/game/missile/MissileScript.h b/game/missile/MissileScript.h new file mode 100644 index 0000000..a492e18 --- /dev/null +++ b/game/missile/MissileScript.h @@ -0,0 +1,20 @@ +#pragma once + +#include <crepe/api/Script.h> + +class MissileScript : public crepe::Script { +private: + bool on_collision(const crepe::CollisionEvent & ev); + + bool seeking_disabled; + + // will be used to calculate when ai will be stopped + static constexpr int X_RANGE = 90; + bool is_in_x_range(const crepe::Transform & missile, const crepe::Transform & player); + void kill_missile(); + void activate(); + +public: + void init(); + void fixed_update(crepe::duration_t dt); +}; diff --git a/game/missile/MissileSubScene.cpp b/game/missile/MissileSubScene.cpp new file mode 100644 index 0000000..d325050 --- /dev/null +++ b/game/missile/MissileSubScene.cpp @@ -0,0 +1,101 @@ +#include "MissileSubScene.h" +#include "../Config.h" +#include "../missile/MissileScript.h" +#include "Random.h" +#include "missile/AlertScript.h" + +#include <crepe/api/AI.h> +#include <crepe/api/Animator.h> +#include <crepe/api/AudioSource.h> +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/CircleCollider.h> +#include <crepe/api/Scene.h> +#include <crepe/api/Sprite.h> +#include <crepe/types.h> + +using namespace crepe; + +void MissileSubScene::create(crepe::Scene & scn) { + GameObject missle = scn.new_object("missile", "missile", {0, 0}, 0, 1); + + Asset missle_ss {"asset/obstacles/missile/missile.png"}; + Asset missle_thruster_ss {"asset/obstacles/missile/missileEffects.png"}; + Asset missile_explosion_ss {"asset/obstacles/missile/missileExplosion.png"}; + Asset explosion_sound {"asset/sfx/rocket_explode_1.ogg"}; + Asset missile_fire {"asset/sfx/missile_launch.ogg"}; + + missle.add_component<BehaviorScript>().set_script<MissileScript>().active = false; + missle.add_component<BehaviorScript>().set_script<AlertScript>(); + + auto & sound = missle.add_component<AudioSource>(missile_fire); + sound.volume = 0.5; + auto & sound2 = missle.add_component<AudioSource>(explosion_sound); + sound2.volume = 3; + + // sprites + auto & missle_sprite = missle.add_component<Sprite>( + missle_ss, + Sprite::Data { + .flip = {true, false}, + .sorting_in_layer = SORT_IN_LAY_OBSTACLES, + .size = {0, 35}, + } + ); + + auto & missle_thruster_sprite = missle.add_component<Sprite>( + missle_thruster_ss, + Sprite::Data { + .flip = {true, false}, + .sorting_in_layer = SORT_IN_LAY_OBSTACLES, + .size = {0, 35}, + .position_offset = {-20, 0}, + } + ); + + auto & missile_explosion_sprite = missle.add_component<Sprite>( + missile_explosion_ss, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_OBSTACLES, + .size = {0, 50}, + } + ); + + // Animations + missle.add_component<Animator>( + missle_sprite, ivec2 {32, 32}, uvec2 {4, 1}, + Animator::Data { + .fps = 15, + .looping = true, + } + ); + + missle.add_component<Animator>( + missle_thruster_sprite, ivec2 {64, 64}, uvec2 {4, 2}, + Animator::Data { + .fps = 15, + .looping = true, + } + ); + + auto & explosion_anim = missle.add_component<Animator>( + missile_explosion_sprite, ivec2 {64, 64}, uvec2 {8, 1}, + Animator::Data { + .fps = 10, + } + ); + + missile_explosion_sprite.active = false; + explosion_anim.active = false; + + missle.add_component<Rigidbody>(Rigidbody::Data { + .body_type = Rigidbody::BodyType::KINEMATIC, + .max_linear_velocity = Random::f(250, 200), + .kinematic_collision = false, + .collision_layers = {COLL_LAY_PLAYER, COLL_LAY_BOT_TOP}, + .collision_layer = COLL_LAY_MISSILE, + }); + + missle.add_component<CircleCollider>(3).active = false; + + auto & missle_ai = missle.add_component<AI>(1000); +} diff --git a/game/missile/MissileSubScene.h b/game/missile/MissileSubScene.h new file mode 100644 index 0000000..9ea422a --- /dev/null +++ b/game/missile/MissileSubScene.h @@ -0,0 +1,12 @@ +#pragma once + +namespace crepe { +class Scene; +} + +class MissileSubScene { +public: + MissileSubScene() = default; + + void create(crepe::Scene & scn); +}; diff --git a/game/missile/SpawnEvent.cpp b/game/missile/SpawnEvent.cpp new file mode 100644 index 0000000..c7209b7 --- /dev/null +++ b/game/missile/SpawnEvent.cpp @@ -0,0 +1,49 @@ +#include "SpawnEvent.h" +#include "Random.h" + +#include <crepe/api/Animator.h> +#include <crepe/api/AudioSource.h> +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/Camera.h> +#include <crepe/api/CircleCollider.h> +#include <crepe/api/Sprite.h> +#include <crepe/api/Transform.h> + +#include <cstdlib> + +using namespace crepe; + +void MissileSpawnEventHandler::init() { + subscribe<MissileSpawnEvent>([this](const MissileSpawnEvent & ev) -> bool { + return this->on_event(ev); + }); +} + +bool MissileSpawnEventHandler::on_event(const MissileSpawnEvent & event) { + auto missile_transforms = this->get_components_by_name<Transform>("missile"); + auto alert_sprites = this->get_components_by_name<Sprite>("missile_alert"); + auto alert_transforms = this->get_components_by_name<Transform>("missile_alert"); + auto colliders = this->get_components_by_name<CircleCollider>("missile"); + auto missile_behaviorscripts = this->get_components_by_name<BehaviorScript>("missile"); + auto missile_audiosources = this->get_components_by_name<AudioSource>("missile"); + auto & camera_transform = this->get_components_by_name<Transform>("camera").front().get(); + + for (size_t i = 0; i < missile_behaviorscripts.size(); ++i) { + auto & script = missile_behaviorscripts[i * 2].get(); + if (script.active) continue; + script.active = true; + colliders[i].get().active = true; + missile_audiosources[i * 2].get().play(); + + auto & transform = missile_transforms[i].get(); + transform.position.x = camera_transform.position.x + this->MISSILE_OFFSET; + transform.position.y = Random::i(this->MAX_RANGE, this->MIN_RANGE); + + auto & alert_transform = alert_transforms[i].get(); + auto & alert_sprite = alert_sprites[i].get(); + alert_sprite.active = true; + break; + } + + return false; +} diff --git a/game/missile/SpawnEvent.h b/game/missile/SpawnEvent.h new file mode 100644 index 0000000..58293d7 --- /dev/null +++ b/game/missile/SpawnEvent.h @@ -0,0 +1,20 @@ +#pragma once + +#include <crepe/api/Event.h> +#include <crepe/api/Script.h> + +#include "../Config.h" + +struct MissileSpawnEvent : public crepe::Event {}; + +class MissileSpawnEventHandler : public crepe::Script { +private: + static constexpr int MISSILE_OFFSET = VIEWPORT_X; + static constexpr int RANGE = GAME_HEIGHT / 4; + static constexpr int MIN_RANGE = -RANGE; + static constexpr int MAX_RANGE = RANGE; + +public: + void init(); + bool on_event(const MissileSpawnEvent & ev); +}; diff --git a/game/player/PlayerAudioScript.cpp b/game/player/PlayerAudioScript.cpp new file mode 100644 index 0000000..6b5f630 --- /dev/null +++ b/game/player/PlayerAudioScript.cpp @@ -0,0 +1,62 @@ +#include "PlayerAudioScript.h" + +#include <crepe/api/Animator.h> +#include <crepe/api/AudioSource.h> + +using namespace crepe; +using namespace std; + +void PlayerAudioScript::fixed_update(crepe::duration_t dt) { + Animator & animator = this->get_components_by_name<Animator>("player").front(); + + if (animator.data.col == 0) { + if (animator.data.row != this->last_row) { + if (animator.data.row == 0) { + // right footstep + if (current_footstep == 0) { + AudioSource & audio + = this->get_components_by_name<AudioSource>("player_audio").at(0); + audio.play(); + } else if (current_footstep == 1) { + AudioSource & audio + = this->get_components_by_name<AudioSource>("player_audio").at(2); + audio.play(); + } else if (current_footstep == 2) { + AudioSource & audio + = this->get_components_by_name<AudioSource>("player_audio").at(4); + audio.play(); + } else if (current_footstep == 3) { + AudioSource & audio + = this->get_components_by_name<AudioSource>("player_audio").at(6); + audio.play(); + } + } else if (animator.data.row == 2) { + // left footstep + if (current_footstep == 0) { + AudioSource & audio + = this->get_components_by_name<AudioSource>("player_audio").at(1); + audio.play(); + current_footstep = 1; + } else if (current_footstep == 1) { + AudioSource & audio + = this->get_components_by_name<AudioSource>("player_audio").at(3); + audio.play(); + current_footstep = 2; + } else if (current_footstep == 2) { + AudioSource & audio + = this->get_components_by_name<AudioSource>("player_audio").at(5); + audio.play(); + current_footstep = 3; + } else if (current_footstep == 3) { + AudioSource & audio + = this->get_components_by_name<AudioSource>("player_audio").at(7); + audio.play(); + current_footstep = 0; + } + } + this->last_row = animator.data.row; + } + } else { + this->last_row = -1; + } +} diff --git a/game/player/PlayerAudioScript.h b/game/player/PlayerAudioScript.h new file mode 100644 index 0000000..764cb20 --- /dev/null +++ b/game/player/PlayerAudioScript.h @@ -0,0 +1,13 @@ +#pragma once + +#include <crepe/api/Event.h> +#include <crepe/api/Script.h> + +class PlayerAudioScript : public crepe::Script { +public: + void fixed_update(crepe::duration_t dt); + +private: + int last_row = -1; + int current_footstep = 0; +}; diff --git a/game/player/PlayerBulletPool.cpp b/game/player/PlayerBulletPool.cpp new file mode 100644 index 0000000..5285ec8 --- /dev/null +++ b/game/player/PlayerBulletPool.cpp @@ -0,0 +1,11 @@ +#include "PlayerBulletPool.h" +#include "PlayerBulletSubScene.h" +using namespace std; + +void PlayerBulletPool::create_bullets(crepe::Scene & scn) { + PlayerBulletSubScene bullet; + int amount = 0; + while (amount < this->MAXIMUM_AMOUNT) { + amount = bullet.create(scn, amount); + } +} diff --git a/game/player/PlayerBulletPool.h b/game/player/PlayerBulletPool.h new file mode 100644 index 0000000..9618d54 --- /dev/null +++ b/game/player/PlayerBulletPool.h @@ -0,0 +1,11 @@ +#pragma once + +#include <crepe/api/Scene.h> + +class PlayerBulletPool { +public: + void create_bullets(crepe::Scene & scn); + +private: + static constexpr int MAXIMUM_AMOUNT = 20; +}; diff --git a/game/player/PlayerBulletScript.cpp b/game/player/PlayerBulletScript.cpp new file mode 100644 index 0000000..a823375 --- /dev/null +++ b/game/player/PlayerBulletScript.cpp @@ -0,0 +1,41 @@ + +#include <crepe/api/Camera.h> +#include <crepe/api/Metadata.h> +#include <crepe/api/Rigidbody.h> + +#include "PlayerBulletScript.h" + +using namespace crepe; +using namespace std; +void PlayerBulletScript::init() { + this->subscribe<CollisionEvent>([this](const CollisionEvent & e) -> bool { + return this->on_collide(e); + }); +} +void PlayerBulletScript::fixed_update(crepe::duration_t dt) { + Transform & transform = this->get_component<Transform>(); + Camera & camera = this->get_components_by_name<Camera>("camera").front(); + Transform & cam_transform = this->get_components_by_name<Transform>("camera").front(); + Rigidbody & bullet_body = this->get_component<Rigidbody>(); + transform.rotation += bullet_body.data.angular_velocity * dt.count(); + transform.position += bullet_body.data.linear_velocity * dt.count(); + vec2 half_screen = camera.viewport_size / 2; + float despawn_location = cam_transform.position.x + half_screen.x + 50; + if (transform.position.x > despawn_location) { + this->despawn_bullet(); + } +} + +void PlayerBulletScript::despawn_bullet() { + Transform & transform = this->get_component<Transform>(); + Rigidbody & bullet_body = this->get_component<Rigidbody>(); + bullet_body.active = false; + BehaviorScript & bullet_script = this->get_component<BehaviorScript>(); + bullet_script.active = false; + transform.position = {0, -850}; +} + +bool PlayerBulletScript::on_collide(const CollisionEvent & e) { + this->despawn_bullet(); + return false; +} diff --git a/game/player/PlayerBulletScript.h b/game/player/PlayerBulletScript.h new file mode 100644 index 0000000..0637790 --- /dev/null +++ b/game/player/PlayerBulletScript.h @@ -0,0 +1,11 @@ +#pragma once +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/Script.h> + +class PlayerBulletScript : public crepe::Script { +public: + void init() override; + void fixed_update(crepe::duration_t dt) override; + bool on_collide(const crepe::CollisionEvent & e); + void despawn_bullet(); +}; diff --git a/game/player/PlayerBulletSubScene.cpp b/game/player/PlayerBulletSubScene.cpp new file mode 100644 index 0000000..5e1c66e --- /dev/null +++ b/game/player/PlayerBulletSubScene.cpp @@ -0,0 +1,52 @@ +#include <string> + +#include "../Config.h" +#include <crepe/api/AI.h> +#include <crepe/api/Animator.h> +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/BoxCollider.h> +#include <crepe/api/CircleCollider.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/Rigidbody.h> +#include <crepe/api/Scene.h> +#include <crepe/api/Sprite.h> + +#include "PlayerBulletScript.h" +#include "PlayerBulletSubScene.h" +#include "PlayerScript.h" +using namespace crepe; +using namespace std; +int PlayerBulletSubScene::create(Scene & scn, int counter) { + string unique_name = "player_bullet_" + to_string(counter++); + GameObject player_bullet + = scn.new_object(unique_name.c_str(), "player_bullet", vec2 {0, -850}, 0, 1); + + Rigidbody & player_bullet_body = player_bullet.add_component<Rigidbody>(Rigidbody::Data { + .gravity_scale = 0, + .body_type = Rigidbody::BodyType::KINEMATIC, + .linear_velocity = vec2 {400, 0}, + .angular_velocity = 300, + .kinematic_collision = false, + .collision_layers = {COLL_LAY_ENEMY, COLL_LAY_ZAPPER}, + + .collision_layer = COLL_LAY_PLAYER_BULLET, + + }); + player_bullet_body.active = false; + BoxCollider & player_bullet_collider + = player_bullet.add_component<BoxCollider>(vec2(30, 30)); + + Asset player_bullet_asset {"asset/other_effects/crepe.png"}; + Sprite & player_bullet_sprite = player_bullet.add_component<Sprite>( + player_bullet_asset, + Sprite::Data { + .flip = {true, false}, + .sorting_in_layer = SORT_IN_LAY_OBSTACLES, + .order_in_layer = 1, + .size = vec2(30, 0), + } + ); + player_bullet.add_component<BehaviorScript>().set_script<PlayerBulletScript>().active + = false; + return counter; +} diff --git a/game/player/PlayerBulletSubScene.h b/game/player/PlayerBulletSubScene.h new file mode 100644 index 0000000..72eda62 --- /dev/null +++ b/game/player/PlayerBulletSubScene.h @@ -0,0 +1,10 @@ +#pragma once + +namespace crepe { +class Scene; +} + +class PlayerBulletSubScene { +public: + int create(crepe::Scene & scn, int counter); +}; diff --git a/game/player/PlayerEndScript.cpp b/game/player/PlayerEndScript.cpp new file mode 100644 index 0000000..4ae813f --- /dev/null +++ b/game/player/PlayerEndScript.cpp @@ -0,0 +1,103 @@ +#include "PlayerEndScript.h" + +#include "../Config.h" +#include "../Events.h" +#include "manager/LoopTimerManager.h" + +#include <crepe/api/Animator.h> +#include <crepe/api/BoxCollider.h> +#include <crepe/api/CircleCollider.h> +#include <crepe/api/Rigidbody.h> +#include <crepe/types.h> + +using namespace crepe; +using namespace std; + +void PlayerEndScript::init() { + Rigidbody & rb_player = this->get_components_by_name<Rigidbody>("player").front(); + rb_player.data.elasticity_coefficient = 0.7; + + subscribe<CollisionEvent>([this](const CollisionEvent & ev) -> bool { + return this->on_collision(ev); + }); +} + +bool PlayerEndScript::on_collision(const crepe::CollisionEvent & ev) { + if (ev.info.other.metadata.name == "floor") { + Transform & transform_player + = this->get_components_by_name<Transform>("player").front(); + RefVector<Animator> anim_player = this->get_components_by_name<Animator>("player"); + Rigidbody & rb_player = this->get_components_by_name<Rigidbody>("player").front(); + Rigidbody & rb_camera = this->get_components_by_name<Rigidbody>("camera").front(); + + float dt = this->get_loop_timer().get_fixed_delta_time().count(); + + if (jump == 0) { + int random_number = rand() % 4; + for (Animator & anim : anim_player) { + anim.active = false; + anim.set_anim(6); + for (int i = 0; i < random_number; i++) { + anim.next_anim(); + } + } + } else if (jump == 1) { + for (Animator & anim : anim_player) { + anim.next_anim(); + } + } + + if (jump == 0) { + rb_player.data.angular_velocity = 16000 * dt; + rb_player.data.angular_velocity_coefficient = 0.7; + jump++; + } else if (jump == 1) { + jump++; + } else if (jump == 2) { + RefVector<Rigidbody> rb_back_forest + = this->get_components_by_tag<Rigidbody>("forest_background"); + for (Rigidbody & rb : rb_back_forest) { + rb.data.linear_velocity_coefficient = vec2(0.5, 0.5); + } + + rb_player.data.angular_velocity = 0; + rb_player.data.elasticity_coefficient = 0; + if (rb_player.data.linear_velocity.x != 0) { + rb_player.data.linear_velocity = vec2(PLAYER_SPEED * dt, 0); + } + rb_player.data.linear_velocity_coefficient = vec2(0.5, 0.5); + rb_camera.data.linear_velocity_coefficient = vec2(0.5, 0.5); + for (Animator & anim : anim_player) { + anim.active = false; + anim.set_anim(7); + } + if (transform_player.rotation > 0 && transform_player.rotation < 90) { + // Do not call next_anim() + } else if (transform_player.rotation > 90 && transform_player.rotation < 180) { + for (Animator & anim : anim_player) { + anim.next_anim(); + } + } else if (transform_player.rotation > 180 && transform_player.rotation < 270) { + for (Animator & anim : anim_player) { + anim.next_anim(); + anim.next_anim(); + } + } else { + for (Animator & anim : anim_player) { + anim.next_anim(); + anim.next_anim(); + anim.next_anim(); + } + } + jump++; + } + + if (rb_player.data.linear_velocity.x < 5 && jump >= 3) { + this->trigger_event<EndGameEvent>(); + } + + return false; + } + + return false; +} diff --git a/game/player/PlayerEndScript.h b/game/player/PlayerEndScript.h new file mode 100644 index 0000000..03ea8a9 --- /dev/null +++ b/game/player/PlayerEndScript.h @@ -0,0 +1,14 @@ +#pragma once + +#include <crepe/api/Script.h> + +class PlayerEndScript : public crepe::Script { +public: + void init(); + +private: + bool on_collision(const crepe::CollisionEvent & ev); + +private: + int jump = 0; +}; diff --git a/game/player/PlayerScript.cpp b/game/player/PlayerScript.cpp new file mode 100644 index 0000000..14ad9cd --- /dev/null +++ b/game/player/PlayerScript.cpp @@ -0,0 +1,215 @@ +#include "PlayerScript.h" + +#include "../Config.h" +#include "../enemy/BattleScript.h" + +#include <crepe/api/Animator.h> +#include <crepe/api/AudioSource.h> +#include <crepe/api/BoxCollider.h> +#include <crepe/api/ParticleEmitter.h> +#include <crepe/api/Rigidbody.h> +#include <crepe/api/Transform.h> +#include <crepe/types.h> + +using namespace crepe; +using namespace std; + +void PlayerScript::init() { + subscribe<CollisionEvent>([this](const CollisionEvent & ev) -> bool { + return this->on_collision(ev); + }); + subscribe<KeyPressEvent>([this](const KeyPressEvent & ev) -> bool { + if (ev.repeat) return false; + return this->on_key_down(ev); + }); + subscribe<KeyReleaseEvent>([this](const KeyReleaseEvent & ev) -> bool { + return this->on_key_up(ev); + }); + this->last_fired = std::chrono::steady_clock::now(); + this->body = get_component<Rigidbody>(); +} + +bool PlayerScript::on_key_down(const KeyPressEvent & ev) { + if (ev.repeat) return false; + if (ev.key == Keycode::SPACE) { + const vec2 UP = {0, -1}; + this->help_kick(UP); + } + return false; +} + +bool PlayerScript::on_key_up(const KeyReleaseEvent & ev) { + if (ev.key == Keycode::SPACE) { + const vec2 DOWN = {0, 1}; + this->help_kick(DOWN); + } + return false; +} + +void PlayerScript::help_kick(const vec2 & direction) { + // softly "kick" the player (at start/end of flight) + vec2 & velocity = this->body->data.linear_velocity; + float kick_amount = std::min( + velocity.length() * PLAYER_HELP_KICK_SCALE, engine_gravity * PLAYER_HELP_KICK_MAX + ); + velocity += direction * kick_amount; +} + +bool PlayerScript::on_collision(const CollisionEvent & ev) { + BehaviorScript & play_scr = this->get_components_by_name<BehaviorScript>("player").front(); + BehaviorScript & end_scr = this->get_components_by_name<BehaviorScript>("player").back(); + RefVector<Animator> animators = this->get_components_by_name<Animator>("player"); + RefVector<ParticleEmitter> emitters + = this->get_components_by_name<ParticleEmitter>("player"); + + if (ev.info.other.metadata.tag == "zapper") { + for (Animator & anim : animators) { + anim.active = true; + anim.set_anim(4); + anim.data.looping = true; + prev_anim = 0; + } + for (ParticleEmitter & emitter : emitters) { + emitter.data.emission_rate = 0; + } + play_scr.active = false; + end_scr.active = true; + + AudioSource & audio = this->get_components_by_name<AudioSource>("player").at(0); + audio.play(); + + return false; + } else if (ev.info.other.metadata.tag == "laser") { + for (Animator & anim : animators) { + anim.active = true; + anim.set_anim(4); + anim.data.looping = true; + prev_anim = 0; + } + for (ParticleEmitter & emitter : emitters) { + emitter.data.emission_rate = 0; + } + play_scr.active = false; + end_scr.active = true; + + AudioSource & audio = this->get_components_by_name<AudioSource>("player").at(1); + audio.play(); + + return false; + } else if (ev.info.other.metadata.tag == "missile" + || ev.info.other.metadata.tag == "enemy_bullet") { + for (Animator & anim : animators) { + anim.active = true; + anim.set_anim(5); + anim.data.looping = true; + prev_anim = 0; + } + for (ParticleEmitter & emitter : emitters) { + emitter.data.emission_rate = 0; + } + play_scr.active = false; + end_scr.active = true; + + AudioSource & audio = this->get_components_by_name<AudioSource>("player").at(2); + audio.play(); + + return false; + } + + return false; +} + +void PlayerScript::fixed_update(crepe::duration_t dt) { + RefVector<Animator> animators = this->get_components_by_name<Animator>("player"); + RefVector<ParticleEmitter> emitters + = this->get_components_by_name<ParticleEmitter>("player"); + Transform & transform = this->get_components_by_name<Transform>("player").front(); + + for (ParticleEmitter & emitter : emitters) { + emitter.data.boundary.offset = vec2(0, -transform.position.y); + } + + Rigidbody & rb = this->body; + if (this->get_key_state(Keycode::ENTER)) { + + auto now = std::chrono::steady_clock::now(); + std::chrono::duration<float> elapsed = now - last_fired; + if (elapsed > shot_delay) { + this->shoot(transform.position, 0); + last_fired = now; + } + } + if (this->get_key_state(Keycode::SPACE)) { + rb.add_force_linear( + vec2(0, -1) * (engine_gravity * PLAYER_GRAVITY_SCALE * dt.count()) + ); + + if (prev_anim != 1) { + for (Animator & anim : animators) { + anim.active = true; + anim.set_anim(1); + anim.data.looping = true; + prev_anim = 1; + } + for (ParticleEmitter & emitter : emitters) { + emitter.data.emission_rate = 30; + } + } + + AudioSource & audio = this->get_components_by_name<AudioSource>("player").at( + 3 + current_jetpack_sound + ); + audio.play(); + current_jetpack_sound++; + if (current_jetpack_sound > 7) { + current_jetpack_sound = 0; + } + } else if (transform.position.y == 195) { + Rigidbody & rb = this->body; + if (prev_anim != 0 && rb.data.linear_velocity.x != 0) { + for (Animator & anim : animators) { + anim.active = true; + anim.set_anim(0); + anim.data.looping = true; + prev_anim = 0; + } + for (ParticleEmitter & emitter : emitters) { + emitter.data.emission_rate = 0; + } + } + } else { + if (prev_anim != 2) { + for (Animator & anim : animators) { + anim.set_anim(2); + anim.data.looping = false; + prev_anim = 2; + } + for (ParticleEmitter & emitter : emitters) { + emitter.data.emission_rate = 0; + } + } + } +} + +void PlayerScript::shoot(const vec2 & location, float angle) { + RefVector<Transform> bullet_transforms + = this->get_components_by_tag<Transform>("player_bullet"); + + for (Transform & bullet_pos : bullet_transforms) { + if (bullet_pos.position.x == 0 && bullet_pos.position.y == -850) { + + bullet_pos.position = location; + bullet_pos.position.x += 20; + Rigidbody & bullet_body + = this->get_components_by_id<Rigidbody>(bullet_pos.game_object_id).front(); + BoxCollider bullet_collider + = this->get_components_by_id<BoxCollider>(bullet_pos.game_object_id).front(); + bullet_body.active = true; + BehaviorScript & bullet_script + = this->get_components_by_id<BehaviorScript>(bullet_pos.game_object_id) + .front(); + bullet_script.active = true; + return; + } + } +} diff --git a/game/player/PlayerScript.h b/game/player/PlayerScript.h new file mode 100644 index 0000000..6875b05 --- /dev/null +++ b/game/player/PlayerScript.h @@ -0,0 +1,31 @@ +#pragma once + +#include "util/OptionalRef.h" +#include <chrono> +#include <crepe/api/Config.h> +#include <crepe/api/Event.h> +#include <crepe/api/Script.h> + +class PlayerScript : public crepe::Script { +public: + void init(); + void fixed_update(crepe::duration_t dt); + +private: + bool on_collision(const crepe::CollisionEvent & ev); + bool on_key_down(const crepe::KeyPressEvent & ev); + bool on_key_up(const crepe::KeyReleaseEvent & ev); + // bool on_key_up(const crepe::KeyReleaseEvent& ev); + void shoot(const crepe::vec2 & location, float angle); + void help_kick(const crepe::vec2 & direction); + +private: + int prev_anim = 0; + std::chrono::time_point<std::chrono::steady_clock> last_fired; + std::chrono::duration<float> shot_delay = std::chrono::duration<float>(0.5); + + int current_jetpack_sound = 0; + + float & engine_gravity = crepe::Config::get_instance().physics.gravity; + crepe::OptionalRef<crepe::Rigidbody> body; +}; diff --git a/game/player/PlayerSubScene.cpp b/game/player/PlayerSubScene.cpp new file mode 100644 index 0000000..371bc42 --- /dev/null +++ b/game/player/PlayerSubScene.cpp @@ -0,0 +1,204 @@ +#include "PlayerSubScene.h" +#include "PlayerAudioScript.h" +#include "PlayerEndScript.h" +#include "PlayerScript.h" + +#include "../Config.h" +#include "../coins/CoinScript.h" +#include "api/Asset.h" + +#include <crepe/api/Animator.h> +#include <crepe/api/AudioSource.h> +#include <crepe/api/BoxCollider.h> +#include <crepe/api/CircleCollider.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/ParticleEmitter.h> +#include <crepe/api/Scene.h> +#include <crepe/api/Script.h> +#include <crepe/api/Sprite.h> +#include <crepe/types.h> + +using namespace crepe; +using namespace std; + +PlayerSubScene::PlayerSubScene(Scene & scn) { + GameObject player = scn.new_object("player", "player", vec2(-100, 200)); + + Asset player_bullet {"asset/other_effects/effect_smgbullet.png"}; + Sprite & player_bullet_sprite = player.add_component<Sprite>( + player_bullet, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_PLAYER, + .order_in_layer = 3, + .size = vec2(0, 6), + } + ); + player.add_component<ParticleEmitter>(player_bullet_sprite, ParticleEmitter::Data{ + .offset = vec2(-15, 15), + .emission_rate = 0, + .min_speed = 300, + .max_speed = 500, + .min_angle = 85, + .max_angle = 100, + .boundary = ParticleEmitter::Boundary { + .height = 400, + .reset_on_exit = true, + }, + }); + Asset player_bullet_x2 {"asset/other_effects/effect_smgbullet_x2.png"}; + Sprite & player_bullet_x2_sprite = player.add_component<Sprite>( + player_bullet_x2, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_PLAYER, + .order_in_layer = 3, + .size = vec2(0, 12), + } + ); + player.add_component<ParticleEmitter>(player_bullet_x2_sprite, ParticleEmitter::Data{ + .offset = vec2(-15, 15), + .emission_rate = 0, + .min_speed = 300, + .max_speed = 500, + .min_angle = 85, + .max_angle = 100, + .boundary = ParticleEmitter::Boundary { + .height = 400, + .reset_on_exit = true, + }, + }); + Asset player_shell {"asset/other_effects/effect_rocketmgshell_TVOS.png"}; + Sprite & player_shell_sprite = player.add_component<Sprite>( + player_shell, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_PLAYER, + .order_in_layer = 3, + .size = vec2(0, 12), + .angle_offset = 90, + } + ); + player.add_component<ParticleEmitter>(player_shell_sprite, ParticleEmitter::Data{ + .offset = vec2(-15, 15), + .emission_rate = 0, + .min_speed = 200, + .max_speed = 500, + .min_angle = 110, + .max_angle = 120, + .force_over_time = vec2(0, 1000), + .boundary = ParticleEmitter::Boundary { + .height = 400, + .reset_on_exit = true, + }, + }); + + Asset player_body_asset {"asset/barry/defaultBody.png"}; + Sprite & player_body_sprite = player.add_component<Sprite>( + player_body_asset, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_PLAYER, + .order_in_layer = 0, + .size = vec2(0, 50), + } + ); + player.add_component<Animator>( + player_body_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = 5, + .looping = true, + } + ); + player.add_component<BoxCollider>(vec2(50, 50)); + Asset player_head_asset {"asset/barry/defaultHead.png"}; + Sprite & player_head_sprite = player.add_component<Sprite>( + player_head_asset, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_PLAYER, + .order_in_layer = 1, + .size = vec2(0, 50), + .position_offset = vec2(0, -20), + } + ); + player.add_component<Animator>( + player_head_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = 5, + .looping = true, + } + ); + player.add_component<CircleCollider>(25, vec2(0, -20)); + Asset player_jetpack_asset {"asset/barry/jetpackDefault.png"}; + Sprite & player_jetpack_sprite = player.add_component<Sprite>( + player_jetpack_asset, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_PLAYER, + .order_in_layer = 2, + .size = vec2(0, 60), + .position_offset = vec2(-20, 0), + } + ); + player_jetpack_sprite.active = false; + player.add_component<Animator>( + player_jetpack_sprite, ivec2(32, 44), uvec2(4, 4), + Animator::Data { + .fps = 5, + .looping = true, + } + ); + player.add_component<BoxCollider>(vec2(40, 60), vec2(-20, 0)); + player.add_component<Rigidbody>(Rigidbody::Data { + .gravity_scale = 1.0, + .body_type = Rigidbody::BodyType::DYNAMIC, + .linear_velocity = vec2(PLAYER_SPEED * 0.02, 0), + .collision_layers + = {COLL_LAY_BOT_TOP, COLL_LAY_ZAPPER, COLL_LAY_LASER, COLL_LAY_MISSILE, COLL_LAY_BULLET + }, + .collision_layer = COLL_LAY_PLAYER, + }); + player.add_component<BehaviorScript>().set_script<PlayerScript>().active = false; + player.add_component<BehaviorScript>().set_script<CoinScript>(); + player.add_component<BehaviorScript>().set_script<PlayerEndScript>().active = false; + + player.add_component<AudioSource>(Asset("asset/sfx/dud_zapper_lp.ogg")); + player.add_component<AudioSource>(Asset("asset/sfx/dud_zapper_pop.ogg")); + player.add_component<AudioSource>(Asset("asset/sfx/dud_fire.ogg")); + player.add_component<AudioSource>(Asset("asset/sfx/jetpack_firecracker_lp_01.ogg")).volume + = 0.1; + player.add_component<AudioSource>(Asset("asset/sfx/jetpack_firecracker_lp_02.ogg")).volume + = 0.1; + player.add_component<AudioSource>(Asset("asset/sfx/jetpack_firecracker_lp_03.ogg")).volume + = 0.1; + player.add_component<AudioSource>(Asset("asset/sfx/jetpack_firecracker_lp_04.ogg")).volume + = 0.1; + player.add_component<AudioSource>(Asset("asset/sfx/jetpack_firecracker_lp_05.ogg")).volume + = 0.1; + player.add_component<AudioSource>(Asset("asset/sfx/jetpack_firecracker_lp_06.ogg")).volume + = 0.1; + player.add_component<AudioSource>(Asset("asset/sfx/jetpack_firecracker_lp_07.ogg")).volume + = 0.1; + player.add_component<AudioSource>(Asset("asset/sfx/jetpack_firecracker_lp_08.ogg")).volume + = 0.1; + + GameObject player_audio = scn.new_object("player_audio", "player_audio", vec2(0, 0)); + player_audio.add_component<AudioSource>(Asset("asset/sfx/barefoot_step_left_1.ogg")).volume + = 3.0; + player_audio.add_component<AudioSource>(Asset("asset/sfx/barefoot_step_right_1.ogg")) + .volume + = 3.0; + player_audio.add_component<AudioSource>(Asset("asset/sfx/barefoot_step_left_2.ogg")).volume + = 3.0; + player_audio.add_component<AudioSource>(Asset("asset/sfx/barefoot_step_right_2.ogg")) + .volume + = 3.0; + player_audio.add_component<AudioSource>(Asset("asset/sfx/barefoot_step_left_3.ogg")).volume + = 3.0; + player_audio.add_component<AudioSource>(Asset("asset/sfx/barefoot_step_right_3.ogg")) + .volume + = 3.0; + player_audio.add_component<AudioSource>(Asset("asset/sfx/barefoot_step_left_4.ogg")).volume + = 3.0; + player_audio.add_component<AudioSource>(Asset("asset/sfx/barefoot_step_right_4.ogg")) + .volume + = 3.0; + + player_audio.add_component<BehaviorScript>().set_script<PlayerAudioScript>().active + = false; +} diff --git a/game/player/PlayerSubScene.h b/game/player/PlayerSubScene.h new file mode 100644 index 0000000..bf94c32 --- /dev/null +++ b/game/player/PlayerSubScene.h @@ -0,0 +1,10 @@ +#pragma once + +namespace crepe { +class Scene; +} + +class PlayerSubScene { +public: + PlayerSubScene(crepe::Scene & scn); +}; diff --git a/game/prefab/CMakeLists.txt b/game/prefab/CMakeLists.txt index 03084e4..6c36ef2 100644 --- a/game/prefab/CMakeLists.txt +++ b/game/prefab/CMakeLists.txt @@ -1,7 +1,6 @@ target_sources(main PUBLIC - PlayerObject.cpp - PlayerScript.cpp ZapperObject.cpp - ZapperScript.cpp + ZapperPoolSubScene.cpp + ZapperPoolScript.cpp ) diff --git a/game/prefab/PlayerObject.cpp b/game/prefab/PlayerObject.cpp deleted file mode 100644 index ef7b6cc..0000000 --- a/game/prefab/PlayerObject.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "Config.h" -#include "PlayerObject.h" -#include "PlayerScript.h" - -using namespace crepe; - -PlayerObject::PlayerObject(crepe::GameObject && base) - : GameObject(std::move(base)), - sprite { - .body = add_component<Sprite>( - Asset {"asset/barry/defaultBody.png"}, - Sprite::Data { - .sorting_in_layer = SORT_IN_LAY_PLAYER, - .order_in_layer = 0, - .size = vec2(0, 50), - } - ), - .head = add_component<Sprite>( - Asset {"asset/barry/defaultHead.png"}, - Sprite::Data { - .sorting_in_layer = SORT_IN_LAY_PLAYER, - .order_in_layer = 1, - .size = vec2(0, 50), - .position_offset = vec2(0, -20), - } - ), - .jetpack = add_component<Sprite>( - Asset {"asset/barry/jetpackDefault.png"}, - Sprite::Data { - .sorting_in_layer = SORT_IN_LAY_PLAYER, - .order_in_layer = 2, - .size = vec2(0, 60), - .position_offset = vec2(-20, 0), - } - ) - }, - animator { - .body = add_component<Animator>( - sprite.body, ivec2(32, 32), uvec2(4, 8), - Animator::Data { - .fps = 5, - .looping = true, - } - ), - .head = add_component<Animator>( - sprite.head, ivec2(32, 32), uvec2(4, 8), - Animator::Data { - .fps = 5, - .looping = true, - } - ), - .jetpack = add_component<Animator>( - sprite.jetpack, ivec2(32, 44), uvec2(4, 4), - Animator::Data { - .fps = 5, - .looping = true, - } - ), - }, - body(add_component<Rigidbody>(Rigidbody::Data { - .gravity_scale = 20, - .body_type = Rigidbody::BodyType::DYNAMIC, - .linear_velocity = vec2(100, 0), - .collision_layers = {COLL_LAY_BOT_TOP}, - .collision_layer = COLL_LAY_PLAYER, - })), - collider(add_component<BoxCollider>(vec2(50, 50))), - controller(add_component<BehaviorScript>().set_script<PlayerScript>(*this)) { - sprite.jetpack.active = false; - controller.active = false; -} - diff --git a/game/prefab/PlayerObject.h b/game/prefab/PlayerObject.h deleted file mode 100644 index a44d367..0000000 --- a/game/prefab/PlayerObject.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include <crepe/api/Animator.h> -#include <crepe/api/BehaviorScript.h> -#include <crepe/api/BoxCollider.h> -#include <crepe/api/GameObject.h> -#include <crepe/api/Rigidbody.h> -#include <crepe/api/Sprite.h> - -class PlayerObject : public crepe::GameObject { -public: - PlayerObject(crepe::GameObject &&); - -public: - struct { - crepe::Sprite & body; - crepe::Sprite & head; - crepe::Sprite & jetpack; - } sprite; - - struct { - crepe::Animator & body; - crepe::Animator & head; - crepe::Animator & jetpack; - } animator; - - crepe::Rigidbody & body; - crepe::BoxCollider & collider; - crepe::BehaviorScript & controller; -}; diff --git a/game/prefab/PlayerScript.cpp b/game/prefab/PlayerScript.cpp deleted file mode 100644 index 67aadb6..0000000 --- a/game/prefab/PlayerScript.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include <crepe/api/Rigidbody.h> -#include <cassert> - -#include "PlayerScript.h" - -using namespace crepe; -using namespace std; - -PlayerScript::PlayerScript(const PlayerObject & player) : player(player) { } - -void PlayerScript::fixed_update(crepe::duration_t dt) { - if (this->get_key_state(Keycode::SPACE)) - player.body.add_force_linear({ 0, -10 }); -} - diff --git a/game/prefab/PlayerScript.h b/game/prefab/PlayerScript.h deleted file mode 100644 index 131c73f..0000000 --- a/game/prefab/PlayerScript.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include <crepe/api/Script.h> - -#include "PlayerObject.h" - -class PlayerScript : public crepe::Script { -public: - PlayerScript(const PlayerObject & player); - -protected: - void fixed_update(crepe::duration_t dt); - -protected: - PlayerObject player; -}; - diff --git a/game/prefab/ZapperObject.cpp b/game/prefab/ZapperObject.cpp index 2791162..24bbbd2 100644 --- a/game/prefab/ZapperObject.cpp +++ b/game/prefab/ZapperObject.cpp @@ -1,6 +1,7 @@ +#include <crepe/api/Transform.h> + #include "Config.h" #include "ZapperObject.h" -#include "ZapperScript.h" using namespace crepe; @@ -11,74 +12,107 @@ ZapperObject::ZapperObject(crepe::GameObject && base) Asset {"asset/obstacles/zapper/orbAnim.png"}, Sprite::Data { .sorting_in_layer = SORT_IN_LAY_OBSTACLES, - .order_in_layer = 1, - .size = vec2{0, 1} * SCALE, - .position_offset = {0, 100}, + .order_in_layer = 1, + .size = vec2(0, 50) * SCALE, } ), .orb_end = add_component<Sprite>( - sprite.orb_start.source, - Sprite::Data { - .flip = {true, true}, - .sorting_in_layer = SORT_IN_LAY_OBSTACLES, - .order_in_layer = 1, - .size = vec2{0, 1} * SCALE, - .position_offset = {0, -100}, - } + sprite.orb_start.source, + Sprite::Data { + .flip = {true, true}, + .sorting_in_layer = SORT_IN_LAY_OBSTACLES, + .order_in_layer = 1, + .size = vec2(0, 50) * SCALE, + } ), .glow_start = add_component<Sprite>( Asset {"asset/obstacles/zapper/regular_zappers/glow.png"}, Sprite::Data { .sorting_in_layer = SORT_IN_LAY_OBSTACLES, - .order_in_layer = -1, - .size = vec2{2, 2} * SCALE, - .position_offset = {0, 100}, + .order_in_layer = -1, + .size = vec2(128, 128) * SCALE, } ), .glow_end = add_component<Sprite>( - sprite.glow_start.source, - Sprite::Data { - .flip = {true, true}, - .sorting_in_layer = SORT_IN_LAY_OBSTACLES, - .order_in_layer = -1, - .size = vec2{2, 2} * SCALE, - .position_offset = {0, -100}, - } + sprite.glow_start.source, + Sprite::Data { + .flip = {true, true}, + .sorting_in_layer = SORT_IN_LAY_OBSTACLES, + .order_in_layer = -1, + .size = vec2(128, 128) * SCALE, + } ), - .beam = add_component<Sprite>( + .beam = add_component<Sprite>( Asset {"asset/obstacles/zapper/regular_zappers/zapEffect.png"}, Sprite::Data { .sorting_in_layer = SORT_IN_LAY_OBSTACLES, - .order_in_layer = 0, - .size = vec2{200, 50}, - .angle_offset = 90, + .order_in_layer = 0, + .size = vec2(0, 40 * SCALE), + .angle_offset = 90, } - ), + ), }, animator { - .orb_start = add_component<Animator>( + .orb_start = add_component<Animator>( sprite.orb_start, ivec2(62, 42), uvec2(4, 1), Animator::Data { .fps = 10, .looping = true, } - ), - .orb_end = add_component<Animator>( - sprite.orb_end, ivec2(62, 42), uvec2(4, 1), - animator.orb_start.data - ), - .glow_start = add_component<Animator>( - sprite.glow_start, ivec2(128, 128), uvec2(4, 4), - Animator::Data { - .fps = 30, - .looping = true, - } - ), - .glow_end = add_component<Animator>( - sprite.glow_end, ivec2(128, 128), uvec2(4, 4), - animator.glow_start.data - ), + ), + .orb_end = add_component<Animator>( + sprite.orb_end, ivec2(62, 42), uvec2(4, 1), animator.orb_start.data + ), + .glow_start = add_component<Animator>( + sprite.glow_start, ivec2(128, 128), uvec2(16, 1), + Animator::Data { + .fps = 30, + .looping = true, + } + ), + .glow_end = add_component<Animator>( + sprite.glow_end, ivec2(128, 128), uvec2(16, 1), animator.glow_start.data + ), }, - controller(add_component<BehaviorScript>().set_script<ZapperScript>(*this)) -{ } + body {add_component<Rigidbody>(Rigidbody::Data { + .body_type = Rigidbody::BodyType::KINEMATIC, + .kinematic_collision = false, + .collision_layer = COLL_LAY_ZAPPER, + })}, + collider {add_component<BoxCollider>(vec2(0, 0))} { + this->set_active(false); +} + +void ZapperObject::place(const crepe::vec2 & position, float rotation, float length) { + this->transform.position = position; + this->transform.rotation = rotation; + + vec2 offset = vec2(0, 1) * length / 2; + + this->sprite.orb_start.data.position_offset = offset; + this->sprite.glow_start.data.position_offset = offset; + this->sprite.orb_end.data.position_offset = -offset; + this->sprite.glow_end.data.position_offset = -offset; + + this->sprite.beam.data.size.x = length; + + this->collider.dimensions = offset.rotate(rotation) * 2 + vec2(30, 30) * SCALE; +} + +void ZapperObject::set_active(bool active) { + this->sprite.orb_start.active = active; + this->sprite.orb_end.active = active; + this->sprite.glow_start.active = active; + this->sprite.glow_end.active = active; + this->sprite.beam.active = active; + + this->animator.orb_start.active = active; + this->animator.orb_end.active = active; + this->animator.glow_start.active = active; + this->animator.glow_end.active = active; + + this->body.active = active; + this->collider.active = active; + this->active = active; +} diff --git a/game/prefab/ZapperObject.h b/game/prefab/ZapperObject.h index 6b68146..42edc51 100644 --- a/game/prefab/ZapperObject.h +++ b/game/prefab/ZapperObject.h @@ -1,7 +1,6 @@ #pragma once #include <crepe/api/Animator.h> -#include <crepe/api/BehaviorScript.h> #include <crepe/api/BoxCollider.h> #include <crepe/api/GameObject.h> #include <crepe/api/Rigidbody.h> @@ -12,6 +11,8 @@ public: ZapperObject(crepe::GameObject &&); public: + bool active = true; + struct { crepe::Sprite & orb_start; crepe::Sprite & orb_end; @@ -27,11 +28,13 @@ public: crepe::Animator & glow_end; } animator; - // crepe::Rigidbody & body; - // crepe::BoxCollider & collider; - crepe::BehaviorScript & controller; + crepe::Rigidbody & body; + crepe::BoxCollider & collider; private: - static constexpr int SCALE = 60; -}; + static constexpr float SCALE = 0.8; +public: + void place(const crepe::vec2 & position, float rotation, float length); + void set_active(bool active); +}; diff --git a/game/prefab/ZapperPoolScript.cpp b/game/prefab/ZapperPoolScript.cpp new file mode 100644 index 0000000..b832ddd --- /dev/null +++ b/game/prefab/ZapperPoolScript.cpp @@ -0,0 +1,70 @@ +#include <crepe/api/Camera.h> + +#include "../Config.h" +#include "../Random.h" + +#include "ZapperPoolScript.h" +#include "ZapperPoolSubScene.h" +#include "util/OptionalRef.h" + +using namespace crepe; +using namespace std; + +ZapperPoolScript::ZapperPoolScript(std::vector<ZapperObject> && pool) : pool(pool) {} + +void ZapperPoolScript::init() { + subscribe<CreateZapperEvent>([this](const CreateZapperEvent &) { + this->spawn_random(); + return true; + }); + + camera_transform = get_components_by_name<Transform>(CAMERA_NAME).back(); + camera_camera = get_components_by_name<Camera>(CAMERA_NAME).back(); +} + +void ZapperPoolScript::fixed_update(crepe::duration_t) { + float threshold + = camera_transform->position.x - camera_camera->viewport_size.x / 2 - OFFSCREEN_MARGIN; + for (ZapperObject & zapper : this->pool) { + if (!zapper.active) continue; + + if (zapper.transform.position.x < threshold) zapper.set_active(false); + } +} + +void ZapperPoolScript::spawn_random() { + OptionalRef<ZapperObject> zapper = this->get_next_zapper(); + if (!zapper) return; // pool exhausted + + bool horizontal = Random::b(); + vec2 pos; + float rotation, length; + pos.x + = camera_transform->position.x + camera_camera->viewport_size.x / 2 + OFFSCREEN_MARGIN; + + if (horizontal) { + rotation = 90; + length = Random::f(400, 200); + pos.y = Random::f(0.5, -0.5) * HALLWAY_HEIGHT; + // align zapper to right edge of camera + pos.x -= MAX_LENGTH - (length / 2); + } else { + rotation = 0; + length = Random::f(200, 75); + // ensure zapper doesn't crash into ceiling or floor + pos.y = Random::f(0.5, -0.5) * (HALLWAY_HEIGHT - length); + // align zapper to right edge of camera + pos.x -= MAX_LENGTH; + } + + zapper->place(pos, rotation, length); + zapper->set_active(true); +} + +OptionalRef<ZapperObject> ZapperPoolScript::get_next_zapper() { + for (ZapperObject & zapper : this->pool) { + if (zapper.active) continue; + return zapper; + } + return {}; +} diff --git a/game/prefab/ZapperPoolScript.h b/game/prefab/ZapperPoolScript.h new file mode 100644 index 0000000..2208c80 --- /dev/null +++ b/game/prefab/ZapperPoolScript.h @@ -0,0 +1,33 @@ +#pragma once + +#include <crepe/api/Script.h> + +#include "ZapperObject.h" +#include "util/OptionalRef.h" + +class ZapperPoolSubScene; + +class ZapperPoolScript : public crepe::Script { +public: + ZapperPoolScript(std::vector<ZapperObject> && pool); + + void init(); + void fixed_update(crepe::duration_t); + + unsigned i = 0; + +private: + std::vector<ZapperObject> pool; + +private: + crepe::OptionalRef<crepe::Transform> camera_transform; + crepe::OptionalRef<crepe::Camera> camera_camera; + crepe::OptionalRef<ZapperObject> get_next_zapper(); + +private: + void spawn_random(); + +private: + static constexpr float MAX_LENGTH = 400; + static constexpr float OFFSCREEN_MARGIN = 50 + MAX_LENGTH; +}; diff --git a/game/prefab/ZapperPoolSubScene.cpp b/game/prefab/ZapperPoolSubScene.cpp new file mode 100644 index 0000000..a52aa75 --- /dev/null +++ b/game/prefab/ZapperPoolSubScene.cpp @@ -0,0 +1,17 @@ +#include <crepe/api/BehaviorScript.h> + +#include "ZapperPoolScript.h" +#include "ZapperPoolSubScene.h" + +using namespace crepe; +using namespace std; + +ZapperPoolSubScene::ZapperPoolSubScene(Scene & scene) + : controller {scene.new_object("controller")} { + + vector<ZapperObject> pool; + for (size_t i = 0; i < this->POOL_SIZE; i++) + pool.emplace_back(scene.new_object("zapper", "zapper")); + BehaviorScript & behavior = this->controller.add_component<BehaviorScript>(); + behavior.set_script<ZapperPoolScript>(std::move(pool)); +} diff --git a/game/prefab/ZapperPoolSubScene.h b/game/prefab/ZapperPoolSubScene.h new file mode 100644 index 0000000..6f6e297 --- /dev/null +++ b/game/prefab/ZapperPoolSubScene.h @@ -0,0 +1,19 @@ +#pragma once + +#include <crepe/api/Event.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/Scene.h> +#include <crepe/util/OptionalRef.h> + +class CreateZapperEvent : public crepe::Event {}; + +class ZapperPoolSubScene { +public: + ZapperPoolSubScene(crepe::Scene & scene); + +private: + crepe::GameObject controller; + +private: + static constexpr size_t POOL_SIZE = 4; +}; diff --git a/game/prefab/ZapperScript.cpp b/game/prefab/ZapperScript.cpp deleted file mode 100644 index b9b24be..0000000 --- a/game/prefab/ZapperScript.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include <crepe/api/Rigidbody.h> -#include <cassert> - -#include "ZapperScript.h" - -using namespace crepe; -using namespace std; - -ZapperScript::ZapperScript(const ZapperObject & zapper) : zapper(zapper) { } - -void ZapperScript::init() { - zapper.sprite.beam.mask = { - .w = 350, - .h = 117, - .x = 0, - .y = 0, - }; -} - -void ZapperScript::frame_update(duration_t delta_time) { - zapper.sprite.beam.mask.x += 4; -} - diff --git a/game/prefab/ZapperScript.h b/game/prefab/ZapperScript.h deleted file mode 100644 index 5a960df..0000000 --- a/game/prefab/ZapperScript.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include <crepe/api/Script.h> - -#include "ZapperObject.h" - -class ZapperScript : public crepe::Script { -public: - ZapperScript(const ZapperObject & zapper); - -protected: - void init(); - void frame_update(crepe::duration_t delta_time); - -protected: - ZapperObject zapper; -}; - diff --git a/game/preview/NpcScript.cpp b/game/preview/NpcScript.cpp new file mode 100644 index 0000000..c4148f2 --- /dev/null +++ b/game/preview/NpcScript.cpp @@ -0,0 +1,32 @@ +#include "NpcScript.h" + +#include <crepe/api/Sprite.h> +#include <crepe/api/Transform.h> +#include <crepe/manager/SaveManager.h> + +using namespace std; +using namespace crepe; + +void NpcScript::init() {} +void NpcScript::fixed_update(duration_t dt) { + auto & rb = this->get_component<Rigidbody>(); + auto & npc = this->get_component<Sprite>(); + auto & transform = this->get_component<Transform>(); + + if (transform.position.x < -990) { + rb.data.linear_velocity.x *= -1; + } + if (transform.position.x > 990) { + rb.data.linear_velocity.x *= -1; + } + + if (rb.data.linear_velocity.x < 0) { + npc.data.flip = {true, false}; + } else { + npc.data.flip = {false, false}; + } + + auto & savemgr = this->get_save_manager(); + savemgr.set("npc_x", transform.position.x); + savemgr.set("npc_y", transform.position.y); +} diff --git a/game/preview/NpcScript.h b/game/preview/NpcScript.h new file mode 100644 index 0000000..8d856fd --- /dev/null +++ b/game/preview/NpcScript.h @@ -0,0 +1,11 @@ + +#include <crepe/api/Script.h> + +class NpcScript : public crepe::Script { + +private: + +public: + void init(); + void fixed_update(crepe::duration_t dt); +}; diff --git a/game/preview/NpcSubScene.cpp b/game/preview/NpcSubScene.cpp new file mode 100644 index 0000000..bd6cfb2 --- /dev/null +++ b/game/preview/NpcSubScene.cpp @@ -0,0 +1,69 @@ + + +#include "NpcSubScene.h" + +#include "../Config.h" +#include "NpcScript.h" + +#include <crepe/ValueBroker.h> +#include <crepe/api/Animator.h> +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/Scene.h> +#include <crepe/api/Sprite.h> +#include <crepe/manager/SaveManager.h> + +using namespace crepe; + +NpcSubScene::NpcSubScene(Scene & scn) { + auto & savemgr = scn.get_save_manager(); + ValueBroker npc_x = savemgr.get<float>("npc_x", 500); + ValueBroker npc_y = savemgr.get<float>("npc_y", 0); + + GameObject npc = scn.new_object("npc", "npc_tag", vec2 {npc_x.get(), npc_y.get()}, 0, 1); + Asset npc_body {"asset/workers/worker1Body.png"}; + Asset npc_head {"asset/workers/worker1Head.png"}; + + auto & npc_body_sprite = npc.add_component<Sprite>( + npc_body, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_PLAYER, + .size = {0, 50}, + } + ); + auto & npc_head_sprite = npc.add_component<Sprite>( + npc_head, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_PLAYER, + .size = {0, 50}, + .position_offset = {0, -20}, + } + ); + + npc.add_component<Animator>( + npc_body_sprite, ivec2 {32, 32}, uvec2 {4, 8}, + Animator::Data { + .fps = 5, + .looping = true, + } + ); + npc.add_component<Animator>( + npc_head_sprite, ivec2 {32, 32}, uvec2 {4, 8}, + Animator::Data { + .fps = 5, + .looping = true, + } + ); + npc.add_component<BoxCollider>(vec2 {50, 50}); + + npc.add_component<Rigidbody>(Rigidbody::Data { + .mass = 10, + .gravity_scale = 1, + .body_type = Rigidbody::BodyType::DYNAMIC, + .linear_velocity = {-50, 0}, + //.max_linear_velocity = 40, + .collision_layers = {COLL_LAY_BOT_TOP, COLL_LAY_PLAYER}, + .collision_layer = COLL_LAY_PLAYER, + }); + + npc.add_component<BehaviorScript>().set_script<NpcScript>(); +} diff --git a/game/preview/NpcSubScene.h b/game/preview/NpcSubScene.h new file mode 100644 index 0000000..a226195 --- /dev/null +++ b/game/preview/NpcSubScene.h @@ -0,0 +1,10 @@ +#pragma once + +namespace crepe { +class Scene; +} + +class NpcSubScene { +public: + NpcSubScene(crepe::Scene & scn); +}; diff --git a/game/preview/PrevPlayerScript.cpp b/game/preview/PrevPlayerScript.cpp new file mode 100644 index 0000000..2657b8d --- /dev/null +++ b/game/preview/PrevPlayerScript.cpp @@ -0,0 +1,132 @@ +#include "PrevPlayerScript.h" + +#include "../missile/SpawnEvent.h" +#include "api/Transform.h" +#include <crepe/api/AudioSource.h> +#include <crepe/api/Camera.h> +#include <crepe/manager/SaveManager.h> +#include <iostream> +#include <ostream> + +using namespace crepe; + +bool PrevPlayerScript::key_pressed(const KeyPressEvent & ev) { + switch (ev.key) { + case Keycode::A: + this->get_component<Rigidbody>().data.linear_velocity.x = -move_speed; + this->body->data.flip = {true, false}; + this->head->data.flip = {true, false}; + break; + case Keycode::D: + this->get_component<Rigidbody>().data.linear_velocity.x = move_speed; + this->body->data.flip = {false, false}; + this->head->data.flip = {false, false}; + break; + + case Keycode::SPACE: + this->get_component<Rigidbody>().data.linear_velocity.y = -move_speed; + break; + case Keycode::D0: + this->body_anim->set_anim(0); + this->head_anim->set_anim(0); + break; + case Keycode::D1: + this->body_anim->set_anim(1); + this->head_anim->set_anim(1); + break; + case Keycode::D2: + this->body_anim->set_anim(2); + this->head_anim->set_anim(2); + break; + case Keycode::D3: + this->body_anim->set_anim(3); + this->head_anim->set_anim(3); + break; + case Keycode::D4: + this->body_anim->set_anim(4); + this->head_anim->set_anim(4); + break; + case Keycode::D5: + this->body_anim->set_anim(5); + this->head_anim->set_anim(5); + break; + case Keycode::D6: + this->body_anim->set_anim(6); + this->head_anim->set_anim(6); + break; + case Keycode::D7: + this->body_anim->set_anim(7); + this->head_anim->set_anim(7); + break; + case Keycode::LEFT: + this->head->data.angle_offset -= 1; + break; + case Keycode::RIGHT: + this->head->data.angle_offset += 1; + break; + case Keycode::UP: + this->head->data.scale_offset += 0.1; + break; + case Keycode::DOWN: + this->head->data.scale_offset -= 0.1; + break; + case Keycode::P: + this->get_component<AudioSource>().play(); + break; + case Keycode::Q: + this->get_components_by_name<Camera>("camera").front().get().data.zoom -= 0.01; + break; + case Keycode::E: + this->get_components_by_name<Camera>("camera").front().get().data.zoom += 0.01; + break; + case Keycode::J: + this->get_components_by_name<Transform>("camera").front().get().position.x + -= move_speed; + break; + case Keycode::K: + this->get_components_by_name<Transform>("camera").front().get().position.y + -= move_speed; + break; + case Keycode::L: + this->get_components_by_name<Transform>("camera").front().get().position.x + += move_speed; + break; + case Keycode::I: + this->get_components_by_name<Transform>("camera").front().get().position.y + += move_speed; + break; + case Keycode::M: + trigger_event<MissileSpawnEvent>(MissileSpawnEvent {}); + break; + //todo + case Keycode::PAGE_UP: + case Keycode::PAGE_DOWN: + case Keycode::HOME: + break; + default: + break; + } + return false; +} + +void PrevPlayerScript::init() { + auto animations = this->get_components<Animator>(); + body_anim = animations[0]; + head_anim = animations[1]; + + auto sprites = this->get_components<Sprite>(); + body = sprites[0]; + head = sprites[1]; + + subscribe<KeyPressEvent>([this](const KeyPressEvent & ev) -> bool { + return this->key_pressed(ev); + }); +}; + +void PrevPlayerScript::fixed_update(crepe::duration_t dt) { + auto & savemgr = this->get_save_manager(); + const auto & pos = this->get_component<Transform>().position; + + savemgr.set("player_x", pos.x); + savemgr.set("player_y", pos.y); +}; diff --git a/game/preview/PrevPlayerScript.h b/game/preview/PrevPlayerScript.h new file mode 100644 index 0000000..cc3184e --- /dev/null +++ b/game/preview/PrevPlayerScript.h @@ -0,0 +1,23 @@ + +#include <crepe/api/Event.h> +#include <crepe/api/Script.h> +#include <crepe/util/OptionalRef.h> + +#include <crepe/api/Animator.h> +#include <crepe/api/Sprite.h> + +class PrevPlayerScript : public crepe::Script { +private: + crepe::OptionalRef<crepe::Animator> head_anim; + crepe::OptionalRef<crepe::Animator> body_anim; + crepe::OptionalRef<crepe::Sprite> head; + crepe::OptionalRef<crepe::Sprite> body; + +private: + float move_speed = 100; + +private: + void init(); + void fixed_update(crepe::duration_t dt); + bool key_pressed(const crepe::KeyPressEvent & ev); +}; diff --git a/game/preview/PrevPlayerSubScene.cpp b/game/preview/PrevPlayerSubScene.cpp new file mode 100644 index 0000000..b59a0af --- /dev/null +++ b/game/preview/PrevPlayerSubScene.cpp @@ -0,0 +1,86 @@ + +#include "PrevPlayerSubScene.h" + +#include "../Config.h" +#include "PrevPlayerScript.h" + +#include <crepe/api/Animator.h> +#include <crepe/api/AudioSource.h> +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/Scene.h> +#include <crepe/api/Sprite.h> + +#include <crepe/ValueBroker.h> +#include <crepe/manager/SaveManager.h> + +using namespace crepe; + +PrevPlayerSubScene::PrevPlayerSubScene(Scene & scn) { + auto & savemgr = scn.get_save_manager(); + + ValueBroker player_x = savemgr.get<float>("player_x", 500); + ValueBroker player_y = savemgr.get<float>("player_y", -100); + + GameObject player + = scn.new_object("player", "TAG", vec2 {player_x.get(), player_y.get()}, 0, 1); + Asset player_body_asset {"asset/barry/defaultBody.png"}; + Sprite & player_body_sprite = player.add_component<Sprite>( + player_body_asset, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_PLAYER, + .order_in_layer = 0, + .size = vec2(0, 50), + } + ); + player.add_component<Animator>( + player_body_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = 5, + .looping = true, + } + ); + Asset player_head_asset {"asset/barry/defaultHead.png"}; + Sprite & player_head_sprite = player.add_component<Sprite>( + player_head_asset, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_PLAYER, + .order_in_layer = 1, + .size = vec2(0, 50), + .position_offset = vec2(0, -20), + } + ); + player.add_component<Animator>( + player_head_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = 5, + .looping = true, + } + ); + Asset player_jetpack_asset {"asset/barry/jetpackDefault.png"}; + Sprite & player_jetpack_sprite = player.add_component<Sprite>( + player_jetpack_asset, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_PLAYER, + .order_in_layer = 2, + .size = vec2(0, 60), + .position_offset = vec2(-20, 0), + } + ); + player_jetpack_sprite.active = false; + player.add_component<Animator>( + player_jetpack_sprite, ivec2(32, 44), uvec2(4, 4), + Animator::Data { + .fps = 5, + .looping = true, + } + ); + player.add_component<Rigidbody>(Rigidbody::Data { + .gravity_scale = 20, + .body_type = Rigidbody::BodyType::DYNAMIC, + .linear_velocity = vec2(100, 0), + .collision_layers = {COLL_LAY_BOT_TOP}, + .collision_layer = COLL_LAY_PLAYER, + }); + player.add_component<BoxCollider>(vec2(50, 50)); + player.add_component<BehaviorScript>().set_script<PrevPlayerScript>(); +} diff --git a/game/preview/PrevPlayerSubScene.h b/game/preview/PrevPlayerSubScene.h new file mode 100644 index 0000000..a61f341 --- /dev/null +++ b/game/preview/PrevPlayerSubScene.h @@ -0,0 +1,10 @@ +#pragma once + +namespace crepe { +class Scene; +} + +class PrevPlayerSubScene { +public: + PrevPlayerSubScene(crepe::Scene & scn); +}; diff --git a/game/preview/PreviewReplaySubScript.cpp b/game/preview/PreviewReplaySubScript.cpp new file mode 100644 index 0000000..580a608 --- /dev/null +++ b/game/preview/PreviewReplaySubScript.cpp @@ -0,0 +1,55 @@ +#include "PreviewReplaySubScript.h" +#include "Config.h" +#include "menus/ButtonReplaySubScript.h" +#include <crepe/api/AudioSource.h> +#include <crepe/types.h> + +using namespace crepe; +using namespace std; + +void PreviewReplaySubScript::init() { + IButtonScript::init(); + this->subscribe<ButtonPressEvent>([this](const ButtonPressEvent & e) { + return this->on_button_press(e); + }); + this->subscribe<StopPreviewRecording>([this](const StopPreviewRecording & e) { + return this->stop_recording(); + }); + this->subscribe<DeleteRecordingEvent>([this](const DeleteRecordingEvent & e) { + return this->delete_recording(); + }); + this->subscribe<StartPreviewRecording>([this](const StartPreviewRecording & e) { + return this->start_recording(); + }); +} + +bool PreviewReplaySubScript::on_button_press(const ButtonPressEvent & e) { + if (DISABLE_REPLAY) return false; + replay.play(this->recording); + return false; +} +bool PreviewReplaySubScript::start_recording() { + if (DISABLE_REPLAY) return false; + if (record_saved) { + this->stop_recording(); + this->delete_recording(); + } + replay.record_start(); + this->record_started = true; + return false; +} + +bool PreviewReplaySubScript::stop_recording() { + if (DISABLE_REPLAY) return false; + if (this->record_started) this->recording = replay.record_end(); + this->record_saved = true; + return false; +} + +bool PreviewReplaySubScript::delete_recording() { + if (DISABLE_REPLAY) return false; + if (this->record_started) this->stop_recording(); + if (this->record_saved) replay.release(this->recording); + this->record_saved = false; + return false; +} diff --git a/game/preview/PreviewReplaySubScript.h b/game/preview/PreviewReplaySubScript.h new file mode 100644 index 0000000..59b78c3 --- /dev/null +++ b/game/preview/PreviewReplaySubScript.h @@ -0,0 +1,24 @@ +#pragma once + +#include "menus/IButtonScript.h" + +#include <crepe/api/Script.h> + +struct StartPreviewRecording : public crepe::Event {}; +struct StopPreviewRecording : public crepe::Event {}; + +class PreviewReplaySubScript : public IButtonScript { +public: + void init() override; + bool on_button_press(const crepe::ButtonPressEvent & e); + +private: + crepe::recording_t recording = 0; + bool start_recording(); + bool stop_recording(); + bool delete_recording(); + +private: + bool record_saved = false; + bool record_started = false; +}; diff --git a/game/preview/PreviewStartRecSubScript.cpp b/game/preview/PreviewStartRecSubScript.cpp new file mode 100644 index 0000000..8a2f54c --- /dev/null +++ b/game/preview/PreviewStartRecSubScript.cpp @@ -0,0 +1,20 @@ +#include "PreviewStartRecSubScript.h" +#include "PreviewReplaySubScript.h" + +#include <crepe/api/AudioSource.h> +#include <crepe/types.h> + +using namespace crepe; +using namespace std; + +void PreviewStartRecSubScript::init() { + IButtonScript::init(); + this->subscribe<ButtonPressEvent>([this](const ButtonPressEvent & e) { + return this->on_button_press(e); + }); +} + +bool PreviewStartRecSubScript::on_button_press(const ButtonPressEvent & e) { + this->trigger_event<StartPreviewRecording>(); + return false; +} diff --git a/game/preview/PreviewStartRecSubScript.h b/game/preview/PreviewStartRecSubScript.h new file mode 100644 index 0000000..a54a085 --- /dev/null +++ b/game/preview/PreviewStartRecSubScript.h @@ -0,0 +1,11 @@ +#pragma once + +#include "menus/IButtonScript.h" + +#include <crepe/api/Script.h> + +class PreviewStartRecSubScript : public IButtonScript { +public: + void init() override; + bool on_button_press(const crepe::ButtonPressEvent & e); +}; diff --git a/game/preview/PreviewStopRecSubScript.cpp b/game/preview/PreviewStopRecSubScript.cpp new file mode 100644 index 0000000..a229da8 --- /dev/null +++ b/game/preview/PreviewStopRecSubScript.cpp @@ -0,0 +1,20 @@ +#include "PreviewStopRecSubScript.h" +#include "PreviewReplaySubScript.h" + +#include <crepe/api/AudioSource.h> +#include <crepe/types.h> + +using namespace crepe; +using namespace std; + +void PreviewStopRecSubScript::init() { + IButtonScript::init(); + this->subscribe<ButtonPressEvent>([this](const ButtonPressEvent & e) { + return this->on_button_press(e); + }); +} + +bool PreviewStopRecSubScript::on_button_press(const ButtonPressEvent & e) { + this->trigger_event<StopPreviewRecording>(); + return false; +} diff --git a/game/preview/PreviewStopRecSubScript.h b/game/preview/PreviewStopRecSubScript.h new file mode 100644 index 0000000..b2dd73b --- /dev/null +++ b/game/preview/PreviewStopRecSubScript.h @@ -0,0 +1,11 @@ +#pragma once + +#include "menus/IButtonScript.h" + +#include <crepe/api/Script.h> + +class PreviewStopRecSubScript : public IButtonScript { +public: + void init() override; + bool on_button_press(const crepe::ButtonPressEvent & e); +}; diff --git a/game/preview/SmokeSubScene.cpp b/game/preview/SmokeSubScene.cpp new file mode 100644 index 0000000..e363f95 --- /dev/null +++ b/game/preview/SmokeSubScene.cpp @@ -0,0 +1,37 @@ + +#include "SmokeSubScene.h" + +#include "../Config.h" + +#include <crepe/api/ParticleEmitter.h> +#include <crepe/api/Scene.h> +#include <crepe/api/Sprite.h> + +using namespace crepe; + +SmokeSubScene::SmokeSubScene(Scene & scn) { + GameObject smoke = scn.new_object("smoke_particle", "TAG", vec2 {500, -210}, 0, 1); + + Asset smoke_ss {"asset/particles/smoke.png"}; + + auto & smoke_sprite = smoke.add_component<Sprite>( + smoke_ss, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_PARTICLES_FOREGROUND, + .size = {0, 30}, + } + ); + + smoke.add_component<ParticleEmitter>( + smoke_sprite, + ParticleEmitter::Data { + .offset = {0, -60}, + .max_particles = 10, + .emission_rate = 25, + .min_angle = 60, + .max_angle = 120, + .begin_lifespan = 1, + .end_lifespan = 2, + } + ); +} diff --git a/game/preview/SmokeSubScene.h b/game/preview/SmokeSubScene.h new file mode 100644 index 0000000..93d8a2d --- /dev/null +++ b/game/preview/SmokeSubScene.h @@ -0,0 +1,10 @@ +#pragma once + +namespace crepe { +class Scene; +} + +class SmokeSubScene { +public: + SmokeSubScene(crepe::Scene & scn); +}; diff --git a/game/scheduler/ObjectsScheduler.cpp b/game/scheduler/ObjectsScheduler.cpp new file mode 100644 index 0000000..36bf901 --- /dev/null +++ b/game/scheduler/ObjectsScheduler.cpp @@ -0,0 +1,85 @@ + + +#include "ObjectsScheduler.h" + +#include "../Config.h" +#include "../Random.h" +#include "../missile/SpawnEvent.h" +#include "api/Rigidbody.h" +#include "api/Transform.h" +#include "enemy/BattleScript.h" +#include "prefab/ZapperPoolSubScene.h" + +using namespace crepe; +void ObjectsScheduler::preset_0() { + trigger_event<MissileSpawnEvent>(MissileSpawnEvent {}); + trigger_event<MissileSpawnEvent>(MissileSpawnEvent {}); +} +void ObjectsScheduler::preset_1() { trigger_event<MissileSpawnEvent>(MissileSpawnEvent {}); } +void ObjectsScheduler::preset_2() { trigger_event<CreateZapperEvent>(CreateZapperEvent {}); } +void ObjectsScheduler::preset_3() { trigger_event<CreateZapperEvent>(CreateZapperEvent {}); } +void ObjectsScheduler::preset_4() {} +void ObjectsScheduler::boss_fight_1() { + this->get_components_by_name<Rigidbody>("camera").front().get().data.linear_velocity.x = 0; + this->get_components_by_name<Rigidbody>("player").front().get().data.linear_velocity.x = 0; + this->trigger_event<BattleStartEvent>(BattleStartEvent {.num_enemies = 2}); + + RefVector<Rigidbody> rb_back_forest + = this->get_components_by_tag<Rigidbody>("forest_background"); + for (Rigidbody & rb : rb_back_forest) { + rb.data.linear_velocity.x = 0; + } +} + +bool ObjectsScheduler::boss_fight_1_event() { + this->get_components_by_name<Rigidbody>("camera").front().get().data.linear_velocity.x + = PLAYER_SPEED * 0.02; + this->get_components_by_name<Rigidbody>("player").front().get().data.linear_velocity.x + = PLAYER_SPEED * 0.02; + + bool first = true; + RefVector<Rigidbody> rb_back_forest + = this->get_components_by_tag<Rigidbody>("forest_background"); + for (Rigidbody & rb : rb_back_forest) { + if (first == true) { + rb.data.linear_velocity.x = 30; + first = false; + } else { + rb.data.linear_velocity.x = 40; + first = true; + } + } + + return false; +} + +void ObjectsScheduler::init() { + this->obstacles.push_back([this]() { preset_0(); }); + this->obstacles.push_back([this]() { preset_1(); }); + this->obstacles.push_back([this]() { preset_2(); }); + this->obstacles.push_back([this]() { preset_3(); }); + this->obstacles.push_back([this]() { preset_4(); }); + + this->obstacles.push_back([this]() { boss_fight_1(); }); + + // subscribe to battlewonevent + this->subscribe<BattleWonEvent>([this](const BattleWonEvent & ev) -> bool { + return this->boss_fight_1_event(); + }); +} + +void ObjectsScheduler::fixed_update(duration_t dt) { + int pos_x + = (int) this->get_components_by_name<Transform>("camera").front().get().position.x; + + int boss_check = (pos_x - this->start_offset) / this->boss_fight_interval; + if (boss_check > this->last_boss_check) { + this->obstacles.back()(); + this->last_boss_check = boss_check; + } + int obstacle_check = (pos_x - this->start_offset) / this->obstacle_interval; + if (obstacle_check > this->last_obstacle_check) { + this->obstacles[Random::i(this->obstacles.size() - 1, 0)](); + this->last_obstacle_check = obstacle_check; + } +} diff --git a/game/scheduler/ObjectsScheduler.h b/game/scheduler/ObjectsScheduler.h new file mode 100644 index 0000000..bd0701b --- /dev/null +++ b/game/scheduler/ObjectsScheduler.h @@ -0,0 +1,32 @@ +#pragma once + +#include "api/Script.h" +#include <functional> +#include <vector> + +class ObjectsScheduler : public crepe::Script { + +private: + std::vector<std::function<void()>> obstacles; + + int last_boss_check = 0; + int last_obstacle_check = 0; + + int boss_fight_interval = 5000; + int obstacle_interval = 350; + int start_offset = 1300; + +private: + void preset_0(); + void preset_1(); + void preset_2(); + void preset_3(); + void preset_4(); + void boss_fight_1(); + + bool boss_fight_1_event(); + +public: + void init(); + void fixed_update(crepe::duration_t dt); +}; diff --git a/game/util/scrollgen b/game/util/scrollgen new file mode 100755 index 0000000..0389107 --- /dev/null +++ b/game/util/scrollgen @@ -0,0 +1,36 @@ +#!/bin/sh +INPUT="$1" +FRAMES="$2" + +die() { + echo "$@" + exit 1 +} +check_command() { + cmd="$1" + command -v "$cmd" > /dev/null || die "command '$cmd' not found" +} + +check_command magick +check_command identify +[ "$#" -eq 2 ] || die "usage: $0 <input image> <frame count>" +[ -e "$INPUT" ] || die "file not found: $INPUT" +[ "$FRAMES" -gt 0 ] || die "invalid frame count: $FRAMES" + +tile_width=$(identify -format "%w" "$INPUT") +tile_height=$(identify -format "%h" "$INPUT") + +OUTPUT="$INPUT.scroll.png" +magick -size "${tile_width}x$(( $tile_height * $FRAMES ))" 'xc:#ff00ff00' "$OUTPUT" + +for i in $(seq 0 $(( $FRAMES - 1 ))); do + offset_x=$(( $tile_width * $i / $FRAMES )) + offset_y=$(( i * $tile_height )) + + magick "$OUTPUT" "$INPUT" -geometry "+${offset_x}+${offset_y}" -composite "$OUTPUT" + magick "$OUTPUT" "$INPUT" -geometry "+$(( $offset_x - $tile_width ))+${offset_y}" -composite "$OUTPUT" + echo "+${offset_x}+${offset_y}" +done + +# magick -size ${total_width}x${sprite_height} xc:none canvas.png + diff --git a/game/workers/CollisionScript.cpp b/game/workers/CollisionScript.cpp new file mode 100644 index 0000000..372bfec --- /dev/null +++ b/game/workers/CollisionScript.cpp @@ -0,0 +1,69 @@ +#include "CollisionScript.h" + +#include <crepe/api/Animator.h> +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/Rigidbody.h> +#include <crepe/api/Sprite.h> +#include <crepe/api/Transform.h> +#include <crepe/types.h> + +using namespace crepe; +using namespace std; + +void CollisionScript::init() { + subscribe<CollisionEvent>([this](const CollisionEvent & ev) -> bool { + return this->on_collision(ev); + }); +} + +bool CollisionScript::on_collision(const CollisionEvent & ev) { + RefVector<Animator> animators = this->get_components<Animator>(); + RefVector<Sprite> sprites = this->get_components<Sprite>(); + Rigidbody & rb = this->get_component<Rigidbody>(); + Transform & tr = this->get_component<Transform>(); + BehaviorScript & bs_panic = this->get_components<BehaviorScript>().front(); + + if (ev.info.other.metadata.tag == "zapper") { + for (Animator & anim : animators) { + anim.active = false; + anim.set_anim(3); + } + for (Sprite & sprite : sprites) { + sprite.data.position_offset.x = 15; + } + rb.data.linear_velocity_coefficient = {0.5, 0.5}; + tr.rotation = 90; + bs_panic.active = false; + + return false; + } else if (ev.info.other.metadata.tag == "laser") { + for (Animator & anim : animators) { + anim.active = false; + anim.set_anim(3); + } + for (Sprite & sprite : sprites) { + sprite.data.position_offset.x = 15; + } + rb.data.linear_velocity_coefficient = {0.5, 0.5}; + tr.rotation = 90; + bs_panic.active = false; + + return false; + } else if (ev.info.other.metadata.tag == "missile" + || ev.info.other.metadata.tag == "enemy_bullet") { + for (Animator & anim : animators) { + anim.active = false; + anim.set_anim(3); + } + for (Sprite & sprite : sprites) { + sprite.data.position_offset.x = 15; + } + rb.data.linear_velocity_coefficient = {0.5, 0.5}; + tr.rotation = 90; + bs_panic.active = false; + + return false; + } + + return false; +} diff --git a/game/workers/CollisionScript.h b/game/workers/CollisionScript.h new file mode 100644 index 0000000..70c5fe1 --- /dev/null +++ b/game/workers/CollisionScript.h @@ -0,0 +1,12 @@ +#pragma once + +#include <crepe/api/Event.h> +#include <crepe/api/Script.h> + +class CollisionScript : public crepe::Script { +public: + void init(); + +private: + bool on_collision(const crepe::CollisionEvent & ev); +}; diff --git a/game/workers/PanicFromPlayerScript.cpp b/game/workers/PanicFromPlayerScript.cpp new file mode 100644 index 0000000..baa48df --- /dev/null +++ b/game/workers/PanicFromPlayerScript.cpp @@ -0,0 +1,55 @@ +#include "PanicFromPlayerScript.h" + +#include <crepe/api/Animator.h> +#include <crepe/api/Rigidbody.h> +#include <crepe/api/Sprite.h> +#include <crepe/api/Transform.h> +#include <crepe/types.h> + +using namespace crepe; +using namespace std; + +void PanicFromPlayerScript::fixed_update(duration_t dt) { + Animator & anim_player = this->get_components_by_name<Animator>("player").front(); + + if (anim_player.data.col == 1) { + Transform & trans_player = this->get_components_by_name<Transform>("player").back(); + Transform & trans_worker = this->get_components<Transform>().back(); + + float result_x = trans_player.position.x - trans_worker.position.x; + + if (result_x < 100 && result_x > -20) { + RefVector<Animator> anim_worker = this->get_components<Animator>(); + RefVector<Sprite> sprite_worker = this->get_components<Sprite>(); + Rigidbody & rb_worker = this->get_components<Rigidbody>().back(); + + if (anim_worker.front().get().data.col != 1) { + anim_worker.front().get().set_anim(1); + anim_worker.back().get().set_anim(1); + + anim_worker.front().get().data.fps = 10; + anim_worker.back().get().data.fps = 10; + } + + if (result_x < 0) { + float min_value = 8000; + float max_value = 10000; + float value = min_value + + static_cast<float>(rand()) + / (static_cast<float>(RAND_MAX / (max_value - min_value))); + rb_worker.data.linear_velocity.x = value * dt.count(); + sprite_worker.front().get().data.flip.flip_x = false; + sprite_worker.back().get().data.flip.flip_x = false; + } else { + float min_value = -4000; + float max_value = -5000; + float value = min_value + + static_cast<float>(rand()) + / (static_cast<float>(RAND_MAX / (max_value - min_value))); + rb_worker.data.linear_velocity.x = value * dt.count(); + sprite_worker.front().get().data.flip.flip_x = true; + sprite_worker.back().get().data.flip.flip_x = true; + } + } + } +}; diff --git a/game/workers/PanicFromPlayerScript.h b/game/workers/PanicFromPlayerScript.h new file mode 100644 index 0000000..d173e89 --- /dev/null +++ b/game/workers/PanicFromPlayerScript.h @@ -0,0 +1,8 @@ +#pragma once + +#include <crepe/api/Script.h> + +class PanicFromPlayerScript : public crepe::Script { +public: + void fixed_update(crepe::duration_t dt); +}; diff --git a/game/workers/WorkerScript.cpp b/game/workers/WorkerScript.cpp new file mode 100644 index 0000000..b0bfc4e --- /dev/null +++ b/game/workers/WorkerScript.cpp @@ -0,0 +1,145 @@ +#include "WorkerScript.h" + +#include "../Config.h" +#include "api/BehaviorScript.h" + +#include <crepe/api/Animator.h> +#include <crepe/api/Rigidbody.h> +#include <crepe/api/Sprite.h> +#include <crepe/api/Transform.h> +#include <crepe/types.h> +#include <cstdlib> + +using namespace crepe; +using namespace std; + +void WorkerScript::fixed_update(duration_t dt) { + RefVector<Rigidbody> rb_workers = this->get_components_by_tag<Rigidbody>("worker"); + RefVector<Transform> trans_workers = this->get_components_by_tag<Transform>("worker"); + + Rigidbody & rb_cam = this->get_components_by_name<Rigidbody>("camera").back(); + Transform & trans_cam = this->get_components_by_name<Transform>("camera").back(); + + int counter = 0; + for (Rigidbody & rb_worker : rb_workers) { + Transform & trans_worker = trans_workers.at(counter); + + float result_x = rb_cam.data.linear_velocity.x - rb_worker.data.linear_velocity.x; + + if (result_x > 0) { + float left_cam_pos_x = trans_cam.position.x - VIEWPORT_X / 2; + if (trans_worker.position.x < left_cam_pos_x - 1000) { + trans_worker.position.x = left_cam_pos_x + VIEWPORT_X + 1000; + + do { + float min_value = -2500 * dt.count(); + float max_value = 2500 * dt.count(); + rb_worker.data.linear_velocity.x + = min_value + + static_cast<float>(rand()) + / (static_cast<float>(RAND_MAX / (max_value - min_value))); + } while (rb_worker.data.linear_velocity.x < 500 * dt.count() + && rb_worker.data.linear_velocity.x > -500 * dt.count()); + + RefVector<Sprite> sprite_worker + = this->get_components_by_id<Sprite>(trans_worker.game_object_id); + RefVector<Animator> animator_worker + = this->get_components_by_id<Animator>(trans_worker.game_object_id); + BehaviorScript & bs_panic + = this->get_components_by_id<BehaviorScript>(trans_worker.game_object_id) + .front(); + + if (rb_worker.data.linear_velocity.x < 0) { + sprite_worker.front().get().data.flip.flip_x = true; + sprite_worker.back().get().data.flip.flip_x = true; + + animator_worker.front().get().data.fps + = -rb_worker.data.linear_velocity.x / 5; + animator_worker.back().get().data.fps + = -rb_worker.data.linear_velocity.x / 5; + animator_worker.front().get().set_anim(0); + animator_worker.back().get().set_anim(0); + animator_worker.front().get().active = true; + animator_worker.back().get().active = true; + } else { + sprite_worker.front().get().data.flip.flip_x = false; + sprite_worker.back().get().data.flip.flip_x = false; + + animator_worker.front().get().data.fps + = rb_worker.data.linear_velocity.x / 5; + animator_worker.back().get().data.fps + = rb_worker.data.linear_velocity.x / 5; + animator_worker.front().get().set_anim(0); + animator_worker.back().get().set_anim(0); + animator_worker.front().get().active = true; + animator_worker.back().get().active = true; + } + + trans_worker.rotation = 0; + bs_panic.active = true; + rb_worker.data.linear_velocity_coefficient = {1, 1}; + for (Sprite & sprite : sprite_worker) { + sprite.data.position_offset.x = 0; + } + } + } else { + float right_cam_pos_x = trans_cam.position.x + VIEWPORT_X / 2; + if (trans_worker.position.x > right_cam_pos_x + 1000) { + do { + float min_value = -2500 * dt.count(); + float max_value = 2500 * dt.count(); + rb_worker.data.linear_velocity.x + = min_value + + static_cast<float>(rand()) + / (static_cast<float>(RAND_MAX / (max_value - min_value))); + } while (rb_worker.data.linear_velocity.x < 500 * dt.count() + && rb_worker.data.linear_velocity.x > -500 * dt.count()); + + RefVector<Sprite> sprite_worker + = this->get_components_by_id<Sprite>(trans_worker.game_object_id); + RefVector<Animator> animator_worker + = this->get_components_by_id<Animator>(trans_worker.game_object_id); + BehaviorScript & bs_panic + = this->get_components_by_id<BehaviorScript>(trans_worker.game_object_id) + .front(); + + if (rb_worker.data.linear_velocity.x < 0) { + sprite_worker.front().get().data.flip.flip_x = true; + sprite_worker.back().get().data.flip.flip_x = true; + + animator_worker.front().get().data.fps + = -rb_worker.data.linear_velocity.x / 5; + animator_worker.back().get().data.fps + = -rb_worker.data.linear_velocity.x / 5; + + animator_worker.front().get().set_anim(0); + animator_worker.back().get().set_anim(0); + animator_worker.front().get().active = true; + animator_worker.back().get().active = true; + } else { + sprite_worker.front().get().data.flip.flip_x = false; + sprite_worker.back().get().data.flip.flip_x = false; + + animator_worker.front().get().data.fps + = rb_worker.data.linear_velocity.x / 5; + animator_worker.back().get().data.fps + = rb_worker.data.linear_velocity.x / 5; + + animator_worker.front().get().set_anim(0); + animator_worker.back().get().set_anim(0); + animator_worker.front().get().active = true; + animator_worker.back().get().active = true; + } + + trans_worker.rotation = 0; + bs_panic.active = true; + rb_worker.data.linear_velocity_coefficient = {1, 1}; + for (Sprite & sprite : sprite_worker) { + sprite.data.position_offset.x = 0; + } + } + } + + counter++; + } +} diff --git a/game/workers/WorkerScript.h b/game/workers/WorkerScript.h new file mode 100644 index 0000000..ae4a6c7 --- /dev/null +++ b/game/workers/WorkerScript.h @@ -0,0 +1,8 @@ +#pragma once + +#include <crepe/api/Script.h> + +class WorkerScript : public crepe::Script { +public: + void fixed_update(crepe::duration_t dt); +}; diff --git a/game/workers/WorkersSubScene.cpp b/game/workers/WorkersSubScene.cpp new file mode 100644 index 0000000..54996d1 --- /dev/null +++ b/game/workers/WorkersSubScene.cpp @@ -0,0 +1,423 @@ +#include "WorkersSubScene.h" +#include "CollisionScript.h" +#include "PanicFromPlayerScript.h" +#include "WorkerScript.h" + +#include "../Config.h" +#include "api/GameObject.h" + +#include <crepe/api/Animator.h> +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/BoxCollider.h> +#include <crepe/api/Rigidbody.h> +#include <crepe/api/Scene.h> +#include <crepe/api/Sprite.h> + +using namespace crepe; +using namespace std; + +WorkersSubScene::WorkersSubScene(Scene & scn) { + this->worker1(scn, 1200, -50); + this->worker2(scn, 1300, 20); + this->worker3(scn, 1400, -40); + this->worker4(scn, 7250, 50); + this->worker5(scn, 3400, -20); + this->worker6(scn, 2000, 30); + this->worker7(scn, 3725, 35); + this->worker8(scn, 2200, -15); + + GameObject script = scn.new_object("workers_script"); + script.add_component<BehaviorScript>().set_script<WorkerScript>(); +} + +void WorkersSubScene::worker1(crepe::Scene & scn, float start_x, float init_speed) { + GameObject worker_1 = scn.new_object("worker_1", "worker", vec2(start_x, 200)); + Sprite & worker_1_body_sprite = worker_1.add_component<Sprite>( + Asset {"asset/workers/worker1Body.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_WORKERS_BACK, + .order_in_layer = 0, + .size = vec2(0, 50), + } + ); + worker_1.add_component<Animator>( + worker_1_body_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = static_cast<unsigned int>(abs(init_speed) / 5), + .looping = true, + } + ); + Sprite & worker_1_head_sprite = worker_1.add_component<Sprite>( + Asset {"asset/workers/worker1Head.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_WORKERS_BACK, + .order_in_layer = 1, + .size = vec2(0, 50), + .position_offset = vec2(0, -20), + } + ); + worker_1.add_component<Animator>( + worker_1_head_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = static_cast<unsigned int>(abs(init_speed) / 5), + .looping = true, + } + ); + worker_1.add_component<BoxCollider>(vec2(50, 50)); + worker_1.add_component<Rigidbody>(Rigidbody::Data { + .gravity_scale = 20, + .body_type = Rigidbody::BodyType::DYNAMIC, + .linear_velocity = vec2(init_speed, 0), + .collision_layers = {COLL_LAY_BOT_TOP}, + }); + worker_1.add_component<BehaviorScript>().set_script<PanicFromPlayerScript>(); + worker_1.add_component<BehaviorScript>().set_script<CollisionScript>(); + + if (init_speed < 0) { + worker_1_body_sprite.data.flip = Sprite::FlipSettings {true, false}; + worker_1_head_sprite.data.flip = Sprite::FlipSettings {true, false}; + } +} + +void WorkersSubScene::worker2(crepe::Scene & scn, float start_x, float init_speed) { + GameObject worker_2 = scn.new_object("worker_2", "worker", vec2(start_x, 200)); + Sprite & worker_2_body_sprite = worker_2.add_component<Sprite>( + Asset {"asset/workers/worker2Body.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_WORKERS_FRONT, + .order_in_layer = 2, + .size = vec2(0, 50), + } + ); + worker_2.add_component<Animator>( + worker_2_body_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = static_cast<unsigned int>(abs(init_speed) / 5), + .looping = true, + } + ); + Sprite & worker_2_head_sprite = worker_2.add_component<Sprite>( + Asset {"asset/workers/worker1Head.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_WORKERS_FRONT, + .order_in_layer = 3, + .size = vec2(0, 50), + .position_offset = vec2(0, -20), + } + ); + worker_2.add_component<Animator>( + worker_2_head_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = static_cast<unsigned int>(abs(init_speed) / 5), + .looping = true, + } + ); + worker_2.add_component<BoxCollider>(vec2(50, 50)); + worker_2.add_component<Rigidbody>(Rigidbody::Data { + .gravity_scale = 20, + .body_type = Rigidbody::BodyType::DYNAMIC, + .linear_velocity = vec2(init_speed, 0), + .collision_layers = {COLL_LAY_BOT_TOP}, + }); + worker_2.add_component<BehaviorScript>().set_script<PanicFromPlayerScript>(); + worker_2.add_component<BehaviorScript>().set_script<CollisionScript>(); + + if (init_speed < 0) { + worker_2_body_sprite.data.flip = Sprite::FlipSettings {true, false}; + worker_2_head_sprite.data.flip = Sprite::FlipSettings {true, false}; + } +} + +void WorkersSubScene::worker3(crepe::Scene & scn, float start_x, float init_speed) { + GameObject worker_3 = scn.new_object("worker_3", "worker", vec2(start_x, 200)); + Sprite & worker_3_body_sprite = worker_3.add_component<Sprite>( + Asset {"asset/workers/worker1Body.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_WORKERS_BACK, + .order_in_layer = 4, + .size = vec2(0, 50), + } + ); + worker_3.add_component<Animator>( + worker_3_body_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = static_cast<unsigned int>(abs(init_speed) / 5), + .looping = true, + } + ); + Sprite & worker_3_head_sprite = worker_3.add_component<Sprite>( + Asset {"asset/workers/worker2Head.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_WORKERS_BACK, + .order_in_layer = 5, + .size = vec2(0, 50), + .position_offset = vec2(0, -20), + } + ); + worker_3.add_component<Animator>( + worker_3_head_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = static_cast<unsigned int>(abs(init_speed) / 5), + .looping = true, + } + ); + worker_3.add_component<BoxCollider>(vec2(50, 50)); + worker_3.add_component<Rigidbody>(Rigidbody::Data { + .gravity_scale = 20, + .body_type = Rigidbody::BodyType::DYNAMIC, + .linear_velocity = vec2(init_speed, 0), + .collision_layers = {COLL_LAY_BOT_TOP}, + }); + worker_3.add_component<BehaviorScript>().set_script<PanicFromPlayerScript>(); + worker_3.add_component<BehaviorScript>().set_script<CollisionScript>(); + + if (init_speed < 0) { + worker_3_body_sprite.data.flip = Sprite::FlipSettings {true, false}; + worker_3_head_sprite.data.flip = Sprite::FlipSettings {true, false}; + } +} + +void WorkersSubScene::worker4(crepe::Scene & scn, float start_x, float init_speed) { + GameObject worker_4 = scn.new_object("worker_4", "worker", vec2(start_x, 200)); + Sprite & worker_4_body_sprite = worker_4.add_component<Sprite>( + Asset {"asset/workers/worker2Body.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_WORKERS_FRONT, + .order_in_layer = 6, + .size = vec2(0, 50), + } + ); + worker_4.add_component<Animator>( + worker_4_body_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = static_cast<unsigned int>(abs(init_speed) / 5), + .looping = true, + } + ); + Sprite & worker_4_head_sprite = worker_4.add_component<Sprite>( + Asset {"asset/workers/worker2Head.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_WORKERS_FRONT, + .order_in_layer = 7, + .size = vec2(0, 50), + .position_offset = vec2(0, -20), + } + ); + worker_4.add_component<Animator>( + worker_4_head_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = static_cast<unsigned int>(abs(init_speed) / 5), + .looping = true, + } + ); + worker_4.add_component<BoxCollider>(vec2(50, 50)); + worker_4.add_component<Rigidbody>(Rigidbody::Data { + .gravity_scale = 20, + .body_type = Rigidbody::BodyType::DYNAMIC, + .linear_velocity = vec2(init_speed, 0), + .collision_layers = {COLL_LAY_BOT_HIGH}, + }); + worker_4.add_component<BehaviorScript>().set_script<PanicFromPlayerScript>(); + worker_4.add_component<BehaviorScript>().set_script<CollisionScript>(); + + if (init_speed < 0) { + worker_4_body_sprite.data.flip = Sprite::FlipSettings {true, false}; + worker_4_head_sprite.data.flip = Sprite::FlipSettings {true, false}; + } +} + +void WorkersSubScene::worker5(crepe::Scene & scn, float start_x, float init_speed) { + GameObject worker_5 = scn.new_object("worker_5", "worker", vec2(start_x, 200)); + Sprite & worker_5_body_sprite = worker_5.add_component<Sprite>( + Asset {"asset/workers/workerFatBody.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_WORKERS_BACK, + .order_in_layer = 8, + .size = vec2(0, 50), + } + ); + worker_5.add_component<Animator>( + worker_5_body_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = static_cast<unsigned int>(abs(init_speed) / 5), + .looping = true, + } + ); + Sprite & worker_5_head_sprite = worker_5.add_component<Sprite>( + Asset {"asset/workers/worker1Head.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_WORKERS_BACK, + .order_in_layer = 9, + .size = vec2(0, 50), + .position_offset = vec2(0, -20), + } + ); + worker_5.add_component<Animator>( + worker_5_head_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = static_cast<unsigned int>(abs(init_speed) / 5), + .looping = true, + } + ); + worker_5.add_component<BoxCollider>(vec2(50, 50)); + worker_5.add_component<Rigidbody>(Rigidbody::Data { + .gravity_scale = 20, + .body_type = Rigidbody::BodyType::DYNAMIC, + .linear_velocity = vec2(init_speed, 0), + .collision_layers = {COLL_LAY_BOT_HIGH}, + }); + worker_5.add_component<BehaviorScript>().set_script<PanicFromPlayerScript>(); + worker_5.add_component<BehaviorScript>().set_script<CollisionScript>(); + + if (init_speed < 0) { + worker_5_body_sprite.data.flip = Sprite::FlipSettings {true, false}; + worker_5_head_sprite.data.flip = Sprite::FlipSettings {true, false}; + } +} + +void WorkersSubScene::worker6(crepe::Scene & scn, float start_x, float init_speed) { + GameObject worker_6 = scn.new_object("worker_6", "worker", vec2(start_x, 200)); + Sprite & worker_6_body_sprite = worker_6.add_component<Sprite>( + Asset {"asset/workers/workerFatBody.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_WORKERS_FRONT, + .order_in_layer = 10, + .size = vec2(0, 50), + } + ); + worker_6.add_component<Animator>( + worker_6_body_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = static_cast<unsigned int>(abs(init_speed) / 5), + .looping = true, + } + ); + Sprite & worker_6_head_sprite = worker_6.add_component<Sprite>( + Asset {"asset/workers/worker2Head.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_WORKERS_FRONT, + .order_in_layer = 11, + .size = vec2(0, 50), + .position_offset = vec2(0, -20), + } + ); + worker_6.add_component<Animator>( + worker_6_head_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = static_cast<unsigned int>(abs(init_speed) / 5), + .looping = true, + } + ); + worker_6.add_component<BoxCollider>(vec2(50, 50)); + worker_6.add_component<Rigidbody>(Rigidbody::Data { + .gravity_scale = 20, + .body_type = Rigidbody::BodyType::DYNAMIC, + .linear_velocity = vec2(init_speed, 0), + .collision_layers = {COLL_LAY_BOT_LOW}, + }); + worker_6.add_component<BehaviorScript>().set_script<PanicFromPlayerScript>(); + worker_6.add_component<BehaviorScript>().set_script<CollisionScript>(); + + if (init_speed < 0) { + worker_6_body_sprite.data.flip = Sprite::FlipSettings {true, false}; + worker_6_head_sprite.data.flip = Sprite::FlipSettings {true, false}; + } +} + +void WorkersSubScene::worker7(crepe::Scene & scn, float start_x, float init_speed) { + GameObject worker_7 = scn.new_object("worker_7", "worker", vec2(start_x, 200)); + Sprite & worker_7_body_sprite = worker_7.add_component<Sprite>( + Asset {"asset/workers/workerTallBody.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_WORKERS_BACK, + .order_in_layer = 12, + .size = vec2(0, 50), + } + ); + worker_7.add_component<Animator>( + worker_7_body_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = static_cast<unsigned int>(abs(init_speed) / 5), + .looping = true, + } + ); + Sprite & worker_7_head_sprite = worker_7.add_component<Sprite>( + Asset {"asset/workers/worker1Head.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_WORKERS_BACK, + .order_in_layer = 13, + .size = vec2(0, 50), + .position_offset = vec2(0, -20), + } + ); + worker_7.add_component<Animator>( + worker_7_head_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = static_cast<unsigned int>(abs(init_speed) / 5), + .looping = true, + } + ); + worker_7.add_component<BoxCollider>(vec2(50, 50)); + worker_7.add_component<Rigidbody>(Rigidbody::Data { + .gravity_scale = 20, + .body_type = Rigidbody::BodyType::DYNAMIC, + .linear_velocity = vec2(init_speed, 0), + .collision_layers = {COLL_LAY_BOT_LOW}, + }); + worker_7.add_component<BehaviorScript>().set_script<PanicFromPlayerScript>(); + worker_7.add_component<BehaviorScript>().set_script<CollisionScript>(); + + if (init_speed < 0) { + worker_7_body_sprite.data.flip = Sprite::FlipSettings {true, false}; + worker_7_head_sprite.data.flip = Sprite::FlipSettings {true, false}; + } +} + +void WorkersSubScene::worker8(crepe::Scene & scn, float start_x, float init_speed) { + GameObject worker_8 = scn.new_object("worker_8", "worker", vec2(start_x, 200)); + Sprite & worker_8_body_sprite = worker_8.add_component<Sprite>( + Asset {"asset/workers/workerTallBody.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_WORKERS_FRONT, + .order_in_layer = 14, + .size = vec2(0, 50), + } + ); + worker_8.add_component<Animator>( + worker_8_body_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = static_cast<unsigned int>(abs(init_speed) / 5), + .looping = true, + } + ); + Sprite & worker_8_head_sprite = worker_8.add_component<Sprite>( + Asset {"asset/workers/worker2Head.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_WORKERS_FRONT, + .order_in_layer = 15, + .size = vec2(0, 50), + .position_offset = vec2(0, -20), + } + ); + worker_8.add_component<Animator>( + worker_8_head_sprite, ivec2(32, 32), uvec2(4, 8), + Animator::Data { + .fps = static_cast<unsigned int>(abs(init_speed) / 5), + .looping = true, + } + ); + worker_8.add_component<BoxCollider>(vec2(50, 50)); + worker_8.add_component<Rigidbody>(Rigidbody::Data { + .gravity_scale = 20, + .body_type = Rigidbody::BodyType::DYNAMIC, + .linear_velocity = vec2(init_speed, 0), + .collision_layers = {COLL_LAY_BOT_LOW}, + }); + worker_8.add_component<BehaviorScript>().set_script<PanicFromPlayerScript>(); + worker_8.add_component<BehaviorScript>().set_script<CollisionScript>(); + + if (init_speed < 0) { + worker_8_body_sprite.data.flip = Sprite::FlipSettings {true, false}; + worker_8_head_sprite.data.flip = Sprite::FlipSettings {true, false}; + } +} diff --git a/game/workers/WorkersSubScene.h b/game/workers/WorkersSubScene.h new file mode 100644 index 0000000..6692d87 --- /dev/null +++ b/game/workers/WorkersSubScene.h @@ -0,0 +1,20 @@ +#pragma once + +namespace crepe { +class Scene; +} + +class WorkersSubScene { +public: + WorkersSubScene(crepe::Scene & scn); + +private: + void worker1(crepe::Scene & scn, float start_x, float init_speed); + void worker2(crepe::Scene & scn, float start_x, float init_speed); + void worker3(crepe::Scene & scn, float start_x, float init_speed); + void worker4(crepe::Scene & scn, float start_x, float init_speed); + void worker5(crepe::Scene & scn, float start_x, float init_speed); + void worker6(crepe::Scene & scn, float start_x, float init_speed); + void worker7(crepe::Scene & scn, float start_x, float init_speed); + void worker8(crepe::Scene & scn, float start_x, float init_speed); +}; diff --git a/lib/segvcatch/CMakeLists.txt b/lib/segvcatch/CMakeLists.txt deleted file mode 100644 index 4449e77..0000000 --- a/lib/segvcatch/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -cmake_minimum_required(VERSION 3.28) -set(CMAKE_CXX_STANDARD 20) -project(segvcatch CXX) - -include(CMakePackageConfigHelpers) - -add_library(segvcatch SHARED lib/lib/segvcatch.cpp) - -install( - TARGETS segvcatch - EXPORT segvcatchTargets - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION lib - INCLUDES DESTINATION include -) -install( - FILES lib/lib/segvcatch.h - DESTINATION include -) -write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/segvcatch-config-version.cmake" - VERSION 0.0.0 - COMPATIBILITY AnyNewerVersion -) -install( - FILES - "${CMAKE_CURRENT_BINARY_DIR}/segvcatch-config-version.cmake" - DESTINATION lib/cmake/segvcatch -) -install( - EXPORT segvcatchTargets - FILE segvcatch-config.cmake - DESTINATION lib/cmake/segvcatch -) diff --git a/lib/segvcatch/lib b/lib/segvcatch/lib deleted file mode 160000 -Subproject afe79c49f7d996e2b3143199e6cef69f406247b diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b7d63d7..696856c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -15,8 +15,6 @@ find_package(GTest REQUIRED) find_package(whereami REQUIRED) find_library(BERKELEY_DB db) find_library(FONTCONFIG_LIB fontconfig) -find_package(segvcatch REQUIRED) -find_package(segvcatch REQUIRED) add_library(crepe SHARED) add_executable(test_main EXCLUDE_FROM_ALL) @@ -33,7 +31,6 @@ target_link_libraries(crepe PUBLIC ${BERKELEY_DB} PUBLIC whereami PUBLIC ${FONTCONFIG_LIB} - PUBLIC segvcatch ) add_subdirectory(crepe) diff --git a/src/crepe/api/Animator.cpp b/src/crepe/api/Animator.cpp index 5ac0617..c558d86 100644 --- a/src/crepe/api/Animator.cpp +++ b/src/crepe/api/Animator.cpp @@ -36,12 +36,24 @@ void Animator::pause() { this->active = false; } void Animator::stop() { this->active = false; - this->data.frame = this->data.cycle_start; + this->data.col = 0; + this->data.row = 0; } void Animator::set_fps(int fps) { this->data.fps = fps; } void Animator::set_cycle_range(int start, int end) { - this->data.cycle_start = start; - this->data.cycle_end = end; + this->data.cycle_start = start, this->data.cycle_end = end; } +void Animator::set_anim(int col) { + Animator::Data & ctx = this->data; + this->spritesheet.mask.x = ctx.row = 0; + ctx.col = col; + this->spritesheet.mask.y = ctx.col * this->spritesheet.mask.h; +} + +void Animator::next_anim() { + Animator::Data & ctx = this->data; + ctx.row = ++ctx.row % this->grid_size.x; + this->spritesheet.mask.x = ctx.row * this->spritesheet.mask.w; +} diff --git a/src/crepe/api/Animator.h b/src/crepe/api/Animator.h index 8be693e..95539d3 100644 --- a/src/crepe/api/Animator.h +++ b/src/crepe/api/Animator.h @@ -1,7 +1,7 @@ #pragma once -#include "../types.h" #include "../manager/LoopTimerManager.h" +#include "../types.h" #include "Component.h" #include "Sprite.h" @@ -23,15 +23,16 @@ public: struct Data { //! frames per second for animation unsigned int fps = 1; - //! The current frame being shown - unsigned int frame = 0; - + //! The current col being animated. + unsigned int col = 0; + //! The current row being animated. + unsigned int row = 0; //! should the animation loop bool looping = false; //! starting frame for cycling unsigned int cycle_start = 0; //! end frame for cycling (-1 = use last frame) - unsigned int cycle_end = -1; + int cycle_end = -1; }; public: @@ -60,6 +61,14 @@ public: * \param end of row animation */ void set_cycle_range(int start, int end); + /** + * \brief select which column to animate from + * + * \param col animation column + */ + void set_anim(int col); + //! will go to the next animaiton of current row + void next_anim(); public: /** @@ -91,11 +100,14 @@ private: //! The maximum number of rows and columns inside the spritesheet const uvec2 grid_size; + // the time elapsed from a frame duration + duration_t elapsed_time = {}; + + // frame counter + unsigned int frame = 0; + //! Uses the spritesheet friend AnimatorSystem; - - //! Elasped time since last frame change - duration_t elapsed; }; } // namespace crepe diff --git a/src/crepe/api/BehaviorScript.h b/src/crepe/api/BehaviorScript.h index 52cf259..3909b96 100644 --- a/src/crepe/api/BehaviorScript.h +++ b/src/crepe/api/BehaviorScript.h @@ -48,8 +48,6 @@ public: BehaviorScript & set_script(Args &&... args); protected: - //! Script type name - std::string name = "unknown script"; //! Script instance std::unique_ptr<Script> script = nullptr; //! ScriptSystem needs direct access to the script instance diff --git a/src/crepe/api/BehaviorScript.hpp b/src/crepe/api/BehaviorScript.hpp index 218f27c..353d5e2 100644 --- a/src/crepe/api/BehaviorScript.hpp +++ b/src/crepe/api/BehaviorScript.hpp @@ -11,7 +11,6 @@ template <class T, typename... Args> BehaviorScript & BehaviorScript::set_script(Args &&... args) { static_assert(std::is_base_of<Script, T>::value); this->script = std::unique_ptr<Script>(new T(std::forward<Args>(args)...)); - this->name = typeid(T).name(); this->script->game_object_id = this->game_object_id; this->script->active = this->active; diff --git a/src/crepe/api/Button.cpp b/src/crepe/api/Button.cpp index 40153c9..8eadd89 100644 --- a/src/crepe/api/Button.cpp +++ b/src/crepe/api/Button.cpp @@ -2,7 +2,10 @@ namespace crepe { -Button::Button(game_object_id_t id, const vec2 & dimensions, const vec2 & offset) - : UIObject(id, dimensions, offset) {} +Button::Button( + game_object_id_t id, const vec2 & dimensions, const Data & data, const vec2 & offset +) + : UIObject(id, dimensions, offset), + data(data) {} } // namespace crepe diff --git a/src/crepe/api/Button.h b/src/crepe/api/Button.h index d42527e..e986c04 100644 --- a/src/crepe/api/Button.h +++ b/src/crepe/api/Button.h @@ -1,8 +1,7 @@ #pragma once -#include <functional> +#include "../types.h" -#include "Event.h" #include "UIObject.h" namespace crepe { @@ -21,14 +20,24 @@ namespace crepe { */ class Button : public UIObject { public: + struct Data { + //! variable indicating if transform is relative to camera(false) or world(true) + bool world_space = false; + }; + +public: /** * \brief Constructs a Button with the specified game object ID and dimensions. * * \param id The unique ID of the game object associated with this button. * \param dimensions The width and height of the UIObject * \param offset The offset relative this GameObjects Transform + * \param data additional data the button has */ - Button(game_object_id_t id, const vec2 & dimensions, const vec2 & offset); + Button( + game_object_id_t id, const vec2 & dimensions, const Data & data, + const vec2 & offset = {0, 0} + ); /** * \brief Get the maximum number of instances for this component * @@ -38,6 +47,9 @@ public: */ virtual int get_instances_max() const { return 1; } +public: + Data data; + private: //! friend relation hover variable friend class InputSystem; diff --git a/src/crepe/api/Color.cpp b/src/crepe/api/Color.cpp index 6858aa8..d0e3b35 100644 --- a/src/crepe/api/Color.cpp +++ b/src/crepe/api/Color.cpp @@ -10,3 +10,5 @@ const Color Color::BLACK {0x00, 0x00, 0x00}; const Color Color::CYAN {0x00, 0xff, 0xff}; const Color Color::YELLOW {0xff, 0xff, 0x00}; const Color Color::MAGENTA {0xff, 0x00, 0xff}; +const Color Color::GREY {0x80, 0x80, 0x80}; +const Color Color::GOLD {249, 205, 91}; diff --git a/src/crepe/api/Color.h b/src/crepe/api/Color.h index 84edb5c..dbfd0ed 100644 --- a/src/crepe/api/Color.h +++ b/src/crepe/api/Color.h @@ -18,6 +18,8 @@ struct Color { static const Color MAGENTA; static const Color YELLOW; static const Color BLACK; + static const Color GREY; + static const Color GOLD; }; } // namespace crepe diff --git a/src/crepe/api/Config.h b/src/crepe/api/Config.h index 32f1a2e..7475528 100644 --- a/src/crepe/api/Config.h +++ b/src/crepe/api/Config.h @@ -86,7 +86,7 @@ struct Config final { * This config option is the font size at which all fonts will be loaded initially. * */ - unsigned int size = 16; + unsigned int size = 500; } font; //! Configuration for click tolerance. struct { diff --git a/src/crepe/api/Engine.cpp b/src/crepe/api/Engine.cpp index bf3f50c..0bbe51f 100644 --- a/src/crepe/api/Engine.cpp +++ b/src/crepe/api/Engine.cpp @@ -1,7 +1,4 @@ -#include <segvcatch.h> - #include "../util/Log.h" -#include "../facade/SignalCatch.h" #include "Engine.h" @@ -9,8 +6,6 @@ using namespace crepe; using namespace std; int Engine::main() noexcept { - SignalCatch signal_catch; - try { this->setup(); } catch (const exception & e) { @@ -42,39 +37,32 @@ void Engine::setup() { void Engine::loop() { LoopTimerManager & timer = this->loop_timer; + SystemManager & systems = this->system_manager; while (this->game_running) { timer.update(); while (timer.get_lag() >= timer.get_fixed_delta_time()) { try { - this->fixed_update(); + systems.fixed_update(); } catch (const exception & e) { Log::logf( - Log::Level::WARNING, "Uncaught exception in fixed update function: {}", + Log::Level::WARNING, "Uncaught exception in fixed update function: {}\n", e.what() ); } + timer.advance_fixed_elapsed_time(); } try { - this->frame_update(); + systems.frame_update(); + this->scene_manager.load_next_scene(); } catch (const exception & e) { Log::logf( - Log::Level::WARNING, "Uncaught exception in frame update function: {}", + Log::Level::WARNING, "Uncaught exception in frame update function: {}\n", e.what() ); } + timer.enforce_frame_rate(); } } - -void Engine::fixed_update() { - this->system_manager.fixed_update(); - this->loop_timer.advance_fixed_elapsed_time(); -} - -void Engine::frame_update() { - this->system_manager.frame_update(); - this->loop_timer.enforce_frame_rate(); -} - diff --git a/src/crepe/api/Engine.h b/src/crepe/api/Engine.h index 23acfb4..452a856 100644 --- a/src/crepe/api/Engine.h +++ b/src/crepe/api/Engine.h @@ -46,11 +46,6 @@ private: */ void loop(); - //! Fixed update function - void fixed_update(); - //! Frame update function - void frame_update(); - //! Game loop condition bool game_running = true; diff --git a/src/crepe/api/Sprite.cpp b/src/crepe/api/Sprite.cpp index 0107c7b..3c77e2e 100644 --- a/src/crepe/api/Sprite.cpp +++ b/src/crepe/api/Sprite.cpp @@ -19,3 +19,16 @@ Sprite::Sprite(game_object_id_t id, const Asset & texture, const Sprite::Data & } Sprite::~Sprite() { dbg_trace(); } + +unique_ptr<Component> Sprite::save() const { return unique_ptr<Component>(new Sprite(*this)); } + +void Sprite::restore(const Component & snapshot) { + *this = static_cast<const Sprite &>(snapshot); +} + +Sprite & Sprite::operator=(const Sprite & snapshot) { + this->active = snapshot.active; + this->data = snapshot.data; + this->mask = snapshot.mask; + return *this; +} diff --git a/src/crepe/api/Sprite.h b/src/crepe/api/Sprite.h index ef65f64..3565bed 100644 --- a/src/crepe/api/Sprite.h +++ b/src/crepe/api/Sprite.h @@ -42,10 +42,10 @@ public: FlipSettings flip; //! Layer sorting level of the sprite - const int sorting_in_layer = 0; + int sorting_in_layer = 0; //! Order within the sorting layer - const int order_in_layer = 0; + int order_in_layer = 0; /** * \brief width and height of the sprite in game units @@ -110,16 +110,21 @@ private: */ float aspect_ratio = 0; -public: - struct Mask { - unsigned w = 0; - unsigned h = 0; - unsigned x = 0; - unsigned y = 0; + struct Rect { + int w = 0; + int h = 0; + int x = 0; + int y = 0; }; //! Render area of the sprite this will also be adjusted by the AnimatorSystem if an Animator // object is present in GameObject. this is in sprite pixels - Mask mask; + Rect mask; + +protected: + virtual std::unique_ptr<Component> save() const; + Sprite(const Sprite &) = default; + virtual void restore(const Component & snapshot); + virtual Sprite & operator=(const Sprite &); }; } // namespace crepe diff --git a/src/crepe/api/Text.cpp b/src/crepe/api/Text.cpp index b24f0ac..e5cc39d 100644 --- a/src/crepe/api/Text.cpp +++ b/src/crepe/api/Text.cpp @@ -1,12 +1,27 @@ +#include "../types.h" + #include "Text.h" using namespace crepe; +using namespace std; Text::Text( - game_object_id_t id, const vec2 & dimensions, const vec2 & offset, - const std::string & font_family, const Data & data, const std::string & text + game_object_id_t id, const vec2 & dimensions, const std::string & font_family, + const Data & data, const vec2 & offset, const std::string & text ) : UIObject(id, dimensions, offset), text(text), data(data), font_family(font_family) {} + +unique_ptr<Component> Text::save() const { return unique_ptr<Component>(new Text(*this)); } + +void Text::restore(const Component & snapshot) { *this = static_cast<const Text &>(snapshot); } + +Text & Text::operator=(const Text & snapshot) { + this->active = snapshot.active; + this->data = snapshot.data; + this->text = snapshot.text; + this->font_family = snapshot.font_family; + return *this; +} diff --git a/src/crepe/api/Text.h b/src/crepe/api/Text.h index 0289b85..859490e 100644 --- a/src/crepe/api/Text.h +++ b/src/crepe/api/Text.h @@ -3,6 +3,8 @@ #include <optional> #include <string> +#include "../types.h" + #include "Asset.h" #include "Color.h" #include "UIObject.h" @@ -17,22 +19,8 @@ class Text : public UIObject { public: //! Text data that does not have to be set in the constructor struct Data { - /** - * \brief fontsize for text rendering - * - * \note this is not the actual font size that is loaded in. - * - * Since SDL_TTF requires the font size when loading in the font it is not possible to switch the font size. - * The default font size that is loaded is set in the Config. - * Instead this value is used to upscale the font texture which can cause blurring or distorted text when upscaling or downscaling too much. - */ - unsigned int font_size = 16; - - //! Layer sorting level of the text - const int sorting_in_layer = 0; - - //! Order within the sorting text - const int order_in_layer = 0; + //! variable indicating if transform is relative to camera(false) or world(true) + bool world_space = false; //! Label text color. Color text_color = Color::BLACK; @@ -49,8 +37,8 @@ public: * \param font Optional font asset that can be passed or left empty. */ Text( - game_object_id_t id, const vec2 & dimensions, const vec2 & offset, - const std::string & font_family, const Data & data, const std::string & text = "" + game_object_id_t id, const vec2 & dimensions, const std::string & font_family, + const Data & data, const vec2 & offset = {0, 0}, const std::string & text = "" ); //! Label text. @@ -61,6 +49,12 @@ public: std::optional<Asset> font; //! Data instance Data data; + +protected: + virtual std::unique_ptr<Component> save() const; + Text(const Text &) = default; + virtual void restore(const Component & snapshot); + virtual Text & operator=(const Text &); }; } // namespace crepe diff --git a/src/crepe/api/UIObject.h b/src/crepe/api/UIObject.h index f1318ab..0d9b1f7 100644 --- a/src/crepe/api/UIObject.h +++ b/src/crepe/api/UIObject.h @@ -15,13 +15,11 @@ public: * \param dimensions width and height of the UIObject * \param offset Offset relative to the GameObject Transform */ - UIObject(game_object_id_t id, const vec2 & dimensions, const vec2 & offset); + UIObject(game_object_id_t id, const vec2 & dimensions, const vec2 & offset = {0, 0}); //! Width and height of the UIObject vec2 dimensions; //! Position offset relative to this GameObjects Transform vec2 offset; - //! variable indicating if transform is relative to camera(false) or world(true) - bool world_space = false; }; } // namespace crepe diff --git a/src/crepe/api/Vector2.h b/src/crepe/api/Vector2.h index 52e1bb6..6613641 100644 --- a/src/crepe/api/Vector2.h +++ b/src/crepe/api/Vector2.h @@ -1,5 +1,7 @@ #pragma once +#include <format> + namespace crepe { //! 2D vector @@ -11,55 +13,55 @@ struct Vector2 { T y = 0; //! Subtracts another vector from this vector and returns the result. - Vector2 operator-(const Vector2<T> & other) const; + Vector2<T> operator-(const Vector2<T> & other) const; //! Subtracts a scalar value from both components of this vector and returns the result. - Vector2 operator-(T scalar) const; + Vector2<T> operator-(T scalar) const; //! Adds another vector to this vector and returns the result. - Vector2 operator+(const Vector2<T> & other) const; + Vector2<T> operator+(const Vector2<T> & other) const; //! Adds a scalar value to both components of this vector and returns the result. - Vector2 operator+(T scalar) const; + Vector2<T> operator+(T scalar) const; //! Multiplies this vector by another vector element-wise and returns the result. - Vector2 operator*(const Vector2<T> & other) const; + Vector2<T> operator*(const Vector2<T> & other) const; //! Multiplies this vector by a scalar and returns the result. - Vector2 operator*(T scalar) const; + Vector2<T> operator*(T scalar) const; //! Divides this vector by another vector element-wise and returns the result. - Vector2 operator/(const Vector2<T> & other) const; + Vector2<T> operator/(const Vector2<T> & other) const; //! Divides this vector by a scalar and returns the result. - Vector2 operator/(T scalar) const; + Vector2<T> operator/(T scalar) const; //! Adds another vector to this vector and updates this vector. - Vector2 & operator+=(const Vector2<T> & other); + Vector2<T> & operator+=(const Vector2<T> & other); //! Adds a scalar value to both components of this vector and updates this vector. - Vector2 & operator+=(T other); + Vector2<T> & operator+=(T other); //! Subtracts another vector from this vector and updates this vector. - Vector2 & operator-=(const Vector2<T> & other); + Vector2<T> & operator-=(const Vector2<T> & other); //! Subtracts a scalar value from both components of this vector and updates this vector. - Vector2 & operator-=(T other); + Vector2<T> & operator-=(T other); //! Multiplies this vector by another vector element-wise and updates this vector. - Vector2 & operator*=(const Vector2<T> & other); + Vector2<T> & operator*=(const Vector2<T> & other); //! Multiplies this vector by a scalar and updates this vector. - Vector2 & operator*=(T other); + Vector2<T> & operator*=(T other); //! Divides this vector by another vector element-wise and updates this vector. - Vector2 & operator/=(const Vector2<T> & other); + Vector2<T> & operator/=(const Vector2<T> & other); //! Divides this vector by a scalar and updates this vector. - Vector2 & operator/=(T other); + Vector2<T> & operator/=(T other); //! Returns the negation of this vector. - Vector2 operator-() const; + Vector2<T> operator-() const; //! Checks if this vector is equal to another vector. bool operator==(const Vector2<T> & other) const; @@ -89,12 +91,20 @@ struct Vector2 { T distance_squared(const Vector2<T> & other) const; //! Returns the perpendicular vector to this vector. - Vector2 perpendicular() const; + Vector2<T> perpendicular() const; //! Checks if both components of the vector are NaN. bool is_nan() const; + + //! Rotate this vector clockwise by \c deg degrees + Vector2<T> rotate(float deg) const; }; } // namespace crepe +template <typename T> +struct std::formatter<crepe::Vector2<T>> : std::formatter<std::string> { + format_context::iterator format(crepe::Vector2<T> vec, format_context & ctx) const; +}; + #include "Vector2.hpp" diff --git a/src/crepe/api/Vector2.hpp b/src/crepe/api/Vector2.hpp index e195760..30441d2 100644 --- a/src/crepe/api/Vector2.hpp +++ b/src/crepe/api/Vector2.hpp @@ -168,4 +168,19 @@ bool Vector2<T>::is_nan() const { return std::isnan(x) && std::isnan(y); } +template <class T> +Vector2<T> Vector2<T>::rotate(float deg) const { + float rad = -deg / 180 * M_PI; + return { + x * std::cos(rad) - y * std::sin(rad), + x * std::sin(rad) + y * std::cos(rad), + }; +} + } // namespace crepe + +template <typename T> +std::format_context::iterator +std::formatter<crepe::Vector2<T>>::format(crepe::Vector2<T> vec, format_context & ctx) const { + return formatter<string>::format(std::format("{{{}, {}}}", vec.x, vec.y), ctx); +} diff --git a/src/crepe/facade/CMakeLists.txt b/src/crepe/facade/CMakeLists.txt index 4873e8d..243ae46 100644 --- a/src/crepe/facade/CMakeLists.txt +++ b/src/crepe/facade/CMakeLists.txt @@ -6,7 +6,6 @@ target_sources(crepe PUBLIC DB.cpp FontFacade.cpp Font.cpp - SignalCatch.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -17,6 +16,5 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES DB.h FontFacade.h Font.h - SignalCatch.h ) diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index 859f966..6c93fb2 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -69,8 +69,6 @@ SDLContext::SDLContext(Mediator & mediator) { throw runtime_error(format("SDL_ttf initialization failed: {}", TTF_GetError())); } - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"); - mediator.sdl_context = *this; } @@ -174,6 +172,7 @@ SDL_FRect SDLContext::get_dst_rect(const DestinationRectangleData & ctx) const { } void SDLContext::draw(const RenderContext & ctx) { + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2"); const Sprite::Data & data = ctx.sprite.data; SDL_RendererFlip render_flip = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * data.flip.flip_x) @@ -206,6 +205,7 @@ void SDLContext::draw(const RenderContext & ctx) { } void SDLContext::draw_text(const RenderText & data) { + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); const Text & text = data.text; const Font & font = data.font; @@ -235,9 +235,16 @@ void SDLContext::draw_text(const RenderText & data) { = {tmp_font_texture, [](SDL_Texture * texture) { SDL_DestroyTexture(texture); }}; vec2 size = text.dimensions * cam_aux_data.render_scale * data.transform.scale; - vec2 screen_pos = (absoluut_pos - cam_aux_data.cam_pos + (cam_aux_data.zoomed_viewport) / 2 - ) * cam_aux_data.render_scale - - size / 2 + cam_aux_data.bar_size; + vec2 screen_pos = absoluut_pos; + if (text.data.world_space) { + screen_pos = (screen_pos - cam_aux_data.cam_pos + (cam_aux_data.zoomed_viewport) / 2) + * cam_aux_data.render_scale + - size / 2 + cam_aux_data.bar_size; + } else { + screen_pos + = (screen_pos + (cam_aux_data.zoomed_viewport) / 2) * cam_aux_data.render_scale + - size / 2 + cam_aux_data.bar_size; + } SDL_FRect dstrect { .x = screen_pos.x, diff --git a/src/crepe/facade/SignalCatch.cpp b/src/crepe/facade/SignalCatch.cpp deleted file mode 100644 index ad92d28..0000000 --- a/src/crepe/facade/SignalCatch.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include <stdexcept> - -#include "SignalCatch.h" - -using namespace crepe; -using namespace std; - -SignalCatch::SignalCatch() { - segvcatch::init_segv(&SignalCatch::segv); - segvcatch::init_fpe(&SignalCatch::fpe); -} - -SignalCatch::~SignalCatch() { - segvcatch::init_segv(); - segvcatch::init_fpe(); -} - -void SignalCatch::segv() { - throw runtime_error("segmentation fault"); -} - -void SignalCatch::fpe() { - throw domain_error("floating point exception"); -} - diff --git a/src/crepe/facade/SignalCatch.h b/src/crepe/facade/SignalCatch.h deleted file mode 100644 index 4562215..0000000 --- a/src/crepe/facade/SignalCatch.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include <segvcatch.h> - -namespace crepe { - -class SignalCatch { -public: - SignalCatch(); - ~SignalCatch(); - -private: - static void segv(); - static void fpe(); - -public: - SignalCatch(const SignalCatch &) = delete; - SignalCatch(SignalCatch &&) = delete; - SignalCatch & operator=(const SignalCatch &) = delete; - SignalCatch & operator=(SignalCatch &&) = delete; -}; - -} - diff --git a/src/crepe/manager/SystemManager.cpp b/src/crepe/manager/SystemManager.cpp index c8f4f3d..eabc022 100644 --- a/src/crepe/manager/SystemManager.cpp +++ b/src/crepe/manager/SystemManager.cpp @@ -31,25 +31,17 @@ SystemManager::SystemManager(Mediator & mediator) : Manager(mediator) { this->mediator.system_manager = *this; } -void SystemManager::fixed_update() noexcept { - for (SystemEntry & entry : this->system_order) { - if (!entry.system.active) continue; - try { - entry.system.fixed_update(); - } catch (const exception & e) { - Log::logf(Log::Level::WARNING, "Uncaught exception in {} fixed update: {}", entry.name, e.what()); - } +void SystemManager::fixed_update() { + for (System & system : this->system_order) { + if (!system.active) continue; + system.fixed_update(); } } -void SystemManager::frame_update() noexcept { - for (SystemEntry & entry : this->system_order) { - if (!entry.system.active) continue; - try { - entry.system.frame_update(); - } catch (const exception & e) { - Log::logf(Log::Level::WARNING, "Uncaught exception in {} frame update: {}", entry.name, e.what()); - } +void SystemManager::frame_update() { + for (System & system : this->system_order) { + if (!system.active) continue; + system.frame_update(); } } diff --git a/src/crepe/manager/SystemManager.h b/src/crepe/manager/SystemManager.h index 7b862a3..614d90c 100644 --- a/src/crepe/manager/SystemManager.h +++ b/src/crepe/manager/SystemManager.h @@ -26,14 +26,14 @@ public: * * Updates the game state based on the elapsed time since the last frame. */ - void frame_update() noexcept; + void frame_update(); /** * \brief Fixed update executed at a fixed rate. * * This function updates physics and game logic based on LoopTimer's fixed_delta_time. */ - void fixed_update() noexcept; + void fixed_update(); private: /** @@ -43,20 +43,13 @@ private: * constructor of \c SystemManager using SystemManager::load_system. */ std::unordered_map<std::type_index, std::unique_ptr<System>> systems; - //! Internal ordered system list entry - struct SystemEntry { - //! System instance reference - System & system; - //! System name - std::string name; - }; /** * \brief Collection of System instances * * This map holds System instances indexed by the system's class typeid. It is filled in the * constructor of \c SystemManager using SystemManager::load_system. */ - std::vector<SystemEntry> system_order; + std::vector<std::reference_wrapper<System>> system_order; /** * \brief Initialize a system * \tparam T System type (must be derivative of \c System) diff --git a/src/crepe/manager/SystemManager.hpp b/src/crepe/manager/SystemManager.hpp index a4c11e3..addd274 100644 --- a/src/crepe/manager/SystemManager.hpp +++ b/src/crepe/manager/SystemManager.hpp @@ -38,10 +38,7 @@ void SystemManager::load_system() { throw runtime_error(format("SystemManager: {} is already initialized", type.name())); System * system = new T(this->mediator); this->systems[type] = unique_ptr<System>(system); - this->system_order.push_back(SystemEntry{ - .system = *this->systems[type], - .name = type.name(), - }); + this->system_order.push_back(*this->systems[type]); } } // namespace crepe diff --git a/src/crepe/system/AnimatorSystem.cpp b/src/crepe/system/AnimatorSystem.cpp index 467d2a2..143d5d6 100644 --- a/src/crepe/system/AnimatorSystem.cpp +++ b/src/crepe/system/AnimatorSystem.cpp @@ -1,7 +1,8 @@ +#include <chrono> + #include "../api/Animator.h" #include "../manager/ComponentManager.h" #include "../manager/LoopTimerManager.h" -#include <chrono> #include "AnimatorSystem.h" @@ -13,30 +14,31 @@ void AnimatorSystem::frame_update() { LoopTimerManager & timer = this->mediator.loop_timer; RefVector<Animator> animations = mgr.get_components_by_type<Animator>(); - duration_t elapsed = timer.get_delta_time(); - - for (Animator & animator : animations) { - if (!animator.active) continue; + duration_t elapsed_time = timer.get_delta_time(); - Animator::Data & data = animator.data; - if (animator.data.fps == 0) continue; + for (Animator & a : animations) { + if (!a.active) continue; + if (a.data.fps == 0) continue; - if (animator.data.cycle_end == -1) - animator.data.cycle_end = animator.grid_size.x * animator.grid_size.y; + Animator::Data & ctx = a.data; - animator.elapsed += elapsed; - duration_t frame_duration = 1000ms / animator.data.fps; + a.elapsed_time += elapsed_time; + duration_t frame_duration = 1000ms / ctx.fps; - if (animator.elapsed > frame_duration) { - animator.elapsed = 0ms; - animator.data.frame++; - - if (animator.data.looping && animator.data.frame >= animator.data.cycle_end) - animator.data.frame = animator.data.cycle_start; + int cycle_end = (ctx.cycle_end == -1) ? a.grid_size.x : ctx.cycle_end; + if (a.elapsed_time >= frame_duration) { + a.elapsed_time = 0ms; + a.frame++; + if (a.frame == cycle_end) { + a.frame = ctx.cycle_start; + if (!ctx.looping) { + a.active = false; + continue; + } + } } - Sprite::Mask & mask = animator.spritesheet.mask; - mask.x = animator.data.frame % animator.grid_size.x * mask.w; - mask.y = animator.data.frame / animator.grid_size.x * mask.h; + ctx.row = ctx.cycle_start + a.frame; + a.spritesheet.mask.x = ctx.row * a.spritesheet.mask.w; } } diff --git a/src/crepe/system/AudioSystem.cpp b/src/crepe/system/AudioSystem.cpp index d4e8b9f..3c2232f 100644 --- a/src/crepe/system/AudioSystem.cpp +++ b/src/crepe/system/AudioSystem.cpp @@ -36,6 +36,8 @@ void AudioSystem::diff_update(AudioSource & component, Sound & resource) { if (component.oneshot_play) { component.voice = context.play(resource); + context.set_loop(component.voice, component.loop); + context.set_volume(component.voice, component.volume); component.oneshot_play = false; } if (component.oneshot_stop) { diff --git a/src/crepe/system/InputSystem.cpp b/src/crepe/system/InputSystem.cpp index b4a0633..be7eda6 100644 --- a/src/crepe/system/InputSystem.cpp +++ b/src/crepe/system/InputSystem.cpp @@ -1,8 +1,8 @@ #include "../api/Button.h" +#include "../api/Config.h" #include "../facade/SDLContext.h" #include "../manager/ComponentManager.h" #include "../manager/EventManager.h" -#include "util/Log.h" #include "InputSystem.h" @@ -213,10 +213,10 @@ bool InputSystem::is_mouse_inside_button( const Transform & cam_transform ) { vec2 actual_pos = transform.position + button.offset; - if (!button.world_space) { + if (!button.data.world_space) { actual_pos += cam_transform.position; } - vec2 half_dimensions = button.dimensions / 2; + vec2 half_dimensions = button.dimensions * transform.scale / 2; return mouse_pos.x >= actual_pos.x - half_dimensions.x && mouse_pos.x <= actual_pos.x + half_dimensions.x diff --git a/src/crepe/system/InputSystem.h b/src/crepe/system/InputSystem.h index 37311cc..be62367 100644 --- a/src/crepe/system/InputSystem.h +++ b/src/crepe/system/InputSystem.h @@ -1,12 +1,9 @@ #pragma once -#include "../api/Config.h" -#include "../facade/EventData.h" - #include "../api/Event.h" #include "../api/Metadata.h" +#include "../facade/EventData.h" #include "../types.h" -#include "../util/OptionalRef.h" #include "System.h" diff --git a/src/crepe/system/ScriptSystem.cpp b/src/crepe/system/ScriptSystem.cpp index 411a9a3..ed0c7cc 100644 --- a/src/crepe/system/ScriptSystem.cpp +++ b/src/crepe/system/ScriptSystem.cpp @@ -32,21 +32,10 @@ void ScriptSystem::update( if (script == nullptr) continue; if (!script->initialized) { - try { - script->init(); - script->initialized = true; - } catch (const exception & e) { - Log::logf(Log::Level::WARNING, "Disabled script \"{}\" due to exception in init function: {}", behavior_script.name, e.what()); - behavior_script.active = false; - } + script->init(); + script->initialized = true; } - try { - (*script.*update_function)(delta_time); - } catch (const exception & e) { - // TODO: discern between fixed/frame update - Log::logf(Log::Level::WARNING, "Disabled script \"{}\" due to exception in update function: {}", behavior_script.name, e.what()); - behavior_script.active = false; - } + (*script.*update_function)(delta_time); } } diff --git a/src/example/rendering_particle.cpp b/src/example/rendering_particle.cpp index 7942fce..e6b31a7 100644 --- a/src/example/rendering_particle.cpp +++ b/src/example/rendering_particle.cpp @@ -7,8 +7,8 @@ #include <crepe/api/Button.h> #include <crepe/api/Camera.h> #include <crepe/api/Color.h> +#include <crepe/api/Engine.h> #include <crepe/api/GameObject.h> -#include <crepe/api/LoopManager.hpp> #include <crepe/api/ParticleEmitter.h> #include <crepe/api/Rigidbody.h> #include <crepe/api/Sprite.h> @@ -27,7 +27,7 @@ public: Color color(255, 255, 255, 255); - Asset img {"asset/texture/square.png"}; + Asset img {"asset/spritesheet/pokemon_spritesheet.png"}; Sprite & test_sprite = game_object.add_component<Sprite>( img, @@ -36,24 +36,24 @@ public: .flip = Sprite::FlipSettings {false, false}, .sorting_in_layer = 2, .order_in_layer = 2, - .size = {1, 1}, + .size = {1, 0}, .angle_offset = 0, .position_offset = {0, 1}, .world_space = false, } ); - //auto & emitter = game_object.add_component<ParticleEmitter>(test_sprite, ParticleEmitter::Data{}); - Sprite & test_sprite1 = game_object.add_component<Sprite>( - img, - Sprite::Data { - .color = color, - .size = {1, 1}, - .position_offset = {0, -1}, - .world_space = false, + auto & anim = game_object.add_component<Animator>( + test_sprite, ivec2 {56, 56}, uvec2 {4, 4}, + Animator::Data { + .looping = 0, } ); + anim.set_anim(1); + anim.pause(); + anim.next_anim(); + auto & cam = game_object.add_component<Camera>( ivec2 {1280, 720}, vec2 {5, 5}, Camera::Data { @@ -61,22 +61,14 @@ public: .postion_offset = {1000, 1000}, } ); - - /* - game_object.add_component<Text>(vec2{1, 1}, vec2{0, -0.5}, "ComicSansMS", - Text::Data{.text_color = Color::RED}, "test TEST"); - - game_object.add_component<Text>(vec2{1, 1}, vec2{0, 0.5}, "ComicSansMS", - Text::Data{.text_color = Color::BLACK}, "TEST test"); - */ } string get_name() const { return "TestScene"; }; }; int main(int argc, char * argv[]) { - LoopManager engine; + Engine engine; engine.add_scene<TestScene>(); - engine.start(); + engine.main(); return 0; } diff --git a/src/test/AudioTest.cpp b/src/test/AudioTest.cpp index 3844c73..e548221 100644 --- a/src/test/AudioTest.cpp +++ b/src/test/AudioTest.cpp @@ -60,6 +60,8 @@ TEST_F(AudioTest, Play) { InSequence seq; EXPECT_CALL(context, play(_)).Times(0); + EXPECT_CALL(context, set_loop(_, _)).Times(0); + EXPECT_CALL(context, set_volume(_, _)).Times(0); component.play(); } @@ -67,6 +69,8 @@ TEST_F(AudioTest, Play) { InSequence seq; EXPECT_CALL(context, play(_)).Times(1); + EXPECT_CALL(context, set_loop(_, _)).Times(1); + EXPECT_CALL(context, set_volume(_, _)).Times(1); system.fixed_update(); } } @@ -146,6 +150,9 @@ TEST_F(AudioTest, PlayOnActive) { InSequence seq; EXPECT_CALL(context, play(_)).Times(1); + EXPECT_CALL(context, set_loop(_, _)).Times(1); + EXPECT_CALL(context, set_volume(_, _)).Times(1); + component.active = true; system.fixed_update(); } @@ -156,6 +163,8 @@ TEST_F(AudioTest, PlayImmediately) { component.play(); EXPECT_CALL(context, play(_)).Times(1); + EXPECT_CALL(context, set_volume(_, _)).Times(1); + EXPECT_CALL(context, set_loop(_, _)).Times(1); system.fixed_update(); } diff --git a/src/test/Vector2Test.cpp b/src/test/Vector2Test.cpp index 1e21af9..b17f95a 100644 --- a/src/test/Vector2Test.cpp +++ b/src/test/Vector2Test.cpp @@ -1,6 +1,7 @@ #include <gtest/gtest.h> #include <crepe/api/Vector2.h> +#include <crepe/types.h> using namespace crepe; @@ -530,3 +531,12 @@ TEST_F(Vector2Test, Perpendicular) { EXPECT_FLOAT_EQ(result4.x, -4.0f); EXPECT_FLOAT_EQ(result4.y, 3.0f); } + +TEST_F(Vector2Test, Rotate) { + vec2 foo {0, 1}; + + foo = foo.rotate(90); + const float GOOD_ENOUGH = 0.001; + EXPECT_NEAR(foo.x, 1, GOOD_ENOUGH); + EXPECT_NEAR(foo.y, 0, GOOD_ENOUGH); +} |