diff options
Diffstat (limited to 'game')
45 files changed, 1507 insertions, 72 deletions
diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index 0955985..ef82339 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -8,6 +8,7 @@ project(game C CXX) add_subdirectory(../src crepe) add_executable(main + # enemy enemy/BattleScript.cpp enemy/EnemyPool.cpp enemy/EnemyBulletScript.cpp @@ -15,29 +16,61 @@ add_executable(main 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 player/PlayerBulletPool.cpp player/PlayerBulletScript.cpp player/PlayerBulletSubScene.cpp - StartGameScript.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 @@ -46,22 +79,30 @@ add_executable(main menus/ButtonNextMainMenuSubScript.cpp menus/FloatingWindowSubScene.cpp menus/IFloatingWindowScript.cpp - menus/shop/ShopMenuScene.cpp menus/mainmenu/ButtonTransitionPreviewSubScript.cpp menus/mainmenu/ITransitionScript.cpp - menus/mainmenu/MainMenuScene.cpp menus/mainmenu/TransitionStartSubScript.cpp menus/endgame/EndGameSubScene.cpp menus/endgame/EndGameSubScript.cpp + + # coins coins/CoinSubScene.cpp coins/CoinPoolSubScene.cpp coins/CoinSystemScript.cpp coins/CoinScript.cpp + + # hud hud/HudSubScene.cpp hud/HudScript.cpp hud/SpeedScript.cpp + + #random Random.cpp ) +add_subdirectory(background) +add_subdirectory(prefab) + target_link_libraries(main PUBLIC crepe) +target_include_directories(main PRIVATE .) diff --git a/game/Config.h b/game/Config.h index 7cca586..c698420 100644 --- a/game/Config.h +++ b/game/Config.h @@ -1,6 +1,17 @@ #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", + }, +}; + static constexpr int SORT_IN_LAY_BACK_BACKGROUND = 3; // For all scenes static constexpr int SORT_IN_LAY_BACKGROUND = 4; // For all scenes static constexpr int SORT_IN_LAY_FORE_BACKGROUND = 5; // For all scenes @@ -24,11 +35,12 @@ static constexpr int COLL_LAY_BULLET = 9; // Only for GameScene static constexpr int COLL_LAY_ENEMY = 10; // Only for GameScene static constexpr int COLL_LAY_PLAYER_BULLET = 11; // Only for GameScene -static constexpr int GAME_HEIGHT = 800; // In game units +static constexpr float GAME_HEIGHT = 800; // In game units +static constexpr float HALLWAY_HEIGHT = 475; // In game units -static constexpr int VIEWPORT_X = 1100; // In game units +static constexpr float VIEWPORT_X = 1100; // In game units // 'GAME_HEIGHT' (below) should be replaced by '500' when game development is finished -static constexpr int VIEWPORT_Y = 500; // In game units +static constexpr float VIEWPORT_Y = 500; // In game units // Font settings static constexpr const char * FONT = "Jetpackia"; @@ -48,3 +60,6 @@ static constexpr const char * DISTANCE_RUN = "distance_run"; 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 const char* CAMERA_NAME = "camera"; + diff --git a/game/GameScene.cpp b/game/GameScene.cpp index d4d07ec..a255e17 100644 --- a/game/GameScene.cpp +++ b/game/GameScene.cpp @@ -14,9 +14,13 @@ #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 "scheduler/ObjectsScheduler.h" +#include "prefab/ZapperPoolSubScene.h" #include "workers/WorkersSubScene.h" #include <cmath> @@ -41,19 +45,24 @@ using namespace crepe; using namespace std; void GameScene::load_scene() { + logf(Log::DEBUG, "Loading (main) GameScene..."); + BackgroundSubScene background(*this); - GameObject camera = new_object("camera", "camera", vec2(650, 0)); - Camera & camera_cam = camera.add_component<Camera>( + GameObject camera = new_object(CAMERA_NAME, "camera", vec2(650, 0)); + camera.add_component<Camera>( ivec2(990, 720), vec2(VIEWPORT_X, VIEWPORT_Y), Camera::Data { - .bg_color = Color::RED, + .bg_color = Color::BLACK, } ); camera.add_component<BehaviorScript>().set_script<MoveCameraManualyScript>(); camera.add_component<BehaviorScript>().set_script<CoinSystemScript>(); camera.add_component<BehaviorScript>().set_script<HudScript>(); camera.add_component<BehaviorScript>().set_script<SpeedScript>(); + camera.add_component<BehaviorScript>().set_script<ObjectsScheduler>(); + camera.add_component<BehaviorScript>().set_script<MissileSpawnEventHandler>(); + camera.add_component<BehaviorScript>().set_script<BattleScript>(); camera.add_component<Rigidbody>(Rigidbody::Data {}); AI & enemy_path_1 = camera.add_component<AI>(400); @@ -65,6 +74,8 @@ void GameScene::load_scene() { // camer.add_component<AI> PlayerSubScene player(*this); + MissilePool missile_pool(*this); + WorkersSubScene workers(*this); GameObject floor = new_object("floor", "game_world", vec2(0, 325)); @@ -91,6 +102,8 @@ void GameScene::load_scene() { }); ceiling.add_component<BoxCollider>(vec2(INFINITY, 200)); + ZapperPoolSubScene {*this}; + GameObject start_game_script = new_object("start_game_script", "script", vec2(0, 0)); start_game_script.add_component<BehaviorScript>().set_script<StartGameScript>(); @@ -105,6 +118,7 @@ void GameScene::load_scene() { enemy_pool.create_enemies(*this); HudSubScene hud; hud.create(*this); + GameObject background_music = new_object("background_music", "audio", vec2(0, 0)); Asset background_music_asset {"asset/music/level.ogg"}; background_music.add_component<AudioSource>(background_music_asset); @@ -113,55 +127,6 @@ void GameScene::load_scene() { Asset boom_audio_asset {"asset/sfx/window_smash.ogg"}; boom_audio.add_component<AudioSource>(boom_audio_asset); - // zapper, laser and missile (below) for testing purpose only!!! - GameObject zapper = new_object("zapper", "zapper", vec2(1000, 200)); - Asset zapper_asset {"asset/obstacles/zapper/regular_zappers/zapEffect.png"}; - Sprite & zapper_sprite = zapper.add_component<Sprite>( - zapper_asset, - Sprite::Data { - .sorting_in_layer = SORT_IN_LAY_OBSTACLES, - .order_in_layer = 0, - .size = vec2(100, 100), - } - ); - zapper.add_component<Rigidbody>(Rigidbody::Data { - .body_type = Rigidbody::BodyType::KINEMATIC, - .kinematic_collision = false, - .collision_layer = COLL_LAY_ZAPPER, - }); - zapper.add_component<BoxCollider>(vec2(100, 100)); - GameObject laser = new_object("laser", "laser", vec2(2000, 200)); - Asset laser_asset {"asset/obstacles/laser/laserPower.png"}; - Sprite & laser_sprite = laser.add_component<Sprite>( - laser_asset, - Sprite::Data { - .sorting_in_layer = SORT_IN_LAY_OBSTACLES, - .order_in_layer = 0, - .size = vec2(100, 100), - } - ); - laser.add_component<Rigidbody>(Rigidbody::Data { - .body_type = Rigidbody::BodyType::KINEMATIC, - .kinematic_collision = false, - .collision_layer = COLL_LAY_LASER, - }); - laser.add_component<BoxCollider>(vec2(100, 100)); - GameObject missile = new_object("missile", "missile", vec2(4000, 200)); - Asset missile_asset {"asset/obstacles/missile/missile.png"}; - Sprite & missile_sprite = missile.add_component<Sprite>( - missile_asset, - Sprite::Data { - .sorting_in_layer = SORT_IN_LAY_OBSTACLES, - .order_in_layer = 0, - .size = vec2(100, 100), - } - ); - missile.add_component<Rigidbody>(Rigidbody::Data { - .body_type = Rigidbody::BodyType::KINEMATIC, - .kinematic_collision = false, - .collision_layer = COLL_LAY_MISSILE, - }); - missile.add_component<BoxCollider>(vec2(100, 100)); EndGameSubScene endgamewindow; endgamewindow.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/Random.cpp b/game/Random.cpp index ace6245..821ddc8 100644 --- a/game/Random.cpp +++ b/game/Random.cpp @@ -25,3 +25,8 @@ unsigned Random::u(unsigned upper, unsigned lower) { unsigned x = rand() % range; return x + lower; } + +bool Random::b() { + return rand() % 2; +} + diff --git a/game/Random.h b/game/Random.h index 8af9669..0f0f79b 100644 --- a/game/Random.h +++ b/game/Random.h @@ -6,4 +6,6 @@ public: static double d(double upper = 1.0, double lower = 0.0); static int i(int upper, int lower = 0); static unsigned u(unsigned upper, unsigned lower = 0); + static bool b(); + }; diff --git a/game/background/AquariumSubScene.cpp b/game/background/AquariumSubScene.cpp index 99466e3..2a07daf 100644 --- a/game/background/AquariumSubScene.cpp +++ b/game/background/AquariumSubScene.cpp @@ -4,6 +4,7 @@ #include <crepe/api/Animator.h> #include <crepe/api/GameObject.h> +#include <crepe/api/ParticleEmitter.h> #include <crepe/api/Scene.h> #include <crepe/api/Sprite.h> #include <crepe/types.h> @@ -41,6 +42,9 @@ float AquariumSubScene::create(Scene & scn, float begin_x) { begin_x += 400; this->add_background(scn, begin_x - 200); + this->add_bubbles(aquarium_middle_1, vec2(-400, 300), 2, 0.7f); + this->add_bubbles(aquarium_middle_1, vec2(-100, 300), 4, 1.0f); + this->add_bubbles(aquarium_middle_1, vec2(500, 300), 4, 0.9f); GameObject aquarium_middle_2 = scn.new_object("aquarium_middle", "background_aqua", vec2(begin_x, 0)); @@ -55,6 +59,8 @@ float AquariumSubScene::create(Scene & scn, float begin_x) { ); begin_x += 400; + this->add_bubbles(aquarium_middle_2, vec2(300, 300), 2, 0.6f); + GameObject aquarium_middle_3 = scn.new_object("aquarium_middle", "background_aqua", vec2(begin_x, 0)); Asset aquarium_middle_3_asset {"asset/background/aquarium/glassTubeFG_3_TVOS.png"}; @@ -84,6 +90,8 @@ float AquariumSubScene::create(Scene & scn, float begin_x) { begin_x += 600; this->add_background(scn, begin_x); + this->add_bubbles(aquarium_middle_4, vec2(175, 300), 4, 1.0f); + this->add_bubbles(aquarium_middle_4, vec2(200, 300), 4, 0.7f); GameObject aquarium_end = scn.new_object("aquarium_end", "background_aqua", vec2(begin_x, 0)); @@ -108,7 +116,7 @@ void AquariumSubScene::add_background(Scene & scn, float begin_x) { bg_1_1_asset, Sprite::Data { .sorting_in_layer = SORT_IN_LAY_BACK_BACKGROUND, - .order_in_layer = 2, + .order_in_layer = 5, .size = vec2(0, 400), .position_offset = vec2(-200, 100), } @@ -118,7 +126,7 @@ void AquariumSubScene::add_background(Scene & scn, float begin_x) { bg_1_2_asset, Sprite::Data { .sorting_in_layer = SORT_IN_LAY_BACK_BACKGROUND, - .order_in_layer = 2, + .order_in_layer = 5, .size = vec2(0, 400), .position_offset = vec2(200, 100), } @@ -129,7 +137,7 @@ void AquariumSubScene::add_background(Scene & scn, float begin_x) { bg_2_1_asset, Sprite::Data { .sorting_in_layer = SORT_IN_LAY_BACK_BACKGROUND, - .order_in_layer = 1, + .order_in_layer = 3, .size = vec2(0, 400), .position_offset = vec2(200, -50), } @@ -139,7 +147,7 @@ void AquariumSubScene::add_background(Scene & scn, float begin_x) { bg_2_2_asset, Sprite::Data { .sorting_in_layer = SORT_IN_LAY_BACK_BACKGROUND, - .order_in_layer = 1, + .order_in_layer = 3, .size = vec2(0, 400), .position_offset = vec2(-200, -50), } @@ -150,7 +158,7 @@ void AquariumSubScene::add_background(Scene & scn, float begin_x) { bg_3_1_asset, Sprite::Data { .sorting_in_layer = SORT_IN_LAY_BACK_BACKGROUND, - .order_in_layer = 0, + .order_in_layer = 1, .size = vec2(0, 400), .position_offset = vec2(200, -200), } @@ -160,9 +168,58 @@ void AquariumSubScene::add_background(Scene & scn, float begin_x) { bg_3_2_asset, Sprite::Data { .sorting_in_layer = SORT_IN_LAY_BACK_BACKGROUND, - .order_in_layer = 0, + .order_in_layer = 1, .size = vec2(0, 400), .position_offset = vec2(-200, -200), } ); } + +void AquariumSubScene::add_bubbles( + GameObject & obj, vec2 offset, int order_in_layer, float scale +) { + Sprite & sprite = obj.add_component<Sprite>( + Asset {"asset/background/aquarium/bubble.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_BACK_BACKGROUND, + .order_in_layer = order_in_layer, + .size = vec2(0, 12.5), + .scale_offset = scale, + } + ); + obj.add_component<ParticleEmitter>( + sprite, + ParticleEmitter::Data { + .offset = offset, + .max_particles = 20, + .emission_rate = 1.2, + .min_speed = 50, + .max_speed = 100, + .min_angle = 265, + .max_angle = 275, + .force_over_time = vec2(0, -50), + } + ); + Sprite & sprite_small = obj.add_component<Sprite>( + Asset {"asset/background/aquarium/bubble.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_BACK_BACKGROUND, + .order_in_layer = order_in_layer, + .size = vec2(0, 7.5), + .scale_offset = scale, + } + ); + obj.add_component<ParticleEmitter>( + sprite_small, + ParticleEmitter::Data { + .offset = offset, + .max_particles = 20, + .emission_rate = 0.8, + .min_speed = 50, + .max_speed = 100, + .min_angle = 265, + .max_angle = 275, + .force_over_time = vec2(0, -50), + } + ); +} diff --git a/game/background/AquariumSubScene.h b/game/background/AquariumSubScene.h index 2a188bc..9dbb04e 100644 --- a/game/background/AquariumSubScene.h +++ b/game/background/AquariumSubScene.h @@ -1,8 +1,11 @@ #pragma once +#include <crepe/types.h> + namespace crepe { class Scene; -} +class GameObject; +} // namespace crepe class AquariumSubScene { public: @@ -10,4 +13,6 @@ public: private: void add_background(crepe::Scene & scn, float begin_x); + void + add_bubbles(crepe::GameObject & obj, crepe::vec2 offset, int order_in_layer, float scale); }; diff --git a/game/background/CMakeLists.txt b/game/background/CMakeLists.txt new file mode 100644 index 0000000..1d705f5 --- /dev/null +++ b/game/background/CMakeLists.txt @@ -0,0 +1,9 @@ +target_sources(main PUBLIC + AquariumSubScene.cpp + BackgroundSubScene.cpp + ForestParallaxScript.cpp + ForestSubScene.cpp + HallwaySubScene.cpp + StartSubScene.cpp +) + diff --git a/game/coins/CoinScript.cpp b/game/coins/CoinScript.cpp index 90150b6..514f4de 100644 --- a/game/coins/CoinScript.cpp +++ b/game/coins/CoinScript.cpp @@ -5,6 +5,8 @@ #include "../Config.h" #include "../hud/HudScript.h" +#include <crepe/api/Animator.h> +#include <crepe/api/AudioSource.h> #include <crepe/api/CircleCollider.h> #include <crepe/api/Sprite.h> @@ -29,6 +31,24 @@ bool CoinScript::on_collision(const CollisionEvent & collisionData) { .active = false; this->amount++; + + AudioSource & audio = this->get_components_by_id<AudioSource>( + collisionData.info.other.metadata.game_object_id + ) + .front(); + audio.play(); + + this->get_components_by_name<Sprite>(collisionData.info.other.metadata.name) + .back() + .get() + .active + = true; + this->get_components_by_name<Animator>(collisionData.info.other.metadata.name) + .back() + .get() + .active + = true; + return false; } diff --git a/game/coins/CoinSubScene.cpp b/game/coins/CoinSubScene.cpp index 2c9feb6..d154819 100644 --- a/game/coins/CoinSubScene.cpp +++ b/game/coins/CoinSubScene.cpp @@ -39,6 +39,26 @@ int CoinSubScene::create(Scene & scn, int coin_counter) { .looping = true, } ); - coin.add_component<AudioSource>(Asset {"asset/sfx/coin_pickup_1.ogg"}); + coin.add_component<AudioSource>(Asset {"asset/sfx/coin_pickup_1.ogg"}).volume = 3; + + Sprite & pick_up = coin.add_component<Sprite>( + Asset {"asset/coin/coinCollect1_TVOS.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_COINS, + .order_in_layer = 1, + .size = size * 2, + } + ); + pick_up.active = false; + coin.add_component<Animator>( + pick_up, ivec2 {64, 64}, uvec2 {5, 1}, + Animator::Data { + .fps = 5, + .looping = false, + } + ) + .active + = false; + return coin_counter; } diff --git a/game/coins/CoinSystemScript.cpp b/game/coins/CoinSystemScript.cpp index 1634aa9..f9816c9 100644 --- a/game/coins/CoinSystemScript.cpp +++ b/game/coins/CoinSystemScript.cpp @@ -209,6 +209,10 @@ void CoinSystemScript::spawn_coins() { for (Sprite & coin_sprite : coin_sprites) { // Skip this sprite if it is already active if (coin_sprite.active) continue; + if (coin_sprite.data.order_in_layer == 1) { + coin_sprite.active = false; + continue; + } // Found an available (inactive) coin sprite // Retrieve its associated components diff --git a/game/main.cpp b/game/main.cpp index 858fad4..14eec99 100644 --- a/game/main.cpp +++ b/game/main.cpp @@ -1,18 +1,26 @@ +#include <cstdlib> + #include <crepe/api/Engine.h> #include <crepe/api/Script.h> +#include "Config.h" #include "GameScene.h" +#include "PreviewScene.h" #include "menus/mainmenu/MainMenuScene.h" #include "menus/shop/ShopMenuScene.h" using namespace crepe; int main() { - Engine gameloop; + srand(time(NULL)); + Config::get_instance() = ENGINE_CONFIG; + + Engine gameloop; gameloop.add_scene<MainMenuScene>(); gameloop.add_scene<ShopMenuScene>(); gameloop.add_scene<GameScene>(); + gameloop.add_scene<PreviewScene>(); return gameloop.main(); } diff --git a/game/menus/MenusConfig.h b/game/menus/MenusConfig.h index 6ec5689..3e357a5 100644 --- a/game/menus/MenusConfig.h +++ b/game/menus/MenusConfig.h @@ -3,10 +3,9 @@ //generic menu config static constexpr int STARTING_SORTING_IN_LAYER = 7; -static constexpr const char * CAMERA_NAME = "camera"; //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/mainmenu/ITransitionScript.cpp b/game/menus/mainmenu/ITransitionScript.cpp index cd929a0..3e51a90 100644 --- a/game/menus/mainmenu/ITransitionScript.cpp +++ b/game/menus/mainmenu/ITransitionScript.cpp @@ -2,6 +2,7 @@ #include "MainMenuConfig.h" #include "../MenusConfig.h" +#include "../../Config.h" #include <crepe/api/Camera.h> #include <crepe/api/Transform.h> diff --git a/game/menus/shop/ShopMenuScene.cpp b/game/menus/shop/ShopMenuScene.cpp index 21e3f02..d5b5af3 100644 --- a/game/menus/shop/ShopMenuScene.cpp +++ b/game/menus/shop/ShopMenuScene.cpp @@ -4,6 +4,7 @@ #include "../BannerSubScene.h" #include "../ButtonSubScene.h" #include "../MenusConfig.h" +#include "../../Config.h" #include <crepe/api/Camera.h> #include <crepe/api/Sprite.h> 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..db49f88 --- /dev/null +++ b/game/missile/MissileSubScene.cpp @@ -0,0 +1,101 @@ +#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.1; + auto & sound2 = missle.add_component<AudioSource>(explosion_sound); + sound2.volume = 0.1; + + // 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 { + .looping = true, + } + ); + + missle.add_component<Animator>( + missle_thruster_sprite, ivec2 {64, 64}, uvec2 {4, 2}, + Animator::Data { + .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(140, 200); + 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..ce301fd --- /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 / 1.8; + 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/prefab/CMakeLists.txt b/game/prefab/CMakeLists.txt new file mode 100644 index 0000000..6c36ef2 --- /dev/null +++ b/game/prefab/CMakeLists.txt @@ -0,0 +1,6 @@ +target_sources(main PUBLIC + ZapperObject.cpp + ZapperPoolSubScene.cpp + ZapperPoolScript.cpp +) + diff --git a/game/prefab/ZapperObject.cpp b/game/prefab/ZapperObject.cpp new file mode 100644 index 0000000..0a290e0 --- /dev/null +++ b/game/prefab/ZapperObject.cpp @@ -0,0 +1,122 @@ +#include <crepe/api/Transform.h> + +#include "Config.h" +#include "ZapperObject.h" + +using namespace crepe; + +ZapperObject::ZapperObject(crepe::GameObject && base) + : GameObject(std::move(base)), + sprite { + .orb_start = add_component<Sprite>( + Asset {"asset/obstacles/zapper/orbAnim.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_OBSTACLES, + .order_in_layer = 1, + .size = vec2(0, 50) * SCALE, + } + ), + .orb_end = add_component<Sprite>( + sprite.orb_start.source, + Sprite::Data { + .flip = {true, true}, + .sorting_in_layer = SORT_IN_LAY_OBSTACLES, + .order_in_layer = 1, + .size = vec2(0, 50) * SCALE, + } + ), + .glow_start = add_component<Sprite>( + Asset {"asset/obstacles/zapper/regular_zappers/glow.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_OBSTACLES, + .order_in_layer = -1, + .size = vec2(128, 128) * SCALE, + } + ), + .glow_end = add_component<Sprite>( + sprite.glow_start.source, + Sprite::Data { + .flip = {true, true}, + .sorting_in_layer = SORT_IN_LAY_OBSTACLES, + .order_in_layer = -1, + .size = vec2(128, 128) * SCALE, + } + ), + .beam = add_component<Sprite>( + Asset {"asset/obstacles/zapper/regular_zappers/zapEffect.png"}, + Sprite::Data { + .sorting_in_layer = SORT_IN_LAY_OBSTACLES, + .order_in_layer = 0, + .size = vec2(0, 40 * SCALE), + .angle_offset = 90, + } + ), + }, + animator { + .orb_start = add_component<Animator>( + sprite.orb_start, ivec2(62, 42), uvec2(4, 1), + Animator::Data { + .fps = 10, + .looping = true, + } + ), + .orb_end = add_component<Animator>( + sprite.orb_end, ivec2(62, 42), uvec2(4, 1), animator.orb_start.data + ), + .glow_start = add_component<Animator>( + sprite.glow_start, ivec2(128, 128), uvec2(16, 1), + Animator::Data { + .fps = 30, + .looping = true, + } + ), + .glow_end = add_component<Animator>( + sprite.glow_end, ivec2(128, 128), uvec2(16, 1), animator.glow_start.data + ), + }, + body {add_component<Rigidbody>(Rigidbody::Data { + .body_type = Rigidbody::BodyType::KINEMATIC, + .kinematic_collision = false, + .collision_layer = COLL_LAY_ZAPPER, + })}, + collider {add_component<BoxCollider>(vec2(0, 0))} { + this->set_active(false); + Log::logf(Log::DEBUG, "Creating zapper"); +} + +void ZapperObject::place(const crepe::vec2 & position, float rotation, float length) { + Log::logf(Log::DEBUG, "Placing zapper [position = {}, rotation = {}, length = {}]", position, rotation, length); + + this->transform.position = position; + this->transform.rotation = rotation; + + vec2 offset = vec2(0, 1) * length / 2; + + this->sprite.orb_start.data.position_offset = offset; + this->sprite.glow_start.data.position_offset = offset; + this->sprite.orb_end.data.position_offset = -offset; + this->sprite.glow_end.data.position_offset = -offset; + + this->sprite.beam.data.size.x = length; + + this->collider.dimensions = offset.rotate(rotation) * 2 + vec2(30, 30) * SCALE; +} + +void ZapperObject::set_active(bool active) { + this->sprite.orb_start.active = active; + this->sprite.orb_end.active = active; + this->sprite.glow_start.active = active; + this->sprite.glow_end.active = active; + this->sprite.beam.active = active; + + this->animator.orb_start.active = active; + this->animator.orb_end.active = active; + this->animator.glow_start.active = active; + this->animator.glow_end.active = active; + + this->body.active = active; + this->collider.active = active; + + this->active = active; +} + diff --git a/game/prefab/ZapperObject.h b/game/prefab/ZapperObject.h new file mode 100644 index 0000000..42edc51 --- /dev/null +++ b/game/prefab/ZapperObject.h @@ -0,0 +1,40 @@ +#pragma once + +#include <crepe/api/Animator.h> +#include <crepe/api/BoxCollider.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/Rigidbody.h> +#include <crepe/api/Sprite.h> + +class ZapperObject : public crepe::GameObject { +public: + ZapperObject(crepe::GameObject &&); + +public: + bool active = true; + + struct { + crepe::Sprite & orb_start; + crepe::Sprite & orb_end; + crepe::Sprite & glow_start; + crepe::Sprite & glow_end; + crepe::Sprite & beam; + } sprite; + + struct { + crepe::Animator & orb_start; + crepe::Animator & orb_end; + crepe::Animator & glow_start; + crepe::Animator & glow_end; + } animator; + + crepe::Rigidbody & body; + crepe::BoxCollider & collider; + +private: + static constexpr float SCALE = 0.8; + +public: + void place(const crepe::vec2 & position, float rotation, float length); + void set_active(bool active); +}; diff --git a/game/prefab/ZapperPoolScript.cpp b/game/prefab/ZapperPoolScript.cpp new file mode 100644 index 0000000..b9b2a76 --- /dev/null +++ b/game/prefab/ZapperPoolScript.cpp @@ -0,0 +1,69 @@ +#include <crepe/api/Camera.h> + +#include "../Config.h" +#include "../Random.h" + +#include "ZapperPoolScript.h" +#include "ZapperPoolSubScene.h" +#include "util/OptionalRef.h" + +using namespace crepe; +using namespace std; + +ZapperPoolScript::ZapperPoolScript(std::vector<ZapperObject> && pool) : pool(pool) {} + +void ZapperPoolScript::init() { + subscribe<CreateZapperEvent>([this](const CreateZapperEvent &) { + this->spawn_random(); + return true; + }); + + camera_transform = get_components_by_name<Transform>(CAMERA_NAME).back(); + camera_camera = get_components_by_name<Camera>(CAMERA_NAME).back(); +} + +void ZapperPoolScript::fixed_update(crepe::duration_t) { + float threshold = camera_transform->position.x - camera_camera->viewport_size.x / 2 - OFFSCREEN_MARGIN; + for (ZapperObject & zapper : this->pool) { + if (!zapper.active) continue; + + if (zapper.transform.position.x < threshold) + zapper.set_active(false); + } +} + +void ZapperPoolScript::spawn_random() { + OptionalRef<ZapperObject> zapper = this->get_next_zapper(); + if (!zapper) return; // pool exhausted + + vec2 pos = { + .x = camera_transform->position.x + camera_camera->viewport_size.x / 2 + OFFSCREEN_MARGIN, + .y = Random::f(0.5, -0.5) * HALLWAY_HEIGHT, + }; + + bool horizontal = Random::b(); + float rotation, length; + + if (horizontal) { + rotation = 90; + length = Random::f(400, 200); + } else { + rotation = 0; + length = Random::f(200, 50); + if (abs(pos.y) + length / 2 > HALLWAY_HEIGHT / 2) { + // TODO: fix offset + } + } + + zapper->place(pos, rotation, length); + zapper->set_active(true); +} + +OptionalRef<ZapperObject> ZapperPoolScript::get_next_zapper() { + for (ZapperObject & zapper : this->pool) { + if (zapper.active) continue; + return zapper; + } + return {}; +} + diff --git a/game/prefab/ZapperPoolScript.h b/game/prefab/ZapperPoolScript.h new file mode 100644 index 0000000..6aee8b2 --- /dev/null +++ b/game/prefab/ZapperPoolScript.h @@ -0,0 +1,33 @@ +#pragma once + +#include <crepe/api/Script.h> + +#include "ZapperObject.h" +#include "util/OptionalRef.h" + +class ZapperPoolSubScene; + +class ZapperPoolScript : public crepe::Script { +public: + ZapperPoolScript(std::vector<ZapperObject> && pool); + + void init(); + void fixed_update(crepe::duration_t); + + unsigned i = 0; + +private: + std::vector<ZapperObject> pool; + +private: + crepe::OptionalRef<crepe::Transform> camera_transform; + crepe::OptionalRef<crepe::Camera> camera_camera; + crepe::OptionalRef<ZapperObject> get_next_zapper(); + +private: + void spawn_random(); + +private: + static constexpr float OFFSCREEN_MARGIN = 40; +}; + diff --git a/game/prefab/ZapperPoolSubScene.cpp b/game/prefab/ZapperPoolSubScene.cpp new file mode 100644 index 0000000..e341090 --- /dev/null +++ b/game/prefab/ZapperPoolSubScene.cpp @@ -0,0 +1,19 @@ +#include <crepe/api/BehaviorScript.h> + +#include "ZapperPoolSubScene.h" +#include "ZapperPoolScript.h" + +using namespace crepe; +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")); + BehaviorScript & behavior = this->controller.add_component<BehaviorScript>(); + behavior.set_script<ZapperPoolScript>(std::move(pool)); +} + diff --git a/game/prefab/ZapperPoolSubScene.h b/game/prefab/ZapperPoolSubScene.h new file mode 100644 index 0000000..f930e22 --- /dev/null +++ b/game/prefab/ZapperPoolSubScene.h @@ -0,0 +1,19 @@ +#pragma once + +#include <crepe/api/Scene.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/Event.h> +#include <crepe/util/OptionalRef.h> + +class CreateZapperEvent : public crepe::Event {}; + +class ZapperPoolSubScene { +public: + ZapperPoolSubScene(crepe::Scene & scene); + +private: + crepe::GameObject controller; + +private: + static constexpr size_t POOL_SIZE = 4; +}; diff --git a/game/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..21465e3 --- /dev/null +++ b/game/scheduler/ObjectsScheduler.cpp @@ -0,0 +1,43 @@ + + +#include "ObjectsScheduler.h" + +#include "../Random.h" +#include "../missile/SpawnEvent.h" +#include "api/Transform.h" +#include "prefab/ZapperPoolSubScene.h" +#include <iostream> + +using namespace crepe; +void ObjectsScheduler::preset_0() { trigger_event<MissileSpawnEvent>(MissileSpawnEvent {}); } +void ObjectsScheduler::preset_1() { trigger_event<MissileSpawnEvent>(MissileSpawnEvent {}); } +void ObjectsScheduler::preset_2() { trigger_event<CreateZapperEvent>(CreateZapperEvent {}); } +void ObjectsScheduler::preset_3() {} +void ObjectsScheduler::preset_4() {} +void ObjectsScheduler::boss_fight_1() { std::cout << "Boss fight" << std::endl; } + +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]() { boss_fight_1(); }); + + // subscribe to battlewonevent +} + +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[2](); + 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..7bc9337 --- /dev/null +++ b/game/scheduler/ObjectsScheduler.h @@ -0,0 +1,34 @@ +#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 = 2500; + int obstacle_interval = 300; + int start_offset = 1300; + + + void preset_0(); + void preset_1(); + void preset_2(); + void preset_3(); + void preset_4(); + void boss_fight_1(); + +public: + void init(); + void fixed_update(crepe::duration_t dt); + +}; diff --git a/game/util/scrollgen b/game/util/scrollgen new file mode 100755 index 0000000..0389107 --- /dev/null +++ b/game/util/scrollgen @@ -0,0 +1,36 @@ +#!/bin/sh +INPUT="$1" +FRAMES="$2" + +die() { + echo "$@" + exit 1 +} +check_command() { + cmd="$1" + command -v "$cmd" > /dev/null || die "command '$cmd' not found" +} + +check_command magick +check_command identify +[ "$#" -eq 2 ] || die "usage: $0 <input image> <frame count>" +[ -e "$INPUT" ] || die "file not found: $INPUT" +[ "$FRAMES" -gt 0 ] || die "invalid frame count: $FRAMES" + +tile_width=$(identify -format "%w" "$INPUT") +tile_height=$(identify -format "%h" "$INPUT") + +OUTPUT="$INPUT.scroll.png" +magick -size "${tile_width}x$(( $tile_height * $FRAMES ))" 'xc:#ff00ff00' "$OUTPUT" + +for i in $(seq 0 $(( $FRAMES - 1 ))); do + offset_x=$(( $tile_width * $i / $FRAMES )) + offset_y=$(( i * $tile_height )) + + magick "$OUTPUT" "$INPUT" -geometry "+${offset_x}+${offset_y}" -composite "$OUTPUT" + magick "$OUTPUT" "$INPUT" -geometry "+$(( $offset_x - $tile_width ))+${offset_y}" -composite "$OUTPUT" + echo "+${offset_x}+${offset_y}" +done + +# magick -size ${total_width}x${sprite_height} xc:none canvas.png + |