Skip to content

Instantly share code, notes, and snippets.

@ryonagana
Created February 27, 2026 20:37
Show Gist options
  • Select an option

  • Save ryonagana/6cb7322efda7d54b52a3fe2b9660980d to your computer and use it in GitHub Desktop.

Select an option

Save ryonagana/6cb7322efda7d54b52a3fe2b9660980d to your computer and use it in GitHub Desktop.
#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