Advertisement

Breakout code review request

Started by August 07, 2014 09:42 PM
6 comments, last by Gaius Baltar 10 years, 5 months ago

This is my third review request on this forum:
Snake
Pong

Game:
Video

BNsRuYV.png

Files:
https://www.dropbox.com/s/5er86wt8wpy30zi/Breakout.zip

KyBfYmK.png

Code:

main.cpp
[spoiler]


#include <iostream>
#include "includes.h"

void doEvents(sf::RenderWindow & window, Upgrades & ups, BallState * ballState, Bullets * bullets, Entity * pad, Entity * ball, SoundEffect & shootSound, float pad_ball_delta_x);

int main(){
	srand(time(0));
	sf::RenderWindow window(sf::VideoMode(SCREEN_SIZE_X, SCREEN_SIZE_Y), "Breakout");
	window.setVerticalSyncEnabled(true);

	Entity pad(PAD_SIZE, (sf::Vector2f)SCREEN_SIZE - sf::Vector2f(SCREEN_CENTER.x - PAD_CENTER.x, PAD_SIZE.y + 10), sf::Color::White);
	Entity ball(BALL_SIZE, sf::Vector2f(pad.getPosition().x + PAD_CENTER.x - BALL_CENTER.x, pad.getPosition().y - BALL_SIZE.y), sf::Color(200, 200, 200));

	float volume = 50;
	SoundEffect powerupSpawnSound("sounds/powerspawn.wav", volume);
	SoundEffect powerupCatchSound("sounds/powercatch.wav", volume);
	SoundEffect blockHitSound("sounds/blockhit.wav", volume);
	SoundEffect explodeSound("sounds/explode.wav", volume);
	SoundEffect wallHitSound("sounds/wallhit.wav", volume);
	SoundEffect padHitSound("sounds/padhit.wav", volume);
	SoundEffect deathSound("sounds/death.wav", volume);
	SoundEffect shootSound("sounds/shoot.wav", volume);

	float global_veloctiy = ORIGIN_VELOCITY;
	float angle = 0;
	sf::Vector2f velocity(global_veloctiy, global_veloctiy * -1);
	Upgrades ups;
	BallState ballState = BallState::Stopped;
	Bullets bullets(sf::Vector2f(5, 15), sf::Color(255, 165, 0), MAX_VELOCITY * -1);
	float lives = LIVES;
	size_t score = 0;
	size_t blockScore = 100;
	size_t deathScore = 1000;
	size_t padScore = 200;
	size_t upgradeScore = 1000;
	size_t boundScore = 50;

	// Setting up the maps
	size_t curMap = 0; // Set first map
	size_t map_count = 11;
	std::vector<std::string> maps(map_count);
	for (size_t i = 0; i < map_count; i++)
		maps[i] = "maps/" + std::to_string(i + 1) + ".png";
	Map map(BLOCK_SIZE, OUTLINE_THICK, maps[curMap]);

	//Fixed timestep stuff
	sf::Clock clock;
	double skippedTime = 0;
	int updates = 0;
	double secondSkipped = 0;

	while (window.isOpen()){
		const double elapsedTime = clock.getElapsedTime().asMicroseconds() / 1000.0;
		skippedTime += elapsedTime;
		secondSkipped += elapsedTime;
		clock.restart();
		while (skippedTime >= INTERVAL){
			updates++;
			while (secondSkipped > SECOND){
				system("cls");
				std::cout << updates << "Updates,	" << secondSkipped / updates << " Average interval\n\n";
				std::cout << "Stats:\n";
				std::cout << "Lives:	" << lives << '\n';
				std::cout << "Score:	" << score << '\n';
				std::cout << '\n';
				std::cout << "Upgrades:\n";
				std::cout << "shooting:	" << ups.isActive(Shooting) << '\n';
				std::cout << "transparent:	" << ups.isActive(Transparent) << '\n';
				std::cout << "large pad:	" << ups.isActive(Large) << '\n';
				std::cout << "small pad:	" << ups.isActive(Small) << '\n';
				std::cout << "ball explode:	" << ups.isActive(Explode) << '\n';
				std::cout << "sticky pad:	" << ups.isActive(Sticky) << '\n';
				std::cout << "Y vel:	" << velocity.y << '\n';
				std::cout << "X vel:	" << velocity.x << '\n';
				std::cout << '\n';
				updates = 0;
				secondSkipped -= SECOND;
			}

			//Events
			doEvents(window, ups, &ballState, &bullets, &pad, &ball, shootSound, ball.getPosition().x - pad.getPosition().x);

			//Update
			bullets.move();
			ups.move();
			if (ballState == BallState::Moving){
				ball.move(velocity);
			}

			Entity bounds((sf::Vector2f)window.getSize(), sf::Vector2f(0, 0));
			if (mth::boundaryIntersect(ball, bounds, Side::Left)){
				velocity.x *= NEG;
				ball.setPosition(bounds.getPosition().x, ball.getPosition().y);
				wallHitSound.play();
				score += boundScore;
			}
			else if (mth::boundaryIntersect(ball, bounds, Side::Right)){
				velocity.x *= NEG;
				ball.setPosition(bounds.getSize().x - ball.getSize().x, ball.getPosition().y);
				wallHitSound.play();
				score += boundScore;
			}
			if (mth::boundaryIntersect(ball, bounds, Side::Top)){
				velocity.y *= NEG;
				ball.setPosition(ball.getPosition().x, bounds.getPosition().y);
				wallHitSound.play();
				score += boundScore;
			}
			if (mth::boundaryIntersect(ball, bounds, Side::Bottom)){
				lives--;
				if (lives <= 0)
					window.close();
				ups.clearActive();
				angle = 0;
				global_veloctiy = ORIGIN_VELOCITY;
				ballState = BallState::Stopped;
				ball.setPosition(pad.getPosition().x + PAD_CENTER.x - BALL_CENTER.x, pad.getPosition().y - BALL_SIZE.y - 1);
				velocity = sf::Vector2f(global_veloctiy, global_veloctiy * -1);
				deathSound.play();
				score += deathScore;
			}

			// Check for collisions between upgrades and pad
			std::vector<Entity> upgrade_entities = ups.getEntities();
			for (size_t i = 0; i < upgrade_entities.size(); i++){
				if (mth::doesIntersect(pad, upgrade_entities[i])){
					ups.addUpgrade(i);
					ups.removeAt(i);
					std::cout << "sup";
					ballState = BallState::Moving;
					powerupCatchSound.play();
					score += upgradeScore;
				}
			}

			// Check for collisions between bullets and blocks
			bool hit = false;
			size_t loc_y;
			size_t loc_x;
			vect2dTile blocks = map.getMap();
			std::vector<Entity> bullet_entities = bullets.get();

			for (size_t z = 0; z < bullet_entities.size(); z++){
				size_t x = bullet_entities[z].getGridPosition().x;
				for (size_t y = 0; y < blocks.size(); y++){
					if (blocks[y][x].strength > 0 && mth::doesIntersect(blocks[y][x].entity, bullet_entities[z])){
						if (!ups.isActive(Transparent)){
							bullets.removeAt(z);
						}
						if (rand() % 1000 <= UP_CHANCE){
							ups.spawn(blocks[y][x].entity, FALL_VELOCITY, GRAVITY);
							powerupSpawnSound.play();
						}
						map.hitAt(y, x);
						if (ups.isActive(Explode)){
							explodeSound.play();
							map.hitAt(y + 1, x);
							map.hitAt(y - 1, x);
							map.hitAt(y, x + 1);
							map.hitAt(y, x - 1);
							score += blockScore * 4;
						}
						score += blockScore;
						blockHitSound.play();
						hit = true;
						break;
					}
				}
				if (hit)
					break;
			}

			// Check for intersepts
			blocks = map.getMap();
			hit = false;
			// Downwards movement intersepts
			if (velocity.y > 0 && !hit){
				if (mth::willIntercept(ball, pad, velocity, Side::Top)){
					if (ups.isActive(Sticky)){
						ballState = BallState::Stopped;
					}
					global_veloctiy += VELOCITY_INC;
					if (global_veloctiy > MAX_VELOCITY) global_veloctiy = MAX_VELOCITY;
					angle = mth::getAngleInRadians(pad.getPosition() + sf::Vector2f(pad.getSize().x / 2.0f, 20), ball.getPosition() + ball.getSize() / 2.0f);
					velocity = mth::getVelocity(angle, global_veloctiy);
					score += padScore;
					padHitSound.play();
				}
				else
				for (size_t i = 0; i < blocks.size(); i++){
					for (size_t j = 0; j < blocks[i].size(); j++)
					if (blocks[i][j].strength > 0 && mth::willIntercept(ball, blocks[i][j].entity, velocity, Side::Top)){
						if (!ups.isActive(Transparent))
							velocity.y *= NEG;
						loc_y = i;
						loc_x = j;
						hit = true;
						break;
					}
					if (hit)
						break;
				}
			}
			// Upwards movement intersepts
			else if (velocity.y < 0 && !hit){
				for (size_t i = 0; i < blocks.size(); i++){
					for (size_t j = 0; j < blocks[i].size(); j++)
					if (blocks[i][j].strength > 0 && mth::willIntercept(ball, blocks[i][j].entity, velocity, Side::Bottom)){
						if (!ups.isActive(Transparent))
							velocity.y *= NEG;
						loc_y = i;
						loc_x = j;
						hit = true;
						break;
					}
					if (hit)
						break;
				}
			}

			// Right movement intersepts
			if (velocity.x > 0 && !hit){
				if (mth::willIntercept(ball, pad, velocity, Side::Left)){
					velocity *= NEG;
					padHitSound.play();
					score += padScore * 2;
				}
				else
				for (size_t i = 0; i < blocks.size(); i++){
					for (size_t j = 0; j < blocks[i].size(); j++)
					if (blocks[i][j].strength > 0 && mth::willIntercept(ball, blocks[i][j].entity, velocity, Side::Left)){
						if (!ups.isActive(Transparent))
							velocity.x *= NEG;
						loc_y = i;
						loc_x = j;
						hit = true;
						break;
					}
					if (hit)
						break;
				}
			}
			// Left movement intersepts
			else if (velocity.x < 0 && !hit){
				if (mth::willIntercept(ball, pad, velocity, Side::Right)){
					velocity *= NEG;
					padHitSound.play();
					score += padScore * 2;
				}
				else
				for (size_t i = 0; i < blocks.size(); i++){
					for (size_t j = 0; j < blocks[i].size(); j++)
					if (blocks[i][j].strength > 0 && mth::willIntercept(ball, blocks[i][j].entity, velocity, Side::Right)){
						if (!ups.isActive(Transparent))
							velocity.x *= NEG;
						loc_y = i;
						loc_x = j;
						hit = true;
						break;
					}
					if (hit)
						break;
				}
			}

			if (hit){
				if (rand() % 1000 <= UP_CHANCE){
					ups.spawn(blocks[loc_y][loc_x].entity, FALL_VELOCITY, GRAVITY);
					powerupSpawnSound.play();
				}
				map.hitAt(loc_y, loc_x);
				if (ups.isActive(Explode)){
					explodeSound.play();
					map.hitAt(loc_y + 1, loc_x);
					map.hitAt(loc_y - 1, loc_x);
					map.hitAt(loc_y, loc_x + 1);
					map.hitAt(loc_y, loc_x - 1);
				}
				blockHitSound.play();
				score += blockScore;
			}

			std::vector<Upgrd> active_ups = ups.getActiveUpgrades();
			Upgrd LorS = None_upgrd;
			for (size_t i = 0; i < active_ups.size(); i++){
				if (active_ups[i] == Large || active_ups[i] == Small)
					LorS = active_ups[i];
			}
			if (LorS == Large){
				pad.setSize(PAD_SIZE.x * 2.0f, PAD_SIZE_Y);
			}
			else if (LorS == Small){
				pad.setSize(PAD_SIZE.x / 2.0f, PAD_SIZE_Y);
			}
			else if (LorS == None_upgrd){
				pad.setSize(PAD_SIZE);
			}

			upgrade_entities = ups.getEntities();
			for (size_t i = 0; i < upgrade_entities.size(); i++){
				if (upgrade_entities[i].getPosition().y > window.getSize().y)
					ups.removeAt(i);
			}

			bullet_entities = bullets.get();
			for (size_t i = 0; i < bullet_entities.size(); i++){
				if (bullet_entities[i].getPosition().y < -100)
					bullets.removeAt(i);
			}

			if (map.isCleared()){
				if (curMap < map_count - 1){
					map.setMap(maps[++curMap]);
					global_veloctiy = ORIGIN_VELOCITY;
					velocity = sf::Vector2f(global_veloctiy, global_veloctiy * -1);
					ballState = BallState::Stopped;
					ball.setPosition(pad.getPosition().x + PAD_CENTER.x - BALL_CENTER.x, pad.getPosition().y - BALL_SIZE.y);
					ups.clearActive();
					bullets.clear();
				}
				else{
					curMap = 0;
				}
			}

			// Subtract INTERVAL from skippedTime
			skippedTime -= INTERVAL;
		}

		// Render
		window.clear(sf::Color(20, 20, 20));
		map.draw(window);
		ball.draw(window);
		ups.draw(window);
		pad.draw(window);
		bullets.draw(window);
		window.display();
	}

	return 0;
}

