diff --git a/Space-Invaders/Header/AnimationSystem/AnimationService.h b/Space-Invaders/Header/AnimationSystem/AnimationService.h new file mode 100644 index 000000000..38b033cc4 --- /dev/null +++ b/Space-Invaders/Header/AnimationSystem/AnimationService.h @@ -0,0 +1,36 @@ +#pragma once +#include +#include +#include "../../header/AnimationSystem/AnimationSystem.h" + +namespace Animation +{ + enum class AnimationType + { + EXPLOSION, + }; + + class AnimationService + { + private: + std::vector animation_system_list; + std::vector flagged_animation_system_list; + + AnimationSystemConfig getAnimationSystemConfig(AnimationType animation_type); + void destroyFlaggedAnimationSystem(); + void destroy(); + + public: + AnimationService(); + virtual ~AnimationService(); + + void initialize(); + void update(); + void render(); + + void reset(); + + void spawnAnimationSystem(sf::Vector2f position, AnimationType animation_type); + void destroyAnimationSystem(AnimationSystem* animation_system); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/AnimationSystem/AnimationSystem.h b/Space-Invaders/Header/AnimationSystem/AnimationSystem.h new file mode 100644 index 000000000..4c5e8406f --- /dev/null +++ b/Space-Invaders/Header/AnimationSystem/AnimationSystem.h @@ -0,0 +1,33 @@ +#pragma once +#include +#include "../../header/AnimationSystem/AnimationSystemConfig.h" +#include "../../header/UI/UIElement/ImageView.h" + +namespace Animation +{ + class AnimationSystem + { + private: + AnimationSystemConfig animation_system_config; + + sf::Vector2f animation_position; + UI::UIElement::ImageView* animation_image; + + void createUIElements(); + void initializeImage(); + + int current_frame; + sf::Clock clock; + sf::Time frame_time; + + public: + AnimationSystem(AnimationSystemConfig config); + ~AnimationSystem(); + + void initialize(sf::Vector2f position); + void update(); + void render(); + + void destroy(); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/AnimationSystem/AnimationSystemConfig.h b/Space-Invaders/Header/AnimationSystem/AnimationSystemConfig.h new file mode 100644 index 000000000..9d1ff6e9d --- /dev/null +++ b/Space-Invaders/Header/AnimationSystem/AnimationSystemConfig.h @@ -0,0 +1,30 @@ +#pragma once +namespace Animation +{ + struct AnimationSystemConfig + { + sf::String Animation_texture_path; + + float sprite_sheet_width; + float sprite_sheet_height; + + //one frame of the sprite sheet - W x H + float tile_width; + float tile_height; + + int number_of_animation_frames; //total frames + float frame_duration; //duration of a single frame - the amount to wait for next frame in the animation spritesheet + + AnimationSystemConfig() = default; // Use default for default constructor + + //this will allow us to initialize an animation with it's configuration. + AnimationSystemConfig(sf::String texture_path, float sprite_width, float sprite_height, float t_width, float t_height, int frames, float duration) : + Animation_texture_path(texture_path), + sprite_sheet_width(sprite_width), + sprite_sheet_height(sprite_height), + tile_width(t_width), + tile_height(t_height), + number_of_animation_frames(frames), + frame_duration(duration) {} + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/AnimationSystem/AnimationSystemConfigData.h b/Space-Invaders/Header/AnimationSystem/AnimationSystemConfigData.h new file mode 100644 index 000000000..3c8978dc9 --- /dev/null +++ b/Space-Invaders/Header/AnimationSystem/AnimationSystemConfigData.h @@ -0,0 +1,8 @@ +#pragma once +#include "AnimationSystemConfig.h" +#include "../../Header/Global/Config.h" + +namespace Animation +{ + const AnimationSystemConfig explosion_animation_config(Global::Config::explosion_texture_path, 70.0f, 80.0f, 14.28f, 20.0f, 7, 0.03f); +} \ No newline at end of file diff --git a/Space-Invaders/Header/Bullet/BulletConfig.h b/Space-Invaders/Header/Bullet/BulletConfig.h new file mode 100644 index 000000000..8a8b7d093 --- /dev/null +++ b/Space-Invaders/Header/Bullet/BulletConfig.h @@ -0,0 +1,28 @@ +#pragma once +#include + +namespace Bullet +{ + enum class BulletType + { + LASER_BULLET, + TORPEDO, + FROST_BULLET, + }; + + enum class MovementDirection + { + UP, //player needs to shoot in upward direction + DOWN, // enemies always shoot in downward direction + }; + + class BulletConfig + { + public: + static const sf::String laser_bullet_texture_path; + static const sf::String torpedoe_texture_path; + static const sf::String frost_beam_texture_path; + + static sf::String getBulletTexturePath(BulletType bullet_type); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Bullet/BulletController.h b/Space-Invaders/Header/Bullet/BulletController.h new file mode 100644 index 000000000..363f1407e --- /dev/null +++ b/Space-Invaders/Header/Bullet/BulletController.h @@ -0,0 +1,48 @@ +#pragma once +#include "../../Header/Projectile/IProjectile.h" +#include "../../Header/Entity/EntityConfig.h" +#include "../Collision/ICollider.h" + +namespace Bullet +{ + class BulletView; + class BulletModel; + enum class BulletType; + + class BulletController : public Projectile::IProjectile, public Collision::ICollider + { + protected: + + BulletView* bullet_view; + BulletModel* bullet_model; + + void updateProjectilePosition() override; + + //Collision funcs + void processBulletCollision(ICollider* other_collider); + void processEnemyCollision(ICollider* other_collider); + void processPlayerCollision(ICollider* other_collider); + void processBunkerCollision(ICollider* other_collider); + + + void moveUp(); + void moveDown(); + void handleOutOfBounds(); + + public: + + BulletController(BulletType type, Entity::EntityType owner_type); + virtual ~BulletController(); + + void initialize(sf::Vector2f position, Bullet::MovementDirection direction) override; + void update() override; + void render() override; + + sf::Vector2f getProjectilePosition() override; + BulletType getBulletType(); + Entity::EntityType getOwnerEntityType(); + + const sf::Sprite& getColliderSprite() override; + void onCollision(ICollider* other_collider) override; + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Bullet/BulletModel.h b/Space-Invaders/Header/Bullet/BulletModel.h new file mode 100644 index 000000000..5eaebd2fb --- /dev/null +++ b/Space-Invaders/Header/Bullet/BulletModel.h @@ -0,0 +1,40 @@ +#pragma once +#include +#include "../../Header/Entity/EntityConfig.h" + +namespace Bullet +{ + enum class BulletType; + enum class MovementDirection; + + class BulletModel + { + private: + float movement_speed = 300.f; + sf::Vector2f bullet_position; + + BulletType bullet_type; + Entity::EntityType owner_type; + MovementDirection movement_direction; + + public: + + BulletModel(BulletType type, Entity::EntityType owner_type); + ~BulletModel(); + + void initialize(sf::Vector2f position, MovementDirection direction); + + sf::Vector2f getBulletPosition(); + void setBulletPosition(sf::Vector2f position); + + BulletType getBulletType(); + + Entity::EntityType getOwnerEntityType(); + + MovementDirection getMovementDirection(); + void setMovementDirection(MovementDirection direction); + + float getMovementSpeed(); + void setMovementSpeed(float speed); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Bullet/BulletService.h b/Space-Invaders/Header/Bullet/BulletService.h new file mode 100644 index 000000000..79983d32f --- /dev/null +++ b/Space-Invaders/Header/Bullet/BulletService.h @@ -0,0 +1,39 @@ +#pragma once +#include +#include "SFML/System/Vector2.hpp" +#include "../../Header/Entity/EntityConfig.h" +#include "../../Header/Projectile/IProjectile.h" + +namespace Bullet +{ + class BulletController; + enum class BulletType; + enum class MovementDirection; + + class BulletService + { + private: + + std::vector flagged_bullet_list; + std::vector bullet_list; + + BulletController* createBullet(BulletType type, Entity::EntityType owner_type); + + bool isValidBullet(int index_i, std::vector& bullet_list); + void destroyFlaggedBullets(); + + void destroy(); + + public: + BulletService(); + virtual ~BulletService(); + + void initialize(); + void update(); + void render(); + void reset(); + + BulletController* spawnBullet(BulletType type, sf::Vector2f position, MovementDirection direction, Entity::EntityType owner_type); + void destroyBullet(BulletController* bullet_controller); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Bullet/BulletView.h b/Space-Invaders/Header/Bullet/BulletView.h new file mode 100644 index 000000000..ba6068000 --- /dev/null +++ b/Space-Invaders/Header/Bullet/BulletView.h @@ -0,0 +1,34 @@ +#pragma once +#include +#include "../../Header/UI/UIElement/ImageView.h" + +namespace Bullet +{ + class BulletController; + + class BulletView + { + private: + const float bullet_sprite_width = 18.f; + const float bullet_sprite_height = 18.f; + + BulletController* bullet_controller; + UI::UIElement::ImageView* bullet_image; + + void createUIElements(); + void initializeImage(); + sf::String getBulletTexturePath(); + + void destroy(); + + public: + BulletView(); + ~BulletView(); + + void initialize(BulletController* controller); + void update(); + void render(); + + const sf::Sprite& getBulletSprite(); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Bullet/Controllers/FrostBulletController.h b/Space-Invaders/Header/Bullet/Controllers/FrostBulletController.h new file mode 100644 index 000000000..37132c5e3 --- /dev/null +++ b/Space-Invaders/Header/Bullet/Controllers/FrostBulletController.h @@ -0,0 +1,20 @@ +#pragma once +#include "../../Header/Bullet/BulletController.h" + +namespace Bullet +{ + namespace Controller + { + class FrostBulletController : public BulletController + { + private: + const float frost_bullet_movement_speed = 500.f; + + public: + FrostBulletController(BulletType type, Entity::EntityType owner_type); + ~FrostBulletController(); + + void initialize(sf::Vector2f position, MovementDirection direction) override; + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/Bullet/Controllers/LaserBulletController.h b/Space-Invaders/Header/Bullet/Controllers/LaserBulletController.h new file mode 100644 index 000000000..ec61a727d --- /dev/null +++ b/Space-Invaders/Header/Bullet/Controllers/LaserBulletController.h @@ -0,0 +1,17 @@ +#pragma once +#include "../../Header/Bullet/BulletController.h" + +namespace Bullet +{ + namespace Controller + { + class LaserBulletController : public BulletController + { + public: + LaserBulletController(BulletType type, Entity::EntityType owner_type); + ~LaserBulletController(); + + void initialize(sf::Vector2f position, MovementDirection direction) override; + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/Bullet/Controllers/TorpedoController.h b/Space-Invaders/Header/Bullet/Controllers/TorpedoController.h new file mode 100644 index 000000000..ea8b59782 --- /dev/null +++ b/Space-Invaders/Header/Bullet/Controllers/TorpedoController.h @@ -0,0 +1,20 @@ +#pragma once +#include "../../Header/Bullet/BulletController.h" + +namespace Bullet +{ + namespace Controller + { + class TorpedoController : public BulletController + { + private: + const float torpedo_movement_speed = 200.f; + + public: + TorpedoController(BulletType type, Entity::EntityType owner_type); + ~TorpedoController(); + + void initialize(sf::Vector2f position, MovementDirection direction) override; + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/Collectible/ICollectible.h b/Space-Invaders/Header/Collectible/ICollectible.h new file mode 100644 index 000000000..d1405aa13 --- /dev/null +++ b/Space-Invaders/Header/Collectible/ICollectible.h @@ -0,0 +1,17 @@ +#pragma once +#include + +namespace Collectible +{ + class ICollectible + { + public: + virtual void onCollected() = 0; + virtual void initialize(sf::Vector2f position) = 0; + virtual void update() = 0; + virtual void render() = 0; + virtual sf::Vector2f getCollectiblePosition() = 0; + + virtual ~ICollectible() {}; + }; +} diff --git a/Space-Invaders/Header/Collision/CollisionService.h b/Space-Invaders/Header/Collision/CollisionService.h new file mode 100644 index 000000000..be71997c3 --- /dev/null +++ b/Space-Invaders/Header/Collision/CollisionService.h @@ -0,0 +1,28 @@ +#pragma once +#include + +namespace Collision +{ + class ICollider; + + class CollisionService + { + private: + std::vector collider_list; + + void processCollision(); + void doCollision(int index_i, int index_j); + bool hasCollisionOccurred(int index_i, int index_j); + bool areActiveColliders(int index_i, int index_j); + + public: + CollisionService(); + ~CollisionService(); + + void initialize(); + void update(); + + void addCollider(ICollider* collider); + void removeCollider(ICollider* collider); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Collision/ICollider.h b/Space-Invaders/Header/Collision/ICollider.h new file mode 100644 index 000000000..0f556a5f3 --- /dev/null +++ b/Space-Invaders/Header/Collision/ICollider.h @@ -0,0 +1,28 @@ +#pragma once +#include + +namespace Collision +{ + enum class CollisionState + { + ENABLED, + DISABLED, + }; + + class ICollider + { + private: + CollisionState collision_state; + + public: + ICollider(); + virtual ~ICollider(); + + virtual const sf::Sprite& getColliderSprite() = 0; + virtual void onCollision(ICollider* other_collider) = 0; + + void enableCollision(); + void disableCollision(); + CollisionState getCollisionState(); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Element/Bunker/BunkerController.h b/Space-Invaders/Header/Element/Bunker/BunkerController.h new file mode 100644 index 000000000..463be0627 --- /dev/null +++ b/Space-Invaders/Header/Element/Bunker/BunkerController.h @@ -0,0 +1,33 @@ +#pragma once +#include +#include "../../Collision/ICollider.h" +#include "../../header/Element/Bunker/BunkerModel.h" + +namespace Element +{ + namespace Bunker + { + class BunkerView; + + class BunkerController : public Collision::ICollider + { + private: + BunkerView* bunker_view; + BunkerData bunker_data; + + public: + BunkerController(); + ~BunkerController(); + + void initialize(BunkerData data); + void update(); + void render(); + + sf::Vector2f getBunkerPosition(); + + //sprite get method using getsprite + const sf::Sprite& getColliderSprite() override; + void onCollision(ICollider* other_collider) override; + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/Element/Bunker/BunkerModel.h b/Space-Invaders/Header/Element/Bunker/BunkerModel.h new file mode 100644 index 000000000..7ae912814 --- /dev/null +++ b/Space-Invaders/Header/Element/Bunker/BunkerModel.h @@ -0,0 +1,15 @@ +#pragma once +#include + +namespace Element +{ + namespace Bunker + { + struct BunkerData + { + sf::Vector2f position; + BunkerData(); + BunkerData(sf::Vector2f position); + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/Element/Bunker/BunkerView.h b/Space-Invaders/Header/Element/Bunker/BunkerView.h new file mode 100644 index 000000000..64dd64d9e --- /dev/null +++ b/Space-Invaders/Header/Element/Bunker/BunkerView.h @@ -0,0 +1,35 @@ +#pragma once +#include +#include "../../Header/UI/UIElement/ImageView.h" + +namespace Element +{ + namespace Bunker + { + class BunkerController; + + class BunkerView + { + private: + const float bunker_sprite_width = 80.f; + const float bunker_sprite_height = 80.f; + + BunkerController* bunker_controller; + UI::UIElement::ImageView* bunker_image; + + void createUIElements(); + void initializeImage(); + + void destroy(); + + public: + BunkerView(); + ~BunkerView(); + + void initialize(BunkerController* controller); + const sf::Sprite& getBunkerSprite(); + void update(); + void render(); + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/Element/ElementService.h b/Space-Invaders/Header/Element/ElementService.h new file mode 100644 index 000000000..23ce7c62c --- /dev/null +++ b/Space-Invaders/Header/Element/ElementService.h @@ -0,0 +1,40 @@ +#pragma once +#include +#include +#include "../../header/Element/Bunker/BunkerController.h" +#include "../../header/Element/Bunker/BunkerModel.h" + +namespace Element +{ + class BunkerController; + + class ElementService + { + private: + //const vector so that the default values will not be changed down the road by mistake. + const std::vector bunker_data_list = { Bunker::BunkerData(sf::Vector2f(130.f, 800.f)), + Bunker::BunkerData(sf::Vector2f(430.0f, 800.f)), + Bunker::BunkerData(sf::Vector2f(730.0f, 800.f)), + Bunker::BunkerData(sf::Vector2f(1130.0f, 800.f)), + Bunker::BunkerData(sf::Vector2f(1430.0f, 800.f)), + Bunker::BunkerData(sf::Vector2f(1730.0f, 800.f)) }; + + std::vector bunker_list; + std::vector flagged_bunker_list; + + void spawnBunkers(); + void destroyFlaggedBunkers(); + void destroy(); + + public: + ElementService(); + virtual ~ElementService(); + + void initialize(); + void update(); + void render(); + + void reset(); + void destroyBunker(Bunker::BunkerController* bunker_controller); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Enemy/Controllers/SubZeroController.h b/Space-Invaders/Header/Enemy/Controllers/SubZeroController.h new file mode 100644 index 000000000..bc9acee12 --- /dev/null +++ b/Space-Invaders/Header/Enemy/Controllers/SubZeroController.h @@ -0,0 +1,31 @@ +#pragma once +#include "../../Header/Enemy/EnemyController.h" + +namespace Enemy +{ + namespace Controller + { + class SubzeroController : public EnemyController + { + private: + + float subzero_vertical_movement_speed = 100.f; + const float subzero_rate_of_fire = 2.f; + + void move() override; + void moveDown(); + + void fireBullet() override; + + void destroy() override; + + public: + + SubzeroController(EnemyType type); + ~SubzeroController(); + + void initialize() override; + + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/Enemy/Controllers/ThunderSnakeController.h b/Space-Invaders/Header/Enemy/Controllers/ThunderSnakeController.h new file mode 100644 index 000000000..b083435e5 --- /dev/null +++ b/Space-Invaders/Header/Enemy/Controllers/ThunderSnakeController.h @@ -0,0 +1,33 @@ +#pragma once +#include "../../Header/Enemy/EnemyController.h" +#include "../../Header/Enemy/EnemyConfig.h" + +namespace Enemy +{ + namespace Controller + { + class ThunderSnakeController : public EnemyController + { + private: + const float thunder_snake_horizontal_movement_speed = 190.f; + + void move() override; + void moveLeft(); + void moveRight(); + void moveDiagonalLeft(); + void moveDiagonalRight(); + + void fireBullet() override; + + void destroy() override; + + MovementDirection getInitialMovementDirection(); + + public: + ThunderSnakeController(EnemyType type); + ~ThunderSnakeController(); + + void initialize() override; + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/Enemy/Controllers/UFOController.h b/Space-Invaders/Header/Enemy/Controllers/UFOController.h new file mode 100644 index 000000000..d829acb67 --- /dev/null +++ b/Space-Invaders/Header/Enemy/Controllers/UFOController.h @@ -0,0 +1,29 @@ +#pragma once +#include "../../header/Enemy/EnemyController.h" +#include "../../header/Powerups/PowerupConfig.h" + +namespace Enemy +{ + namespace Controller + { + class UFOController : public EnemyController + { + private: + + void move() override; + void moveLeft(); + void moveRight(); + + void fireBullet() override; + void destroy() override; + Powerup::PowerupType getRandomPowerupType(); + + public: + UFOController(EnemyType type); + ~UFOController(); + + void initialize() override; + void onCollision(ICollider* other_collider) override; + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/Enemy/Controllers/ZapperController.h b/Space-Invaders/Header/Enemy/Controllers/ZapperController.h new file mode 100644 index 000000000..1a4eeb54a --- /dev/null +++ b/Space-Invaders/Header/Enemy/Controllers/ZapperController.h @@ -0,0 +1,31 @@ +#pragma once +#include "../../Header/Enemy/EnemyController.h" + +namespace Enemy +{ + namespace Controller + { + class ZapperController : public EnemyController + { + private: + + float vertical_travel_distance = 100.f; + + void move() override; + void moveLeft(); + void moveRight(); + void moveDown(); + + void fireBullet() override; + void destroy() override; + + public: + + ZapperController(EnemyType type); + ~ZapperController(); + + void initialize() override; + + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/Enemy/EnemyConfig.h b/Space-Invaders/Header/Enemy/EnemyConfig.h new file mode 100644 index 000000000..81fa1b4d5 --- /dev/null +++ b/Space-Invaders/Header/Enemy/EnemyConfig.h @@ -0,0 +1,28 @@ +#pragma once + +namespace Enemy +{ + enum class EnemyType + { + ZAPPER, + SUBZERO, + THUNDER_SNAKE, + UFO, + }; + + enum class EnemyState + { + PATROLLING, + ATTACK, + DEAD, + }; + + enum class MovementDirection + { + LEFT, + RIGHT, + DOWN, + LEFT_DOWN, + RIGHT_DOWN, + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Enemy/EnemyController.h b/Space-Invaders/Header/Enemy/EnemyController.h new file mode 100644 index 000000000..8876770aa --- /dev/null +++ b/Space-Invaders/Header/Enemy/EnemyController.h @@ -0,0 +1,52 @@ +#pragma once +#include +#include "../../Header/Collision/ICollider.h" + +namespace Enemy +{ + class EnemyView; + class EnemyModel; + + enum class EnemyType; + enum class EnemyState; + + class EnemyController : public Collision::ICollider + { + + protected: + + float vertical_movement_speed = 30.f; + float horizontal_movement_speed = 200.0f; + + float rate_of_fire = 3.f; //we want to fire the bullet every 3 seconds + float elapsed_fire_duration = 0.f; //variable to check how long it has been since we last fired + + EnemyView* enemy_view; + EnemyModel* enemy_model; + + void updateFireTimer(); + void processBulletFire(); + virtual void fireBullet() = 0; + + virtual void move() = 0; + + sf::Vector2f getRandomInitialPosition(); + virtual void destroy(); + void handleOutOfBounds(); + + public: + EnemyController(EnemyType type); + virtual ~EnemyController(); + + virtual void initialize(); + void update(); + void render(); + + sf::Vector2f getEnemyPosition(); + EnemyState getEnemyState(); + EnemyType getEnemyType(); + + const sf::Sprite& getColliderSprite() override; + virtual void onCollision(ICollider* other_collider) override; + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Enemy/EnemyModel.h b/Space-Invaders/Header/Enemy/EnemyModel.h new file mode 100644 index 000000000..c33c311a6 --- /dev/null +++ b/Space-Invaders/Header/Enemy/EnemyModel.h @@ -0,0 +1,51 @@ +#pragma once +#include +#include "../../header/Entity/EntityConfig.h" + +namespace Enemy +{ + enum class EnemyType; + enum class MovementDirection; + enum class EnemyState; + + class EnemyModel + { + private: + sf::Vector2f reference_position = sf::Vector2f(50.f, 50.f); + sf::Vector2f enemy_position; + + Entity::EntityType entity_type; + MovementDirection movement_direction; + EnemyType enemy_type; + EnemyState enemy_state; + + public: + //const settings for enemy + const sf::Vector2f left_most_position = sf::Vector2f(50.f, 50.f); + const sf::Vector2f right_most_position = sf::Vector2f(1800.f, 50.f); + const sf::Vector2f barrel_position_offset = sf::Vector2f(20.f, 50.f); + + EnemyModel(EnemyType type); + ~EnemyModel(); + + void initialize(); + + // Getters and Setters + sf::Vector2f getEnemyPosition(); + void setEnemyPosition(sf::Vector2f position); + + sf::Vector2f getReferencePosition(); + void setReferencePosition(sf::Vector2f position); + + EnemyState getEnemyState(); + void setEnemyState(EnemyState state); + + EnemyType getEnemyType(); + void setEnemyType(EnemyType type); + + MovementDirection getMovementDirection(); + void setMovementDirection(MovementDirection direction); + + Entity::EntityType getEntityType(); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Enemy/EnemyService.h b/Space-Invaders/Header/Enemy/EnemyService.h new file mode 100644 index 000000000..16e5900bf --- /dev/null +++ b/Space-Invaders/Header/Enemy/EnemyService.h @@ -0,0 +1,39 @@ +#pragma once +#include + +namespace Enemy +{ + class EnemyController; + enum class EnemyType; + + class EnemyService + { + private: + + const float spawn_interval = 2.f; + + std::vector enemy_list; + std::vector flagged_enemy_list; + float spawn_timer; + + void updateSpawnTimer(); + void processEnemySpawn(); + EnemyType getRandomEnemyType(); + EnemyController* createEnemy(EnemyType enemy_type); + void destroy(); + void destroyFlaggedEnemies(); + + public: + EnemyService(); + virtual ~EnemyService(); + + void initialize(); + void update(); + void render(); + + void reset(); + + EnemyController* spawnEnemy(); // Function to spawn enemy + void destroyEnemy(EnemyController* enemy_controller); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Enemy/EnemyView.h b/Space-Invaders/Header/Enemy/EnemyView.h new file mode 100644 index 000000000..d494f85b8 --- /dev/null +++ b/Space-Invaders/Header/Enemy/EnemyView.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include "../../Header/UI/UIElement/ImageView.h" + +namespace Enemy +{ + class EnemyController; + + class EnemyView + { + private: + const float enemy_sprite_width = 60.f; + const float enemy_sprite_height = 60.f; + + EnemyController* enemy_controller; + UI::UIElement::ImageView* enemy_image; + + void createUIElements(); + void initializeImage(); + sf::String getEnemyTexturePath(); + + void destroy(); + + public: + EnemyView(); + ~EnemyView(); + + void initialize(EnemyController* controller); + void update(); + void render(); + const sf::Sprite& getEnemySprite(); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Entity/EntityConfig.h b/Space-Invaders/Header/Entity/EntityConfig.h new file mode 100644 index 000000000..234b5e75d --- /dev/null +++ b/Space-Invaders/Header/Entity/EntityConfig.h @@ -0,0 +1,12 @@ +#pragma once +namespace Entity +{ + enum class EntityType + { + PLAYER, + ENEMY, + BULLET, + BUNKER, + DEFAULT, + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Event/EventService.h b/Space-Invaders/Header/Event/EventService.h new file mode 100644 index 000000000..87772f930 --- /dev/null +++ b/Space-Invaders/Header/Event/EventService.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include + +namespace Event +{ + enum class ButtonState + { + PRESSED, + HELD, + RELEASED, + }; + + class EventService + { + private: + sf::Event game_event; //event var + sf::RenderWindow* game_window; //ptr to our game window + + //Button States + ButtonState left_mouse_button_state; + ButtonState right_mouse_button_state; + ButtonState left_arrow_button_state; + ButtonState right_arrow_button_state; + ButtonState A_button_state; + ButtonState D_button_state; + + bool isGameWindowOpen(); + bool gameWindowWasClosed(); //for the condition we already had - the title bar cross. + bool hasQuitGame(); //for our new 'ESC' condition + + //Button and mouse state functions + void updateMouseButtonsState(ButtonState& current_button_state, sf::Mouse::Button mouse_button); + void updateKeyboardButtonsState(ButtonState& current_button_state, sf::Keyboard::Key keyboard_button); + + + public: + EventService(); + ~EventService(); + + void initialize(); + void update(); + void processEvents(); // while window is open we will check for events + + // Inputs + bool pressedEscapeKey(); + bool isKeyboardEvent(); + bool pressedLeftKey(); // getting inputs for the player + bool pressedRightKey(); + bool pressedLeftMouseButton(); // Mouse inputs for the player + bool pressedRightMouseButton(); + bool pressedAKey(); // AD held check + bool pressedDKey(); + }; +} + diff --git a/Space-Invaders/Header/Gameplay/GameplayController.h b/Space-Invaders/Header/Gameplay/GameplayController.h new file mode 100644 index 000000000..76b6fcf24 --- /dev/null +++ b/Space-Invaders/Header/Gameplay/GameplayController.h @@ -0,0 +1,21 @@ +#pragma once +#include + +namespace Gameplay +{ + class GameplayView; + + class GameplayController + { + private: + GameplayView* gameplay_view; + + public: + GameplayController(); + ~GameplayController(); + + void initialize(); + void update(); + void render(); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Gameplay/GameplayService.h b/Space-Invaders/Header/Gameplay/GameplayService.h new file mode 100644 index 000000000..2ca78e2e9 --- /dev/null +++ b/Space-Invaders/Header/Gameplay/GameplayService.h @@ -0,0 +1,21 @@ +#pragma once +namespace Gameplay +{ + class GameplayController; + + class GameplayService + { + private: + GameplayController* gameplay_controller; + + public: + GameplayService(); + ~GameplayService(); + + void initialize(); + void update(); + void render(); + + void restart(); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Gameplay/GameplayView.h b/Space-Invaders/Header/Gameplay/GameplayView.h new file mode 100644 index 000000000..96772b0f8 --- /dev/null +++ b/Space-Invaders/Header/Gameplay/GameplayView.h @@ -0,0 +1,31 @@ +#pragma once +#include +#include "../../Header/UI/UIElement/ImageView.h" + +namespace Gameplay +{ + class GameplayController; + + class GameplayView + { + private: + sf::RenderWindow* game_window; + sf::Texture background_texture; + sf::Sprite background_sprite; + + const float background_alpha = 150.f; + + GameplayController* gameplay_controller; + UI::UIElement::ImageView* background_image; + + void initializeBackgroundImage(); + + public: + GameplayView(); + ~GameplayView(); + + void initialize(); + void update(); + void render(); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Global/Config.h b/Space-Invaders/Header/Global/Config.h new file mode 100644 index 000000000..37cac583b --- /dev/null +++ b/Space-Invaders/Header/Global/Config.h @@ -0,0 +1,44 @@ +#pragma once +#include + +namespace Global +{ + class Config + { + public: + static const sf::String outscal_logo_texture_path; + static const sf::String background_texture_path; + static const sf::String player_texture_path; + + static const sf::String zapper_texture_path; + static const sf::String thunder_snake_texture_path; + static const sf::String subzero_texture_path; + static const sf::String ufo_texture_path; + static const sf::String bunker_texture_path; + + static const sf::String explosion_texture_path; + + static const sf::String shield_texture_path; + static const sf::String tripple_laser_texture_path; + static const sf::String rapid_fire_texture_path; + static const sf::String outscal_bomb_texture_path; + + static const sf::String laser_bullet_texture_path; + static const sf::String torpedoe_texture_path; + static const sf::String frost_beam_texture_path; + + static const sf::String play_button_texture_path; + static const sf::String instructions_button_texture_path; + static const sf::String quit_button_texture_path; + static const sf::String menu_button_texture_path; + + static const sf::String bubble_bobble_font_path; + static const sf::String DS_DIGIB_font_path; + + static const sf::String background_music_path; + static const sf::String button_click_sound_path; + static const sf::String bullet_fire_sound_path; + static const sf::String powerup_enabled_sound_path; + static const sf::String powerup_disabled_sound_path; + }; +} diff --git a/Space-Invaders/Header/Global/ServiceLocator.h b/Space-Invaders/Header/Global/ServiceLocator.h new file mode 100644 index 000000000..a337fc025 --- /dev/null +++ b/Space-Invaders/Header/Global/ServiceLocator.h @@ -0,0 +1,73 @@ +#pragma once +#include "../../Header/Graphic/GraphicService.h" +#include "../../Header/Event/EventService.h" +#include "../../Header/UI/UIService.h" +#include "../../Header/Player/PlayerService.h" +#include "../../Header/Time/TimeService.h" +#include "../../Header/Enemy/EnemyService.h" +#include "../../Header/Gameplay/GameplayService.h" +#include "../../Header/Element/ElementService.h" +#include "../../Header/Bullet/BulletService.h" +#include "../../Header/Powerups/PowerupService.h" +#include "../../Header/Sound/SoundService.h" +#include "../../Header/Collision/CollisionService.h" +#include "../../Header/AnimationSystem/AnimationService.h" + + +// ServiceLocator Class Summary: This class manages access to various services in the application. +// include relevant headers files + +namespace Global +{ + class ServiceLocator + { + private: + + // Private Attributes: + Event::EventService* event_service; + Graphics::GraphicService* graphic_service; + UI::UIService* ui_service; + Time::TimeService* time_service; + Gameplay::GameplayService* gameplay_service; + Player::PlayerService* player_service; + Enemy::EnemyService* enemy_service; + Element::ElementService* element_service; + Bullet::BulletService* bullet_service; + Powerup::PowerupService* powerup_service; + Sound::SoundService* sound_service; + Collision::CollisionService* collision_service; + Animation::AnimationService* animation_service; + + // Public Methods + ServiceLocator(); + ~ServiceLocator(); + + // Private Methods: + void createServices(); + void clearAllServices(); + + public: + + // Public Methods: + static ServiceLocator* getInstance(); + void initialize(); // Initializes the ServiceLocator. + void update(); // Updates all services. + void render(); // Renders using the services. + + // Methods to Get Specific Services: + Event::EventService* getEventService(); // Retrieve the EventService instance + Graphics::GraphicService* getGraphicService(); // Retrieve the GraphicService instance + Player::PlayerService* getPlayerService(); // Retrieve the PlayerService instance + Time::TimeService* getTimeService(); // Retrieve the TimeService instance + UI::UIService* getUIService(); // Retrive the UIService instance + Enemy::EnemyService* getEnemyService(); // Retrive the EnemyService instance + Gameplay::GameplayService* getGameplayService(); // Retrive the GameplayService instance + Element::ElementService* getElementService(); // Retrive the ElementService instance + Sound::SoundService* getSoundService(); // Retrive the SoundService instance + Bullet::BulletService* getBulletService(); // Retrive the BulletService instance + Powerup::PowerupService* getPowerupService(); // Retrive the PowerupService instance + Collision::CollisionService* getCollisionService(); // Retrive the CollisionService instance + Animation::AnimationService* getAnimationService(); // Retrive the AnimationService instance + void deleteServiceLocator(); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Graphic/GraphicService.h b/Space-Invaders/Header/Graphic/GraphicService.h new file mode 100644 index 000000000..f14989a3e --- /dev/null +++ b/Space-Invaders/Header/Graphic/GraphicService.h @@ -0,0 +1,41 @@ +#pragma once +#include + +namespace Graphics +{ + class GraphicService + { + private: + + const std::string game_window_title = "Alien Invader"; + + const int game_window_width = 1920; + const int game_window_height = 1080; + + const int frame_rate = 60; + + const sf::Color window_color = sf::Color::Black; + + sf::VideoMode* video_mode; // ptr to video mode + sf::RenderWindow* game_window; // ptr to a RenderWindow + + void setVideoMode(); // Method for setting our video mode + void onDestroy(); // method to run when window is deleted + + public: + GraphicService(); + ~GraphicService(); //cleanup + + //method to create the game window. returns a pointer to an instance of the game window + sf::RenderWindow* createGameWindow(); + + + void initialize(); //lifecycle functions + void update(); //.. + void render(); //.. + bool isGameWindowOpen(); //check if the window is open + void setFrameRate(int); + sf::RenderWindow* getGameWindow(); //getter for the game window instance + sf::Color getWindowColor();//get the color + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Main/GameService.h b/Space-Invaders/Header/Main/GameService.h new file mode 100644 index 000000000..0cce5b481 --- /dev/null +++ b/Space-Invaders/Header/Main/GameService.h @@ -0,0 +1,43 @@ +#pragma once +#include +#include "../../header/Global/ServiceLocator.h" + +namespace Main +{ + enum class GameState + { + BOOT, + MAIN_MENU, + GAMEPLAY, + SPLASH_SCREEN, + INSTRUCTIONS, + CREDITS, + }; + + class GameService + { + private: + + static GameState current_state; + + Global::ServiceLocator* service_locator; + sf::RenderWindow* game_window; + + + void initialize(); // Handles game initialization. + void initializeVariables();// Handles game initialization. + void destroy(); // Handles cleanup tasks. + void showSplashScreen(); + + public: + GameService(); // Constructor for initializing the GameService object. + ~GameService(); // Destructor for cleaning up resources upon object deletion. + + void ignite(); // Initiates the game. + void update(); // Updates the game logic and game state. + void render(); // Renders each frame of the game. + bool isRunning(); // Checks if the game is currently running. + static void setGameState(GameState new_state); + static GameState getGameState(); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Player/PlayerController.h b/Space-Invaders/Header/Player/PlayerController.h new file mode 100644 index 000000000..b409006f4 --- /dev/null +++ b/Space-Invaders/Header/Player/PlayerController.h @@ -0,0 +1,70 @@ +#pragma once +#include +#include "../../Header/Collision/ICollider.h" +#include "../../Header/Powerups/PowerupConfig.h" +#include "../../Header/Player/PlayerModel.h" + +namespace Player +{ + class PlayerView; + enum class PlayerState; + + class PlayerController : public Collision::ICollider + { + private: + float elapsed_shield_duration; + float elapsed_rapid_fire_duration; + float elapsed_tripple_laser_duration; + + float elapsed_fire_duration; + float elapsed_freeze_duration; + + PlayerView* player_view; + PlayerModel* player_model; + + void processPlayerInput(); + void moveLeft(); + void moveRight(); + + bool processBulletCollision(ICollider* other_collider); + bool processPowerupCollision(ICollider* other_collider); + bool processEnemyCollision(ICollider* other_collider); + void updateFreezeDuration(); + void freezePlayer(); + + void updateFireDuration(); + void processBulletFire(); + void fireBullet(bool b_tripple_laser = false); + void fireBullet(sf::Vector2f position); + + void updatePowerupDuration(); + + void disableShield(); + void disableRapidFire(); + void disableTrippleLaser(); + + public: + PlayerController(); + ~PlayerController(); + + void initialize(); + void update(); + void render(); + + void reset(); + + void decreasePlayerLive(); + inline void increaseEnemiesKilled(int val) { PlayerModel::enemies_killed += val; } + inline void increaseBulletsFired(int val) { PlayerModel::bullets_fired += val; } + + void enableShield(); + void enableRapidFire(); + void enableTrippleLaser(); + + sf::Vector2f getPlayerPosition(); + PlayerState getPlayerState(); + + const sf::Sprite& getColliderSprite() override; + void onCollision(ICollider* other_collider) override; + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Player/PlayerModel.h b/Space-Invaders/Header/Player/PlayerModel.h new file mode 100644 index 000000000..aebfb54f5 --- /dev/null +++ b/Space-Invaders/Header/Player/PlayerModel.h @@ -0,0 +1,81 @@ +#pragma once +#include +#include "../../header/Entity/EntityConfig.h" +#include "../../header/UI/GameplayUI/GameplayUIController.h" + +namespace Player +{ + enum class PlayerState //Our Enum + { + ALIVE, + FROZEN, + DEAD, + }; + + class PlayerModel + { + private: + friend class PlayerController; + friend void UI::GameplayUI::GameplayUIController::updateEnemiesKilledText(); + friend void UI::GameplayUI::GameplayUIController::drawPlayerLives(); + + const sf::Vector2f initial_player_position = sf::Vector2f(950.f, 950.f); + const int max_player_lives = 3; + + sf::Vector2f player_position; + Entity::EntityType entity_type; + PlayerState player_state; //Declaration + + static int player_lives; + static int player_score; + static int enemies_killed; + static int bullets_fired; + + bool b_shield; + bool b_rapid_fire; + bool b_tripple_laser; + + public: + const sf::Vector2f left_most_position = sf::Vector2f(50.f, 950.f); + const sf::Vector2f right_most_position = sf::Vector2f(1800.f, 950.f); + const sf::Vector2f barrel_position_offset = sf::Vector2f(20.f, 50.f); + const sf::Vector2f second_weapon_position_offset = sf::Vector2f(45.f, 0.f); + const sf::Vector2f third_weapon_position_offset = sf::Vector2f(-45.f, 0.f); + + const float shiled_powerup_duration = 10.f; + const float rapid_fire_powerup_duration = 10.f; + const float tripple_laser_powerup_duration = 10.f; + + const float freeze_duration = 2.f; + + const float fire_cooldown_duration = 0.2f; + const float rapid_fire_cooldown_duration = 0.05f; + const float tripple_laser_position_offset = 30.f; + + const float player_movement_speed = 600.0f; + static const int invincible_player_alpha = 170.f; + + PlayerModel(); + ~PlayerModel(); + + void initialize(); + void reset(); + + sf::Vector2f getPlayerPosition(); + void setPlayerPosition(sf::Vector2f position); + + //new getter and setter + PlayerState getPlayerState(); + void setPlayerState(PlayerState state); + + Entity::EntityType getEntityType(); + + bool isShieldEnabled(); + bool isRapidFireEnabled(); + bool isTrippleLaserEnabled(); + + void setShieldState(bool value); + void setRapidFireState(bool value); + void setTrippleFireState(bool value); + }; +} diff --git a/Space-Invaders/Header/Player/PlayerService.h b/Space-Invaders/Header/Player/PlayerService.h new file mode 100644 index 000000000..3a5c47b01 --- /dev/null +++ b/Space-Invaders/Header/Player/PlayerService.h @@ -0,0 +1,28 @@ +#pragma once + +namespace Player +{ + class PlayerController; + + class PlayerService + { + private: + PlayerController* player_controller; + + public: + PlayerService(); + ~PlayerService(); + + void initialize(); + void update(); + void render(); + + void enableShield(); + void enableRapidFire(); + void enableTrippleLaser(); + + void reset(); + + void increaseEnemiesKilled(int val); + }; +} diff --git a/Space-Invaders/Header/Player/PlayerView.h b/Space-Invaders/Header/Player/PlayerView.h new file mode 100644 index 000000000..51eaa26aa --- /dev/null +++ b/Space-Invaders/Header/Player/PlayerView.h @@ -0,0 +1,32 @@ +#pragma once +#include +#include "../../Header/UI/UIElement/ImageView.h" + +namespace Player +{ + class PlayerController; + class PlayerView + { + private: + const float player_sprite_width = 60.f; + const float player_sprite_height = 60.f; + + PlayerController* player_controller; + UI::UIElement::ImageView* player_image; + + void createUIElements(); + void initializeImage(); + void destroy(); + + public: + PlayerView(); + ~PlayerView(); + + void update(); + void render(); + + void setPlayerHighlight(bool b_highlight); + const sf::Sprite& getPlayerSprite(); + void initialize(PlayerController* controller); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Powerups/Controllers/OutscalBombController.h b/Space-Invaders/Header/Powerups/Controllers/OutscalBombController.h new file mode 100644 index 000000000..0d9ed30d7 --- /dev/null +++ b/Space-Invaders/Header/Powerups/Controllers/OutscalBombController.h @@ -0,0 +1,18 @@ +#pragma once +#include "../../Header/Powerups/PowerupController.h" + +namespace Powerup +{ + namespace Controller + { + class OutscalBombController : public PowerupController + { + public: + OutscalBombController(PowerupType type); + virtual ~OutscalBombController(); + + void onCollected() override; + void applyPowerup(); + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/Powerups/Controllers/RapidFireController.h b/Space-Invaders/Header/Powerups/Controllers/RapidFireController.h new file mode 100644 index 000000000..c1120a9a2 --- /dev/null +++ b/Space-Invaders/Header/Powerups/Controllers/RapidFireController.h @@ -0,0 +1,18 @@ +#pragma once +#include "../../Header/Powerups/PowerupController.h" + +namespace Powerup +{ + namespace Controller + { + class RapidFireController : public PowerupController + { + public: + RapidFireController(PowerupType type); + virtual ~RapidFireController(); + + void onCollected() override; + void applyPowerup(); + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/Powerups/Controllers/ShieldController.h b/Space-Invaders/Header/Powerups/Controllers/ShieldController.h new file mode 100644 index 000000000..2bc45a297 --- /dev/null +++ b/Space-Invaders/Header/Powerups/Controllers/ShieldController.h @@ -0,0 +1,18 @@ +#pragma once +#include "../../Header/Powerups/PowerupController.h" + +namespace Powerup +{ + namespace Controller + { + class ShieldController : public PowerupController + { + public: + ShieldController(PowerupType type); + virtual ~ShieldController(); + + void onCollected() override; + void applyPowerup(); + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/Powerups/Controllers/TrippleLaserController.h b/Space-Invaders/Header/Powerups/Controllers/TrippleLaserController.h new file mode 100644 index 000000000..85cef995f --- /dev/null +++ b/Space-Invaders/Header/Powerups/Controllers/TrippleLaserController.h @@ -0,0 +1,18 @@ +#pragma once +#include "../../Header/Powerups/PowerupController.h" + +namespace Powerup +{ + namespace Controller + { + class TrippleLaserController : public PowerupController + { + public: + TrippleLaserController(PowerupType type); + virtual ~TrippleLaserController(); + + void onCollected() override; + void applyPowerup(); + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/Powerups/PowerupConfig.h b/Space-Invaders/Header/Powerups/PowerupConfig.h new file mode 100644 index 000000000..2a11ef64f --- /dev/null +++ b/Space-Invaders/Header/Powerups/PowerupConfig.h @@ -0,0 +1,11 @@ +#pragma once +namespace Powerup +{ + enum class PowerupType + { + SHIELD, + RAPID_FIRE, + TRIPPLE_LASER, + OUTSCAL_BOMB, // later redacted + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Powerups/PowerupController.h b/Space-Invaders/Header/Powerups/PowerupController.h new file mode 100644 index 000000000..f13de6bdc --- /dev/null +++ b/Space-Invaders/Header/Powerups/PowerupController.h @@ -0,0 +1,38 @@ +#pragma once +#include "../../header/Collectible/ICollectible.h" +#include "../../Header/Collision/ICollider.h" + +namespace Powerup +{ + class PowerupView; + class PowerupModel; + + enum class PowerupType; + + class PowerupController : public Collectible::ICollectible, public Collision::ICollider + { + protected: + PowerupView* powerup_view; + PowerupModel* powerup_model; + virtual void applyPowerup() = 0; + void updatePowerupPosition(); + void handleOutOfBounds(); + + public: + PowerupController(PowerupType type); + virtual ~PowerupController(); + + void initialize(sf::Vector2f position) override; + void update() override; + void render() override; + + void onCollected() override; + + sf::Vector2f getCollectiblePosition() override; + PowerupType getPowerupType(); + + //Collision + const sf::Sprite& getColliderSprite() override; + void onCollision(ICollider* other_collider) override; + }; +} diff --git a/Space-Invaders/Header/Powerups/PowerupModel.h b/Space-Invaders/Header/Powerups/PowerupModel.h new file mode 100644 index 000000000..104f227ee --- /dev/null +++ b/Space-Invaders/Header/Powerups/PowerupModel.h @@ -0,0 +1,31 @@ +#pragma once +#include + +namespace Powerup +{ + enum class PowerupType; + + class PowerupModel + { + private: + float movement_speed = 300.f; + + sf::Vector2f powerup_position; + PowerupType powerup_type; + + public: + PowerupModel(PowerupType type); + ~PowerupModel(); + + void initialize(sf::Vector2f position); + + sf::Vector2f getPowerupPosition(); + void setPowerupPosition(sf::Vector2f position); + + PowerupType getPowerupType(); + void setPowerupType(PowerupType type); + + float getMovementSpeed(); + void setMovementSpeed(float speed); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Powerups/PowerupService.h b/Space-Invaders/Header/Powerups/PowerupService.h new file mode 100644 index 000000000..35d76192d --- /dev/null +++ b/Space-Invaders/Header/Powerups/PowerupService.h @@ -0,0 +1,35 @@ +#pragma once +#include +#include "SFML/System/Vector2.hpp" +#include "../../Header/Collectible/ICollectible.h" + +namespace Powerup +{ + + class PowerupController; + enum class PowerupType; + enum class MovementDirection; + + class PowerupService + { + private: + std::vector powerup_list; + std::vector flagged_powerup_list; + + PowerupController* createPowerup(PowerupType powerup_type); + void destroyFlaggedPowerup(); + void destroy(); + + public: + PowerupService(); + virtual ~PowerupService(); + + void initialize(); + void update(); + void render(); + + + PowerupController* spawnPowerup(PowerupType powerup_type, sf::Vector2f position); + void destroyPowerup(PowerupController* powerup_controller); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Powerups/PowerupView.h b/Space-Invaders/Header/Powerups/PowerupView.h new file mode 100644 index 000000000..d33eef621 --- /dev/null +++ b/Space-Invaders/Header/Powerups/PowerupView.h @@ -0,0 +1,34 @@ +#pragma once +#include +#include "../../Header/UI/UIElement/ImageView.h" + +namespace Powerup +{ + class PowerupController; + enum class PowerupType; + + class PowerupView + { + private: + const float powerup_sprite_width = 30.f; + const float powerup_sprite_height = 30.f; + + PowerupController* powerup_controller; + UI::UIElement::ImageView* powerup_image; + + void createUIElements(); + void initializeImage(); + sf::String getPowerupTexturePath(); + + void destroy(); + + public: + PowerupView(); + ~PowerupView(); + + void initialize(PowerupController* controller); + void update(); + void render(); + const sf::Sprite& getPowerupSprite(); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Projectile/IProjectile.h b/Space-Invaders/Header/Projectile/IProjectile.h new file mode 100644 index 000000000..770b0e973 --- /dev/null +++ b/Space-Invaders/Header/Projectile/IProjectile.h @@ -0,0 +1,21 @@ +#pragma once +#include +#include "../../Header/Bullet/BulletConfig.h" + +namespace Projectile +{ + enum class MovementDirection; + + class IProjectile + { + public: + virtual void initialize(sf::Vector2f position, Bullet::MovementDirection direction) = 0; + virtual void update() = 0; + virtual void render() = 0; + + virtual void updateProjectilePosition() = 0; + virtual sf::Vector2f getProjectilePosition() = 0; + + virtual ~IProjectile() {}; + }; +} diff --git a/Space-Invaders/Header/Sound/SoundService.h b/Space-Invaders/Header/Sound/SoundService.h new file mode 100644 index 000000000..195d86835 --- /dev/null +++ b/Space-Invaders/Header/Sound/SoundService.h @@ -0,0 +1,40 @@ +#pragma once +#include "SFML/Audio.hpp" + +namespace Sound +{ + enum class SoundType + { + BUTTON_CLICK, + BULLET_FIRE, + EXPLOSION, + POWERUP_ENABLED, + POWERUP_DISABLED, + }; + + class SoundService + { + private: + const int background_music_volume = 20; + + sf::Music background_music; + sf::Sound sound_effect; + sf::Sound explosion_sound_effect; + sf::Sound powerup_sound_effect; + + sf::SoundBuffer buffer_button_click; + sf::SoundBuffer buffer_bullet_fire; + sf::SoundBuffer buffer_explosion; + sf::SoundBuffer buffer_powerup_enabled; + sf::SoundBuffer buffer_powerup_disabled; + + void loadBackgroundMusicFromFile(); + void loadSoundFromFile(); + + public: + void initialize(); + + void playSound(SoundType soundType); + void playBackgroundMusic(); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Header/Time/TimeService.h b/Space-Invaders/Header/Time/TimeService.h new file mode 100644 index 000000000..71184c46e --- /dev/null +++ b/Space-Invaders/Header/Time/TimeService.h @@ -0,0 +1,32 @@ +#pragma once +#include + + // The TimeService class helps keep track of time in game and calculate delta time. + // Utilizes the library to calculate delta time. + +namespace Time +{ + class TimeService + { + private: + + // A point in time which indicates the starting time of previous frame. + std::chrono::time_point previous_time; + + float delta_time; //to store the detla time + + void updateDeltaTime(); // method to update time + float calculateDeltaTime(); //calculate time by subtracting the previous time from the current time + void updatePreviousTime(); // finally update the current time to be previous time + + public: + + //lifecycle methods + void initialize(); + void update(); + + //getter + float getDeltaTime(); + }; +} + diff --git a/Space-Invaders/Header/UI/GameplayUI/GameplayUIController.h b/Space-Invaders/Header/UI/GameplayUI/GameplayUIController.h new file mode 100644 index 000000000..03c3dc3ad --- /dev/null +++ b/Space-Invaders/Header/UI/GameplayUI/GameplayUIController.h @@ -0,0 +1,51 @@ +#pragma once +#include "../../header/UI/Interface/IUIController.h" +#include "../../header/UI/UIElement/ImageView.h" +#include "../../header/UI/UIElement/ButtonView.h" +#include "../../header/UI/UIElement/TextView.h" + +namespace UI +{ + namespace GameplayUI + { + class GameplayUIController : public Interface::IUIController + { + private: + // Constants: + const float font_size = 40.f; + + const float text_y_position = 15.f; + const float enemies_killed_text_x_position = 60.f; + + const float player_lives_y_offset = 25.f; + const float player_lives_x_offset = 1850.f; + const float player_lives_spacing = 60.f; + + const float player_sprite_width = 30.f; + const float player_sprite_height = 30.f; + + const sf::Color text_color = sf::Color::White; + + UI::UIElement::ImageView* player_image; + UI::UIElement::TextView* enemies_killed_text; + + void createUIElements(); + void initializeImage(); + void initializeText(); + + void destroy(); + + public: + GameplayUIController(); + ~GameplayUIController(); + + void initialize(); + void update(); + void render(); + void show(); + + void updateEnemiesKilledText(); + void drawPlayerLives(); + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/UI/Interface/IUIController.h b/Space-Invaders/Header/UI/Interface/IUIController.h new file mode 100644 index 000000000..c97cf8d7a --- /dev/null +++ b/Space-Invaders/Header/UI/Interface/IUIController.h @@ -0,0 +1,18 @@ +#pragma once +namespace UI +{ + namespace Interface + { + class IUIController + { + public: + + virtual void initialize() = 0; + virtual void update() = 0; + virtual void render() = 0; + virtual void show() = 0; + + virtual ~IUIController() { } + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/UI/MainMenu/MainMenuUIController.h b/Space-Invaders/Header/UI/MainMenu/MainMenuUIController.h new file mode 100644 index 000000000..1772f5c02 --- /dev/null +++ b/Space-Invaders/Header/UI/MainMenu/MainMenuUIController.h @@ -0,0 +1,52 @@ +#pragma once +#include +#include "../../header/UI/Interface/IUIController.h" +#include "../../header/UI/UIElement/ImageView.h" +#include "../../header/UI/UIElement/ButtonView.h" + +namespace UI +{ + namespace MainMenu + { + class MainMenuUIController :public Interface::IUIController + { + + private: + // Constants: + const float button_width = 400.f; + const float button_height = 140.f; + const float play_button_y_position = 500.f; + const float instructions_button_y_position = 700.f; + const float quit_button_y_position = 900.f; + const float background_alpha = 85.f; + UIElement::ImageView* background_image; + + // UI Elements + UIElement::ButtonView* play_button; + UIElement::ButtonView* instructions_button; + UIElement::ButtonView* quit_button; + + // Buttons and scaling + void createImage(); + void createButtons(); + void initializeBackgroundImage(); + void initializeButtons(); + void registerButtonCallback(); + + void playButtonCallback(); + void instructionsButtonCallback(); + void quitButtonCallback(); + + void destroy(); + + public: + MainMenuUIController(); + ~MainMenuUIController(); + + void initialize(); + void update(); + void render(); + void show() override; + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/UI/SplashScreen/SplashScreenUIController.h b/Space-Invaders/Header/UI/SplashScreen/SplashScreenUIController.h new file mode 100644 index 000000000..c1042b4c3 --- /dev/null +++ b/Space-Invaders/Header/UI/SplashScreen/SplashScreenUIController.h @@ -0,0 +1,36 @@ +#pragma once +#include "../../header/UI/Interface/IUIController.h" +#include "../../header/UI/UIElement/AnimatedImageView.h" + +namespace UI +{ + namespace SplashScreen + { + class SplashScreenUIController : public Interface::IUIController + { + private: + // Constants: + const float logo_animation_duration = 2.0f; + const float logo_width = 600.f; + const float logo_height = 134.f; + + UIElement::AnimatedImageView* outscal_logo_view; + + void initializeOutscalLogo(); + void fadeInAnimationCallback(); + void fadeOutAnimationCallback(); + sf::Vector2f getLogoPosition(); + + public: + + + SplashScreenUIController(); + ~SplashScreenUIController(); + + void initialize() override; + void update() override; + void render() override; + void show() override; + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/UI/UIElement/AnimatedImageView.h b/Space-Invaders/Header/UI/UIElement/AnimatedImageView.h new file mode 100644 index 000000000..a7b380960 --- /dev/null +++ b/Space-Invaders/Header/UI/UIElement/AnimatedImageView.h @@ -0,0 +1,56 @@ +#pragma once +#include "../../header/UI/UIElement/ImageView.h" +#include + +namespace UI +{ + namespace UIElement + { + enum class AnimationType + { + FADE_IN, + FADE_OUT, + }; + + class AnimatedImageView : public ImageView + { + private: + // Define a function pointer type for the callback function + using CallbackFunction = std::function; + + // Store the callback function + CallbackFunction callback_function = nullptr; + + void updateElapsedDuration(); + void handleAnimationProgress(); + void updateAnimation(); + + protected: + const float default_animation_duration = 2.0f; + + AnimationType animation_type; + float animation_duration; + float elapsed_duration; + sf::Clock clock; + + virtual void reset(); + void setAnimationDuration(float duration); + void setAnimationType(AnimationType type); + + virtual void fadeIn(); + virtual void fadeOut(); + + public: + AnimatedImageView(); + virtual ~AnimatedImageView(); + + virtual void initialize(sf::String texture_path, float image_width, float image_height, sf::Vector2f position) override; + virtual void update() override; + virtual void render() override; + + virtual void playAnimation(AnimationType type, float duration, CallbackFunction animation_end_callback); + + void registerCallbackFuntion(CallbackFunction animation_end_callback); + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/UI/UIElement/ButtonView.h b/Space-Invaders/Header/UI/UIElement/ButtonView.h new file mode 100644 index 000000000..10941f6a6 --- /dev/null +++ b/Space-Invaders/Header/UI/UIElement/ButtonView.h @@ -0,0 +1,37 @@ +#pragma once +#include "../../header/UI/UIElement/ImageView.h" +#include + +namespace UI +{ + namespace UIElement + { + class ButtonView : public ImageView + { + private: + // Define a function pointer type for the callback function + using CallbackFunction = std::function; + + // Store the callback function + CallbackFunction callback_function = nullptr; + + void printButtonClicked(); + + protected: + sf::String button_title; + + virtual void handleButtonInteraction(); + virtual bool clickedButton(sf::Sprite* button_sprite, sf::Vector2f mouse_position); + + public: + ButtonView(); + virtual ~ButtonView(); + + virtual void initialize(sf::String title, sf::String texture_path, float button_width, float button_height, sf::Vector2f position); + virtual void update() override; + virtual void render() override; + + void registerCallbackFuntion(CallbackFunction button_callback); + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/UI/UIElement/ImageView.h b/Space-Invaders/Header/UI/UIElement/ImageView.h new file mode 100644 index 000000000..2c23b9db5 --- /dev/null +++ b/Space-Invaders/Header/UI/UIElement/ImageView.h @@ -0,0 +1,36 @@ +#pragma once +#include "../../header/UI/UIElement/UIView.h" + +namespace UI +{ + namespace UIElement + { + class ImageView : public UIView + { + protected: + sf::Texture image_texture; + sf::Sprite image_sprite; + + public: + ImageView(); + virtual ~ImageView(); + + virtual void initialize(sf::String texture_path, float image_width, float image_height, sf::Vector2f position); + virtual void update() override; + virtual void render() override; + + virtual void setTexture(sf::String texture_path); + virtual void setScale(float width, float height); + virtual void setPosition(sf::Vector2f position); + virtual void setRotation(float rotation_angle); + virtual void setOriginAtCentre(); + virtual void setImageAlpha(float alpha); + virtual void setCentreAlinged(); + // animation sprite variants of scale and set + virtual void setTextureRect(sf::IntRect texture_rect); + virtual void setScale(float width, float height, float tile_width, float tile_height); + + const virtual sf::Sprite& getSprite(); + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/UI/UIElement/TextView.h b/Space-Invaders/Header/UI/UIElement/TextView.h new file mode 100644 index 000000000..5a5e51c6a --- /dev/null +++ b/Space-Invaders/Header/UI/UIElement/TextView.h @@ -0,0 +1,45 @@ +#pragma once +#include "../../header/UI/UIElement/UIView.h" + +namespace UI +{ + namespace UIElement + { + enum class FontType + { + BUBBLE_BOBBLE, + DS_DIGIB, + }; + + class TextView : public UIView + { + private: + static const int default_font_size = 55; + + static sf::Font font_bubble_bobble; + static sf::Font font_DS_DIGIB; + + sf::Text text; + + static void loadFont(); + + void setFont(FontType font_type); + void setFontSize(int font_size); + void setTextPosition(sf::Vector2f position); + void setTextColor(sf::Color color); + + public: + TextView(); + virtual ~TextView(); + + static void initializeTextView(); + + virtual void initialize(sf::String text_value, sf::Vector2f position, FontType font_type = FontType::BUBBLE_BOBBLE, int font_size = default_font_size, sf::Color color = sf::Color::White); + virtual void update() override; + virtual void render() override; + + void setText(sf::String text_value); + void setTextCentreAligned(); + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/UI/UIElement/UIView.h b/Space-Invaders/Header/UI/UIElement/UIView.h new file mode 100644 index 000000000..be748be05 --- /dev/null +++ b/Space-Invaders/Header/UI/UIElement/UIView.h @@ -0,0 +1,33 @@ +#pragma once +#include + +namespace UI +{ + namespace UIElement + { + enum class UIState + { + VISIBLE, + HIDDEN, + }; + + class UIView + { + protected: + sf::RenderWindow* game_window; + UIState ui_state; + + public: + UIView(); + virtual ~UIView(); + + virtual void initialize(); + virtual void update(); + virtual void render(); + + // to enable/disable render of ui + virtual void show(); + virtual void hide(); + }; + } +} \ No newline at end of file diff --git a/Space-Invaders/Header/UI/UIService.h b/Space-Invaders/Header/UI/UIService.h new file mode 100644 index 000000000..8d94aecdb --- /dev/null +++ b/Space-Invaders/Header/UI/UIService.h @@ -0,0 +1,30 @@ +#pragma once +#include "../../Header/UI/MainMenu/MainMenuUIController.h" +#include "../../header/UI/SplashScreen/SplashScreenUIController.h" +#include "../../header/UI/GameplayUI/GameplayUIController.h" +#include "../../Header/UI/Interface/IUIController.h" + +namespace UI +{ + class UIService + { + private: + MainMenu::MainMenuUIController* main_menu_controller; + GameplayUI::GameplayUIController* gameplay_ui_controller; + SplashScreen::SplashScreenUIController* splash_screen_ui_controller; + + void createControllers(); + void initializeControllers(); + Interface::IUIController* getCurrentUIController(); + void destroy(); + + public: + UIService(); + ~UIService(); + + void initialize(); + void update(); + void render(); + void showScreen(); + }; +} \ No newline at end of file diff --git a/Space-Invaders/Source/AnimationSystem/AnimationService.cpp b/Space-Invaders/Source/AnimationSystem/AnimationService.cpp new file mode 100644 index 000000000..47360e71a --- /dev/null +++ b/Space-Invaders/Source/AnimationSystem/AnimationService.cpp @@ -0,0 +1,63 @@ +#include "../../header/AnimationSystem/AnimationService.h" +#include "../../header/AnimationSystem/AnimationSystemConfigData.h" + +namespace Animation +{ + AnimationService::AnimationService() { } + + AnimationService::~AnimationService() { destroy(); } + + void AnimationService::initialize() { } + + void AnimationService::update() + { + for (AnimationSystem* animation_system : animation_system_list) + animation_system->update(); + + destroyFlaggedAnimationSystem(); + } + + void AnimationService::render() + { + for (AnimationSystem* animation_system : animation_system_list) + animation_system->render(); + } + + void AnimationService::spawnAnimationSystem(sf::Vector2f position, AnimationType animation_type) + { + AnimationSystem* animation_system = new AnimationSystem(getAnimationSystemConfig(animation_type)); + animation_system->initialize(position); + animation_system_list.push_back(animation_system); + } + + void AnimationService::destroyAnimationSystem(AnimationSystem* animation_system) + { + flagged_animation_system_list.push_back(animation_system); + animation_system_list.erase(std::remove(animation_system_list.begin(), animation_system_list.end(), animation_system), animation_system_list.end()); + } + + AnimationSystemConfig AnimationService::getAnimationSystemConfig(AnimationType animation_type) + { + switch (animation_type) + { + case Animation::AnimationType::EXPLOSION: + return explosion_animation_config; + } + } + + void AnimationService::destroyFlaggedAnimationSystem() + { + for (AnimationSystem* particle_system : flagged_animation_system_list) + delete (particle_system); + + flagged_animation_system_list.clear(); + } + + void AnimationService::reset() { destroy(); } + + void AnimationService::destroy() + { + for (AnimationSystem* animation_system : animation_system_list) + delete (animation_system); + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/AnimationSystem/AnimationSystem.cpp b/Space-Invaders/Source/AnimationSystem/AnimationSystem.cpp new file mode 100644 index 000000000..ea516759e --- /dev/null +++ b/Space-Invaders/Source/AnimationSystem/AnimationSystem.cpp @@ -0,0 +1,72 @@ +#include "../../header/AnimationSystem/AnimationSystem.h" +#include "../../header/Global/Config.h" +#include "../../header/Global/ServiceLocator.h" +#include "../../header/AnimationSystem/AnimationService.h" + +namespace Animation +{ + using namespace Global; + using namespace UI::UIElement; + + AnimationSystem::AnimationSystem(AnimationSystemConfig config) + { + animation_system_config = config; + createUIElements(); + } + + AnimationSystem::~AnimationSystem() + { + delete(animation_image); + } + + void AnimationSystem::initialize(sf::Vector2f position) + { + animation_position = position; + current_frame = 0; + frame_time = sf::seconds(animation_system_config.frame_duration); + + initializeImage(); + } + + void AnimationSystem::createUIElements() + { + animation_image = new ImageView(); + } + + void AnimationSystem::initializeImage() + { + animation_image->initialize(Config::explosion_texture_path, 0, 0, animation_position); + animation_image->setTextureRect(sf::IntRect(0, 0, animation_system_config.tile_width, animation_system_config.tile_height)); + + animation_image->setScale(animation_system_config.sprite_sheet_width, animation_system_config.sprite_sheet_height, animation_system_config.tile_width, animation_system_config.tile_height); + } + + void AnimationSystem::update() + { + if (clock.getElapsedTime() >= frame_time) + { + if (current_frame + 1 >= animation_system_config.number_of_animation_frames) + destroy(); + + current_frame = (current_frame + 1) % animation_system_config.number_of_animation_frames; + clock.restart(); + + animation_image->setTextureRect(sf::IntRect( + current_frame * animation_system_config.tile_width, + 0, + animation_system_config.tile_width, + animation_system_config.tile_height)); + } + animation_image->update(); + } + + void AnimationSystem::render() + { + animation_image->render(); + } + + void AnimationSystem::destroy() + { + ServiceLocator::getInstance()->getAnimationService()->destroyAnimationSystem(this); + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Bullet/BulletConfig.cpp b/Space-Invaders/Source/Bullet/BulletConfig.cpp new file mode 100644 index 000000000..2d29edd85 --- /dev/null +++ b/Space-Invaders/Source/Bullet/BulletConfig.cpp @@ -0,0 +1,25 @@ +#include "../../Header/Bullet/BulletConfig.h" + +namespace Bullet +{ + const sf::String BulletConfig::laser_bullet_texture_path = "assets/textures/laser_bullet.png"; + + const sf::String BulletConfig::torpedoe_texture_path = "assets/textures/torpedoe.png"; + + const sf::String BulletConfig::frost_beam_texture_path = "assets/textures/frost_beam.png"; + + sf::String BulletConfig::getBulletTexturePath(BulletType bullet_type) + { + switch (bullet_type) + { + case::Bullet::BulletType::LASER_BULLET: + return laser_bullet_texture_path; + + case::Bullet::BulletType::FROST_BULLET: + return frost_beam_texture_path; + + case::Bullet::BulletType::TORPEDO: + return torpedoe_texture_path; + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Bullet/BulletController.cpp b/Space-Invaders/Source/Bullet/BulletController.cpp new file mode 100644 index 000000000..0ba4beb69 --- /dev/null +++ b/Space-Invaders/Source/Bullet/BulletController.cpp @@ -0,0 +1,153 @@ +#include "../../Header/Bullet/BulletController.h" +#include "../../Header/Bullet/BulletView.h" +#include "../../Header/Bullet/BulletModel.h" +#include "../../Header/Bullet/BulletConfig.h" +#include "../../Header/Global/ServiceLocator.h" +#include "../../Header/Player/PlayerController.h" +#include "../../Header/Enemy/EnemyController.h" +#include "../../Header/Element/Bunker/BunkerController.h" + +namespace Bullet +{ + using namespace Global; + using namespace Entity; + using namespace Player; + using namespace Enemy; + using namespace Element::Bunker; + + BulletController::BulletController(BulletType type, Entity::EntityType owner_type) + { + bullet_view = new BulletView(); + bullet_model = new BulletModel(type, owner_type); + } + + BulletController::~BulletController() + { + delete (bullet_view); + delete (bullet_model); + } + + void BulletController::initialize(sf::Vector2f position, Bullet::MovementDirection direction) + { + bullet_view->initialize(this); + bullet_model->initialize(position, direction); + } + + void BulletController::update() + { + updateProjectilePosition(); + bullet_view->update(); + handleOutOfBounds(); + } + + void BulletController::render() + { + bullet_view->render(); + } + + void Bullet::BulletController::moveUp() + { + sf::Vector2f currentPosition = bullet_model->getBulletPosition(); + currentPosition.y -= bullet_model->getMovementSpeed() * ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + + bullet_model->setBulletPosition(currentPosition); + } + + void Bullet::BulletController::moveDown() + { + sf::Vector2f currentPosition = bullet_model->getBulletPosition(); + currentPosition.y += bullet_model->getMovementSpeed() * ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + + bullet_model->setBulletPosition(currentPosition); + } + + void Bullet::BulletController::handleOutOfBounds() + { + sf::Vector2f bulletPosition = getProjectilePosition(); + sf::Vector2u windowSize = ServiceLocator::getInstance()->getGraphicService()->getGameWindow()->getSize(); + + if (bulletPosition.x < 0 || bulletPosition.x > windowSize.x || + bulletPosition.y < 0 || bulletPosition.y > windowSize.y) + { + ServiceLocator::getInstance()->getBulletService()->destroyBullet(this); + } + } + + sf::Vector2f BulletController::getProjectilePosition() + { + return bullet_model->getBulletPosition(); + } + + BulletType BulletController::getBulletType() + { + return bullet_model->getBulletType(); + } + + Entity::EntityType BulletController::getOwnerEntityType() + { + return bullet_model->getOwnerEntityType(); + } + + const sf::Sprite& BulletController::getColliderSprite() + { + return bullet_view->getBulletSprite(); + } + + void BulletController::onCollision(ICollider* other_collider) + { + processPlayerCollision(other_collider); + processEnemyCollision(other_collider); + processBunkerCollision(other_collider); + processBulletCollision(other_collider); + } + + void Bullet::BulletController::updateProjectilePosition() + { + switch (bullet_model->getMovementDirection()) + { + case::Bullet::MovementDirection::UP: + moveUp(); + break; + + case::Bullet::MovementDirection::DOWN: + moveDown(); + break; + } + } + + void BulletController::processBulletCollision(ICollider* other_collider) + { + BulletController* bullet_controller = dynamic_cast(other_collider); + + if (bullet_controller) + ServiceLocator::getInstance()->getBulletService()->destroyBullet(this); + } + + void BulletController::processEnemyCollision(ICollider* other_collider) + { + EnemyController* enemy_controller = dynamic_cast(other_collider); + + if (enemy_controller && getOwnerEntityType() != EntityType::ENEMY) + { + ServiceLocator::getInstance()->getBulletService()->destroyBullet(this); + } + } + + void BulletController::processPlayerCollision(ICollider* other_collider) + { + PlayerController* player_controller = dynamic_cast(other_collider); + + if (player_controller && getOwnerEntityType() != EntityType::PLAYER) + { + ServiceLocator::getInstance()->getBulletService()->destroyBullet(this); + } + } + + void BulletController::processBunkerCollision(ICollider* other_collider) + { + BunkerController* bunker_controller = dynamic_cast(other_collider); + + if (bunker_controller) + ServiceLocator::getInstance()->getBulletService()->destroyBullet(this); + } +} diff --git a/Space-Invaders/Source/Bullet/BulletModel.cpp b/Space-Invaders/Source/Bullet/BulletModel.cpp new file mode 100644 index 000000000..f0020975b --- /dev/null +++ b/Space-Invaders/Source/Bullet/BulletModel.cpp @@ -0,0 +1,60 @@ +#include "../../Header/Bullet/BulletModel.h" + +namespace Bullet +{ + using namespace Entity; + + BulletModel::BulletModel(BulletType type, EntityType owner_type) + { + this->bullet_type = type; + this->owner_type = owner_type; + } + + BulletModel::~BulletModel() { } + + void BulletModel::initialize(sf::Vector2f position, MovementDirection direction) + { + movement_direction = direction; + bullet_position = position; + } + + sf::Vector2f BulletModel::getBulletPosition() + { + return bullet_position; + } + + void BulletModel::setBulletPosition(sf::Vector2f position) + { + bullet_position = position; + } + + BulletType BulletModel::getBulletType() + { + return bullet_type; + } + + Entity::EntityType BulletModel::getOwnerEntityType() + { + return owner_type; + } + + MovementDirection BulletModel::getMovementDirection() + { + return movement_direction; + } + + void BulletModel::setMovementDirection(MovementDirection direction) + { + movement_direction = direction; + } + + float BulletModel::getMovementSpeed() + { + return movement_speed; + } + + void BulletModel::setMovementSpeed(float speed) + { + movement_speed = speed; + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Bullet/BulletService.cpp b/Space-Invaders/Source/Bullet/BulletService.cpp new file mode 100644 index 000000000..1750745c3 --- /dev/null +++ b/Space-Invaders/Source/Bullet/BulletService.cpp @@ -0,0 +1,107 @@ +#include "../../Header/Bullet/BulletService.h" +#include "../../Header/Bullet/BulletController.h" +#include "../../Header/Bullet/BulletConfig.h" +#include "../../Header/Bullet/Controllers/FrostBulletController.h" +#include "../../Header/Bullet/Controllers/LaserBulletController.h" +#include "../../Header/Bullet/Controllers/TorpedoController.h" +#include "../../Header/Collision/ICollider.h" +#include "../../Header/Global/ServiceLocator.h" + +namespace Bullet +{ + using namespace Controller; + using namespace Projectile; + using namespace Entity; + using namespace Global; + using namespace Collision; + + BulletService::BulletService() { } + + BulletService::~BulletService() { destroy(); } + + void BulletService::initialize() + { + bullet_list.clear(); + flagged_bullet_list.clear(); + } + + void BulletService::update() + { + for (Projectile::IProjectile* bullet : bullet_list) + bullet->update(); + + destroyFlaggedBullets(); + } + + void BulletService::render() + { + for (Projectile::IProjectile* bullet : bullet_list) + bullet->render(); + } + + BulletController* BulletService::createBullet(BulletType type, Entity::EntityType owner_type) + { + switch (type) + { + case::Bullet::BulletType::LASER_BULLET: + return new LaserBulletController(Bullet::BulletType::LASER_BULLET, owner_type); + + case::Bullet::BulletType::FROST_BULLET: + return new FrostBulletController(Bullet::BulletType::FROST_BULLET, owner_type); + + case::Bullet::BulletType::TORPEDO: + return new TorpedoController(Bullet::BulletType::TORPEDO, owner_type); + } + } + + bool BulletService::isValidBullet(int index, std::vector& bullet_list) + { + return index >= 0 && index < bullet_list.size() && bullet_list[index] != nullptr; + } + + void BulletService::destroyFlaggedBullets() + { + for (int i = 0; i < flagged_bullet_list.size(); i++) + { + if (!isValidBullet(i, flagged_bullet_list)) continue; + + ServiceLocator::getInstance()->getCollisionService()->removeCollider(dynamic_cast(flagged_bullet_list[i])); + delete (flagged_bullet_list[i]); + } + flagged_bullet_list.clear(); + } + + void BulletService::destroy() + { + for (int i = 0; i < bullet_list.size(); i++) + { + if (!isValidBullet(i, bullet_list)) continue; + + ServiceLocator::getInstance()->getCollisionService()->removeCollider(dynamic_cast(bullet_list[i])); + delete (bullet_list[i]); + } + bullet_list.clear(); + } + + BulletController* BulletService::spawnBullet(BulletType type, sf::Vector2f position, MovementDirection direction, Entity::EntityType owner_type) + { + BulletController* bullet_controller = createBullet(type, owner_type); + bullet_controller->initialize(position, direction); + + ServiceLocator::getInstance()->getCollisionService()->addCollider(dynamic_cast(bullet_controller)); + bullet_list.push_back(bullet_controller); + return bullet_controller; + } + + void BulletService::destroyBullet(BulletController* bullet_controller) + { + dynamic_cast(bullet_controller)->disableCollision(); + flagged_bullet_list.push_back(bullet_controller); + bullet_list.erase(std::remove(bullet_list.begin(), bullet_list.end(), bullet_controller), bullet_list.end()); + } + + void BulletService::reset() + { + destroy(); + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Bullet/BulletView.cpp b/Space-Invaders/Source/Bullet/BulletView.cpp new file mode 100644 index 000000000..5084b2355 --- /dev/null +++ b/Space-Invaders/Source/Bullet/BulletView.cpp @@ -0,0 +1,67 @@ +#include "../../Header/Bullet/BulletView.h" +#include "../../Header/Bullet/BulletController.h" +#include "../../Header/Global/ServiceLocator.h" +#include "../../Header/Global/Config.h" +#include "../../Header/Bullet/BulletConfig.h" + +namespace Bullet +{ + using namespace Global; + using namespace UI::UIElement; + + BulletView::BulletView() { createUIElements(); } + + BulletView::~BulletView() { destroy(); } + + void BulletView::initialize(BulletController* controller) + { + bullet_controller = controller; + initializeImage(); + } + + void BulletView::createUIElements() + { + bullet_image = new ImageView(); + } + + void BulletView::initializeImage() + { + bullet_image->initialize(getBulletTexturePath(), bullet_sprite_width, bullet_sprite_height, bullet_controller->getProjectilePosition()); + } + + void BulletView::update() + { + bullet_image->setPosition(bullet_controller->getProjectilePosition()); + bullet_image->update(); + } + + void BulletView::render() + { + bullet_image->render(); + } + + sf::String BulletView::getBulletTexturePath() + { + switch (bullet_controller->getBulletType()) + { + case::Bullet::BulletType::LASER_BULLET: + return Config::laser_bullet_texture_path; + + case::Bullet::BulletType::FROST_BULLET: + return Config::frost_beam_texture_path; + + case::Bullet::BulletType::TORPEDO: + return Config::torpedoe_texture_path; + } + } + + const sf::Sprite& BulletView::getBulletSprite() + { + return bullet_image->getSprite(); + } + + void BulletView::destroy() + { + delete (bullet_image); + } +} diff --git a/Space-Invaders/Source/Bullet/Controllers/FrostBulletController.cpp b/Space-Invaders/Source/Bullet/Controllers/FrostBulletController.cpp new file mode 100644 index 000000000..d2033ebcc --- /dev/null +++ b/Space-Invaders/Source/Bullet/Controllers/FrostBulletController.cpp @@ -0,0 +1,18 @@ +#include "../../Header/Bullet/Controllers/FrostBulletController.h" +#include "../../Header/Bullet/BulletModel.h" + +namespace Bullet +{ + namespace Controller + { + FrostBulletController::FrostBulletController(BulletType type, Entity::EntityType owner_type) : BulletController(type, owner_type) { } + + FrostBulletController::~FrostBulletController() { } + + void FrostBulletController::initialize(sf::Vector2f position, MovementDirection direction) + { + BulletController::initialize(position, direction); + bullet_model->setMovementSpeed(frost_bullet_movement_speed); + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Bullet/Controllers/LaserBulletController.cpp b/Space-Invaders/Source/Bullet/Controllers/LaserBulletController.cpp new file mode 100644 index 000000000..fd9f7194b --- /dev/null +++ b/Space-Invaders/Source/Bullet/Controllers/LaserBulletController.cpp @@ -0,0 +1,16 @@ +#include "../../Header/Bullet/Controllers/LaserBulletController.h" + +namespace Bullet +{ + namespace Controller + { + LaserBulletController::LaserBulletController(BulletType type, Entity::EntityType owner_type) : BulletController(type, owner_type) { } + + LaserBulletController::~LaserBulletController() { } + + void LaserBulletController::initialize(sf::Vector2f position, MovementDirection direction) + { + BulletController::initialize(position, direction); + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Bullet/Controllers/TorpedoController.cpp b/Space-Invaders/Source/Bullet/Controllers/TorpedoController.cpp new file mode 100644 index 000000000..6f4a177e5 --- /dev/null +++ b/Space-Invaders/Source/Bullet/Controllers/TorpedoController.cpp @@ -0,0 +1,20 @@ +#include "../../Header/Bullet/Controllers/TorpedoController.h" +#include "../../Header/Bullet/BulletModel.h" + +namespace Bullet +{ + namespace Controller + { + using namespace Entity; + + TorpedoController::TorpedoController(BulletType type, Entity::EntityType owner_type) : BulletController(type, owner_type) { } + + TorpedoController::~TorpedoController() { } + + void TorpedoController::initialize(sf::Vector2f position, MovementDirection direction) + { + BulletController::initialize(position, direction); + bullet_model->setMovementSpeed(torpedo_movement_speed); + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Collision/CollisionService.cpp b/Space-Invaders/Source/Collision/CollisionService.cpp new file mode 100644 index 000000000..b5c83a8c7 --- /dev/null +++ b/Space-Invaders/Source/Collision/CollisionService.cpp @@ -0,0 +1,66 @@ +#include "../../Header/Collision/CollisionService.h" +#include "../../Header/Collision/ICollider.h" + +namespace Collision +{ + CollisionService::CollisionService() { } + + CollisionService::~CollisionService() { } + + void CollisionService::initialize() { } + + void CollisionService::update() + { + processCollision(); + } + + void CollisionService::processCollision() + { + for (int i = 0; i < collider_list.size(); i++) + { + for (int j = i + 1; j < collider_list.size(); j++) + { + doCollision(i, j); + } + } + } + + void CollisionService::doCollision(int index_i, int index_j) + { + if (collider_list[index_i]->getCollisionState() == CollisionState::DISABLED || + collider_list[index_j]->getCollisionState() == CollisionState::DISABLED) return; + + if (hasCollisionOccurred(index_i, index_j)) + { + if (areActiveColliders(index_i, index_j)) + collider_list[index_i]->onCollision(collider_list[index_j]); + + if (areActiveColliders(index_i, index_j)) + collider_list[index_j]->onCollision(collider_list[index_i]); + } + } + + bool CollisionService::hasCollisionOccurred(int index_i, int index_j) + { + const sf::Sprite& collider_one_sprite = collider_list[index_i]->getColliderSprite(); + const sf::Sprite& collider_two_sprite = collider_list[index_j]->getColliderSprite(); + + return collider_one_sprite.getGlobalBounds().intersects(collider_two_sprite.getGlobalBounds()); + } + + bool CollisionService::areActiveColliders(int index_i, int index_j) + { + return (index_i < collider_list.size() && index_j < collider_list.size() && + collider_list[index_i] != nullptr && collider_list[index_j] != nullptr); + } + + void CollisionService::addCollider(ICollider* collider) + { + collider_list.push_back(collider); + } + + void CollisionService::removeCollider(ICollider* collider) + { + collider_list.erase(std::remove(collider_list.begin(), collider_list.end(), collider), collider_list.end()); + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Collision/ICollider.cpp b/Space-Invaders/Source/Collision/ICollider.cpp new file mode 100644 index 000000000..16829d4f6 --- /dev/null +++ b/Space-Invaders/Source/Collision/ICollider.cpp @@ -0,0 +1,14 @@ +#include "../../Header/Collision/ICollider.h" + +namespace Collision +{ + ICollider::ICollider() { collision_state = CollisionState::ENABLED; } + + ICollider::~ICollider() { } + + void ICollider::enableCollision() { collision_state = CollisionState::ENABLED; } + + void ICollider::disableCollision() { collision_state = CollisionState::DISABLED; } + + CollisionState ICollider::getCollisionState() { return collision_state; } +} diff --git a/Space-Invaders/Source/Element/Bunker/BunkerController.cpp b/Space-Invaders/Source/Element/Bunker/BunkerController.cpp new file mode 100644 index 000000000..882500eb6 --- /dev/null +++ b/Space-Invaders/Source/Element/Bunker/BunkerController.cpp @@ -0,0 +1,47 @@ +#include "../../header/Element/Bunker/BunkerController.h" +#include "../../header/Element/Bunker/BunkerView.h" +#include "../../../header/Bullet/BulletController.h" +#include "../../../header/Entity/EntityConfig.h" +#include "../../header/Global/ServiceLocator.h" +#include "../../../header/Bullet/BulletConfig.h" + +namespace Element +{ + namespace Bunker + { + using namespace Bullet; + using namespace Entity; + using namespace Global; + + BunkerController::BunkerController() { bunker_view = new BunkerView(); } + + BunkerController::~BunkerController() { delete(bunker_view); } + + void BunkerController::initialize(BunkerData data) + { + bunker_data = data; + bunker_view->initialize(this); + } + + void BunkerController::update() { bunker_view->update(); } + + void BunkerController::render() { bunker_view->render(); } + + sf::Vector2f BunkerController::getBunkerPosition() { return bunker_data.position; } + + const sf::Sprite& BunkerController::getColliderSprite() + { + return bunker_view->getBunkerSprite(); + } + + void BunkerController::onCollision(ICollider* other_collider) + { + BulletController* bullet_controller = dynamic_cast(other_collider); + + if (bullet_controller && bullet_controller->getBulletType() == BulletType::TORPEDO) + { + ServiceLocator::getInstance()->getElementService()->destroyBunker(this); + } + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Element/Bunker/BunkerModel.cpp b/Space-Invaders/Source/Element/Bunker/BunkerModel.cpp new file mode 100644 index 000000000..04d29b58d --- /dev/null +++ b/Space-Invaders/Source/Element/Bunker/BunkerModel.cpp @@ -0,0 +1,14 @@ +#include "../../header/Element/Bunker/BunkerModel.h" + +namespace Element +{ + namespace Bunker + { + BunkerData::BunkerData() { }; + + BunkerData::BunkerData(sf::Vector2f position) + { + this->position = position; + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Element/Bunker/BunkerView.cpp b/Space-Invaders/Source/Element/Bunker/BunkerView.cpp new file mode 100644 index 000000000..25e56380f --- /dev/null +++ b/Space-Invaders/Source/Element/Bunker/BunkerView.cpp @@ -0,0 +1,55 @@ +#include "../../header/Element/Bunker/BunkerView.h" +#include "../../header/Global/ServiceLocator.h" +#include "../../Header/Graphic/GraphicService.h" +#include "../../header/Element/Bunker/BunkerController.h" +#include "../../Header/Global/Config.h" + +namespace Element +{ + namespace Bunker + { + using namespace Global; + using namespace UI::UIElement; + + BunkerView::BunkerView() { createUIElements(); } + + BunkerView::~BunkerView() { destroy(); } + + void BunkerView::initialize(BunkerController* controller) + { + bunker_controller = controller; + initializeImage(); + } + + const sf::Sprite& BunkerView::getBunkerSprite() + { + return bunker_image->getSprite(); + } + + void BunkerView::createUIElements() + { + bunker_image = new ImageView(); + } + + void BunkerView::initializeImage() + { + bunker_image->initialize(Config::bunker_texture_path, bunker_sprite_width, bunker_sprite_height, bunker_controller->getBunkerPosition()); + } + + void BunkerView::update() + { + bunker_image->update(); + } + + void BunkerView::render() + { + bunker_image->render(); + } + + void BunkerView::destroy() + { + delete(bunker_image); + } + + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Element/ElementService.cpp b/Space-Invaders/Source/Element/ElementService.cpp new file mode 100644 index 000000000..1d6f11db0 --- /dev/null +++ b/Space-Invaders/Source/Element/ElementService.cpp @@ -0,0 +1,77 @@ +#include "../../header/Element/ElementService.h" +#include "../../header/Collision/ICollider.h" +#include "../../header/Global/ServiceLocator.h" + +namespace Element +{ + using namespace Global; + using namespace Collision; + + ElementService::ElementService() { } + + ElementService::~ElementService() { destroy(); } + + void ElementService::initialize() + { + spawnBunkers(); + } + + void ElementService::update() + { + for (Bunker::BunkerController* bunker : bunker_list) + bunker->update(); + + destroyFlaggedBunkers(); + } + + void ElementService::render() + { + for (Bunker::BunkerController* bunker : bunker_list) + bunker->render(); + } + + void ElementService::reset() + { + destroy(); + spawnBunkers(); + } + + void ElementService::destroyBunker(Bunker::BunkerController* bunker_controller) + { + flagged_bunker_list.push_back(bunker_controller); + bunker_list.erase(std::remove(bunker_list.begin(), bunker_list.end(), bunker_controller), bunker_list.end()); + } + + void ElementService::spawnBunkers() + { + for (int i = 0; i < bunker_data_list.size(); i++) + { + Bunker::BunkerController* bunker_controller = new Bunker::BunkerController(); + + bunker_controller->initialize(bunker_data_list[i]); + bunker_list.push_back(bunker_controller); + + ServiceLocator::getInstance()->getCollisionService()->addCollider(dynamic_cast(bunker_controller)); + } + } + + void ElementService::destroyFlaggedBunkers() + { + for (int i = 0; i < flagged_bunker_list.size(); i++) + { + ServiceLocator::getInstance()->getCollisionService()->removeCollider(dynamic_cast(flagged_bunker_list[i])); + delete (flagged_bunker_list[i]); + } + flagged_bunker_list.clear(); + } + + void ElementService::destroy() + { + for (int i = 0; i < bunker_list.size(); i++) + { + ServiceLocator::getInstance()->getCollisionService()->removeCollider(dynamic_cast(bunker_list[i])); + delete(bunker_list[i]); + } + bunker_list.clear(); + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Enemy/Controllers/SubZeroController.cpp b/Space-Invaders/Source/Enemy/Controllers/SubZeroController.cpp new file mode 100644 index 000000000..bc204a90c --- /dev/null +++ b/Space-Invaders/Source/Enemy/Controllers/SubZeroController.cpp @@ -0,0 +1,58 @@ +#include "../../Header/Enemy/Controllers/SubZeroController.h" +#include "../../header/Enemy/EnemyView.h" +#include "../../Header/Enemy/EnemyModel.h" +#include "../../header/Enemy/EnemyConfig.h" +#include "../../Header/Global/ServiceLocator.h" +#include "../../header/Bullet/BulletConfig.h" + +namespace Enemy +{ + using namespace Global; + using namespace Time; + using namespace Bullet; + + namespace Controller + { + SubzeroController::SubzeroController(EnemyType type):EnemyController(type) { } + + SubzeroController::~SubzeroController() { } + + void SubzeroController::initialize() + { + EnemyController::initialize(); + enemy_model->setMovementDirection(MovementDirection::DOWN); + rate_of_fire = subzero_rate_of_fire; + vertical_movement_speed = subzero_vertical_movement_speed; + } + + void SubzeroController::move() + { + switch (enemy_model->getMovementDirection()) + { + case::Enemy::MovementDirection::DOWN: + moveDown(); + break; + } + } + + void SubzeroController::moveDown() + { + sf::Vector2f currentPosition = enemy_model->getEnemyPosition(); + currentPosition.y += vertical_movement_speed * ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + + enemy_model->setEnemyPosition(currentPosition); + } + + void SubzeroController::fireBullet() + { + ServiceLocator::getInstance()->getBulletService()->spawnBullet(BulletType::FROST_BULLET, + enemy_model->getEnemyPosition() + enemy_model->barrel_position_offset, + Bullet::MovementDirection::DOWN, enemy_model->getEntityType()); + } + + void SubzeroController::destroy() + { + EnemyController::destroy(); + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Enemy/Controllers/ThunderSnakeController.cpp b/Space-Invaders/Source/Enemy/Controllers/ThunderSnakeController.cpp new file mode 100644 index 000000000..92a84f7eb --- /dev/null +++ b/Space-Invaders/Source/Enemy/Controllers/ThunderSnakeController.cpp @@ -0,0 +1,126 @@ +#include "../../Header/Enemy/Controllers/ThunderSnakeController.h" +#include "../../Header/Enemy/EnemyView.h" +#include "../../Header/Enemy/EnemyModel.h" +#include "../../Header/Global/ServiceLocator.h" +#include "../../Header/Bullet/BulletConfig.h" + +namespace Enemy +{ + using namespace Global; + using namespace Time; + using namespace Bullet; + + namespace Controller + { + ThunderSnakeController::ThunderSnakeController(EnemyType type) : EnemyController(type) { } + + ThunderSnakeController::~ThunderSnakeController() { } + + void ThunderSnakeController::initialize() + { + EnemyController::initialize(); + enemy_model->setMovementDirection(getInitialMovementDirection()); + horizontal_movement_speed = thunder_snake_horizontal_movement_speed; + } + + MovementDirection ThunderSnakeController::getInitialMovementDirection() + { + static MovementDirection initial_direction = MovementDirection::RIGHT; + + switch (initial_direction) + { + case Enemy::MovementDirection::LEFT: + initial_direction = MovementDirection::RIGHT; + return initial_direction; + + case Enemy::MovementDirection::RIGHT: + initial_direction = MovementDirection::LEFT; + return initial_direction; + } + } + + void ThunderSnakeController::move() + { + switch (enemy_model->getMovementDirection()) + { + case::Enemy::MovementDirection::LEFT: + moveLeft(); + break; + + case::Enemy::MovementDirection::RIGHT: + moveRight(); + break; + + case::Enemy::MovementDirection::LEFT_DOWN: + moveDiagonalLeft(); + break; + + case::Enemy::MovementDirection::RIGHT_DOWN: + moveDiagonalRight(); + break; + } + } + + void ThunderSnakeController::moveLeft() + { + sf::Vector2f currentPosition = enemy_model->getEnemyPosition(); + currentPosition.x -= horizontal_movement_speed * ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + + if (currentPosition.x <= enemy_model->left_most_position.x) + { + enemy_model->setMovementDirection(MovementDirection::RIGHT_DOWN); + } + else enemy_model->setEnemyPosition(currentPosition); + } + + void ThunderSnakeController::moveRight() + { + sf::Vector2f currentPosition = enemy_model->getEnemyPosition(); + currentPosition.x += horizontal_movement_speed * ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + + if (currentPosition.x >= enemy_model->right_most_position.x) + { + enemy_model->setMovementDirection(MovementDirection::LEFT_DOWN); + } + else enemy_model->setEnemyPosition(currentPosition); + } + + void ThunderSnakeController::moveDiagonalLeft() + { + sf::Vector2f currentPosition = enemy_model->getEnemyPosition(); + currentPosition.y += vertical_movement_speed * ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + currentPosition.x -= horizontal_movement_speed * ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + + if (currentPosition.x <= enemy_model->left_most_position.x) + { + enemy_model->setMovementDirection(MovementDirection::RIGHT); + } + else enemy_model->setEnemyPosition(currentPosition); + } + + void ThunderSnakeController::moveDiagonalRight() + { + sf::Vector2f currentPosition = enemy_model->getEnemyPosition(); + currentPosition.y += vertical_movement_speed * ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + currentPosition.x += horizontal_movement_speed * ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + + if (currentPosition.x >= enemy_model->right_most_position.x) + { + enemy_model->setMovementDirection(MovementDirection::LEFT); + } + else enemy_model->setEnemyPosition(currentPosition); + } + + void ThunderSnakeController::fireBullet() + { + ServiceLocator::getInstance()->getBulletService()->spawnBullet(BulletType::TORPEDO, + enemy_model->getEnemyPosition() + enemy_model->barrel_position_offset, + Bullet::MovementDirection::DOWN, enemy_model->getEntityType()); + } + + void ThunderSnakeController::destroy() + { + EnemyController::destroy(); + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Enemy/Controllers/UFOController.cpp b/Space-Invaders/Source/Enemy/Controllers/UFOController.cpp new file mode 100644 index 000000000..7eb92e493 --- /dev/null +++ b/Space-Invaders/Source/Enemy/Controllers/UFOController.cpp @@ -0,0 +1,100 @@ +#include "../../Header/Enemy/Controllers/UFOController.h" +#include "../../Header/Enemy/EnemyView.h" +#include "../../Header/Enemy/EnemyModel.h" +#include "../../Header/Enemy/EnemyConfig.h" +#include "../../Header/Global/ServiceLocator.h" +#include "../../Header/Bullet/BulletConfig.h" +#include "../../Header/Powerups/PowerupService.h" +#include "../../Header/Bullet/BulletController.h" +#include "../../Header/Entity/EntityConfig.h" + + +namespace Enemy +{ + using namespace Global; + using namespace Bullet; + using namespace Time; + using namespace Entity; + + namespace Controller + { + UFOController::UFOController(EnemyType type) : EnemyController(type) { } + + UFOController::~UFOController() { } + + void UFOController::initialize() + { + EnemyController::initialize(); + } + + void UFOController::fireBullet() + { + } + + Powerup::PowerupType UFOController::getRandomPowerupType() + { + std::srand(static_cast(std::time(nullptr))); + + //We add '1' to OutscalBomb below because enum has a 0 index, making the bomb number 3, we need to add 1 to make it 4 + + int random_value = std::rand() % (static_cast(Powerup::PowerupType::OUTSCAL_BOMB) + 1); + return static_cast(random_value); + } + + void UFOController::move() + { + switch (enemy_model->getMovementDirection()) + { + case::Enemy::MovementDirection::LEFT: + moveLeft(); + break; + + case::Enemy::MovementDirection::RIGHT: + moveRight(); + break; + } + } + + void UFOController::moveLeft() + { + sf::Vector2f currentPosition = enemy_model->getEnemyPosition(); + currentPosition.x -= horizontal_movement_speed * ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + + if (currentPosition.x <= enemy_model->left_most_position.x) + { + enemy_model->setMovementDirection(MovementDirection::RIGHT); + enemy_model->setReferencePosition(currentPosition); + } + else enemy_model->setEnemyPosition(currentPosition); + } + + void UFOController::moveRight() + { + sf::Vector2f currentPosition = enemy_model->getEnemyPosition(); + currentPosition.x += horizontal_movement_speed * ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + + if (currentPosition.x >= enemy_model->right_most_position.x) + { + enemy_model->setMovementDirection(MovementDirection::LEFT); + enemy_model->setReferencePosition(currentPosition); + } + else enemy_model->setEnemyPosition(currentPosition); + } + + void UFOController::onCollision(ICollider* other_collider) + { + EnemyController::onCollision(other_collider); + BulletController* bullet_controller = dynamic_cast(other_collider); + + if (bullet_controller && bullet_controller->getOwnerEntityType() != EntityType::ENEMY) + { + ServiceLocator::getInstance()->getPowerupService()->spawnPowerup(getRandomPowerupType(), enemy_model->getEnemyPosition()); + return; + } + } + void UFOController::destroy() + { + EnemyController::destroy(); + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Enemy/Controllers/ZapperController.cpp b/Space-Invaders/Source/Enemy/Controllers/ZapperController.cpp new file mode 100644 index 000000000..b1660bf2e --- /dev/null +++ b/Space-Invaders/Source/Enemy/Controllers/ZapperController.cpp @@ -0,0 +1,113 @@ +#include "../../Header/Enemy/Controllers/ZapperController.h" +#include "../../Header/Enemy/EnemyModel.h" +#include "../../Header/Enemy/EnemyView.h" +#include "../../Header/Enemy/EnemyConfig.h" +#include "../../Header/Global/ServiceLocator.h" +#include "../../Header/Bullet/BulletConfig.h" + +namespace Enemy +{ + using namespace Global; + using namespace Time; + using namespace Bullet; + + namespace Controller + { + ZapperController::ZapperController(EnemyType type) : EnemyController(type){ } + + ZapperController::~ZapperController() { } + + void ZapperController::initialize() + { + EnemyController::initialize();; + } + + void ZapperController::move() + { + // Switch statement based on the movement direction of the enemy + switch (enemy_model->getMovementDirection()) + { + // If the movement direction is LEFT + case::Enemy::MovementDirection::LEFT: + moveLeft(); + break; + + // If the movement direction is RIGHT + case::Enemy::MovementDirection::RIGHT: + moveRight(); + break; + + // If the movement direction is DOWN + case::Enemy::MovementDirection::DOWN: + moveDown(); + break; + } + } + + void ZapperController::moveLeft() + { + sf::Vector2f currentPosition = enemy_model->getEnemyPosition(); + currentPosition.x -= horizontal_movement_speed * ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + + if (currentPosition.x <= enemy_model->left_most_position.x) + { + enemy_model->setMovementDirection(MovementDirection::DOWN); + enemy_model->setReferencePosition(currentPosition); + } + else + { + enemy_model->setEnemyPosition(currentPosition); + } + } + + void ZapperController::moveRight() + { + sf::Vector2f currentPosition = enemy_model->getEnemyPosition(); + currentPosition.x += horizontal_movement_speed * ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + + if (currentPosition.x >= enemy_model->right_most_position.x) + { + enemy_model->setMovementDirection(MovementDirection::DOWN); + enemy_model->setReferencePosition(currentPosition); + } + else + { + enemy_model->setEnemyPosition(currentPosition); + } + } + + void ZapperController::moveDown() + { + sf::Vector2f currentPosition = enemy_model->getEnemyPosition(); + currentPosition.y += horizontal_movement_speed * ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + + if (currentPosition.y >= enemy_model->getReferencePosition().y + vertical_travel_distance) + { + if (enemy_model->getReferencePosition().x <= enemy_model->left_most_position.x) + { + enemy_model->setMovementDirection(MovementDirection::RIGHT); + } + else + { + enemy_model->setMovementDirection(MovementDirection::LEFT); + } + } + else + { + enemy_model->setEnemyPosition(currentPosition); + } + } + + void ZapperController::fireBullet() + { + ServiceLocator::getInstance()->getBulletService()->spawnBullet(BulletType::LASER_BULLET, + enemy_model->getEnemyPosition() + enemy_model->barrel_position_offset, + Bullet::MovementDirection::DOWN, enemy_model->getEntityType()); + } + + void ZapperController::destroy() + { + EnemyController::destroy(); + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Enemy/EnemyController.cpp b/Space-Invaders/Source/Enemy/EnemyController.cpp new file mode 100644 index 000000000..8f4fb0387 --- /dev/null +++ b/Space-Invaders/Source/Enemy/EnemyController.cpp @@ -0,0 +1,135 @@ +#include "../../Header/Enemy/EnemyController.h" +#include "../../Header/Enemy/EnemyView.h" +#include "../../Header/Enemy/EnemyModel.h" +#include "../../Header/Enemy/EnemyConfig.h" +#include "../../Header/Global/ServiceLocator.h" +#include "../../Header/Bullet/BulletConfig.h" +#include "../../Header/Entity/EntityConfig.h" +#include "../../Header/Bullet/BulletController.h" +#include "../../Header/Player/PlayerController.h" +#include "../../Header/Sound/SoundService.h" + +namespace Enemy +{ + using namespace Global; + using namespace Bullet; + using namespace Collision; + using namespace Entity; + using namespace Player; + using namespace Sound; + + EnemyController::EnemyController(EnemyType type) + { + enemy_view = new EnemyView(); + enemy_model = new EnemyModel(type); + } + + EnemyController::~EnemyController() + { + delete (enemy_view); + delete (enemy_model); + } + + void EnemyController::initialize() + { + enemy_model->initialize(); + enemy_model->setEnemyPosition(getRandomInitialPosition()); + enemy_view->initialize(this); + } + + void EnemyController::update() + { + move(); + updateFireTimer(); + processBulletFire(); + enemy_view->update(); + } + + void EnemyController::render() + { + enemy_view->render(); + } + + void EnemyController::updateFireTimer() + { + elapsed_fire_duration += ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); //update the elapsed duration + } + + void EnemyController::processBulletFire() //if elapsed duration is equal to or more than the amount of time we want to wait until firing than call the fire method. + { + if (elapsed_fire_duration >= rate_of_fire) + { + fireBullet(); + elapsed_fire_duration = 0.f; //set elapsed duration back to 0. + } + } + + sf::Vector2f EnemyController::getRandomInitialPosition() + { + float x_offset_distance = (std::rand() % static_cast(enemy_model->right_most_position.x - enemy_model->left_most_position.x)); + float x_position = enemy_model->left_most_position.x + x_offset_distance; + float y_position = enemy_model->left_most_position.y; + + return sf::Vector2f(x_position, y_position); + } + + void EnemyController::handleOutOfBounds() + { + sf::Vector2f enemyPosition = getEnemyPosition(); + sf::Vector2u windowSize = ServiceLocator::getInstance()->getGraphicService()->getGameWindow()->getSize(); + + if (enemyPosition.x < 0 || enemyPosition.x > windowSize.x || + enemyPosition.y < 0 || enemyPosition.y > windowSize.y) + { + ServiceLocator::getInstance()->getEnemyService()->destroyEnemy(this); + } + } + + sf::Vector2f EnemyController::getEnemyPosition() + { + return enemy_model->getEnemyPosition(); + } + + EnemyState EnemyController::getEnemyState() + { + return enemy_model->getEnemyState(); + } + + EnemyType EnemyController::getEnemyType() + { + return enemy_model->getEnemyType(); + } + + const sf::Sprite& EnemyController::getColliderSprite() + { + return enemy_view->getEnemySprite(); + } + + void EnemyController::onCollision(ICollider* other_collider) + { + BulletController* bullet_controller = dynamic_cast(other_collider); + if (bullet_controller && bullet_controller->getOwnerEntityType() != EntityType::ENEMY) + { + destroy(); + return; + } + + PlayerController* player_controller = dynamic_cast(other_collider); + if (player_controller) + { + destroy(); + return; + } + } + + void EnemyController::destroy() + { + ServiceLocator::getInstance()->getAnimationService()->spawnAnimationSystem(enemy_model->getEnemyPosition(), + Animation::AnimationType::EXPLOSION); + + ServiceLocator::getInstance()->getSoundService()->playSound(SoundType::EXPLOSION); + + ServiceLocator::getInstance()->getPlayerService()->increaseEnemiesKilled(1); + ServiceLocator::getInstance()->getEnemyService()->destroyEnemy(this); + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Enemy/EnemyModel.cpp b/Space-Invaders/Source/Enemy/EnemyModel.cpp new file mode 100644 index 000000000..534bc2beb --- /dev/null +++ b/Space-Invaders/Source/Enemy/EnemyModel.cpp @@ -0,0 +1,75 @@ +#include "../../Header/Enemy/EnemyModel.h" +#include "../../Header/Enemy/EnemyConfig.h" + +namespace Enemy +{ + EnemyModel::EnemyModel(EnemyType type) + { + enemy_type = type; + entity_type = Entity::EntityType::ENEMY; + } + + EnemyModel::~EnemyModel() { } + + void EnemyModel::initialize() + { + enemy_state = EnemyState::PATROLLING; + movement_direction = MovementDirection::RIGHT; + enemy_position = reference_position; + } + + sf::Vector2f EnemyModel::getEnemyPosition() + { + return enemy_position; + } + + void EnemyModel::setEnemyPosition(sf::Vector2f position) + { + enemy_position = position; + } + + sf::Vector2f EnemyModel::getReferencePosition() + { + return reference_position; + } + + void EnemyModel::setReferencePosition(sf::Vector2f position) + { + reference_position = position; + } + + EnemyState EnemyModel::getEnemyState() + { + return enemy_state; + } + + void EnemyModel::setEnemyState(EnemyState state) + { + enemy_state = state; + } + + EnemyType EnemyModel::getEnemyType() + { + return enemy_type; + } + + void EnemyModel::setEnemyType(EnemyType type) + { + enemy_type = type; + } + + MovementDirection EnemyModel::getMovementDirection() + { + return movement_direction; + } + + void EnemyModel::setMovementDirection(MovementDirection direction) + { + movement_direction = direction; + } + + Entity::EntityType EnemyModel::getEntityType() + { + return entity_type; + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Enemy/EnemyService.cpp b/Space-Invaders/Source/Enemy/EnemyService.cpp new file mode 100644 index 000000000..3f7764262 --- /dev/null +++ b/Space-Invaders/Source/Enemy/EnemyService.cpp @@ -0,0 +1,126 @@ +#include "../../Header/Enemy/EnemyService.h" +#include "../../Header/Enemy/EnemyController.h" +#include "../../Header/Global/ServiceLocator.h" +#include "../../Header/Time/TimeService.h" +#include "../../Header/Enemy/EnemyConfig.h" +#include "../../Header/Enemy/Controllers/SubZeroController.h" +#include "../../Header/Enemy/Controllers/ZapperController.h" +#include "../../Header/Enemy/Controllers/ThunderSnakeController.h" +#include "../../Header/Enemy/Controllers/UFOController.h" +#include "../../Header/Collision/ICollider.h" + +namespace Enemy +{ + using namespace Global; + using namespace Time; + using namespace Controller; + using namespace Collision; + + EnemyService::EnemyService() { std::srand(static_cast(std::time(nullptr))); } + + EnemyService::~EnemyService() { destroy(); } + + void EnemyService::initialize() + { + spawn_timer = spawn_interval; + } + + void EnemyService::update() + { + updateSpawnTimer(); + processEnemySpawn(); + + for (EnemyController* enemy : enemy_list) + enemy->update(); + + destroyFlaggedEnemies(); + } + + void EnemyService::render() + { + for (EnemyController* enemy : enemy_list) + enemy->render(); + } + + void EnemyService::reset() + { + destroy(); + spawn_timer = 0.0f; + } + + EnemyController* EnemyService::spawnEnemy() + { + // The base class pointer will be pointing to a child class object + EnemyController* enemy_controller = createEnemy(getRandomEnemyType()); + + enemy_controller->initialize(); + enemy_list.push_back(enemy_controller); + + return enemy_controller; + } + + void EnemyService::destroyEnemy(EnemyController* enemy_controller) + { + dynamic_cast(enemy_controller)->disableCollision(); + flagged_enemy_list.push_back(enemy_controller); + enemy_list.erase(std::remove(enemy_list.begin(), enemy_list.end(), enemy_controller), enemy_list.end()); + } + + void EnemyService::updateSpawnTimer() + { + spawn_timer += ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); // increase timer + } + + void EnemyService::processEnemySpawn() + { + if (spawn_timer >= spawn_interval) + { + spawnEnemy(); //spawn + spawn_timer = 0.0f; // reset + } + } + + EnemyType EnemyService::getRandomEnemyType() + { + int randomType = std::rand() % 4; //since we only have 2 enemies right now + return static_cast(randomType); + } + + EnemyController* EnemyService::createEnemy(EnemyType enemy_type) + { + switch (enemy_type) + { + case::Enemy::EnemyType::ZAPPER: + return new ZapperController(Enemy::EnemyType::ZAPPER); + + case::Enemy::EnemyType::THUNDER_SNAKE: + return new ThunderSnakeController(Enemy::EnemyType::THUNDER_SNAKE); + + case::Enemy::EnemyType::SUBZERO: + return new SubzeroController(Enemy::EnemyType::SUBZERO); + + case::Enemy::EnemyType::UFO: + return new UFOController(Enemy::EnemyType::UFO); + } + } + + void EnemyService::destroy() + { + for (int i = 0; i < enemy_list.size(); i++) + { + ServiceLocator::getInstance()->getCollisionService()->removeCollider(dynamic_cast(enemy_list[i])); + delete (enemy_list[i]); + } + enemy_list.clear(); + } + + void EnemyService::destroyFlaggedEnemies() + { + for (int i = 0; i < flagged_enemy_list.size(); i++) + { + ServiceLocator::getInstance()->getCollisionService()->removeCollider(dynamic_cast(flagged_enemy_list[i])); + delete (flagged_enemy_list[i]); + } + flagged_enemy_list.clear(); + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Enemy/EnemyView.cpp b/Space-Invaders/Source/Enemy/EnemyView.cpp new file mode 100644 index 000000000..9965adcab --- /dev/null +++ b/Space-Invaders/Source/Enemy/EnemyView.cpp @@ -0,0 +1,72 @@ +#include "../../Header/Enemy/EnemyView.h" +#include "../../Header/Global/ServiceLocator.h" +#include "../../Header/Global/Config.h" +#include "../../Header/Graphic/GraphicService.h" +#include "../../Header/Enemy/EnemyController.h" +#include"../../Header/Enemy/EnemyConfig.h" + +namespace Enemy +{ + using namespace Global; + using namespace Graphics; + using namespace UI::UIElement; + + EnemyView::EnemyView() { createUIElements(); } + + EnemyView::~EnemyView() { destroy(); } + + void EnemyView::initialize(EnemyController* controller) + { + enemy_controller = controller; + initializeImage(); + } + + void EnemyView::createUIElements() + { + enemy_image = new ImageView(); + } + + void EnemyView::initializeImage() + { + enemy_image->initialize(getEnemyTexturePath(), enemy_sprite_width, enemy_sprite_height, enemy_controller->getEnemyPosition()); + } + + void EnemyView::update() + { + enemy_image->setPosition(enemy_controller->getEnemyPosition()); + enemy_image->update(); + } + + void EnemyView::render() + { + enemy_image->render(); + } + + const sf::Sprite& EnemyView::getEnemySprite() + { + return enemy_image->getSprite(); + } + + sf::String EnemyView::getEnemyTexturePath() + { + switch (enemy_controller->getEnemyType()) + { + case::Enemy::EnemyType::ZAPPER: + return Config::zapper_texture_path; + + case::Enemy::EnemyType::THUNDER_SNAKE: + return Config::thunder_snake_texture_path; + + case::Enemy::EnemyType::SUBZERO: + return Config::subzero_texture_path; + + case::Enemy::EnemyType::UFO: + return Config::ufo_texture_path; + } + } + + void EnemyView::destroy() + { + delete (enemy_image); + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Event/EventService.cpp b/Space-Invaders/Source/Event/EventService.cpp new file mode 100644 index 000000000..ebeb4e732 --- /dev/null +++ b/Space-Invaders/Source/Event/EventService.cpp @@ -0,0 +1,103 @@ +#include "../../Header/Event/EventService.h" +#include "../../Header/Graphic/GraphicService.h" +#include "../../Header/Global/ServiceLocator.h" + +namespace Event +{ + using namespace Global; + + EventService::EventService() { game_window = nullptr; } + + EventService::~EventService() = default; //calls the default destructor + + void EventService::initialize() + { + game_window = ServiceLocator::getInstance()->getGraphicService()->getGameWindow(); + } + + void EventService::update() + { + updateMouseButtonsState(left_mouse_button_state, sf::Mouse::Left); + updateMouseButtonsState(right_mouse_button_state, sf::Mouse::Right); + updateKeyboardButtonsState(left_arrow_button_state, sf::Keyboard::Left); + updateKeyboardButtonsState(right_arrow_button_state, sf::Keyboard::Right); + updateKeyboardButtonsState(A_button_state, sf::Keyboard::A); + updateKeyboardButtonsState(D_button_state, sf::Keyboard::D); + } + + void EventService::processEvents() + { + if (isGameWindowOpen()) { + while (game_window->pollEvent(game_event)) { + // Check for window closure + if (gameWindowWasClosed() || hasQuitGame()) + { + game_window->close(); + } + } + } + } + + void EventService::updateMouseButtonsState(ButtonState& current_button_state, sf::Mouse::Button mouse_button) + { + if (sf::Mouse::isButtonPressed(mouse_button)) + { + switch (current_button_state) + { + case ButtonState::RELEASED: + current_button_state = ButtonState::PRESSED; + break; + case ButtonState::PRESSED: + current_button_state = ButtonState::HELD; + break; + } + } + else + { + current_button_state = ButtonState::RELEASED; + } + } + + void EventService::updateKeyboardButtonsState(ButtonState& current_button_state, sf::Keyboard::Key keyboard_button) + { + if (sf::Keyboard::isKeyPressed(keyboard_button)) + { + switch (current_button_state) + { + case ButtonState::RELEASED: + current_button_state = ButtonState::PRESSED; + break; + case ButtonState::PRESSED: + current_button_state = ButtonState::HELD; + break; + } + } + else + { + current_button_state = ButtonState::RELEASED; + } + } + + bool EventService::hasQuitGame() { return (isKeyboardEvent() && pressedEscapeKey()); } // only true if the ESC key is pressed and a keyboard event has been registered + + //checks for if a keyboard key has been pressed + bool EventService::isKeyboardEvent() { return game_event.type == sf::Event::KeyPressed; } + + //control click on the SFML functions to see what they do internally + bool EventService::pressedEscapeKey() { return game_event.key.code == sf::Keyboard::Escape; } + bool EventService::isGameWindowOpen() { return game_window != nullptr; } + bool EventService::gameWindowWasClosed() { return game_event.type == sf::Event::Closed; } + + // Player inputs + bool EventService::pressedLeftKey() { return left_arrow_button_state == ButtonState::HELD; } + + bool EventService::pressedRightKey() { return right_arrow_button_state == ButtonState::HELD; } + + bool EventService::pressedAKey() { return A_button_state == ButtonState::HELD; } + + bool EventService::pressedDKey() { return D_button_state == ButtonState::HELD; } + + bool EventService::pressedLeftMouseButton() { return left_mouse_button_state == ButtonState::PRESSED; } + + bool EventService::pressedRightMouseButton() { return right_mouse_button_state == ButtonState::PRESSED; } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Gameplay/GameplayController.cpp b/Space-Invaders/Source/Gameplay/GameplayController.cpp new file mode 100644 index 000000000..ceb231491 --- /dev/null +++ b/Space-Invaders/Source/Gameplay/GameplayController.cpp @@ -0,0 +1,15 @@ +#include "../../header/Gameplay/GameplayController.h" +#include "../../header/Gameplay/GameplayView.h" + +namespace Gameplay +{ + GameplayController::GameplayController() { gameplay_view = new GameplayView(); } + + GameplayController::~GameplayController() { delete (gameplay_view); } + + void GameplayController::initialize() { gameplay_view->initialize(); } + + void GameplayController::update() { gameplay_view->update(); } + + void GameplayController::render() { gameplay_view->render(); } +} diff --git a/Space-Invaders/Source/Gameplay/GameplayService.cpp b/Space-Invaders/Source/Gameplay/GameplayService.cpp new file mode 100644 index 000000000..4991f2d90 --- /dev/null +++ b/Space-Invaders/Source/Gameplay/GameplayService.cpp @@ -0,0 +1,30 @@ +#include "../../Header/Gameplay/GameplayService.h" +#include "../../Header/Gameplay/GameplayController.h" +#include "../../Header/Global/ServiceLocator.h" + +namespace Gameplay +{ + using namespace Global; + using namespace Player; + using namespace Enemy; + using namespace Element; + using namespace Bullet; + + GameplayService::GameplayService() { gameplay_controller = new GameplayController(); } + + GameplayService::~GameplayService() { delete (gameplay_controller); } + + void GameplayService::initialize() { gameplay_controller->initialize(); } + + void GameplayService::update() { gameplay_controller->update(); } + + void GameplayService::render() { gameplay_controller->render(); } + + void GameplayService::restart() + { + ServiceLocator::getInstance()->getPlayerService()->reset(); + ServiceLocator::getInstance()->getEnemyService()->reset(); + ServiceLocator::getInstance()->getBulletService()->reset(); + ServiceLocator::getInstance()->getElementService()->reset(); + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Gameplay/GameplayView.cpp b/Space-Invaders/Source/Gameplay/GameplayView.cpp new file mode 100644 index 000000000..91b223283 --- /dev/null +++ b/Space-Invaders/Source/Gameplay/GameplayView.cpp @@ -0,0 +1,33 @@ +#include "../../header/Gameplay/GameplayView.h" +#include "../../header/Global/ServiceLocator.h" +#include "../../Header/Global/Config.h" +#include "../../header/Graphic/GraphicService.h" + +namespace Gameplay +{ + using namespace Global; + using namespace UI::UIElement; + + GameplayView::GameplayView() { background_image = new ImageView(); } + + GameplayView::~GameplayView() { delete(background_image); } + + void GameplayView::initialize() + { + initializeBackgroundImage(); + } + + void GameplayView::initializeBackgroundImage() + { + sf::RenderWindow* game_window = ServiceLocator::getInstance()->getGraphicService()->getGameWindow(); + + background_image->initialize(Config::background_texture_path, + game_window->getSize().x, + game_window->getSize().y, + sf::Vector2f(0, 0)); + } + + void GameplayView::update() { background_image->update(); } + + void GameplayView::render() { background_image->render(); } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Global/Config.cpp b/Space-Invaders/Source/Global/Config.cpp new file mode 100644 index 000000000..9fd478e69 --- /dev/null +++ b/Space-Invaders/Source/Global/Config.cpp @@ -0,0 +1,63 @@ +#include "../../header/Global/Config.h" + +namespace Global +{ + const sf::String Config::outscal_logo_texture_path = "assets/textures/outscal_logo.png"; + + const sf::String Config::background_texture_path = "assets/textures/space_invaders_bg.png"; + + const sf::String Config::player_texture_path = "assets/textures/player_ship.png"; + + + const sf::String Config::zapper_texture_path = "assets/textures/zapper.png"; + + const sf::String Config::thunder_snake_texture_path = "assets/textures/thunder_snake.png"; + + const sf::String Config::subzero_texture_path = "assets/textures/subzero.png"; + + const sf::String Config::ufo_texture_path = "assets/textures/ufo.png"; + + const sf::String Config::bunker_texture_path = "assets/textures/bunker.png"; + + const sf::String Config::explosion_texture_path = "assets/textures/explosion.png"; + + const sf::String Config::shield_texture_path = "assets/textures/shield.png"; + + const sf::String Config::tripple_laser_texture_path = "assets/textures/tripple_laser.png"; + + const sf::String Config::rapid_fire_texture_path = "assets/textures/rapid_fire.png"; + + const sf::String Config::outscal_bomb_texture_path = "assets/textures/outscal_bomb.png"; + + + const sf::String Config::laser_bullet_texture_path = "assets/textures/laser_bullet.png"; + + const sf::String Config::torpedoe_texture_path = "assets/textures/torpedoe.png"; + + const sf::String Config::frost_beam_texture_path = "assets/textures/frost_beam.png"; + + + const sf::String Config::play_button_texture_path = "assets/textures/play_button.png"; + + const sf::String Config::instructions_button_texture_path = "assets/textures/instructions_button.png"; + + const sf::String Config::quit_button_texture_path = "assets/textures/quit_button.png"; + + const sf::String Config::menu_button_texture_path = "assets/textures/menu_button.png"; + + + const sf::String Config::bubble_bobble_font_path = "assets/fonts/bubbleBobble.ttf"; + + const sf::String Config::DS_DIGIB_font_path = "assets/fonts/DS_DIGIB.ttf"; + + + const sf::String Config::background_music_path = "assets/sounds/background_music.mp3"; + + const sf::String Config::button_click_sound_path = "assets/sounds/button_click_sound.wav"; + + const sf::String Config::bullet_fire_sound_path = "assets/sounds/bullet_fire.ogg"; + + const sf::String Config::powerup_enabled_sound_path = "assets/sounds/powerup_enabled.ogg"; + + const sf::String Config::powerup_disabled_sound_path = "assets/sounds/powerup_disabled.ogg"; +} \ No newline at end of file diff --git a/Space-Invaders/Source/Global/ServiceLocator.cpp b/Space-Invaders/Source/Global/ServiceLocator.cpp new file mode 100644 index 000000000..0d42f9936 --- /dev/null +++ b/Space-Invaders/Source/Global/ServiceLocator.cpp @@ -0,0 +1,160 @@ +#include "../../Header/Global/ServiceLocator.h" +#include "../../header/Main/GameService.h" + +namespace Global +{ + using namespace Main; + using namespace Graphics; + using namespace Event; + using namespace Time; + using namespace Player; + using namespace UI; + using namespace Enemy; + using namespace Gameplay; + using namespace Element; + using namespace Sound; + using namespace Bullet; + using namespace Powerup; + using namespace Collision; + using namespace Animation; + + + ServiceLocator::ServiceLocator() + { + graphic_service = nullptr; + event_service = nullptr; + player_service = nullptr; + time_service = nullptr; + ui_service = nullptr; + enemy_service = nullptr; + gameplay_service = nullptr; + element_service = nullptr; + sound_service = nullptr; + bullet_service = nullptr; + powerup_service = nullptr; + collision_service = nullptr; + animation_service = nullptr; + createServices(); + } + ServiceLocator::~ServiceLocator() + { + clearAllServices(); + } + + void ServiceLocator::createServices() + { + graphic_service = new GraphicService(); + event_service = new EventService(); + player_service = new PlayerService(); + time_service = new TimeService(); + ui_service = new UIService(); + enemy_service = new EnemyService(); + gameplay_service = new GameplayService(); + element_service = new ElementService(); + sound_service = new SoundService(); + bullet_service = new BulletService(); + powerup_service = new PowerupService(); + collision_service = new CollisionService(); + animation_service = new AnimationService(); + } + + void ServiceLocator::clearAllServices() + { + delete(graphic_service); + delete(event_service); + delete(player_service); + delete(time_service); + delete(ui_service); + delete(enemy_service); + delete(gameplay_service); + delete(element_service); + delete(sound_service); + delete(bullet_service); + delete(powerup_service); + delete(collision_service); + delete(animation_service); + } + + ServiceLocator* ServiceLocator::getInstance() + { + static ServiceLocator instance; + return &instance; + } + + void ServiceLocator::initialize() + { + graphic_service->initialize(); + event_service->initialize(); + player_service->initialize(); + time_service->initialize(); + ui_service->initialize(); + enemy_service->initialize(); + gameplay_service->initialize(); + element_service->initialize(); + sound_service->initialize(); + bullet_service->initialize(); + powerup_service->initialize(); + collision_service->initialize(); + animation_service->initialize(); + } + + void ServiceLocator::update() + { + graphic_service->update(); + time_service->update(); + event_service->update(); + + if (GameService::getGameState() == GameState::GAMEPLAY) + { + gameplay_service->update(); + player_service->update(); + enemy_service->update(); + element_service->update(); + bullet_service->update(); + powerup_service->update(); + collision_service->update(); + animation_service->update(); + } + + ui_service->update(); + } + + void ServiceLocator::render() + { + graphic_service->render(); + + if (GameService::getGameState() == GameState::GAMEPLAY) + { + gameplay_service->render(); + player_service->render(); + enemy_service->render(); + element_service->render(); + bullet_service->render(); + powerup_service->render(); + animation_service->render(); + } + + ui_service->render(); + //no event service because nothing to render + //no time service because nothing to render + } + + GraphicService* ServiceLocator::getGraphicService() { return graphic_service; } + EventService* ServiceLocator::getEventService() { return event_service; } + PlayerService* ServiceLocator::getPlayerService() { return player_service; } + TimeService* ServiceLocator::getTimeService() { return time_service; } + UIService* ServiceLocator::getUIService() { return ui_service; } + EnemyService* ServiceLocator::getEnemyService() { return enemy_service; } + GameplayService* ServiceLocator::getGameplayService() { return gameplay_service; } + ElementService* ServiceLocator::getElementService() { return element_service; } + SoundService* ServiceLocator::getSoundService() { return sound_service; } + BulletService* ServiceLocator::getBulletService() { return bullet_service; } + PowerupService* ServiceLocator::getPowerupService() { return powerup_service; } + CollisionService* ServiceLocator::getCollisionService(){return collision_service;} + AnimationService* ServiceLocator::getAnimationService() { return animation_service; } + + void ServiceLocator::deleteServiceLocator() + { + delete(this); + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Graphic/GraphicService.cpp b/Space-Invaders/Source/Graphic/GraphicService.cpp new file mode 100644 index 000000000..968903a7c --- /dev/null +++ b/Space-Invaders/Source/Graphic/GraphicService.cpp @@ -0,0 +1,54 @@ +#include "../../Header/Graphic/GraphicService.h" + +namespace Graphics +{ + GraphicService::GraphicService() { + game_window = nullptr; + video_mode = nullptr; + } + + GraphicService::~GraphicService() { + onDestroy(); + } + + void GraphicService::initialize() { + game_window = createGameWindow(); + setFrameRate(frame_rate); + } + + sf::RenderWindow* GraphicService::createGameWindow() { + setVideoMode(); + return new sf::RenderWindow(*video_mode, game_window_title, sf::Style::Fullscreen); // Creates and returns a new RenderWindow object + } + + // Sets up the video mode for the game window using specified dimensions and system's color depth. + void GraphicService::setVideoMode() { + video_mode = new sf::VideoMode(game_window_width, game_window_height, sf::VideoMode::getDesktopMode().bitsPerPixel); // Allocates and sets the video mode + } + + void GraphicService::onDestroy() { + delete(video_mode); + delete(game_window); + } + + void GraphicService::setFrameRate(int frame_rate_to_set) + { + game_window->setFramerateLimit(frame_rate_to_set); + } + + void GraphicService::update() { } + + void GraphicService::render() { } + + bool GraphicService::isGameWindowOpen() { + return game_window->isOpen(); + } + + sf::RenderWindow* GraphicService::getGameWindow() { + return game_window; + } + + sf::Color GraphicService::getWindowColor() { + return window_color; + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Main/GameService.cpp b/Space-Invaders/Source/Main/GameService.cpp new file mode 100644 index 000000000..8b9766a03 --- /dev/null +++ b/Space-Invaders/Source/Main/GameService.cpp @@ -0,0 +1,71 @@ +#include "../../Header/Main/GameService.h" +#include "../../Header/Graphic/GraphicService.h" +#include "../../header/Event/EventService.h" +#include "../../header/UI/UIService.h" + +namespace Main +{ + using namespace Global; + using namespace Graphics; + using namespace Event; + using namespace UI; + + GameState GameService::current_state = GameState::BOOT; + + GameService::GameService() { + service_locator = nullptr; + } + + GameService::~GameService() { + destroy(); + } + + void GameService::ignite() { + service_locator = Global::ServiceLocator::getInstance(); // Get ServiceLocator + initialize(); // Initialize services. + } + + void GameService::initialize() + { + service_locator->initialize(); + initializeVariables(); + showSplashScreen(); + } + + void GameService::initializeVariables() + { + game_window = service_locator->getGraphicService()->getGameWindow(); //set game window (it was null before this) + } + + void GameService::showSplashScreen() + { + setGameState(GameState::SPLASH_SCREEN); + ServiceLocator::getInstance()->getUIService()->showScreen(); + } + + void GameService::update() + { + service_locator->getEventService()->processEvents(); + service_locator->update(); + } + + void GameService::render() + { + game_window->clear(); + service_locator->render(); + game_window->display(); + } + + bool GameService::isRunning() + { + return service_locator->getGraphicService()->isGameWindowOpen(); + } + + void GameService::setGameState(GameState new_state) { current_state = new_state; } + + GameState GameService::getGameState() { return current_state; } + + void GameService::destroy() { } +} + + diff --git a/Space-Invaders/Source/Player/PlayerController.cpp b/Space-Invaders/Source/Player/PlayerController.cpp new file mode 100644 index 000000000..f1ec41684 --- /dev/null +++ b/Space-Invaders/Source/Player/PlayerController.cpp @@ -0,0 +1,320 @@ +#include "../../Header/Player/PlayerController.h" +#include "../../Header/Player/PlayerModel.h" +#include "../../Header/Player/PlayerView.h" +#include "../../Header/Event/EventService.h" +#include "../../Header/Global/ServiceLocator.h" +#include "../../Header/Bullet/BulletConfig.h" +#include "../../Header/Entity/EntityConfig.h" +#include "../../Header/Bullet/BulletController.h" +#include "../../Header/Enemy/EnemyController.h" +#include "../../Header/Powerups/PowerupController.h" +#include "../../header/Sound/SoundService.h" +#include "../../header/Main/GameService.h" + +namespace Player +{ + using namespace Global; + using namespace Event; + using namespace Bullet; + using namespace Entity; + using namespace Enemy; + using namespace Powerup; + using namespace Sound; + using namespace Main; + using namespace Gameplay; + + PlayerController::PlayerController() + { + player_view = new PlayerView(); + player_model = new PlayerModel(); + } + + PlayerController::~PlayerController() + { + delete (player_view); + delete (player_model); + } + + void PlayerController::initialize() + { + player_model->initialize(); + player_view->initialize(this); + } + + void PlayerController::update() + { + switch (player_model->getPlayerState()) + { + case::Player::PlayerState::ALIVE: + processPlayerInput(); + break; + + case::Player::PlayerState::FROZEN: + updateFreezeDuration(); + break; + } + + updatePowerupDuration(); + updateFireDuration(); + player_view->update(); + } + + void PlayerController::render() + { + player_view->render(); + } + + void PlayerController::reset() + { + player_model->reset(); + } + + sf::Vector2f PlayerController::getPlayerPosition() + { + return player_model->getPlayerPosition(); + } + + PlayerState PlayerController::getPlayerState() + { + return player_model->getPlayerState(); + } + + const sf::Sprite& PlayerController::getColliderSprite() + { + return player_view->getPlayerSprite(); + } + + void PlayerController::onCollision(ICollider* other_collider) + { + if (processPowerupCollision(other_collider)) + return; + + if (processBulletCollision(other_collider)) + return; + + processEnemyCollision(other_collider); + } + + void PlayerController::decreasePlayerLive() + { + PlayerModel::player_lives -= 1; + if (PlayerModel::player_lives <= 0) + { + reset(); //game over condition + } + } + + bool PlayerController::processBulletCollision(ICollider* other_collider) + { + if (player_model->isShieldEnabled()) + return false; + + BulletController* bullet_controller = dynamic_cast(other_collider); + + if (bullet_controller && bullet_controller->getOwnerEntityType() != EntityType::PLAYER) + { + if (bullet_controller->getBulletType() == BulletType::FROST_BULLET) + { + freezePlayer(); + } + else decreasePlayerLive(); + return true; + } + return false; + } + + bool PlayerController::processEnemyCollision(ICollider* other_collider) + { + if (player_model->isShieldEnabled()) + return false; + + EnemyController* enemy_controller = dynamic_cast(other_collider); + if (enemy_controller) + { + decreasePlayerLive(); + return true; + } + return false; + } + + bool PlayerController::processPowerupCollision(ICollider* other_collider) + { + PowerupController* powerup_controller = dynamic_cast(other_collider); + if (powerup_controller) + { + return true; + } + return false; + } + + void PlayerController::updatePowerupDuration() + { + if (elapsed_shield_duration > 0) + { + elapsed_shield_duration -= ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + + if (elapsed_shield_duration <= 0) + disableShield(); + } + + if (elapsed_rapid_fire_duration > 0) + { + elapsed_rapid_fire_duration -= ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + + if (elapsed_rapid_fire_duration <= 0) + disableRapidFire(); + } + + if (elapsed_tripple_laser_duration > 0) + { + elapsed_tripple_laser_duration -= ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + + if (elapsed_tripple_laser_duration <= 0) + disableTrippleLaser(); + } + } + + void PlayerController::enableShield() + { + ServiceLocator::getInstance()->getSoundService()->playSound(SoundType::POWERUP_ENABLED); + elapsed_shield_duration = player_model->shiled_powerup_duration; + player_model->setShieldState(true); + player_view->setPlayerHighlight(true); + } + + void PlayerController::disableShield() + { + ServiceLocator::getInstance()->getSoundService()->playSound(SoundType::POWERUP_DISABLED); + player_model->setShieldState(false); + player_view->setPlayerHighlight(false); + } + + void PlayerController::enableRapidFire() + { + ServiceLocator::getInstance()->getSoundService()->playSound(SoundType::POWERUP_ENABLED); + elapsed_rapid_fire_duration = player_model->rapid_fire_powerup_duration; + player_model->setRapidFireState(true); + } + + void PlayerController::disableRapidFire() + { + ServiceLocator::getInstance()->getSoundService()->playSound(SoundType::POWERUP_DISABLED); + player_model->setRapidFireState(false); + } + + void PlayerController::enableTrippleLaser() + { + ServiceLocator::getInstance()->getSoundService()->playSound(SoundType::POWERUP_ENABLED); + elapsed_tripple_laser_duration = player_model->tripple_laser_powerup_duration; + player_model->setTrippleFireState(true); + } + + void PlayerController::disableTrippleLaser() + { + ServiceLocator::getInstance()->getSoundService()->playSound(SoundType::POWERUP_DISABLED); + player_model->setTrippleFireState(false); + } + + void PlayerController::processPlayerInput() + { + + EventService* event_service = ServiceLocator::getInstance()->getEventService(); + + if (event_service->pressedLeftKey() || event_service->pressedAKey()) + { + moveLeft(); + } + + if (event_service->pressedRightKey() || event_service->pressedDKey()) + { + moveRight(); + } + + if (event_service->pressedLeftMouseButton()) + { + processBulletFire(); + } + } + + void PlayerController::moveLeft() + { + sf::Vector2f currentPosition = player_model->getPlayerPosition(); + currentPosition.x -= player_model->player_movement_speed * ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + + currentPosition.x = std::max(currentPosition.x, player_model->left_most_position.x); + player_model->setPlayerPosition(currentPosition); + } + + void PlayerController::moveRight() + { + sf::Vector2f currentPosition = player_model->getPlayerPosition(); + currentPosition.x += player_model->player_movement_speed * ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + + currentPosition.x = std::min(currentPosition.x, player_model->right_most_position.x); + player_model->setPlayerPosition(currentPosition); + } + + void PlayerController::updateFireDuration() + { + if (elapsed_fire_duration >= 0) + { + elapsed_fire_duration -= ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + } + } + + void PlayerController::updateFreezeDuration() + { + if (elapsed_freeze_duration >= 0) + { + elapsed_freeze_duration -= ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + + if (elapsed_freeze_duration <= 0) + { + player_model->setPlayerState(PlayerState::ALIVE); + player_view->setPlayerHighlight(false); + } + } + } + + void PlayerController::freezePlayer() + { + player_model->setPlayerState(PlayerState::FROZEN); + elapsed_freeze_duration = player_model->freeze_duration; + player_view->setPlayerHighlight(true); + } + + void PlayerController::processBulletFire() + { + if (elapsed_fire_duration > 0) return; + + if (player_model->isTrippleLaserEnabled()) + fireBullet(true); + + else fireBullet(); + + if (player_model->isRapidFireEnabled()) + elapsed_fire_duration = player_model->rapid_fire_cooldown_duration; + + else elapsed_fire_duration = player_model->fire_cooldown_duration; + } + + void PlayerController::fireBullet(bool b_tripple_laser) + { + sf::Vector2f bullet_position = player_model->getPlayerPosition() + player_model->barrel_position_offset; + fireBullet(bullet_position); + + if (b_tripple_laser) + { + fireBullet(bullet_position + player_model->second_weapon_position_offset); + fireBullet(bullet_position + player_model->third_weapon_position_offset); + } + ServiceLocator::getInstance()->getSoundService()->playSound(SoundType::BULLET_FIRE); + } + + void PlayerController::fireBullet(sf::Vector2f position) + { + increaseBulletsFired(1); + ServiceLocator::getInstance()->getBulletService()->spawnBullet(BulletType::LASER_BULLET, + position, Bullet::MovementDirection::UP, player_model->getEntityType()); + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Player/PlayerModel.cpp b/Space-Invaders/Source/Player/PlayerModel.cpp new file mode 100644 index 000000000..a4b36ba13 --- /dev/null +++ b/Space-Invaders/Source/Player/PlayerModel.cpp @@ -0,0 +1,84 @@ +#include "../../Header/Player/PlayerModel.h" + +namespace Player +{ + int PlayerModel::player_lives; + int PlayerModel::enemies_killed; + int PlayerModel::bullets_fired; + + PlayerModel::PlayerModel() { entity_type = Entity::EntityType::PLAYER; } + + PlayerModel::~PlayerModel() { } + + void PlayerModel::initialize() { reset(); } // reset the player + + void PlayerModel::reset() + { + player_state = PlayerState::ALIVE; + player_position = initial_player_position; + //lives set to max of 3 at restart + player_lives = max_player_lives; + + enemies_killed = 0; + bullets_fired = 0; + //powerups + b_shield = false; + b_rapid_fire = false; + b_tripple_laser = false; + } + + sf::Vector2f PlayerModel::getPlayerPosition() + { + return player_position; + } + + void PlayerModel::setPlayerPosition(sf::Vector2f position) + { + player_position = position; + } + + PlayerState PlayerModel::getPlayerState() + { + return player_state; + } + + void PlayerModel::setPlayerState(PlayerState state) + { + player_state = state; + } + + Entity::EntityType PlayerModel::getEntityType() + { + return entity_type; + } + + bool PlayerModel::isShieldEnabled() + { + return b_shield; + } + + bool PlayerModel::isRapidFireEnabled() + { + return b_rapid_fire; + } + + bool PlayerModel::isTrippleLaserEnabled() + { + return b_tripple_laser; + } + + void PlayerModel::setShieldState(bool value) + { + b_shield = value; + } + + void PlayerModel::setRapidFireState(bool value) + { + b_rapid_fire = value; + } + + void PlayerModel::setTrippleFireState(bool value) + { + b_tripple_laser = value; + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Player/PlayerService.cpp b/Space-Invaders/Source/Player/PlayerService.cpp new file mode 100644 index 000000000..f7cb67877 --- /dev/null +++ b/Space-Invaders/Source/Player/PlayerService.cpp @@ -0,0 +1,62 @@ +#include "../../Header/Player/PlayerService.h" +#include "../../Header/Player/PlayerController.h" +#include "../../header/Global/ServiceLocator.h" +#include "../../header/Collision/ICollider.h" + +namespace Player +{ + using namespace Global; + using namespace Collision; + + PlayerService::PlayerService() + { + player_controller = new PlayerController(); + } + + PlayerService::~PlayerService() + { + ServiceLocator::getInstance()->getCollisionService()->removeCollider(dynamic_cast(player_controller)); + delete (player_controller); + } + + void PlayerService::initialize() + { + player_controller->initialize(); + ServiceLocator::getInstance()->getCollisionService()->addCollider(dynamic_cast(player_controller)); + } + + void PlayerService::update() + { + player_controller->update(); + } + + void PlayerService::render() + { + player_controller->render(); + } + + void PlayerService::enableShield() + { + player_controller->enableShield(); + } + + void PlayerService::enableRapidFire() + { + player_controller->enableRapidFire(); + } + + void PlayerService::enableTrippleLaser() + { + player_controller->enableTrippleLaser(); + } + + void PlayerService::reset() + { + player_controller->reset(); + } + + void PlayerService::increaseEnemiesKilled(int val) + { + player_controller->increaseEnemiesKilled(val); + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Player/PlayerView.cpp b/Space-Invaders/Source/Player/PlayerView.cpp new file mode 100644 index 000000000..0e38b71f2 --- /dev/null +++ b/Space-Invaders/Source/Player/PlayerView.cpp @@ -0,0 +1,59 @@ +#include "../../Header/Player/PlayerView.h" +#include "../../Header/Global/ServiceLocator.h" +#include "../../Header/Global/Config.h" +#include "../../Header/Graphic/GraphicService.h" +#include "../../Header/Player/PlayerController.h" +#include "../../header/Player/PlayerModel.h" + +namespace Player +{ + using namespace Global; + using namespace UI::UIElement; + + PlayerView::PlayerView() { createUIElements(); } + + PlayerView::~PlayerView() { destroy(); } + + void PlayerView::initialize(PlayerController* controller) + { + player_controller = controller; //to later use it for setting position + initializeImage(); + } + + void PlayerView::createUIElements() + { + player_image = new ImageView(); + } + + void PlayerView::initializeImage() + { + player_image->initialize(Config::player_texture_path, player_sprite_width, player_sprite_height, player_controller->getPlayerPosition()); + } + + void PlayerView::update() + { + player_image->setPosition(player_controller->getPlayerPosition()); + player_image->update(); + } + + void PlayerView::render() + { + player_image->render(); + } + + const sf::Sprite& PlayerView::getPlayerSprite() + { + return player_image->getSprite(); + } + + void PlayerView::setPlayerHighlight(bool b_highlight) + { + if (b_highlight) player_image->setImageAlpha(PlayerModel::invincible_player_alpha); + else player_image->setImageAlpha(255); + } + + void PlayerView::destroy() + { + delete(player_image); + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Powerups/Controllers/OutscalBombController.cpp b/Space-Invaders/Source/Powerups/Controllers/OutscalBombController.cpp new file mode 100644 index 000000000..385f95301 --- /dev/null +++ b/Space-Invaders/Source/Powerups/Controllers/OutscalBombController.cpp @@ -0,0 +1,21 @@ +#include "../../Header/Powerups/Controllers/OutscalBombController.h" +#include "../../header/Global/ServiceLocator.h" + +namespace Powerup +{ + namespace Controller + { + using namespace Global; + + OutscalBombController::OutscalBombController(PowerupType type) : PowerupController(type) {} + + OutscalBombController::~OutscalBombController() {} + + void OutscalBombController::onCollected() {}; + + void OutscalBombController::applyPowerup() + { + ServiceLocator::getInstance()->getEnemyService()->reset(); + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Powerups/Controllers/RapidFireController.cpp b/Space-Invaders/Source/Powerups/Controllers/RapidFireController.cpp new file mode 100644 index 000000000..9a182c805 --- /dev/null +++ b/Space-Invaders/Source/Powerups/Controllers/RapidFireController.cpp @@ -0,0 +1,21 @@ +#include "../../Header/Powerups/Controllers/RapidFireController.h" +#include "../../Header/Global/ServiceLocator.h" + +namespace Powerup +{ + namespace Controller + { + using namespace Global; + + RapidFireController::RapidFireController(PowerupType type) : PowerupController(type) {} + + RapidFireController::~RapidFireController() {} + + void RapidFireController::onCollected() {}; + + void RapidFireController::applyPowerup() + { + ServiceLocator::getInstance()->getPlayerService()->enableRapidFire(); + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Powerups/Controllers/ShieldController.cpp b/Space-Invaders/Source/Powerups/Controllers/ShieldController.cpp new file mode 100644 index 000000000..522e0ded3 --- /dev/null +++ b/Space-Invaders/Source/Powerups/Controllers/ShieldController.cpp @@ -0,0 +1,22 @@ +#include "../../Header/Powerups/Controllers/ShieldController.h" +#include "../../header/Global/ServiceLocator.h" + + +namespace Powerup +{ + using namespace Global; + + namespace Controller + { + ShieldController::ShieldController(PowerupType type) : PowerupController(type) {} + + ShieldController::~ShieldController() {} + + void ShieldController::onCollected() {}; + + void ShieldController::applyPowerup() + { + ServiceLocator::getInstance()->getPlayerService()->enableShield(); + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Powerups/Controllers/TrippleLaserController.cpp b/Space-Invaders/Source/Powerups/Controllers/TrippleLaserController.cpp new file mode 100644 index 000000000..0009562f4 --- /dev/null +++ b/Space-Invaders/Source/Powerups/Controllers/TrippleLaserController.cpp @@ -0,0 +1,21 @@ +#include "../../Header/Powerups/Controllers/TrippleLaserController.h" +#include "../../Header/Global/ServiceLocator.h" + +namespace Powerup +{ + namespace Controller + { + using namespace Global; + + TrippleLaserController::TrippleLaserController(PowerupType type) : PowerupController(type) {} + + TrippleLaserController::~TrippleLaserController() {} + + void TrippleLaserController::onCollected() {} + + void TrippleLaserController::applyPowerup() + { + ServiceLocator::getInstance()->getPlayerService()->enableTrippleLaser(); + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Powerups/Controllers/TrippleLaserController.h.cpp b/Space-Invaders/Source/Powerups/Controllers/TrippleLaserController.h.cpp new file mode 100644 index 000000000..3541092aa --- /dev/null +++ b/Space-Invaders/Source/Powerups/Controllers/TrippleLaserController.h.cpp @@ -0,0 +1,13 @@ +#include "../../Header/Powerups/Controllers/TrippleLaserController.h" + +namespace Powerup +{ + namespace Controller + { + TrippleLaserController::TrippleLaserController(PowerupType type) : PowerupController(type) {} + + TrippleLaserController::~TrippleLaserController() {} + + void TrippleLaserController::onCollected() {}; + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Powerups/PowerupController.cpp b/Space-Invaders/Source/Powerups/PowerupController.cpp new file mode 100644 index 000000000..b6a92202b --- /dev/null +++ b/Space-Invaders/Source/Powerups/PowerupController.cpp @@ -0,0 +1,89 @@ +#include "../../Header/Powerups/PowerupController.h" +#include "../../Header/Powerups/PowerupView.h" +#include "../../Header/Powerups/PowerupModel.h" +#include "../../Header/Global/ServiceLocator.h" +#include "../../Header/Player/PlayerController.h" + +namespace Powerup +{ + using namespace Global; + using namespace Player; + + PowerupController::PowerupController(PowerupType type) + { + powerup_view = new PowerupView(); + powerup_model = new PowerupModel(type); + } + + PowerupController::~PowerupController() + { + delete (powerup_view); + delete (powerup_model); + } + + void PowerupController::initialize(sf::Vector2f position) + { + powerup_model->initialize(position); + powerup_view->initialize(this); + } + + void PowerupController::update() + { + updatePowerupPosition(); + powerup_view->update(); + } + + void PowerupController::render() + { + powerup_view->render(); + } + + void PowerupController::onCollected() + { + applyPowerup(); + } + + void PowerupController::updatePowerupPosition() + { + sf::Vector2f currentPosition = powerup_model->getPowerupPosition(); + currentPosition.y += powerup_model->getMovementSpeed() * ServiceLocator::getInstance()->getTimeService()->getDeltaTime(); + + powerup_model->setPowerupPosition(currentPosition); + } + + void PowerupController::handleOutOfBounds() + { + sf::Vector2f powerupPosition = getCollectiblePosition(); + sf::Vector2u windowSize = ServiceLocator::getInstance()->getGraphicService()->getGameWindow()->getSize(); + + if (powerupPosition.x < 0 || powerupPosition.x > windowSize.x || + powerupPosition.y < 0 || powerupPosition.y > windowSize.y) + { + ServiceLocator::getInstance()->getPowerupService()->destroyPowerup(this); + } + } + + sf::Vector2f PowerupController::getCollectiblePosition() + { + return powerup_model->getPowerupPosition(); + } + + PowerupType PowerupController::getPowerupType() + { + return powerup_model->getPowerupType(); + } + const sf::Sprite& PowerupController::getColliderSprite() + { + return powerup_view->getPowerupSprite(); + } + void PowerupController::onCollision(ICollider* other_collider) + { + PlayerController* player_controller = dynamic_cast(other_collider); + + if (player_controller) + { + onCollected(); + ServiceLocator::getInstance()->getPowerupService()->destroyPowerup(this); + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Powerups/PowerupModel.cpp b/Space-Invaders/Source/Powerups/PowerupModel.cpp new file mode 100644 index 000000000..d12f790d1 --- /dev/null +++ b/Space-Invaders/Source/Powerups/PowerupModel.cpp @@ -0,0 +1,46 @@ +#include "../../Header/Powerups/PowerupModel.h" + +namespace Powerup +{ + PowerupModel::PowerupModel(PowerupType type) + { + powerup_type = type; + } + + PowerupModel::~PowerupModel() { } + + void PowerupModel::initialize(sf::Vector2f position) + { + powerup_position = position; + } + + sf::Vector2f PowerupModel::getPowerupPosition() + { + return powerup_position; + } + + void PowerupModel::setPowerupPosition(sf::Vector2f position) + { + powerup_position = position; + } + + PowerupType PowerupModel::getPowerupType() + { + return powerup_type; + } + + void PowerupModel::setPowerupType(PowerupType type) + { + powerup_type = type; + } + + float PowerupModel::getMovementSpeed() + { + return movement_speed; + } + + void PowerupModel::setMovementSpeed(float speed) + { + movement_speed = speed; + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Powerups/PowerupService.cpp b/Space-Invaders/Source/Powerups/PowerupService.cpp new file mode 100644 index 000000000..65acf150f --- /dev/null +++ b/Space-Invaders/Source/Powerups/PowerupService.cpp @@ -0,0 +1,86 @@ +#include "../../Header/Powerups/PowerupService.h" +#include "../../header/Powerups/PowerupController.h" +#include "../../header/Powerups/PowerupConfig.h" +#include "../../header/Global/ServiceLocator.h" +#include "../../header/Collision/ICollider.h" +#include "../../header/Powerups/Controllers/OutscalBombController.h" +#include "../../header/Powerups/Controllers/RapidFireController.h" +#include "../../header/Powerups/Controllers/ShieldController.h" +#include "../../header/Powerups/Controllers/TrippleLaserController.h" + +namespace Powerup +{ + using namespace Global; + using namespace Controller; + using namespace Collectible; + using namespace Collision; + + PowerupService::PowerupService() { } + + PowerupService::~PowerupService() { destroy(); } + + void PowerupService::initialize() { } + + void PowerupService::update() + { + for (Collectible::ICollectible* powerup : powerup_list) + powerup->update(); + + destroyFlaggedPowerup(); + } + + void PowerupService::render() + { + for (Collectible::ICollectible* powerup : powerup_list) + powerup->render(); + } + + PowerupController* PowerupService::createPowerup(PowerupType powerup_type) //creates and returns a pointer to the created powerup + { + switch (powerup_type) + { + case::Powerup::PowerupType::SHIELD: + return new ShieldController(Powerup::PowerupType::SHIELD); + + case::Powerup::PowerupType::RAPID_FIRE: + return new RapidFireController(Powerup::PowerupType::RAPID_FIRE); + + case::Powerup::PowerupType::TRIPPLE_LASER: + return new TrippleLaserController(Powerup::PowerupType::TRIPPLE_LASER); + + case::Powerup::PowerupType::OUTSCAL_BOMB: + return new OutscalBombController(Powerup::PowerupType::OUTSCAL_BOMB); + } + } + + void PowerupService::destroyFlaggedPowerup() + { + for (Collectible::ICollectible* powerup : flagged_powerup_list) + delete (powerup); + + flagged_powerup_list.clear(); + } + + PowerupController* PowerupService::spawnPowerup(PowerupType powerup_type, sf::Vector2f position) //initialize a powerup + { + PowerupController* powerup_controller = createPowerup(powerup_type); + + powerup_controller->initialize(position); + powerup_list.push_back(powerup_controller); + return powerup_controller; + } + + void PowerupService::destroyPowerup(PowerupController* powerup_controller) //destroy the powerup by controller type + { + ServiceLocator::getInstance()->getCollisionService()->removeCollider(dynamic_cast(powerup_controller)); + + flagged_powerup_list.push_back(powerup_controller); + powerup_list.erase(std::remove(powerup_list.begin(), powerup_list.end(), powerup_controller), powerup_list.end()); + } + + void PowerupService::destroy() + { + for (Collectible::ICollectible* powerup : powerup_list) + delete (powerup); + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Powerups/PowerupView.cpp b/Space-Invaders/Source/Powerups/PowerupView.cpp new file mode 100644 index 000000000..e3d884e7e --- /dev/null +++ b/Space-Invaders/Source/Powerups/PowerupView.cpp @@ -0,0 +1,71 @@ +#include "../../Header/Powerups/PowerupView.h" +#include "../../Header/Global/ServiceLocator.h" +#include "../../Header/Global/Config.h" +#include "../../Header/Bullet/BulletConfig.h" +#include "../../Header/Powerups/PowerupController.h" +#include "../../Header/Powerups/PowerupConfig.h" + +namespace Powerup +{ + using namespace Global; + using namespace UI::UIElement; + + PowerupView::PowerupView() { createUIElements(); } + + PowerupView::~PowerupView() { destroy(); } + + void PowerupView::initialize(PowerupController* controller) + { + powerup_controller = controller; + initializeImage(); + } + + void PowerupView::createUIElements() + { + powerup_image = new ImageView(); + } + + void PowerupView::initializeImage() + { + powerup_image->initialize(getPowerupTexturePath(), powerup_sprite_width, powerup_sprite_height, powerup_controller->getCollectiblePosition()); + } + + void PowerupView::update() + { + powerup_image->setPosition(powerup_controller->getCollectiblePosition()); + powerup_image->update(); + } + + void PowerupView::render() + { + powerup_image->render(); + } + + const sf::Sprite& PowerupView::getPowerupSprite() + { + return powerup_image->getSprite(); + } + + sf::String PowerupView::getPowerupTexturePath() + { + switch (powerup_controller->getPowerupType()) + { + case::Powerup::PowerupType::SHIELD: + return Config::shield_texture_path; + + case::Powerup::PowerupType::TRIPPLE_LASER: + return Config::tripple_laser_texture_path; + + case::Powerup::PowerupType::RAPID_FIRE: + return Config::rapid_fire_texture_path; + + case::Powerup::PowerupType::OUTSCAL_BOMB: + return Config::outscal_bomb_texture_path; + } + } + + void PowerupView::destroy() + { + delete(powerup_image); + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Sound/SoundService.cpp b/Space-Invaders/Source/Sound/SoundService.cpp new file mode 100644 index 000000000..f0cad0e9e --- /dev/null +++ b/Space-Invaders/Source/Sound/SoundService.cpp @@ -0,0 +1,75 @@ +#include "../../header/Sound/SoundService.h" +#include "../../header/Global/Config.h" + +namespace Sound +{ + using namespace Global; + + void SoundService::initialize() + { + loadBackgroundMusicFromFile(); + loadSoundFromFile(); + } + + void SoundService::loadBackgroundMusicFromFile() + { + if (!background_music.openFromFile(Config::background_music_path)) + { + printf("Error loading background music file"); + } + } + + void SoundService::loadSoundFromFile() + { + if (!buffer_button_click.loadFromFile(Config::button_click_sound_path)) + printf("Error loading background music file"); + if (!buffer_bullet_fire.loadFromFile(Config::bullet_fire_sound_path)) + printf("Error loading background music file"); + if (!buffer_powerup_enabled.loadFromFile(Config::powerup_enabled_sound_path)) + printf("Error loading background music file"); + if (!buffer_powerup_disabled.loadFromFile(Config::powerup_disabled_sound_path)) + printf("Error loading background music file"); + } + + void SoundService::playSound(SoundType soundType) + { + switch (soundType) + { + case SoundType::BUTTON_CLICK: + sound_effect.setBuffer(buffer_button_click); + sound_effect.play(); + break; + + case SoundType::BULLET_FIRE: + sound_effect.setBuffer(buffer_bullet_fire); + sound_effect.play(); + break; + + case SoundType::EXPLOSION: + explosion_sound_effect.setBuffer(buffer_explosion); + explosion_sound_effect.play(); + break; + + case SoundType::POWERUP_ENABLED: + powerup_sound_effect.setBuffer(buffer_powerup_enabled); + powerup_sound_effect.play(); + break; + + case SoundType::POWERUP_DISABLED: + powerup_sound_effect.setBuffer(buffer_powerup_disabled); + powerup_sound_effect.play(); + break; + + default: + printf("Invalid sound type"); + return; + } + } + + void SoundService::playBackgroundMusic() + { + background_music.setLoop(true); + background_music.setVolume(background_music_volume); + background_music.play(); + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/Time/TimeService.cpp b/Space-Invaders/Source/Time/TimeService.cpp new file mode 100644 index 000000000..718d1fa8c --- /dev/null +++ b/Space-Invaders/Source/Time/TimeService.cpp @@ -0,0 +1,42 @@ +#include "../../Header/Time/TimeService.h" + +namespace Time +{ + void TimeService::initialize() + { + previous_time = std::chrono::steady_clock::now(); + delta_time = 0; + } + + void TimeService::update() + { + updateDeltaTime(); + } + + float TimeService::getDeltaTime() + { + return delta_time; + } + + void TimeService::updateDeltaTime() + { + delta_time = calculateDeltaTime(); + updatePreviousTime(); + } + + float TimeService::calculateDeltaTime() + { + // Calculate time difference in microseconds between the current and previous frame. + int delta = std::chrono::duration_cast( + std::chrono::steady_clock::now() - previous_time).count(); + + // The cast is used to convert delta time from microseconds into seconds. + return static_cast(delta) / static_cast(1000000); + } + + // Update previous_time to the current time + void TimeService::updatePreviousTime() + { + previous_time = std::chrono::steady_clock::now(); + } +} diff --git a/Space-Invaders/Source/UI/GameplayUI/GameplayUIController.cpp b/Space-Invaders/Source/UI/GameplayUI/GameplayUIController.cpp new file mode 100644 index 000000000..356214c14 --- /dev/null +++ b/Space-Invaders/Source/UI/GameplayUI/GameplayUIController.cpp @@ -0,0 +1,85 @@ +#include "../../header/UI/GameplayUI/GameplayUIController.h" +#include "../../header/Global/Config.h" +#include "../../header/Global/ServiceLocator.h" +#include "../../header/Gameplay/GameplayService.h" +#include "../../header/Sound/SoundService.h" +#include "../../header/Main/GameService.h" +#include "../../header/Player/PlayerModel.h" + +namespace UI +{ + namespace GameplayUI + { + using namespace Main; + using namespace Sound; + using namespace Global; + using namespace Player; + using namespace UI::UIElement; + + GameplayUIController::GameplayUIController() { createUIElements(); } + + GameplayUIController::~GameplayUIController() { destroy(); } + + void GameplayUIController::initialize() + { + initializeImage(); + initializeText(); + } + + void GameplayUIController::createUIElements() + { + player_image = new ImageView(); + enemies_killed_text = new TextView(); + } + + void GameplayUIController::initializeImage() + { + player_image->initialize(Config::player_texture_path, player_sprite_width, player_sprite_height, sf::Vector2f(0, 0)); + } + + void GameplayUIController::initializeText() + { + sf::String enemies_killed_string = "Enemies Killed : 0"; + enemies_killed_text->initialize(enemies_killed_string, sf::Vector2f(enemies_killed_text_x_position, text_y_position), FontType::BUBBLE_BOBBLE, font_size, text_color); + } + + void GameplayUIController::update() + { + updateEnemiesKilledText(); + } + + void GameplayUIController::render() + { + enemies_killed_text->render(); + drawPlayerLives(); + } + + void GameplayUIController::show() + { + + } + + void GameplayUIController::updateEnemiesKilledText() + { + sf::String enemies_killed_string = "Enemies Killed : " + std::to_string(PlayerModel::enemies_killed); + enemies_killed_text->setText(enemies_killed_string); + } + + void GameplayUIController::drawPlayerLives() + { + sf::RenderWindow* game_window = Global::ServiceLocator::getInstance()->getGraphicService()->getGameWindow(); + + for (int i = 0; i < PlayerModel::player_lives; i++) + { + player_image->setPosition(sf::Vector2f(player_lives_x_offset - (i * player_lives_spacing), player_lives_y_offset)); + player_image->render(); + } + } + + void GameplayUIController::destroy() + { + delete(player_image); + delete(enemies_killed_text); + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/UI/MainMenu/MainMenuUIController.cpp b/Space-Invaders/Source/UI/MainMenu/MainMenuUIController.cpp new file mode 100644 index 000000000..c33f7f73e --- /dev/null +++ b/Space-Invaders/Source/UI/MainMenu/MainMenuUIController.cpp @@ -0,0 +1,124 @@ +#include "../../Header/UI/MainMenu/MainMenuUIController.h" +#include "../../Header/Main/GameService.h" +#include "../../Header/Global/ServiceLocator.h" +#include "../../Header/Graphic/GraphicService.h" +#include "../../Header/Global/Config.h" +#include "../../Header/Sound/SoundService.h" +#include "../../Header/Event/EventService.h" + +namespace UI +{ + namespace MainMenu + { + using namespace Global; + using namespace Main; + using namespace UIElement; + using namespace Sound; + + MainMenuUIController::MainMenuUIController() + { + createImage(); + createButtons(); + } + + MainMenuUIController::~MainMenuUIController() + { + destroy(); + } + + void MainMenuUIController::initialize() + { + initializeBackgroundImage(); + initializeButtons(); + registerButtonCallback(); + } + + void MainMenuUIController::createImage() + { + background_image = new ImageView(); + } + + void MainMenuUIController::createButtons() + { + play_button = new ButtonView(); + instructions_button = new ButtonView(); + quit_button = new ButtonView(); + } + + void MainMenuUIController::initializeBackgroundImage() + { + sf::RenderWindow* game_window = Global::ServiceLocator::getInstance()->getGraphicService()->getGameWindow(); + + background_image->initialize(Config::background_texture_path, game_window->getSize().x, game_window->getSize().y, sf::Vector2f(0, 0)); + background_image->setImageAlpha(background_alpha); + } + + void MainMenuUIController::initializeButtons() + { + play_button->initialize("Play Button", Config::play_button_texture_path, button_width, button_height, sf::Vector2f(0, play_button_y_position)); + instructions_button->initialize("Instructions Button", Config::instructions_button_texture_path, button_width, button_height, sf::Vector2f(0, instructions_button_y_position)); + quit_button->initialize("Quit Button", Config::quit_button_texture_path, button_width, button_height, sf::Vector2f(0, quit_button_y_position)); + + play_button->setCentreAlinged(); + instructions_button->setCentreAlinged(); + quit_button->setCentreAlinged(); + } + + void MainMenuUIController::registerButtonCallback() + { + play_button->registerCallbackFuntion(std::bind(&MainMenuUIController::playButtonCallback, this)); + instructions_button->registerCallbackFuntion(std::bind(&MainMenuUIController::instructionsButtonCallback, this)); + quit_button->registerCallbackFuntion(std::bind(&MainMenuUIController::quitButtonCallback, this)); + } + + void MainMenuUIController::playButtonCallback() + { + Global::ServiceLocator::getInstance()->getSoundService()->playSound(SoundType::BUTTON_CLICK); + GameService::setGameState(GameState::GAMEPLAY); + } + + void MainMenuUIController::instructionsButtonCallback() + { + Global::ServiceLocator::getInstance()->getSoundService()->playSound(SoundType::BUTTON_CLICK); + } + + void MainMenuUIController::quitButtonCallback() + { + Global::ServiceLocator::getInstance()->getGraphicService()->getGameWindow()->close(); + } + + void MainMenuUIController::update() + { + background_image->update(); + play_button->update(); + instructions_button->update(); + quit_button->update(); + } + + void MainMenuUIController::render() + { + background_image->render(); + play_button->render(); + instructions_button->render(); + quit_button->render(); + } + + void MainMenuUIController::show() + { + background_image->show(); + play_button->show(); + instructions_button->show(); + quit_button->show(); + + Global::ServiceLocator::getInstance()->getSoundService()->playBackgroundMusic(); + } + + void MainMenuUIController::destroy() + { + delete (play_button); + delete (instructions_button); + delete (quit_button); + delete (background_image); + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/UI/SplashScreen/SplashScreenUIController.cpp b/Space-Invaders/Source/UI/SplashScreen/SplashScreenUIController.cpp new file mode 100644 index 000000000..1a7961700 --- /dev/null +++ b/Space-Invaders/Source/UI/SplashScreen/SplashScreenUIController.cpp @@ -0,0 +1,76 @@ +#include "../../header/UI/SplashScreen/SplashScreenUIController.h" +#include "../../header/Main/GameService.h" +#include "../../header/Global/ServiceLocator.h" +#include "../../header/Graphic/GraphicService.h" +#include "../../header/Sound/SoundService.h" +#include "../../header/Global/Config.h" + +namespace UI +{ + namespace SplashScreen + { + using namespace Main; + using namespace Graphics; + using namespace Global; + using namespace UIElement; + using namespace Sound; + + SplashScreenUIController::SplashScreenUIController() + { + outscal_logo_view = new AnimatedImageView(); + } + + SplashScreenUIController::~SplashScreenUIController() + { + delete (outscal_logo_view); + } + + void SplashScreenUIController::initialize() + { + initializeOutscalLogo(); + } + + void SplashScreenUIController::update() + { + outscal_logo_view->update(); + } + + void SplashScreenUIController::render() + { + outscal_logo_view->render(); + } + + void SplashScreenUIController::initializeOutscalLogo() + { + sf::Vector2f position = getLogoPosition(); + outscal_logo_view->initialize(Config::outscal_logo_texture_path, logo_width, logo_height, position); + + } + + sf::Vector2f SplashScreenUIController::getLogoPosition() + { + sf::RenderWindow* game_window = Global::ServiceLocator::getInstance()->getGraphicService()->getGameWindow(); + + float x_position = (game_window->getSize().x - logo_width) / 2.0f; + float y_position = (game_window->getSize().y - logo_height) / 2.0f; + + return sf::Vector2f(x_position, y_position); + } + + void SplashScreenUIController::show() + { + outscal_logo_view->playAnimation(AnimationType::FADE_IN, logo_animation_duration, std::bind(&SplashScreenUIController::fadeInAnimationCallback, this)); + } + + void SplashScreenUIController::fadeInAnimationCallback() + { + outscal_logo_view->playAnimation(AnimationType::FADE_OUT, logo_animation_duration, std::bind(&SplashScreenUIController::fadeOutAnimationCallback, this)); + } + + void SplashScreenUIController::fadeOutAnimationCallback() + { + ServiceLocator::getInstance()->getSoundService()->playBackgroundMusic(); + GameService::setGameState(GameState::MAIN_MENU); + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/UI/UIElement/AnimatedImageView.cpp b/Space-Invaders/Source/UI/UIElement/AnimatedImageView.cpp new file mode 100644 index 000000000..b07e25481 --- /dev/null +++ b/Space-Invaders/Source/UI/UIElement/AnimatedImageView.cpp @@ -0,0 +1,104 @@ +#include "../../Header/UI/UIElement/AnimatedImageView.h" + +namespace UI +{ + namespace UIElement + { + AnimatedImageView::AnimatedImageView() = default; + + AnimatedImageView::~AnimatedImageView() = default; + + void AnimatedImageView::initialize(sf::String texture_path, float image_width, float image_height, sf::Vector2f position) + { + ImageView::initialize(texture_path, image_width, image_height, position); + } + + void AnimatedImageView::registerCallbackFuntion(CallbackFunction animation_end_callback) + { + callback_function = animation_end_callback; + } + + void AnimatedImageView::update() + { + ImageView::update(); + + if (ui_state == UIState::VISIBLE) + { + updateElapsedDuration(); + handleAnimationProgress(); + updateAnimation(); + } + } + + void AnimatedImageView::render() + { + ImageView::render(); + } + + void AnimatedImageView::playAnimation(AnimationType type, float duration, CallbackFunction animation_end_callback) + { + ImageView::show(); + reset(); + setAnimationType(type); + setAnimationDuration(duration); + registerCallbackFuntion(animation_end_callback); + } + + void AnimatedImageView::updateElapsedDuration() + { + float deltaTime = clock.restart().asSeconds(); + elapsed_duration += deltaTime; + } + + void AnimatedImageView::handleAnimationProgress() + { + if (elapsed_duration >= animation_duration && callback_function) + { + callback_function(); + } + } + + void AnimatedImageView::updateAnimation() + { + switch (animation_type) + { + case AnimationType::FADE_IN: + fadeIn(); + break; + case AnimationType::FADE_OUT: + fadeOut(); + break; + } + } + + void AnimatedImageView::setAnimationDuration(float duration) + { + animation_duration = duration; + } + + void AnimatedImageView::setAnimationType(AnimationType type) + { + animation_type = type; + } + + void AnimatedImageView::fadeIn() + { + float alpha = std::min(1.0f, elapsed_duration / animation_duration); + image_sprite.setColor(sf::Color(255, 255, 255, static_cast(alpha * 255))); + } + + void AnimatedImageView::fadeOut() + { + float alpha = std::max(0.0f, 1.0f - (elapsed_duration / animation_duration)); + image_sprite.setColor(sf::Color(255, 255, 255, static_cast(alpha * 255))); + } + + void AnimatedImageView::reset() + { + animation_duration = default_animation_duration; + animation_type = AnimationType::FADE_IN; + clock.restart(); + elapsed_duration = 0.0f; + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/UI/UIElement/ButtonView.cpp b/Space-Invaders/Source/UI/UIElement/ButtonView.cpp new file mode 100644 index 000000000..a8aaeb26f --- /dev/null +++ b/Space-Invaders/Source/UI/UIElement/ButtonView.cpp @@ -0,0 +1,64 @@ +#include "../../header/UI/UIElement/ButtonView.h" +#include "../../header/Global/ServiceLocator.h" +#include "../../header/Event/EventService.h" +#include "../../header/Sound/SoundService.h" + +namespace UI +{ + namespace UIElement + { + using namespace Event; + using namespace Global; + + ButtonView::ButtonView() = default; + + ButtonView::~ButtonView() = default; + + void ButtonView::initialize(sf::String title, sf::String texture_path, float button_width, float button_height, sf::Vector2f position) + { + ImageView::initialize(texture_path, button_width, button_height, position); + button_title = title; + } + + void ButtonView::registerCallbackFuntion(CallbackFunction button_callback) + { + callback_function = button_callback; + } + + void ButtonView::update() + { + ImageView::update(); + + if (ui_state == UIState::VISIBLE) + { + handleButtonInteraction(); + } + } + + void ButtonView::render() + { + ImageView::render(); + } + + void ButtonView::handleButtonInteraction() + { + sf::Vector2f mouse_position = sf::Vector2f(sf::Mouse::getPosition(*game_window)); + + if (clickedButton(&image_sprite, mouse_position)) + { + if (callback_function) callback_function(); + } + } + + bool ButtonView::clickedButton(sf::Sprite* button_sprite, sf::Vector2f mouse_position) + { + return ServiceLocator::getInstance()->getEventService()->pressedLeftMouseButton() && + button_sprite->getGlobalBounds().contains(mouse_position); + } + + void ButtonView::printButtonClicked() + { + printf("Clicked %s\n", button_title.toAnsiString().c_str()); + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/UI/UIElement/ImageView.cpp b/Space-Invaders/Source/UI/UIElement/ImageView.cpp new file mode 100644 index 000000000..1d12cf92d --- /dev/null +++ b/Space-Invaders/Source/UI/UIElement/ImageView.cpp @@ -0,0 +1,98 @@ +#include "../../header/UI/UIElement/ImageView.h" + +namespace UI +{ + namespace UIElement + { + ImageView::ImageView() = default; + + ImageView::~ImageView() = default; + + void ImageView::initialize(sf::String texture_path, float image_width, float image_height, sf::Vector2f position) + { + UIView::initialize(); + setTexture(texture_path); + setScale(image_width, image_height); + setPosition(position); + } + + void ImageView::update() + { + UIView::update(); + } + + void ImageView::render() + { + UIView::render(); + + if (ui_state == UIState::VISIBLE) + { + game_window->draw(image_sprite); + } + } + + void ImageView::setTexture(sf::String texture_path) + { + if (image_texture.loadFromFile(texture_path)) + { + image_sprite.setTexture(image_texture); + } + } + + void ImageView::setScale(float width, float height) + { + float scale_x = width / image_sprite.getTexture()->getSize().x; + float scale_y = height / image_sprite.getTexture()->getSize().y; + + image_sprite.setScale(scale_x, scale_y); + } + + void ImageView::setPosition(sf::Vector2f position) + { + image_sprite.setPosition(position); + } + + void ImageView::setRotation(float rotation_angle) + { + image_sprite.setRotation(rotation_angle); + } + + void ImageView::setOriginAtCentre() + { + image_sprite.setOrigin(image_sprite.getLocalBounds().width / 2, image_sprite.getLocalBounds().height / 2); + } + + void ImageView::setImageAlpha(float alpha) + { + sf::Color color = image_sprite.getColor(); + color.a = alpha; + image_sprite.setColor(color); + } + + void ImageView::setCentreAlinged() + { + float x_position = (game_window->getSize().x / 2) - (image_sprite.getGlobalBounds().width / 2); + float y_position = image_sprite.getGlobalBounds().getPosition().y; + + image_sprite.setPosition(x_position, y_position); + } + + void ImageView::setTextureRect(sf::IntRect texture_rect) + { + image_sprite.setTextureRect(texture_rect); + } + + void ImageView::setScale(float width, float height, float tile_width, float tile_height) + { + float scale_x = width / tile_width; + float scale_y = height / tile_height; + + image_sprite.setScale(scale_x, scale_y); + } + + const sf::Sprite& ImageView::getSprite() + { + return image_sprite; //returns the sprite. + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/UI/UIElement/TextView.cpp b/Space-Invaders/Source/UI/UIElement/TextView.cpp new file mode 100644 index 000000000..400b351b7 --- /dev/null +++ b/Space-Invaders/Source/UI/UIElement/TextView.cpp @@ -0,0 +1,95 @@ +#include "../../Header/UI/UIElement/TextView.h" +#include "../../Header/Global/Config.h" + +namespace UI +{ + namespace UIElement + { + using namespace Global; + + sf::Font TextView::font_bubble_bobble; + sf::Font TextView::font_DS_DIGIB; + + TextView::TextView() = default; + + TextView::~TextView() = default; + + void TextView::initialize(sf::String text_value, sf::Vector2f position, FontType font_type, int font_size, sf::Color color) + { + UIView::initialize(); + + setText(text_value); + setTextPosition(position); + setFont(font_type); + setFontSize(font_size); + setTextColor(color); + } + + void TextView::update() + { + UIView::update(); + } + + void TextView::render() + { + UIView::render(); + + if (ui_state == UIState::VISIBLE) + { + game_window->draw(text); + } + } + + void TextView::initializeTextView() + { + loadFont(); + } + + void TextView::loadFont() + { + font_bubble_bobble.loadFromFile(Config::bubble_bobble_font_path); + font_DS_DIGIB.loadFromFile(Config::DS_DIGIB_font_path); + } + + void TextView::setText(sf::String text_value) + { + text.setString(text_value); + } + + void TextView::setFont(FontType font_type) + { + switch (font_type) + { + case FontType::BUBBLE_BOBBLE: + text.setFont(font_bubble_bobble); + break; + case FontType::DS_DIGIB: + text.setFont(font_DS_DIGIB); + break; + } + } + + void TextView::setFontSize(int font_size) + { + text.setCharacterSize(font_size); + } + + void TextView::setTextPosition(sf::Vector2f position) + { + text.setPosition(position); + } + + void TextView::setTextColor(sf::Color color) + { + text.setFillColor(color); + } + + void TextView::setTextCentreAligned() + { + float x_position = (game_window->getSize().x - text.getLocalBounds().width) / 2; + float y_position = text.getGlobalBounds().getPosition().y; + + text.setPosition(sf::Vector2f(x_position, y_position)); + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/UI/UIElement/UIView.cpp b/Space-Invaders/Source/UI/UIElement/UIView.cpp new file mode 100644 index 000000000..3b500c488 --- /dev/null +++ b/Space-Invaders/Source/UI/UIElement/UIView.cpp @@ -0,0 +1,36 @@ +#include "../../header/UI/UIElement/UIView.h" +#include "../../header/Global/ServiceLocator.h" +#include "../../Header/Graphic/GraphicService.h" + +namespace UI +{ + namespace UIElement + { + using namespace Global; + using namespace Graphics; + + UIView::UIView() = default; + + UIView::~UIView() = default; + + void UIView::initialize() + { + game_window = ServiceLocator::getInstance()->getGraphicService()->getGameWindow(); + ui_state = UIState::VISIBLE; + } + + void UIView::update() { } + + void UIView::render() { } + + void UIView::show() + { + ui_state = UIState::VISIBLE; + } + + void UIView::hide() + { + ui_state = UIState::HIDDEN; + } + } +} \ No newline at end of file diff --git a/Space-Invaders/Source/UI/UIService.cpp b/Space-Invaders/Source/UI/UIService.cpp new file mode 100644 index 000000000..810d66c40 --- /dev/null +++ b/Space-Invaders/Source/UI/UIService.cpp @@ -0,0 +1,89 @@ +#include "../../Header/UI/UIService.h" +#include "../../Header/Main/GameService.h" +#include "../../Header/UI/UIElement/TextView.h" + +namespace UI +{ + using namespace Main; + using namespace MainMenu; + using namespace GameplayUI; + using namespace UIElement; + using namespace Interface; + using namespace SplashScreen; + + UIService::UIService() + { + main_menu_controller = nullptr; + gameplay_ui_controller = nullptr; + splash_screen_ui_controller = nullptr; + createControllers(); + } + + void UIService::createControllers() + { + main_menu_controller = new MainMenuUIController(); + gameplay_ui_controller = new GameplayUIController(); + splash_screen_ui_controller = new SplashScreenUIController(); + } + + UIService::~UIService() + { + destroy(); + } + + void UIService::initialize() + { + TextView::initializeTextView(); + initializeControllers(); + } + + void UIService::update() + { + IUIController* ui_controller = getCurrentUIController(); + if (ui_controller) ui_controller->update(); + } + + void UIService::render() + { + IUIController* ui_controller = getCurrentUIController(); + if (ui_controller) ui_controller->render(); + } + + void UIService::showScreen() + { + IUIController* ui_controller = getCurrentUIController(); + if (ui_controller) ui_controller->show(); + } + + void UIService::initializeControllers() + { + main_menu_controller->initialize(); + gameplay_ui_controller->initialize(); + splash_screen_ui_controller->initialize(); + } + + IUIController* UIService::getCurrentUIController() + { + switch (GameService::getGameState()) + { + case GameState::MAIN_MENU: + return main_menu_controller; + + case GameState::GAMEPLAY: + return gameplay_ui_controller; + + case GameState::SPLASH_SCREEN: + return splash_screen_ui_controller; + + default: + return nullptr; + } + } + + void UIService::destroy() + { + delete(main_menu_controller); + delete(gameplay_ui_controller); + delete(splash_screen_ui_controller); + } +} \ No newline at end of file diff --git a/Space-Invaders/Space-Invaders.vcxproj b/Space-Invaders/Space-Invaders.vcxproj index 6f7fa388d..3dd5235bd 100644 --- a/Space-Invaders/Space-Invaders.vcxproj +++ b/Space-Invaders/Space-Invaders.vcxproj @@ -1,140 +1,160 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 17.0 - Win32Proj - {ab3664cd-9870-4359-8811-b481db3b55a0} - SpaceInvaders - 10.0 - - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - Level3 - true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - - - - - Level3 - true - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - true - true - - - - - Level3 - true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - $(SolutionDir)sfml\include;%(AdditionalIncludeDirectories) - - - Console - true - $(SolutionDir)sfml\lib;%(AdditionalLibraryDirectories) - sfml-graphics-d.lib;sfml-window-d.lib;sfml-network-d.lib;sfml-audio-d.lib;sfml-system-d.lib;%(AdditionalDependencies) - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - $(SolutionDir)sfml\include;%(AdditionalIncludeDirectories) - - - Console - true - true - true - $(SolutionDir)sfml\lib;%(AdditionalLibraryDirectories) - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {ab3664cd-9870-4359-8811-b481db3b55a0} + SpaceInvaders + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)sfml\include;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)sfml\lib;%(AdditionalLibraryDirectories) + sfml-graphics-d.lib;sfml-window-d.lib;sfml-network-d.lib;sfml-audio-d.lib;sfml-system-d.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)sfml\include;%(AdditionalIncludeDirectories) + + + Console + true + true + true + $(SolutionDir)sfml\lib;%(AdditionalLibraryDirectories) + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Space-Invaders/Space-Invaders.vcxproj.filters b/Space-Invaders/Space-Invaders.vcxproj.filters index ce0c35ccf..8ae369c39 100644 --- a/Space-Invaders/Space-Invaders.vcxproj.filters +++ b/Space-Invaders/Space-Invaders.vcxproj.filters @@ -1,22 +1,78 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/Space-Invaders/Space-Invaders.vcxproj.user b/Space-Invaders/Space-Invaders.vcxproj.user index 966b4ffb6..429333de9 100644 --- a/Space-Invaders/Space-Invaders.vcxproj.user +++ b/Space-Invaders/Space-Invaders.vcxproj.user @@ -1,6 +1,6 @@ - - - - true - + + + + true + \ No newline at end of file diff --git a/Space-Invaders/main.cpp b/Space-Invaders/main.cpp index 7d5f90dff..db819e86b 100644 --- a/Space-Invaders/main.cpp +++ b/Space-Invaders/main.cpp @@ -1,5 +1,17 @@ - -int main() -{ - return 0; -} \ No newline at end of file +#include "../../header/Main/GameService.h" + +int main() +{ + using namespace Main; + + GameService* game_service = new GameService(); + game_service->ignite(); + + while (game_service->isRunning()) + { + game_service->update(); + game_service->render(); + } + + return 0; +}