Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
cmake_minimum_required(VERSION 3.10)
project(Arkanoid)

set(CMAKE_CXX_STANDARD 11)

find_package(SFML 2.5 COMPONENTS graphics window system REQUIRED)

include_directories(include)
file(GLOB SOURCES "src/*.cpp")

add_executable(arkanoid ${SOURCES})
target_link_libraries(arkanoid sfml-graphics sfml-window sfml-system)
33 changes: 33 additions & 0 deletions include/Ball.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#ifndef BALL_H
#define BALL_H

#include <SFML/Graphics.hpp>

class Ball : public sf::CircleShape {
public:
Ball(float windowWidth, float windowHeight);
void update(sf::Time deltaTime);
void bounceX();
void bounceY();
void bounceFromPaddle(float hitPosition);
void randomBounce();
void stickToPaddle(const sf::RectangleShape& paddle);
void release();
void reset();
void increaseSpeed();
void decreaseSpeed();

sf::Vector2f getPosition() const;
float getRadius() const;
sf::FloatRect getGlobalBounds() const;

private:
float mWindowWidth;
float mWindowHeight;
float mDefaultRadius;
sf::Vector2f mVelocity;
float mDefaultSpeed;
bool mIsReleased;
};

#endif // BALL_H
28 changes: 28 additions & 0 deletions include/Block.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef BLOCK_H
#define BLOCK_H

#include <SFML/Graphics.hpp>

enum class BlockType {
Regular,
Unbreakable,
WithBonus,
SpeedUp
};

class Block : public sf::RectangleShape {
public:
Block(const sf::Vector2f& position, const sf::Vector2f& size, BlockType type, int health);
bool hit();
bool isDestroyed() const;
int getHealth() const;
BlockType getType() const;
bool hasBonus() const;

private:
BlockType mType;
int mHealth;
bool mIsDestroyed;
};

#endif // BLOCK_H
29 changes: 29 additions & 0 deletions include/Bonus.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifndef BONUS_H
#define BONUS_H

#include <SFML/Graphics.hpp>

enum class BonusType {
EnlargePaddle,
ShrinkPaddle,
StickyPaddle,
BottomShield,
RandomTrajectory,
SpeedUp,
SlowDown
};

class Bonus : public sf::CircleShape {
public:
Bonus(const sf::Vector2f& position, BonusType type);
void update(sf::Time deltaTime);
bool isDestroyed() const;
BonusType getType() const;

private:
BonusType mType;
float mSpeed;
bool mIsDestroyed;
};

#endif // BONUS_H
16 changes: 16 additions & 0 deletions include/Constants.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef CONSTANTS_H
#define CONSTANTS_H

namespace Constants {
constexpr float WINDOW_WIDTH = 800.f;
constexpr float WINDOW_HEIGHT = 600.f;
constexpr float PADDLE_WIDTH = 100.f;
constexpr float PADDLE_HEIGHT = 20.f;
constexpr float BALL_RADIUS = 10.f;
constexpr float BONUS_RADIUS = 8.f;
constexpr float BLOCK_WIDTH = 70.f;
constexpr float BLOCK_HEIGHT = 30.f;
constexpr float BLOCK_PADDING = 5.f;
}

#endif CONSTANTS_H
44 changes: 44 additions & 0 deletions include/Game.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#ifndef GAME_H
#define GAME_H

#include <SFML/Graphics.hpp>
#include <vector>
#include <memory>
#include "Paddle.h"
#include "Ball.h"
#include "Block.h"
#include "Bonus.h"

class Game {
public:
Game();
void run();

private:
void processEvents();
void update(sf::Time deltaTime);
void render();
void handleCollisions();
void spawnBonus(const sf::Vector2f& position, BonusType type);
void activateBonus(BonusType type);
void resetGame();

sf::RenderWindow mWindow;
Paddle mPaddle;
Ball mBall;
std::vector<std::unique_ptr<Block>> mBlocks;
std::vector<std::unique_ptr<Bonus>> mBonuses;

int mScore;
int mLives;
bool mIsBallSticky;
bool mHasBottomShield;
bool mIsGameOver;

sf::Font mFont;
sf::Text mScoreText;
sf::Text mLivesText;
sf::Text mGameOverText;
};

#endif // GAME_H
24 changes: 24 additions & 0 deletions include/Paddle.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef PADDLE_H
#define PADDLE_H

#include <SFML/Graphics.hpp>

class Paddle : public sf::RectangleShape {
public:
Paddle(float windowWidth, float windowHeight);
void handleInput();
void enlarge();
void shrink();
void reset();

sf::Vector2f getSize() const;

private:
float mWindowWidth;
float mWindowHeight;
float mDefaultWidth;
float mDefaultHeight;
float mSpeed;
};