void doEvents(sf::RenderWindow & window, Upgrades & ups, BallState * ballState, Bullets * bullets, Entity * pad, Entity * ball, SoundEffect & shootSound, float pad_ball_delta_x){
	sf::Event event;
	while (window.pollEvent(event)){
		if (event.type == sf::Event::Closed)
			window.close();
		else if (event.type == sf::Event::KeyPressed){
			sf::Keyboard k;
			if (event.key.code == k.Escape){
				window.close();
			}
			if (event.key.code == k.Space){
				*ballState = BallState::Moving;
			}
			if (event.key.code == k.F1){
				ups.addUpgrade(Sticky);
			}
			if (event.key.code == k.F2){
				ups.addUpgrade(Shooting);
			}
			if (event.key.code == k.F3){
				ups.addUpgrade(Explode);
			}
			if (event.key.code == k.F4){
				ups.addUpgrade(Transparent);
			}
			if (event.key.code == k.F5){
				ups.addUpgrade(Large);
			}
			if (event.key.code == k.F6){
				ups.addUpgrade(Small);
			}
		}
		else if (event.type == sf::Event::MouseMoved){
			pad->setPosition(event.mouseMove.x - pad->getSize().x / 2.0f, pad->getPosition().y);
			if (*ballState == BallState::Stopped){
				ball->setPosition(pad->getPosition().x + pad_ball_delta_x, pad->getPosition().y - ball->getSize().y);
			}

		}
		else if (event.type == sf::Event::MouseButtonPressed){
			if (event.mouseButton.button == sf::Mouse::Button::Left){
				*ballState = BallState::Moving;
				if (ups.isActive(Shooting)){
					bullets->spawn(pad->getPosition() + sf::Vector2f(pad->getSize().x / 2.0f, 0));
					shootSound.play();
				}
			}

		}
	}
} 

[/spoiler]

includes.h
[spoiler]


#pragma once

#include <string>
#include <vector>
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include "globals.h"
#include "Entity.h"
#include "SoundEffect.h"
#include "Map.h"
#include "Bullet.h"
#include "Upgrade.h"
#include "mth_namespace.h" 

[/spoiler]

globals.h
[spoiler]


#pragma once
#include <SFML/System/Vector2.hpp>
struct Tile;

const float BLOCK_SIZE_XY	= 40.0f;
const float BALL_SIZE_XY	= 20.0f;
const float PAD_SIZE_Y		= 20.0f;
const float PAD_SIZE_X		= PAD_SIZE_Y * 5.0f;
const float UP_SIZE_XY		= 40.0f;
const int	GRID_SIZE_X		= 20;
const int	GRID_SIZE_Y		= 10;
const int	SCREEN_SIZE_X	= (int)BLOCK_SIZE_XY * GRID_SIZE_X;
const int	SCREEN_SIZE_Y	= (int)BLOCK_SIZE_XY * GRID_SIZE_Y + 200;
const float FALL_VELOCITY	= -2;
const float GRAVITY			= 0.04f;
const float ORIGIN_VELOCITY	= 2;
const float VELOCITY_INC	= 0.15f;
const float MAX_VELOCITY	= 8;
const int	LIVES			= 3;
const int	INTERVAL		= 10;
const int	SECOND			= 1000;
const int	UP_CHANCE		= 50; // in 1000
const float OUTLINE_THICK	= -10.0f;
const float NEG				= -1.0f;

