--- /dev/null
+#include "Ball.h"
+
+#include <random>
+#include <iostream>
+
+using namespace std;
+
+/*
+ * One way to create variables, functions and classes
+ * which are only visible in one file is by using an
+ * anonymous namespace (that is, a namespace which
+ * has no name).
+ *
+ * This will ensure that no other file will get
+ * access to these variables.
+ */
+namespace
+{
+ /*
+ * an engine which generates random numbers
+ */
+ random_device rd { };
+
+ /*
+ * wrappers which defines various ranges
+ * we want to generate numbers in.
+ */
+
+ // used to randomly choose what sprite to use
+ uniform_int_distribution<unsigned> index { 0, 1 };
+
+ // randomly choose a radius
+ uniform_real_distribution<float> radius { 10, 50 };
+
+ // randomly choose a velocity direction
+ uniform_real_distribution<float> angle { 0, 2*3.14 };
+
+ // randomly choose a speed for our ball
+ uniform_real_distribution<float> length { 0.5, 8.0 };
+}
+
+/*
+ * This constructor uses some basic trigonometry
+ * to create a velocity vector.
+ */
+//Ball :: Ball (Spritesheet & sheet,
+// float x,
+// float y)
+// : sprite { sheet.get_sprite (0, index (rd)) },
+// velocity { }
+//{
+// float direction { angle (rd) };
+// float speed { length (rd) };
+//
+// velocity = sf::Vector2f { speed * cos (direction),
+// speed * sin (direction) };
+//
+// /* position the ball, and make sure that we place
+// * the center of the ball where the mouse clicked */
+// auto sprite_size { sheet.sprite_size () };
+// sprite.setPosition (x, y);
+// sprite.setOrigin (sprite_size.x / 2, sprite_size.y / 2);
+//}
+
+Ball :: Ball (float x,
+ float y)
+ :
+ sprite{radius(rd)}, velocity { }
+{
+ float direction { angle (rd) };
+ float speed { length (rd) };
+
+ velocity = sf::Vector2f { speed * cos (direction),
+ speed * sin (direction) };
+
+ /* position the ball, and make sure that we place
+ * the center of the ball where the mouse clicked */
+
+ // Create a sprite
+ float sprite_size { sprite.getRadius () };
+ sprite.setPosition (x, y);
+ sprite.setOrigin (sprite_size / 2, sprite_size / 2);
+}
+
+void Ball :: update ()
+{
+ // move the sprite according to the velocity
+ sprite.move (velocity);
+}
+
+void Ball :: render (sf::RenderTarget & target)
+{
+ // draw the sprite
+ target.draw (sprite);
+}
+
+sf::FloatRect Ball :: bounds () const
+{
+ // get the hitbox of the sprite
+ return sprite.getGlobalBounds ();
+}
+++ /dev/null
-#include "Ball.h"
-
-#include <random>
-#include <iostream>
-
-using namespace std;
-
-/*
- * One way to create variables, functions and classes
- * which are only visible in one file is by using an
- * anonymous namespace (that is, a namespace which
- * has no name).
- *
- * This will ensure that no other file will get
- * access to these variables.
- */
-namespace
-{
- /*
- * an engine which generates random numbers
- */
- random_device rd { };
-
- /*
- * wrappers which defines various ranges
- * we want to generate numbers in.
- */
-
- // used to randomly choose what sprite to use
- uniform_int_distribution<unsigned> index { 0, 1 };
-
- // randomly choose a radius
- uniform_real_distribution<float> radius { 10, 50 };
-
- // randomly choose a velocity direction
- uniform_real_distribution<float> angle { 0, 2*3.14 };
-
- // randomly choose a speed for our ball
- uniform_real_distribution<float> length { 0.5, 8.0 };
-}
-
-/*
- * This constructor uses some basic trigonometry
- * to create a velocity vector.
- */
-//Ball :: Ball (Spritesheet & sheet,
-// float x,
-// float y)
-// : sprite { sheet.get_sprite (0, index (rd)) },
-// velocity { }
-//{
-// float direction { angle (rd) };
-// float speed { length (rd) };
-//
-// velocity = sf::Vector2f { speed * cos (direction),
-// speed * sin (direction) };
-//
-// /* position the ball, and make sure that we place
-// * the center of the ball where the mouse clicked */
-// auto sprite_size { sheet.sprite_size () };
-// sprite.setPosition (x, y);
-// sprite.setOrigin (sprite_size.x / 2, sprite_size.y / 2);
-//}
-
-Ball :: Ball (float x,
- float y)
- :
- sprite{radius(rd)}, velocity { }
-{
- float direction { angle (rd) };
- float speed { length (rd) };
-
- velocity = sf::Vector2f { speed * cos (direction),
- speed * sin (direction) };
-
- /* position the ball, and make sure that we place
- * the center of the ball where the mouse clicked */
-
- // Create a sprite
- float sprite_size { sprite.getRadius () };
- sprite.setPosition (x, y);
- sprite.setOrigin (sprite_size / 2, sprite_size / 2);
-}
-
-void Ball :: update ()
-{
- // move the sprite according to the velocity
- sprite.move (velocity);
-}
-
-void Ball :: render (sf::RenderTarget & target)
-{
- // draw the sprite
- target.draw (sprite);
-}
-
-sf::FloatRect Ball :: bounds () const
-{
- // get the hitbox of the sprite
- return sprite.getGlobalBounds ();
-}
--- /dev/null
+#include "constants.h"
+#include "Game.h"
+#include "Menu_State.h"
+#include "Game_State.h"
+
+using namespace sf;
+
+/*
+ * Initialize the window and the first state is Menu_State.
+ *
+ * The constructor of RenderWindow takes a 'VideoMode'
+ * which defines the width, height and bits per pixel
+ * (default 32), a title which should be visible in
+ * the titlebar of the windows, as well as a style flag.
+ * The style flag is a bit mask (i.e. a value where
+ * each bit represents a property) of properties we
+ * want our window to have. If we do not care,
+ * we can omitt this argument or use sf::Style::Default.
+ */
+Game :: Game (std::string const & title,
+ unsigned width,
+ unsigned height)
+ : window { VideoMode { width, height },
+ title, Style::Titlebar | Style::Close },
+ current_state{ MENU_STATE },
+ running { true }
+{
+ // Insert all sates you want in your game in the states map
+ states.insert(std::pair<int,
+ std::unique_ptr<State>>({MENU_STATE,
+ std::make_unique<Menu_State>()}));
+
+ states.insert(std::pair<int,
+ std::unique_ptr<State>>({GAME_STATE,
+ std::make_unique<Game_State>()}));
+}
+
+
+void Game :: start ()
+{
+ // The clock is used to measure of long each iteration took
+ // this is used to keep the framerate as steady as possible.
+ Clock clock { };
+ while ( running )
+ {
+ // Handle user events e.g. mouse click or key pressed
+ handle_events();
+
+ // Let the current state do its update
+ states.at(current_state) -> update();
+
+ /*
+ * clear fills the entire window with one color
+ * (by default black) thus overwriting everything
+ * that was drawn before.
+ *
+ * If we do not perform this step we allow for weird
+ * graphical artifacts to show up.
+ */
+ window.clear ();
+
+ // let the current state render itself onto the window
+ states.at(current_state) -> render(window);
+
+ /*
+ * No drawn pixels will be shown in the window
+ * until this function is called.
+ *
+ * All drawing operations are performed on a
+ * hidden buffer in memory, so if we want them
+ * to actually show up on the screen we have
+ * make sure that the window switches to drawing
+ * that buffer instead of its current one.
+ * (This technique is called 'double buffering')
+ */
+ window.display ();
+
+ /*
+ * When all logic and rendering has been performed
+ * we are now ready to update the current_state
+ */
+ current_state = states.at(current_state) -> get_next_state();
+
+ /*
+ * Wait if we still haven't reached the target
+ * time for a frame.
+ */
+ delay (clock);
+ }
+}
+
+
+void Game :: handle_events ()
+{
+ /*
+ * event is an object which contains all
+ * relevant information for an event that
+ * occured in the window (i.e. key-pressed,
+ * mouse clicks etc.).
+ *
+ * The function 'pollEvent' takes the next
+ * event in the event queue and places it
+ * in the 'event' variable so that we can
+ * read what that event was.
+ *
+ * While there are events in event queue
+ * 'pollEvent' will return true.
+ */
+ Event event;
+ while ( window.pollEvent (event) )
+ {
+ // Check if the window has been closed.
+ // This event fires whenever the user
+ // presses the X icon, or if the operating
+ // system kills it.
+ if ( event.type == Event::Closed )
+ running = false;
+
+ // send the event to 'state'
+ states.at(current_state) -> handle_event (event);
+ }
+}
+
+void Game :: delay (sf::Clock & clock) const
+{
+ sleep (milliseconds (1000.0 / fps) - clock.getElapsedTime ());
+ clock.restart ();
+}
+++ /dev/null
-#include "constants.h"
-#include "Game.h"
-#include "Menu_State.h"
-#include "Game_State.h"
-
-using namespace sf;
-
-/*
- * Initialize the window and the first state is Menu_State.
- *
- * The constructor of RenderWindow takes a 'VideoMode'
- * which defines the width, height and bits per pixel
- * (default 32), a title which should be visible in
- * the titlebar of the windows, as well as a style flag.
- * The style flag is a bit mask (i.e. a value where
- * each bit represents a property) of properties we
- * want our window to have. If we do not care,
- * we can omitt this argument or use sf::Style::Default.
- */
-Game :: Game (std::string const & title,
- unsigned width,
- unsigned height)
- : window { VideoMode { width, height },
- title, Style::Titlebar | Style::Close },
- current_state{ MENU_STATE },
- running { true }
-{
- // Insert all sates you want in your game in the states map
- states.insert(std::pair<int,
- std::unique_ptr<State>>({MENU_STATE,
- std::make_unique<Menu_State>()}));
-
- states.insert(std::pair<int,
- std::unique_ptr<State>>({GAME_STATE,
- std::make_unique<Game_State>()}));
-}
-
-
-void Game :: start ()
-{
- // The clock is used to measure of long each iteration took
- // this is used to keep the framerate as steady as possible.
- Clock clock { };
- while ( running )
- {
- // Handle user events e.g. mouse click or key pressed
- handle_events();
-
- // Let the current state do its update
- states.at(current_state) -> update();
-
- /*
- * clear fills the entire window with one color
- * (by default black) thus overwriting everything
- * that was drawn before.
- *
- * If we do not perform this step we allow for weird
- * graphical artifacts to show up.
- */
- window.clear ();
-
- // let the current state render itself onto the window
- states.at(current_state) -> render(window);
-
- /*
- * No drawn pixels will be shown in the window
- * until this function is called.
- *
- * All drawing operations are performed on a
- * hidden buffer in memory, so if we want them
- * to actually show up on the screen we have
- * make sure that the window switches to drawing
- * that buffer instead of its current one.
- * (This technique is called 'double buffering')
- */
- window.display ();
-
- /*
- * When all logic and rendering has been performed
- * we are now ready to update the current_state
- */
- current_state = states.at(current_state) -> get_next_state();
-
- /*
- * Wait if we still haven't reached the target
- * time for a frame.
- */
- delay (clock);
- }
-}
-
-
-void Game :: handle_events ()
-{
- /*
- * event is an object which contains all
- * relevant information for an event that
- * occured in the window (i.e. key-pressed,
- * mouse clicks etc.).
- *
- * The function 'pollEvent' takes the next
- * event in the event queue and places it
- * in the 'event' variable so that we can
- * read what that event was.
- *
- * While there are events in event queue
- * 'pollEvent' will return true.
- */
- Event event;
- while ( window.pollEvent (event) )
- {
- // Check if the window has been closed.
- // This event fires whenever the user
- // presses the X icon, or if the operating
- // system kills it.
- if ( event.type == Event::Closed )
- running = false;
-
- // send the event to 'state'
- states.at(current_state) -> handle_event (event);
- }
-}
-
-void Game :: delay (sf::Clock & clock) const
-{
- sleep (milliseconds (1000.0 / fps) - clock.getElapsedTime ());
- clock.restart ();
-}
--- /dev/null
+#include "Game_State.h"
+#include "constants.h"
+
+#include <iostream>
+
+using namespace sf;
+
+/*
+ * Check for mouse button presses.
+ *
+ * If a mouse button press is detected, when that
+ * mouse button is release we add a new ball to
+ * the screen at the mouse's location.
+ *
+ * This demonstrates how we can integrate the mouse
+ * into our project.
+ */
+void Game_State :: handle_event (Event event)
+{
+ if ( event.type == Event::MouseButtonReleased )
+ {
+ if ( event.mouseButton.button == Mouse::Button::Left )
+ {
+ balls.emplace_back (
+ // get the coordinates of the mouse right now
+ event.mouseButton.x,
+ event.mouseButton.y);
+ }
+ }
+ else if ( event.type == Event::KeyPressed )
+ {
+ if ( event.key.code == Keyboard::Key::Return )
+ end_game = true;
+ }
+}
+
+void Game_State :: update ()
+{
+ // Iterate over all balls and let
+ // them update themselves.
+ for ( auto & ball : balls )
+ ball.update ();
+}
+
+void Game_State :: render (RenderTarget & target)
+{
+ // Let each ball render itself onto the
+ // supplied RenderTarget
+ for ( auto & ball : balls )
+ ball.render (target);
+}
+
+/*
+ * If return was pressed, we jump back to MENU_STATE,
+ * otherwise we stay in this state GAME_STATE
+ */
+int Game_State :: get_next_state()
+{
+ if (end_game)
+ {
+ end_game = false;
+ return MENU_STATE;
+ }
+ return GAME_STATE;
+}
+
+/*
+ * If we want to remove all balls which are outside
+ * of the screen we need to iterate all balls and
+ * do two things for each ball:
+ * 1. Check if it is outside of the screen
+ * 2. If it is, make sure that we remove it from
+ * the vector.
+ *
+ * The first part can be solved in several ways.
+ * We can for instance implement our own logic
+ * for checking if a sprite is on the screen
+ * or not, or we can use some built-in functions
+ * in SFML.
+ *
+ * In this example we use the latter.
+ *
+ * We begin by getting the global bounds of each ball.
+ *
+ * A bounds is the smallest possible rectangle which
+ * covers the entire ball (these are basically the
+ * "hitboxes" of our balls).
+ *
+ * There are two kinds of bounds for each ball, a
+ * global bound and a local bound, the difference
+ * is where the (0, 0) coordinate is placed.
+ *
+ * In a global bound, (0, 0) referes to top-left
+ * corner of the window, while in a local bounds
+ * it referes to the origin of the ball (in this
+ * example, the center of the ball (see Ball.cpp
+ * for details)).
+ *
+ * Using the global bounds we can use the built-in
+ * 'intersects' function to check if the bounds
+ * intersects the screen. If it does, it is still
+ * visible, if not it is safe to remove.
+ *
+ * The second part is a bit trickier.
+ *
+ * A problem arises when we iterate over the
+ * balls and then remove one of them; the current
+ * index has been changed so we have now potentially
+ * skipped over an element.
+ *
+ * Example of how this might happen:
+ *
+ * Say that we are iterating over this list, with
+ * a standard index based for-loop (here ^ denotes
+ * the element we are currently looking at):
+ *
+ * 1 5 7 2 4 3
+ * ^
+ * Now say that we remove the 7, then we have:
+ *
+ * 1 5 2 4 3
+ * ^
+ * Note that ^ now points to the next element, but the
+ * same location as before, which might at first glance
+ * seem like what we exactly want. But we must not
+ * forget that the final step in a for loop is to step
+ * the index, so the next iteration will look like this:
+ *
+ * 1 5 2 4 3
+ * ^
+ * Which shows that we have skipped an element.
+ *
+ * This means that we have to be a bit more cleaver
+ * when removing elements from the list we are
+ * iterating.
+ *
+ * But we are in luck, we can use an iterator based
+ * for-loop, since erase (the function which removes
+ * elements from the vector) removes elements pointed
+ * to by iterators, and returns an iterator to the next
+ * element.
+ */
+void Game_State :: cleanup ()
+{
+ for ( auto it { std::begin (balls) }; it != std::end (balls); )
+ {
+ // get the global bounds of our current ball
+ auto bounds { it -> bounds () };
+ // get a rectangle representing the screen
+ FloatRect screen { 0, 0, screen_width, screen_height };
+ if ( !screen.intersects (bounds) )
+ it = balls.erase (it);
+ else
+ ++it;
+ }
+}
+++ /dev/null
-#include "Game_State.h"
-#include "constants.h"
-
-#include <iostream>
-
-using namespace sf;
-
-/*
- * Check for mouse button presses.
- *
- * If a mouse button press is detected, when that
- * mouse button is release we add a new ball to
- * the screen at the mouse's location.
- *
- * This demonstrates how we can integrate the mouse
- * into our project.
- */
-void Game_State :: handle_event (Event event)
-{
- if ( event.type == Event::MouseButtonReleased )
- {
- if ( event.mouseButton.button == Mouse::Button::Left )
- {
- balls.emplace_back (
- // get the coordinates of the mouse right now
- event.mouseButton.x,
- event.mouseButton.y);
- }
- }
- else if ( event.type == Event::KeyPressed )
- {
- if ( event.key.code == Keyboard::Key::Return )
- end_game = true;
- }
-}
-
-void Game_State :: update ()
-{
- // Iterate over all balls and let
- // them update themselves.
- for ( auto & ball : balls )
- ball.update ();
-}
-
-void Game_State :: render (RenderTarget & target)
-{
- // Let each ball render itself onto the
- // supplied RenderTarget
- for ( auto & ball : balls )
- ball.render (target);
-}
-
-/*
- * If return was pressed, we jump back to MENU_STATE,
- * otherwise we stay in this state GAME_STATE
- */
-int Game_State :: get_next_state()
-{
- if (end_game)
- {
- end_game = false;
- return MENU_STATE;
- }
- return GAME_STATE;
-}
-
-/*
- * If we want to remove all balls which are outside
- * of the screen we need to iterate all balls and
- * do two things for each ball:
- * 1. Check if it is outside of the screen
- * 2. If it is, make sure that we remove it from
- * the vector.
- *
- * The first part can be solved in several ways.
- * We can for instance implement our own logic
- * for checking if a sprite is on the screen
- * or not, or we can use some built-in functions
- * in SFML.
- *
- * In this example we use the latter.
- *
- * We begin by getting the global bounds of each ball.
- *
- * A bounds is the smallest possible rectangle which
- * covers the entire ball (these are basically the
- * "hitboxes" of our balls).
- *
- * There are two kinds of bounds for each ball, a
- * global bound and a local bound, the difference
- * is where the (0, 0) coordinate is placed.
- *
- * In a global bound, (0, 0) referes to top-left
- * corner of the window, while in a local bounds
- * it referes to the origin of the ball (in this
- * example, the center of the ball (see Ball.cpp
- * for details)).
- *
- * Using the global bounds we can use the built-in
- * 'intersects' function to check if the bounds
- * intersects the screen. If it does, it is still
- * visible, if not it is safe to remove.
- *
- * The second part is a bit trickier.
- *
- * A problem arises when we iterate over the
- * balls and then remove one of them; the current
- * index has been changed so we have now potentially
- * skipped over an element.
- *
- * Example of how this might happen:
- *
- * Say that we are iterating over this list, with
- * a standard index based for-loop (here ^ denotes
- * the element we are currently looking at):
- *
- * 1 5 7 2 4 3
- * ^
- * Now say that we remove the 7, then we have:
- *
- * 1 5 2 4 3
- * ^
- * Note that ^ now points to the next element, but the
- * same location as before, which might at first glance
- * seem like what we exactly want. But we must not
- * forget that the final step in a for loop is to step
- * the index, so the next iteration will look like this:
- *
- * 1 5 2 4 3
- * ^
- * Which shows that we have skipped an element.
- *
- * This means that we have to be a bit more cleaver
- * when removing elements from the list we are
- * iterating.
- *
- * But we are in luck, we can use an iterator based
- * for-loop, since erase (the function which removes
- * elements from the vector) removes elements pointed
- * to by iterators, and returns an iterator to the next
- * element.
- */
-void Game_State :: cleanup ()
-{
- for ( auto it { std::begin (balls) }; it != std::end (balls); )
- {
- // get the global bounds of our current ball
- auto bounds { it -> bounds () };
- // get a rectangle representing the screen
- FloatRect screen { 0, 0, screen_width, screen_height };
- if ( !screen.intersects (bounds) )
- it = balls.erase (it);
- else
- ++it;
- }
-}
--- /dev/null
+#include "Menu_State.h"
+
+#include <string>
+#include <stdexcept>
+
+using namespace sf;
+
+/*
+ * Create the welcome message using the font given in
+ * 'resources/fonts/font.ttf'.
+ *
+ * The first argument of the sf::Text constructor is what string
+ * it should draw, the second argument is what font should be used
+ * to draw the text and the final argument specifies the font-size
+ * (in pixels) of the text.
+ */
+Menu_State :: Menu_State ()
+ :play { false }
+{
+ std::string file = "resources/fonts/font.ttf";
+ if ( !font.loadFromFile (file) )
+ throw std::invalid_argument ("Unable to load font");
+ text = sf::Text{ "Press <Enter> to start", font, 16 };
+}
+
+/*
+ * check for the 'enter' key.
+ *
+ * If it has been pressed we want to change to a new state.
+ */
+void Menu_State :: handle_event (Event event)
+{
+ if ( event.type == Event::KeyPressed )
+ {
+ if ( event.key.code == Keyboard::Key::Return )
+ play = true;
+ }
+}
+
+
+void Menu_State :: update ()
+{
+
+}
+
+void Menu_State :: render (RenderTarget & target)
+{
+ auto bounds { text.getGlobalBounds () };
+ auto size { target.getSize () };
+
+ text.setPosition ((size.x - bounds.width) / 2,
+ (size.y - bounds.height) / 2);
+
+ target.draw (text);
+}
+
+/*
+ * If return has been pressed we change to the GAME_STATE, otherwise
+ * we stay in MENU_STATE
+ */
+int Menu_State :: get_next_state()
+{
+ if (play)
+ {
+ play = false;
+ return GAME_STATE;
+ }
+ else
+ {
+ return MENU_STATE;
+ }
+}
+
+++ /dev/null
-#include "Menu_State.h"
-
-#include <string>
-#include <stdexcept>
-
-using namespace sf;
-
-/*
- * Create the welcome message using the font given in
- * 'resources/fonts/font.ttf'.
- *
- * The first argument of the sf::Text constructor is what string
- * it should draw, the second argument is what font should be used
- * to draw the text and the final argument specifies the font-size
- * (in pixels) of the text.
- */
-Menu_State :: Menu_State ()
- :play { false }
-{
- std::string file = "resources/fonts/font.ttf";
- if ( !font.loadFromFile (file) )
- throw std::invalid_argument ("Unable to load font");
- text = sf::Text{ "Press <Enter> to start", font, 16 };
-}
-
-/*
- * check for the 'enter' key.
- *
- * If it has been pressed we want to change to a new state.
- */
-void Menu_State :: handle_event (Event event)
-{
- if ( event.type == Event::KeyPressed )
- {
- if ( event.key.code == Keyboard::Key::Return )
- play = true;
- }
-}
-
-
-void Menu_State :: update ()
-{
-
-}
-
-void Menu_State :: render (RenderTarget & target)
-{
- auto bounds { text.getGlobalBounds () };
- auto size { target.getSize () };
-
- text.setPosition ((size.x - bounds.width) / 2,
- (size.y - bounds.height) / 2);
-
- target.draw (text);
-}
-
-/*
- * If return has been pressed we change to the GAME_STATE, otherwise
- * we stay in MENU_STATE
- */
-int Menu_State :: get_next_state()
-{
- if (play)
- {
- play = false;
- return GAME_STATE;
- }
- else
- {
- return MENU_STATE;
- }
-}
-