aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--game/CMakeLists.txt63
-rw-r--r--game/Config.h21
-rw-r--r--game/EngineConfig.h19
-rw-r--r--game/GameScene.cpp35
-rw-r--r--game/PreviewScene.cpp99
-rw-r--r--game/PreviewScene.h11
-rw-r--r--game/StartGameScript.cpp1
-rw-r--r--game/enemy/BattleScript.cpp51
-rw-r--r--game/enemy/BattleScript.h24
-rw-r--r--game/enemy/EnemyBulletPool.cpp11
-rw-r--r--game/enemy/EnemyBulletPool.h11
-rw-r--r--game/enemy/EnemyBulletScript.cpp40
-rw-r--r--game/enemy/EnemyBulletScript.h11
-rw-r--r--game/enemy/EnemyBulletSubScene.cpp51
-rw-r--r--game/enemy/EnemyBulletSubScene.h10
-rw-r--r--game/enemy/EnemyConfig.h7
-rw-r--r--game/enemy/EnemyPool.cpp10
-rw-r--r--game/enemy/EnemyPool.h11
-rw-r--r--game/enemy/EnemyScript.cpp122
-rw-r--r--game/enemy/EnemyScript.h31
-rw-r--r--game/enemy/EnemySubScene.cpp101
-rw-r--r--game/enemy/EnemySubScene.h10
-rw-r--r--game/hud/HudSubScene.cpp2
-rw-r--r--game/hud/SpeedScript.cpp8
-rw-r--r--game/hud/SpeedScript.h2
-rw-r--r--game/main.cpp6
-rw-r--r--game/menus/ButtonReplaySubScript.cpp30
-rw-r--r--game/menus/ButtonReplaySubScript.h18
-rw-r--r--game/menus/ButtonShowCreditsSubScript.cpp20
-rw-r--r--game/menus/ButtonShowCreditsSubScript.h14
-rw-r--r--game/menus/ButtonSubScene.cpp14
-rw-r--r--game/menus/ButtonSubScene.h3
-rw-r--r--game/menus/MenusConfig.h2
-rw-r--r--game/menus/endgame/EndGameSubScene.cpp2
-rw-r--r--game/menus/endgame/EndGameSubScript.cpp1
-rw-r--r--game/menus/mainmenu/CreditsSubScene.cpp132
-rw-r--r--game/menus/mainmenu/CreditsSubScene.h9
-rw-r--r--game/menus/mainmenu/CreditsSubScript.cpp58
-rw-r--r--game/menus/mainmenu/CreditsSubScript.h18
-rw-r--r--game/menus/mainmenu/MainMenuScene.cpp19
-rw-r--r--game/menus/mainmenu/TransitionStartSubScript.cpp2
-rw-r--r--game/menus/shop/ShopMenuScene.cpp70
-rw-r--r--game/missile/MissilePool.cpp16
-rw-r--r--game/missile/MissilePool.h11
-rw-r--r--game/missile/MissileScript.cpp105
-rw-r--r--game/missile/MissileScript.h20
-rw-r--r--game/missile/MissileSubScene.cpp103
-rw-r--r--game/missile/MissileSubScene.h12
-rw-r--r--game/missile/SpawnEvent.cpp47
-rw-r--r--game/missile/SpawnEvent.h20
-rw-r--r--game/player/PlayerBulletPool.cpp11
-rw-r--r--game/player/PlayerBulletPool.h11
-rw-r--r--game/player/PlayerBulletScript.cpp41
-rw-r--r--game/player/PlayerBulletScript.h11
-rw-r--r--game/player/PlayerBulletSubScene.cpp52
-rw-r--r--game/player/PlayerBulletSubScene.h10
-rw-r--r--game/player/PlayerEndScript.cpp6
-rw-r--r--game/player/PlayerScript.cpp77
-rw-r--r--game/player/PlayerScript.h14
-rw-r--r--game/player/PlayerSubScene.cpp5
-rw-r--r--game/prefab/ZapperPoolSubScene.cpp1
-rw-r--r--game/preview/NpcScript.cpp32
-rw-r--r--game/preview/NpcScript.h11
-rw-r--r--game/preview/NpcSubScene.cpp69
-rw-r--r--game/preview/NpcSubScene.h10
-rw-r--r--game/preview/PrevPlayerScript.cpp132
-rw-r--r--game/preview/PrevPlayerScript.h23
-rw-r--r--game/preview/PrevPlayerSubScene.cpp86
-rw-r--r--game/preview/PrevPlayerSubScene.h10
-rw-r--r--game/preview/SmokeSubScene.cpp37
-rw-r--r--game/preview/SmokeSubScene.h10
-rw-r--r--game/scheduler/ObjectsScheduler.cpp77
-rw-r--r--game/scheduler/ObjectsScheduler.h32
-rw-r--r--game/workers/CollisionScript.cpp3
-rw-r--r--src/crepe/api/Color.cpp1
-rw-r--r--src/crepe/api/Color.h1
-rw-r--r--src/crepe/api/Text.cpp13
-rw-r--r--src/crepe/api/Text.h6
78 files changed, 2263 insertions, 43 deletions
diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt
index 4d02633..e1168eb 100644
--- a/game/CMakeLists.txt
+++ b/game/CMakeLists.txt
@@ -11,48 +11,99 @@ add_subdirectory(../src crepe)
add_executable(main)
target_sources(main PUBLIC
+ # enemy
+ enemy/BattleScript.cpp
+ enemy/EnemyPool.cpp
+ enemy/EnemyBulletScript.cpp
+ enemy/EnemyBulletSubScene.cpp
+ enemy/EnemyBulletPool.cpp
+ enemy/EnemySubScene.cpp
+ enemy/EnemyScript.cpp
+
+ #background
background/AquariumSubScene.cpp
background/AquariumScript.cpp
background/BackgroundSubScene.cpp
background/ForestParallaxScript.cpp
background/ForestSubScene.cpp
- GameScene.cpp
background/HallwaySubScene.cpp
+ background/StartSubScene.cpp
background/HallwayScript.cpp
+
+ # mainscenes
+ GameScene.cpp
+ menus/shop/ShopMenuScene.cpp
+ menus/mainmenu/MainMenuScene.cpp
+ PreviewScene.cpp
+ main.cpp
+
+ # missile
+ missile/MissilePool.cpp
+ missile/MissileScript.cpp
+ missile/MissileSubScene.cpp
+ missile/SpawnEvent.cpp
+
+ #scheduling
+ scheduler/ObjectsScheduler.cpp
+
+ # Preview
+ preview/SmokeSubScene.cpp
+ preview/NpcSubScene.cpp
+ preview/NpcScript.cpp
+ preview/PrevPlayerSubScene.cpp
+ preview/PrevPlayerScript.cpp
+
+ # scripts
+ GameScene.cpp
MoveCameraManualyScript.cpp
+ StartGameScript.cpp
+
+ # player
player/PlayerScript.cpp
player/PlayerSubScene.cpp
- StartGameScript.cpp
+ player/PlayerBulletPool.cpp
+ player/PlayerBulletScript.cpp
+ player/PlayerBulletSubScene.cpp
player/PlayerEndScript.cpp
player/PlayerAudioScript.cpp
- background/StartSubScene.cpp
+
+ # workers
workers/WorkersSubScene.cpp
workers/WorkerScript.cpp
workers/PanicFromPlayerScript.cpp
workers/CollisionScript.cpp
- main.cpp
+
+ # menus
menus/BannerSubScene.cpp
menus/ButtonSubScene.cpp
menus/IButtonScript.cpp
menus/ButtonSetShopSubScript.cpp
menus/ButtonSetMainMenuSubScript.cpp
+ menus/ButtonReplaySubScript.cpp
menus/ButtonNextMainMenuSubScript.cpp
menus/FloatingWindowSubScene.cpp
menus/IFloatingWindowScript.cpp
- menus/shop/ShopMenuScene.cpp
+ menus/ButtonShowCreditsSubScript.cpp
menus/mainmenu/ButtonTransitionPreviewSubScript.cpp
menus/mainmenu/ITransitionScript.cpp
- menus/mainmenu/MainMenuScene.cpp
menus/mainmenu/TransitionStartSubScript.cpp
+ menus/mainmenu/CreditsSubScene.cpp
+ menus/mainmenu/CreditsSubScript.cpp
menus/endgame/EndGameSubScene.cpp
menus/endgame/EndGameSubScript.cpp
+
+ # coins
coins/CoinSubScene.cpp
coins/CoinPoolSubScene.cpp
coins/CoinSystemScript.cpp
coins/CoinScript.cpp
+
+ # hud
hud/HudSubScene.cpp
hud/HudScript.cpp
hud/SpeedScript.cpp
+
+ #random
Random.cpp
)
diff --git a/game/Config.h b/game/Config.h
index 580e9ec..c6bbfda 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
@@ -31,6 +21,9 @@ static constexpr int COLL_LAY_WALL_FRAGS = 5; // Only for GameScene
static constexpr int COLL_LAY_ZAPPER = 6; // Only for GameScene
static constexpr int COLL_LAY_LASER = 7; // Only for GameScene
static constexpr int COLL_LAY_MISSILE = 8; // Only for GameScene
+static constexpr int COLL_LAY_BULLET = 9; // Only for GameScene
+static constexpr int COLL_LAY_ENEMY = 10; // Only for GameScene
+static constexpr int COLL_LAY_PLAYER_BULLET = 11; // Only for GameScene
static constexpr float GAME_HEIGHT = 800; // In game units
static constexpr float HALLWAY_HEIGHT = 475; // In game units
@@ -56,6 +49,10 @@ 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 = 3; // factor
+static constexpr float PLAYER_HELP_KICK_SCALE = 0.2; // factor
+static constexpr float PLAYER_HELP_KICK_MAX = 0.3; // factor
static constexpr const char * CAMERA_NAME = "camera";
+// Jetpack particles
+static constexpr const char * JETPACK_PARTICLES = "jetpack_particles";
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 9de2fd1..ea55f7b 100644
--- a/game/GameScene.cpp
+++ b/game/GameScene.cpp
@@ -6,15 +6,26 @@
#include "coins/CoinSystemScript.h"
#include "background/BackgroundSubScene.h"
+#include "enemy/BattleScript.h"
+#include "enemy/EnemyBulletPool.h"
+#include "enemy/EnemyBulletSubScene.h"
+#include "enemy/EnemyPool.h"
+#include "enemy/EnemySubScene.h"
#include "hud/HudScript.h"
#include "hud/HudSubScene.h"
#include "hud/SpeedScript.h"
#include "menus/endgame/EndGameSubScene.h"
+#include "missile/MissilePool.h"
+#include "missile/SpawnEvent.h"
+#include "player/PlayerBulletPool.h"
+#include "player/PlayerBulletSubScene.h"
#include "player/PlayerSubScene.h"
#include "prefab/ZapperPoolSubScene.h"
+#include "scheduler/ObjectsScheduler.h"
#include "workers/WorkersSubScene.h"
#include <cmath>
+#include <crepe/api/AI.h>
#include <crepe/api/Animator.h>
#include <crepe/api/Asset.h>
#include <crepe/api/AudioSource.h>
@@ -35,8 +46,6 @@ using namespace crepe;
using namespace std;
void GameScene::load_scene() {
- logf(Log::DEBUG, "Loading (main) GameScene...");
-
BackgroundSubScene background(*this);
GameObject camera = new_object(CAMERA_NAME, "camera", vec2(650, 0));
@@ -46,15 +55,24 @@ void GameScene::load_scene() {
.bg_color = Color::BLACK,
}
);
- camera.add_component<BehaviorScript>().set_script<MoveCameraManualyScript>();
+ //camera.add_component<BehaviorScript>().set_script<MoveCameraManualyScript>();
camera.add_component<BehaviorScript>().set_script<CoinSystemScript>();
camera.add_component<BehaviorScript>().set_script<HudScript>();
camera.add_component<BehaviorScript>().set_script<SpeedScript>();
+ camera.add_component<BehaviorScript>().set_script<BattleScript>();
+ camera.add_component<BehaviorScript>().set_script<MissileSpawnEventHandler>();
+ camera.add_component<BehaviorScript>().set_script<ObjectsScheduler>();
camera.add_component<Rigidbody>(Rigidbody::Data {});
-
+ AI & enemy_path_1 = camera.add_component<AI>(400);
+ enemy_path_1.make_oval_path(100, 100, camera.transform.position, 1.5708, true);
+ AI & enemy_path_2 = camera.add_component<AI>(400);
+ enemy_path_2.make_oval_path(100, 100, {0, 0}, 1.5708, true);
+ AI & enemy_path_3 = camera.add_component<AI>(400);
+ enemy_path_3.make_oval_path(100, 100, {0, 0}, 1.5708, true);
+ // camer.add_component<AI>
PlayerSubScene player(*this);
-
+ MissilePool missile_pool(*this);
WorkersSubScene workers(*this);
GameObject floor = new_object("floor", "game_world", vec2(0, 325));
@@ -89,7 +107,12 @@ void GameScene::load_scene() {
//create coin pool
CoinPoolSubScene coin_system;
coin_system.create_coins(*this);
-
+ EnemyBulletPool enemy_bullet_pool;
+ enemy_bullet_pool.create_bullets(*this);
+ PlayerBulletPool player_bullet_pool;
+ player_bullet_pool.create_bullets(*this);
+ EnemyPool enemy_pool;
+ enemy_pool.create_enemies(*this);
HudSubScene hud;
hud.create(*this);
diff --git a/game/PreviewScene.cpp b/game/PreviewScene.cpp
new file mode 100644
index 0000000..6cd9e78
--- /dev/null
+++ b/game/PreviewScene.cpp
@@ -0,0 +1,99 @@
+#include "PreviewScene.h"
+
+#include "Config.h"
+#include "background/BackgroundSubScene.h"
+#include "missile/MissilePool.h"
+#include "missile/SpawnEvent.h"
+#include "preview/NpcSubScene.h"
+#include "preview/PrevPlayerSubScene.h"
+#include "preview/SmokeSubScene.h"
+
+#include "missile/MissileSubScene.h"
+
+#include <cmath>
+#include <crepe/api/Animator.h>
+#include <crepe/api/Asset.h>
+#include <crepe/api/AudioSource.h>
+#include <crepe/api/BehaviorScript.h>
+#include <crepe/api/BoxCollider.h>
+#include <crepe/api/Camera.h>
+#include <crepe/api/Color.h>
+#include <crepe/api/Event.h>
+#include <crepe/api/GameObject.h>
+#include <crepe/api/ParticleEmitter.h>
+#include <crepe/api/Rigidbody.h>
+#include <crepe/api/Script.h>
+#include <crepe/api/Sprite.h>
+#include <crepe/api/Transform.h>
+
+#include <crepe/ValueBroker.h>
+#include <crepe/manager/SaveManager.h>
+#include <crepe/types.h>
+#include <iostream>
+
+using namespace crepe;
+using namespace std;
+
+void PreviewScene::load_scene() {
+
+ BackgroundSubScene background(*this);
+
+ GameObject camera = new_object("camera", "camera", vec2(650, 0));
+ camera.add_component<Camera>(
+ ivec2(990, 720), vec2(VIEWPORT_X, VIEWPORT_Y),
+ Camera::Data {
+ .bg_color = Color::RED,
+ }
+ );
+ camera.add_component<Rigidbody>(Rigidbody::Data {});
+ camera.add_component<BehaviorScript>().set_script<MissileSpawnEventHandler>();
+
+ GameObject floor = new_object("floor", "game_world", vec2(0, 325));
+ floor.add_component<Rigidbody>(Rigidbody::Data {
+ .body_type = Rigidbody::BodyType::STATIC,
+ .collision_layer = COLL_LAY_BOT_TOP,
+ });
+ floor.add_component<BoxCollider>(vec2(INFINITY, 200));
+ GameObject floor_low = new_object("floor_low", "game_world", vec2(0, 350));
+ floor_low.add_component<Rigidbody>(Rigidbody::Data {
+ .body_type = Rigidbody::BodyType::STATIC,
+ .collision_layer = COLL_LAY_BOT_LOW,
+ });
+ floor_low.add_component<BoxCollider>(vec2(INFINITY, 200));
+ GameObject floor_high = new_object("floor_high", "game_world", vec2(0, 300));
+ floor_high.add_component<Rigidbody>(Rigidbody::Data {
+ .body_type = Rigidbody::BodyType::STATIC,
+ .collision_layer = COLL_LAY_BOT_HIGH,
+ });
+ GameObject ceiling = new_object("ceiling", "game_world", vec2(0, -325));
+ ceiling.add_component<Rigidbody>(Rigidbody::Data {
+ .body_type = Rigidbody::BodyType::STATIC,
+ .collision_layer = COLL_LAY_BOT_TOP,
+ });
+ ceiling.add_component<BoxCollider>(vec2(INFINITY, 200));
+ GameObject world = this->new_object("world", "TAG", vec2 {0, 0}, 0, 1);
+
+ world.add_component<Rigidbody>(Rigidbody::Data {
+ .body_type = Rigidbody::BodyType::STATIC,
+ .collision_layers = {0},
+ });
+
+ PrevPlayerSubScene player(*this);
+ NpcSubScene npc(*this);
+ SmokeSubScene smoke(*this);
+ MissilePool mpool(*this);
+
+ /*
+
+ for (int i = 0; i < 200; ++i) {
+ int row = i / 10;
+ int col = i % 10;
+ float x = col * 25 + i;
+ float y = row * 25 - 400;
+ GameObject game_coin = this->new_object("coin", "coin", vec2 {x, y}, 0, 1);
+ Coin coin(game_coin, vec2 {0, 0});
+ }
+ */
+}
+
+string PreviewScene::get_name() const { return "preview scene"; }
diff --git a/game/PreviewScene.h b/game/PreviewScene.h
new file mode 100644
index 0000000..afe911e
--- /dev/null
+++ b/game/PreviewScene.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <crepe/api/Scene.h>
+#include <string>
+
+class PreviewScene : public crepe::Scene {
+public:
+ void load_scene();
+
+ std::string get_name() const;
+};
diff --git a/game/StartGameScript.cpp b/game/StartGameScript.cpp
index e88b329..48055af 100644
--- a/game/StartGameScript.cpp
+++ b/game/StartGameScript.cpp
@@ -12,7 +12,6 @@ using namespace std;
void StartGameScript::fixed_update(crepe::duration_t dt) {
Transform & player_transform = this->get_components_by_name<Transform>("player").front();
-
// Create hole in wall and activate panic lamp
if (player_transform.position.x > 75 && !this->created_hole) {
Sprite & lamp_sprite = this->get_components_by_name<Sprite>("start_end").back();
diff --git a/game/enemy/BattleScript.cpp b/game/enemy/BattleScript.cpp
new file mode 100644
index 0000000..6d96ef6
--- /dev/null
+++ b/game/enemy/BattleScript.cpp
@@ -0,0 +1,51 @@
+#include "BattleScript.h"
+#include "EnemyScript.h"
+#include <crepe/api/AI.h>
+#include <crepe/api/BehaviorScript.h>
+#include <crepe/api/Metadata.h>
+using namespace std;
+using namespace crepe;
+
+BattleScript::BattleScript() { engine.seed(rd()); }
+void BattleScript::init() {
+ std::uniform_int_distribution<int> dist(2, 10);
+ int random_enemy_amount = dist(this->engine);
+ // this->create_battle(random_enemy_amount);
+ this->subscribe<BattleStartEvent>([this](const BattleStartEvent & e) -> bool {
+ return this->create_battle(e);
+ });
+}
+void BattleScript::fixed_update(duration_t dt) {
+ if (!battle_active) return;
+ bool enemies_alive = false;
+ RefVector<BehaviorScript> enemy_scripts
+ = this->get_components_by_tag<BehaviorScript>("enemy");
+
+ for (BehaviorScript & script : enemy_scripts) {
+ if (script.active) {
+ enemies_alive = true;
+ }
+ }
+ if (!enemies_alive) {
+ this->battle_active = false;
+ this->trigger_event<BattleWonEvent>();
+ }
+}
+bool BattleScript::create_battle(const BattleStartEvent & e) {
+ this->battle_active = true;
+ RefVector<BehaviorScript> enemy_scripts
+ = this->get_components_by_tag<BehaviorScript>("enemy");
+ std::uniform_real_distribution<float> dist(10, 30);
+ for (int i = 0; i < e.num_enemies; i++) {
+ BehaviorScript & script = enemy_scripts[i];
+ script.active = true;
+ this->queue_event<SpawnEnemyEvent>(
+ SpawnEnemyEvent {
+ .speed = dist(engine),
+ .column = i,
+ },
+ script.game_object_id
+ );
+ }
+ return false;
+}
diff --git a/game/enemy/BattleScript.h b/game/enemy/BattleScript.h
new file mode 100644
index 0000000..ddd0be1
--- /dev/null
+++ b/game/enemy/BattleScript.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <crepe/api/BehaviorScript.h>
+#include <crepe/api/Event.h>
+#include <crepe/api/Script.h>
+#include <random>
+struct BattleWonEvent : public crepe::Event {};
+
+struct BattleStartEvent : public crepe::Event {
+public:
+ int num_enemies = 0;
+};
+class BattleScript : public crepe::Script {
+public:
+ BattleScript();
+ void init() override;
+ void fixed_update(crepe::duration_t dt) override;
+
+private:
+ bool battle_active = false;
+ std::random_device rd;
+ std::default_random_engine engine;
+ bool create_battle(const BattleStartEvent & e);
+};
diff --git a/game/enemy/EnemyBulletPool.cpp b/game/enemy/EnemyBulletPool.cpp
new file mode 100644
index 0000000..3ee4816
--- /dev/null
+++ b/game/enemy/EnemyBulletPool.cpp
@@ -0,0 +1,11 @@
+#include "EnemyBulletPool.h"
+#include "EnemyBulletSubScene.h"
+using namespace std;
+
+void EnemyBulletPool::create_bullets(crepe::Scene & scn) {
+ EnemyBulletSubScene bullet;
+ int amount = 0;
+ while (amount < this->MAXIMUM_AMOUNT) {
+ amount = bullet.create(scn, amount);
+ }
+}
diff --git a/game/enemy/EnemyBulletPool.h b/game/enemy/EnemyBulletPool.h
new file mode 100644
index 0000000..ee53fc4
--- /dev/null
+++ b/game/enemy/EnemyBulletPool.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <crepe/api/Scene.h>
+
+class EnemyBulletPool {
+public:
+ void create_bullets(crepe::Scene & scn);
+
+private:
+ static constexpr int MAXIMUM_AMOUNT = 20;
+};
diff --git a/game/enemy/EnemyBulletScript.cpp b/game/enemy/EnemyBulletScript.cpp
new file mode 100644
index 0000000..65c0c23
--- /dev/null
+++ b/game/enemy/EnemyBulletScript.cpp
@@ -0,0 +1,40 @@
+#include "EnemyBulletScript.h"
+#include <crepe/api/Camera.h>
+#include <crepe/api/Metadata.h>
+#include <crepe/api/Rigidbody.h>
+#include <iostream>
+
+#include "EnemyConfig.h"
+using namespace crepe;
+using namespace std;
+void EnemyBulletScript::init() {
+ this->subscribe<CollisionEvent>([this](const CollisionEvent & e) -> bool {
+ return this->on_collide(e);
+ });
+}
+void EnemyBulletScript::fixed_update(crepe::duration_t dt) {
+ Transform & transform = this->get_component<Transform>();
+ Camera & camera = this->get_components_by_name<Camera>("camera").front();
+ Transform & cam_transform = this->get_components_by_name<Transform>("camera").front();
+ Rigidbody & bullet_body = this->get_component<Rigidbody>();
+ //move
+ transform.position.x += bullet_body.data.linear_velocity.x * dt.count();
+ vec2 half_screen = camera.viewport_size / 2;
+ float despawn_location = cam_transform.position.x - half_screen.x - 50;
+ if (transform.position.x < despawn_location) {
+ this->despawn_bullet();
+ }
+}
+
+void EnemyBulletScript::despawn_bullet() {
+ Transform & transform = this->get_component<Transform>();
+ Rigidbody & bullet_body = this->get_component<Rigidbody>();
+ bullet_body.active = false;
+ transform.position = ENEMY_BULLET_POOL_LOCATION;
+}
+
+bool EnemyBulletScript::on_collide(const CollisionEvent & e) {
+ //cout << "collision happened with " << e.info.other.metadata.tag << endl;
+ this->despawn_bullet();
+ return false;
+}
diff --git a/game/enemy/EnemyBulletScript.h b/game/enemy/EnemyBulletScript.h
new file mode 100644
index 0000000..7dab751
--- /dev/null
+++ b/game/enemy/EnemyBulletScript.h
@@ -0,0 +1,11 @@
+#pragma once
+#include <crepe/api/BehaviorScript.h>
+#include <crepe/api/Script.h>
+
+class EnemyBulletScript : public crepe::Script {
+public:
+ void init() override;
+ void fixed_update(crepe::duration_t dt) override;
+ bool on_collide(const crepe::CollisionEvent & e);
+ void despawn_bullet();
+};
diff --git a/game/enemy/EnemyBulletSubScene.cpp b/game/enemy/EnemyBulletSubScene.cpp
new file mode 100644
index 0000000..ad2ca9d
--- /dev/null
+++ b/game/enemy/EnemyBulletSubScene.cpp
@@ -0,0 +1,51 @@
+#include <string>
+
+#include "../Config.h"
+#include "EnemyConfig.h"
+#include <crepe/api/AI.h>
+#include <crepe/api/Animator.h>
+#include <crepe/api/BehaviorScript.h>
+#include <crepe/api/BoxCollider.h>
+#include <crepe/api/CircleCollider.h>
+#include <crepe/api/GameObject.h>
+#include <crepe/api/Rigidbody.h>
+#include <crepe/api/Scene.h>
+#include <crepe/api/Sprite.h>
+
+#include "../Random.h"
+#include "EnemyBulletScript.h"
+#include "EnemyBulletSubScene.h"
+#include "EnemyScript.h"
+using namespace crepe;
+using namespace std;
+int EnemyBulletSubScene::create(Scene & scn, int counter) {
+ string unique_name = "enemy_bullet_" + to_string(counter++);
+ GameObject bullet = scn.new_object(
+ unique_name.c_str(), "enemy_bullet", ENEMY_BULLET_POOL_LOCATION, 0, 1
+ );
+
+ Rigidbody & bullet_body = bullet.add_component<Rigidbody>(Rigidbody::Data {
+ .gravity_scale = 0,
+ .body_type = Rigidbody::BodyType::KINEMATIC,
+
+ .linear_velocity = vec2 {-250, 0},
+ .kinematic_collision = false,
+ .collision_layers = {COLL_LAY_MISSILE, COLL_LAY_ZAPPER},
+ .collision_layer = COLL_LAY_BULLET
+ });
+ bullet_body.active = false;
+ BoxCollider & bullet_collider = bullet.add_component<BoxCollider>(vec2(60, 30));
+ //bullet_collider.active = false;
+ Asset bullet_asset {"asset/other_effects/effect_smgbullet_x2.png"};
+ Sprite & bullet_sprite = bullet.add_component<Sprite>(
+ bullet_asset,
+ Sprite::Data {
+ .flip = {true, false},
+ .sorting_in_layer = SORT_IN_LAY_OBSTACLES,
+ .order_in_layer = 1,
+ .size = vec2(60, 0),
+ }
+ );
+ bullet.add_component<BehaviorScript>().set_script<EnemyBulletScript>();
+ return counter;
+}
diff --git a/game/enemy/EnemyBulletSubScene.h b/game/enemy/EnemyBulletSubScene.h
new file mode 100644
index 0000000..ac78ad9
--- /dev/null
+++ b/game/enemy/EnemyBulletSubScene.h
@@ -0,0 +1,10 @@
+#pragma once
+
+namespace crepe {
+class Scene;
+}
+
+class EnemyBulletSubScene {
+public:
+ int create(crepe::Scene & scn, int counter);
+};
diff --git a/game/enemy/EnemyConfig.h b/game/enemy/EnemyConfig.h
new file mode 100644
index 0000000..f7b660a
--- /dev/null
+++ b/game/enemy/EnemyConfig.h
@@ -0,0 +1,7 @@
+#pragma once
+#include <crepe/types.h>
+
+//button config
+// static constexpr crepe::vec2 PLAYER_BULLET_POOL_LOCATION = {0, -850};
+static constexpr crepe::vec2 ENEMY_BULLET_POOL_LOCATION = {0, -750};
+static constexpr crepe::vec2 ENEMY_POOL_LOCATION = {0, -650};
diff --git a/game/enemy/EnemyPool.cpp b/game/enemy/EnemyPool.cpp
new file mode 100644
index 0000000..a7179bf
--- /dev/null
+++ b/game/enemy/EnemyPool.cpp
@@ -0,0 +1,10 @@
+#include "EnemyPool.h"
+#include "EnemySubScene.h"
+using namespace std;
+void EnemyPool::create_enemies(crepe::Scene & scn) {
+ EnemySubScene enemy;
+ int amount = 0;
+ while (amount < this->MAXIMUM_AMOUNT) {
+ amount = enemy.create(scn, amount);
+ }
+}
diff --git a/game/enemy/EnemyPool.h b/game/enemy/EnemyPool.h
new file mode 100644
index 0000000..f4d6765
--- /dev/null
+++ b/game/enemy/EnemyPool.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <crepe/api/Scene.h>
+
+class EnemyPool {
+public:
+ void create_enemies(crepe::Scene & scn);
+
+private:
+ static constexpr int MAXIMUM_AMOUNT = 10;
+};
diff --git a/game/enemy/EnemyScript.cpp b/game/enemy/EnemyScript.cpp
new file mode 100644
index 0000000..5c03539
--- /dev/null
+++ b/game/enemy/EnemyScript.cpp
@@ -0,0 +1,122 @@
+#include "EnemyScript.h"
+#include "../Config.h"
+#include "../Random.h"
+#include "EnemyConfig.h"
+#include <crepe/api/AI.h>
+#include <crepe/api/Animator.h>
+#include <crepe/api/AudioSource.h>
+#include <crepe/api/BoxCollider.h>
+#include <crepe/api/ParticleEmitter.h>
+#include <crepe/api/Rigidbody.h>
+#include <crepe/api/Transform.h>
+#include <crepe/types.h>
+#include <random>
+using namespace crepe;
+using namespace std;
+EnemyScript::EnemyScript() {
+ engine.seed(rd());
+ this->last_fired = std::chrono::steady_clock::now();
+ this->shot_delay = std::chrono::duration<float>(3 + Random::f(1, 0));
+}
+void EnemyScript::init() {
+ Metadata & meta = this->get_component<Metadata>();
+ this->subscribe<SpawnEnemyEvent>(
+ [this](const SpawnEnemyEvent & e) -> bool { return this->spawn_enemy(e); },
+ meta.game_object_id
+ );
+ this->subscribe<CollisionEvent>([this](const CollisionEvent & e) -> bool {
+ return this->on_collide(e);
+ });
+};
+void EnemyScript::fixed_update(duration_t dt) {
+ if (this->alive) {
+ return;
+ }
+ Transform & transform = this->get_component<Transform>();
+ Transform & player_transform = this->get_components_by_name<Transform>("player").front();
+ Rigidbody & enemy_body = this->get_component<Rigidbody>();
+ AI & ai_component = this->get_component<AI>();
+
+ //transform.position += enemy_body.data.linear_velocity * dt.count();
+ float direction_to_player_y = player_transform.position.y - transform.position.y;
+ float distance_to_player_y = std::abs(direction_to_player_y);
+
+ float adjustment_speed = speed * (distance_to_player_y / MAX_DISTANCE);
+
+ adjustment_speed = std::clamp(adjustment_speed, MIN_SPEED, MAX_SPEED);
+ // Move the path nodes on the Y-axis
+ for (vec2 & path_node : ai_component.path) {
+ path_node.y += (direction_to_player_y > 0 ? 1 : -1) * adjustment_speed * dt.count();
+ }
+ //bullet fire logic:
+ auto now = std::chrono::steady_clock::now();
+ std::chrono::duration<float> elapsed = now - last_fired;
+ if (elapsed > shot_delay) {
+ this->shoot(transform.position, 0);
+ last_fired = now;
+ this->shot_delay = std::chrono::duration<float>(Random::f(4, 1));
+ }
+}
+bool EnemyScript::spawn_enemy(const SpawnEnemyEvent & e) {
+ this->speed = e.speed;
+ AI & ai_component = this->get_component<AI>();
+ Transform & transform = this->get_component<Transform>();
+ Camera & camera = this->get_components_by_name<Camera>("camera").front();
+ Transform & cam_transform = this->get_components_by_name<Transform>("camera").front();
+
+ vec2 half_screen = camera.viewport_size / 2;
+ float x_value = cam_transform.position.x + half_screen.x - 50 * (1 + e.column);
+ uniform_real_distribution<float> dist(
+ cam_transform.position.y - half_screen.y + 100,
+ cam_transform.position.y + half_screen.y - 100
+ );
+ float random_height = dist(engine);
+ vec2 spawn_location
+ = {cam_transform.position.x + camera.viewport_size.x / 2 + 100, random_height};
+ transform.position = spawn_location;
+ ai_component.path.clear();
+ ai_component.make_oval_path(10, 10, vec2 {x_value, random_height}, 1.5708, true);
+ ai_component.active = true;
+ this->last_fired = std::chrono::steady_clock::now();
+ return false;
+}
+
+bool EnemyScript::on_collide(const CollisionEvent & e) {
+ if (e.info.other.metadata.tag == "player_bullet") {
+ this->despawn_enemy();
+ }
+ Animator & body_animator = this->get_components<Animator>().front();
+ body_animator.data.col = 2;
+ //body_animator.play();
+ BehaviorScript & enemy_script = this->get_component<BehaviorScript>();
+ enemy_script.active = false;
+ return false;
+}
+void EnemyScript::despawn_enemy() {
+ Transform & transform = this->get_component<Transform>();
+ transform.position = ENEMY_POOL_LOCATION;
+ AI & ai_component = this->get_component<AI>();
+ // Rigidbody& enemy_body
+ ai_component.active = false;
+}
+void EnemyScript::shoot(const vec2 & location, float angle) {
+ RefVector<Transform> bullet_transforms
+ = this->get_components_by_tag<Transform>("enemy_bullet");
+
+ for (Transform & bullet_pos : bullet_transforms) {
+ if (bullet_pos.position.x == 0 && bullet_pos.position.y == -750) {
+
+ bullet_pos.position = location;
+ bullet_pos.position.x -= 20;
+ Rigidbody & bullet_body
+ = this->get_components_by_id<Rigidbody>(bullet_pos.game_object_id).front();
+ BoxCollider bullet_collider
+ = this->get_components_by_id<BoxCollider>(bullet_pos.game_object_id).front();
+ bullet_collider.active = true;
+ bullet_body.active = true;
+ AudioSource & audio = this->get_component<AudioSource>();
+ audio.play();
+ return;
+ }
+ }
+}
diff --git a/game/enemy/EnemyScript.h b/game/enemy/EnemyScript.h
new file mode 100644
index 0000000..42ecac4
--- /dev/null
+++ b/game/enemy/EnemyScript.h
@@ -0,0 +1,31 @@
+#pragma once
+#include <chrono>
+#include <crepe/api/Camera.h>
+#include <crepe/api/Event.h>
+#include <crepe/api/Script.h>
+#include <random>
+struct SpawnEnemyEvent : public crepe::Event {
+ float speed = 0;
+ int column = 0;
+};
+class EnemyScript : public crepe::Script {
+public:
+ EnemyScript();
+ void init() override;
+ void fixed_update(crepe::duration_t dt) override;
+ void shoot(const crepe::vec2 & position, float angle);
+ bool on_collide(const crepe::CollisionEvent & collisionData);
+ void despawn_enemy();
+ bool spawn_enemy(const SpawnEnemyEvent & e);
+
+private:
+ std::random_device rd;
+ std::default_random_engine engine;
+ bool alive = false;
+ float speed = 50;
+ const float MIN_SPEED = 10;
+ const float MAX_SPEED = 130;
+ const float MAX_DISTANCE = 100;
+ std::chrono::time_point<std::chrono::steady_clock> last_fired;
+ std::chrono::duration<float> shot_delay = std::chrono::duration<float>(0);
+};
diff --git a/game/enemy/EnemySubScene.cpp b/game/enemy/EnemySubScene.cpp
new file mode 100644
index 0000000..607b9a9
--- /dev/null
+++ b/game/enemy/EnemySubScene.cpp
@@ -0,0 +1,101 @@
+#include <string>
+
+#include <crepe/api/AI.h>
+#include <crepe/api/Animator.h>
+#include <crepe/api/AudioSource.h>
+#include <crepe/api/BehaviorScript.h>
+#include <crepe/api/BoxCollider.h>
+#include <crepe/api/CircleCollider.h>
+#include <crepe/api/GameObject.h>
+#include <crepe/api/Rigidbody.h>
+#include <crepe/api/Scene.h>
+#include <crepe/api/Sprite.h>
+
+#include "../Config.h"
+#include "EnemyConfig.h"
+#include "EnemyScript.h"
+#include "EnemySubScene.h"
+using namespace crepe;
+using namespace std;
+//#TODO add sound
+int EnemySubScene::create(Scene & scn, int enemy_counter) {
+
+ string unique_name = "enemy_" + to_string(enemy_counter++);
+ GameObject enemy = scn.new_object(unique_name.c_str(), "enemy", ENEMY_POOL_LOCATION, 0, 1);
+
+ enemy.add_component<Rigidbody>(Rigidbody::Data {
+ .gravity_scale = 0,
+ .body_type = Rigidbody::BodyType::DYNAMIC,
+ .max_linear_velocity = 400,
+ .collision_layers = {COLL_LAY_BOT_TOP, COLL_LAY_PLAYER_BULLET},
+ .collision_layer = COLL_LAY_ENEMY,
+
+ });
+ Asset enemy_body_asset {"asset/workers/worker2Body.png"};
+ enemy.add_component<BoxCollider>(vec2(50, 50));
+ Sprite & enemy_body_sprite = enemy.add_component<Sprite>(
+ enemy_body_asset,
+ Sprite::Data {
+ .flip = {true, false},
+ .sorting_in_layer = SORT_IN_LAY_WORKERS_FRONT,
+ .order_in_layer = 0,
+ .size = vec2(0, 50),
+ }
+ );
+ Animator & body_animator = enemy.add_component<Animator>(
+ enemy_body_sprite, ivec2(32, 32), uvec2(4, 8),
+ Animator::Data {
+ .fps = 5,
+ .col = 1,
+ .row = 0,
+ .looping = false,
+ }
+ );
+ body_animator.pause();
+ enemy.add_component<BoxCollider>(vec2(40, 60), vec2(-20, 0));
+ Asset enemy_head_asset {"asset/workers/worker2Head.png"};
+ Sprite & enemy_head_sprite = enemy.add_component<Sprite>(
+ enemy_head_asset,
+ Sprite::Data {
+ .flip = {true, false},
+ .sorting_in_layer = SORT_IN_LAY_WORKERS_FRONT,
+ .order_in_layer = 1,
+ .size = vec2(0, 50),
+ .position_offset = vec2(0, -20),
+ }
+ );
+ enemy.add_component<Animator>(
+ enemy_head_sprite, ivec2(32, 32), uvec2(4, 8),
+ Animator::Data {
+ .fps = 5,
+ .looping = true,
+ }
+ );
+ enemy.add_component<CircleCollider>(25, vec2(0, -20));
+ Asset enemy_jetpack_asset {"asset/barry/jetpackDefault.png"};
+ Sprite & enemy_jetpack_sprite = enemy.add_component<Sprite>(
+ enemy_jetpack_asset,
+ Sprite::Data {
+ .flip = {true, false},
+ .sorting_in_layer = SORT_IN_LAY_WORKERS_FRONT,
+ .order_in_layer = 2,
+ .size = vec2(0, 60),
+ .position_offset = vec2(20, 0),
+ }
+ );
+ enemy_jetpack_sprite.active = true;
+ enemy.add_component<Animator>(
+ enemy_jetpack_sprite, ivec2(32, 44), uvec2(4, 4),
+ Animator::Data {
+ .fps = 5,
+ .looping = true,
+ }
+ );
+ enemy.add_component<AudioSource>(Asset("asset/sfx/bike_gun_2.ogg")).volume = 0.1;
+ AI & ai_component = enemy.add_component<AI>(3000);
+ ai_component.path_follow_on();
+ BehaviorScript & enemy_script
+ = enemy.add_component<BehaviorScript>().set_script<EnemyScript>();
+ enemy_script.active = false;
+ return enemy_counter;
+}
diff --git a/game/enemy/EnemySubScene.h b/game/enemy/EnemySubScene.h
new file mode 100644
index 0000000..3899250
--- /dev/null
+++ b/game/enemy/EnemySubScene.h
@@ -0,0 +1,10 @@
+#pragma once
+
+namespace crepe {
+class Scene;
+}
+
+class EnemySubScene {
+public:
+ int create(crepe::Scene & scn, int enemy_counter);
+};
diff --git a/game/hud/HudSubScene.cpp b/game/hud/HudSubScene.cpp
index ca81614..dcc07b4 100644
--- a/game/hud/HudSubScene.cpp
+++ b/game/hud/HudSubScene.cpp
@@ -45,7 +45,7 @@ void HudSubScene::create(Scene & scn) {
size_coin, FONT,
Text::Data {
.world_space = false,
- .text_color = Color::YELLOW,
+ .text_color = Color::GOLD,
},
TOP_LEFT + FONTOFFSET + COINS_OFFSET + vec2 {COINS_LENGTH * COINS_CHAR_WIDTH / 2, 0},
COINS
diff --git a/game/hud/SpeedScript.cpp b/game/hud/SpeedScript.cpp
index d0a4dfe..2ced47a 100644
--- a/game/hud/SpeedScript.cpp
+++ b/game/hud/SpeedScript.cpp
@@ -1,5 +1,7 @@
#include "SpeedScript.h"
+#include "../Events.h"
+#include "api/BehaviorScript.h"
#include <crepe/api/Event.h>
#include <crepe/api/KeyCodes.h>
#include <crepe/manager/LoopTimerManager.h>
@@ -21,14 +23,20 @@ void SpeedScript::init() {
return true;
});
+ this->subscribe<EndGameEvent>([this](const EndGameEvent e) {
+ this->get_component<BehaviorScript>().active = false;
+ return false;
+ });
}
void SpeedScript::fixed_update(crepe::duration_t dt) {
LoopTimerManager & lp = this->get_loop_timer();
if (this->get_key_state(Keycode::PAGE_UP)) {
+ if (lp.get_time_scale() >= 2) return;
lp.set_time_scale(lp.get_time_scale() + 0.1);
}
if (this->get_key_state(Keycode::PAGE_DOWN)) {
+ if (lp.get_time_scale() <= 0.5) return;
lp.set_time_scale(lp.get_time_scale() - 0.1);
}
}
diff --git a/game/hud/SpeedScript.h b/game/hud/SpeedScript.h
index 6c15a89..b40f7cc 100644
--- a/game/hud/SpeedScript.h
+++ b/game/hud/SpeedScript.h
@@ -10,6 +10,6 @@ public:
private:
crepe::SaveManager * savemgr;
- bool toggle = true;
+ bool toggle = false;
float timescale = 1;
};
diff --git a/game/main.cpp b/game/main.cpp
index b6458b8..c9ad8c1 100644
--- a/game/main.cpp
+++ b/game/main.cpp
@@ -3,8 +3,9 @@
#include <crepe/api/Engine.h>
#include <crepe/api/Script.h>
-#include "Config.h"
+#include "EngineConfig.h"
#include "GameScene.h"
+#include "PreviewScene.h"
#include "menus/mainmenu/MainMenuScene.h"
#include "menus/shop/ShopMenuScene.h"
@@ -16,9 +17,10 @@ int main() {
Config::get_instance() = ENGINE_CONFIG;
Engine gameloop;
- gameloop.add_scene<GameScene>();
gameloop.add_scene<MainMenuScene>();
gameloop.add_scene<ShopMenuScene>();
+ gameloop.add_scene<GameScene>();
+ gameloop.add_scene<PreviewScene>();
return gameloop.main();
}
diff --git a/game/menus/ButtonReplaySubScript.cpp b/game/menus/ButtonReplaySubScript.cpp
new file mode 100644
index 0000000..9308350
--- /dev/null
+++ b/game/menus/ButtonReplaySubScript.cpp
@@ -0,0 +1,30 @@
+#include "ButtonReplaySubScript.h"
+#include "MenusConfig.h"
+
+#include "../Events.h"
+#include <crepe/api/AudioSource.h>
+#include <crepe/types.h>
+
+using namespace crepe;
+using namespace std;
+
+void ButtonReplaySubScript::init() {
+ IButtonScript::init();
+ this->subscribe<ButtonPressEvent>([this](const ButtonPressEvent & e) {
+ return this->on_button_press(e);
+ });
+ this->subscribe<EndGameEvent>([this](const EndGameEvent & e) {
+ return this->set_recording();
+ });
+ replay.record_start();
+}
+
+bool ButtonReplaySubScript::on_button_press(const ButtonPressEvent & e) {
+ replay.play(this->recording);
+ return false;
+}
+
+bool ButtonReplaySubScript::set_recording() {
+ this->recording = replay.record_end();
+ return false;
+}
diff --git a/game/menus/ButtonReplaySubScript.h b/game/menus/ButtonReplaySubScript.h
new file mode 100644
index 0000000..bfc684d
--- /dev/null
+++ b/game/menus/ButtonReplaySubScript.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "IButtonScript.h"
+
+#include <crepe/api/Script.h>
+
+class ButtonReplaySubScript : public IButtonScript {
+public:
+ void init() override;
+ bool on_button_press(const crepe::ButtonPressEvent & e);
+
+private:
+ crepe::recording_t recording = 0;
+ bool set_recording();
+
+protected:
+ bool transition = false;
+};
diff --git a/game/menus/ButtonShowCreditsSubScript.cpp b/game/menus/ButtonShowCreditsSubScript.cpp
new file mode 100644
index 0000000..ec0e980
--- /dev/null
+++ b/game/menus/ButtonShowCreditsSubScript.cpp
@@ -0,0 +1,20 @@
+#include "ButtonShowCreditsSubScript.h"
+#include "MenusConfig.h"
+#include "mainmenu/CreditsSubScript.h"
+#include <crepe/api/AudioSource.h>
+#include <crepe/types.h>
+
+using namespace crepe;
+using namespace std;
+
+void ButtonShowCreditsSubScript::init() {
+ IButtonScript::init();
+ this->subscribe<ButtonPressEvent>([this](const ButtonPressEvent & e) {
+ return this->on_button_press(e);
+ });
+}
+
+bool ButtonShowCreditsSubScript::on_button_press(const ButtonPressEvent & e) {
+ this->trigger_event<ShowCreditsEvent>();
+ return false;
+}
diff --git a/game/menus/ButtonShowCreditsSubScript.h b/game/menus/ButtonShowCreditsSubScript.h
new file mode 100644
index 0000000..3c73c44
--- /dev/null
+++ b/game/menus/ButtonShowCreditsSubScript.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "IButtonScript.h"
+
+#include <crepe/api/Script.h>
+
+class ButtonShowCreditsSubScript : public IButtonScript {
+public:
+ void init() override;
+ bool on_button_press(const crepe::ButtonPressEvent & e);
+
+protected:
+ bool transition = false;
+};
diff --git a/game/menus/ButtonSubScene.cpp b/game/menus/ButtonSubScene.cpp
index e41c798..30646f1 100644
--- a/game/menus/ButtonSubScene.cpp
+++ b/game/menus/ButtonSubScene.cpp
@@ -1,13 +1,16 @@
#include "ButtonSubScene.h"
#include "ButtonNextMainMenuSubScript.h"
+#include "ButtonReplaySubScript.h"
#include "ButtonSetMainMenuSubScript.h"
#include "ButtonSetShopSubScript.h"
+#include "ButtonShowCreditsSubScript.h"
#include "IButtonScript.h"
#include "MenusConfig.h"
#include "mainmenu/ButtonTransitionPreviewSubScript.h"
#include "../Config.h"
+#include "mainmenu/CreditsSubScript.h"
#include <crepe/api/BehaviorScript.h>
#include <crepe/api/Button.h>
@@ -58,6 +61,17 @@ void ButtonSubScene::set_script(crepe::GameObject & button_object, const Data &
button_object.add_component<BehaviorScript>()
.set_script<ButtonNextMainMenuSubScript>();
break;
+ case ScriptSelect::REPLAY:
+ button_object.add_component<BehaviorScript>().set_script<ButtonReplaySubScript>();
+ break;
+ case ScriptSelect::CREDITS_BACK:
+ button_object.add_component<BehaviorScript>().set_script<CreditsSubScript>(data.tag
+ );
+ break;
+ case ScriptSelect::CREDITS_SHOW:
+ button_object.add_component<BehaviorScript>()
+ .set_script<ButtonShowCreditsSubScript>();
+ break;
case ScriptSelect::NONE:
button_object.add_component<BehaviorScript>().set_script<IButtonScript>();
break;
diff --git a/game/menus/ButtonSubScene.h b/game/menus/ButtonSubScene.h
index c1c6de8..74f9464 100644
--- a/game/menus/ButtonSubScene.h
+++ b/game/menus/ButtonSubScene.h
@@ -16,6 +16,9 @@ public:
SHOP,
MAINMENU,
NEXT,
+ REPLAY,
+ CREDITS_SHOW,
+ CREDITS_BACK,
NONE,
};
//icon enum
diff --git a/game/menus/MenusConfig.h b/game/menus/MenusConfig.h
index 24b60e8..3e357a5 100644
--- a/game/menus/MenusConfig.h
+++ b/game/menus/MenusConfig.h
@@ -5,7 +5,7 @@
static constexpr int STARTING_SORTING_IN_LAYER = 7;
//Scene names
static constexpr const char * START_SCENE = "scene1";
-static constexpr const char * PREVIEW_SCENE = "scene1";
+static constexpr const char * PREVIEW_SCENE = "preview scene";
static constexpr const char * SHOP_SCENE = "shopmenu";
static constexpr const char * MAINMENU_SCENE = "mainmenu";
//button config
diff --git a/game/menus/endgame/EndGameSubScene.cpp b/game/menus/endgame/EndGameSubScene.cpp
index 3ef0f9a..a6f8b25 100644
--- a/game/menus/endgame/EndGameSubScene.cpp
+++ b/game/menus/endgame/EndGameSubScene.cpp
@@ -71,7 +71,7 @@ void EndGameSubScene::create(Scene & scn) {
.text = "REPLAY",
.text_width = 150,
.position = {-button_position.x, button_position.y},
- // .script_type = ButtonSubScene::ScriptSelect::MAINMENU,
+ .script_type = ButtonSubScene::ScriptSelect::REPLAY,
.button_type = ButtonSubScene::ButtonSelect::BACK,
.scale = 0.6,
.worldspace = false,
diff --git a/game/menus/endgame/EndGameSubScript.cpp b/game/menus/endgame/EndGameSubScript.cpp
index f120e2d..6edfe7b 100644
--- a/game/menus/endgame/EndGameSubScript.cpp
+++ b/game/menus/endgame/EndGameSubScript.cpp
@@ -1,6 +1,7 @@
#include "EndGameSubScript.h"
#include "../../Events.h"
+#include "../ButtonReplaySubScript.h"
#include "../IFloatingWindowScript.h"
#include <string>
diff --git a/game/menus/mainmenu/CreditsSubScene.cpp b/game/menus/mainmenu/CreditsSubScene.cpp
new file mode 100644
index 0000000..65576ee
--- /dev/null
+++ b/game/menus/mainmenu/CreditsSubScene.cpp
@@ -0,0 +1,132 @@
+
+#include "CreditsSubScene.h"
+#include "CreditsSubScript.h"
+
+#include "../../Config.h"
+#include "../ButtonSubScene.h"
+#include "../FloatingWindowSubScene.h"
+
+#include <string>
+
+#include <crepe/api/BehaviorScript.h>
+#include <crepe/api/GameObject.h>
+#include <crepe/api/Text.h>
+#include <crepe/types.h>
+
+using namespace crepe;
+using namespace std;
+
+void CreditsSubScene::create(Scene & scn) {
+
+ const std::string TAG = "credits_tag";
+ GameObject script = scn.new_object("script");
+ script.add_component<BehaviorScript>().set_script<CreditsSubScript>(TAG);
+
+ // Window
+ FloatingWindowSubScene window;
+ window.create(
+ scn,
+ FloatingWindowSubScene::Data {
+ .group_tag = TAG,
+ .width = 500,
+ .offset = {150, -50},
+ .width_middle_offset = -2,
+ }
+ );
+
+ // Titel
+ const string TITEL_STRING = "Credits";
+ GameObject titel = scn.new_object("titel", TAG);
+ crepe::vec2 size = {200, (200.0f / TITEL_STRING.size()) * 2};
+ titel.add_component<Text>(
+ size, FONT,
+ Text::Data {
+ .world_space = false,
+ .text_color = Color::WHITE,
+ },
+ vec2 {150, -207} + FONTOFFSET, TITEL_STRING
+ );
+
+ // Buttons
+ vec2 button_position = {190, 190};
+ ButtonSubScene button;
+ button.create(
+ scn,
+ ButtonSubScene::Data {
+ .text = "Back",
+ .text_width = 150,
+ .position = {-button_position.x + 150, button_position.y},
+ .script_type = ButtonSubScene::ScriptSelect::CREDITS_BACK,
+ .button_type = ButtonSubScene::ButtonSelect::BACK,
+ .scale = 0.6,
+ .worldspace = false,
+ .tag = TAG,
+ .sorting_layer_offset = 20,
+ }
+ );
+
+ const float SIZE_CHAR_NAMES = 10;
+ const float Y_OFFSET_NAMES_BEGIN = 100;
+ const float Y_OFFSET_NAMES = 30;
+ const string LOEK = "Loek Le Blansch";
+ crepe::vec2 size_loek
+ = {LOEK.size() * SIZE_CHAR_NAMES, (LOEK.size() * SIZE_CHAR_NAMES / LOEK.size()) * 2};
+ titel.add_component<Text>(
+ size_loek, FONT,
+ Text::Data {
+ .world_space = false,
+ .text_color = Color::WHITE,
+ },
+ vec2 {150, -207 + Y_OFFSET_NAMES + Y_OFFSET_NAMES_BEGIN} + FONTOFFSET, LOEK
+ );
+
+ const string WOUTER = "Wouter Boerenkamps";
+ crepe::vec2 size_wouter
+ = {WOUTER.size() * SIZE_CHAR_NAMES,
+ (WOUTER.size() * SIZE_CHAR_NAMES / WOUTER.size()) * 2};
+ titel.add_component<Text>(
+ size_wouter, FONT,
+ Text::Data {
+ .world_space = false,
+ .text_color = Color::WHITE,
+ },
+ vec2 {150, -207 + Y_OFFSET_NAMES * 2 + Y_OFFSET_NAMES_BEGIN} + FONTOFFSET, WOUTER
+ );
+
+ const string JARO = "Jaro Rutjes";
+ crepe::vec2 size_jaro
+ = {JARO.size() * SIZE_CHAR_NAMES, (JARO.size() * SIZE_CHAR_NAMES / JARO.size()) * 2};
+ titel.add_component<Text>(
+ size_jaro, FONT,
+ Text::Data {
+ .world_space = false,
+ .text_color = Color::WHITE,
+ },
+ vec2 {150, -207 + Y_OFFSET_NAMES * 3 + Y_OFFSET_NAMES_BEGIN} + FONTOFFSET, JARO
+ );
+
+ const string MAX = "Max Smits";
+ crepe::vec2 size_max
+ = {MAX.size() * SIZE_CHAR_NAMES, (MAX.size() * SIZE_CHAR_NAMES / MAX.size()) * 2};
+ titel.add_component<Text>(
+ size_max, FONT,
+ Text::Data {
+ .world_space = false,
+ .text_color = Color::WHITE,
+ },
+ vec2 {150, -207 + Y_OFFSET_NAMES * 4 + Y_OFFSET_NAMES_BEGIN} + FONTOFFSET, MAX
+ );
+
+ const string NIELS = "Niels Stunnebrink";
+ crepe::vec2 size_niels
+ = {NIELS.size() * SIZE_CHAR_NAMES, (NIELS.size() * SIZE_CHAR_NAMES / NIELS.size()) * 2
+ };
+ titel.add_component<Text>(
+ size_niels, FONT,
+ Text::Data {
+ .world_space = false,
+ .text_color = Color::WHITE,
+ },
+ vec2 {150, -207 + Y_OFFSET_NAMES * 5 + Y_OFFSET_NAMES_BEGIN} + FONTOFFSET, NIELS
+ );
+}
diff --git a/game/menus/mainmenu/CreditsSubScene.h b/game/menus/mainmenu/CreditsSubScene.h
new file mode 100644
index 0000000..e7ff735
--- /dev/null
+++ b/game/menus/mainmenu/CreditsSubScene.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <crepe/api/Scene.h>
+
+class CreditsSubScene {
+
+public:
+ void create(crepe::Scene & scn);
+};
diff --git a/game/menus/mainmenu/CreditsSubScript.cpp b/game/menus/mainmenu/CreditsSubScript.cpp
new file mode 100644
index 0000000..4224dc8
--- /dev/null
+++ b/game/menus/mainmenu/CreditsSubScript.cpp
@@ -0,0 +1,58 @@
+#include "CreditsSubScript.h"
+
+#include "../../Events.h"
+#include "../ButtonReplaySubScript.h"
+#include "../IFloatingWindowScript.h"
+
+#include <string>
+
+#include <crepe/api/Button.h>
+#include <crepe/api/Sprite.h>
+#include <crepe/api/Text.h>
+#include <crepe/types.h>
+
+using namespace crepe;
+
+CreditsSubScript::CreditsSubScript(const std::string & tag) { this->tag = tag; }
+
+void CreditsSubScript::init() {
+ IButtonScript::init();
+ this->subscribe<ButtonPressEvent>([this](const ButtonPressEvent & e) {
+ return this->on_button_press(e);
+ });
+ this->subscribe<ShowCreditsEvent>([this](const ShowCreditsEvent & e) {
+ this->enable_all();
+ return false;
+ });
+ this->disable_all();
+}
+
+bool CreditsSubScript::disable_all() {
+ IFloatingWindowScript::disable_all_sprites();
+ RefVector<Button> buttons = this->get_components_by_tag<Button>(this->tag);
+ for (Button & button : buttons) {
+ button.active = false;
+ }
+ RefVector<Text> texts = this->get_components_by_tag<Text>(this->tag);
+ for (Text & text : texts) {
+ text.active = false;
+ }
+ return false;
+}
+
+bool CreditsSubScript::enable_all() {
+ IFloatingWindowScript::enable_all_sprites();
+ RefVector<Button> buttons = this->get_components_by_tag<Button>(this->tag);
+ for (Button & button : buttons) {
+ button.active = true;
+ }
+ RefVector<Text> texts = this->get_components_by_tag<Text>(this->tag);
+ for (Text & text : texts) {
+ text.active = true;
+ }
+ return false;
+}
+
+bool CreditsSubScript::on_button_press(const ButtonPressEvent & e) {
+ return this->disable_all();
+}
diff --git a/game/menus/mainmenu/CreditsSubScript.h b/game/menus/mainmenu/CreditsSubScript.h
new file mode 100644
index 0000000..81f941a
--- /dev/null
+++ b/game/menus/mainmenu/CreditsSubScript.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "../IButtonScript.h"
+#include "../IFloatingWindowScript.h"
+
+#include <crepe/api/Event.h>
+#include <crepe/api/Script.h>
+
+struct ShowCreditsEvent : public crepe::Event {};
+
+class CreditsSubScript : public IFloatingWindowScript, public IButtonScript {
+public:
+ CreditsSubScript(const std::string & tag);
+ void init() override;
+ bool disable_all();
+ bool enable_all();
+ bool on_button_press(const crepe::ButtonPressEvent & e);
+};
diff --git a/game/menus/mainmenu/MainMenuScene.cpp b/game/menus/mainmenu/MainMenuScene.cpp
index 43418e3..fba90ac 100644
--- a/game/menus/mainmenu/MainMenuScene.cpp
+++ b/game/menus/mainmenu/MainMenuScene.cpp
@@ -1,5 +1,6 @@
#include "MainMenuScene.h"
+#include "CreditsSubScene.h"
#include "MainMenuConfig.h"
#include "TransitionStartSubScript.h"
@@ -64,7 +65,7 @@ void MainMenuScene::load_scene() {
ButtonSubScene::Data {
.text = "SHOP",
.text_offset = {-20, 0},
- .text_width = 115,
+ .text_width = 110,
.icon_offset = {60, 0},
.icon_type = ButtonSubScene::IconSelect::SHOP,
.position = pos_btn,
@@ -72,6 +73,19 @@ void MainMenuScene::load_scene() {
}
);
+ //Credits btn
+ pos_btn.y += MENU_BUTTON_SPACING + LARGE_OVERLAY_SIZE.y;
+ button.create(
+ *this,
+ ButtonSubScene::Data {
+ .text = "CREDITS",
+ .text_offset = {0, 0},
+ .text_width = 200,
+ .position = pos_btn,
+ .script_type = ButtonSubScene::ScriptSelect::CREDITS_SHOW,
+ }
+ );
+
//Start of map
StartSubScene start;
HallwaySubScene hallway;
@@ -110,6 +124,9 @@ void MainMenuScene::load_scene() {
.tag = MENU_INFO_TAG,
}
);
+
+ CreditsSubScene creditscene;
+ creditscene.create(*this);
}
string MainMenuScene::get_name() const { return MAINMENU_SCENE; }
diff --git a/game/menus/mainmenu/TransitionStartSubScript.cpp b/game/menus/mainmenu/TransitionStartSubScript.cpp
index 63723cf..f737f7f 100644
--- a/game/menus/mainmenu/TransitionStartSubScript.cpp
+++ b/game/menus/mainmenu/TransitionStartSubScript.cpp
@@ -6,7 +6,7 @@ using namespace crepe;
using namespace std;
void TransitionStartSubScript::fixed_update(crepe::duration_t dt) {
- if (this->get_key_state(Keycode::ENTER) && this->transition == false)
+ if (this->get_key_state(Keycode::SPACE) && this->transition == false)
this->transition = true;
}
diff --git a/game/menus/shop/ShopMenuScene.cpp b/game/menus/shop/ShopMenuScene.cpp
index d4542ba..d1ea81d 100644
--- a/game/menus/shop/ShopMenuScene.cpp
+++ b/game/menus/shop/ShopMenuScene.cpp
@@ -5,9 +5,11 @@
#include "../BannerSubScene.h"
#include "../ButtonSubScene.h"
#include "../MenusConfig.h"
+#include "types.h"
#include <crepe/api/Camera.h>
#include <crepe/api/Sprite.h>
+#include <crepe/api/Text.h>
using namespace crepe;
using namespace std;
@@ -51,6 +53,74 @@ void ShopMenuScene::load_scene() {
.scale = 0.8
}
);
+
+ GameObject shop_item_bullet = this->new_object("bullet", "shop_item", vec2(-100, 0));
+ shop_item_bullet.add_component<Sprite>(
+ Asset("asset/other_effects/effect_rocketmgshell_TVOS.png"),
+ Sprite::Data {
+ .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1,
+ .size = {0, 100},
+ .position_offset = {0, 0},
+ }
+ );
+ shop_item_bullet.add_component<Text>(
+ vec2 {100, 50}, FONT,
+ Text::Data {
+ .world_space = true,
+ .text_color = Color::WHITE,
+ },
+ vec2 {0, -75}, "BULLETS"
+ );
+ shop_item_bullet.add_component<Sprite>(
+ Asset("asset/ui/buttonCoinsSmall.png"),
+ Sprite::Data {
+ .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1,
+ .size = {0, 45},
+ .position_offset = {25, 75},
+ }
+ );
+ shop_item_bullet.add_component<Text>(
+ vec2 {37.5, 37.5}, FONT,
+ Text::Data {
+ .world_space = true,
+ .text_color = Color::GOLD,
+ },
+ vec2 {-25, 75}, "0"
+ );
+
+ GameObject shop_item_bubble = this->new_object("bubble", "shop_item", vec2(100, 0));
+ shop_item_bubble.add_component<Sprite>(
+ Asset("asset/background/aquarium/bubble.png"),
+ Sprite::Data {
+ .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1,
+ .size = {0, 100},
+ .position_offset = {0, 0},
+ }
+ );
+ shop_item_bubble.add_component<Text>(
+ vec2 {100, 50}, FONT,
+ Text::Data {
+ .world_space = true,
+ .text_color = Color::WHITE,
+ },
+ vec2 {0, -75}, "BUBBLE"
+ );
+ shop_item_bubble.add_component<Sprite>(
+ Asset("asset/ui/buttonCoinsSmall.png"),
+ Sprite::Data {
+ .sorting_in_layer = STARTING_SORTING_IN_LAYER + 1,
+ .size = {0, 45},
+ .position_offset = {45, 75},
+ }
+ );
+ shop_item_bubble.add_component<Text>(
+ vec2 {100, 25}, FONT,
+ Text::Data {
+ .world_space = true,
+ .text_color = Color::GOLD,
+ },
+ vec2 {-25, 75}, "1000"
+ );
}
string ShopMenuScene::get_name() const { return SHOP_SCENE; }
diff --git a/game/missile/MissilePool.cpp b/game/missile/MissilePool.cpp
new file mode 100644
index 0000000..e549210
--- /dev/null
+++ b/game/missile/MissilePool.cpp
@@ -0,0 +1,16 @@
+#include "MissilePool.h"
+#include "MissileSubScene.h"
+
+#include <crepe/api/Scene.h>
+
+using namespace std;
+using namespace crepe;
+
+MissilePool::MissilePool(Scene & scn) {
+ int amount = 0;
+ MissileSubScene missile;
+ while (amount < this->MAX_MISSILE_COUNT) {
+ missile.create(scn);
+ amount++;
+ }
+}
diff --git a/game/missile/MissilePool.h b/game/missile/MissilePool.h
new file mode 100644
index 0000000..296701e
--- /dev/null
+++ b/game/missile/MissilePool.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <crepe/api/Scene.h>
+
+class MissilePool {
+public:
+ MissilePool(crepe::Scene & scn);
+
+private:
+ static constexpr unsigned int MAX_MISSILE_COUNT = 5;
+};
diff --git a/game/missile/MissileScript.cpp b/game/missile/MissileScript.cpp
new file mode 100644
index 0000000..6d0e40e
--- /dev/null
+++ b/game/missile/MissileScript.cpp
@@ -0,0 +1,105 @@
+#include "MissileScript.h"
+#include "../Config.h"
+#include "api/BehaviorScript.h"
+
+#include <crepe/api/Animator.h>
+#include <crepe/api/AudioSource.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;
+
+void MissileScript::init() {
+ subscribe<CollisionEvent>([this](const CollisionEvent & ev) -> bool {
+ return this->on_collision(ev);
+ });
+ this->seeking_disabled = false;
+}
+void MissileScript::kill_missile() {
+ auto animations = this->get_components<Animator>();
+ auto sprites = this->get_components<Sprite>();
+ auto & fly_sound = this->get_components<AudioSource>().front().get();
+ auto & this_script = this->get_components<BehaviorScript>().back().get();
+
+ animations[0].get().active = false;
+ animations[1].get().active = false;
+ animations[2].get().active = true;
+ sprites[0].get().active = false;
+ sprites[1].get().active = false;
+ sprites[2].get().active = true;
+
+ 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;
+}
+
+bool MissileScript::on_collision(const CollisionEvent & ev) {
+ auto & explosion_sound = this->get_components<AudioSource>().back().get();
+
+ this->kill_missile();
+ explosion_sound.play();
+
+ return false;
+}
+
+bool MissileScript::is_in_x_range(const Transform & missile, const Transform & player) {
+ return fabs(missile.position.x - player.position.x) <= this->X_RANGE;
+}
+
+void MissileScript::fixed_update(crepe::duration_t dt) {
+ auto & explosion_anim = this->get_components<Animator>().back().get();
+ auto & missile = this->get_component<Transform>();
+ auto & m_ai = this->get_component<AI>();
+
+ const auto & player = this->get_components_by_name<Transform>("player").front().get();
+ const auto & cam = this->get_components_by_name<Transform>("camera").front().get();
+ const auto & velocity = this->get_component<Rigidbody>().data.linear_velocity;
+
+ if (missile.position.x < (cam.position.x - VIEWPORT_X / 1.8)) {
+ this->kill_missile();
+ return;
+ }
+
+ // check if animation is at the end
+ if (explosion_anim.data.row == 7) {
+ this->activate();
+ this->seeking_disabled = false;
+ }
+
+ if (this->seeking_disabled) {
+ m_ai.seek_off();
+ } else {
+ m_ai.seek_target = player.position;
+ m_ai.seek_on();
+
+ if (is_in_x_range(missile, player)) {
+ this->seeking_disabled = true;
+ m_ai.seek_off();
+ }
+ }
+
+ vec2 angle_pos = velocity;
+ float angle = atan2(angle_pos.y, angle_pos.x) * (180 / M_PI);
+
+ missile.rotation = angle;
+ missile.position += velocity * dt.count();
+}
diff --git a/game/missile/MissileScript.h b/game/missile/MissileScript.h
new file mode 100644
index 0000000..a492e18
--- /dev/null
+++ b/game/missile/MissileScript.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <crepe/api/Script.h>
+
+class MissileScript : public crepe::Script {
+private:
+ bool on_collision(const crepe::CollisionEvent & ev);
+
+ bool seeking_disabled;
+
+ // will be used to calculate when ai will be stopped
+ static constexpr int X_RANGE = 90;
+ bool is_in_x_range(const crepe::Transform & missile, const crepe::Transform & player);
+ void kill_missile();
+ void activate();
+
+public:
+ void init();
+ void fixed_update(crepe::duration_t dt);
+};
diff --git a/game/missile/MissileSubScene.cpp b/game/missile/MissileSubScene.cpp
new file mode 100644
index 0000000..6719c3d
--- /dev/null
+++ b/game/missile/MissileSubScene.cpp
@@ -0,0 +1,103 @@
+#include "MissileSubScene.h"
+#include "../Config.h"
+#include "../missile/MissileScript.h"
+
+#include <crepe/api/AI.h>
+#include <crepe/api/Animator.h>
+#include <crepe/api/AudioSource.h>
+#include <crepe/api/BehaviorScript.h>
+#include <crepe/api/CircleCollider.h>
+#include <crepe/api/Scene.h>
+#include <crepe/api/Sprite.h>
+#include <crepe/types.h>
+#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"};
+ Asset missle_thruster_ss {"asset/obstacles/missile/missileEffects.png"};
+ Asset missile_explosion_ss {"asset/obstacles/missile/missileExplosion.png"};
+ Asset explosion_sound {"asset/sfx/rocket_explode_1.ogg"};
+ Asset missile_fire {"asset/sfx/missile_launch.ogg"};
+
+ missle.add_component<BehaviorScript>().set_script<MissileScript>().active = false;
+
+ auto & sound = missle.add_component<AudioSource>(missile_fire);
+ sound.volume = 0.5;
+ auto & sound2 = missle.add_component<AudioSource>(explosion_sound);
+ sound2.volume = 3;
+
+ // sprites
+ auto & missle_sprite = missle.add_component<Sprite>(
+ missle_ss,
+ Sprite::Data {
+ .flip = {true, false},
+ .sorting_in_layer = SORT_IN_LAY_OBSTACLES,
+ .size = {0, 35},
+ }
+ );
+
+ auto & missle_thruster_sprite = missle.add_component<Sprite>(
+ missle_thruster_ss,
+ Sprite::Data {
+ .flip = {true, false},
+ .sorting_in_layer = SORT_IN_LAY_OBSTACLES,
+ .size = {0, 35},
+ .position_offset = {-20, 0},
+ }
+ );
+
+ auto & missile_explosion_sprite = missle.add_component<Sprite>(
+ missile_explosion_ss,
+ Sprite::Data {
+ .sorting_in_layer = SORT_IN_LAY_OBSTACLES,
+ .size = {0, 50},
+ }
+ );
+
+ // Animations
+ missle.add_component<Animator>(
+ missle_sprite, ivec2 {32, 32}, uvec2 {4, 1},
+ Animator::Data {
+ .fps = 15,
+ .looping = true,
+ }
+ );
+
+ missle.add_component<Animator>(
+ missle_thruster_sprite, ivec2 {64, 64}, uvec2 {4, 2},
+ Animator::Data {
+ .fps = 15,
+ .looping = true,
+ }
+ );
+
+ auto & explosion_anim = missle.add_component<Animator>(
+ missile_explosion_sprite, ivec2 {64, 64}, uvec2 {8, 1},
+ Animator::Data {
+ .fps = 10,
+ }
+ );
+
+ missile_explosion_sprite.active = false;
+ explosion_anim.active = false;
+
+ 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)),
+ .kinematic_collision = false,
+ .collision_layers = {COLL_LAY_PLAYER, COLL_LAY_BOT_TOP},
+ .collision_layer = COLL_LAY_MISSILE,
+ });
+
+ missle.add_component<CircleCollider>(3);
+
+ auto & missle_ai = missle.add_component<AI>(1000);
+}
diff --git a/game/missile/MissileSubScene.h b/game/missile/MissileSubScene.h
new file mode 100644
index 0000000..9ea422a
--- /dev/null
+++ b/game/missile/MissileSubScene.h
@@ -0,0 +1,12 @@
+#pragma once
+
+namespace crepe {
+class Scene;
+}
+
+class MissileSubScene {
+public:
+ MissileSubScene() = default;
+
+ void create(crepe::Scene & scn);
+};
diff --git a/game/missile/SpawnEvent.cpp b/game/missile/SpawnEvent.cpp
new file mode 100644
index 0000000..03a9b8c
--- /dev/null
+++ b/game/missile/SpawnEvent.cpp
@@ -0,0 +1,47 @@
+#include "SpawnEvent.h"
+
+#include <crepe/api/Animator.h>
+#include <crepe/api/AudioSource.h>
+#include <crepe/api/BehaviorScript.h>
+#include <crepe/api/Camera.h>
+#include <crepe/api/Sprite.h>
+#include <crepe/api/Transform.h>
+
+#include <cstdlib>
+#include <random>
+
+using namespace crepe;
+
+void MissileSpawnEventHandler::init() {
+ subscribe<MissileSpawnEvent>([this](const MissileSpawnEvent & ev) -> bool {
+ return this->on_event(ev);
+ });
+}
+
+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 missile_transforms = this->get_components_by_name<Transform>("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();
+ if (script.active) continue;
+ script.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);
+
+ break;
+ }
+
+ return false;
+}
diff --git a/game/missile/SpawnEvent.h b/game/missile/SpawnEvent.h
new file mode 100644
index 0000000..58293d7
--- /dev/null
+++ b/game/missile/SpawnEvent.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <crepe/api/Event.h>
+#include <crepe/api/Script.h>
+
+#include "../Config.h"
+
+struct MissileSpawnEvent : public crepe::Event {};
+
+class MissileSpawnEventHandler : public crepe::Script {
+private:
+ static constexpr int MISSILE_OFFSET = VIEWPORT_X;
+ static constexpr int RANGE = GAME_HEIGHT / 4;
+ static constexpr int MIN_RANGE = -RANGE;
+ static constexpr int MAX_RANGE = RANGE;
+
+public:
+ void init();
+ bool on_event(const MissileSpawnEvent & ev);
+};
diff --git a/game/player/PlayerBulletPool.cpp b/game/player/PlayerBulletPool.cpp
new file mode 100644
index 0000000..5285ec8
--- /dev/null
+++ b/game/player/PlayerBulletPool.cpp
@@ -0,0 +1,11 @@
+#include "PlayerBulletPool.h"
+#include "PlayerBulletSubScene.h"
+using namespace std;
+
+void PlayerBulletPool::create_bullets(crepe::Scene & scn) {
+ PlayerBulletSubScene bullet;
+ int amount = 0;
+ while (amount < this->MAXIMUM_AMOUNT) {
+ amount = bullet.create(scn, amount);
+ }
+}
diff --git a/game/player/PlayerBulletPool.h b/game/player/PlayerBulletPool.h
new file mode 100644
index 0000000..9618d54
--- /dev/null
+++ b/game/player/PlayerBulletPool.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <crepe/api/Scene.h>
+
+class PlayerBulletPool {
+public:
+ void create_bullets(crepe::Scene & scn);
+
+private:
+ static constexpr int MAXIMUM_AMOUNT = 20;
+};
diff --git a/game/player/PlayerBulletScript.cpp b/game/player/PlayerBulletScript.cpp
new file mode 100644
index 0000000..a823375
--- /dev/null
+++ b/game/player/PlayerBulletScript.cpp
@@ -0,0 +1,41 @@
+
+#include <crepe/api/Camera.h>
+#include <crepe/api/Metadata.h>
+#include <crepe/api/Rigidbody.h>
+
+#include "PlayerBulletScript.h"
+
+using namespace crepe;
+using namespace std;
+void PlayerBulletScript::init() {
+ this->subscribe<CollisionEvent>([this](const CollisionEvent & e) -> bool {
+ return this->on_collide(e);
+ });
+}
+void PlayerBulletScript::fixed_update(crepe::duration_t dt) {
+ Transform & transform = this->get_component<Transform>();
+ Camera & camera = this->get_components_by_name<Camera>("camera").front();
+ Transform & cam_transform = this->get_components_by_name<Transform>("camera").front();
+ Rigidbody & bullet_body = this->get_component<Rigidbody>();
+ transform.rotation += bullet_body.data.angular_velocity * dt.count();
+ transform.position += bullet_body.data.linear_velocity * dt.count();
+ vec2 half_screen = camera.viewport_size / 2;
+ float despawn_location = cam_transform.position.x + half_screen.x + 50;
+ if (transform.position.x > despawn_location) {
+ this->despawn_bullet();
+ }
+}
+
+void PlayerBulletScript::despawn_bullet() {
+ Transform & transform = this->get_component<Transform>();
+ Rigidbody & bullet_body = this->get_component<Rigidbody>();
+ bullet_body.active = false;
+ BehaviorScript & bullet_script = this->get_component<BehaviorScript>();
+ bullet_script.active = false;
+ transform.position = {0, -850};
+}
+
+bool PlayerBulletScript::on_collide(const CollisionEvent & e) {
+ this->despawn_bullet();
+ return false;
+}
diff --git a/game/player/PlayerBulletScript.h b/game/player/PlayerBulletScript.h
new file mode 100644
index 0000000..0637790
--- /dev/null
+++ b/game/player/PlayerBulletScript.h
@@ -0,0 +1,11 @@
+#pragma once
+#include <crepe/api/BehaviorScript.h>
+#include <crepe/api/Script.h>
+
+class PlayerBulletScript : public crepe::Script {
+public:
+ void init() override;
+ void fixed_update(crepe::duration_t dt) override;
+ bool on_collide(const crepe::CollisionEvent & e);
+ void despawn_bullet();
+};
diff --git a/game/player/PlayerBulletSubScene.cpp b/game/player/PlayerBulletSubScene.cpp
new file mode 100644
index 0000000..5e1c66e
--- /dev/null
+++ b/game/player/PlayerBulletSubScene.cpp
@@ -0,0 +1,52 @@
+#include <string>
+
+#include "../Config.h"
+#include <crepe/api/AI.h>
+#include <crepe/api/Animator.h>
+#include <crepe/api/BehaviorScript.h>
+#include <crepe/api/BoxCollider.h>
+#include <crepe/api/CircleCollider.h>
+#include <crepe/api/GameObject.h>
+#include <crepe/api/Rigidbody.h>
+#include <crepe/api/Scene.h>
+#include <crepe/api/Sprite.h>
+
+#include "PlayerBulletScript.h"
+#include "PlayerBulletSubScene.h"
+#include "PlayerScript.h"
+using namespace crepe;
+using namespace std;
+int PlayerBulletSubScene::create(Scene & scn, int counter) {
+ string unique_name = "player_bullet_" + to_string(counter++);
+ GameObject player_bullet
+ = scn.new_object(unique_name.c_str(), "player_bullet", vec2 {0, -850}, 0, 1);
+
+ Rigidbody & player_bullet_body = player_bullet.add_component<Rigidbody>(Rigidbody::Data {
+ .gravity_scale = 0,
+ .body_type = Rigidbody::BodyType::KINEMATIC,
+ .linear_velocity = vec2 {400, 0},
+ .angular_velocity = 300,
+ .kinematic_collision = false,
+ .collision_layers = {COLL_LAY_ENEMY, COLL_LAY_ZAPPER},
+
+ .collision_layer = COLL_LAY_PLAYER_BULLET,
+
+ });
+ player_bullet_body.active = false;
+ BoxCollider & player_bullet_collider
+ = player_bullet.add_component<BoxCollider>(vec2(30, 30));
+
+ Asset player_bullet_asset {"asset/other_effects/crepe.png"};
+ Sprite & player_bullet_sprite = player_bullet.add_component<Sprite>(
+ player_bullet_asset,
+ Sprite::Data {
+ .flip = {true, false},
+ .sorting_in_layer = SORT_IN_LAY_OBSTACLES,
+ .order_in_layer = 1,
+ .size = vec2(30, 0),
+ }
+ );
+ player_bullet.add_component<BehaviorScript>().set_script<PlayerBulletScript>().active
+ = false;
+ return counter;
+}
diff --git a/game/player/PlayerBulletSubScene.h b/game/player/PlayerBulletSubScene.h
new file mode 100644
index 0000000..72eda62
--- /dev/null
+++ b/game/player/PlayerBulletSubScene.h
@@ -0,0 +1,10 @@
+#pragma once
+
+namespace crepe {
+class Scene;
+}
+
+class PlayerBulletSubScene {
+public:
+ int create(crepe::Scene & scn, int counter);
+};
diff --git a/game/player/PlayerEndScript.cpp b/game/player/PlayerEndScript.cpp
index fb18f2f..4ae813f 100644
--- a/game/player/PlayerEndScript.cpp
+++ b/game/player/PlayerEndScript.cpp
@@ -62,7 +62,9 @@ bool PlayerEndScript::on_collision(const crepe::CollisionEvent & ev) {
rb_player.data.angular_velocity = 0;
rb_player.data.elasticity_coefficient = 0;
- rb_player.data.linear_velocity = vec2(PLAYER_SPEED * dt, 0);
+ if (rb_player.data.linear_velocity.x != 0) {
+ rb_player.data.linear_velocity = vec2(PLAYER_SPEED * dt, 0);
+ }
rb_player.data.linear_velocity_coefficient = vec2(0.5, 0.5);
rb_camera.data.linear_velocity_coefficient = vec2(0.5, 0.5);
for (Animator & anim : anim_player) {
@@ -90,7 +92,7 @@ bool PlayerEndScript::on_collision(const crepe::CollisionEvent & ev) {
jump++;
}
- if (rb_player.data.linear_velocity.x < 5) {
+ if (rb_player.data.linear_velocity.x < 5 && jump >= 3) {
this->trigger_event<EndGameEvent>();
}
diff --git a/game/player/PlayerScript.cpp b/game/player/PlayerScript.cpp
index d45a519..c3843ca 100644
--- a/game/player/PlayerScript.cpp
+++ b/game/player/PlayerScript.cpp
@@ -1,9 +1,11 @@
#include "PlayerScript.h"
#include "../Config.h"
+#include "../enemy/BattleScript.h"
#include <crepe/api/Animator.h>
#include <crepe/api/AudioSource.h>
+#include <crepe/api/BoxCollider.h>
#include <crepe/api/ParticleEmitter.h>
#include <crepe/api/Rigidbody.h>
#include <crepe/api/Transform.h>
@@ -16,6 +18,36 @@ 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) {
+ const vec2 UP = {0, -1};
+ this->help_kick(UP);
+ return false;
+}
+
+bool PlayerScript::on_key_up(const KeyReleaseEvent & ev) {
+ 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) {
@@ -59,7 +91,8 @@ bool PlayerScript::on_collision(const CollisionEvent & ev) {
audio.play();
return false;
- } else if (ev.info.other.metadata.tag == "missile") {
+ } else if (ev.info.other.metadata.tag == "missile"
+ || ev.info.other.metadata.tag == "enemy_bullet") {
for (Animator & anim : animators) {
anim.active = true;
anim.set_anim(5);
@@ -91,9 +124,21 @@ 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();
+ std::chrono::duration<float> elapsed = now - last_fired;
+ if (elapsed > shot_delay) {
+ this->shoot(transform.position, 0);
+ last_fired = now;
+ }
+ }
if (this->get_key_state(Keycode::SPACE)) {
- rb.add_force_linear(vec2(0, -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;
@@ -115,7 +160,8 @@ void PlayerScript::fixed_update(crepe::duration_t dt) {
current_jetpack_sound = 0;
}
} else if (transform.position.y == 195) {
- if (prev_anim != 0) {
+ Rigidbody & rb = this->body;
+ if (prev_anim != 0 && rb.data.linear_velocity.x != 0) {
for (Animator & anim : animators) {
anim.active = true;
anim.set_anim(0);
@@ -139,3 +185,26 @@ void PlayerScript::fixed_update(crepe::duration_t dt) {
}
}
}
+
+void PlayerScript::shoot(const vec2 & location, float angle) {
+ RefVector<Transform> bullet_transforms
+ = this->get_components_by_tag<Transform>("player_bullet");
+
+ for (Transform & bullet_pos : bullet_transforms) {
+ if (bullet_pos.position.x == 0 && bullet_pos.position.y == -850) {
+
+ bullet_pos.position = location;
+ bullet_pos.position.x += 20;
+ Rigidbody & bullet_body
+ = this->get_components_by_id<Rigidbody>(bullet_pos.game_object_id).front();
+ BoxCollider bullet_collider
+ = this->get_components_by_id<BoxCollider>(bullet_pos.game_object_id).front();
+ bullet_body.active = true;
+ BehaviorScript & bullet_script
+ = this->get_components_by_id<BehaviorScript>(bullet_pos.game_object_id)
+ .front();
+ bullet_script.active = true;
+ return;
+ }
+ }
+}
diff --git a/game/player/PlayerScript.h b/game/player/PlayerScript.h
index 482b40d..6875b05 100644
--- a/game/player/PlayerScript.h
+++ b/game/player/PlayerScript.h
@@ -1,5 +1,8 @@
#pragma once
+#include "util/OptionalRef.h"
+#include <chrono>
+#include <crepe/api/Config.h>
#include <crepe/api/Event.h>
#include <crepe/api/Script.h>
@@ -10,8 +13,19 @@ 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::duration<float> shot_delay = std::chrono::duration<float>(0.5);
+
int current_jetpack_sound = 0;
+
+ float & engine_gravity = crepe::Config::get_instance().physics.gravity;
+ crepe::OptionalRef<crepe::Rigidbody> body;
};
diff --git a/game/player/PlayerSubScene.cpp b/game/player/PlayerSubScene.cpp
index f136605..371bc42 100644
--- a/game/player/PlayerSubScene.cpp
+++ b/game/player/PlayerSubScene.cpp
@@ -145,11 +145,12 @@ PlayerSubScene::PlayerSubScene(Scene & scn) {
);
player.add_component<BoxCollider>(vec2(40, 60), 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
- = {COLL_LAY_BOT_TOP, COLL_LAY_ZAPPER, COLL_LAY_LASER, COLL_LAY_MISSILE},
+ = {COLL_LAY_BOT_TOP, COLL_LAY_ZAPPER, COLL_LAY_LASER, COLL_LAY_MISSILE, COLL_LAY_BULLET
+ },
.collision_layer = COLL_LAY_PLAYER,
});
player.add_component<BehaviorScript>().set_script<PlayerScript>().active = false;
diff --git a/game/prefab/ZapperPoolSubScene.cpp b/game/prefab/ZapperPoolSubScene.cpp
index 8422b8c..a52aa75 100644
--- a/game/prefab/ZapperPoolSubScene.cpp
+++ b/game/prefab/ZapperPoolSubScene.cpp
@@ -9,7 +9,6 @@ using namespace std;
ZapperPoolSubScene::ZapperPoolSubScene(Scene & scene)
: controller {scene.new_object("controller")} {
- Log::logf(Log::DEBUG, "Building zapper pool...");
vector<ZapperObject> pool;
for (size_t i = 0; i < this->POOL_SIZE; i++)
pool.emplace_back(scene.new_object("zapper", "zapper"));
diff --git a/game/preview/NpcScript.cpp b/game/preview/NpcScript.cpp
new file mode 100644
index 0000000..c4148f2
--- /dev/null
+++ b/game/preview/NpcScript.cpp
@@ -0,0 +1,32 @@
+#include "NpcScript.h"
+
+#include <crepe/api/Sprite.h>
+#include <crepe/api/Transform.h>
+#include <crepe/manager/SaveManager.h>
+
+using namespace std;
+using namespace crepe;
+
+void NpcScript::init() {}
+void NpcScript::fixed_update(duration_t dt) {
+ auto & rb = this->get_component<Rigidbody>();
+ auto & npc = this->get_component<Sprite>();
+ auto & transform = this->get_component<Transform>();
+
+ if (transform.position.x < -990) {
+ rb.data.linear_velocity.x *= -1;
+ }
+ if (transform.position.x > 990) {
+ rb.data.linear_velocity.x *= -1;
+ }
+
+ if (rb.data.linear_velocity.x < 0) {
+ npc.data.flip = {true, false};
+ } else {
+ npc.data.flip = {false, false};
+ }
+
+ auto & savemgr = this->get_save_manager();
+ savemgr.set("npc_x", transform.position.x);
+ savemgr.set("npc_y", transform.position.y);
+}
diff --git a/game/preview/NpcScript.h b/game/preview/NpcScript.h
new file mode 100644
index 0000000..8d856fd
--- /dev/null
+++ b/game/preview/NpcScript.h
@@ -0,0 +1,11 @@
+
+#include <crepe/api/Script.h>
+
+class NpcScript : public crepe::Script {
+
+private:
+
+public:
+ void init();
+ void fixed_update(crepe::duration_t dt);
+};
diff --git a/game/preview/NpcSubScene.cpp b/game/preview/NpcSubScene.cpp
new file mode 100644
index 0000000..bd6cfb2
--- /dev/null
+++ b/game/preview/NpcSubScene.cpp
@@ -0,0 +1,69 @@
+
+
+#include "NpcSubScene.h"
+
+#include "../Config.h"
+#include "NpcScript.h"
+
+#include <crepe/ValueBroker.h>
+#include <crepe/api/Animator.h>
+#include <crepe/api/BehaviorScript.h>
+#include <crepe/api/Scene.h>
+#include <crepe/api/Sprite.h>
+#include <crepe/manager/SaveManager.h>
+
+using namespace crepe;
+
+NpcSubScene::NpcSubScene(Scene & scn) {
+ auto & savemgr = scn.get_save_manager();
+ ValueBroker npc_x = savemgr.get<float>("npc_x", 500);
+ ValueBroker npc_y = savemgr.get<float>("npc_y", 0);
+
+ GameObject npc = scn.new_object("npc", "npc_tag", vec2 {npc_x.get(), npc_y.get()}, 0, 1);
+ Asset npc_body {"asset/workers/worker1Body.png"};
+ Asset npc_head {"asset/workers/worker1Head.png"};
+
+ auto & npc_body_sprite = npc.add_component<Sprite>(
+ npc_body,
+ Sprite::Data {
+ .sorting_in_layer = SORT_IN_LAY_PLAYER,
+ .size = {0, 50},
+ }
+ );
+ auto & npc_head_sprite = npc.add_component<Sprite>(
+ npc_head,
+ Sprite::Data {
+ .sorting_in_layer = SORT_IN_LAY_PLAYER,
+ .size = {0, 50},
+ .position_offset = {0, -20},
+ }
+ );
+
+ npc.add_component<Animator>(
+ npc_body_sprite, ivec2 {32, 32}, uvec2 {4, 8},
+ Animator::Data {
+ .fps = 5,
+ .looping = true,
+ }
+ );
+ npc.add_component<Animator>(
+ npc_head_sprite, ivec2 {32, 32}, uvec2 {4, 8},
+ Animator::Data {
+ .fps = 5,
+ .looping = true,
+ }
+ );
+ npc.add_component<BoxCollider>(vec2 {50, 50});
+
+ npc.add_component<Rigidbody>(Rigidbody::Data {
+ .mass = 10,
+ .gravity_scale = 1,
+ .body_type = Rigidbody::BodyType::DYNAMIC,
+ .linear_velocity = {-50, 0},
+ //.max_linear_velocity = 40,
+ .collision_layers = {COLL_LAY_BOT_TOP, COLL_LAY_PLAYER},
+ .collision_layer = COLL_LAY_PLAYER,
+ });
+
+ npc.add_component<BehaviorScript>().set_script<NpcScript>();
+}
diff --git a/game/preview/NpcSubScene.h b/game/preview/NpcSubScene.h
new file mode 100644
index 0000000..a226195
--- /dev/null
+++ b/game/preview/NpcSubScene.h
@@ -0,0 +1,10 @@
+#pragma once
+
+namespace crepe {
+class Scene;
+}
+
+class NpcSubScene {
+public:
+ NpcSubScene(crepe::Scene & scn);
+};
diff --git a/game/preview/PrevPlayerScript.cpp b/game/preview/PrevPlayerScript.cpp
new file mode 100644
index 0000000..2657b8d
--- /dev/null
+++ b/game/preview/PrevPlayerScript.cpp
@@ -0,0 +1,132 @@
+#include "PrevPlayerScript.h"
+
+#include "../missile/SpawnEvent.h"
+#include "api/Transform.h"
+#include <crepe/api/AudioSource.h>
+#include <crepe/api/Camera.h>
+#include <crepe/manager/SaveManager.h>
+#include <iostream>
+#include <ostream>
+
+using namespace crepe;
+
+bool PrevPlayerScript::key_pressed(const KeyPressEvent & ev) {
+ switch (ev.key) {
+ case Keycode::A:
+ this->get_component<Rigidbody>().data.linear_velocity.x = -move_speed;
+ this->body->data.flip = {true, false};
+ this->head->data.flip = {true, false};
+ break;
+ case Keycode::D:
+ this->get_component<Rigidbody>().data.linear_velocity.x = move_speed;
+ this->body->data.flip = {false, false};
+ this->head->data.flip = {false, false};
+ break;
+
+ case Keycode::SPACE:
+ this->get_component<Rigidbody>().data.linear_velocity.y = -move_speed;
+ break;
+ case Keycode::D0:
+ this->body_anim->set_anim(0);
+ this->head_anim->set_anim(0);
+ break;
+ case Keycode::D1:
+ this->body_anim->set_anim(1);
+ this->head_anim->set_anim(1);
+ break;
+ case Keycode::D2:
+ this->body_anim->set_anim(2);
+ this->head_anim->set_anim(2);
+ break;
+ case Keycode::D3:
+ this->body_anim->set_anim(3);
+ this->head_anim->set_anim(3);
+ break;
+ case Keycode::D4:
+ this->body_anim->set_anim(4);
+ this->head_anim->set_anim(4);
+ break;
+ case Keycode::D5:
+ this->body_anim->set_anim(5);
+ this->head_anim->set_anim(5);
+ break;
+ case Keycode::D6:
+ this->body_anim->set_anim(6);
+ this->head_anim->set_anim(6);
+ break;
+ case Keycode::D7:
+ this->body_anim->set_anim(7);
+ this->head_anim->set_anim(7);
+ break;
+ case Keycode::LEFT:
+ this->head->data.angle_offset -= 1;
+ break;
+ case Keycode::RIGHT:
+ this->head->data.angle_offset += 1;
+ break;
+ case Keycode::UP:
+ this->head->data.scale_offset += 0.1;
+ break;
+ case Keycode::DOWN:
+ this->head->data.scale_offset -= 0.1;
+ break;
+ case Keycode::P:
+ this->get_component<AudioSource>().play();
+ break;
+ case Keycode::Q:
+ this->get_components_by_name<Camera>("camera").front().get().data.zoom -= 0.01;
+ break;
+ case Keycode::E:
+ this->get_components_by_name<Camera>("camera").front().get().data.zoom += 0.01;
+ break;
+ case Keycode::J:
+ this->get_components_by_name<Transform>("camera").front().get().position.x
+ -= move_speed;
+ break;
+ case Keycode::K:
+ this->get_components_by_name<Transform>("camera").front().get().position.y
+ -= move_speed;
+ break;
+ case Keycode::L:
+ this->get_components_by_name<Transform>("camera").front().get().position.x
+ += move_speed;
+ break;
+ case Keycode::I:
+ this->get_components_by_name<Transform>("camera").front().get().position.y
+ += move_speed;
+ break;
+ case Keycode::M:
+ trigger_event<MissileSpawnEvent>(MissileSpawnEvent {});
+ break;
+ //todo
+ case Keycode::PAGE_UP:
+ case Keycode::PAGE_DOWN:
+ case Keycode::HOME:
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+void PrevPlayerScript::init() {
+ auto animations = this->get_components<Animator>();
+ body_anim = animations[0];
+ head_anim = animations[1];
+
+ auto sprites = this->get_components<Sprite>();
+ body = sprites[0];
+ head = sprites[1];
+
+ subscribe<KeyPressEvent>([this](const KeyPressEvent & ev) -> bool {
+ return this->key_pressed(ev);
+ });
+};
+
+void PrevPlayerScript::fixed_update(crepe::duration_t dt) {
+ auto & savemgr = this->get_save_manager();
+ const auto & pos = this->get_component<Transform>().position;
+
+ savemgr.set("player_x", pos.x);
+ savemgr.set("player_y", pos.y);
+};
diff --git a/game/preview/PrevPlayerScript.h b/game/preview/PrevPlayerScript.h
new file mode 100644
index 0000000..cc3184e
--- /dev/null
+++ b/game/preview/PrevPlayerScript.h
@@ -0,0 +1,23 @@
+
+#include <crepe/api/Event.h>
+#include <crepe/api/Script.h>
+#include <crepe/util/OptionalRef.h>
+
+#include <crepe/api/Animator.h>
+#include <crepe/api/Sprite.h>
+
+class PrevPlayerScript : public crepe::Script {
+private:
+ crepe::OptionalRef<crepe::Animator> head_anim;
+ crepe::OptionalRef<crepe::Animator> body_anim;
+ crepe::OptionalRef<crepe::Sprite> head;
+ crepe::OptionalRef<crepe::Sprite> body;
+
+private:
+ float move_speed = 100;
+
+private:
+ void init();
+ void fixed_update(crepe::duration_t dt);
+ bool key_pressed(const crepe::KeyPressEvent & ev);
+};
diff --git a/game/preview/PrevPlayerSubScene.cpp b/game/preview/PrevPlayerSubScene.cpp
new file mode 100644
index 0000000..b59a0af
--- /dev/null
+++ b/game/preview/PrevPlayerSubScene.cpp
@@ -0,0 +1,86 @@
+
+#include "PrevPlayerSubScene.h"
+
+#include "../Config.h"
+#include "PrevPlayerScript.h"
+
+#include <crepe/api/Animator.h>
+#include <crepe/api/AudioSource.h>
+#include <crepe/api/BehaviorScript.h>
+#include <crepe/api/Scene.h>
+#include <crepe/api/Sprite.h>
+
+#include <crepe/ValueBroker.h>
+#include <crepe/manager/SaveManager.h>
+
+using namespace crepe;
+
+PrevPlayerSubScene::PrevPlayerSubScene(Scene & scn) {
+ auto & savemgr = scn.get_save_manager();
+
+ ValueBroker player_x = savemgr.get<float>("player_x", 500);
+ ValueBroker player_y = savemgr.get<float>("player_y", -100);
+
+ GameObject player
+ = scn.new_object("player", "TAG", vec2 {player_x.get(), player_y.get()}, 0, 1);
+ Asset player_body_asset {"asset/barry/defaultBody.png"};
+ Sprite & player_body_sprite = player.add_component<Sprite>(
+ player_body_asset,
+ Sprite::Data {
+ .sorting_in_layer = SORT_IN_LAY_PLAYER,
+ .order_in_layer = 0,
+ .size = vec2(0, 50),
+ }
+ );
+ player.add_component<Animator>(
+ player_body_sprite, ivec2(32, 32), uvec2(4, 8),
+ Animator::Data {
+ .fps = 5,
+ .looping = true,
+ }
+ );
+ Asset player_head_asset {"asset/barry/defaultHead.png"};
+ Sprite & player_head_sprite = player.add_component<Sprite>(
+ player_head_asset,
+ Sprite::Data {
+ .sorting_in_layer = SORT_IN_LAY_PLAYER,
+ .order_in_layer = 1,
+ .size = vec2(0, 50),
+ .position_offset = vec2(0, -20),
+ }
+ );
+ player.add_component<Animator>(
+ player_head_sprite, ivec2(32, 32), uvec2(4, 8),
+ Animator::Data {
+ .fps = 5,
+ .looping = true,
+ }
+ );
+ Asset player_jetpack_asset {"asset/barry/jetpackDefault.png"};
+ Sprite & player_jetpack_sprite = player.add_component<Sprite>(
+ player_jetpack_asset,
+ Sprite::Data {
+ .sorting_in_layer = SORT_IN_LAY_PLAYER,
+ .order_in_layer = 2,
+ .size = vec2(0, 60),
+ .position_offset = vec2(-20, 0),
+ }
+ );
+ player_jetpack_sprite.active = false;
+ player.add_component<Animator>(
+ player_jetpack_sprite, ivec2(32, 44), uvec2(4, 4),
+ Animator::Data {
+ .fps = 5,
+ .looping = true,
+ }
+ );
+ player.add_component<Rigidbody>(Rigidbody::Data {
+ .gravity_scale = 20,
+ .body_type = Rigidbody::BodyType::DYNAMIC,
+ .linear_velocity = vec2(100, 0),
+ .collision_layers = {COLL_LAY_BOT_TOP},
+ .collision_layer = COLL_LAY_PLAYER,
+ });
+ player.add_component<BoxCollider>(vec2(50, 50));
+ player.add_component<BehaviorScript>().set_script<PrevPlayerScript>();
+}
diff --git a/game/preview/PrevPlayerSubScene.h b/game/preview/PrevPlayerSubScene.h
new file mode 100644
index 0000000..a61f341
--- /dev/null
+++ b/game/preview/PrevPlayerSubScene.h
@@ -0,0 +1,10 @@
+#pragma once
+
+namespace crepe {
+class Scene;
+}
+
+class PrevPlayerSubScene {
+public:
+ PrevPlayerSubScene(crepe::Scene & scn);
+};
diff --git a/game/preview/SmokeSubScene.cpp b/game/preview/SmokeSubScene.cpp
new file mode 100644
index 0000000..e363f95
--- /dev/null
+++ b/game/preview/SmokeSubScene.cpp
@@ -0,0 +1,37 @@
+
+#include "SmokeSubScene.h"
+
+#include "../Config.h"
+
+#include <crepe/api/ParticleEmitter.h>
+#include <crepe/api/Scene.h>
+#include <crepe/api/Sprite.h>
+
+using namespace crepe;
+
+SmokeSubScene::SmokeSubScene(Scene & scn) {
+ GameObject smoke = scn.new_object("smoke_particle", "TAG", vec2 {500, -210}, 0, 1);
+
+ Asset smoke_ss {"asset/particles/smoke.png"};
+
+ auto & smoke_sprite = smoke.add_component<Sprite>(
+ smoke_ss,
+ Sprite::Data {
+ .sorting_in_layer = SORT_IN_LAY_PARTICLES_FOREGROUND,
+ .size = {0, 30},
+ }
+ );
+
+ smoke.add_component<ParticleEmitter>(
+ smoke_sprite,
+ ParticleEmitter::Data {
+ .offset = {0, -60},
+ .max_particles = 10,
+ .emission_rate = 25,
+ .min_angle = 60,
+ .max_angle = 120,
+ .begin_lifespan = 1,
+ .end_lifespan = 2,
+ }
+ );
+}
diff --git a/game/preview/SmokeSubScene.h b/game/preview/SmokeSubScene.h
new file mode 100644
index 0000000..93d8a2d
--- /dev/null
+++ b/game/preview/SmokeSubScene.h
@@ -0,0 +1,10 @@
+#pragma once
+
+namespace crepe {
+class Scene;
+}
+
+class SmokeSubScene {
+public:
+ SmokeSubScene(crepe::Scene & scn);
+};
diff --git a/game/scheduler/ObjectsScheduler.cpp b/game/scheduler/ObjectsScheduler.cpp
new file mode 100644
index 0000000..3ce2018
--- /dev/null
+++ b/game/scheduler/ObjectsScheduler.cpp
@@ -0,0 +1,77 @@
+
+
+#include "ObjectsScheduler.h"
+
+#include "../Config.h"
+#include "../Random.h"
+#include "../missile/SpawnEvent.h"
+#include "api/Rigidbody.h"
+#include "api/Transform.h"
+#include "enemy/BattleScript.h"
+#include "prefab/ZapperPoolSubScene.h"
+
+using namespace crepe;
+void ObjectsScheduler::preset_0() {
+ trigger_event<MissileSpawnEvent>(MissileSpawnEvent {});
+ trigger_event<MissileSpawnEvent>(MissileSpawnEvent {});
+}
+void ObjectsScheduler::preset_1() { trigger_event<MissileSpawnEvent>(MissileSpawnEvent {}); }
+void ObjectsScheduler::preset_2() { trigger_event<CreateZapperEvent>(CreateZapperEvent {}); }
+void ObjectsScheduler::preset_3() { trigger_event<CreateZapperEvent>(CreateZapperEvent {}); }
+void ObjectsScheduler::preset_4() {}
+void ObjectsScheduler::boss_fight_1() {
+ this->get_components_by_name<Rigidbody>("camera").front().get().data.linear_velocity.x = 0;
+ this->get_components_by_name<Rigidbody>("player").front().get().data.linear_velocity.x = 0;
+ this->trigger_event<BattleStartEvent>(BattleStartEvent {.num_enemies = 2});
+
+ RefVector<Rigidbody> rb_back_forest
+ = this->get_components_by_tag<Rigidbody>("forest_background");
+ for (Rigidbody & rb : rb_back_forest) {
+ rb.data.linear_velocity.x = 0;
+ }
+}
+
+bool ObjectsScheduler::boss_fight_1_event() {
+ this->get_components_by_name<Rigidbody>("camera").front().get().data.linear_velocity.x
+ = PLAYER_SPEED * 0.02;
+ this->get_components_by_name<Rigidbody>("player").front().get().data.linear_velocity.x
+ = PLAYER_SPEED * 0.02;
+
+ 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;
+
+ return false;
+}
+
+void ObjectsScheduler::init() {
+ this->obstacles.push_back([this]() { preset_0(); });
+ this->obstacles.push_back([this]() { preset_1(); });
+ this->obstacles.push_back([this]() { preset_2(); });
+ this->obstacles.push_back([this]() { preset_3(); });
+ this->obstacles.push_back([this]() { preset_4(); });
+
+ this->obstacles.push_back([this]() { boss_fight_1(); });
+
+ // subscribe to battlewonevent
+ this->subscribe<BattleWonEvent>([this](const BattleWonEvent & ev) -> bool {
+ return this->boss_fight_1_event();
+ });
+}
+
+void ObjectsScheduler::fixed_update(duration_t dt) {
+ int pos_x
+ = (int) this->get_components_by_name<Transform>("camera").front().get().position.x;
+
+ int boss_check = (pos_x - this->start_offset) / this->boss_fight_interval;
+ if (boss_check > this->last_boss_check) {
+ this->obstacles.back()();
+ this->last_boss_check = boss_check;
+ }
+ int obstacle_check = (pos_x - this->start_offset) / this->obstacle_interval;
+ if (obstacle_check > this->last_obstacle_check) {
+ this->obstacles[Random::i(this->obstacles.size() - 1, 0)]();
+ this->last_obstacle_check = obstacle_check;
+ }
+}
diff --git a/game/scheduler/ObjectsScheduler.h b/game/scheduler/ObjectsScheduler.h
new file mode 100644
index 0000000..bd0701b
--- /dev/null
+++ b/game/scheduler/ObjectsScheduler.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "api/Script.h"
+#include <functional>
+#include <vector>
+
+class ObjectsScheduler : public crepe::Script {
+
+private:
+ std::vector<std::function<void()>> obstacles;
+
+ int last_boss_check = 0;
+ int last_obstacle_check = 0;
+
+ int boss_fight_interval = 5000;
+ int obstacle_interval = 350;
+ int start_offset = 1300;
+
+private:
+ void preset_0();
+ void preset_1();
+ void preset_2();
+ void preset_3();
+ void preset_4();
+ void boss_fight_1();
+
+ bool boss_fight_1_event();
+
+public:
+ void init();
+ void fixed_update(crepe::duration_t dt);
+};
diff --git a/game/workers/CollisionScript.cpp b/game/workers/CollisionScript.cpp
index deaf0ee..372bfec 100644
--- a/game/workers/CollisionScript.cpp
+++ b/game/workers/CollisionScript.cpp
@@ -49,7 +49,8 @@ bool CollisionScript::on_collision(const CollisionEvent & ev) {
bs_panic.active = false;
return false;
- } else if (ev.info.other.metadata.tag == "missile") {
+ } else if (ev.info.other.metadata.tag == "missile"
+ || ev.info.other.metadata.tag == "enemy_bullet") {
for (Animator & anim : animators) {
anim.active = false;
anim.set_anim(3);
diff --git a/src/crepe/api/Color.cpp b/src/crepe/api/Color.cpp
index 1374198..d0e3b35 100644
--- a/src/crepe/api/Color.cpp
+++ b/src/crepe/api/Color.cpp
@@ -11,3 +11,4 @@ const Color Color::CYAN {0x00, 0xff, 0xff};
const Color Color::YELLOW {0xff, 0xff, 0x00};
const Color Color::MAGENTA {0xff, 0x00, 0xff};
const Color Color::GREY {0x80, 0x80, 0x80};
+const Color Color::GOLD {249, 205, 91};
diff --git a/src/crepe/api/Color.h b/src/crepe/api/Color.h
index 22c0c43..dbfd0ed 100644
--- a/src/crepe/api/Color.h
+++ b/src/crepe/api/Color.h
@@ -19,6 +19,7 @@ struct Color {
static const Color YELLOW;
static const Color BLACK;
static const Color GREY;
+ static const Color GOLD;
};
} // namespace crepe
diff --git a/src/crepe/api/Text.cpp b/src/crepe/api/Text.cpp
index e5b623d..e5cc39d 100644
--- a/src/crepe/api/Text.cpp
+++ b/src/crepe/api/Text.cpp
@@ -3,6 +3,7 @@
#include "Text.h"
using namespace crepe;
+using namespace std;
Text::Text(
game_object_id_t id, const vec2 & dimensions, const std::string & font_family,
@@ -12,3 +13,15 @@ Text::Text(
text(text),
data(data),
font_family(font_family) {}
+
+unique_ptr<Component> Text::save() const { return unique_ptr<Component>(new Text(*this)); }
+
+void Text::restore(const Component & snapshot) { *this = static_cast<const Text &>(snapshot); }
+
+Text & Text::operator=(const Text & snapshot) {
+ this->active = snapshot.active;
+ this->data = snapshot.data;
+ this->text = snapshot.text;
+ this->font_family = snapshot.font_family;
+ return *this;
+}
diff --git a/src/crepe/api/Text.h b/src/crepe/api/Text.h
index 8b3d53e..859490e 100644
--- a/src/crepe/api/Text.h
+++ b/src/crepe/api/Text.h
@@ -49,6 +49,12 @@ public:
std::optional<Asset> font;
//! Data instance
Data data;
+
+protected:
+ virtual std::unique_ptr<Component> save() const;
+ Text(const Text &) = default;
+ virtual void restore(const Component & snapshot);
+ virtual Text & operator=(const Text &);
};
} // namespace crepe