const sf::Vector2i SCREEN_SIZE(SCREEN_SIZE_X, SCREEN_SIZE_Y);
const sf::Vector2f BLOCK_SIZE(BLOCK_SIZE_XY, BLOCK_SIZE_XY);
const sf::Vector2f BALL_SIZE(BALL_SIZE_XY, BALL_SIZE_XY);
const sf::Vector2i GRID_SIZE(GRID_SIZE_X , GRID_SIZE_Y);
const sf::Vector2f SCREEN_CENTER(SCREEN_SIZE / 2);
const sf::Vector2f PAD_SIZE(PAD_SIZE_X, PAD_SIZE_Y);
const sf::Vector2f BLOCK_CENTER(BLOCK_SIZE / 2.0f);
const sf::Vector2f BALL_CENTER(BALL_SIZE  / 2.0f);
const sf::Vector2f PAD_CENTER( PAD_SIZE /  2.0f);

typedef std::vector<std::vector<Tile>> vect2dTile;

enum BallState{
	Moving,
	Stopped
};

enum class Movement{
	Up,
	Down,
	Left,
	Right
};

enum Side{
	Top,
	Bottom,
	Left,
	Right
};

enum Upgrd{
	Shooting,
	Transparent,
	Large,
	Small,
	Explode,
	Sticky,
	LAST_upgrd,
	None_upgrd
}; 

[/spoiler]

mth_namespace.h
[spoiler]


#pragma once
#include <SFML/System/Vector2.hpp>
#include <SFML/Graphics/RenderWindow.hpp>
class Entity;
enum Side;

namespace mth{

	// A simple struct to make it easier to do stuff with lines
	struct Line;
	// A simple function to determine whether entity1 is within entity2
	bool doesIntersect(Entity entity1, Entity entity2);
	// Test if an entity is outside the entity bounds
	bool boundaryIntersect(Entity entity, Entity bounds, Side side);
	// Test for an intersection between two lines
	bool lineIntersect(Line line, sf::Vector2f pointMoving, float diam);
	// Test if two entities will intersect with the current velocity vel
	bool willIntercept(const Entity & entityMoving, const Entity & entityStatic, sf::Vector2f vel, Side side);
	// Get the angle between two vectors in radians
	float getAngleInRadians(const sf::Vector2f & entityStaticCenter, const sf::Vector2f & entityMovingCenter);
	// Calculate directional veloctiy, given radians and global velocity
	sf::Vector2f getVelocity(float radians, float vel);
} 

[/spoiler]

mth_namespace.cpp
[spoiler]


#include "mth_namespace.h"
#include "includes.h"
#include <iostream>

struct mth::Line{
	Line(){}
	Line(sf::Vector2f pointA, sf::Vector2f pointB) : A(pointA), B(pointB){}
	sf::Vector2f A;
	sf::Vector2f B;
};

bool mth::doesIntersect(Entity entity1, Entity entity2){
	if (entity1.getPosition().x <= entity2.getPosition().x + entity2.getSize().x &&
		entity1.getPosition().x + entity1.getSize().x >= entity2.getPosition().x &&
		entity1.getPosition().y <= entity2.getPosition().y + entity2.getSize().y &&
		entity1.getPosition().y + entity1.getSize().y >= entity2.getPosition().y)
		return true;
	return false;
}

bool mth::boundaryIntersect(Entity entity, Entity bounds, Side side){
	if (side == Side::Top && entity.getPosition().y < bounds.getPosition().y)
		return true;
	else if (side == Side::Bottom && entity.getPosition().y + entity.getSize().y > bounds.getPosition().y + bounds.getSize().y)
		return true;
	else if (side == Side::Left && entity.getPosition().x < bounds.getPosition().x)
		return true;
	else if (side == Side::Right && entity.getPosition().x + entity.getSize().x > bounds.getPosition().x + bounds.getSize().x)
		return true;
	return false;
}

bool mth::lineIntersect(Line line, sf::Vector2f pointMoving, float diam){
	if (line.A.x == line.B.x && pointMoving.x >= line.A.x - diam / 2.0f && pointMoving.x <= line.A.x + diam / 2.0f &&
		pointMoving.y >= line.A.y && pointMoving.y <= line.B.y)
		return true;
	if (line.A.y == line.B.y && pointMoving.y >= line.A.y - diam / 2.0f && pointMoving.y <= line.A.y + diam / 2.0f &&
		pointMoving.x >= line.A.x && pointMoving.x <= line.B.x)
		return true;
	return false;
}

bool mth::willIntercept(const Entity & entityMoving, const Entity & entityStatic, sf::Vector2f vel, Side side){
	float m, b;
	sf::Vector2f emCenter(entityMoving.getPosition() + (entityMoving.getSize() / 2.0f));
	m = ((emCenter.y + vel.y) - emCenter.y) /
		((emCenter.x + vel.x) - emCenter.x);
	b = emCenter.y - m * emCenter.x;

	Line line;
	sf::Vector2f start(emCenter);
	sf::Vector2f end;
	if (side <= Bottom){
		line.A = entityStatic.getPosition() + sf::Vector2f(0, entityStatic.getSize().y * side);
		line.B = entityStatic.getPosition() + sf::Vector2f(entityStatic.getSize().x, entityStatic.getSize().y * side);
		end = sf::Vector2f((int)((vel.y + emCenter.y - b) / m), vel.y + emCenter.y);
		if (side == Top){
			for (float y = 0; y <= vel.y; y += 0.1f){
				if (lineIntersect(line, sf::Vector2f((int)((y + emCenter.y - b) / m), y + emCenter.y), entityMoving.getSize().y))
					return true;
			}
		}
		else if (side == Bottom){
			for (float y = 0; y >= vel.y; y -= 0.1f){
				if (lineIntersect(line, sf::Vector2f((int)((y + emCenter.y - b) / m), y + emCenter.y), entityMoving.getSize().y))
					return true;
			}
		}
	}
	else if (side >= Left){
		int tmpSide = side - Left;
		line.A = entityStatic.getPosition() + sf::Vector2f(entityStatic.getSize().x * tmpSide, 0);
		line.B = entityStatic.getPosition() + sf::Vector2f(entityStatic.getSize().x * tmpSide, entityStatic.getSize().y);
		end = sf::Vector2f(vel.x + emCenter.x, (int)(m * (vel.x + emCenter.x) + b));
		if (side == Left){
			for (float x = 0; x <= vel.x; x += 0.1f){
				if (lineIntersect(line, sf::Vector2f(x + emCenter.x, (int)(m * (x + emCenter.x) + b)), entityMoving.getSize().x))
					return true;
			}
		}
		else if (side == Right){
			for (float x = 0; x >= vel.x; x -= 0.1f){
				if (lineIntersect(line, sf::Vector2f(x + emCenter.x, (int)(m * (x + emCenter.x) + b)), entityMoving.getSize().x))
					return true;
			}
		}
	}
	return false;
}

float mth::getAngleInRadians(const sf::Vector2f & entityStaticCenter, const sf::Vector2f & entityMovingCenter){
	return atan2f((entityMovingCenter.y - (entityStaticCenter.y)), (entityMovingCenter.x - (entityStaticCenter.x)));
}

sf::Vector2f mth::getVelocity(float radians, float vel){
	return sf::Vector2f((float)cos(radians) * (float)vel, (float)sin(radians) * (float)vel);
} 

[/spoiler]

Entity.h
[spoiler]


#pragma once
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/System/Vector2.hpp>
#include <SFML/Graphics/Color.hpp>
#include <SFML/Graphics/RenderWindow.hpp>

