intial implementation
This commit is contained in:
parent
87e1f863be
commit
e5e7028554
|
|
@ -0,0 +1,80 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <Util.h>
|
||||||
|
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
#include <imgui-SFML.h>
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <Random.h>
|
||||||
|
|
||||||
|
struct Ball
|
||||||
|
{
|
||||||
|
Ball(sf::Vector2f, sf::Vector2f);
|
||||||
|
|
||||||
|
sf::Vector2f pos;
|
||||||
|
sf::Vector2f previousPos{};
|
||||||
|
sf::Vector2f velocity;
|
||||||
|
Color color{sf::Color::Red};
|
||||||
|
bool alive{true};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Brick
|
||||||
|
{
|
||||||
|
Brick(sf::Vector2f);
|
||||||
|
|
||||||
|
sf::Vector2f pos;
|
||||||
|
Color color{sf::Color::White};
|
||||||
|
bool alive{true};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Player
|
||||||
|
{
|
||||||
|
Player();
|
||||||
|
|
||||||
|
sf::Vector2f pos;
|
||||||
|
sf::Vector2f previousPos{};
|
||||||
|
Color color{sf::Color::White};
|
||||||
|
float score{};
|
||||||
|
int lives{3};
|
||||||
|
bool left{false};
|
||||||
|
bool right{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
class Game
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Game();
|
||||||
|
|
||||||
|
void run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void imgui();
|
||||||
|
|
||||||
|
void render();
|
||||||
|
|
||||||
|
void input();
|
||||||
|
|
||||||
|
void collision();
|
||||||
|
|
||||||
|
void movement();
|
||||||
|
|
||||||
|
void updateEntities();
|
||||||
|
|
||||||
|
void checkEndGame();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
sf::Clock clock;
|
||||||
|
sf::RenderWindow window;
|
||||||
|
|
||||||
|
Player player;
|
||||||
|
std::vector<Brick> bricks;
|
||||||
|
std::vector<Brick> specialBricks;
|
||||||
|
std::vector<Ball> balls;
|
||||||
|
std::vector<sf::Vector2f> ballsToAdd;
|
||||||
|
sf::CircleShape tempCircle;
|
||||||
|
sf::RectangleShape tempRect;
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef RANDOM_MT_H
|
||||||
|
#define RANDOM_MT_H
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
// This header-only Random namespace implements a self-seeding Mersenne Twister.
|
||||||
|
// Requires C++17 or newer.
|
||||||
|
// It can be #included into as many code files as needed (The inline keyword avoids ODR violations)
|
||||||
|
// Freely redistributable, courtesy of learncpp.com (https://www.learncpp.com/cpp-tutorial/global-random-numbers-random-h/)
|
||||||
|
namespace Random
|
||||||
|
{
|
||||||
|
// Returns a seeded Mersenne Twister
|
||||||
|
// Note: we'd prefer to return a std::seed_seq (to initialize a std::mt19937), but std::seed can't be copied, so it can't be returned by value.
|
||||||
|
// Instead, we'll create a std::mt19937, seed it, and then return the std::mt19937 (which can be copied).
|
||||||
|
inline std::mt19937 generate()
|
||||||
|
{
|
||||||
|
std::random_device rd{};
|
||||||
|
|
||||||
|
// Create seed_seq with clock and 7 random numbers from std::random_device
|
||||||
|
std::seed_seq ss{
|
||||||
|
static_cast<std::seed_seq::result_type>(std::chrono::steady_clock::now().time_since_epoch().count()),
|
||||||
|
rd(), rd(), rd(), rd(), rd(), rd(), rd() };
|
||||||
|
|
||||||
|
return std::mt19937{ ss };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here's our global std::mt19937 object.
|
||||||
|
// The inline keyword means we only have one global instance for our whole program.
|
||||||
|
inline std::mt19937 mt{ generate() }; // generates a seeded std::mt19937 and copies it into our global object
|
||||||
|
|
||||||
|
// Generate a random int between [min, max] (inclusive)
|
||||||
|
// * also handles cases where the two arguments have different types but can be converted to int
|
||||||
|
inline int get(int min, int max)
|
||||||
|
{
|
||||||
|
return std::uniform_int_distribution{min, max}(mt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following function templates can be used to generate random numbers in other cases
|
||||||
|
|
||||||
|
// See https://www.learncpp.com/cpp-tutorial/function-template-instantiation/
|
||||||
|
// You can ignore these if you don't understand them
|
||||||
|
|
||||||
|
// Generate a random value between [min, max] (inclusive)
|
||||||
|
// * min and max must have the same type
|
||||||
|
// * return value has same type as min and max
|
||||||
|
// * Supported types:
|
||||||
|
// * short, int, long, long long
|
||||||
|
// * unsigned short, unsigned int, unsigned long, or unsigned long long
|
||||||
|
// Sample call: Random::get(1L, 6L); // returns long
|
||||||
|
// Sample call: Random::get(1u, 6u); // returns unsigned int
|
||||||
|
template <typename T>
|
||||||
|
T get(T min, T max)
|
||||||
|
{
|
||||||
|
return std::uniform_int_distribution<T>{min, max}(mt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a random value between [min, max] (inclusive)
|
||||||
|
// * min and max can have different types
|
||||||
|
// * return type must be explicitly specified as a template argument
|
||||||
|
// * min and max will be converted to the return type
|
||||||
|
// Sample call: Random::get<std::size_t>(0, 6); // returns std::size_t
|
||||||
|
// Sample call: Random::get<std::size_t>(0, 6u); // returns std::size_t
|
||||||
|
// Sample call: Random::get<std::int>(0, 6u); // returns int
|
||||||
|
template <typename R, typename S, typename T>
|
||||||
|
R get(S min, T max)
|
||||||
|
{
|
||||||
|
return get<R>(static_cast<R>(min), static_cast<R>(max));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
|
||||||
|
struct Color
|
||||||
|
{
|
||||||
|
Color() = default;
|
||||||
|
Color(float r_in, float g_in, float b_in, float a_in = 255)
|
||||||
|
: r(r_in)
|
||||||
|
, g(g_in)
|
||||||
|
, b(b_in)
|
||||||
|
, a(a_in)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Color(sf::Color color_in)
|
||||||
|
{
|
||||||
|
r = (float)color_in.r / 255.f;
|
||||||
|
g = (float)color_in.g / 255.f;
|
||||||
|
b = (float)color_in.b / 255.f;
|
||||||
|
a = (float)color_in.a / 255.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float r{};
|
||||||
|
float g{};
|
||||||
|
float b{};
|
||||||
|
float a{};
|
||||||
|
|
||||||
|
sf::Color sfml()
|
||||||
|
{
|
||||||
|
return sf::Color{uint8_t(r * 255), uint8_t(g * 255), uint8_t(b * 255), uint8_t(a * 255)};
|
||||||
|
}
|
||||||
|
|
||||||
|
float* imgui()
|
||||||
|
{
|
||||||
|
return &r;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace global
|
||||||
|
{
|
||||||
|
inline sf::Vector2f playerSize{500, 25};
|
||||||
|
inline sf::Vector2f playerHalfSize{playerSize / 2.f};
|
||||||
|
inline sf::Vector2f brickSize{50, 10};
|
||||||
|
inline sf::Vector2f brickHalfSize{brickSize / 2.f};
|
||||||
|
inline int totalSpecialBricks{3};
|
||||||
|
inline int rowSize{8};
|
||||||
|
inline int columnSize{5};
|
||||||
|
inline int totalBricks{rowSize * columnSize};
|
||||||
|
inline float ballRadius{5.0f};
|
||||||
|
inline float ballMaxSpeed{10};
|
||||||
|
inline float playerSpeed{10};
|
||||||
|
inline sf::Vector2f playerStartPos{700,700};
|
||||||
|
inline bool windowCollasped{false};
|
||||||
|
}
|
||||||
32
premake5.lua
32
premake5.lua
|
|
@ -29,18 +29,20 @@ workspace "breakout"
|
||||||
cdialect "C17"
|
cdialect "C17"
|
||||||
systemversion "latest"
|
systemversion "latest"
|
||||||
kind "WindowedApp"
|
kind "WindowedApp"
|
||||||
|
targetname "breakout"
|
||||||
|
|
||||||
files
|
files
|
||||||
{
|
{
|
||||||
"src/**.cpp",
|
"src/**.cpp",
|
||||||
"include/**.h",
|
"include/**.h",
|
||||||
"include/**.hpp",
|
"include/**.hpp",
|
||||||
"vendor/imgui/imgui.cpp",
|
"vendor/imgui/imgui.cpp",
|
||||||
"vendor/imgui/imgui_draw.cpp",
|
"vendor/imgui/imgui_draw.cpp",
|
||||||
"vendor/imgui/imgui_tables.cpp",
|
"vendor/imgui/imgui_tables.cpp",
|
||||||
"vendor/imgui/imgui_widgets.cpp",
|
"vendor/imgui/imgui_widgets.cpp",
|
||||||
"vendor/imgui/imgui-SFML.cpp"
|
"vendor/imgui/imgui-SFML.cpp"
|
||||||
}
|
}
|
||||||
|
|
||||||
--visual studio--
|
--visual studio--
|
||||||
filter {"action:vs*", "system:windows"}
|
filter {"action:vs*", "system:windows"}
|
||||||
targetdir (vs_bindir)
|
targetdir (vs_bindir)
|
||||||
|
|
@ -63,7 +65,7 @@ workspace "breakout"
|
||||||
{
|
{
|
||||||
"src",
|
"src",
|
||||||
include_dir,
|
include_dir,
|
||||||
vs_sfmldir .. "/include",
|
sfmldir .. "/include",
|
||||||
imguidir
|
imguidir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -140,12 +142,10 @@ workspace "breakout"
|
||||||
defines {"LOG_ENABLE", "GAME_DEBUG"}
|
defines {"LOG_ENABLE", "GAME_DEBUG"}
|
||||||
symbols "on"
|
symbols "on"
|
||||||
runtime "Debug"
|
runtime "Debug"
|
||||||
targetname "breakout"
|
|
||||||
|
|
||||||
filter "configurations:release"
|
filter "configurations:release"
|
||||||
defines {"GAME_RELEASE"}
|
defines {"GAME_RELEASE"}
|
||||||
optimize "Speed"
|
optimize "Speed"
|
||||||
inlining "Auto"
|
inlining "Auto"
|
||||||
symbols "off"
|
symbols "off"
|
||||||
runtime "Release"
|
runtime "Release"
|
||||||
targetname "breakout"
|
|
||||||
|
|
@ -0,0 +1,400 @@
|
||||||
|
#include <Game.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
sf::Vector2f getOverlap(sf::FloatRect first, sf::FloatRect second)
|
||||||
|
{
|
||||||
|
sf::Vector2f result;
|
||||||
|
sf::Vector2f delta;
|
||||||
|
delta.x = std::abs(second.position.x - first.position.x);
|
||||||
|
delta.y = std::abs(second.position.y - first.position.y);
|
||||||
|
|
||||||
|
result.x = (first.size.x + second.size.x) - delta.x;
|
||||||
|
result.y = (first.size.y + second.size.y) - delta.y;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
sf::Vector2f velocityInRandomDir(float speed_in)
|
||||||
|
{
|
||||||
|
bool upOrDown{(bool)Random::get(0,1)};
|
||||||
|
|
||||||
|
sf::Angle angle = sf::degrees((float)upOrDown ? Random::get(225, 315) : Random::get(45, 135));
|
||||||
|
|
||||||
|
return {speed_in * std::cos(angle.asRadians()), speed_in * std::sin(angle.asRadians())};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ball::Ball(sf::Vector2f position_in, sf::Vector2f vel_in)
|
||||||
|
: velocity(vel_in)
|
||||||
|
, pos(position_in)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Brick::Brick(sf::Vector2f position_in)
|
||||||
|
: pos(position_in)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Player::Player()
|
||||||
|
: pos(global::playerStartPos)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
Game::Game()
|
||||||
|
: player()
|
||||||
|
, window({sf::VideoMode({ 1920u, 1080u }), "breakout"})
|
||||||
|
{
|
||||||
|
window.setFramerateLimit(60);
|
||||||
|
|
||||||
|
if (!ImGui::SFML::Init(window))
|
||||||
|
return;
|
||||||
|
|
||||||
|
tempCircle.setOrigin({global::ballRadius, global::ballRadius});
|
||||||
|
|
||||||
|
bricks.reserve(global::totalBricks);
|
||||||
|
bricks.emplace_back(sf::Vector2f{200, 100});
|
||||||
|
specialBricks.reserve(global::totalSpecialBricks);
|
||||||
|
balls.reserve(10);
|
||||||
|
ballsToAdd.reserve(10);
|
||||||
|
|
||||||
|
ballsToAdd.emplace_back(global::playerStartPos.x, global::playerStartPos.y - 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::input()
|
||||||
|
{
|
||||||
|
while (const std::optional event = window.pollEvent())
|
||||||
|
{
|
||||||
|
ImGui::SFML::ProcessEvent(window, *event);
|
||||||
|
|
||||||
|
if (event->is<sf::Event::Closed>())
|
||||||
|
{
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto* keyPressed = event->getIf<sf::Event::KeyPressed>())
|
||||||
|
{
|
||||||
|
switch (keyPressed->scancode)
|
||||||
|
{
|
||||||
|
case sf::Keyboard::Scan::Escape:
|
||||||
|
window.close();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sf::Keyboard::Scan::Left:
|
||||||
|
case sf::Keyboard::Scan::A:
|
||||||
|
player.left = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sf::Keyboard::Scan::Right:
|
||||||
|
case sf::Keyboard::Scan::D:
|
||||||
|
player.right = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto* keyReleased = event->getIf<sf::Event::KeyReleased>())
|
||||||
|
{
|
||||||
|
switch (keyReleased->scancode)
|
||||||
|
{
|
||||||
|
case sf::Keyboard::Scan::Left:
|
||||||
|
case sf::Keyboard::Scan::A:
|
||||||
|
player.left = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sf::Keyboard::Scan::Right:
|
||||||
|
case sf::Keyboard::Scan::D:
|
||||||
|
player.right = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::collision()
|
||||||
|
{
|
||||||
|
// declaring at top so it can be used in and out of the ball collision loop
|
||||||
|
const sf:: FloatRect playerBounds = {player.pos, global::playerHalfSize};
|
||||||
|
const sf:: FloatRect previousPlayerBounds = {player.previousPos, global::playerHalfSize};
|
||||||
|
|
||||||
|
//ball collisions
|
||||||
|
for (auto& ball : balls)
|
||||||
|
{
|
||||||
|
const sf::FloatRect ballBounds = {ball.pos, {global::ballRadius, global::ballRadius}};
|
||||||
|
const sf::FloatRect previousBallBounds = {ball.previousPos, {global::ballRadius, global::ballRadius}};
|
||||||
|
|
||||||
|
for (auto& brick : bricks)
|
||||||
|
{
|
||||||
|
const sf::FloatRect brickBounds = {brick.pos, global::brickHalfSize};
|
||||||
|
auto intersect = getOverlap(ballBounds, brickBounds);
|
||||||
|
auto previousIntersect = getOverlap(previousBallBounds, brickBounds);
|
||||||
|
|
||||||
|
if (intersect.x > 0 && previousIntersect.x <= 0 && intersect.y > 0)
|
||||||
|
{
|
||||||
|
brick.alive = false;
|
||||||
|
ball.velocity.x *= -1;
|
||||||
|
if (ball.pos.x < player.pos.x)
|
||||||
|
{
|
||||||
|
ball.pos.x -= intersect.x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ball.pos.x += intersect.x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// coming from y direction
|
||||||
|
if (intersect.y > 0 && previousIntersect.y <= 0 && intersect.x > 0)
|
||||||
|
{
|
||||||
|
brick.alive = false;
|
||||||
|
ball.velocity.y *= -1;
|
||||||
|
if (ball.pos.y < player.pos.y)
|
||||||
|
{
|
||||||
|
ball.pos.y -= intersect.y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ball.pos.y += intersect.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& brick : specialBricks)
|
||||||
|
{
|
||||||
|
const sf::FloatRect brickBounds = {brick.pos, global::brickHalfSize};
|
||||||
|
const auto intersect = getOverlap(ballBounds, brickBounds);
|
||||||
|
const auto previousIntersect = getOverlap(previousBallBounds, brickBounds);
|
||||||
|
bool spawnExtraBall{false};
|
||||||
|
|
||||||
|
// coming from x direction
|
||||||
|
if (intersect.x > 0 && previousIntersect.x <= 0 && intersect.y > 0)
|
||||||
|
{
|
||||||
|
brick.alive = false;
|
||||||
|
spawnExtraBall = true;
|
||||||
|
ball.velocity.x *= -1;
|
||||||
|
if (ball.pos.x < player.pos.x)
|
||||||
|
{
|
||||||
|
ball.pos.x -= intersect.x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ball.pos.x += intersect.x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// coming from y direction
|
||||||
|
if (intersect.y > 0 && previousIntersect.y <= 0 && intersect.x > 0)
|
||||||
|
{
|
||||||
|
brick.alive = false;
|
||||||
|
spawnExtraBall = true;
|
||||||
|
ball.velocity.y *= -1;
|
||||||
|
if (ball.pos.y < player.pos.y)
|
||||||
|
{
|
||||||
|
ball.pos.y -= intersect.y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ball.pos.y += intersect.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spawnExtraBall)
|
||||||
|
{
|
||||||
|
ballsToAdd.emplace_back(ball.pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//wall collide
|
||||||
|
if (ballBounds.position.y + ballBounds.size.y > window.getSize().y)
|
||||||
|
{
|
||||||
|
ball.alive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ball.pos.x - global::ballRadius <= 0)
|
||||||
|
{
|
||||||
|
ball.pos.x = global::ballRadius;
|
||||||
|
ball.velocity.x *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ball.pos.x + global::ballRadius >= window.getSize().x)
|
||||||
|
{
|
||||||
|
ball.pos.x = window.getSize().x - global::ballRadius;
|
||||||
|
ball.velocity.x *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ball.pos.y - global::ballRadius < 0)
|
||||||
|
{
|
||||||
|
ball.pos.y = global::ballRadius;
|
||||||
|
ball.velocity.y *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// player collide
|
||||||
|
auto intersect = getOverlap(ballBounds, playerBounds);
|
||||||
|
auto previousIntersect = getOverlap(previousBallBounds, previousPlayerBounds);
|
||||||
|
|
||||||
|
// coming from x direction
|
||||||
|
if (intersect.x > 0 && previousIntersect.x <= 0 && intersect.y > 0)
|
||||||
|
{
|
||||||
|
ball.velocity.x *= -1;
|
||||||
|
if (ball.pos.x < player.pos.x)
|
||||||
|
{
|
||||||
|
ball.pos.x -= intersect.x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ball.pos.x += intersect.x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// coming from y direction
|
||||||
|
if (intersect.y > 0 && previousIntersect.y <= 0 && intersect.x > 0)
|
||||||
|
{
|
||||||
|
ball.velocity.y *= -1;
|
||||||
|
if (ball.pos.y < player.pos.y)
|
||||||
|
{
|
||||||
|
ball.pos.y -= intersect.y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ball.pos.y += intersect.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//player wall collide
|
||||||
|
if (playerBounds.position.x + playerBounds.size.x > window.getSize().x)
|
||||||
|
{
|
||||||
|
player.pos.x = window.getSize().x - global::playerHalfSize.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playerBounds.position.x < global::playerHalfSize.x)
|
||||||
|
{
|
||||||
|
player.pos.x = global::playerHalfSize.x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::updateEntities()
|
||||||
|
{
|
||||||
|
balls.erase(std::remove_if(balls.begin(), balls.end(), [](const Ball& ball){ return !ball.alive; }), balls.end());
|
||||||
|
bricks.erase(std::remove_if(bricks.begin(), bricks.end(), [](const Brick& brick){ return !brick.alive; }), bricks.end());
|
||||||
|
|
||||||
|
const auto limit = ballsToAdd.size();
|
||||||
|
|
||||||
|
for (int i = 0; i < limit; i++)
|
||||||
|
{
|
||||||
|
balls.emplace_back(ballsToAdd[i], velocityInRandomDir(global::ballMaxSpeed));
|
||||||
|
ballsToAdd[i] = {0,0};
|
||||||
|
}
|
||||||
|
|
||||||
|
ballsToAdd.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::checkEndGame()
|
||||||
|
{
|
||||||
|
if (balls.empty())
|
||||||
|
{
|
||||||
|
player.lives--;
|
||||||
|
ballsToAdd.emplace_back(sf::Vector2f{player.pos.x, player.pos.y - 500});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (player.lives <= 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::movement()
|
||||||
|
{
|
||||||
|
for (auto& ball : balls)
|
||||||
|
{
|
||||||
|
ball.previousPos = ball.pos;
|
||||||
|
ball.pos += ball.velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dir = player.right - player.left;
|
||||||
|
|
||||||
|
player.previousPos = player.pos;
|
||||||
|
player.pos.x += global::playerSpeed * dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::imgui()
|
||||||
|
{
|
||||||
|
ImGui::SFML::Update(window, clock.restart());
|
||||||
|
|
||||||
|
ImGui::Begin("menu");
|
||||||
|
ImGui::SetWindowCollapsed(global::windowCollasped);
|
||||||
|
ImGui::Text("Controls:");
|
||||||
|
ImGui::Indent();
|
||||||
|
ImGui::Text("A/D or arrow keys: move left and right");
|
||||||
|
ImGui::Text("R: reset game");
|
||||||
|
ImGui::Text("F1: expand/collaspe this window");
|
||||||
|
ImGui::Unindent();
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::render()
|
||||||
|
{
|
||||||
|
window.clear();
|
||||||
|
|
||||||
|
|
||||||
|
tempRect.setSize(global::brickSize);
|
||||||
|
tempRect.setOrigin(global::brickHalfSize);
|
||||||
|
for (auto& brick : bricks)
|
||||||
|
{
|
||||||
|
tempRect.setPosition(brick.pos);
|
||||||
|
tempRect.setFillColor(brick.color.sfml());
|
||||||
|
window.draw(tempRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& brick : specialBricks)
|
||||||
|
{
|
||||||
|
tempRect.setPosition(brick.pos);
|
||||||
|
tempRect.setFillColor(brick.color.sfml());
|
||||||
|
window.draw(tempRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
tempRect.setOrigin(global::playerHalfSize);
|
||||||
|
tempRect.setSize(global::playerSize);
|
||||||
|
tempRect.setPosition(player.pos);
|
||||||
|
tempRect.setFillColor(player.color.sfml());
|
||||||
|
window.draw(tempRect);
|
||||||
|
tempCircle.setRadius(global::ballRadius);
|
||||||
|
for (auto& ball : balls)
|
||||||
|
{
|
||||||
|
tempCircle.setPosition(ball.pos);
|
||||||
|
tempCircle.setFillColor(ball.color.sfml());
|
||||||
|
window.draw(tempCircle);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SFML::Render(window);
|
||||||
|
|
||||||
|
window.display();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::run()
|
||||||
|
{
|
||||||
|
while(window.isOpen())
|
||||||
|
{
|
||||||
|
input();
|
||||||
|
|
||||||
|
updateEntities();
|
||||||
|
|
||||||
|
movement();
|
||||||
|
|
||||||
|
collision();
|
||||||
|
|
||||||
|
checkEndGame();
|
||||||
|
|
||||||
|
imgui();
|
||||||
|
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SFML::Shutdown();
|
||||||
|
}
|
||||||
51
src/main.cpp
51
src/main.cpp
|
|
@ -1,52 +1,7 @@
|
||||||
#define DRAW_SCREEN 1
|
#include <Game.h>
|
||||||
|
|
||||||
#include <SFML/Graphics.hpp>
|
|
||||||
#include <imgui-SFML.h>
|
|
||||||
#include <imgui.h>
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
Game game;
|
||||||
|
game.run();
|
||||||
#if DRAW_SCREEN == 1
|
|
||||||
auto window = sf::RenderWindow(sf::VideoMode({ 1920u, 1080u }), "2d-platformer");
|
|
||||||
window.setFramerateLimit(60);
|
|
||||||
if (!ImGui::SFML::Init(window))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
sf::Clock clock;
|
|
||||||
while (window.isOpen())
|
|
||||||
{
|
|
||||||
while (const std::optional event = window.pollEvent())
|
|
||||||
{
|
|
||||||
ImGui::SFML::ProcessEvent(window, *event);
|
|
||||||
|
|
||||||
if (event->is<sf::Event::Closed>())
|
|
||||||
{
|
|
||||||
window.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const auto* keyPressed = event->getIf<sf::Event::KeyPressed>())
|
|
||||||
{
|
|
||||||
if (keyPressed->scancode == sf::Keyboard::Scan::Escape)
|
|
||||||
{
|
|
||||||
window.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}// end user input loop
|
|
||||||
|
|
||||||
ImGui::SFML::Update(window, clock.restart());
|
|
||||||
|
|
||||||
ImGui::Begin("sdfkjasbdf");
|
|
||||||
ImGui::End();
|
|
||||||
window.clear();
|
|
||||||
ImGui::SFML::Render(window);
|
|
||||||
|
|
||||||
window.display();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SFML::Shutdown();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue