From ba8a30d80033003d35cef901c91eae9ab63bbc8c Mon Sep 17 00:00:00 2001 From: Gregor Maclaine Date: Wed, 17 Nov 2021 16:30:40 +0000 Subject: [PATCH 01/20] Added sprite class and new enemy image --- assets/enemy.png | Bin 1968 -> 57332 bytes src/Enemy.cpp | 15 ++++----------- src/Enemy.hpp | 4 ++-- src/Hitbox.cpp | 2 +- src/Sprite.cpp | 19 +++++++++++++++++++ src/Sprite.hpp | 23 +++++++++++++++++++++++ src/main.cpp | 6 ++++-- 7 files changed, 53 insertions(+), 16 deletions(-) create mode 100644 src/Sprite.cpp create mode 100644 src/Sprite.hpp diff --git a/assets/enemy.png b/assets/enemy.png index bac3c56221e08207d72f7b3487d41200e7511ce4..2f6f1e02052a581b3834f72418f16c17057750c1 100644 GIT binary patch literal 57332 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 literal 1968 zcmZ8ido+}393CB(X3EwsBV|=0Wp}y=IQRd6}c0M zKp?idx;T14BOifK+obgsGz*(|$b$y8XfJ061f$(x6k4bU+n=^aASyFZivb$YdUJ$} zZ!`j--MI3pwS+&tgg|IIxjNc=$DfxC9tKE(1}#(G0-n8N2PT!L=eY@4c)Pdoc8*r* z2Yf9Kt&2o{H&|qqhW5)d*41`zB)_MBLaaV?Aw-k3sgk|B&?5a$zoH2_#NedWoznBghH@~BsYwQWBPxAdX_y+Uc1q5_9F$xhJHul7yvj_5vBYl4x!ffsB*<~& zq=EK4Yd#}eHZj4Z1&UO20E@`=1Om#1F;kOLf9&_L9NYy&f_{h-y@=o7rqC8!de{jV zJ(l&ll~N_;Rawp_eE*H&8<6w7! zu;U~ROtdcw!^V*1M8dFTYR1Y~#jF|FE$R^}|*iQus{a*$RtpBEgk&{5l=1 z=wcb+XN|NY<)TOeDqz!EeL*d1T!+Tf{N--3idHd$->=NdOa~|96MUKqwtz<3Q<1QO zh|A8f$AhiOCm#&(o(mP_7Tsoqhe{}~e%q8QyagZqVMC{l)Vtik+USt(b^-6K{XA<>yv<a5--`wyhT<*}B9h<0$`X*1pr%bm>K+NSkiU-!MH5j}^ji ztxRC#N7eM<5<|pp(Xvk+bZq7Ksu< zmh0!Y6e=DY@lFz*aUW9q=1bSz>!T-+o}HXxOQE`66$5i%Z`-{!ErWWNfXeYvE!C0A zBvS6t3+*|yW!1c-YB@Yva_0*AI2#;CA)Hvmu>|Hn@~(GY<^m=mpNcXoGx8Z7ZWX(+Wm9ggD5wf^JuZX z;yjv|$EIS=OUTOcR<8A9iuP_R7>hMc5Re5Edj%qvAu012q>rc+q6S65NadOJ0u;$( z26x~sQA==qoq)8O1ku3=I#h{0NIno!UKQt*J8edQ_5B?*KQB(b91{3=iwSxNjSAY; zwOl-RPIG1UuR84SEE=C+S6$(?B(Rw^5FP>JjKYW6H`%Z<6&G59V1)Urh1z-QX_zE` zew5Zf46|re#+bANpi@wo30zzB1~wc+! Date: Wed, 17 Nov 2021 16:54:05 +0000 Subject: [PATCH 02/20] Implemented sprite class in player and staticsprite --- src/Player.cpp | 17 +++++++++-------- src/Player.hpp | 5 ++--- src/StaticSprite.cpp | 12 +++--------- src/StaticSprite.hpp | 12 +++++------- src/main.cpp | 13 ++++++------- 5 files changed, 25 insertions(+), 34 deletions(-) diff --git a/src/Player.cpp b/src/Player.cpp index 5d203f2..2635777 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -2,13 +2,14 @@ unsigned int Player::maxJumps { 1 }; -Player::Player(sf::Vector2f _pos, sf::Vector2f _size) : - Hitbox { _pos, _size } +Player::Player(sf::Vector2f _pos, sf::Vector2f target_size) : + Hitbox { _pos, target_size }, + Sprite { "assets/main_character.png", _pos, target_size } { - // Load Texture - texture.loadFromFile("assets/main_character.png"); - sprite.setTexture(texture); - size = sf::Vector2f(texture.getSize()); + // // Load Texture + // texture.loadFromFile("assets/main_character.png"); + // sprite.setTexture(texture); + // size = sf::Vector2f(texture.getSize()); // Initialise Held Keys Map held_keys[sf::Keyboard::W] = 0; @@ -18,9 +19,9 @@ Player::Player(sf::Vector2f _pos, sf::Vector2f _size) : held_keys[sf::Keyboard::Space] = 0; // Initialise Position - pos = _pos; + // pos = _pos; speed = 3.f; - sprite.setPosition(pos); + // sprite.setPosition(pos); } void Player::handleKeyPress(sf::Keyboard::Key key) diff --git a/src/Player.hpp b/src/Player.hpp index b0333ca..640658b 100644 --- a/src/Player.hpp +++ b/src/Player.hpp @@ -2,6 +2,7 @@ #define Player_H #include "Hitbox.hpp" +#include "Sprite.hpp" #include "StaticSprite.hpp" /** @@ -10,10 +11,9 @@ * @param pos The initial position of the top left of the player * @param size The width and height of the player's hitbox */ -class Player : public Hitbox +class Player : public Hitbox, public Sprite { private: - sf::Texture texture; float speed; // A map of keys that are 1 if held but 0 if not std::unordered_map held_keys; @@ -28,7 +28,6 @@ class Player : public Hitbox bool isGrounded; public: - sf::Sprite sprite; Player(sf::Vector2f pos, sf::Vector2f size); // Handles a key press event from the keyboard void handleKeyPress(sf::Keyboard::Key key); diff --git a/src/StaticSprite.cpp b/src/StaticSprite.cpp index 744474f..95b843f 100644 --- a/src/StaticSprite.cpp +++ b/src/StaticSprite.cpp @@ -1,13 +1,7 @@ #include "StaticSprite.hpp" -StaticSprite::StaticSprite(std::string texture_name, sf::Vector2f _pos) : - Hitbox { _pos, sf::Vector2f() } +StaticSprite::StaticSprite(std::string texture_name, sf::Vector2f _pos, sf::Vector2f target_size) : + Hitbox { _pos, target_size }, + Sprite { texture_name, _pos, target_size } { - // Load Texture - texture.loadFromFile(texture_name); - sprite.setTexture(texture); - size = sf::Vector2f(texture.getSize()); - - // Initialise Position - sprite.setPosition(pos); } diff --git a/src/StaticSprite.hpp b/src/StaticSprite.hpp index d3f00ab..11b9228 100644 --- a/src/StaticSprite.hpp +++ b/src/StaticSprite.hpp @@ -2,6 +2,7 @@ #define StaticSprite_H #include "Hitbox.hpp" +#include "Sprite.hpp" /** * A class for objects such as obsticles and platforms that will @@ -9,16 +10,13 @@ * be interacted with using its hitbox. * * @param texture_name The path to the image for the sprite texture - * @param _pos The initial position for the top left of the sprite + * @param pos The initial position for the top left of the sprite + * @param target_size The size that the platform should be */ -class StaticSprite : public Hitbox +class StaticSprite : public Hitbox, public Sprite { -private: - sf::Texture texture; - public: - sf::Sprite sprite; - StaticSprite(std::string texture_name, sf::Vector2f _pos); + StaticSprite(std::string texture_name, sf::Vector2f pos, sf::Vector2f target_size); }; #endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index f5f89d9..258b23f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,11 +13,11 @@ int main() bool show_hitboxes = false; - Player player(sf::Vector2f(500.f, 0.f), sf::Vector2f()); + Player player(sf::Vector2f(500.f, 0.f), sf::Vector2f(215.f, 258.f)); StaticSprite platforms[2] = { - StaticSprite("assets/platform.png", sf::Vector2f(10.f, 500.f)), - StaticSprite("assets/platform.png", sf::Vector2f(1100.f, 720.f)) + StaticSprite("assets/platform.png", sf::Vector2f(10.f, 500.f), sf::Vector2f(760.f, 107.f)), + StaticSprite("assets/platform.png", sf::Vector2f(1100.f, 720.f), sf::Vector2f(760.f, 107.f)) }; Enemy enemies[2] = { @@ -68,10 +68,8 @@ int main() { enemies[i].updatePosition(platforms, player.pos); - window.draw(platforms[i].sprite); - + platforms[i].draw(window); enemies[i].draw(window); - window.draw(enemies[i].sprite); if (show_hitboxes) { @@ -80,7 +78,8 @@ int main() } } - window.draw(player.sprite); + player.draw(window); + if (show_hitboxes) window.draw(player.get_hitbox_outline()); From af504642ea5b5eb931a7d89a7d2ac5729ca0cd5b Mon Sep 17 00:00:00 2001 From: Gregor Maclaine Date: Wed, 17 Nov 2021 17:22:02 +0000 Subject: [PATCH 03/20] Added third platform --- src/Enemy.cpp | 2 +- src/Player.cpp | 2 +- src/main.cpp | 18 +++++++++++------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/Enemy.cpp b/src/Enemy.cpp index 25fcc6a..966aa90 100644 --- a/src/Enemy.cpp +++ b/src/Enemy.cpp @@ -15,7 +15,7 @@ void Enemy::updatePosition(StaticSprite* platforms, sf::Vector2f player_pos) const float horiz_vel = player_pos.x > pos.x ? speed : -speed; update(horiz_vel); - for (unsigned int i = 0; i < 2; i++) + for (unsigned int i = 0; i < 3; i++) { if (overlaps(platforms[i])) { diff --git a/src/Player.cpp b/src/Player.cpp index 2635777..f10e517 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -56,7 +56,7 @@ void Player::updatePosition(StaticSprite* platforms) isGrounded = false; CollisionFix fix; - for (unsigned int i = 0; i < 2; i++) + for (unsigned int i = 0; i < 3; i++) { if (overlaps(platforms[i])) { diff --git a/src/main.cpp b/src/main.cpp index 258b23f..5e5ae1b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,9 +15,10 @@ int main() Player player(sf::Vector2f(500.f, 0.f), sf::Vector2f(215.f, 258.f)); - StaticSprite platforms[2] = { + StaticSprite platforms[3] = { StaticSprite("assets/platform.png", sf::Vector2f(10.f, 500.f), sf::Vector2f(760.f, 107.f)), - StaticSprite("assets/platform.png", sf::Vector2f(1100.f, 720.f), sf::Vector2f(760.f, 107.f)) + StaticSprite("assets/platform.png", sf::Vector2f(1100.f, 720.f), sf::Vector2f(760.f, 107.f)), + StaticSprite("assets/platform.png", sf::Vector2f(1100.f, 100.f), sf::Vector2f(760.f, 107.f)) }; Enemy enemies[2] = { @@ -64,18 +65,21 @@ int main() window.clear(); - for (int i = 0; i < 2; i++) + for (unsigned int i = 0; i < 2; i++) { enemies[i].updatePosition(platforms, player.pos); + enemies[i].draw(window); + + if (show_hitboxes) + window.draw(enemies[i].get_hitbox_outline()); + } + for (unsigned int i = 0; i < 3; i++) + { platforms[i].draw(window); - enemies[i].draw(window); if (show_hitboxes) - { window.draw(platforms[i].get_hitbox_outline()); - window.draw(enemies[i].get_hitbox_outline()); - } } player.draw(window); From 790fb27a32d84530785a5aaab12edd35f499692f Mon Sep 17 00:00:00 2001 From: Gregor Maclaine Date: Wed, 17 Nov 2021 18:08:27 +0000 Subject: [PATCH 04/20] Added delta time fix This commit technically does not work because for some reason at the start of the program the framerate acts a bit weird. It causes everything effected by gravity (player and enemies) to fall directly through the platforms and therefore go beneath the screen. This then immediately fixes itself as the framerate stabalises. I am not going to try to fix this because when there is a menu beforehand, it will allow time before the players and enemies are placed, meaning that issue should never occur. --- src/Physics.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Physics.cpp b/src/Physics.cpp index a34afb6..a3a2dbc 100644 --- a/src/Physics.cpp +++ b/src/Physics.cpp @@ -19,7 +19,7 @@ void Physics::update(float horizontalVel = 0.f) acc += g; vel += acc * deltatime; - vel = sf::Vector2f(std::min(horizontalVel * deltatime, termVel), std::min(vel.y, termVel)); + vel = sf::Vector2f(std::min(horizontalVel, termVel), std::min(vel.y, termVel)); - pos += vel; + pos += vel * deltatime; } From 3364cb014e54d3b2dbef5520c95e19f18e341af4 Mon Sep 17 00:00:00 2001 From: Gregor Maclaine Date: Wed, 17 Nov 2021 18:13:23 +0000 Subject: [PATCH 05/20] Added control-r to also reset enemies positions --- src/main.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 5e5ae1b..e9c6fd3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -49,7 +49,14 @@ int main() show_hitboxes = !show_hitboxes; else if (event.key.code == sf::Keyboard::R) + { player.pos = sf::Vector2f(500.f, 0.f); + if (sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)) + { + enemies[0].pos = sf::Vector2f(0.f, 210.f); + enemies[1].pos = sf::Vector2f(1800.f, 320.f); + } + } break; case sf::Event::KeyReleased: From 7b0abe9ae134e80c7a585689d8cb6b4cbd1c3348 Mon Sep 17 00:00:00 2001 From: Gregor Maclaine Date: Wed, 8 Dec 2021 16:03:50 +0000 Subject: [PATCH 06/20] TEMP: states --- src/WindowStates/GameState.cpp | 19 +++++++++++++++ src/WindowStates/GameState.hpp | 17 ++++++++++++++ src/WindowStates/MenuState.cpp | 42 ++++++++++++++++++++++++++++++++++ src/WindowStates/MenuState.hpp | 20 ++++++++++++++++ src/WindowStates/State.cpp | 14 ++++++++++++ src/WindowStates/State.hpp | 23 +++++++++++++++++++ src/main.cpp | 33 ++++---------------------- 7 files changed, 140 insertions(+), 28 deletions(-) create mode 100644 src/WindowStates/GameState.cpp create mode 100644 src/WindowStates/GameState.hpp create mode 100644 src/WindowStates/MenuState.cpp create mode 100644 src/WindowStates/MenuState.hpp create mode 100644 src/WindowStates/State.cpp create mode 100644 src/WindowStates/State.hpp diff --git a/src/WindowStates/GameState.cpp b/src/WindowStates/GameState.cpp new file mode 100644 index 0000000..7e1da1a --- /dev/null +++ b/src/WindowStates/GameState.cpp @@ -0,0 +1,19 @@ +#include "GameState.hpp" + +GameState::GameState(sf::RenderWindow& window) : + BaseState { window } +{ +} + +void GameState::handle_event(sf::Event& event) +{ + std::cout << event.key << std::endl; +} + +void GameState::update() +{ +} + +void GameState::show() +{ +} \ No newline at end of file diff --git a/src/WindowStates/GameState.hpp b/src/WindowStates/GameState.hpp new file mode 100644 index 0000000..ad93b87 --- /dev/null +++ b/src/WindowStates/GameState.hpp @@ -0,0 +1,17 @@ +#ifndef GameState_H +#define GameState_H + +#include "State.hpp" + +class GameState : BaseState +{ +private: +public: + GameState(sf::RenderWindow& window); + + void handle_event(sf::Event& event); + void update(); + void show(); +}; + +#endif diff --git a/src/WindowStates/MenuState.cpp b/src/WindowStates/MenuState.cpp new file mode 100644 index 0000000..466d1c6 --- /dev/null +++ b/src/WindowStates/MenuState.cpp @@ -0,0 +1,42 @@ +#include "MenuState.hpp" + +MenuState::MenuState(sf::RenderWindow& window) : + BaseState { window } +{ + Menu menu(window.getSize().x, window.getSize().y); +} + +void MenuState::handle_event(sf::Event& event) +{ + switch (event.type) + { + case sf::Event::Closed: + window.close(); + break; + case sf::Event::MouseButtonPressed: + menu.handleButtonPress(sf::Mouse::getPosition()); + break; + default: + break; + } +} + +void MenuState::update() +{ + if (menu.getSelection(0)) + { + std::cout << "Leave menu" << std::endl; + } + else if (menu.getSelection(2)) + { + window.close(); + } +} + +void MenuState::show() +{ + window.clear(); + + menu.draw(window); + window.display(); +} \ No newline at end of file diff --git a/src/WindowStates/MenuState.hpp b/src/WindowStates/MenuState.hpp new file mode 100644 index 0000000..5649d48 --- /dev/null +++ b/src/WindowStates/MenuState.hpp @@ -0,0 +1,20 @@ +#ifndef MenuState_H +#define MenuState_H + +#include "Menu.hpp" +#include "State.hpp" + +class MenuState : BaseState +{ +protected: + Menu menu; + +public: + MenuState(sf::RenderWindow& window); + + void handle_event(sf::Event& event); + void update(); + void show(); +}; + +#endif diff --git a/src/WindowStates/State.cpp b/src/WindowStates/State.cpp new file mode 100644 index 0000000..6b78dea --- /dev/null +++ b/src/WindowStates/State.cpp @@ -0,0 +1,14 @@ +#include "State.hpp" + +void BaseState::handle_event(sf::Event& event) +{ + std::cout << event.key.code << std::endl; +} + +void BaseState::update() +{ +} + +void BaseState::show() +{ +} \ No newline at end of file diff --git a/src/WindowStates/State.hpp b/src/WindowStates/State.hpp new file mode 100644 index 0000000..fc64328 --- /dev/null +++ b/src/WindowStates/State.hpp @@ -0,0 +1,23 @@ +#ifndef BaseState_H +#define BaseState_H + +/** + * The base state for the finite state machine that defines what + * is shown on the window. It should be inherited by other classes. + */ +class BaseState +{ +protected: + sf::RenderWindow& window; + +public: + BaseState(sf::RenderWindow& _window) : + window { _window } + {} + + void handle_event(sf::Event& event); + void update(); + void show(); +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp index 0494790..7a1b2d7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,7 @@ #include "Menu.hpp" #include "Player.hpp" #include "StaticSprite.hpp" +#include "WindowStates/MenuState.hpp" float deltatime = 0.f; @@ -15,42 +16,18 @@ int main() // Setup our view (camera) sf::View player_view(sf::FloatRect(0, 0, window.getSize().x, window.getSize().y)); - Menu menu(window.getSize().x, window.getSize().y); + MenuState current_state(window); sf::Event event; //menu loop while (window.isOpen()) { - //waits for player to make a choice - while (window.pollEvent(event)) - { - switch (event.type) - { - case sf::Event::Closed: - window.close(); - break; - case sf::Event::MouseButtonPressed: - menu.handleButtonPress(sf::Mouse::getPosition()); - break; - default: - break; - } - } - - if (menu.getSelection(0)) - { - break; - } - else if (menu.getSelection(2)) - { - window.close(); - } + current_state.handle_event(event); - window.clear(); + current_state.update(); - menu.draw(window); - window.display(); + current_state.show(); } bool show_hitboxes = false; From dc2de67824c445425db7dc38c356e196780dbc84 Mon Sep 17 00:00:00 2001 From: Gregor Maclaine Date: Wed, 2 Feb 2022 17:24:21 +0000 Subject: [PATCH 07/20] Edits for Mac installation --- .vscode/c_cpp_properties.json | 3 +-- .vscode/settings.json | 1 - src/Menu.cpp | 4 ---- src/Menu.hpp | 6 +++++- src/Player.hpp | 2 ++ src/WindowStates/GameState.cpp | 2 +- src/WindowStates/MenuState.cpp | 4 ++-- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 0f52086..0e9b377 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -29,8 +29,7 @@ ], "includePath": [ "${workspaceFolder}/src", - "${workspaceFolder}/lib", - "/usr/local/include/**" + "${workspaceFolder}/lib" ], "defines": [ "_DEBUG" diff --git a/.vscode/settings.json b/.vscode/settings.json index 5470b03..241ebdf 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -87,7 +87,6 @@ "typeinfo": "cpp", "variant": "cpp" }, - "terminal.integrated.automationShell.windows": "C:/Program Files/Git/bin/bash.exe", "terminal.integrated.env.windows": { "Path": "C:/mingw32/bin;C:/SFML-2.5.1/bin" }, diff --git a/src/Menu.cpp b/src/Menu.cpp index ab9cb1b..42026a9 100644 --- a/src/Menu.cpp +++ b/src/Menu.cpp @@ -32,10 +32,6 @@ Menu::Menu(float width, float height) } } -Menu::~Menu() -{ -} - void Menu::draw(sf::RenderWindow& window) { //draws the menu options diff --git a/src/Menu.hpp b/src/Menu.hpp index e5dfb91..fce2a9e 100644 --- a/src/Menu.hpp +++ b/src/Menu.hpp @@ -1,3 +1,6 @@ +#ifndef Menu_H +#define Menu_H + #define max_number_of_items 3 class Menu @@ -9,9 +12,10 @@ class Menu public: Menu(float width, float height); - ~Menu(); void draw(sf::RenderWindow& window); void handleButtonPress(sf::Vector2i position_of_mouse); bool getSelection(int choice); }; + +#endif \ No newline at end of file diff --git a/src/Player.hpp b/src/Player.hpp index 640658b..5918d92 100644 --- a/src/Player.hpp +++ b/src/Player.hpp @@ -5,6 +5,8 @@ #include "Sprite.hpp" #include "StaticSprite.hpp" +#include + /** * The main player class that the user controls * diff --git a/src/WindowStates/GameState.cpp b/src/WindowStates/GameState.cpp index 7e1da1a..a9d43e1 100644 --- a/src/WindowStates/GameState.cpp +++ b/src/WindowStates/GameState.cpp @@ -7,7 +7,7 @@ GameState::GameState(sf::RenderWindow& window) : void GameState::handle_event(sf::Event& event) { - std::cout << event.key << std::endl; + std::cout << event.key.code << std::endl; } void GameState::update() diff --git a/src/WindowStates/MenuState.cpp b/src/WindowStates/MenuState.cpp index 466d1c6..fecbfc0 100644 --- a/src/WindowStates/MenuState.cpp +++ b/src/WindowStates/MenuState.cpp @@ -1,9 +1,9 @@ #include "MenuState.hpp" MenuState::MenuState(sf::RenderWindow& window) : - BaseState { window } + BaseState { window }, + menu(window.getSize().x, window.getSize().y) { - Menu menu(window.getSize().x, window.getSize().y); } void MenuState::handle_event(sf::Event& event) From 01f025c4c08d365b53e271662299a10e8525fe84 Mon Sep 17 00:00:00 2001 From: Gregor Maclaine Date: Fri, 4 Feb 2022 10:25:58 +0000 Subject: [PATCH 08/20] Added update function to sprite class --- src/Sprite.cpp | 7 +++++++ src/Sprite.hpp | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/src/Sprite.cpp b/src/Sprite.cpp index 16dc4f6..9fa1d23 100644 --- a/src/Sprite.cpp +++ b/src/Sprite.cpp @@ -17,3 +17,10 @@ void Sprite::draw(sf::RenderWindow& window) { window.draw(sprite); } + +void Sprite::update_sprite(sf::Vector2f pos, sf::Vector2f target_size) +{ + const sf::FloatRect bounds = sprite.getLocalBounds(); + sprite.setScale(target_size.x / bounds.width, target_size.y / bounds.height); + sprite.setPosition(pos); +} diff --git a/src/Sprite.hpp b/src/Sprite.hpp index 783f349..196320f 100644 --- a/src/Sprite.hpp +++ b/src/Sprite.hpp @@ -4,6 +4,8 @@ /** * A class for anything that will show to a screen with a predefined * texture. + * Note: It does not save its position and size, as this is kept by the physics and hitbox classes. + * This is purely for displaying textures. * * @param texture_name The path to the image for the sprite texture * @param start_pos The initial position for the top left of the sprite @@ -17,7 +19,10 @@ class Sprite public: sf::Sprite sprite; Sprite(std::string texture_name, sf::Vector2f start_pos, sf::Vector2f target_size); + Sprite() {}; + void draw(sf::RenderWindow& window); + void update_sprite(sf::Vector2f pos, sf::Vector2f target_size); }; #endif \ No newline at end of file From 9acd164df78d4b6724302dbe7fab51b818da5eb1 Mon Sep 17 00:00:00 2001 From: Gregor Maclaine Date: Fri, 4 Feb 2022 10:26:30 +0000 Subject: [PATCH 09/20] Updates to vscode settings --- .vscode/settings.json | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 241ebdf..7de2f21 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -85,7 +85,28 @@ "streambuf": "cpp", "thread": "cpp", "typeinfo": "cpp", - "variant": "cpp" + "variant": "cpp", + "__bit_reference": "cpp", + "__bits": "cpp", + "__config": "cpp", + "__debug": "cpp", + "__errc": "cpp", + "__functional_base": "cpp", + "__hash_table": "cpp", + "__locale": "cpp", + "__mutex_base": "cpp", + "__node_handle": "cpp", + "__nullptr": "cpp", + "__split_buffer": "cpp", + "__string": "cpp", + "__threading_support": "cpp", + "__tree": "cpp", + "__tuple": "cpp", + "bit": "cpp", + "complex": "cpp", + "ios": "cpp", + "locale": "cpp", + "stack": "cpp" }, "terminal.integrated.env.windows": { "Path": "C:/mingw32/bin;C:/SFML-2.5.1/bin" From c420b6811479bf1b39fdb0b43702e154dae272c6 Mon Sep 17 00:00:00 2001 From: Gregor Maclaine Date: Fri, 4 Feb 2022 10:26:43 +0000 Subject: [PATCH 10/20] TMP: Added main functionality of menu buttons and finite state machine This is a temporary commit, as currently the user stays in the menu stage and can't progress to the game due to the buttons not being fully functional. --- assets/button-background.png | Bin 0 -> 50972 bytes src/Menu.cpp | 64 ----------------------------- src/Menu.hpp | 21 ---------- src/Menu/Button.cpp | 71 +++++++++++++++++++++++++++++++++ src/Menu/Button.hpp | 27 +++++++++++++ src/Menu/Menu.cpp | 34 ++++++++++++++++ src/Menu/Menu.hpp | 19 +++++++++ src/WindowStates/GameState.cpp | 2 +- src/WindowStates/MenuState.cpp | 23 ++++++----- src/WindowStates/MenuState.hpp | 2 +- src/main.cpp | 17 ++++---- 11 files changed, 177 insertions(+), 103 deletions(-) create mode 100644 assets/button-background.png delete mode 100644 src/Menu.cpp delete mode 100644 src/Menu.hpp create mode 100644 src/Menu/Button.cpp create mode 100644 src/Menu/Button.hpp create mode 100644 src/Menu/Menu.cpp create mode 100644 src/Menu/Menu.hpp diff --git a/assets/button-background.png b/assets/button-background.png new file mode 100644 index 0000000000000000000000000000000000000000..7aab5957c3462ceb5d0e96c1a29902ebc913e384 GIT binary patch literal 50972 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
oXHEJi5K8`sDMSPVZp zvKvocx^F5oGp<%=cm&j0N+}Q{9BOwd`%ONM)-4YjWc-HIG(Pr^ydva8lAHr|?UiOY z(rS(GyG6)*2&;$88boj&_cQJWf3|wW)-N@WepwjRLM8ODQ|aPEC@*=EbODpG?Ean& zOoALBAK;rCYzoT}2ofcp0Z6}~=!zl;Bn?hW|0%+8)=PBd{CKm4L6Z723s0~Gbg$LUKC#8p>=rnh4BRdgwE!=8S>cZ-v=UHDXNw^1#1 z2(Yhc-;6(>|E*AwkeNSfF*!>ND&WEjJkn^Mp&4KO(WnryxUp%-;_CKXra9$#&-<~b zlGq+SLNfdB*57aT7k>=xThv;DIGS7ZVZ zd{k1Ne9bGw3>L%g?)+{dyo<5cns07P(qt7tiN}WcW=P#tN@L;fwKyr68;GJrZguT-u|I`BFFFVI zm4NBrH~_k)VFlw1k?SI`B(QnmQ#A=UFYXswx1=s@R;6h3HiW3t zrRXJ34w<}j<&d~f4mkO}`A!UOu2uNs`@5PGXYtQ)G0weZ=J_T|2NfTP0=)r5@?4zoXA8}yK-<;T z%z@00?(Upf5<7!dJ4y{Pr;+O~0>|#i|7^@`{BP=CHLggsNWTLJDWvBV3jJ;Ii|jmI zg!xUG>CkU4{9<-PEh?#eY?+!B>!EiSKG({dAn_5u1kN|OUS_%M=t>e4ablI)k)=!p|2X4z@N_o-dX(0|5 zhhTJEC3-D&Df@W(%~yX6CDbDPQ(%exzBbMdeknSbTl`dG7afi&Z2 z*fl-=%WAgpFa0DBSS%)rmK^!0ELVl1M2fuc_OW5-dT;qk=M=01r}K1SZF@8vBpVsw za=wDWWxWK-l^kfIY$@3}Xu?)Y*{na(bepi@Q>alXjjQ-_dDsMajsv{m!M^bhTp)35 z#e;48w{ZI5Ko|!tNJB9%GKj8%S>Ak##3g?Ok&2Qt(kiSLSo8H}KZI11l}X3NmTX@2 zd09cUAhGa{xQ5PD3;^0pE~3#}=z_r916r4@h+`->shp zB9EE8R;!yG^@zXx%u7$tY!M81nxvQ1iiPNl#q=Vfkf3a%C#G!K zW^3~mgbz!~p%T7$rGR7ggr!+-u~8{8_>Z^ag~1Jm$vnXjKS?P$m#8r`DjmfH5`J>jdOtDZkxo;?-{}1he3( z3U7GP(xJ}NS3J*Hr!slNGK;G3pR}?M-H0-M9xVUah|{?Gu&4yFrOpj1ti*-`{;Q#| z$pWcqfW?4*ZFkj#1CiCwZ^D8oO*HTh#4{B-MM~h8aUT8}_jDr9P9T5Ub!A__r|pts zx%=obWx1z7;DTq#{hN`eUF=7`u{wrEu#qYO%Ynz3g*B62zi<)JEvt(P8+B*?o(ZJw zSaOA?budeWJqQ*HCg7d1(|Z@C7JKF&FOGLY)e#rqgwwtanFl+juxC*yDpAUW4wgy4H{zXdfphkK#Cr z!1#Ttw;<`Q=&0|6!A1JtMHUb-@l|5(VEudF)UK+#Por8S;QGxX9GlG5BXQRqTBjQByOQ=-A%{&6pLc(lz^r$5lPB6t= z{dge8Z4Z@b_?W}}xx&*?%^;Nu4u!82{uvm5O@$V;M{f{cfc$4XiUM9@>B1!bKuijp zFR-Uk!YGI$;kp|AN2g9yD*ZfIBHl(K?PEX_H3msUL^m+~LPB}x<>!(N%dYsKzb<1A zMV%RiL?4FpGF=qXw*#+Q1W38i1g?0g?-#veV#Ib^NBK4@MOG0U2!W_y#OWxCq=mm{ zaYbrlXMi?0rb^H#D~PfY%nSzvC1GL|N8zu3NzG9zG`IM!z8q`+b^+Hel9+_0RMo#f z_kQz{K5emT%jT7d3)vs-VA{38a2{n!uBSP94ArMDNVTb|p%;7bEh)U=M6-SSL>h)r zF{0>lY`(Gzkq97nE}S)2i|(XfNFPz1)3MnNZtyoa9znf@+#*1!0|kZBlVXVVr*f!M zPjkeJ&3pQBT<{?<+P&4M$P;s_B>%ERz9n0)38aawCmVX5UixPuG4Zp2cL5jr!X5_l z;CRpTV(B+mLt2|zdMDd4qfAUoC*??T&S8ak>yF-=@Tp~a^=!XB$xR@qT%>I34_mu! z613j>)!&3BQj`kFSZ;~2slU;Wp&k=&OcMI>m!;VlzP6B6-wI@I814}vP(iFT=H>9* z3)22IC~yvChLgF_6lkYG%0#J$x)Ca*<@)uLG(i^-v6A|O(YC*FhFi$AO$Qsg>QA>4 zs+Vh<2Yhc_KcP4J+#1O(TzLjPZz-GGG8pBQDMgv#o7F_S}@o1vqrlS2r7@ExpEqPXr>mkfFB)RKO-+vo9h$eA2Hl)&&i+wl_+@x3CNUqxHCt+M;{Hh9r+tn5Q$K`6L zBE6dT`C6V(kr7=8xD6yv5jIWLb~;dArR|gpOn#ZfWpfvR*WV>{=n4%Dx{tlEIM=QNrB1~@@Czg%4L=VN--?DpVVKx3}2;(g2E9uEz0-t zZ0Te_{%P;zaxgvGwM!g9!>G!ZVr&HhRk)u6ls5hh8G)uZI6w?L%iQg;z3-8{?KoNC zWU%d4W+*aJy^QOVnXK|>%@5aaJX`qb*d-;=v;3k4ZL>LaCs|BB?lx4t7trUl{+^o7 zb<{FoNP0u*^(!@Lm{RcGPjI;L!@JQff2r&Ip~SB(XKDwj)U3IM01^c=Vqu?I)P3Fv;!rhh(OYf&j5wM^%l^fH0i1)Y0mO zZH&f}(Srzh%PUKff(=w6>D?;8`}im-D6R6O^rel{uR*!DxYcuPkamzWqbF)@TTiQV z#x(caG+r?|Tj>UlpE?=Jo1q;JxSp39fo7UR^n)XN2|Tq^x^PYc^;JLYg#Vz#*3>Y| z>|{Q591U`S5aB%HOL2M_*9zFFu>z$>X)X;WRmDZ&vv3O^`la=9k0bOBn+&2+Pi(fe z`}?%HegDIs)=|$WIy!bG3DC_#(LLfVgw^l%^)U>F0_4t4UM2Ti^zJTsM5Mb#Y}koM z`3Fa(?9f>j!1}0gpm?;y`^1gCiJL=Hg$W@?Wtmc8VNEvKnZ^{3DzOD_5+VNKU19)u zVSim#M`gr7a%fCwdS678uE05qkzZeDcwA1zUu%287)eM1cN?i|!h&*nbww52o&;QO zf?fE>x^b%CBA!dmKITbV6RF&uW=L{i!chAn(QZOLqYMHac`yKjG8mZWjt-1wjX)Ac z$)BVPo6*@IdYZ~u&$y3$3Ou@7RcOEA0fQ^wzmggrmTVFTYF-&Z=F%vC{muPBN612# zx$}#0vrwu^C!FPfJVW1;$Xg z3Kw|@8KmAmp#1)O;%WWU<#K=uOCg4`s0r5i}xjRI9iB#;Scpi4Eg|a{HQMH7=RiZ`ES(NLZj0q2>y=$5qnH&x=Lv=lmZq* z>~q)|>hL07!_^Jf^`_u0&5f7WW(K4I4x6dbdYY78dK5^{Lq;S?!Tj-Y`3^Th<~lIa zgJJZ|Szi>RKR|<3G7=7-JzJxYc?t!GT=K6n!(o_=85|5dz~+-z9RCtXL=Liw4UnS`Oq+=;o>$u&-mk zLt$GWs@nLw`uG*SYr+Jni{j9j{!x9KS3oHx(!;PU>Jf#);=qj@34f_!y9OiHqIW*n z+uNgu7?BYgZ$Zn>xThrZXZGudEVx*`1k&V^V)nZDuH=cf8jiBz(cJhK(i-)DWkj-T#&5QvB`yZy(;>)lp>dkmc)yBIRy>|(I2s}7T>2}eK#X^zAmh{ z7PK_KET4gh#;rFCt*8Wi8}-t8W=ujwpUoX#u;ijd9`mh3*1EyZeoD3oa%o+G!?Z9T z^$SYcs}YE5oeShiAz}G46e7}~g2+SJ}q8a&Ai5k^@DZqFx#UBq~9b0=rmL3G9iVULn|oUEb! zdAKNi)|2hvG`CrcLhGL^OXlSe{JHqBdY#0b8e2(I9s8NB-0t;V)~mQSmFc5D2qC}k znu`X3x{nL2=gjM{^_}V=X`v-=ij(` z?MG%W1wn#|F1_de$RD2t{5)YrZX18w{O*He|hI=wjR9H=`5O`1Z~xEKJ4%9{_fU&l~baSu>nGUC*Sz zjMn}5lqD#>{oA-ODl<5HRvkUAegWSz`RNEJHM-uB6jnvSQ%ZMFcrI14JkDyjW9r=; zgKRk|uSg~vJBkUxJxbX#_i<|-Eld{eD$-p|_$v~BZ2G3es;gLQ{PLA4Yk^dBj?}O% zSh-(lDA`0r630(~AVT`v{H5*%|Kys%k39|u(rCW|F_;P%Y`aDIeQR`;qT-ooj80K0)rm8wQqi3q>x5 zBmT<{OL=7YIr!qnES*nNu}EZr&w7?<9CSCiEaK1f3}zC4SH<9vA)%mbLw0JjvR>AG zgi>89Br2A6>{#ziq2`p?vW5QrjiL_AIfhwo6&Y+LA%_%hwS`k?YNh zuNxR(%i9F-xBUT@ZK45)qrB@9>9zYth-eMz=k(SBF0kY8=@|LSofXn4OQ9Dt_9Eqj z-H>-gJRM~U$Zb_x4B*CA(H(AR^pUkGzSj|vN)t{BBEC-?cIk%}#XXE_T&j!hF$nwLzOHFG(-^V zcW%lW*q1K>tVYF(uc<5~Sb&J8(&6^3%JXHQ1q{EDowIP^twLhZ3AR+9B(Kks?sr9w z^%0@ie>=_UF_=qDaFpwjMyK!TWO8{R<8HLg=kTk}uen}sku0L^s_{O=3me~8MEO74 zaYgv2hSvOJjXEndFzP<<1p`HddXEO(Y-(>ePri;T&DZ$uzvcP9B#H2QaT-J+fgbxjTqka?Pos@dOYp}unGtV z(}F|*S?B7>7!*whV@djJCh!ZYC3QY#ZLT=(vVPD0TmglHsrlH`Xc9}7Qi>izMrD@K z*V7Q=O5>C=%Qknd%EPN!5?s=VV+Ll~7+}~hJz9UKRaZL+65H7p}ehR)q)5t{Ql5g$V8(l!;CEK-Y+`W%M zl07xatY5d-r~O;^)L*|ALWtPJI$ZLM5XzOuvRZ6LRz2z6Lob?0`@oe>=l2#2%VzMM zgicJPxI_25sA=hZgdJdkIX^gF;MFIh*3Lt~`17tFYrfd@pyv3=&!4B`AVyK**>hi* zAK^nyw5O_(mN9+`zyM)Zf?~3dPi00iV^44Qt_Co&0J@nxIkuVEy)P4Yv5VfwnUJfx zmWs*r45;)S$FqcOc+u?s^CG;-pn0VktX!H8|&W8po zd1L=u$=D12$ zkRPVb1C34hpw6qCLeR(of;XBB>@U?b`S1fTv71G4ql{^CF-Ug#YV6`~#ONKaw~gP3 z8k?UjA59yG3aJ?Huu}l$6wza%mV_n5&dJdyvz$j8AGOLhp`E9G^9UUSLf|ATlYoR* z*7fDfnj`g6ybWOy4t49o6h1~SuB)j-W2)jJru*kDtU zL^kR6+x@FEZ=q6ZpxUG*kYK{Z%-wh@(tt0`}syZbu9P31-9Zke>QA3xT}( z)dYo={mDdU1P8xjR_~#CQbfprCmesoIav_B1NdDSMX?H4pS4JePH15qH8~B3XvL4r zJ$=;U(7sfa2oeNuR#O%i>s9V1v9nD$N;gR|PJR`u4?(tgft6c4kXD*iV9n=C=OnL? zJi}qF^+wl|ef9p)H;K}J`_Ebj;Z-pEhr@pJSc88DE4Z8iQAn^_#isEZ@3}GSf2xeg}!isIoDl$t^c^8nv zwS0>sa8Jc_b|-krs&l?^e6W1Oa;w+#iB$dTXt^UsD6J6`#w$8He0`r%7}_CfWu@>p zZhL6eM!uVnZPCQ$zh|1c61kE z=1v*b(~iAMC@wb16+Z3$>#LY`Jn8uZ!lL1K1+bLZ5l!+}Tl z5p6>!R+(=wl(rtlRn3AGb%>1d4&Y=|lJgHG& zbt5rDytgy1c*4B5TT;y}HABG1qgwssBiRjr>~7YpUFZ7RiJ8w-y=(>_Cgb*IG;`3N zlvEC&5iCky;s8M|NX!%-OfK9(zBNQ`UBQ?uU{J~M3T()Zo|{SgvBqy7Rbv^q0F&14 zD;vM&$Jel`3}O@>%OW#X?=_EqAuNp=3q06wsBPL8^J2meuy*JF;~FUHR7eDqrlKRg znJ@`w+{s$ZFdU+JqGI@^#ILOUrZ0~qJL;eq_E~Yf5y^dsbk3nXAC0{NGoH>1k`^1p z!#hjbuIVP+M?UdxOi&a{AF|P@teqPFac?r}NVG<(s&El(B7-=6-toX9=7n%9{C2w? z<7M>sQWY%9bZ==XD;Rax-gi_Zpqr$7;F9pFhDl7xbuDf|G8ARObv|j|Q?kgu)7>fm zA*hN-F;E{TU$dY}dVl908Gu$7%caQQ>zam%1XpC!z3t8&>gc4G9bm}>C8bIhCpc91C^QEh|=)ZEcvMq9eb0 zO>y`Xm)GCv7mn-4@hJi)dqMJdU*UF_I zuA|9rc<|u^>%_q!<5$2x>9&i9z){ajyauNuj(My8dXGD=;mD_)$TL*0<2@H=$BZ<$ zVtVh{>G4bgNDkmIWeJhBY`|r~OL}Jkx4|LI6W_$h{(YR_SwUN};2F)W(s|>>>f-vd zHq{`C6MNkC)U}*T7Jl@QezcL(#@F$p?P~c}3DO8cTnVWVRp?s^soC3~CEAucvGJ`= zj>0n7pg7W3P`EP1AGm}O=7%9y3S}MKkz6v%DA4C&vmxbzR()N6^xM(#aSWYPJxEWr zx-G#+%H>fB!P|G9yJSx<9kkfiBeK|bcb(O~Vq%=)SCz3QMyt^Jm@(mn&`Ba{NR0CL z{aS?q3hQ?n)e0A&PHqNQZ@{Ujt*wHap9Y>4$DO5A^c(c2fR9l5x+BU_Tdla$B2{J`&3LvBwBwtVTy__Gtf;#1lEzL1Ny7| zkK~JYyz#mY59&<#7EV}Z3oK18VS0*?hW|+;NyLktVv=;@WlR{*nEUguNuLj#9|gzR z94d4uJxU9tMxE+mEJlf(J!Gd8^gXVXpQvlv5%H> zRE>>+M8&bnQQbl!FDuOu^rbi6iFvpeWc@xMKcOnSU2C)DMZj|8_+4Wxsiex&K0)ZD zEMFGI5DF(QIww41o8}f!+k8)wfb&+Lr#NCTMayY@fDDYVk{m3(i#Q_3sehPP975q9 zB2SmmB1i>*;{qHZ{c<+MHtG|gwKOM4@zV=VQn*ZYVZ8-9?z0T)pi(DNw3sZa4-!GI zeIJTP(zq;dFau`^ob2Xb7U66dVnhWGg^VJK5QlJ6oWH4Wi}sSSJ(t(0MI!=^dOIlH zNC_jSLR0hjkcx(_qB(I$+FBLhlLR~I$rz>~^$8M9l0OsUG)p+?InD|}f>@P-BYx*& zZ}O1h;_q`wviXd7kZu?Wlas~(oohkfOitYd;qc&h@`&d8*gvdWdir-ThG_n&;8Wz0 z3Q#GU=$bE*OU4}R>;t8PSeZ@wTwAhD&5WuEt_~LsoCHi14iw0mYGh?5n~bW?Uj&OW zM=y8Uyy)w(MA{y)?_60frGpa)X}(L zbM}L!weu;iQrFT3S1cs}f;;OT=xN_F zo{81-YfJ|AJh)jD^9&XI8>UJ;aqms0!AP`XD=vdZ;gAL1t<}IMrL)@-JPXyf_MSXD zcXwn&#hH-v*@!e6JV9$Ro}Yn?SU`g}X|MtP!&sb=KTt~GYQFwg|0)8s!1MBtv45$K zsHU&`(b#@0rPaJ>j|VT&e9C{rRs08}1;=&mp4_3D^5Rw5LpP2E@mX2BVj2D%`^xP)v~|xae21amL1YPQ7|rf-E%$3u5(L9Pi>5g4aqP zq!_!8!#9rtC*wNEk*FB7A@s+UKFJ+|z(?%idgp6$TgSFvm&3~gId{t1ckUGYUn!`< z^~|qwS7uiN;$FM@TiPd}BEhPbpq|aK491WCso7m6u&}V_(sQX?IbX-cUFqmzi%?)# zdV0J%v(I?MUOql*>pW$pz)Y6itg-Cds9HNek83PS9^J~-5;j{H5k4YUt zGIeYfhA3K=$XQ*~zC~{?f4>e=lBP?Y^idXiFHFWaZUtLE*OYK5{K8c(gRL%^4F!gd zgari%z0FK6;(~N?@Rlt&F5&VZyG!evep8sSyOXD{BZT~~ka8{E{n>HIyaHab zZq_gF3Usa;{RXz(>F*ZMRE_4wO;S=VwMNXBL_y)nsiY_fR5jl{_GS-q&<1@T+aYA} zd7-g^JS%=3;M@e2_ghc3M-Ty5W{Sa7x9du?i>rVLHQ*o@er0OS@%(bb>sS|B^6SZ7 zH{Q)QJf~c&&z&nXw)~gr?I3mt$&D>`% z8=)&2PW@Y?4nG`Bi=?6|5+&tQ1@y64h{{9BUxPMr`Ne_%(j{@N1tJO5W6_0Wbb)98 zloEdPhJ&SySVdy1TbpK~v*=#|I7wP8Te14A~QQ{g$Ya`?iKfnOC$7~Bt! zkyCK4sexTZXcm~Iz+M*y$TmR#;kYrp;BrMN())321?P|JwrE!p%>fw|ibLwXS8`v} zk-Vj93I*RBR;t~6#-GgO{V_h^1$`!g^qduP<{e(EN;#d%{M;9yPTI!`NDgO-`p9&Y zq;+9<5CQON;a8_!0H{4GmFqw6)nh|gSr!x)IAv@SgNSV0e*E58Wn4!W^HOK3hl@Jd zgWIy9zcszO$?>4<7hee9*%Po6Vx#J&^uvZXo7=UKh8W^i#Yno(cW*N3R-MBqR z51wp;oN@L%Y`%0xx&ZyqWoNn*y0vp5njBf)rdWsnz0 zcrG_O(lT=!MIA7>>AUouUMkX_C&BGpI!WJesl5U%m~Ue?JzgPz5c~?*J)TeFL%uP5 zO5d3P6pj$0QK5Q~g%sk4&Wfvs2O5A(g0$KRee;@>PQUVkUUnBagb}<^9r;E4k2}j4ce&lvDUC18Z9K|*kBP$5Q)`-@F!C^bQ=4h zW(RJlYB_c|Fi%QM63^Etw{wOUG z|AxvxujOE5-_y7)B|g27`!h&}F(De6ux|kTe@(pwTb#?%HJk(|1b27W5MXeJ;5N9s zLvV-Smf$jYumJ{lhY&2dySuylH~V?dKIfYsFjsZm)vK$ktJWfD;zE%<)!pZb<6QPk z!JKS(V-Tiv{UJW z)5^c+Zm9M;xTD(K)#F9pLjn8IGuQ05iWpT0hZZ75;2{OtMxfL+JkrH?QF`R4ucXYF z6x7tp5kYamk_+l7rg1yp?SS#b;y5Lbk4u^Ul@_C2-O#a~=G)c1ATF8 z3Wu1RoVN=y(_Ov%-a69QyKD$#|IVjQ7F;QO_c0)*^N7y>L;7@$D8kKPN?-m*TxP8* zqplzxVtr_*ne1yRNa2J+KGWJtlgr&bCp|u$AgTZt<%*1C>GSjv7sh<2??Arg7$QY| zoMzyNHv&ZRBSNER)qnm3&QSnzLNFpthLMpn?iyuy%;2_@)_$*;O(gLSN=|9K1UVT{jC#Y8 zJ!aOeJ*`HtS39-FXAKOS$L`Bmv%RP5yq6A{T^6URrOhK8T$F`lD^^F5$;Xfe&=TJN z^F5p+y9H)E(%zXrS<8~j3>S0|MLT`c%$*EF+F4yJ6yWZKzNwO;EP=jvaO;z4IPv8Z z?AAoS^k0jtRc*{N$u6CLJvQ-04qd&Xq9Wo+kRxa=YQ`JJ53NFIUACVxG3EFOn^_8~ zCwmuyeqPaM&#l+?M&bWgG+i`Fz6Lj_{{Q)$*%L;k0I~cC9fP#}1vU4~`VI=6=&@5l zMeFJ|nJ%s;q-W4#rDZMT;3;O1q5USLq8o-*7G)v7-bZ3h5*=*@nR@c54Cncu@ArRe z%jmA8R!jqwv%Bc6Ew3L&(GQ-y;&R(okuGxOStk>z3^8gDw`+Gm1sxhB{cOk~kY(R{ z<3SD~pOh4CYztB*-IjW`|9Jd003L(DoVt-PJ?b{3%qEh75?M9(P%t(}sCO8VVtnoN zLG5j}b7bs!=nZoOfy_(_p_qykovF1*!0G?u32M)}Pbe@;EH0Z|koLV3Ii%R77|KC# zKkufuvTT&QH=*lz<=kmmzi@GFUEqCoMWq(qe9)SUU(~Kq6IcH4itb=*O?JI8GYpJ)8Pj42GX&P83U6-nv+4;n(si`Tmy6AB5)L~?o;1XI?{l8tmM)Wna4_HO@n2)Y;plR83+y^-kfk4^=CQA2~jHl}^HBx0}6I^`r z+82Ls`x4K8y^Gt%(R29SY~(fRVN29Wg97ZTAlK@s^?*!qx$)%l%v??vW*%lyG*4`% zs@_&~BmyM``1$d3!hf9_#Dkn7sF~N_6Xlifrdbbi^Rz6}ux(p%_In62d>k^|N_`El z+{_Xo{+foQf-){qbsT3Q3H!c!I*o!*g=G6newvs*8=cjE!tQ)G*N&g7&RPWB3E%iu z?+1_Rh2b%Ahl`zuqe@l)srNZ$n0O@b3OyxOCEw?AIa;kqJpzn!Ta%@U<>g=g3RzDU z|65nJgzd9>- zd;}zbU)cOPOEi&to&yzOB`}5#34)>uz`A~DjAfd(dY1E>|Aijk%JXv7Z-d*&!5K=z zVKan{23r!=t%9@eRy*?!v%v#`X-hNY5hD>P5d}M*%<+6YNpw+#bDn6qd#9%{pGY-I zckKRyg&$XeQf}AdRUcdytfmG1WPikubHhdhGd|5&h_Bs!q1aTn8Mc%Ei2CZu*)7&n zmhT*uC;}x3(r^1detthd#eD19Dm~6`vK6mGZoo!o`R_OA>*{6cIu#)rkI;==Rk|jy^F1W-^cQ|jGWhnoE_np2Vq&1s)e%q%Gc+d@UhO1UAepC`&bMA0y?v2 zH#s4CB)%XeYOgX<$vb5j#m`7s;_|cs8W&^M-oyOV8OuN8j*lX{wR^sM*KQonz)jn} zrW!sF8otd45Ar*9zdg%!%Ddf0;M)!p+eA@D{}1S?axq24Soh_kl0L*lq?><$M+A(t zg_nc||CMNIi!xr=7J6)v7s27&x;;#XYH%++q@=QCUyZ$N1u*iqH`uOv-~Nau4T<;= z#XrjVFP7l8y+0@9;4-m!h>ZHxvt2#8Y^IOZ?Tq3lqZYqDp6}{8toeaMkz{#m{OhzT zt#jj&u|-J7-t#lZ=>V2QuH)_UiLTy?v5E?u6LQVzfUTUd-mtDKHL{R4$Pz zHG-Uj8E&d`UPV!Y2Q$(v(S1qDD@)A+GKEjYOSNmXg+O+1Pt!*%dcA!{^{+4sWNcEU z(9s+ywEjgIo_M48)CoJz7ui^n91=BM`l_Q9vJN)|1|0QH=~DxgTi2vuUezy|2gZ{N2s(Aqq@_&Gm8FfD16l$ zI0t(YuQCcK6Ff9y2`BRn|G>Wr3LTJ<{A(-KI+Btx#B>PxLv4~~ru_vdunOJ5I|oyi zdcMyTfX2++e-9g?aJtt1wx(y$$t{X^Y+gt90B>gBm*?|KOJ^J3J{r|u06G$I_{u)nl*##KU?{m|X_^upi z1J&D*l1qiVmU1M*B!$1PUzb#vck6MN*FKE(j$>ZtQ|&g_X4CXO#ZXfp^|&+enVf(WRWd z-e|nCxk#> z-Iw;xBPi$nh<7{KUKiR<88Yp5dwS}i^Wt;g5gg6Xr%6Xt@aYY0??ec3V>_SD*t<^9 zqBXzYLYH8w0Z{IFx8mV-RNi>Mov7sb_JURdK?XYWU`Cx}-)c^OV|@%qhfT$Dq$Ooi$a%_#C8m#pw0DFjDBc+$mB_pWc`26KxzhCm_)joKT=^@-@-#tGMei-HL;g?7@ zipQsF@4Z+gXpq6s7*%^h4o4ST*I@P$**bPPYrREnJd%H3B=N&mz^E^s@;s@=XJZR$SPITM6F_h!71;Njsx zZ)Hg*?*E)*7E1i{3LuQeGeVRNqmkDcviZ+jeVh* z_JVS|<7rj`0@@0#9Utze(7c{+dCB}P?cGbse)o)n(miAh_~|9*em~@MDY*2y>t9`? zJtIQ3bcCZTN&L+vTE*Q6tJ0eTLGj*TDfy74C8ChOt!I9L^EcB>V>fO?O0V6*14TJ) zn-9^k3p_kf`l^VEaP*8i#eC`pA{s0nRU>AfYOv9)nmP`}Ex8!khr`|a%Crrbn- zMTy`Qb>T5ENRokcQRqz_-imVuE^cmc)m^0)-g8R9uH;TB@Q*`yWYq>b*W_4nG&zf4k)CIh7D{ONQ04eSUF-Q^EcO$D0BFS)84Kj&|zGeBI78G5y*` z2#wM!4m{_f&|;0nBtebv0Mf~iFe$U3bbD=ym-jp?${;qTF4I^Z-YsatZr!7{RP+a5 zodMPCqd!bU;Kt!cJV-k16Pa4`BGI9KjPJ0GG>AokiuQdDl(VG z=F;h!WBWx>NOM49=rdB1Z^h(KFf|Exb`<_2)g(^!1##tU33L@eW$xJ{IF!v7H5F4)Oz5cU+k-f3M zAlz6qsH!{<21Y6pl!nt|a+?(vjcXlnY5ByMJwLZfV)vLKEINm@2Z)bM+W;Z>0)(jWGIzWrdNO zV2|nSEke~Jvc_W+D7_b(3-=R4U0m<$g#qlP8>ay$O&}8vv$}%(*rftRPTgg{`3~c| zDB7vk0wdBVqBgL01m^q+R1z5Jg$0627f+879|sd`%)vt=sa@%=XRvyCO7<-NT-bSS zc=faMVd;7F%s2QX)jtG1q~d4Kc#zj3cb;nXQdX`_W{$ArBey;*pB{h#&@&$lcY8ug z5`+j+ZCUxKbKDVuFMQ;3<6O&2y5(ppK zYW)ir)^_{_rRy_AQ%Cd8t%mb=_4O1hbE5&gZ=?e7#hh{c>D>C~T@L7THT?Yf5JrRg zC;15Ypk$xS?Kjh;v`216ZL0T3TWbdo*Xa_Nv~afMPTelpkU0_eu#E4xoXrw(s?kZt z<9uh)zv_fZ*L#~wG!~Qyu0~kA`$<1`G>lPCfRDUgqrpUe16Q#PSm;OSsX^H`XtP_HLG&@-w~>J9vzDiJoRXF1{D~2N%2V(5 z+;hmmnkr}L(MT6aA=8vN60ufRESw5t)N*nY#STP$9Xom5X`&2A;w5Ir~b--Tet^bGdDt-xaqbHH!pP~N8b1C*YE8M>Ga_~tCE#^L`V=|eugw&WS=PW z=qjYW`{_&CPuL*dwyXO^aP|6Q0Y;kfLkp&5{-Hx&&p6)pYVLz);h9GW`2(mfBBTUu zvc$-JEacKSY-X+WHYat zC#4kw)FPli6jDj9nqqN3HBZ_&^fPO6t`ujaBlk#+y9lCT$HN30 z_@4wa_U}5 zw2oTDY=5l;yHum>TXmgWyt>Gqo?h97U&G(vUjG>0vqkP|RoaT}PnL0=m2PXNo0Tha zkP5DjbFt+3UXzTH*+&|WSsYm}36lBVzl}?M8?9b-I9SxpgFBo_A9wS@IPna^R|p0} zm=-expWs_wV`d(3Zz4kf?fzgf29>=7|erQKeOQ)?)L&ln#&S~ zZS030nHfF>3&kwC>NW>!`GFX8n28S>=#AUj5i(o@{)!P1x5WkU{oU?K$hd!)SvV8s zoo8(Y6|aW%(hH1oixE}23Y0jV6-q>_Whi8WbQ52&55g*h>{}DF+CsM}Cx}xgETEqT^9)&ZTg?R7OjDtw{brxE z)b$JuC+g<@;omHX&{fn%2~q#5z5ydM#nDUF&*2!tP>%m3e=0U=)5Eco`o|#?Sh_(N z)m=bEi96}-K%EyGT^pI{G1U`@P8-VLC^L5hZ3kQ_0-Ca=Nkf)V)m*Pf~|6huDcuJlt4bv_{9?b?C#> z9B@4k4`49JZTvRIOqi0KOlvR^h%vR1dRGW4YH1GA(4j(BSI`&qZyXzw#sI<>vR%M3 z{~Vxr;-bIqXzE09;)tX^z~^}~%UN*X0TC#;482x#?fGmkoZ3Hj6rK4vII6ZhO+4sA z$5o)IrJMfPDO&h#xcbR~m@IGK{FJN5@u=X@pv#T(Sejv>x=qg|VdyVRsVuKD=FAuN z#m~MtML?8EB_1t3mW*5{yiTf6(7ttVAfLp;y?^I~Yw3}r ze)^hz(MPMD&<_X^v+@D{xLbYrUyJ6K?mS#UMSEP<`e$z7ayfnVjrD(}qT7&P(NGNxR!_Dhx9?G-ky?Vyv>H`B z`houmc>(`-OSVFLkQLPOG6gTw`lP8@3J}hgQ5&5sbrexbt5oTxvZrm(R*~2aY$WML1xwIl6k9D5HrD^=kT%j-rJ0{? zSNG9Zr=c_d`;oM^%-3&It9^AmrC0s1NlWw*$oAM~E@5s*Uz)@&Nm?L-Q7Re+nPiTx z=}7X!kfey=h`?Ua2WKy$no0AtI*N#9U-C<@ffDeyUqPP^8bxv}F1>z#R`dDYdx9;J zXLdI3TE4P^vL}X7B8|kKh1<2MC)N+L5AJP_V(85RN;F|giiNPpnT1=?qVbaK^pV?x z04UPf6jAw&-lr$kFwUt;N1#b4pMlfUyL`&fwy%x}(+pSm915tMUT6>c>5hOd6irQN zF{pvlJ8;A%{7P)CE~Lt`aHjZGrj8@Il!C1CN_yFq#NO(_9Bw8(j-_1j@B(aUA%ipY z)|a8Tk2bm2P0f8IY#}{{w%TUw+XC5jcLX#J*_2G2elnMqCDhVLHkn1(#NT^54orJ! zMam=@iYZ0ZFq^3Np~D;#T0x&=lA<%|W< z-xL*;3zT!)Mg+COvrF-LjP;d5 zm78s-XIUkv8w75-aN()E(>+T`JPlY>OUO3}F^n}U<2AAd;$R$?zAWoCw%r_K_*vcGZzcHc$Vqg#{`oFNM92JAc1J`_@*huz9OCG%v+!6&gFk9#DmFW~EK{N4s5X zH*cFqBurt8C%An@=vj7@uUT}@bR_yaZ8SX7C9IZE`n=+;bm~t`j{tt`UWi)E^j_Hb zvCDc+_FR_WmFvqB`s~&pCW$m2TFZF1gV9vKhOS0D+ zDz=?~jKT6t(P?xKn4UYDzlbGoG3djq+Yh;r;&@?W_#~9j!MudZ@Ye*<#9=o;6}e=2 zx1$&U@pU!{^F42-D;od2kKDU=9}HE7aB$z`1QnU}yV&-+qxr|MlMugz!a5o2aSrvaAL}L4_-U}xse%GRSzBG=Jh1jeqrJa}e~e34$?NA&dZYk#%e5*= z?3chDqsWTpnZ&3e*WjZAeyZz(mq>hmd6Z}uo=YGTFo9N+o}hPh0jTAg>A;9W4DMaq z5gnF#bvkZ+UIgr$Cw5i=sy<`0{~VmH!v4Df7@Pdd&fT}iRkU6gA@|w7v?rK@2(8HN zfzw3e(F8+StfoebL$s|DWI^u2tH0%jm8$BA6G37A$iwyS`G%9~sh%iJ3ny5C*B%ATdNSsWP&CGV$ z61pdF5>Pk#qNt2OoGA4%O#X=DW6A>}-73>oNh^=! ze!f=TG%8YUB~<34okV(j@kCOWz^qw?)?j-o*8P``KK zHuJ?_Y0j+-qVD{B*1$kM@Cho?8P+|jYM|c}L18qz0gRZP;?^uKyPtaN>-^*RcKbG< z+4-oRE#MV4zCm23f#cyLnnyI^oP0$eGY@AVs3e;-9pka)9eZ?Sn=RlyI5UG&ue((U zt_^F<7RX=V5fBOp5x{(GC_K|?0rx%#WZ;GC5bsQN`E2!=PbOJ9^%P8gC6-Cjax%>7 zO$5L-h#$CJH!lL1Km;-UPDFH+Zi7{be~)Q#gaNbzVbe@cWrXP9u=&aQSMsAgK)GH z>l&*Qw zlPj8cTpR^+tqE`E@UH#LT9?4r`p1YP`j2fdq|q3eL%Y@6BSBxubeUZlM8Z-kns*J~ zG~d1$J`AEw-3722K2FYg-JKLIuYhM^*$g}KE{T{k=uBY^8Img_7+te2?hi~2+P!;g z>0&P+u21k{+Xq{8ZJrlFbYl&!`rN;Z&XM#{|4J@d58#c{tziJ<=+dQUO zx?GJh%Y+)Mu-7}S%b^Y@mliFkeFr->H8rgt9!9;Kkk0z!vdbc^hE0PM#)>#{)zW-Y z7j24>{MIIJFwPFm>>6B0(2~I>!AL9YBRoC_(bIdsGlB_!o0%3C*_o30ZPC{OHpH* zLbXkkHy=Hx`HWa=HpFg`p-K=ELA|~eL)yR=McTarg?Osi2Vk=2V1}1S0hnN3 z!Xyk+V$&5|XjiWW(cuVC6adXHsKEU~6{?y*B<(v(E7?GxRz&@~F^y}Q{&m0V6L&8? zLuBHoJt0kM;*wQ{8$Cvm+wVO>KQupnD!mD7sc1$?)%yCR?4xw|q~&EM1bz~8Ty5?FUw=SfeR+$`{hQ*=l@6@H)a4`!b*@-vOTQhqy!OgH zyj};SkKHY&b4s-;*LD|bEq#x4*ESzFQ=nvy-gsIwtjP+t@`4iStR7)!-;h@ezo!g) z1|P0}8!evR$gHZEeeN~9kFN6&?sk0cbF9)m@qC@2v*Xrfb!6pTJMB}Oxs%%0Mf@;I zA<-rw)@Z5D(8vSbJ!3ZN)#W69K11#&2N`k|tZWZmWY3su&%1A-p{{>e4SavsT8=sA zWCBS3c57Sc;RKIHx&F~4=O!@TvBe2J zRs4C+F?n&vA?O)pw9{{zn@7CEvX}pMk3!M`2Gx@a8mtzdm8LU(Xd9_WzNA#b2@Nzm zSK`upUnu4T6pEqUw5q1Bpnr-`D12cYI9k`&x&1=m1w-MUW>f$yh|0rMyU78VmDx>M z=WtBpsJmE1puQCGi6Pi~a9aCz57(6qy0XG;FI2HjxhHf^ppps~((k=$NUlM=z60VZ znUQb{fd>9c08xO;VQfQ$C5+QY-gr{F8{4*Q7lJ;Ks!*-=HC+hgFl4B2=ss9+{jx$>z%`8&f~M zt#&@R_^$b!Id%Amtx0mA)vKvrPPNU}Cm*LY$vhr=69^yb>=>VFspNfmW!amxfY(9}ni{D>lLdwsXMk3Om`KZ8Nx+64{AS;TF4{?5tllex{^nN}iJ z- zyHTJq2Fmdh*Qpu`KfvuEp@nO3jge`|bta;@5-=V)DQI}!h>xw*)y^Pv`&0%a9b0ps zA;|oqRSqL1O8b-x$E6gJDo^&bixUI>XCV6I#W%vsp8{SeQgCKpk<1Fe?W=ERZf36Q zJsyvTFaM~u`oIvTEqq%y^oid&r`0oVGLz6YYWJP>XH5F&>Tj4xLSw}f#@s}GxX2db zerEV|B|AR>F*b1|co}~MxBy-?idf9mT}(b->#hylYzT1*gK$ujK)e8{2olO{*W40K=OFd0DjR*zzysSG3$xO5as7;eho=cu zc*)N0%zD)5iP;5rA4IYFUAXw3cOd{S#tB%xvyZd$AbKl$MIDrWHe=sg7y}x&})Nnt&WS&%K7~>0b7pYCE3fe;jT-LPxvl)=lPiV4l%kmP8qx} zk2+<$P-LDkRbh>Npyfb<79=B}kmMW}M=8n9?NLB2c~Ov5fUERaydCFVOp?gBQR~xS z;`0k%a?(`-=wNRq*vJ zx_lNnJ~=^LxTH|(qrE2HFWB`pBF5~A{blW;z9dWg_BGYDegYA;8gcc$qxPpfSzigI zOM&wnX3DhnLyA4r?R2j{Nn4LETAMt3cXlKX=@2|~_?jF2?(_>0aoVMaVyA57xYquN zjxq9+v$%XnPaRyf9H++xUeBoG;M@mb-rSY`DL1M^rBp`gorq!|9yLGrXQEb2{x7?^B!wf9x#%1Te zavvd-i7ltKYY1iJxO7|8QtI@NoWRZT;CWUq zuSl%=oV8PX^oh(B7Gh;)IQT-ZbgD-C_I7S$V&pb9M{(Q0edjIZ8HTDGzcDBeIkd&G zSpZL?6h~p|`_k0i%RQ;_VOBn}-&&DH#3-~I42roWoUH}ghY%a6_>NiQ();t*#?Ih~ z^Xmh(*_$Ys2orsN2k5>IuySzp6gg=MmJhoAM0uAZ)*I7AS^XLgHGPT`Z`z;!tO${^sHRio; zGaOo10I`L0+N+VxZPowU)Gp_?E=m2XRj#9XlvyF45YVm@D@o|#Bzz>Hm%@~4F`}I~ zvEUR>Rl7q!*|~e+^E2K3(eo(sT|Ree6Iy_<9k>wQ5&J&tza( z#BqvfJDxv(1T=VpXw#g0{h|~`1S}*n2sTY`0oD`X+~t6JcPX(UPwVjNTCD`jD9aZa z+aCJojB1_o{g$v7A@!y?x2!(TrL4FPA($>kh20%h4m3}tW;%trgUBYUMSHDtr#t(mlTiwHLZjMo?dGCu73Y!446&Fx=%m=JL-23Eoji@PCmi(!n^CZsn8S%NM|C@y86@egELX3gm zM?(o-P zZS5+&Q)%@Bl#lF^Gs!cdICu7&h{%Pwe|zJS zw|ns$hty*($aEJgJ0&~vLYZS0rZzx8r+r=d#&4fg0R8o#{fZ`RQ^hV_c+He;n5gySz9QAGQTZjm`t4;6ktqVi`}5o8s7?>F8m3rI&q z**@IXseRc>%ppTVG?ZB#oIm8{Uu8?91$DRk5O?!A-V$^(yd~gbr3N=agQ8lFz;wj)qC&h!X|ygNMIzE&9JW(8h8gxHiGsW zNoTjgb>93mH1)fcZn8D_zN!L^zO}ud$IjmUcnpM!tPp}G0Z)I$@9=J0*OvRoXWIQ6 zCSFJbCpd#&R;|)!mLmauZ5HYsGChb3MDB*~WMIl#=hg~(yuOnO!b;l0BcWjy6r*W2 zU+0eC@ZIg6lj@ZlLnt5oFw4Z@hOe_1R{f%r!_sP$AIAm*GZ@Exz;F$!f-s8Fr&|^0 ztf3~jxc#eIGWv(H1-qcs`RcUeoVm`yYzBgY(*%hSeGDz|j=L(O$|awBV$Md@aLeS4 z(}E+x^7M#+ntNQgIxopzmZx79ax__5z(ucsv#W#0#hf-Gg*B}HEiyC6Vw#&pO~O6x z*5!FRYs0nZz7xR3C9!yysDOlCj{`jtg#UsBM?qTf-f~nV4Xd2~qL@(u_3LkOHAKT} z6~d%9Wq(W1rna>aS!=Ge1xKzOZF-G&cy@L0oQ?;jAHP>MSmubMS=RBOztAVl+yT7f zpsFFlLdtS4kic>R=0Z+GHV1?Ad(AGt4=dV|_9Z?Q^$-MRP1nlwlF`j0aIkJi7LmZs z0jP{NxUi4vkvlT?joldac^@+#y=0F?6a4_Hc`~jv}QDL?Y=5m%&crZHx7rpv}Oz89r(cA)dwH+;^`6X}b8KG6c7Li4PPP)hgw( zSOvVIjGweI#GeIj6)UUrBaazAFhT3-muJ|ii=r+40{U}P9`Q3ap;uyvEcPBl{bT`O zr%oR_iiEjGR|kgDe~{A8P*>ye%y(;Rt?#a0V@tN2oj0p)Fd~d??A`J9``_Q+Klt${ z0II!iCY#9ad_Df$baQ5UnuKwywQSlV4tFyEKE4PF1$v&*9m4cK-3bLBkx?sGs#jkp zX$P!E+iDQ{7OV~$KOs_;-im2%qZt?Fvlw!D|y2y`5i^VJ;tVT~Wxe;4gfT$K?y=UUmtw z$K&|usv4vAJN>n7fH|FMg_BQ!Z;Gc$#vb*Mc2mF`^(f9W)|qhOVRV*8>$OA}Ir19G z=}-I1U*;x25rf9b7y$wQA?%HkIk;1$i=y%}r6nedYK^m%6j@RdCRaX&Yjt%6lfNPj zQJfpw%7VgHnUKd{341>faPAWeiahP=A*TUQ3*8FhDkI0<*qTF?2Pd2+dEY^QGLniC J6=Fs~{~tnm&s_ij literal 0 HcmV?d00001 diff --git a/src/Menu.cpp b/src/Menu.cpp deleted file mode 100644 index 42026a9..0000000 --- a/src/Menu.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "Menu.hpp" - -Menu::Menu(float width, float height) -{ - //creates menu options - - font.loadFromFile("assets/opensans.ttf"); - - for (int i = 0; i < max_number_of_items; i++) - { - menu[i] = sf::Text("0 fps", font); - menu[i].setCharacterSize(100); - menu[i].setFillColor(sf::Color::Red); - - switch (i) - { - case 0: - menu[i].setString("Play"); - break; - case 1: - menu[i].setString("Options"); - break; - default: - menu[i].setString("Exit"); - } - - selection[i] = false; - - float text_width = menu[i].getLocalBounds().width; - - menu[i].setPosition(sf::Vector2f((width / 2) - (text_width / 2), height / (max_number_of_items + 1) * (i + 1))); - } -} - -void Menu::draw(sf::RenderWindow& window) -{ - //draws the menu options - for (int i = 0; i < max_number_of_items; i++) - { - window.draw(menu[i]); - } -} - -void Menu::handleButtonPress(sf::Vector2i position_of_mouse) -{ - //find where the mouse is clicking - //this needs to be made dynamic as it only works with the exact window size - for (int i = 0; i < max_number_of_items; i++) - { - if ((position_of_mouse.x > menu[i].getPosition().x + 550) and position_of_mouse.x < menu[i].getPosition().x + 550 + menu[i].getLocalBounds().width) - { - if ((position_of_mouse.y > menu[i].getPosition().y + 550) and (position_of_mouse.y < menu[i].getPosition().y + 550 + menu[i].getLocalBounds().height)) - { - menu[i].setFillColor(sf::Color::White); - selection[i] = true; - } - } - } -} - -bool Menu::getSelection(int choice) -{ - return selection[choice]; -} \ No newline at end of file diff --git a/src/Menu.hpp b/src/Menu.hpp deleted file mode 100644 index fce2a9e..0000000 --- a/src/Menu.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef Menu_H -#define Menu_H - -#define max_number_of_items 3 - -class Menu -{ -private: - sf::Font font; - sf::Text menu[max_number_of_items]; - bool selection[max_number_of_items]; - -public: - Menu(float width, float height); - - void draw(sf::RenderWindow& window); - void handleButtonPress(sf::Vector2i position_of_mouse); - bool getSelection(int choice); -}; - -#endif \ No newline at end of file diff --git a/src/Menu/Button.cpp b/src/Menu/Button.cpp new file mode 100644 index 0000000..f99d5b6 --- /dev/null +++ b/src/Menu/Button.cpp @@ -0,0 +1,71 @@ +#include "Menu/Button.hpp" + +MenuButton::MenuButton(std::string _text, sf::Vector2f _pos, sf::Vector2f _size) : + Sprite { "assets/button-background.png", _pos, _size } +{ + has_been_selected = false; + + font.loadFromFile("assets/opensans.ttf"); + text_sprite = sf::Text(text, font); + text_sprite.setCharacterSize(100); + text_sprite.setFillColor(sf::Color::Black); + set_details(_text, _pos, _size); +} + +MenuButton::MenuButton() : + Sprite { "assets/button-background.png", sf::Vector2f(), sf::Vector2f() } +{ + has_been_selected = false; + + font.loadFromFile("assets/opensans.ttf"); + text_sprite = sf::Text("", font); + text_sprite.setCharacterSize(100); + text_sprite.setFillColor(sf::Color::Black); +} + +void MenuButton::set_details(std::string _text, sf::Vector2f _pos, sf::Vector2f _size) +{ + text = _text; + pos = _pos; + size = _size; + + text_sprite.setString(_text); + + const sf::FloatRect tsize = text_sprite.getLocalBounds(); + text_sprite.setPosition(sf::Vector2f( + pos.x + size.x / 2 - tsize.width / 2 - 5, + pos.y + size.y / 2 - tsize.height / 2 - 15)); + + update_sprite(_pos, _size); +}; + +void MenuButton::draw(sf::RenderWindow& window) +{ + window.draw(sprite); + window.draw(text_sprite); +} + +void MenuButton::handleButtonPress(sf::Vector2i position_of_mouse) +{ + has_been_selected = true; + + if (position_of_mouse.x < pos.x || (pos.x + size.x) < position_of_mouse.x) + { + has_been_selected = false; + } + + else if (position_of_mouse.y < pos.y || (pos.y + size.y) < position_of_mouse.y) + { + has_been_selected = false; + } +} + +bool MenuButton::hasBeenPressed() +{ + if (has_been_selected) + { + has_been_selected = false; + return true; + } + return false; +} \ No newline at end of file diff --git a/src/Menu/Button.hpp b/src/Menu/Button.hpp new file mode 100644 index 0000000..23bcd82 --- /dev/null +++ b/src/Menu/Button.hpp @@ -0,0 +1,27 @@ +#ifndef MenuButton_H +#define MenuButton_H + +#include "Sprite.hpp" + +class MenuButton : Sprite +{ +private: + sf::Font font; + sf::Text text_sprite; + + std::string text; + bool has_been_selected; + +public: + sf::Vector2f pos; + sf::Vector2f size; + MenuButton(std::string text, sf::Vector2f start_pos, sf::Vector2f target_size); + MenuButton(); + + void set_details(std::string text, sf::Vector2f start_pos, sf::Vector2f target_size); + void draw(sf::RenderWindow& window); + void handleButtonPress(sf::Vector2i position_of_mouse); + bool hasBeenPressed(); +}; + +#endif \ No newline at end of file diff --git a/src/Menu/Menu.cpp b/src/Menu/Menu.cpp new file mode 100644 index 0000000..081840b --- /dev/null +++ b/src/Menu/Menu.cpp @@ -0,0 +1,34 @@ +#include "Menu/Menu.hpp" + +Menu::Menu(sf::Vector2u screen_size) +{ + const sf::Vector2f button_size = sf::Vector2f(600, 299); + float x_line = screen_size.x / 2 - button_size.x / 2; + + buttons[0].set_details("Play", sf::Vector2f(x_line, screen_size.y / 4 * 1 - button_size.y / 2 - 50), button_size); + buttons[1].set_details("Options", sf::Vector2f(x_line, screen_size.y / 4 * 2 - button_size.y / 2), button_size); + buttons[2].set_details("Exit", sf::Vector2f(x_line, screen_size.y / 4 * 3 - button_size.y / 2 + 50), button_size); +} + +void Menu::draw(sf::RenderWindow& window) +{ + for (int i = 0; i < 3; i++) + buttons[i].draw(window); +} + +void Menu::handleButtonPress(sf::Vector2i position_of_mouse) +{ + for (int i = 0; i < 3; i++) + buttons[i].handleButtonPress(position_of_mouse); +} + +int Menu::hasButtonBeenPressed() +{ + for (int i = 0; i < 3; i++) + { + if (buttons[i].hasBeenPressed()) + return i; + } + + return -1; +} diff --git a/src/Menu/Menu.hpp b/src/Menu/Menu.hpp new file mode 100644 index 0000000..b263145 --- /dev/null +++ b/src/Menu/Menu.hpp @@ -0,0 +1,19 @@ +#ifndef Menu_H +#define Menu_H + +#include "Menu/Button.hpp" + +class Menu +{ +private: + MenuButton buttons[3] = {}; + +public: + Menu(sf::Vector2u screen_size); + + void draw(sf::RenderWindow& window); + void handleButtonPress(sf::Vector2i position_of_mouse); + int hasButtonBeenPressed(); +}; + +#endif \ No newline at end of file diff --git a/src/WindowStates/GameState.cpp b/src/WindowStates/GameState.cpp index a9d43e1..c0cb6da 100644 --- a/src/WindowStates/GameState.cpp +++ b/src/WindowStates/GameState.cpp @@ -16,4 +16,4 @@ void GameState::update() void GameState::show() { -} \ No newline at end of file +} diff --git a/src/WindowStates/MenuState.cpp b/src/WindowStates/MenuState.cpp index fecbfc0..2dbd7b8 100644 --- a/src/WindowStates/MenuState.cpp +++ b/src/WindowStates/MenuState.cpp @@ -2,7 +2,7 @@ MenuState::MenuState(sf::RenderWindow& window) : BaseState { window }, - menu(window.getSize().x, window.getSize().y) + menu(sf::Vector2u(window.getSize().x, window.getSize().y)) { } @@ -14,7 +14,7 @@ void MenuState::handle_event(sf::Event& event) window.close(); break; case sf::Event::MouseButtonPressed: - menu.handleButtonPress(sf::Mouse::getPosition()); + menu.handleButtonPress(sf::Mouse::getPosition(window)); break; default: break; @@ -23,20 +23,25 @@ void MenuState::handle_event(sf::Event& event) void MenuState::update() { - if (menu.getSelection(0)) + switch (menu.hasButtonBeenPressed()) { - std::cout << "Leave menu" << std::endl; - } - else if (menu.getSelection(2)) - { - window.close(); + case 0: + std::cout << "Play the game" << std::endl; + break; + case 1: + std::cout << "Go to options page" << std::endl; + break; + case 2: + window.close(); + break; + default: + break; } } void MenuState::show() { window.clear(); - menu.draw(window); window.display(); } \ No newline at end of file diff --git a/src/WindowStates/MenuState.hpp b/src/WindowStates/MenuState.hpp index 5649d48..a0834c5 100644 --- a/src/WindowStates/MenuState.hpp +++ b/src/WindowStates/MenuState.hpp @@ -1,7 +1,7 @@ #ifndef MenuState_H #define MenuState_H -#include "Menu.hpp" +#include "Menu/Menu.hpp" #include "State.hpp" class MenuState : BaseState diff --git a/src/main.cpp b/src/main.cpp index 7a1b2d7..6cf63bf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,8 @@ #include "Enemy.hpp" #include "FrameRate.hpp" -#include "Menu.hpp" #include "Player.hpp" #include "StaticSprite.hpp" +#include "WindowStates/GameState.hpp" #include "WindowStates/MenuState.hpp" float deltatime = 0.f; @@ -16,18 +16,21 @@ int main() // Setup our view (camera) sf::View player_view(sf::FloatRect(0, 0, window.getSize().x, window.getSize().y)); - MenuState current_state(window); + MenuState menu_state(window); + GameState game_state(window); + + // BaseState* current_state = &menu_state; + MenuState* current_state = &menu_state; sf::Event event; - //menu loop + // menu loop while (window.isOpen()) { while (window.pollEvent(event)) - current_state.handle_event(event); - - current_state.update(); + current_state->handle_event(event); - current_state.show(); + current_state->update(); + current_state->show(); } bool show_hitboxes = false; From 023f51a089038fe5193b1fd5b9d89bc756283c5e Mon Sep 17 00:00:00 2001 From: Gregor Maclaine Date: Fri, 4 Feb 2022 14:31:42 +0000 Subject: [PATCH 11/20] Moved game logic to Game class and finished FSM --- src/Enemy.cpp | 14 +++- src/Enemy.hpp | 3 + src/Game/Game.cpp | 84 ++++++++++++++++++++ src/Game/Game.hpp | 36 +++++++++ src/Player.cpp | 6 ++ src/Player.hpp | 3 + src/WindowStates/GameState.cpp | 35 +++++++-- src/WindowStates/GameState.hpp | 5 +- src/WindowStates/MenuState.cpp | 9 +-- src/WindowStates/MenuState.hpp | 2 +- src/WindowStates/State.cpp | 5 +- src/WindowStates/State.hpp | 9 ++- src/main.cpp | 135 ++++++++------------------------- 13 files changed, 224 insertions(+), 122 deletions(-) create mode 100644 src/Game/Game.cpp create mode 100644 src/Game/Game.hpp diff --git a/src/Enemy.cpp b/src/Enemy.cpp index 3aea7b8..01a8de4 100644 --- a/src/Enemy.cpp +++ b/src/Enemy.cpp @@ -4,8 +4,12 @@ Enemy::Enemy(sf::Vector2f _pos, sf::Vector2f target_size) : Hitbox { _pos, target_size }, Sprite { "assets/enemy.png", _pos, target_size } -{ -} +{} + +Enemy::Enemy() : + Hitbox { sf::Vector2f(), sf::Vector2f() }, + Sprite { "assets/enemy.png", sf::Vector2f(), sf::Vector2f() } +{} void Enemy::updatePosition(StaticSprite* platforms, sf::Vector2f player_pos) { @@ -23,3 +27,9 @@ void Enemy::updatePosition(StaticSprite* platforms, sf::Vector2f player_pos) sprite.setPosition(pos); } + +void Enemy::setPosition(sf::Vector2f _pos) +{ + pos = _pos; + update_sprite(pos, size); +} diff --git a/src/Enemy.hpp b/src/Enemy.hpp index 9f5d242..39ee5fa 100644 --- a/src/Enemy.hpp +++ b/src/Enemy.hpp @@ -18,9 +18,12 @@ class Enemy : public Hitbox, public Sprite public: Enemy(sf::Vector2f pos, sf::Vector2f size); + Enemy(); // Updates the position of the sprite void updatePosition(StaticSprite* platforms, sf::Vector2f player_pos); + // Force sets the position of the sprites + void setPosition(sf::Vector2f _pos); }; #endif diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp new file mode 100644 index 0000000..4fb26ac --- /dev/null +++ b/src/Game/Game.cpp @@ -0,0 +1,84 @@ +#include "Game/Game.hpp" + +Game::Game(sf::RenderWindow& _window) : + window { _window }, + player_view { sf::FloatRect(0, 0, window.getSize().x, window.getSize().y) }, + player { sf::Vector2f(500.f, 0.f), sf::Vector2f(215.f, 258.f) }, + platforms { + StaticSprite("assets/platform.png", sf::Vector2f(10.f, 500.f), sf::Vector2f(760.f, 107.f)), + StaticSprite("assets/platform.png", sf::Vector2f(1100.f, 720.f), sf::Vector2f(760.f, 107.f)), + StaticSprite("assets/platform.png", sf::Vector2f(1100.f, 100.f), sf::Vector2f(760.f, 107.f)) + }, + enemies { + Enemy(sf::Vector2f(0.f, 250.f), sf::Vector2f(215.f, 258.f)), + Enemy(sf::Vector2f(1800.f, 670.f), sf::Vector2f(215.f, 258.f)) + } +{ + reset_positions(true); +} + +void Game::reset_positions(bool hard_reset) +{ + player.setDetails(sf::Vector2f(500.f, 0.f), player.size); + if (hard_reset) + { + enemies[0].setPosition(sf::Vector2f(0.f, 210.f)); + enemies[1].setPosition(sf::Vector2f(1800.f, 320.f)); + } +} + +void Game::handleKeyPress(sf::Keyboard::Key key_code) +{ + player.handleKeyPress(key_code); +} + +void Game::handleKeyRelease(sf::Keyboard::Key key_code) +{ + player.handleKeyRelease(key_code); +} + +void Game::update() +{ + player.updatePosition(platforms); + + for (unsigned int i = 0; i < 2; i++) + { + enemies[i].updatePosition(platforms, player.pos); + } + + frame_tracker.add_info("Vel", std::to_string(player.vel.x).substr(0, 4) + " | " + std::to_string(player.vel.y).substr(0, 4)); + frame_tracker.update(); +} + +void Game::moveViewToPlayer() +{ + player_view.setCenter(sf::Vector2f(player.pos.x, 300)); + window.setView(player_view); +} + +void Game::draw() +{ + unsigned int i; + for (i = 0; i < 2; i++) + { + enemies[i].draw(window); + + if (show_hitboxes) + window.draw(enemies[i].get_hitbox_outline()); + } + + for (i = 0; i < 3; i++) + { + platforms[i].draw(window); + + if (show_hitboxes) + window.draw(platforms[i].get_hitbox_outline()); + } + + player.draw(window); + + if (show_hitboxes) + window.draw(player.get_hitbox_outline()); + + window.draw(frame_tracker.text); +} \ No newline at end of file diff --git a/src/Game/Game.hpp b/src/Game/Game.hpp new file mode 100644 index 0000000..21ed145 --- /dev/null +++ b/src/Game/Game.hpp @@ -0,0 +1,36 @@ +#ifndef Game_H +#define Game_H + +#include "Enemy.hpp" +#include "FrameRate.hpp" +#include "Player.hpp" + +class Game +{ +private: + sf::RenderWindow& window; + sf::View player_view; + + FrameRateTracker frame_tracker; + + Player player; + StaticSprite platforms[3]; + Enemy enemies[2]; + +public: + bool show_hitboxes; + + Game(sf::RenderWindow& window); + + void reset_positions(bool hard_reset); + + void handleKeyPress(sf::Keyboard::Key key_code); + void handleKeyRelease(sf::Keyboard::Key key_code); + + void moveViewToPlayer(); + void draw(); + + void update(); +}; + +#endif diff --git a/src/Player.cpp b/src/Player.cpp index f10e517..826b6dc 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -71,3 +71,9 @@ void Player::updatePosition(StaticSprite* platforms) sprite.setPosition(pos); } + +void Player::setDetails(sf::Vector2f _pos, sf::Vector2f _size) +{ + pos = _pos; + update_sprite(pos, _size); +} diff --git a/src/Player.hpp b/src/Player.hpp index 5918d92..62ddb3d 100644 --- a/src/Player.hpp +++ b/src/Player.hpp @@ -31,6 +31,7 @@ class Player : public Hitbox, public Sprite public: Player(sf::Vector2f pos, sf::Vector2f size); + Player(); // Handles a key press event from the keyboard void handleKeyPress(sf::Keyboard::Key key); // Handles a key release event from the keyboard @@ -41,6 +42,8 @@ class Player : public Hitbox, public Sprite void updatePosition(StaticSprite* platforms); // Handled when space is pressed void handleJump(); + + void setDetails(sf::Vector2f pos, sf::Vector2f _size); }; #endif diff --git a/src/WindowStates/GameState.cpp b/src/WindowStates/GameState.cpp index c0cb6da..375d090 100644 --- a/src/WindowStates/GameState.cpp +++ b/src/WindowStates/GameState.cpp @@ -1,19 +1,44 @@ #include "GameState.hpp" GameState::GameState(sf::RenderWindow& window) : - BaseState { window } -{ -} + BaseState { window }, + game(window) +{} void GameState::handle_event(sf::Event& event) { - std::cout << event.key.code << std::endl; + const bool control_down = sf::Keyboard::isKeyPressed(sf::Keyboard::LControl); + + switch (event.type) + { + case sf::Event::KeyPressed: + game.handleKeyPress(event.key.code); + + if (control_down && event.key.code == sf::Keyboard::B) + game.show_hitboxes = !game.show_hitboxes; + + else if (event.key.code == sf::Keyboard::R) + game.reset_positions(control_down); + + break; + + case sf::Event::KeyReleased: + game.handleKeyRelease(event.key.code); + break; + + default: + break; + } } -void GameState::update() +void GameState::update(WindowStates& next_state) { + game.update(); + (void)next_state; } void GameState::show() { + game.moveViewToPlayer(); + game.draw(); } diff --git a/src/WindowStates/GameState.hpp b/src/WindowStates/GameState.hpp index ad93b87..c948a5a 100644 --- a/src/WindowStates/GameState.hpp +++ b/src/WindowStates/GameState.hpp @@ -1,16 +1,19 @@ #ifndef GameState_H #define GameState_H +#include "Game/Game.hpp" #include "State.hpp" class GameState : BaseState { private: + Game game; + public: GameState(sf::RenderWindow& window); void handle_event(sf::Event& event); - void update(); + void update(WindowStates& next_state); void show(); }; diff --git a/src/WindowStates/MenuState.cpp b/src/WindowStates/MenuState.cpp index 2dbd7b8..8ecb28a 100644 --- a/src/WindowStates/MenuState.cpp +++ b/src/WindowStates/MenuState.cpp @@ -10,9 +10,6 @@ void MenuState::handle_event(sf::Event& event) { switch (event.type) { - case sf::Event::Closed: - window.close(); - break; case sf::Event::MouseButtonPressed: menu.handleButtonPress(sf::Mouse::getPosition(window)); break; @@ -21,12 +18,12 @@ void MenuState::handle_event(sf::Event& event) } } -void MenuState::update() +void MenuState::update(WindowStates& next_state) { switch (menu.hasButtonBeenPressed()) { case 0: - std::cout << "Play the game" << std::endl; + next_state = WindowStates::GAME; break; case 1: std::cout << "Go to options page" << std::endl; @@ -41,7 +38,5 @@ void MenuState::update() void MenuState::show() { - window.clear(); menu.draw(window); - window.display(); } \ No newline at end of file diff --git a/src/WindowStates/MenuState.hpp b/src/WindowStates/MenuState.hpp index a0834c5..91fa824 100644 --- a/src/WindowStates/MenuState.hpp +++ b/src/WindowStates/MenuState.hpp @@ -13,7 +13,7 @@ class MenuState : BaseState MenuState(sf::RenderWindow& window); void handle_event(sf::Event& event); - void update(); + void update(WindowStates& next_state); void show(); }; diff --git a/src/WindowStates/State.cpp b/src/WindowStates/State.cpp index 6b78dea..a61606f 100644 --- a/src/WindowStates/State.cpp +++ b/src/WindowStates/State.cpp @@ -2,11 +2,12 @@ void BaseState::handle_event(sf::Event& event) { - std::cout << event.key.code << std::endl; + (void)event; } -void BaseState::update() +void BaseState::update(WindowStates& next_state) { + (void)next_state; } void BaseState::show() diff --git a/src/WindowStates/State.hpp b/src/WindowStates/State.hpp index fc64328..f196c3b 100644 --- a/src/WindowStates/State.hpp +++ b/src/WindowStates/State.hpp @@ -1,6 +1,13 @@ #ifndef BaseState_H #define BaseState_H +enum WindowStates +{ + NONE, + MENU, + GAME, +}; + /** * The base state for the finite state machine that defines what * is shown on the window. It should be inherited by other classes. @@ -16,7 +23,7 @@ class BaseState {} void handle_event(sf::Event& event); - void update(); + void update(WindowStates& next_state); void show(); }; diff --git a/src/main.cpp b/src/main.cpp index 6cf63bf..e7c7c8e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,128 +5,57 @@ #include "WindowStates/GameState.hpp" #include "WindowStates/MenuState.hpp" +sf::Clock deltatime_clock; float deltatime = 0.f; -int main() +template +WindowStates MainStateLoop(T current_state, sf::RenderWindow& window) { - sf::Clock deltatime_clock; - - sf::RenderWindow window(sf::VideoMode(1920, 1080), "Game"); - - // Setup our view (camera) - sf::View player_view(sf::FloatRect(0, 0, window.getSize().x, window.getSize().y)); - - MenuState menu_state(window); - GameState game_state(window); - - // BaseState* current_state = &menu_state; - MenuState* current_state = &menu_state; - sf::Event event; - // menu loop - while (window.isOpen()) - { - while (window.pollEvent(event)) - current_state->handle_event(event); - - current_state->update(); - current_state->show(); - } - - bool show_hitboxes = false; - - StaticSprite platforms[3] = { - StaticSprite("assets/platform.png", sf::Vector2f(10.f, 500.f), sf::Vector2f(760.f, 107.f)), - StaticSprite("assets/platform.png", sf::Vector2f(1100.f, 720.f), sf::Vector2f(760.f, 107.f)), - StaticSprite("assets/platform.png", sf::Vector2f(1100.f, 100.f), sf::Vector2f(760.f, 107.f)) - }; - - Enemy enemies[2] = { - Enemy(sf::Vector2f(0.f, 250.f), sf::Vector2f(215.f, 258.f)), - Enemy(sf::Vector2f(1800.f, 670.f), sf::Vector2f(215.f, 258.f)) - }; - - Player player(sf::Vector2f(500.f, 0.f), sf::Vector2f(215.f, 258.f)); - - FrameRateTracker frame_tracker; - - // Main Game Loop - while (window.isOpen()) + WindowStates next_state = WindowStates::NONE; + while (next_state == WindowStates::NONE && window.isOpen()) { deltatime = deltatime_clock.restart().asSeconds() * 450.f; - // we keep our view centered on the player - player_view.setCenter(sf::Vector2f(player.pos.x, 300)); - window.setView(player_view); - while (window.pollEvent(event)) { - switch (event.type) - { - case sf::Event::Closed: - window.close(); - break; + if (event.type == sf::Event::Closed) + window.close(); - case sf::Event::KeyPressed: - player.handleKeyPress(event.key.code); - - if (sf::Keyboard::isKeyPressed(sf::Keyboard::LControl) && event.key.code == sf::Keyboard::B) - show_hitboxes = !show_hitboxes; - - else if (event.key.code == sf::Keyboard::R) - { - player.pos = sf::Vector2f(500.f, 0.f); - if (sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)) - { - enemies[0].pos = sf::Vector2f(0.f, 210.f); - enemies[1].pos = sf::Vector2f(1800.f, 320.f); - } - } - break; - - case sf::Event::MouseButtonPressed: - // - break; - - case sf::Event::KeyReleased: - player.handleKeyRelease(event.key.code); - break; - - default: - break; - } + current_state.handle_event(event); } - player.updatePosition(platforms); + current_state.update(next_state); window.clear(); + current_state.show(); + window.display(); + } + return next_state; +}; - for (unsigned int i = 0; i < 2; i++) - { - enemies[i].updatePosition(platforms, player.pos); - enemies[i].draw(window); +int main() +{ + sf::RenderWindow window(sf::VideoMode(1920, 1080), "Game"); - if (show_hitboxes) - window.draw(enemies[i].get_hitbox_outline()); - } + MenuState menu_state(window); + GameState game_state(window); - for (unsigned int i = 0; i < 3; i++) + WindowStates current_state = WindowStates::MENU; + while (window.isOpen()) + { + switch (current_state) { - platforms[i].draw(window); + case WindowStates::GAME: + current_state = MainStateLoop(game_state, window); + break; - if (show_hitboxes) - window.draw(platforms[i].get_hitbox_outline()); - } + default: + std::cout << "Error: Window State is not defined - Defaulting to menu" << std::endl; - player.draw(window); - - if (show_hitboxes) - window.draw(player.get_hitbox_outline()); - - frame_tracker.add_info("Vel", std::to_string(player.vel.x).substr(0, 4) + " | " + std::to_string(player.vel.y).substr(0, 4)); - frame_tracker.update(); - window.draw(frame_tracker.text); - - window.display(); + case WindowStates::MENU: + current_state = MainStateLoop(menu_state, window); + break; + } } return 0; From e557119d0a16a28d23f42ae2bca69d16e531e97b Mon Sep 17 00:00:00 2001 From: Gregor Maclaine Date: Mon, 7 Feb 2022 18:03:41 +0000 Subject: [PATCH 12/20] Added a lot of comments --- src/Game/Background.cpp | 7 +++++++ src/Game/Background.hpp | 7 +++++++ src/Game/Game.cpp | 10 ++++++++++ src/Game/Game.hpp | 6 ++++++ src/Menu/Button.cpp | 21 +++++++++++++++++++++ src/Menu/Button.hpp | 9 +++++++++ src/Menu/Menu.cpp | 12 ++++++++++++ src/Menu/Menu.hpp | 6 ++++++ src/Sprite.cpp | 7 +++++++ src/WindowStates/GameState.hpp | 5 +++++ src/WindowStates/MenuState.cpp | 4 ++-- src/WindowStates/MenuState.hpp | 6 ++++++ src/WindowStates/State.cpp | 25 +++++++++++++++++++++++-- src/WindowStates/State.hpp | 5 +++++ src/main.cpp | 18 ++++++++++++++++++ 15 files changed, 144 insertions(+), 4 deletions(-) diff --git a/src/Game/Background.cpp b/src/Game/Background.cpp index ed11b9c..b301093 100644 --- a/src/Game/Background.cpp +++ b/src/Game/Background.cpp @@ -4,6 +4,13 @@ Background::Background(sf::RenderWindow& window) : Sprite { "assets/background-image.png", sf::Vector2f(0, 0), sf::Vector2f(window.getSize()) } {} +/** + * Calculates where to place the background based on the player view, + * and draws it behind all other sprites. + * + * @param window A reference to the main window object + * @param view A reference to the currently active player view + */ void Background::draw(sf::RenderWindow& window, sf::View& view) { const sf::Vector2f view_center = view.getCenter(); diff --git a/src/Game/Background.hpp b/src/Game/Background.hpp index 1cd15ee..40aa6c3 100644 --- a/src/Game/Background.hpp +++ b/src/Game/Background.hpp @@ -3,6 +3,13 @@ #include "Sprite.hpp" +/** + * A sprite that draws a static image to the background during the game. + * It takes into account the moving window view and adjusts the background position to + * account for it. + * + * @param window A reference to the window + */ class Background : public Sprite { public: diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 0ead44c..721e9c5 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -1,6 +1,9 @@ #include "Game/Game.hpp" #include "WindowStates/State.hpp" +/** + * Initialise all objects and classes inside the game + */ Game::Game(sf::RenderWindow& _window) : window { _window }, player { sf::Vector2f(500.f, 0.f), sf::Vector2f(215.f, 258.f) }, @@ -18,6 +21,11 @@ Game::Game(sf::RenderWindow& _window) : reset_positions(true); } +/** + * Resets the positions of the player (and possibly enemies) + * + * @param hard_reset Whether to reset enemies as well + */ void Game::reset_positions(bool hard_reset) { player.setDetails(sf::Vector2f(500.f, 0.f), player.size); @@ -42,6 +50,7 @@ void Game::update(WindowStates& next_state) { if (player.health < 0) { + // If the player has died, go to Menu screen (TODO: implement GameOver screen) next_state = WindowStates::MENU; return; } @@ -56,6 +65,7 @@ void Game::update(WindowStates& next_state) player.updateHealth(); + // Update information in frame_tracker text widget frame_tracker.add_info("Vel", std::to_string(player.vel.x).substr(0, 4) + " | " + std::to_string(player.vel.y).substr(0, 4)); frame_tracker.update(); } diff --git a/src/Game/Game.hpp b/src/Game/Game.hpp index 24d3d95..9f930a0 100644 --- a/src/Game/Game.hpp +++ b/src/Game/Game.hpp @@ -6,6 +6,12 @@ #include "Player.hpp" #include "WindowStates/State.hpp" +/** + * The main game object to control all game functionality. + * Keeps references to player, platforms, and enemies, while also running collision logic. + * + * @param window A reference to the main window object + */ class Game { private: diff --git a/src/Menu/Button.cpp b/src/Menu/Button.cpp index f99d5b6..4c2c0d5 100644 --- a/src/Menu/Button.cpp +++ b/src/Menu/Button.cpp @@ -23,6 +23,14 @@ MenuButton::MenuButton() : text_sprite.setFillColor(sf::Color::Black); } +/** + * Takes in the parameters for the button and applies them. + * Automatically positions text in center of button. + * + * @param _text The text inside the button + * @param _pos The position of the top left coordinate of the button sprite + * @param _size The size of the button sprite + */ void MenuButton::set_details(std::string _text, sf::Vector2f _pos, sf::Vector2f _size) { text = _text; @@ -45,6 +53,11 @@ void MenuButton::draw(sf::RenderWindow& window) window.draw(text_sprite); } +/** + * If the click occured inside the button, record it and return it when asked + * + * @param position_of_mouse The vector for mouse position + */ void MenuButton::handleButtonPress(sf::Vector2i position_of_mouse) { has_been_selected = true; @@ -60,6 +73,14 @@ void MenuButton::handleButtonPress(sf::Vector2i position_of_mouse) } } +/** + * All buttons will be asked whether they were clicked at the same time. + * Therefore this will return whether it was clicked during any of the events. + * If it was clicked, then it will reset its attribute (to prevent multiple perceived mouse clicks) + * and return true. Else it will return false. + * + * @return bool Whether the button has been clicked + */ bool MenuButton::hasBeenPressed() { if (has_been_selected) diff --git a/src/Menu/Button.hpp b/src/Menu/Button.hpp index 23bcd82..622bcd6 100644 --- a/src/Menu/Button.hpp +++ b/src/Menu/Button.hpp @@ -3,6 +3,15 @@ #include "Sprite.hpp" +/** + * This defines a button that does not move, has a background rectangular image, + * and contains centred variable text. + * + * Once clicked the button records it and returns true once asked. + * + * While the class can be initialised through the constructor, the default constructor + * can also be used if calculations are needed. Then just use the `set_details` method. + */ class MenuButton : Sprite { private: diff --git a/src/Menu/Menu.cpp b/src/Menu/Menu.cpp index 081840b..261a983 100644 --- a/src/Menu/Menu.cpp +++ b/src/Menu/Menu.cpp @@ -1,5 +1,8 @@ #include "Menu/Menu.hpp" +/** + * This initialises the class and fills in the button information + */ Menu::Menu(sf::Vector2u screen_size) { const sf::Vector2f button_size = sf::Vector2f(600, 299); @@ -16,12 +19,21 @@ void Menu::draw(sf::RenderWindow& window) buttons[i].draw(window); } +/** + * For each mouse click tell all buttons to check if they were clicked. + * If so then they will remember that they have been clicked. + */ void Menu::handleButtonPress(sf::Vector2i position_of_mouse) { for (int i = 0; i < 3; i++) buttons[i].handleButtonPress(position_of_mouse); } +/** + * Returns the index of the button that has been clicked, -1 if none were clicked + * + * @return int The index of the clicked button + */ int Menu::hasButtonBeenPressed() { for (int i = 0; i < 3; i++) diff --git a/src/Menu/Menu.hpp b/src/Menu/Menu.hpp index b263145..f58e1b7 100644 --- a/src/Menu/Menu.hpp +++ b/src/Menu/Menu.hpp @@ -3,6 +3,12 @@ #include "Menu/Button.hpp" +/** + * This handle the main functionality of the Menu by containing each of the buttons + * and collating the information for each of them. + * + * @param screen_size This is the vector containing the size in pixels of the screen + */ class Menu { private: diff --git a/src/Sprite.cpp b/src/Sprite.cpp index 9fa1d23..1604aaa 100644 --- a/src/Sprite.cpp +++ b/src/Sprite.cpp @@ -18,6 +18,13 @@ void Sprite::draw(sf::RenderWindow& window) window.draw(sprite); } +/** + * Use this function when you want to chage the position or size in order to + * accurately update sprite. + * + * @param pos The new position of the sprite + * @param target_size The new size to scale the sprite to + */ void Sprite::update_sprite(sf::Vector2f pos, sf::Vector2f target_size) { const sf::FloatRect bounds = sprite.getLocalBounds(); diff --git a/src/WindowStates/GameState.hpp b/src/WindowStates/GameState.hpp index 3eaa7d1..b0cad8f 100644 --- a/src/WindowStates/GameState.hpp +++ b/src/WindowStates/GameState.hpp @@ -5,6 +5,11 @@ #include "Game/Game.hpp" #include "State.hpp" +/** + * This is the state contains the main gameplay + * + * @param window A reference to the main window object + */ class GameState : BaseState { private: diff --git a/src/WindowStates/MenuState.cpp b/src/WindowStates/MenuState.cpp index 8ecb28a..78a3ed1 100644 --- a/src/WindowStates/MenuState.cpp +++ b/src/WindowStates/MenuState.cpp @@ -3,8 +3,7 @@ MenuState::MenuState(sf::RenderWindow& window) : BaseState { window }, menu(sf::Vector2u(window.getSize().x, window.getSize().y)) -{ -} +{} void MenuState::handle_event(sf::Event& event) { @@ -20,6 +19,7 @@ void MenuState::handle_event(sf::Event& event) void MenuState::update(WindowStates& next_state) { + // Check to see if the menu has received any button presses switch (menu.hasButtonBeenPressed()) { case 0: diff --git a/src/WindowStates/MenuState.hpp b/src/WindowStates/MenuState.hpp index 91fa824..d5240dd 100644 --- a/src/WindowStates/MenuState.hpp +++ b/src/WindowStates/MenuState.hpp @@ -4,6 +4,12 @@ #include "Menu/Menu.hpp" #include "State.hpp" +/** + * The default state for the program which shows a menu with a few options. + * Primarily there is a button to go to the main game. + * + * @param window A reference to the main window object + */ class MenuState : BaseState { protected: diff --git a/src/WindowStates/State.cpp b/src/WindowStates/State.cpp index a61606f..6887bf5 100644 --- a/src/WindowStates/State.cpp +++ b/src/WindowStates/State.cpp @@ -1,15 +1,36 @@ #include "State.hpp" +/** + * This should handle all events that occur in the gameloop. + * It will most commonly just hold a switch statement that points + * to different functions of classes that the State contains. + * + * @param event A reference to the event to handle. + */ void BaseState::handle_event(sf::Event& event) { (void)event; } +/** + * This should handle all calculations and updates to sprites before showing them. + * It should also run the logic to handle whether the WindowState changes. If it + * does need to change, then use the passed in reference to `next_state` and change it + * to the state to move to. By default it should always be WindowStates::NONE when passed in. + * + * @param next_state A reference to the next state variable. When changed the FSM changes states. + */ void BaseState::update(WindowStates& next_state) { (void)next_state; } +/** + * This should display all visuals to the screen. Use the `window` object passed + * directly to the BaseState to draw it. + * + * Also do not include any `window.clear()` or `window.display()` here, as that is + * done in main.py. + */ void BaseState::show() -{ -} \ No newline at end of file +{} \ No newline at end of file diff --git a/src/WindowStates/State.hpp b/src/WindowStates/State.hpp index f196c3b..269bc2b 100644 --- a/src/WindowStates/State.hpp +++ b/src/WindowStates/State.hpp @@ -1,6 +1,11 @@ #ifndef BaseState_H #define BaseState_H +/** + * This is dictates all options for the WindowState FSM. + * The NONE option means that the current state should remain the same, + * while other states mean that the gameloop should stop and switch to a different state. + */ enum WindowStates { NONE, diff --git a/src/main.cpp b/src/main.cpp index db26283..1b38238 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,10 +8,23 @@ sf::Clock deltatime_clock; float deltatime = 0.f; +/** + * This runs the main loop of each page. It takes in a certain WindowState class instance + * and runs the game loop as long as the window remains open. + * + * When the state updates, it is able to change the `next_state` variable. When this changes + * the game loop ends and the function returns the next state to move to. + * + * @tparam T This is dynamic type to act as a particular child of the BaseState class + * @param current_state The state object that inherits from BaseState + * @param window A reference to the RenderWindow object + * @return WindowStates The next state/page to go to + */ template WindowStates MainStateLoop(T current_state, sf::RenderWindow& window) { sf::Event event; + // When next_state is NONE then do not leave current state WindowStates next_state = WindowStates::NONE; while (next_state == WindowStates::NONE && window.isOpen()) { @@ -37,13 +50,18 @@ int main() { sf::RenderWindow window(sf::VideoMode(1920, 1080), "Game"); + // Here define all states that can be moved to in the program MenuState menu_state(window); GameState game_state(window); + // Begin the program in the MENU state WindowStates current_state = WindowStates::MENU; while (window.isOpen()) { window.setView(window.getDefaultView()); + // Depending on WindowState run gameloop with correct class instance + // Once gameloop ends, it will return the next state and then redo this switch + // statement with the new state. switch (current_state) { case WindowStates::GAME: From 5eaf88871a77b374a32296455dedcde9db7b916b Mon Sep 17 00:00:00 2001 From: Gregor Maclaine Date: Tue, 8 Feb 2022 14:41:08 +0000 Subject: [PATCH 13/20] Added some docs on the FSM --- docs/Window FSM.md | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 docs/Window FSM.md diff --git a/docs/Window FSM.md b/docs/Window FSM.md new file mode 100644 index 0000000..7490677 --- /dev/null +++ b/docs/Window FSM.md @@ -0,0 +1,72 @@ +# Window Finite State Machine + +To make the game engine usable and scalable, there needed to be the option to split functionality into different pages and files, such as the menu and the game itself. Therefore a **finite state machine** (hereafter FSM) is needed to keep track of what state the program is currently in and to provide methods of transitioning from different states. + +The primary logic for the FSM is held in the `main.cpp` file as it runs the main game loop and the high-level process of the program. This file has two main functions: **the gameloop** & **the stateloop**. Below shows some code for the gameloop: + +```c++ +template +WindowStates MainStateLoop(T current_state, sf::RenderWindow& window) +{ + sf::Event event; + // When next_state is NONE then do not leave current state + WindowStates next_state = WindowStates::NONE; + while (next_state == WindowStates::NONE && window.isOpen()) + { + deltatime = deltatime_clock.restart().asSeconds() * 450.f; + while (window.pollEvent(event)) + { + if (event.type == sf::Event::Closed) + window.close(); + + current_state.handle_event(event); + } + + current_state.update(next_state); + + window.clear(); + current_state.show(); + window.display(); + } + return next_state; +}; +``` + +The above code makes use of the `template <>` c++ feature which allows a function to take in an object of any type and just assume that it has the correct interface (functions). This means that states can do the same process even when represented as different classes such as the `GameState` and the `MenuState`. + +The function then initialises some variables and begins the gameloop. It runs as long as the window is open or `next_state` is changed. `next_state` pretty much always takes the value of NONE, as that means that no state transitions should occur. + +When `next_state` changes, we see that the gameloop will terminate and the new state will be returned by the function. Then it will move back to the state loop shown here: + +```c++ +// Here define all states that can be moved to in the program +MenuState menu_state(window); +GameState game_state(window); + +// Begin the program in the MENU state +WindowStates current_state = WindowStates::MENU; +while (window.isOpen()) +{ + window.setView(window.getDefaultView()); + // Depending on WindowState run gameloop with correct class instance + // Once gameloop ends, it will return the next state and then redo this switch + // statement with the new state. + switch (current_state) + { + case WindowStates::GAME: + current_state = MainStateLoop(game_state, window); + break; + + default: + std::cout << "Error: Window State is not defined - Defaulting to menu" << std::endl; + + case WindowStates::MENU: + current_state = MainStateLoop(menu_state, window); + break; + } +} +``` + +Here you can see the stateloop, which stays open as long as the window is open. It starts by resetting the window view, and then looks and the current state, which at the start is set the MENU. + +Depending on the current state it will run the `MainStateLoop` function which holds the gameloop on a particular state object. Once the gameloop ends, it will return the new state and that will be set to current_state. From 16f4c26dea86f03b5422cec1825207fee95d8349 Mon Sep 17 00:00:00 2001 From: Alan Xu Date: Wed, 9 Feb 2022 15:58:25 +0000 Subject: [PATCH 14/20] Fixed bugs to work on windows --- .vscode/settings.json | 1 + src/Menu/Button.cpp | 2 +- src/main.cpp | 9 +++++---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index c61e501..61b797d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -109,6 +109,7 @@ "stack": "cpp", "__availability": "cpp" }, + "terminal.integrated.automationShell.windows": "C:/Program Files/Git/bin/bash.exe", "terminal.integrated.env.windows": { "Path": "C:/mingw32/bin;C:/SFML-2.5.1/bin" }, diff --git a/src/Menu/Button.cpp b/src/Menu/Button.cpp index 4c2c0d5..e906439 100644 --- a/src/Menu/Button.cpp +++ b/src/Menu/Button.cpp @@ -45,7 +45,7 @@ void MenuButton::set_details(std::string _text, sf::Vector2f _pos, sf::Vector2f pos.y + size.y / 2 - tsize.height / 2 - 15)); update_sprite(_pos, _size); -}; +} void MenuButton::draw(sf::RenderWindow& window) { diff --git a/src/main.cpp b/src/main.cpp index 1b38238..40928c4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -44,7 +44,7 @@ WindowStates MainStateLoop(T current_state, sf::RenderWindow& window) window.display(); } return next_state; -}; +} int main() { @@ -68,12 +68,13 @@ int main() current_state = MainStateLoop(game_state, window); break; - default: - std::cout << "Error: Window State is not defined - Defaulting to menu" << std::endl; - case WindowStates::MENU: current_state = MainStateLoop(menu_state, window); break; + + default: + std::cout << "Error: Window State is not defined - Defaulting to menu" << std::endl; + break; } } From 62a27500b14e11209eb46474fc3bc093c63b4136 Mon Sep 17 00:00:00 2001 From: Alan Xu Date: Wed, 9 Feb 2022 16:05:34 +0000 Subject: [PATCH 15/20] Fixed hitbox always showing bug on windows --- src/Game/Game.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Game/Game.hpp b/src/Game/Game.hpp index 9f930a0..ce70877 100644 --- a/src/Game/Game.hpp +++ b/src/Game/Game.hpp @@ -25,7 +25,7 @@ class Game public: sf::View player_view; - bool show_hitboxes; + bool show_hitboxes = false; Game(sf::RenderWindow& window); From c5f1c485ce6d77a87f8b12ccb003a5ecae8dfa02 Mon Sep 17 00:00:00 2001 From: Gregor Maclaine Date: Sat, 12 Feb 2022 16:56:11 +0000 Subject: [PATCH 16/20] Sprites now don't clip through platforms during window resize --- src/main.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 40928c4..a9753f1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,16 +23,33 @@ float deltatime = 0.f; template WindowStates MainStateLoop(T current_state, sf::RenderWindow& window) { + /** + * When the screen resizes, it runs the event sf::Event::Resized. However this causes deltatime + * to be much larger than it should be once it has resized, causing entities to clips through others. + * Therefore it records if it is resizing, and if so sets deltatime to 0 for next gameloop iteration. + */ + bool is_resizing = false; + sf::Event event; // When next_state is NONE then do not leave current state WindowStates next_state = WindowStates::NONE; while (next_state == WindowStates::NONE && window.isOpen()) { deltatime = deltatime_clock.restart().asSeconds() * 450.f; + if (is_resizing) + { + deltatime = 0; + is_resizing = false; + } + while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) window.close(); + else if (event.type == sf::Event::Resized) + { + is_resizing = true; + } current_state.handle_event(event); } From 497b1c0a5cb4448fb352ea595c58a4480ef94d34 Mon Sep 17 00:00:00 2001 From: Gregor Maclaine Date: Sat, 12 Feb 2022 17:30:44 +0000 Subject: [PATCH 17/20] Separated deltatime checker into separate file --- src/Utils/DeltatimeChecker.cpp | 31 +++++++++++++++++++++++++++++++ src/Utils/Utils.hpp | 18 ++++++++++++++++++ src/main.cpp | 17 ++--------------- 3 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 src/Utils/DeltatimeChecker.cpp create mode 100644 src/Utils/Utils.hpp diff --git a/src/Utils/DeltatimeChecker.cpp b/src/Utils/DeltatimeChecker.cpp new file mode 100644 index 0000000..a374303 --- /dev/null +++ b/src/Utils/DeltatimeChecker.cpp @@ -0,0 +1,31 @@ +#include "Utils/Utils.hpp" +#include + +// The last 5 deltatime values +std::array deltatime_history = {}; + +// Where the new deltatime value should be saved in the history array +int deltatime_history_index = 0; + +bool does_deltatime_seem_wrong(float new_deltatime) +{ + // Copy the history array so that it can be sorted + std::array history_copy = deltatime_history; + + // Save the new deltatime value + deltatime_history[deltatime_history_index] = new_deltatime; + + // Update the index + deltatime_history_index = (deltatime_history_index + 1) % 5; + + // If 5 values have not been recorded yet, assume deltatime is valid + if (deltatime_history[4] == 0.f) + return false; + + // Sort array to find median + std::sort(history_copy.begin(), history_copy.end()); + const float median = history_copy[2]; + + // Return whether new value is anomalous + return median * 3 < new_deltatime; +} diff --git a/src/Utils/Utils.hpp b/src/Utils/Utils.hpp new file mode 100644 index 0000000..5b6f5e5 --- /dev/null +++ b/src/Utils/Utils.hpp @@ -0,0 +1,18 @@ +#ifndef Utils_H +#define Utils_H + +/** + * @brief Takes in the new deltatime value and checks whether it is anomalous. + * + * Sometimes there is an extended period of time between gameloop iterations, causing an abnormally + * large deltatime. This causes sprites to clip through others. Therefore this func records a small history + * of the deltatime and checks if a new one is abnormal. + * + * Abnormal is calculated if the new value is greater than triple the median. + * + * @param new_deltatime + * @return Whether the deltatime is anomalous + */ +bool does_deltatime_seem_wrong(float new_deltatime); + +#endif diff --git a/src/main.cpp b/src/main.cpp index a9753f1..6c3882d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,6 +2,7 @@ #include "FrameRate.hpp" #include "Player.hpp" #include "StaticSprite.hpp" +#include "Utils/Utils.hpp" #include "WindowStates/GameState.hpp" #include "WindowStates/MenuState.hpp" @@ -23,33 +24,19 @@ float deltatime = 0.f; template WindowStates MainStateLoop(T current_state, sf::RenderWindow& window) { - /** - * When the screen resizes, it runs the event sf::Event::Resized. However this causes deltatime - * to be much larger than it should be once it has resized, causing entities to clips through others. - * Therefore it records if it is resizing, and if so sets deltatime to 0 for next gameloop iteration. - */ - bool is_resizing = false; - sf::Event event; // When next_state is NONE then do not leave current state WindowStates next_state = WindowStates::NONE; while (next_state == WindowStates::NONE && window.isOpen()) { deltatime = deltatime_clock.restart().asSeconds() * 450.f; - if (is_resizing) - { + if (does_deltatime_seem_wrong(deltatime)) deltatime = 0; - is_resizing = false; - } while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) window.close(); - else if (event.type == sf::Event::Resized) - { - is_resizing = true; - } current_state.handle_event(event); } From 3ca3c0206c34caafe92f6d60ad33976ddd72d5c2 Mon Sep 17 00:00:00 2001 From: Gregor Maclaine Date: Sat, 12 Feb 2022 17:39:48 +0000 Subject: [PATCH 18/20] Increased certainty of deltatime anomaly & fixed enemies clipping through ground on gamestart --- src/Game/Game.cpp | 4 ++-- src/Utils/DeltatimeChecker.cpp | 2 +- src/Utils/Utils.hpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 721e9c5..7ac7f0a 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -13,8 +13,8 @@ Game::Game(sf::RenderWindow& _window) : StaticSprite("assets/platform.png", sf::Vector2f(2100.f, 500.f), sf::Vector2f(760.f, 107.f)) }, enemies { - Enemy(sf::Vector2f(0.f, 250.f), sf::Vector2f(215.f, 258.f)), - Enemy(sf::Vector2f(2700.f, 250.f), sf::Vector2f(215.f, 258.f)) + Enemy(sf::Vector2f(0.f, -100.f), sf::Vector2f(215.f, 258.f)), + Enemy(sf::Vector2f(2700.f, -100.f), sf::Vector2f(215.f, 258.f)) }, player_view { sf::FloatRect(0, 0, window.getSize().x, window.getSize().y) } { diff --git a/src/Utils/DeltatimeChecker.cpp b/src/Utils/DeltatimeChecker.cpp index a374303..dc96db8 100644 --- a/src/Utils/DeltatimeChecker.cpp +++ b/src/Utils/DeltatimeChecker.cpp @@ -27,5 +27,5 @@ bool does_deltatime_seem_wrong(float new_deltatime) const float median = history_copy[2]; // Return whether new value is anomalous - return median * 3 < new_deltatime; + return median * 30 < new_deltatime; } diff --git a/src/Utils/Utils.hpp b/src/Utils/Utils.hpp index 5b6f5e5..830de13 100644 --- a/src/Utils/Utils.hpp +++ b/src/Utils/Utils.hpp @@ -8,7 +8,7 @@ * large deltatime. This causes sprites to clip through others. Therefore this func records a small history * of the deltatime and checks if a new one is abnormal. * - * Abnormal is calculated if the new value is greater than triple the median. + * Abnormal is calculated if the new value is greater than 30x the median. * * @param new_deltatime * @return Whether the deltatime is anomalous From ed00e4e8dca8561d7b05d0284333193a6091c72e Mon Sep 17 00:00:00 2001 From: Gregor Maclaine Date: Sun, 13 Feb 2022 00:18:40 +0000 Subject: [PATCH 19/20] Hopefully fixed warning in vscode settings from deprecated key --- .vscode/settings.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 61b797d..9f5e95c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -109,7 +109,9 @@ "stack": "cpp", "__availability": "cpp" }, - "terminal.integrated.automationShell.windows": "C:/Program Files/Git/bin/bash.exe", + "terminal.integrated.automationProfile.windows": { + "path": "C:/Program Files/Git/bin/bash.exe", + }, "terminal.integrated.env.windows": { "Path": "C:/mingw32/bin;C:/SFML-2.5.1/bin" }, From 9585f85c221960af9a2a312ca727b20e03cac123 Mon Sep 17 00:00:00 2001 From: Gregor Maclaine Date: Tue, 15 Feb 2022 04:46:34 +0000 Subject: [PATCH 20/20] Changed enemies and platforms to std::vector from basic C array std::vector is dynamic so it can be freely added to, which will be important later on. It's also much easier to iterate through. I needed the vectors to be of the class pointers as sometimes (by that I mean all the time) the textures of the sprites would unload since the vector would keep trying to move the memory around which would break the reference between the texture and the sprite causing it to show a tan rectangle instead of the actual picture. --- src/Enemy.cpp | 10 ++++------ src/Enemy.hpp | 2 +- src/Game/Game.cpp | 34 ++++++++++++++++------------------ src/Game/Game.hpp | 4 ++-- src/Player.cpp | 8 ++++---- src/Player.hpp | 2 +- src/StaticSprite.cpp | 3 +-- 7 files changed, 29 insertions(+), 34 deletions(-) diff --git a/src/Enemy.cpp b/src/Enemy.cpp index 01a8de4..87f9d11 100644 --- a/src/Enemy.cpp +++ b/src/Enemy.cpp @@ -11,18 +11,16 @@ Enemy::Enemy() : Sprite { "assets/enemy.png", sf::Vector2f(), sf::Vector2f() } {} -void Enemy::updatePosition(StaticSprite* platforms, sf::Vector2f player_pos) +void Enemy::updatePosition(std::vector& platforms, sf::Vector2f player_pos) { float speed = 0.4f; const float horiz_vel = player_pos.x > pos.x ? speed : -speed; update(horiz_vel); - for (unsigned int i = 0; i < 3; i++) + for (StaticSprite* platform : platforms) { - if (overlaps(platforms[i])) - { - correctHitboxOverlap(platforms[i]); - } + if (overlaps(*platform)) + correctHitboxOverlap(*platform); } sprite.setPosition(pos); diff --git a/src/Enemy.hpp b/src/Enemy.hpp index 39ee5fa..cdccdec 100644 --- a/src/Enemy.hpp +++ b/src/Enemy.hpp @@ -21,7 +21,7 @@ class Enemy : public Hitbox, public Sprite Enemy(); // Updates the position of the sprite - void updatePosition(StaticSprite* platforms, sf::Vector2f player_pos); + void updatePosition(std::vector& platforms, sf::Vector2f player_pos); // Force sets the position of the sprites void setPosition(sf::Vector2f _pos); }; diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 7ac7f0a..cf36c42 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -1,5 +1,4 @@ #include "Game/Game.hpp" -#include "WindowStates/State.hpp" /** * Initialise all objects and classes inside the game @@ -8,13 +7,13 @@ Game::Game(sf::RenderWindow& _window) : window { _window }, player { sf::Vector2f(500.f, 0.f), sf::Vector2f(215.f, 258.f) }, platforms { - StaticSprite("assets/platform.png", sf::Vector2f(10.f, 500.f), sf::Vector2f(760.f, 107.f)), - StaticSprite("assets/platform.png", sf::Vector2f(1100.f, 100.f), sf::Vector2f(760.f, 107.f)), - StaticSprite("assets/platform.png", sf::Vector2f(2100.f, 500.f), sf::Vector2f(760.f, 107.f)) + new StaticSprite("assets/platform.png", sf::Vector2f(10.f, 500.f), sf::Vector2f(760.f, 107.f)), + new StaticSprite("assets/platform.png", sf::Vector2f(1100.f, 100.f), sf::Vector2f(760.f, 107.f)), + new StaticSprite("assets/platform.png", sf::Vector2f(2100.f, 500.f), sf::Vector2f(760.f, 107.f)) }, enemies { - Enemy(sf::Vector2f(0.f, -100.f), sf::Vector2f(215.f, 258.f)), - Enemy(sf::Vector2f(2700.f, -100.f), sf::Vector2f(215.f, 258.f)) + new Enemy(sf::Vector2f(0.f, -100.f), sf::Vector2f(215.f, 258.f)), + new Enemy(sf::Vector2f(2700.f, -100.f), sf::Vector2f(215.f, 258.f)) }, player_view { sf::FloatRect(0, 0, window.getSize().x, window.getSize().y) } { @@ -31,8 +30,8 @@ void Game::reset_positions(bool hard_reset) player.setDetails(sf::Vector2f(500.f, 0.f), player.size); if (hard_reset) { - enemies[0].setPosition(sf::Vector2f(0.f, 250.f)); - enemies[1].setPosition(sf::Vector2f(2700.f, 250.f)); + enemies[0]->setPosition(sf::Vector2f(0.f, 250.f)); + enemies[1]->setPosition(sf::Vector2f(2700.f, 250.f)); } } @@ -57,10 +56,10 @@ void Game::update(WindowStates& next_state) player.updatePosition(platforms); - for (unsigned int i = 0; i < 2; i++) + for (Enemy* enemy : enemies) { - enemies[i].updatePosition(platforms, player.pos); - player.handleCollide(enemies[i]); + enemy->updatePosition(platforms, player.pos); + player.handleCollide(*enemy); } player.updateHealth(); @@ -78,21 +77,20 @@ void Game::moveViewToPlayer() void Game::draw() { - unsigned int i; - for (i = 0; i < 2; i++) + for (Enemy* enemy : enemies) { - enemies[i].draw(window); + enemy->draw(window); if (show_hitboxes) - window.draw(enemies[i].get_hitbox_outline()); + window.draw(enemy->get_hitbox_outline()); } - for (i = 0; i < 3; i++) + for (StaticSprite* platform : platforms) { - platforms[i].draw(window); + platform->draw(window); if (show_hitboxes) - window.draw(platforms[i].get_hitbox_outline()); + window.draw(platform->get_hitbox_outline()); } player.draw(window); diff --git a/src/Game/Game.hpp b/src/Game/Game.hpp index ce70877..47285a9 100644 --- a/src/Game/Game.hpp +++ b/src/Game/Game.hpp @@ -20,8 +20,8 @@ class Game FrameRateTracker frame_tracker; Player player; - StaticSprite platforms[3]; - Enemy enemies[2]; + std::vector platforms; + std::vector enemies; public: sf::View player_view; diff --git a/src/Player.cpp b/src/Player.cpp index 80dfd4a..0f38a4e 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -43,18 +43,18 @@ float Player::getHorizontalMovement() return speed * (held_keys.at(sf::Keyboard::D) - held_keys.at(sf::Keyboard::A)); } -void Player::updatePosition(StaticSprite* platforms) +void Player::updatePosition(std::vector& platforms) { update(getHorizontalMovement()); isGrounded = false; CollisionFix fix; - for (unsigned int i = 0; i < 3; i++) + for (StaticSprite* platform : platforms) { - if (overlaps(platforms[i])) + if (overlaps(*platform)) { - fix = correctHitboxOverlap(platforms[i]); + fix = correctHitboxOverlap(*platform); if (fix.h1_direction() == Direction::up) { jumpsLeft = maxJumps; diff --git a/src/Player.hpp b/src/Player.hpp index 9555ac4..3292df2 100644 --- a/src/Player.hpp +++ b/src/Player.hpp @@ -45,7 +45,7 @@ class Player : public Hitbox, public Sprite // Calculates the velocity based on what keys are pressed down float getHorizontalMovement(); // Updates the position of the sprite - void updatePosition(StaticSprite* platforms); + void updatePosition(std::vector& platforms); // Handled when space is pressed void handleJump(); diff --git a/src/StaticSprite.cpp b/src/StaticSprite.cpp index 95b843f..55b4620 100644 --- a/src/StaticSprite.cpp +++ b/src/StaticSprite.cpp @@ -3,5 +3,4 @@ StaticSprite::StaticSprite(std::string texture_name, sf::Vector2f _pos, sf::Vector2f target_size) : Hitbox { _pos, target_size }, Sprite { texture_name, _pos, target_size } -{ -} +{}