class Entity
{
private:
protected:
	sf::RectangleShape rect;
public:
	Entity(sf::Vector2f size, sf::Vector2f pos, sf::Color color = sf::Color::White);
	Entity(){ }

	sf::Vector2f getPosition() const;
	sf::Vector2i getGridPosition() const;
	sf::Vector2f getSize() const;
	float getOutlineThickness() const;
	void draw(sf::RenderWindow & window);
	void move(const sf::Vector2f & dist);
	void setPosition(float x, float y);
	void setPosition(const sf::Vector2f & pos);
	void setGridPosition(size_t x, size_t y);
	void setSize(float x, float y);
	void setSize(const sf::Vector2f & size);
	void setColor(const sf::Color & color);
	void setOutline(float thickness, const sf::Color & color);
	void setOutlineThickness(float thickness);
	void setOutlineColor(const sf::Color & color);
}; 

[/spoiler]

Entity.cpp
[spoiler]


#include "Entity.h"
#include "includes.h"
#include <iostream>

Entity::Entity(sf::Vector2f size, sf::Vector2f pos, sf::Color color){
	setSize(size);
	setPosition(pos);
	setColor(color);
}

sf::Vector2f Entity::getPosition() const{
	return rect.getPosition();
}

sf::Vector2i Entity::getGridPosition() const{
	return sf::Vector2i(rect.getPosition().x / BLOCK_SIZE_XY, rect.getPosition().y / BLOCK_SIZE_XY);
}

sf::Vector2f Entity::getSize() const{
	return rect.getSize();
}

float Entity::getOutlineThickness() const{
	return rect.getOutlineThickness();
}

void Entity::draw(sf::RenderWindow & window){
	window.draw(rect);
}

void Entity::move(const sf::Vector2f & dist){
	rect.setPosition(rect.getPosition() + dist);
}

void Entity::setPosition(float x, float y){
	rect.setPosition(x, y);
}

void Entity::setPosition(const sf::Vector2f & pos){
	rect.setPosition(pos);
}

void Entity::setGridPosition(size_t x, size_t y){
	setPosition(x * getSize().x, y * getSize().y);
}

void Entity::setSize(float x, float y){
	rect.setSize(sf::Vector2f(x, y));
}

void Entity::setSize(const sf::Vector2f & size){
	rect.setSize(size);
}

void Entity::setColor(const sf::Color & color){
	rect.setFillColor(color);
}

void Entity::setOutline(float thickness, const sf::Color & color){
	rect.setOutlineThickness(thickness);
	rect.setOutlineColor(color);
}

void Entity::setOutlineThickness(float thickness){
	rect.setOutlineThickness(thickness);
}

void Entity::setOutlineColor(const sf::Color & color){
	rect.setOutlineColor(color);
} 

[/spoiler]

Map.h
[spoiler]


#pragma once
#include "Entity.h"
#include "globals.h"

struct Tile{
	Entity entity;
	char strength = 1;
};

class Map
{
	vect2dTile tileMap;
	sf::Image map;
	Entity model;
public:
	Map(const sf::Vector2f & tileSize, float outlineThickness, std::string mapPath);

	vect2dTile getMap() const;
	bool isCleared() const;
	void setMap(std::string mapPath);
	void hitAt(size_t y, size_t x);

	void draw(sf::RenderWindow & window);
}; 

[/spoiler]

Map.cpp
[spoiler]


#include "Map.h"
#include "includes.h"

Map::Map(const sf::Vector2f & tileSize, float outlineThickness, std::string mapPath){
	model.setSize(tileSize);
	model.setOutlineThickness(outlineThickness);

	setMap(mapPath);
}

vect2dTile Map::getMap() const{
	return tileMap;
}

bool Map::isCleared() const{
	bool cleared = true;
	for (size_t y = 0; y < tileMap.size(); y++){
		for (size_t x = 0; x < tileMap[y].size(); x++){
			if (tileMap[y][x].strength > 0)
				cleared = false;
		}
	}
	return cleared;
}

void Map::setMap(std::string mapPath){
	// Load map
	if (!map.loadFromFile(mapPath))
		std::exit(-3);

	// Initialize tile map
	tileMap.resize(map.getSize().y);
	for (size_t i = 0; i < tileMap.size(); i++)
		tileMap[i].resize(map.getSize().x);

	// Set tile map
	for (size_t y = 0; y < tileMap.size(); y++){
		for (size_t x = 0; x < tileMap[y].size(); x++){
			if (map.getPixel(x, y) == sf::Color::Magenta)
				tileMap[y][x].strength = 0;
			else{
				tileMap[y][x].strength = 1;
				sf::Color pixCol = map.getPixel(x, y);
				tileMap[y][x].entity.setSize(model.getSize());
				tileMap[y][x].entity.setGridPosition(x, y);
				tileMap[y][x].entity.setColor(pixCol);
				tileMap[y][x].entity.setOutline(model.getOutlineThickness(), sf::Color(pixCol.r / 1.5f, pixCol.g / 1.5f, pixCol.b / 1.5f));
			}
		}
	}
}

