Created
February 27, 2026 20:37
-
-
Save ryonagana/6cb7322efda7d54b52a3fe2b9660980d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <SFML/Graphics.hpp> | |
| #include <SFML/System.hpp> | |
| #include <SFML/Window.hpp> | |
| #include <SFML/Audio.hpp> | |
| #include <vector> | |
| #include <array> | |
| #include <unordered_map> | |
| const float PADDLE_SPEED = 300.0f; | |
| const float BALL_SPEED = 300.f; | |
| const int MAX_ROWS = 8; | |
| const int MAX_COLS = 14; | |
| //blocks | |
| const float BLOCK_W = 50.0f; | |
| const float BLOCK_H = 10.0f; | |
| const float BLOCK_PADDING = 2.5f; | |
| bool checkAABBCoollision(const sf::FloatRect& rect1, const sf::FloatRect& rect2); | |
| static const char *hit_sfx_list[] = { | |
| {"hit01"}, | |
| {"hit02"}, | |
| {"hit03"}, | |
| {"hit04"}, | |
| nullptr, | |
| }; | |
| struct GameSound { | |
| sf::SoundBuffer buffer; | |
| sf::Sound sound; | |
| GameSound(const std::string& filename): buffer(filename), sound(buffer){ | |
| } | |
| bool Load(const std::string& filename){ | |
| if(!buffer.loadFromFile(filename)){ | |
| fprintf(stderr, "sound: %s not found!", filename.c_str()); | |
| return false; | |
| } | |
| sound.setBuffer(buffer); | |
| return true; | |
| } | |
| void Play(){ | |
| sound.play(); | |
| } | |
| void Stop(){ | |
| sound.stop(); | |
| } | |
| }; | |
| std::unordered_map<std::string, GameSound> soundMap; | |
| enum class GameState:int { | |
| START, | |
| PLAY, | |
| GAMEOVER | |
| }; | |
| struct Paddle { | |
| sf::Sprite* paddle; | |
| sf::Vector2f pos; | |
| sf::Vector2f accel; | |
| Paddle(sf::Sprite *paddle){ | |
| this->paddle = paddle; | |
| accel.x = PADDLE_SPEED; | |
| accel.y = 0.0f; | |
| } | |
| inline sf::FloatRect getBounds() const { | |
| return paddle->getGlobalBounds(); | |
| } | |
| void Update(float dt){ | |
| pos.x += accel.x * dt; | |
| pos.y += accel.y * dt; | |
| if(pos.x > 0.5f && pos.x < (1024.0f - 60.0f) - 0.5f){ | |
| paddle->setPosition(pos); | |
| } | |
| } | |
| void Draw(sf::RenderWindow &window){ | |
| window.draw(*paddle); | |
| } | |
| }; | |
| struct Block { | |
| sf::RectangleShape shape; | |
| bool alive; | |
| int hit_counter; | |
| Block(){ | |
| alive = false; | |
| hit_counter = 1; | |
| } | |
| ~Block(){ | |
| } | |
| void Create(float x, float y, float w, float h, sf::Color color){ | |
| shape.setSize({w,h}); | |
| shape.setPosition({x,y}); | |
| shape.setOutlineColor(sf::Color::Magenta); | |
| shape.setFillColor(color); | |
| alive = true; | |
| } | |
| inline sf::FloatRect getBounds() const{ | |
| return shape.getGlobalBounds(); | |
| } | |
| void Draw(sf::RenderWindow &window){ | |
| if(alive){ | |
| window.draw(shape); | |
| } | |
| } | |
| }; | |
| struct Ball { | |
| //sf::Sprite* ball; | |
| sf::CircleShape shape; | |
| sf::Vector2<float> pos; | |
| sf::Vector2<float> vel; | |
| sf::Vector2f dir; | |
| Ball(){ | |
| dir.x = 1.0f; | |
| dir.y = 1.0f; | |
| vel.x = dir.x * 1.0f; | |
| vel.y = dir.y * 1.0f; | |
| shape.setFillColor(sf::Color::White); | |
| shape.setRadius(6.0f); | |
| } | |
| inline sf::FloatRect getBounds() const { | |
| return shape.getGlobalBounds(); | |
| } | |
| void Update(float dt){ | |
| pos.x += dir.x * vel.x * BALL_SPEED * dt; | |
| pos.y += dir.y * vel.y * BALL_SPEED * dt; | |
| shape.setPosition(pos); | |
| } | |
| void Draw(sf::RenderWindow &window){ | |
| window.draw(shape); | |
| } | |
| }; | |
| static GameState actual_state = GameState::START; | |
| int main(){ | |
| sf::RenderWindow window(sf::VideoMode({1024,768}), "AUAUIA"); | |
| window.setFramerateLimit(60); | |
| const sf::Texture spritesheet("assets/breakout-img.png"); | |
| sf::Sprite spr_sheet(spritesheet); | |
| sf::Sprite paddle_texture(spritesheet); | |
| sf::Sprite ball_texture(spritesheet); | |
| Paddle game_paddle(&paddle_texture); | |
| Ball game_ball; | |
| GameSound hit01("assets//hit01.wav"); | |
| GameSound hit02("assets//hit02.wav"); | |
| GameSound hit03("assets//hit03.wav"); | |
| GameSound hit04("assets//hit04.wav"); | |
| GameSound hitpaddlesfx("assets//hitpaddle.wav"); | |
| GameSound blockdeadsfx("assets//blockdead.wav"); | |
| soundMap.insert(std::make_pair("hit01", hit01)); | |
| soundMap.insert(std::make_pair("hit02", hit02)); | |
| soundMap.insert(std::make_pair("hit03", hit03)); | |
| soundMap.insert(std::make_pair("hit04", hit04)); | |
| soundMap.insert(std::make_pair("hitpaddle", hitpaddlesfx)); | |
| soundMap.insert(std::make_pair("blockdead", blockdeadsfx)); | |
| paddle_texture.setTextureRect(sf::IntRect( | |
| { 305, | |
| 148}, | |
| {60, | |
| 16} | |
| )); | |
| ball_texture.setTextureRect(sf::IntRect( | |
| {366,178}, | |
| {17,15} | |
| )); | |
| sf::Clock clock; | |
| sf::Vector2u windowSize = window.getSize(); | |
| game_paddle.pos.x = (windowSize.x / 2) + 60; | |
| game_paddle.pos.y = windowSize.y - 40.0f; | |
| paddle_texture.setPosition(game_paddle.pos); | |
| const int t = MAX_ROWS * MAX_COLS; | |
| std::array<Block, t> blocks; | |
| float totalWidth = MAX_COLS + (BLOCK_W + BLOCK_PADDING) - BLOCK_PADDING; | |
| float startX = (window.getSize().x - totalWidth) / 2.0f; | |
| float startY = 50.0f; | |
| game_ball.pos = game_paddle.getBounds().getCenter(); | |
| for(int i = 0; i < MAX_ROWS * MAX_COLS; i++){ | |
| int x = i / MAX_ROWS; | |
| int y = i % MAX_ROWS; | |
| float px = x * (BLOCK_W + 2.0f); | |
| float py = y * (BLOCK_W + 1.0f); | |
| sf::Color color; | |
| int r = rand() % 5; | |
| const sf::Color col[5] { | |
| sf::Color::Blue, | |
| sf::Color::Yellow, | |
| sf::Color::Red, | |
| sf::Color::Green, | |
| sf::Color::Magenta | |
| }; | |
| color = col[r]; | |
| blocks[i].Create(px, py, BLOCK_W, BLOCK_H, color); | |
| blocks[i].hit_counter = (r >= 0 && r <= 3) ? 2 : 1; | |
| } | |
| while(window.isOpen()){ | |
| sf::Time dt = clock.restart(); | |
| float deltaTime = dt.asSeconds(); | |
| while(const std::optional event = window.pollEvent()){ | |
| if(event->is<sf::Event::Closed>()){ | |
| window.close(); | |
| } | |
| if(const auto* keypressed = event->getIf<sf::Event::KeyPressed>()){ | |
| if(keypressed->code == sf::Keyboard::Key::Left || keypressed->code == sf::Keyboard::Key::A){ | |
| game_paddle.accel.x = -PADDLE_SPEED; | |
| } | |
| if(keypressed->code == sf::Keyboard::Key::Right || keypressed->code == sf::Keyboard::Key::D){ | |
| game_paddle.accel.x = PADDLE_SPEED; | |
| } | |
| if(keypressed->code == sf::Keyboard::Key::Space && actual_state == GameState::START){ | |
| game_ball.vel.x = 1.0f; | |
| game_ball.vel.y = -1.0f; | |
| actual_state = GameState::PLAY; | |
| } | |
| } | |
| if(const auto* keyreleased = event->getIf<sf::Event::KeyReleased>()){ | |
| if(keyreleased->code == sf::Keyboard::Key::Left || keyreleased->code == sf::Keyboard::Key::A){ | |
| game_paddle.accel.x = 0.0f; | |
| } | |
| if(keyreleased->code == sf::Keyboard::Key::Right || keyreleased->code == sf::Keyboard::Key::D){ | |
| game_paddle.accel.x = 0.0f; | |
| } | |
| } | |
| } | |
| game_paddle.Update(deltaTime); | |
| game_ball.Update(deltaTime); | |
| if( actual_state == GameState::START){ | |
| game_ball.pos = game_paddle.getBounds().getCenter(); | |
| game_ball.pos.y = game_paddle.getBounds().position.y - 16; | |
| } | |
| if(actual_state == GameState::PLAY){ | |
| if(game_ball.pos.x < 0.5f || game_ball.pos.x > (windowSize.x - 0.5f) ){ | |
| game_ball.dir.x *= -1; | |
| const char* name = hit_sfx_list[rand() % 4]; | |
| soundMap.at(name).Play(); | |
| } | |
| if(game_ball.pos.y < 0.5f || game_ball.pos.y > (windowSize.y - .5f)){ | |
| game_ball.dir.y *= -1; | |
| const char* name = hit_sfx_list[rand() % 4]; | |
| soundMap.at(name).Play(); | |
| } | |
| if(checkAABBCoollision(game_ball.getBounds(), game_paddle.getBounds())){ | |
| game_ball.dir.y *= -1; | |
| soundMap.at("hitpaddle").Play(); | |
| } | |
| for(auto& block: blocks){ | |
| if(checkAABBCoollision(block.getBounds(), game_ball.getBounds() ) && block.alive){ | |
| block.hit_counter--; | |
| if(block.hit_counter <= 0){ | |
| block.alive = false; | |
| soundMap.at("blockdead").Play(); | |
| } | |
| //game_ball.dir.x *= -1; | |
| game_ball.dir.y *= -1; | |
| const char* name = hit_sfx_list[rand() % 4]; | |
| soundMap.at(name).Play(); | |
| } | |
| } | |
| } | |
| window.clear(); | |
| game_paddle.Draw(window); | |
| game_ball.Draw(window); | |
| for(auto& block: blocks){ | |
| block.Draw(window); | |
| } | |
| window.display(); | |
| } | |
| window.close(); | |
| return 0; | |
| } | |
| bool checkAABBCoollision(const sf::FloatRect& rect1, const sf::FloatRect& rect2){ | |
| return rect1.findIntersection(rect2).has_value(); | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment