diff options
Diffstat (limited to 'game')
67 files changed, 1495 insertions, 244 deletions
diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index e1168eb..a94beca 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -3,7 +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) @@ -33,6 +33,9 @@ target_sources(main PUBLIC # 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 @@ -41,6 +44,8 @@ target_sources(main PUBLIC missile/MissilePool.cpp missile/MissileScript.cpp missile/MissileSubScene.cpp + missile/AlertSubScene.cpp + missile/AlertScript.cpp missile/SpawnEvent.cpp #scheduling @@ -52,11 +57,15 @@ target_sources(main PUBLIC 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 + QuitScript.cpp # player player/PlayerScript.cpp diff --git a/game/Config.h b/game/Config.h index 8fa41ba..d2b5fc4 100644 --- a/game/Config.h +++ b/game/Config.h @@ -1,16 +1,6 @@ #pragma once -#include "types.h" - -#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 @@ -36,7 +26,7 @@ static constexpr int COLL_LAY_ENEMY = 10; // Only for GameScene static constexpr int COLL_LAY_PLAYER_BULLET = 11; // Only for GameScene static constexpr float GAME_HEIGHT = 800; // In game units -static constexpr float HALLWAY_HEIGHT = 475; // In game units +static constexpr float HALLWAY_HEIGHT = 450; // 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 @@ -59,8 +49,12 @@ 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 int PLAYER_GRAVITY_SCALE = 60; // In game units +static constexpr float PLAYER_GRAVITY_SCALE = 2.2; // 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/GameScene.cpp b/game/GameScene.cpp index ea55f7b..7803c9d 100644 --- a/game/GameScene.cpp +++ b/game/GameScene.cpp @@ -1,6 +1,5 @@ #include "GameScene.h" #include "Config.h" -#include "MoveCameraManualyScript.h" #include "StartGameScript.h" #include "coins/CoinPoolSubScene.h" #include "coins/CoinSystemScript.h" diff --git a/game/PreviewScene.cpp b/game/PreviewScene.cpp index 6cd9e78..bc28192 100644 --- a/game/PreviewScene.cpp +++ b/game/PreviewScene.cpp @@ -1,7 +1,14 @@ #include "PreviewScene.h" #include "Config.h" -#include "background/BackgroundSubScene.h" +#include "background/AquariumSubScene.h" +#include "background/ForestSubScene.h" +#include "background/HallwaySubScene.h" +#include "background/StartSubScene.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" @@ -36,17 +43,32 @@ using namespace std; void PreviewScene::load_scene() { - BackgroundSubScene background(*this); + StartSubScene start; + HallwaySubScene hallway; + ForestSubScene forest; + AquariumSubScene aquarium; + + float begin_x = 400; + + begin_x = start.create(*this, begin_x); + + begin_x = hallway.create(*this, begin_x, 1, Color::YELLOW); + + begin_x = aquarium.create(*this, begin_x); + + begin_x = hallway.create(*this, begin_x, 2, Color::GREEN); 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, + .bg_color = Color::BLACK, } ); - 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 { @@ -71,29 +93,90 @@ void PreviewScene::load_scene() { .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); + 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}, + .collision_layer = 100, }); + world.add_component<BoxCollider>(vec2(100, INFINITY), vec2(VIEWPORT_X, VIEWPORT_Y)); + world.add_component<BoxCollider>(vec2(100, INFINITY), vec2(100, VIEWPORT_Y)); + PrevPlayerSubScene player(*this); NpcSubScene npc(*this); SmokeSubScene smoke(*this); MissilePool mpool(*this); - /* - - 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}); - } - */ + 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, + } + ); } string PreviewScene::get_name() const { return "preview scene"; } 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/StartGameScript.cpp b/game/StartGameScript.cpp index 48055af..6d47e65 100644 --- a/game/StartGameScript.cpp +++ b/game/StartGameScript.cpp @@ -64,7 +64,7 @@ void StartGameScript::fixed_update(crepe::duration_t dt) { // 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(PLAYER_SPEED * dt.count(), 0); + rb.data.linear_velocity = vec2(PLAYER_SPEED * 0.02, 0); BehaviorScript & player_script = this->get_components_by_name<BehaviorScript>("player").front(); player_script.active = true; diff --git a/game/background/StartSubScene.cpp b/game/background/StartSubScene.cpp index d68287b..ba80517 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, -500), .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, -400), .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/enemy/BattleScript.cpp b/game/enemy/BattleScript.cpp index 6d96ef6..798cbb9 100644 --- a/game/enemy/BattleScript.cpp +++ b/game/enemy/BattleScript.cpp @@ -1,5 +1,7 @@ #include "BattleScript.h" +#include "EnemyConfig.h" #include "EnemyScript.h" +#include "api/Transform.h" #include <crepe/api/AI.h> #include <crepe/api/BehaviorScript.h> #include <crepe/api/Metadata.h> @@ -18,11 +20,10 @@ void BattleScript::init() { 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"); + RefVector<AI> enemy_ai = this->get_components_by_tag<AI>("enemy"); - for (BehaviorScript & script : enemy_scripts) { - if (script.active) { + for (AI & ai : enemy_ai) { + if (ai.active) { enemies_alive = true; } } @@ -32,20 +33,29 @@ void BattleScript::fixed_update(duration_t dt) { } } 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->battle_active = e.battle; + this->spawn_enemies(e.num_enemies); + return false; +} +void BattleScript::spawn_enemies(int amount) { + RefVector<AI> enemy_ai = this->get_components_by_tag<AI>("enemy"); + std::uniform_real_distribution<float> dist(70, 150); + int spawned = 0; + for (int i = 0; i < ENEMY_POOL_MAX; i++) { + AI & ai = enemy_ai[i]; + Transform & enemy_transform + = this->get_components_by_id<Transform>(ai.game_object_id).front(); + if (ai.active == true || enemy_transform.position != ENEMY_POOL_LOCATION) continue; this->queue_event<SpawnEnemyEvent>( SpawnEnemyEvent { .speed = dist(engine), .column = i, }, - script.game_object_id + ai.game_object_id ); + spawned++; + if (spawned >= amount) { + return; + } } - return false; } diff --git a/game/enemy/BattleScript.h b/game/enemy/BattleScript.h index ddd0be1..57aa16c 100644 --- a/game/enemy/BattleScript.h +++ b/game/enemy/BattleScript.h @@ -9,6 +9,7 @@ struct BattleWonEvent : public crepe::Event {}; struct BattleStartEvent : public crepe::Event { public: int num_enemies = 0; + bool battle = false; }; class BattleScript : public crepe::Script { public: @@ -20,5 +21,6 @@ private: bool battle_active = false; std::random_device rd; std::default_random_engine engine; + void spawn_enemies(int amount); bool create_battle(const BattleStartEvent & e); }; diff --git a/game/enemy/EnemyBulletScript.cpp b/game/enemy/EnemyBulletScript.cpp index 65c0c23..d208a88 100644 --- a/game/enemy/EnemyBulletScript.cpp +++ b/game/enemy/EnemyBulletScript.cpp @@ -18,7 +18,7 @@ void EnemyBulletScript::fixed_update(crepe::duration_t dt) { 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(); + 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) { diff --git a/game/enemy/EnemyBulletSubScene.cpp b/game/enemy/EnemyBulletSubScene.cpp index ad2ca9d..bc31ba8 100644 --- a/game/enemy/EnemyBulletSubScene.cpp +++ b/game/enemy/EnemyBulletSubScene.cpp @@ -16,6 +16,7 @@ #include "EnemyBulletScript.h" #include "EnemyBulletSubScene.h" #include "EnemyScript.h" +#include "api/Color.h" using namespace crepe; using namespace std; int EnemyBulletSubScene::create(Scene & scn, int counter) { @@ -27,19 +28,19 @@ int EnemyBulletSubScene::create(Scene & scn, int counter) { Rigidbody & bullet_body = bullet.add_component<Rigidbody>(Rigidbody::Data { .gravity_scale = 0, .body_type = Rigidbody::BodyType::KINEMATIC, - - .linear_velocity = vec2 {-250, 0}, + .linear_velocity = vec2 {-300, 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)); + BoxCollider & bullet_collider = bullet.add_component<BoxCollider>(vec2(40, 10)); //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 { + .color = Color::BLUE, .flip = {true, false}, .sorting_in_layer = SORT_IN_LAY_OBSTACLES, .order_in_layer = 1, diff --git a/game/enemy/EnemyConfig.h b/game/enemy/EnemyConfig.h index f7b660a..f9fb469 100644 --- a/game/enemy/EnemyConfig.h +++ b/game/enemy/EnemyConfig.h @@ -5,3 +5,4 @@ // 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}; +static constexpr int ENEMY_POOL_MAX = 12; diff --git a/game/enemy/EnemyPool.cpp b/game/enemy/EnemyPool.cpp index a7179bf..135fc35 100644 --- a/game/enemy/EnemyPool.cpp +++ b/game/enemy/EnemyPool.cpp @@ -4,7 +4,7 @@ using namespace std; void EnemyPool::create_enemies(crepe::Scene & scn) { EnemySubScene enemy; int amount = 0; - while (amount < this->MAXIMUM_AMOUNT) { + while (amount < ENEMY_POOL_MAX) { amount = enemy.create(scn, amount); } } diff --git a/game/enemy/EnemyPool.h b/game/enemy/EnemyPool.h index f4d6765..cfd0b1c 100644 --- a/game/enemy/EnemyPool.h +++ b/game/enemy/EnemyPool.h @@ -1,11 +1,8 @@ #pragma once +#include "EnemyConfig.h" #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 index 5c03539..0822c29 100644 --- a/game/enemy/EnemyScript.cpp +++ b/game/enemy/EnemyScript.cpp @@ -1,13 +1,16 @@ #include "EnemyScript.h" #include "../Config.h" #include "../Random.h" -#include "EnemyConfig.h" +#include "../enemy/EnemyConfig.h" +#include "api/Color.h" +#include "api/Sprite.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/Sprite.h> #include <crepe/api/Transform.h> #include <crepe/types.h> #include <random> @@ -16,7 +19,7 @@ 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)); + this->shot_delay = std::chrono::duration<float>(1.5 + Random::f(2, 0)); } void EnemyScript::init() { Metadata & meta = this->get_component<Metadata>(); @@ -29,43 +32,78 @@ void EnemyScript::init() { }); }; void EnemyScript::fixed_update(duration_t dt) { - if (this->alive) { - return; + if (!spawned) return; + auto now = std::chrono::steady_clock::now(); + std::chrono::duration<float> elapsed_hit = now - last_hit; + //hit blink timer + if (elapsed_hit > blink_time) { + set_hit_blink(false); } Transform & transform = this->get_component<Transform>(); + if (!this->alive) { + 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 - 100; + if (transform.position.x < x_value) { + this->despawn_enemy(); + } + return; + } + 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 + Rigidbody & player_body = this->get_components_by_tag<Rigidbody>("player").front(); + // move path nodes for (vec2 & path_node : ai_component.path) { path_node.y += (direction_to_player_y > 0 ? 1 : -1) * adjustment_speed * dt.count(); + path_node.x += player_body.data.linear_velocity.x * 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); + this->shoot(transform.position); last_fired = now; - this->shot_delay = std::chrono::duration<float>(Random::f(4, 1)); + this->shot_delay = std::chrono::duration<float>(Random::f(3, 1.5)); } } + bool EnemyScript::spawn_enemy(const SpawnEnemyEvent & e) { + this->speed = e.speed; + this->alive = true; + this->spawned = true; + this->health = 2; + RefVector<Animator> animators = this->get_components<Animator>(); + for (Animator & anim : animators) { + anim.active = false; + anim.set_anim(0); + } + RefVector<Sprite> sprites = this->get_components<Sprite>(); + for (Sprite & sprite : sprites) { + sprite.data.position_offset.x = 0; + } + Sprite & jetpack = sprites[2]; + jetpack.data.position_offset.x = 20; + Sprite & gun = sprites[3]; + gun.data.position_offset.x = -20; 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(); - + Rigidbody & rb = this->get_component<Rigidbody>(); + rb.data.collision_layers = {COLL_LAY_BOT_TOP, COLL_LAY_PLAYER_BULLET}; + rb.data.collision_layer = COLL_LAY_ENEMY; vec2 half_screen = camera.viewport_size / 2; - float x_value = cam_transform.position.x + half_screen.x - 50 * (1 + e.column); + float x_value = cam_transform.position.x + half_screen.x - 40 * (1 + e.column); uniform_real_distribution<float> dist( cam_transform.position.y - half_screen.y + 100, cam_transform.position.y + half_screen.y - 100 @@ -75,31 +113,77 @@ bool EnemyScript::spawn_enemy(const SpawnEnemyEvent & e) { = {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.make_oval_path(10, 30, vec2 {x_value, random_height}, 1.5708, true); ai_component.active = true; this->last_fired = std::chrono::steady_clock::now(); + return false; } +void EnemyScript::set_hit_blink(bool status) { + RefVector<Sprite> sprites = this->get_components<Sprite>(); + for (Sprite & sprite : sprites) { + if (status) { + sprite.data.color = Color::RED; + continue; + } + sprite.data.color = Color::WHITE; + } +} + bool EnemyScript::on_collide(const CollisionEvent & e) { + if (!this->alive) return false; if (e.info.other.metadata.tag == "player_bullet") { - this->despawn_enemy(); + this->health--; + last_hit = std::chrono::steady_clock::now(); + //Sprite& sprite; + set_hit_blink(true); + if (health <= 0) { + this->death(); + } } - 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::death() { + + Rigidbody & rb = this->get_component<Rigidbody>(); + Transform & tr = this->get_component<Transform>(); + RefVector<Animator> animators = this->get_components<Animator>(); + for (Animator & anim : animators) { + anim.active = false; + anim.set_anim(3); + } + RefVector<Sprite> sprites = this->get_components<Sprite>(); + for (Sprite & sprite : sprites) { + sprite.data.position_offset.x = 15; + } + rb.data.linear_velocity_coefficient = {0.5, 1}; + rb.data.collision_layers = {COLL_LAY_BOT_TOP}; + rb.data.collision_layer = 0; + + rb.data.gravity_scale = 1; + tr.rotation = 90; + AI & ai = this->get_component<AI>(); + ai.active = false; + this->alive = false; + AI & ai_component = this->get_component<AI>(); + ai_component.active = false; +} void EnemyScript::despawn_enemy() { Transform & transform = this->get_component<Transform>(); + Rigidbody & rb = this->get_component<Rigidbody>(); + rb.data.gravity_scale = 0; + rb.data.linear_velocity = {0, 0}; + transform.rotation = 0; transform.position = ENEMY_POOL_LOCATION; - AI & ai_component = this->get_component<AI>(); - // Rigidbody& enemy_body - ai_component.active = false; + + this->spawned = false; } -void EnemyScript::shoot(const vec2 & location, float angle) { + +void EnemyScript::shoot(const vec2 & location) { RefVector<Transform> bullet_transforms = this->get_components_by_tag<Transform>("enemy_bullet"); diff --git a/game/enemy/EnemyScript.h b/game/enemy/EnemyScript.h index 42ecac4..be71a78 100644 --- a/game/enemy/EnemyScript.h +++ b/game/enemy/EnemyScript.h @@ -13,19 +13,25 @@ public: EnemyScript(); void init() override; void fixed_update(crepe::duration_t dt) override; - void shoot(const crepe::vec2 & position, float angle); + void shoot(const crepe::vec2 & position); bool on_collide(const crepe::CollisionEvent & collisionData); void despawn_enemy(); bool spawn_enemy(const SpawnEnemyEvent & e); + void death(); + void set_hit_blink(bool status); private: std::random_device rd; std::default_random_engine engine; bool alive = false; + bool spawned = false; float speed = 50; - const float MIN_SPEED = 10; - const float MAX_SPEED = 130; - const float MAX_DISTANCE = 100; + int health = 2; + const float MIN_SPEED = 20; + const float MAX_SPEED = 150; + const float MAX_DISTANCE = 200; std::chrono::time_point<std::chrono::steady_clock> last_fired; + std::chrono::time_point<std::chrono::steady_clock> last_hit; std::chrono::duration<float> shot_delay = std::chrono::duration<float>(0); + std::chrono::duration<float> blink_time = std::chrono::duration<float>(0.1); }; diff --git a/game/enemy/EnemySubScene.cpp b/game/enemy/EnemySubScene.cpp index 607b9a9..c6aecec 100644 --- a/game/enemy/EnemySubScene.cpp +++ b/game/enemy/EnemySubScene.cpp @@ -31,8 +31,9 @@ int EnemySubScene::create(Scene & scn, int enemy_counter) { .collision_layer = COLL_LAY_ENEMY, }); + // normal body Asset enemy_body_asset {"asset/workers/worker2Body.png"}; - enemy.add_component<BoxCollider>(vec2(50, 50)); + enemy.add_component<BoxCollider>(vec2(40, 60)); Sprite & enemy_body_sprite = enemy.add_component<Sprite>( enemy_body_asset, Sprite::Data { @@ -52,7 +53,7 @@ int EnemySubScene::create(Scene & scn, int enemy_counter) { } ); 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, @@ -71,7 +72,9 @@ int EnemySubScene::create(Scene & scn, int enemy_counter) { .looping = true, } ); - enemy.add_component<CircleCollider>(25, vec2(0, -20)); + + //jetpack + //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, @@ -91,11 +94,24 @@ int EnemySubScene::create(Scene & scn, int enemy_counter) { .looping = true, } ); + //gun + Asset enemy_pistol_asset {"asset/workers/gun.png"}; + Sprite & enemy_pistol_sprite = enemy.add_component<Sprite>( + enemy_pistol_asset, + Sprite::Data { + .flip = {false, false}, + .sorting_in_layer = SORT_IN_LAY_WORKERS_FRONT, + .order_in_layer = 2, + .size = vec2(0, 20), + .position_offset = vec2(-20, 0), + } + ); 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(); + ai_component.active = false; BehaviorScript & enemy_script = enemy.add_component<BehaviorScript>().set_script<EnemyScript>(); - enemy_script.active = false; + //enemy_script.active = false; return enemy_counter; } diff --git a/game/hud/HudScript.cpp b/game/hud/HudScript.cpp index 8f77706..e4aeae7 100644 --- a/game/hud/HudScript.cpp +++ b/game/hud/HudScript.cpp @@ -3,6 +3,8 @@ #include "../Config.h" #include "../Events.h" +#include "api/KeyCodes.h" +#include "menus/endgame/EndGameSubScript.h" #include <climits> @@ -36,7 +38,7 @@ void HudScript::init() { } bool HudScript::toggle_fps(crepe::KeyPressEvent ev) { - if (ev.key != Keycode::END) return false; + 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) { @@ -91,5 +93,6 @@ 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/main.cpp b/game/main.cpp index 14eec99..95cb35c 100644 --- a/game/main.cpp +++ b/game/main.cpp @@ -3,7 +3,7 @@ #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" @@ -17,6 +17,7 @@ int main() { Config::get_instance() = ENGINE_CONFIG; Engine gameloop; + gameloop.add_scene<MainMenuScene>(); gameloop.add_scene<ShopMenuScene>(); gameloop.add_scene<GameScene>(); diff --git a/game/menus/ButtonNextMainMenuSubScript.cpp b/game/menus/ButtonNextMainMenuSubScript.cpp index e03a34a..63a2777 100644 --- a/game/menus/ButtonNextMainMenuSubScript.cpp +++ b/game/menus/ButtonNextMainMenuSubScript.cpp @@ -1,4 +1,5 @@ #include "ButtonNextMainMenuSubScript.h" +#include "ButtonReplaySubScript.h" #include "MenusConfig.h" #include "ValueBroker.h" @@ -27,6 +28,7 @@ bool ButtonNextMainMenuSubScript::on_button_press(const ButtonPressEvent & e) { audio.stop(); } + this->trigger_event<DeleteRecordingEvent>(); SaveManager & savemgr = this->get_save_manager(); ValueBroker<int> coins = savemgr.get<int>(TOTAL_COINS_RUN, 0); diff --git a/game/menus/ButtonReplaySubScript.cpp b/game/menus/ButtonReplaySubScript.cpp index 9308350..01cccbf 100644 --- a/game/menus/ButtonReplaySubScript.cpp +++ b/game/menus/ButtonReplaySubScript.cpp @@ -1,4 +1,5 @@ #include "ButtonReplaySubScript.h" +#include "Config.h" #include "MenusConfig.h" #include "../Events.h" @@ -16,15 +17,27 @@ void ButtonReplaySubScript::init() { 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 index bfc684d..3eb8aa9 100644 --- a/game/menus/ButtonReplaySubScript.h +++ b/game/menus/ButtonReplaySubScript.h @@ -4,6 +4,8 @@ #include <crepe/api/Script.h> +struct DeleteRecordingEvent : public crepe::Event {}; + class ButtonReplaySubScript : public IButtonScript { public: void init() override; @@ -12,6 +14,7 @@ public: private: crepe::recording_t recording = 0; bool set_recording(); + bool delete_recording(); protected: bool transition = false; diff --git a/game/menus/ButtonSubScene.cpp b/game/menus/ButtonSubScene.cpp index 30646f1..1fe6b03 100644 --- a/game/menus/ButtonSubScene.cpp +++ b/game/menus/ButtonSubScene.cpp @@ -7,10 +7,16 @@ #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> @@ -72,6 +78,25 @@ void ButtonSubScene::set_script(crepe::GameObject & button_object, const Data & 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; @@ -196,8 +221,31 @@ void ButtonSubScene::next_btn_overlay(crepe::GameObject & button_object, const D 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>( - Asset("asset/ui/buttonSmallBlue.png"), + *selected, Sprite::Data { .sorting_in_layer = STARTING_SORTING_IN_LAYER + 2 + data.sorting_layer_offset, .size = SIDE_PANEL_SIZE, @@ -206,7 +254,7 @@ void ButtonSubScene::btn_color_side( } ); button_object.add_component<Sprite>( - Asset("asset/ui/buttonSmallBlue.png"), + *selected, Sprite::Data { .flip = {true, false}, .sorting_in_layer = STARTING_SORTING_IN_LAYER + 2 + data.sorting_layer_offset, diff --git a/game/menus/ButtonSubScene.h b/game/menus/ButtonSubScene.h index 74f9464..d4c7223 100644 --- a/game/menus/ButtonSubScene.h +++ b/game/menus/ButtonSubScene.h @@ -19,6 +19,11 @@ public: REPLAY, CREDITS_SHOW, CREDITS_BACK, + PREVIEW_START, + PREVIEW_STOP, + PREVIEW_REPLAY, + SHOP_BULLET, + SHOP_BUBBLE, NONE, }; //icon enum @@ -33,6 +38,14 @@ public: NEXT, LARGE, }; + + enum class ButtonSideColor { + BLUE, + ORANGE, + PURPLE, + YELLOW, + NONE, + }; //data struct struct Data { const std::string & text = "NODATA"; @@ -48,6 +61,7 @@ public: const bool color_side = true; const std::string & tag = ""; const int sorting_layer_offset = 0; + const ButtonSideColor btn_side_color = ButtonSideColor::NONE; }; public: diff --git a/game/menus/endgame/EndGameSubScene.cpp b/game/menus/endgame/EndGameSubScene.cpp index a6f8b25..b33072a 100644 --- a/game/menus/endgame/EndGameSubScene.cpp +++ b/game/menus/endgame/EndGameSubScene.cpp @@ -47,6 +47,51 @@ void EndGameSubScene::create(Scene & scn) { 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; diff --git a/game/menus/endgame/EndGameSubScript.cpp b/game/menus/endgame/EndGameSubScript.cpp index 6edfe7b..6793f3e 100644 --- a/game/menus/endgame/EndGameSubScript.cpp +++ b/game/menus/endgame/EndGameSubScript.cpp @@ -1,8 +1,11 @@ #include "EndGameSubScript.h" +#include "../../Config.h" #include "../../Events.h" #include "../ButtonReplaySubScript.h" #include "../IFloatingWindowScript.h" +#include "ValueBroker.h" +#include "manager/SaveManager.h" #include <string> @@ -21,6 +24,9 @@ void EndGameSubScript::init() { 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() { @@ -53,3 +59,43 @@ 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 index 62a2f0c..c25f6ca 100644 --- a/game/menus/endgame/EndGameSubScript.h +++ b/game/menus/endgame/EndGameSubScript.h @@ -5,6 +5,8 @@ #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); @@ -12,4 +14,5 @@ public: bool disable_all(); bool enable_all(); bool reset_timescale(); + bool showscore(); }; diff --git a/game/menus/mainmenu/MainMenuScene.cpp b/game/menus/mainmenu/MainMenuScene.cpp index fba90ac..c5d2030 100644 --- a/game/menus/mainmenu/MainMenuScene.cpp +++ b/game/menus/mainmenu/MainMenuScene.cpp @@ -2,6 +2,7 @@ #include "MainMenuScene.h" #include "CreditsSubScene.h" #include "MainMenuConfig.h" +#include "QuitScript.h" #include "TransitionStartSubScript.h" #include "../ButtonSubScene.h" @@ -29,10 +30,11 @@ void MainMenuScene::load_scene() { camera_object.add_component<Camera>( ivec2(990, 720), vec2(1100, 800), Camera::Data { - .bg_color = Color::RED, + .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); @@ -55,6 +57,7 @@ void MainMenuScene::load_scene() { .text_width = 200, .position = pos_btn, .script_type = ButtonSubScene::ScriptSelect::PREVIEW, + .btn_side_color = ButtonSubScene::ButtonSideColor::PURPLE, } ); @@ -70,6 +73,7 @@ void MainMenuScene::load_scene() { .icon_type = ButtonSubScene::IconSelect::SHOP, .position = pos_btn, .script_type = ButtonSubScene::ScriptSelect::SHOP, + .btn_side_color = ButtonSubScene::ButtonSideColor::ORANGE, } ); @@ -83,6 +87,7 @@ void MainMenuScene::load_scene() { .text_width = 200, .position = pos_btn, .script_type = ButtonSubScene::ScriptSelect::CREDITS_SHOW, + .btn_side_color = ButtonSubScene::ButtonSideColor::BLUE, } ); 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 index d1ea81d..4975a95 100644 --- a/game/menus/shop/ShopMenuScene.cpp +++ b/game/menus/shop/ShopMenuScene.cpp @@ -2,11 +2,14 @@ #include "ShopMenuScene.h" #include "../../Config.h" -#include "../BannerSubScene.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> @@ -40,6 +43,7 @@ void ShopMenuScene::load_scene() { .position_offset {0}, } ); + menu_background.add_component<BehaviorScript>().set_script<ShopLoadScript>(); ButtonSubScene button; button.create( @@ -50,26 +54,74 @@ void ShopMenuScene::load_scene() { .position = {-400, -350}, .script_type = ButtonSubScene::ScriptSelect::MAINMENU, .button_type = ButtonSubScene::ButtonSelect::BACK, - .scale = 0.8 + .scale = 0.8, + .sorting_layer_offset = 1, } ); + 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}, + .size = {0, 20}, + .angle_offset = 30, .position_offset = {0, 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, 20}, + .angle_offset = 10, + .position_offset = {-10, -30}, + } + ); + 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, 20}, + .angle_offset = -10, + .position_offset = {-40, 30}, + } + ); + 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, 20}, + .angle_offset = 0, + .position_offset = {10, 15}, + } + ); + 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, 20}, + .angle_offset = -5, + .position_offset = {45, -5}, + } + ); + + 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>( - vec2 {100, 50}, FONT, + size, FONT, Text::Data { .world_space = true, .text_color = Color::WHITE, }, - vec2 {0, -75}, "BULLETS" + vec2 {0, -75}, BULLETS_STRING ); shop_item_bullet.add_component<Sprite>( Asset("asset/ui/buttonCoinsSmall.png"), @@ -79,13 +131,18 @@ void ShopMenuScene::load_scene() { .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>( - vec2 {37.5, 37.5}, FONT, + size, FONT, Text::Data { .world_space = true, .text_color = Color::GOLD, }, - vec2 {-25, 75}, "0" + vec2 {-5, 75}, BULLETS_GOLD_STRING ); GameObject shop_item_bubble = this->new_object("bubble", "shop_item", vec2(100, 0)); @@ -93,17 +150,94 @@ void ShopMenuScene::load_scene() { Asset("asset/background/aquarium/bubble.png"), Sprite::Data { .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1, - .size = {0, 100}, + .size = {0, 10}, .position_offset = {0, 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, 10}, + .position_offset = {-50, -20}, + } + ); + shop_item_bubble.add_component<Sprite>( + Asset("asset/background/aquarium/bubble.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1, + .size = {0, 20}, + .position_offset = {45, -40}, + } + ); + shop_item_bubble.add_component<Sprite>( + Asset("asset/background/aquarium/bubble.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1, + .size = {0, 20}, + .position_offset = {-20, 40}, + } + ); + shop_item_bubble.add_component<Sprite>( + Asset("asset/background/aquarium/bubble.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1, + .size = {0, 15}, + .position_offset = {15, -25}, + } + ); + shop_item_bubble.add_component<Sprite>( + Asset("asset/background/aquarium/bubble.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1, + .size = {0, 10}, + .position_offset = {10, 5}, + } + ); + shop_item_bubble.add_component<Sprite>( + Asset("asset/background/aquarium/bubble.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1, + .size = {0, 10}, + .position_offset = {-5, -20}, + } + ); + shop_item_bubble.add_component<Sprite>( + Asset("asset/background/aquarium/bubble.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1, + .size = {0, 20}, + .position_offset = {15, -40}, + } + ); + shop_item_bubble.add_component<Sprite>( + Asset("asset/background/aquarium/bubble.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1, + .size = {0, 20}, + .position_offset = {-20, 10}, + } + ); + shop_item_bubble.add_component<Sprite>( + Asset("asset/background/aquarium/bubble.png"), + Sprite::Data { + .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1, + .size = {0, 15}, + .position_offset = {30, -25}, + } + ); + + 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>( - vec2 {100, 50}, FONT, + size, FONT, Text::Data { .world_space = true, .text_color = Color::WHITE, }, - vec2 {0, -75}, "BUBBLE" + vec2 {0, -75}, BUBBLE_STRING ); shop_item_bubble.add_component<Sprite>( Asset("asset/ui/buttonCoinsSmall.png"), @@ -113,13 +247,79 @@ void ShopMenuScene::load_scene() { .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>( - vec2 {100, 25}, FONT, + size, FONT, Text::Data { .world_space = true, .text_color = Color::GOLD, }, - vec2 {-25, 75}, "1000" + 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 + } ); } 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..0e6f5c5 --- /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 index e549210..23f03c9 100644 --- a/game/missile/MissilePool.cpp +++ b/game/missile/MissilePool.cpp @@ -1,5 +1,6 @@ #include "MissilePool.h" #include "MissileSubScene.h" +#include "missile/AlertSubScene.h" #include <crepe/api/Scene.h> @@ -10,6 +11,7 @@ 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/MissileScript.cpp b/game/missile/MissileScript.cpp index 6d0e40e..3aa4eb6 100644 --- a/game/missile/MissileScript.cpp +++ b/game/missile/MissileScript.cpp @@ -1,18 +1,19 @@ #include "MissileScript.h" #include "../Config.h" -#include "api/BehaviorScript.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> -#include <cmath> -#include <crepe/api/AI.h> -#include <crepe/api/KeyCodes.h> -#include <crepe/api/Sprite.h> - using namespace std; using namespace crepe; @@ -25,8 +26,8 @@ void MissileScript::init() { void MissileScript::kill_missile() { auto animations = this->get_components<Animator>(); auto sprites = this->get_components<Sprite>(); - auto & fly_sound = this->get_components<AudioSource>().front().get(); - auto & this_script = this->get_components<BehaviorScript>().back().get(); + auto collider = this->get_component<CircleCollider>(); + auto & this_script = this->get_components<BehaviorScript>().front().get(); animations[0].get().active = false; animations[1].get().active = false; @@ -35,23 +36,22 @@ void MissileScript::kill_missile() { 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(); sprites[0].get().active = true; sprites[1].get().active = true; sprites[2].get().active = false; -} + anim[0].get().active = true; + anim[1].get().active = true; + anim[2].get().stop(); +} bool MissileScript::on_collision(const CollisionEvent & ev) { auto & explosion_sound = this->get_components<AudioSource>().back().get(); @@ -74,15 +74,16 @@ void MissileScript::fixed_update(crepe::duration_t dt) { 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; + return; + } + + if (missile.position.x < (cam.position.x - VIEWPORT_X / 1.8)) { + this->kill_missile(); + return; } if (this->seeking_disabled) { diff --git a/game/missile/MissileSubScene.cpp b/game/missile/MissileSubScene.cpp index 6719c3d..d325050 100644 --- a/game/missile/MissileSubScene.cpp +++ b/game/missile/MissileSubScene.cpp @@ -1,6 +1,8 @@ #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> @@ -10,14 +12,10 @@ #include <crepe/api/Scene.h> #include <crepe/api/Sprite.h> #include <crepe/types.h> -#include <random> using namespace crepe; void MissileSubScene::create(crepe::Scene & scn) { - std::random_device rd; - std::mt19937 gen(rd()); - GameObject missle = scn.new_object("missile", "missile", {0, 0}, 0, 1); Asset missle_ss {"asset/obstacles/missile/missile.png"}; @@ -27,6 +25,7 @@ void MissileSubScene::create(crepe::Scene & scn) { 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; @@ -88,16 +87,15 @@ void MissileSubScene::create(crepe::Scene & scn) { missile_explosion_sprite.active = false; explosion_anim.active = false; - std::uniform_int_distribution<> dist(200, 250); missle.add_component<Rigidbody>(Rigidbody::Data { .body_type = Rigidbody::BodyType::KINEMATIC, - .max_linear_velocity = static_cast<float>(dist(gen)), + .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); + missle.add_component<CircleCollider>(3).active = false; auto & missle_ai = missle.add_component<AI>(1000); } diff --git a/game/missile/SpawnEvent.cpp b/game/missile/SpawnEvent.cpp index 03a9b8c..6109686 100644 --- a/game/missile/SpawnEvent.cpp +++ b/game/missile/SpawnEvent.cpp @@ -1,14 +1,15 @@ #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> -#include <random> using namespace crepe; @@ -18,28 +19,29 @@ void MissileSpawnEventHandler::init() { }); } -std::random_device rd; -std::mt19937 gen(rd()); - bool MissileSpawnEventHandler::on_event(const MissileSpawnEvent & event) { - auto missile_sprites = this->get_components_by_name<Sprite>("missile"); + auto alert_sprites = this->get_components_by_name<Sprite>("missile_alert"); + auto missile_transforms = this->get_components_by_name<Transform>("missile"); + 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].get(); + for (size_t i = 0; i < missile_transforms.size(); ++i) { + BehaviorScript & 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; - std::uniform_int_distribution<> dist(this->MIN_RANGE, this->MAX_RANGE); - transform.position.y = dist(gen); + transform.position.y = Random::i(this->MAX_RANGE, this->MIN_RANGE); + auto & alert_sprite = alert_sprites[i].get(); + alert_sprite.active = true; break; } diff --git a/game/missile/SpawnEvent.h b/game/missile/SpawnEvent.h index 58293d7..84b1987 100644 --- a/game/missile/SpawnEvent.h +++ b/game/missile/SpawnEvent.h @@ -10,9 +10,8 @@ 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; + static constexpr int MIN_RANGE = -150; + static constexpr int MAX_RANGE = 150; public: void init(); diff --git a/game/player/PlayerBulletScript.cpp b/game/player/PlayerBulletScript.cpp index a76b7eb..a823375 100644 --- a/game/player/PlayerBulletScript.cpp +++ b/game/player/PlayerBulletScript.cpp @@ -17,7 +17,7 @@ void PlayerBulletScript::fixed_update(crepe::duration_t dt) { 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; + 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; diff --git a/game/player/PlayerBulletSubScene.cpp b/game/player/PlayerBulletSubScene.cpp index 795747b..82ce4a9 100644 --- a/game/player/PlayerBulletSubScene.cpp +++ b/game/player/PlayerBulletSubScene.cpp @@ -24,8 +24,8 @@ int PlayerBulletSubScene::create(Scene & scn, int counter) { 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 = 10, + .linear_velocity = vec2 {450, 0}, + .angular_velocity = 300, .kinematic_collision = false, .collision_layers = {COLL_LAY_ENEMY, COLL_LAY_ZAPPER}, diff --git a/game/player/PlayerEndScript.cpp b/game/player/PlayerEndScript.cpp index 4ae813f..62fd350 100644 --- a/game/player/PlayerEndScript.cpp +++ b/game/player/PlayerEndScript.cpp @@ -92,8 +92,9 @@ bool PlayerEndScript::on_collision(const crepe::CollisionEvent & ev) { jump++; } - if (rb_player.data.linear_velocity.x < 5 && jump >= 3) { + if (rb_player.data.linear_velocity.x < 5 && jump == 3) { this->trigger_event<EndGameEvent>(); + jump++; } return false; diff --git a/game/player/PlayerScript.cpp b/game/player/PlayerScript.cpp index fadca9c..8cbe8dc 100644 --- a/game/player/PlayerScript.cpp +++ b/game/player/PlayerScript.cpp @@ -18,8 +18,42 @@ 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.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(); @@ -94,7 +128,7 @@ void PlayerScript::fixed_update(crepe::duration_t dt) { emitter.data.boundary.offset = vec2(0, -transform.position.y); } - Rigidbody & rb = this->get_components_by_name<Rigidbody>("player").front(); + Rigidbody & rb = this->body; if (this->get_key_state(Keycode::ENTER)) { auto now = std::chrono::steady_clock::now(); @@ -105,7 +139,10 @@ void PlayerScript::fixed_update(crepe::duration_t dt) { } } if (this->get_key_state(Keycode::SPACE)) { - rb.add_force_linear(vec2(0, -PLAYER_GRAVITY_SCALE / 2.5) * dt.count() / 0.02); + 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; @@ -126,8 +163,8 @@ void PlayerScript::fixed_update(crepe::duration_t dt) { if (current_jetpack_sound > 7) { current_jetpack_sound = 0; } - } else if (transform.position.y == 195) { - Rigidbody & rb = this->get_components_by_name<Rigidbody>("player").front(); + } else if (transform.position.y == 200) { + Rigidbody & rb = this->body; if (prev_anim != 0 && rb.data.linear_velocity.x != 0) { for (Animator & anim : animators) { anim.active = true; diff --git a/game/player/PlayerScript.h b/game/player/PlayerScript.h index e7d860a..6a7dedb 100644 --- a/game/player/PlayerScript.h +++ b/game/player/PlayerScript.h @@ -1,8 +1,11 @@ #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(); @@ -10,13 +13,20 @@ public: 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::time_point<std::chrono::steady_clock> last_switched; std::chrono::duration<float> shot_delay = std::chrono::duration<float>(0.5); - + std::chrono::duration<float> switch_delay = std::chrono::duration<float>(0.01); 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 index c4d689a..d0142e0 100644 --- a/game/player/PlayerSubScene.cpp +++ b/game/player/PlayerSubScene.cpp @@ -5,8 +5,8 @@ #include "../Config.h" #include "../coins/CoinScript.h" -#include "api/Asset.h" +#include <crepe/ValueBroker.h> #include <crepe/api/Animator.h> #include <crepe/api/AudioSource.h> #include <crepe/api/BoxCollider.h> @@ -16,6 +16,7 @@ #include <crepe/api/Scene.h> #include <crepe/api/Script.h> #include <crepe/api/Sprite.h> +#include <crepe/manager/SaveManager.h> #include <crepe/types.h> using namespace crepe; @@ -24,7 +25,23 @@ 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"}; + SaveManager & save = scn.get_save_manager(); + ValueBroker<int> particle_type = save.get<int>(JETPACK_PARTICLES, 0); + + string player_bullet_string; + string player_bullet_x2_string; + string player_shell_string; + if (particle_type.get() == 0) { + player_bullet_string = "asset/other_effects/effect_smgbullet.png"; + player_bullet_x2_string = "asset/other_effects/effect_smgbullet_x2.png"; + player_shell_string = "asset/other_effects/effect_rocketmgshell_TVOS.png"; + } else { + player_bullet_string = "asset/background/aquarium/bubble.png"; + player_bullet_x2_string = "asset/background/aquarium/bubble.png"; + player_shell_string = "asset/background/aquarium/bubble.png"; + } + + Asset player_bullet {player_bullet_string}; Sprite & player_bullet_sprite = player.add_component<Sprite>( player_bullet, Sprite::Data { @@ -45,7 +62,7 @@ PlayerSubScene::PlayerSubScene(Scene & scn) { .reset_on_exit = true, }, }); - Asset player_bullet_x2 {"asset/other_effects/effect_smgbullet_x2.png"}; + Asset player_bullet_x2 {player_bullet_x2_string}; Sprite & player_bullet_x2_sprite = player.add_component<Sprite>( player_bullet_x2, Sprite::Data { @@ -66,7 +83,7 @@ PlayerSubScene::PlayerSubScene(Scene & scn) { .reset_on_exit = true, }, }); - Asset player_shell {"asset/other_effects/effect_rocketmgshell_TVOS.png"}; + Asset player_shell {player_shell_string}; Sprite & player_shell_sprite = player.add_component<Sprite>( player_shell, Sprite::Data { @@ -106,7 +123,7 @@ PlayerSubScene::PlayerSubScene(Scene & scn) { .looping = true, } ); - player.add_component<BoxCollider>(vec2(50, 50)); + player.add_component<BoxCollider>(vec2(50, 35)); Asset player_head_asset {"asset/barry/defaultHead.png"}; Sprite & player_head_sprite = player.add_component<Sprite>( player_head_asset, @@ -143,9 +160,9 @@ PlayerSubScene::PlayerSubScene(Scene & scn) { .looping = true, } ); - player.add_component<BoxCollider>(vec2(40, 60), vec2(-20, 0)); + player.add_component<BoxCollider>(vec2(40, 50), vec2(-20, 0)); player.add_component<Rigidbody>(Rigidbody::Data { - .gravity_scale = PLAYER_GRAVITY_SCALE, + .gravity_scale = 1.0, .body_type = Rigidbody::BodyType::DYNAMIC, .linear_velocity = vec2(PLAYER_SPEED * 0.02, 0), .collision_layers @@ -153,6 +170,7 @@ PlayerSubScene::PlayerSubScene(Scene & scn) { }, .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; diff --git a/game/preview/NpcScript.cpp b/game/preview/NpcScript.cpp index c4148f2..86117d4 100644 --- a/game/preview/NpcScript.cpp +++ b/game/preview/NpcScript.cpp @@ -7,26 +7,23 @@ 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 npc = this->get_components<Sprite>(); auto & transform = this->get_component<Transform>(); - if (transform.position.x < -990) { + if (transform.position.x < 200) { rb.data.linear_velocity.x *= -1; } - if (transform.position.x > 990) { + if (transform.position.x > 700) { rb.data.linear_velocity.x *= -1; } if (rb.data.linear_velocity.x < 0) { - npc.data.flip = {true, false}; + npc.front().get().data.flip = {true, false}; + npc.back().get().data.flip = {true, false}; } else { - npc.data.flip = {false, false}; + npc.front().get().data.flip = {false, false}; + npc.back().get().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 index 8d856fd..d278f83 100644 --- a/game/preview/NpcScript.h +++ b/game/preview/NpcScript.h @@ -1,11 +1,8 @@ +#pragma once #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 index bd6cfb2..5ededb6 100644 --- a/game/preview/NpcSubScene.cpp +++ b/game/preview/NpcSubScene.cpp @@ -15,11 +15,7 @@ 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); + GameObject npc = scn.new_object("npc", "npc_tag", vec2 {500, 0}, 0, 1); Asset npc_body {"asset/workers/worker1Body.png"}; Asset npc_head {"asset/workers/worker1Head.png"}; @@ -53,7 +49,7 @@ NpcSubScene::NpcSubScene(Scene & scn) { .looping = true, } ); - npc.add_component<BoxCollider>(vec2 {50, 50}); + npc.add_component<BoxCollider>(vec2 {40, 50}); npc.add_component<Rigidbody>(Rigidbody::Data { .mass = 10, @@ -61,7 +57,7 @@ NpcSubScene::NpcSubScene(Scene & scn) { .body_type = Rigidbody::BodyType::DYNAMIC, .linear_velocity = {-50, 0}, //.max_linear_velocity = 40, - .collision_layers = {COLL_LAY_BOT_TOP, COLL_LAY_PLAYER}, + .collision_layers = {COLL_LAY_BOT_TOP, 100}, .collision_layer = COLL_LAY_PLAYER, }); diff --git a/game/preview/PrevPlayerScript.cpp b/game/preview/PrevPlayerScript.cpp index 2657b8d..ae25dad 100644 --- a/game/preview/PrevPlayerScript.cpp +++ b/game/preview/PrevPlayerScript.cpp @@ -1,12 +1,11 @@ #include "PrevPlayerScript.h" #include "../missile/SpawnEvent.h" -#include "api/Transform.h" + #include <crepe/api/AudioSource.h> #include <crepe/api/Camera.h> +#include <crepe/api/Transform.h> #include <crepe/manager/SaveManager.h> -#include <iostream> -#include <ostream> using namespace crepe; @@ -22,10 +21,6 @@ bool PrevPlayerScript::key_pressed(const KeyPressEvent & ev) { 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); @@ -59,25 +54,20 @@ bool PrevPlayerScript::key_pressed(const KeyPressEvent & ev) { this->head_anim->set_anim(7); break; case Keycode::LEFT: - this->head->data.angle_offset -= 1; + this->get_component<Transform>().rotation += 10; break; case Keycode::RIGHT: - this->head->data.angle_offset += 1; + this->get_component<Transform>().rotation -= 10; break; case Keycode::UP: - this->head->data.scale_offset += 0.1; + this->head->data.position_offset += 10; break; case Keycode::DOWN: - this->head->data.scale_offset -= 0.1; + this->head->data.position_offset -= 10; 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; + this->get_components_by_name<AudioSource>("background_music").front().get().active + = true; break; case Keycode::J: this->get_components_by_name<Transform>("camera").front().get().position.x @@ -98,11 +88,6 @@ bool PrevPlayerScript::key_pressed(const KeyPressEvent & ev) { case Keycode::M: trigger_event<MissileSpawnEvent>(MissileSpawnEvent {}); break; - //todo - case Keycode::PAGE_UP: - case Keycode::PAGE_DOWN: - case Keycode::HOME: - break; default: break; } @@ -110,6 +95,8 @@ bool PrevPlayerScript::key_pressed(const KeyPressEvent & ev) { } void PrevPlayerScript::init() { + this->rb = get_component<Rigidbody>(); + auto animations = this->get_components<Animator>(); body_anim = animations[0]; head_anim = animations[1]; @@ -121,12 +108,50 @@ void PrevPlayerScript::init() { subscribe<KeyPressEvent>([this](const KeyPressEvent & ev) -> bool { return this->key_pressed(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); + }); }; void PrevPlayerScript::fixed_update(crepe::duration_t dt) { + if (this->get_key_state(Keycode::SPACE)) { + this->rb->add_force_linear( + vec2(0, -1) * (engine_gravity * PLAYER_GRAVITY_SCALE * dt.count()) + ); + } + 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); }; + +bool PrevPlayerScript::on_key_down(const KeyPressEvent & ev) { + if (ev.key == Keycode::SPACE) { + const vec2 UP = {0, -1}; + this->help_kick(UP); + } + return false; +} + +bool PrevPlayerScript::on_key_up(const KeyReleaseEvent & ev) { + if (ev.key == Keycode::SPACE) { + const vec2 DOWN = {0, 1}; + this->help_kick(DOWN); + } + return false; +} + +void PrevPlayerScript::help_kick(const vec2 & direction) { + // softly "kick" the player (at start/end of flight) + vec2 & velocity = this->rb->data.linear_velocity; + float kick_amount = std::min( + velocity.length() * PLAYER_HELP_KICK_SCALE, engine_gravity * PLAYER_HELP_KICK_MAX + ); + velocity += direction * kick_amount; +} diff --git a/game/preview/PrevPlayerScript.h b/game/preview/PrevPlayerScript.h index cc3184e..ae66449 100644 --- a/game/preview/PrevPlayerScript.h +++ b/game/preview/PrevPlayerScript.h @@ -1,10 +1,10 @@ - +#include <crepe/api/Animator.h> +#include <crepe/api/Config.h> #include <crepe/api/Event.h> +#include <crepe/api/Rigidbody.h> #include <crepe/api/Script.h> -#include <crepe/util/OptionalRef.h> - -#include <crepe/api/Animator.h> #include <crepe/api/Sprite.h> +#include <crepe/util/OptionalRef.h> class PrevPlayerScript : public crepe::Script { private: @@ -20,4 +20,13 @@ private: void init(); void fixed_update(crepe::duration_t dt); bool key_pressed(const crepe::KeyPressEvent & ev); + +private: + bool on_key_down(const crepe::KeyPressEvent & ev); + bool on_key_up(const crepe::KeyReleaseEvent & ev); + void help_kick(const crepe::vec2 & direction); + +private: + float & engine_gravity = crepe::Config::get_instance().physics.gravity; + crepe::OptionalRef<crepe::Rigidbody> rb; }; diff --git a/game/preview/PrevPlayerSubScene.cpp b/game/preview/PrevPlayerSubScene.cpp index b59a0af..074cfb4 100644 --- a/game/preview/PrevPlayerSubScene.cpp +++ b/game/preview/PrevPlayerSubScene.cpp @@ -16,13 +16,8 @@ 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); + GameObject player = scn.new_object("player", "player", vec2 {800, -100}, 0, 1); Asset player_body_asset {"asset/barry/defaultBody.png"}; Sprite & player_body_sprite = player.add_component<Sprite>( player_body_asset, @@ -75,12 +70,18 @@ PrevPlayerSubScene::PrevPlayerSubScene(Scene & scn) { } ); player.add_component<Rigidbody>(Rigidbody::Data { - .gravity_scale = 20, + .gravity_scale = 1, .body_type = Rigidbody::BodyType::DYNAMIC, .linear_velocity = vec2(100, 0), - .collision_layers = {COLL_LAY_BOT_TOP}, + .collision_layers = {COLL_LAY_BOT_TOP, 100}, .collision_layer = COLL_LAY_PLAYER, }); - player.add_component<BoxCollider>(vec2(50, 50)); + player.add_component<BoxCollider>(vec2(40, 50)); player.add_component<BehaviorScript>().set_script<PrevPlayerScript>(); + + GameObject music = scn.new_object("background_music", "background_music"); + AudioSource & audio = music.add_component<AudioSource>(Asset {"asset/music/level.ogg"}); + audio.loop = true; + audio.play_on_awake = true; + audio.active = false; } 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/scheduler/ObjectsScheduler.cpp b/game/scheduler/ObjectsScheduler.cpp index 3ce2018..7f58c79 100644 --- a/game/scheduler/ObjectsScheduler.cpp +++ b/game/scheduler/ObjectsScheduler.cpp @@ -4,6 +4,7 @@ #include "../Config.h" #include "../Random.h" +#include "../enemy/EnemyScript.h" #include "../missile/SpawnEvent.h" #include "api/Rigidbody.h" #include "api/Transform.h" @@ -11,18 +12,52 @@ #include "prefab/ZapperPoolSubScene.h" using namespace crepe; + void ObjectsScheduler::preset_0() { + for (int i = 0; i < this->amount_of_boss_fights; i++) { + this->trigger_event<MissileSpawnEvent>(MissileSpawnEvent {}); + } + if (this->amount_of_boss_fights >= 1) { + this->trigger_event<BattleStartEvent>(BattleStartEvent { + .num_enemies = Random::i(this->amount_of_boss_fights, 0), + .battle = false, + }); + } +} + +void ObjectsScheduler::preset_1() { trigger_event<MissileSpawnEvent>(MissileSpawnEvent {}); - trigger_event<MissileSpawnEvent>(MissileSpawnEvent {}); + if (this->amount_of_boss_fights >= 3) { + this->trigger_event<BattleStartEvent>(BattleStartEvent { + .num_enemies = Random::i(1, 0), + .battle = false, + }); + } } -void ObjectsScheduler::preset_1() { trigger_event<MissileSpawnEvent>(MissileSpawnEvent {}); } -void ObjectsScheduler::preset_2() { trigger_event<CreateZapperEvent>(CreateZapperEvent {}); } + +void ObjectsScheduler::preset_2() { + trigger_event<CreateZapperEvent>(CreateZapperEvent {}); + if (this->amount_of_boss_fights >= 2) { + this->trigger_event<BattleStartEvent>(BattleStartEvent { + .num_enemies = Random::i(2, 1), + .battle = false, + }); + } +} + 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}); + + this->amount_of_boss_fights++; + this->trigger_event<BattleStartEvent>(BattleStartEvent { + .num_enemies = amount_of_boss_fights, + .battle = true, + }); RefVector<Rigidbody> rb_back_forest = this->get_components_by_tag<Rigidbody>("forest_background"); @@ -37,10 +72,18 @@ bool ObjectsScheduler::boss_fight_1_event() { 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"); - rb_back_forest.front().get().data.linear_velocity.x = 30; - rb_back_forest.back().get().data.linear_velocity.x = 40; + 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; } diff --git a/game/scheduler/ObjectsScheduler.h b/game/scheduler/ObjectsScheduler.h index bd0701b..7ada8e1 100644 --- a/game/scheduler/ObjectsScheduler.h +++ b/game/scheduler/ObjectsScheduler.h @@ -16,6 +16,8 @@ private: int obstacle_interval = 350; int start_offset = 1300; + int amount_of_boss_fights = 0; + private: void preset_0(); void preset_1(); |