void Map::hitAt(size_t y, size_t x){
	if (tileMap.size() > y && y >= 0 && tileMap[y].size() > x && x >= 0){
		if (tileMap[y][x].strength <= 1)
			tileMap[y][x].strength = 0;
		else
			tileMap[y][x].strength--;
	}
}

void Map::draw(sf::RenderWindow & window){
	for (size_t i = 0; i < tileMap.size(); i++)
	for (size_t j = 0; j < tileMap[i].size(); j++){
		if (tileMap[i][j].strength > 0)
			tileMap[i][j].entity.draw(window);
	}
} 

[/spoiler]

Upgrade.h
[spoiler]


#pragma once
#include <vector>
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/System/Vector2.hpp>
#include "globals.h"
class Entity;

class Upgrades
{
	std::vector<Upgrd> active;
	std::vector<Entity> entity;
	std::vector<Upgrd> upgrd;
	std::vector<sf::Vector2f> velocity;
	float gravity;
public:
	Upgrades(){

	}

	std::vector<Upgrd> getActiveUpgrades() const;
	std::vector<Entity> getEntities() const;
	void spawn(const Entity & origin, float startYVel, float gravity);
	void move();
	void removeAt(size_t item);
	void addUpgrade(Upgrd up);
	void addUpgrade(size_t upgrd_item);
	bool isActive(Upgrd up) const;
	void draw(sf::RenderWindow & window);
	void clearActive();
}; 

[/spoiler]

Upgrade.cpp
[spoiler]


#include "Upgrade.h"
#include "includes.h"

std::vector<Upgrd> Upgrades::getActiveUpgrades() const{
	return active;
}

std::vector<Entity> Upgrades::getEntities() const{
	return entity;
}

void Upgrades::spawn(const Entity & origin, float startYVel, float gravity){
	entity.push_back(origin);
	Upgrd tmp = (Upgrd)(rand() % LAST_upgrd);
	upgrd.push_back(tmp);
	velocity.push_back(sf::Vector2f(-0.5f + rand() % 11 / 10.0f, startYVel));
	this->gravity = gravity;
}

void Upgrades::move(){
	for (size_t i = 0; i < entity.size(); i++){
		entity[i].move(velocity[i]);
		if (velocity[i].y < MAX_VELOCITY)
			velocity[i].y += gravity;
		else
			velocity[i].y = MAX_VELOCITY;
	}
}

void Upgrades::removeAt(size_t item){
	entity.erase(entity.begin() + item);
	upgrd.erase(upgrd.begin() + item);
	velocity.erase(velocity.begin() + item);
}

void Upgrades::addUpgrade(Upgrd up){
	active.push_back(up);
}

void Upgrades::addUpgrade(size_t upgrd_item){
	active.push_back(upgrd[upgrd_item]);
}

bool Upgrades::isActive(Upgrd up) const{
	for (size_t i = 0; i < active.size(); i++){
		if (active[i] == up)
			return true;
	}
	return false;
}

void Upgrades::draw(sf::RenderWindow & window){
	for (size_t i = 0; i < entity.size(); i++){
		entity[i].draw(window);
	}
}

void Upgrades::clearActive(){
	active.clear();
} 

[/spoiler]

Bullet.h
[spoiler]


#pragma once
#include <vector>
#include "Entity.h"
#include <SFML/System/Vector2.hpp>
namespace sf{
	class Color;
	class RenderWindow;
};

class Bullets
{
	std::vector<Entity> bullets;
	Entity model;
	float yVel;
public:
	Bullets(const sf::Vector2f & size, const sf::Color & color, float vel);

	std::vector<Entity> get() const;
	void draw(sf::RenderWindow & window);
	void move();
	void clear();
	void removeAt(size_t item);
	void spawn(const sf::Vector2f & origin);
}; 

[/spoiler]

Bullet.cpp
[spoiler]


#include "Bullet.h"
#include "includes.h"

Bullets::Bullets(const sf::Vector2f & size, const sf::Color & color, float vel){
	model.setSize(size);
	model.setColor(color);
	yVel = vel;
}

std::vector<Entity> Bullets::get() const{
	return bullets;
}

void Bullets::draw(sf::RenderWindow & window){
	for (size_t i = 0; i < bullets.size(); i++){
		bullets[i].draw(window);
	}
}

void Bullets::move(){
	for (size_t i = 0; i < bullets.size(); i++){
		bullets[i].move(sf::Vector2f(0, yVel));
	}
}

void Bullets::clear(){
	bullets.clear();
}

void Bullets::removeAt(size_t item){
	bullets.erase(bullets.begin() + item);
}

void Bullets::spawn(const sf::Vector2f & origin){
	model.setPosition(origin);
	bullets.push_back(model);
} 

[/spoiler]