#endif // PADDLE_H
101 changes: 101 additions & 0 deletions src/Ball.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#include "Ball.h"
#include "Constants.h"
#include <cmath>
#include <random>

Ball::Ball()
: mDefaultRadius(Constants::BALL_RADIUS),
mDefaultSpeed(300.f),
mIsReleased(false) {

setRadius(mDefaultRadius);
setOrigin(getRadius(), getRadius());
reset();
setFillColor(sf::Color::White);
}

void Ball::update(sf::Time deltaTime) {
if (!mIsReleased) return;

move(mVelocity * deltaTime.asSeconds());

// Bounce from walls
if (getPosition().x - getRadius() < 0 || getPosition().x + getRadius() > mWindowWidth) {
bounceX();
}

if (getPosition().y - getRadius() < 0) {
bounceY();
}
}

void Ball::bounceX() {
mVelocity.x = -mVelocity.x;
}

void Ball::bounceY() {
mVelocity.y = -mVelocity.y;
}

void Ball::bounceFromPaddle(float hitPosition) {
mVelocity.x = mDefaultSpeed * hitPosition * 0.5f;
mVelocity.y = -std::abs(mVelocity.y);
}

void Ball::randomBounce() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dist(-1.f, 1.f);

mVelocity.x = mDefaultSpeed * dist(gen);
mVelocity.y = -std::abs(mDefaultSpeed * dist(gen));

// Normalize to maintain speed
float length = std::sqrt(mVelocity.x * mVelocity.x + mVelocity.y * mVelocity.y);
mVelocity = mVelocity / length * mDefaultSpeed;
}

void Ball::stickToPaddle(const sf::RectangleShape& paddle) {
setPosition(paddle.getPosition().x, paddle.getPosition().y - paddle.getSize().y / 2.f - getRadius());
mVelocity = sf::Vector2f(0.f, 0.f);
}

void Ball::release() {
mIsReleased = true;
mVelocity = sf::Vector2f(0.f, -mDefaultSpeed);
}

void Ball::reset() {
setPosition(mWindowWidth / 2.f, mWindowHeight / 2.f);
mVelocity = sf::Vector2f(0.f, 0.f);
mIsReleased = false;
}

void Ball::increaseSpeed() {
mDefaultSpeed *= 1.2f;
float length = std::sqrt(mVelocity.x * mVelocity.x + mVelocity.y * mVelocity.y);
if (length > 0) {
mVelocity = mVelocity / length * mDefaultSpeed;
}
}

void Ball::decreaseSpeed() {
mDefaultSpeed *= 0.8f;
if (mDefaultSpeed < 150.f) mDefaultSpeed = 150.f;
float length = std::sqrt(mVelocity.x * mVelocity.x + mVelocity.y * mVelocity.y);
if (length > 0) {
mVelocity = mVelocity / length * mDefaultSpeed;
}
}

sf::Vector2f Ball::getPosition() const {
return sf::CircleShape::getPosition();
}

float Ball::getRadius() const {
return sf::CircleShape::getRadius();
}

sf::FloatRect Ball::getGlobalBounds() const {
return sf::CircleShape::getGlobalBounds();
}
60 changes: 60 additions & 0 deletions src/Block.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include "Block.h"

Block::Block(const sf::Vector2f& position, const sf::Vector2f& size, BlockType type, int health)
: mType(type), mHealth(health), mIsDestroyed(false) {

setPosition(position);
setSize(size);
setOrigin(getSize() / 2.f);

switch (mType) {
case BlockType::Regular:
setFillColor(sf::Color::Red);
break;
case BlockType::Unbreakable:
setFillColor(sf::Color::Gray);
break;
case BlockType::WithBonus:
setFillColor(sf::Color::Green);
break;
case BlockType::SpeedUp:
setFillColor(sf::Color::Yellow);
break;
}
}

bool Block::hit() {
if (mType == BlockType::Unbreakable) {
return false;
}

mHealth--;

if (mHealth <= 0) {
mIsDestroyed = true;
return true;
}

// Change color based on health
sf::Color color = getFillColor();
color.a = 100 + 155 * mHealth / 3;
setFillColor(color);

return false;
}

bool Block::isDestroyed() const {
return mIsDestroyed;
}

int Block::getHealth() const {
return mHealth;
}

BlockType Block::getType() const {
return mType;
}

bool Block::hasBonus() const {
return mType == BlockType::WithBonus && mIsDestroyed;
}
Loading