SoundEffect.h
[spoiler]


#pragma once
#include <SFML/Audio/SoundBuffer.hpp>
#include <SFML/Audio/Sound.hpp>

class SoundEffect
{
	sf::SoundBuffer buffer;
	sf::Sound sound;
public:
	SoundEffect(std::string filePath, float volume);
	SoundEffect(std::string filePath, sf::Sound sound);
	SoundEffect(){ }

	float getVolume() const;
	void setVolume(float volume);

	void play();
	void pause();
	void stop();
}; 

[/spoiler]

SoundEffect.cpp
[spoiler]


#include "SoundEffect.h"
#include "includes.h"

SoundEffect::SoundEffect(std::string filePath, float volume){
	if (!buffer.loadFromFile(filePath))
		std::exit(-2);
	sound.setBuffer(buffer);
	sound.setVolume(volume);
}

SoundEffect::SoundEffect(std::string filePath, sf::Sound sound){
	if (!buffer.loadFromFile(filePath))
		std::exit(-2);
	this->sound = sound;
	this->sound.setBuffer(buffer);
}

float SoundEffect::getVolume() const{
	return sound.getVolume();
}

void SoundEffect::setVolume(float volume){
	sound.setVolume(volume);
}

void SoundEffect::play(){
	sound.play();
}

void SoundEffect::pause(){
	sound.pause();
}

void SoundEffect::stop(){
	sound.stop();
} 

[/spoiler]

Overall I would say you have done a good work, but I also see room for a lot of improvement here.

Here are some hints in a blog post I wrote:

http://www.flodihn.se/2014/05/20/guide-lines-to-clean-code-on-the-small-scope/

In addition to what the blog say, limit your functions to 10-40 lines of code.

Advertisement

Overall I would say you have done a good work, but I also see room for a lot of improvement here.

Here are some hints in a blog post I wrote:

http://www.flodihn.se/2014/05/20/guide-lines-to-clean-code-on-the-small-scope/

In addition to what the blog say, limit your functions to 10-40 lines of code.

Thanks for the feedback, I read your blog post and it helped me a lot with understanding code design. I'm gonna try sticking to some of the things you said in there in my next project (Missile Command), I was thinking of taking a whole new design path to my code this time over by placing the entire game into a class system so that my main function isn't so cluttered and so that I don't need to pass so many parameters when I want do something as simple as poll events etc..

Hi,

Previously, most here have done a good overview of your code. I would like to draw attention to the game's playability. By making a new game, it is more important than clean code.

1) Tiles with explosion effect should disappear.
2) The game belongs all good background music and sound effects.
3) Depending on the level of the game, the game background should change the artistic images.
4) Management should be by: joystic, gamepad, keyboard and mouse.
5) The results achieved memorize topical and place it on the Internet globally.
6) Arrange for the use of resources and the game does not take up 100% of the CPU and GPU.

Good success.

(c) 2000 by "vvv2".

Hi

Hi.

1) Tiles with explosion effect should disappear.

They do disappear,
The way it works is, when the ball hits a tile, the tile explodes, and all tiles immediately next to it are removed in a pattern like so:
O = Hit tile
- = Affected tile
. = nothing
.........-------
------- OOO -------
.........-------

2) The game belongs all good background music and sound effects.

There are sound effects tongue.png , the video just didn't catch them for some reason.
You're right about music I should get on that.

3) Depending on the level of the game, the game background should change the artistic images.

I was thinking about that, but then I remembered the DX-Ball 2 game with it's background feature, and I kind of disliked it. It made it hard for me to see the moving ball at times. I made the background dark gray in order to be able to have black tiles and because that shade of gray is rarely used.

4) Management should be by: joystic, gamepad, keyboard and mouse.

I never thought about that, will get on it.

5) The results achieved memorize topical and place it on the Internet globally.

I don't understand, could you rephrase?

6) Arrange for the use of resources and the game does not take up 100% of the CPU and GPU.

I never really got into that, gonna have to check it out first.

Good success.

Thanks.

>> I don't understand, could you rephrase?

- Sorry, I had thought, that the result of the game is a very important reason to play. It is therefore appropriate to save it to a local HDD on its own computer and to be able to compare it in the global Internet.

Thanks.

(c) 2000 by "vvv2".
Advertisement

Sounds like vvv2 is talking about high score lists. Locally (just on the computer the game is played on) or globally (connecting to a server on the internet somewhere).

Hello to all my stalkers.

Sorry, I had thought, that the result of the game is a very important reason to play. It is therefore appropriate to save it to a local HDD on its own computer and to be able to compare it in the global Internet.

Sounds like vvv2 is talking about high score lists. Locally (just on the computer the game is played on) or globally (connecting to a server on the internet somewhere).

Oh, yeah, high scores. I wanted to do that, but I was missing the required menu system for my game. I'll probably just save the result to a file an be done with it. Thanks for clarifying.

This topic is closed to new replies.

Advertisement