Jump to content

  • Log In with Google      Sign In   
  • Create Account

Calling all IT Pros from Canada and Australia.. we need your help! Support our site by taking a quick sponsored surveyand win a chance at a $50 Amazon gift card. Click here to get started!


Gaius Baltar

Member Since 06 Jul 2014
Offline Last Active Aug 15 2015 09:01 PM

#5237903 Issue with personal DirectX Framework

Posted by Gaius Baltar on 01 July 2015 - 03:06 PM

First off I'd like to point out that I'm an absolute beginner regarding 3D graphics programming and DirectX in general. So if you have any code optimization tips for me I'll accept them with open arms.
 
I've been learning my way about the DirectX API using SlimDX and the help of some useful resources like Frank D. Luna's book on programming with DirectX 11 and this site. (The book and site go very well together, especially for someone learning to use DirectX with C#).
 
Anyhow, I've recently finished chapter 6 of Luna's book and decided to try and make a personal DirectX framework of sorts for learning purposes, but now that I've got a sort of skeleton of the thing going, it throws weird errors at me occasionally or it just doesn't do what I want it to (display a cube in this case).
 
So, here it is:
 
Window.cs
Spoiler

 
Sahder.cs
Spoiler

 
Entity3D.cs
Spoiler

 
Cube.cs
Spoiler

 
Vertex.cs
Spoiler

 
Program.cs //Main entry point
 
Spoiler

 
And lastly, my shader, "shader.fx"
Spoiler

 
I'd like to leave you with a screenshot of what I get when I run Program.cs:
xLWUvXf.png
 
Also, please don't bash the hard-coded stuff too much, everything so far is mostly just placeholder code for me to get my bearings.


#5176704 c# method question

Posted by Gaius Baltar on 28 August 2014 - 10:53 AM

Wow, thanks for the quick replies. Both of the suggestions above work and I will keep both in mind for the future.

 

It appears, I was wrong, go with Nypyren's suggestion, in this case it would be the better solution overall.




#5176520 c# method question

Posted by Gaius Baltar on 27 August 2014 - 03:54 PM

Disregard this post. 




#5176513 c# method question

Posted by Gaius Baltar on 27 August 2014 - 03:22 PM

Disregard this post




#5176297 Line vs Triangle collision in 3D

Posted by Gaius Baltar on 26 August 2014 - 03:42 PM

I'm just guessing right now, so this might be wrong:

 

First check if the line ever passes the triangle, if yes, take the point where the line passes the triangle and make three more triangles with each of the points of the original triangle and the point like so:

 

7zog0Lp.png

 

 

If the area of the three triangles is equal to the area of the larger triangle, you have yourself an intersection.

I actually had a quick glimpse at a youtube video talking about this kind of intersection, thought it might be worth sharing my two cents.

 

Edit: Here's the video: 




#5175652 3D Graphics with C#

Posted by Gaius Baltar on 23 August 2014 - 10:25 AM

You can use OpenTK for C#, it might even be what 3ddreamer meant with "There is an OpenGL library for 3D but I don't remember what it is called".




#5175470 Missile Command code review request

Posted by Gaius Baltar on 22 August 2014 - 07:46 AM

I recently finished programming a clone to the popular game Missile Command as part of the "getting started" article on gamedev.net. This project took me about two weeks to complete whilst working on it every now and then. The code contains over 1500 lines of C++ and SFML. This time I took a different design approach to my previous projects in order to simplify the code and make it more readable... hopefully.

 

Links to my other projects in this series:

Breakout

Snake

Pong

 

Video of my Missile Command clone:

 

Download:

https://www.dropbox.com/s/07lq4wc5fsp1djb/Missile%20Command.zip

(Please tell me if the game doesn't work)

 

Features:

Crappy UI

Highscores

Explosions 

 

Screenshots:

 

j1hCiNy.png

8QaWa3D.png

 

sA2uS5R.png

 

7IJDoBn.png

 

 

Files:

 

U3GL4T7.png

 

 

Last but not least: A huge chunk of code.

 

main.cpp

#include "init.h"

int main(){
	Missile_Command game;

	game.run();

	return 0;
}

init.h

#pragma once

// C++
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <sstream>

// SFML
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <SFML/Network.hpp>

// Framework
#include "SoundEffect.h"
#include "Entity.h"
#include "Button.h"
#include "Math.h"
#include "Collision_Detection.h"
#include "Windows_Stuff.h"

// Game
#include "Missiles.h"
#include "Missile_Command.h"

// Globals
const float SECOND = 1000;
const float BLOCKSIZE = 20;
const int GRIDSIZE_X = 50;
const int GRIDSIZE_Y = 30;
const int SCRW = (int)BLOCKSIZE * GRIDSIZE_X;
const int SCRH = (int)BLOCKSIZE * GRIDSIZE_Y;
const double INTERVAL = 16.6; // 1000 / INTERVAL = FPS -> ~60
const sf::Color CLEARCOLOR(sf::Color(0, 0, 0));

Missile_Command.h

#pragma once
struct Particle;

enum class GameState{
	Home,
	Settings,
	About,
	Highscores,
	Playing,
	Paused,
	GameOver,
	Win
};

class Missile_Command{
	sf::RenderWindow _window;
	sf::Event _event;
	GameState _gameState;
	sf::Clock _clock;

	sf::Font _font;
	sf::Text _aboutText;
	sf::Text _volumeText;
	sf::Text _volumeInfoText;
	sf::Text _scoreText;
	sf::Text _inGameInfoText;
	sf::Text _gameOverText;
	sf::Text _winText;
	sf::Text _highscoreNamesText;
	sf::Text _highscoreScoresText;
	sf::Text _ammunitionText;

	sf::Texture _bgTex;
	sf::Sprite _bgSprite1;
	sf::Sprite _bgSprite2;

	sf::Vector2f _wallSize;
	sf::Vector2f _windowCenter;
	sf::Vector2f _playerCenterLoc;
	sf::Vector2f _missileSize;
	std::vector<sf::Vector2f> _enemyVel;

	int _score;
	int _wave;
	int _ammunition;
	int _enemyCount; // wave limit
	int _enemiesSpawned; // amount of enemies spawned in this wave
	float _explosionExpandVel;
	float _explosionFadeVel;
	size_t _updates;
	double _skippedTime;
	double _secondSkipped;
	float _canonAngle;
	float _missileSpeed;
	float _enemySpeed;
	float _bgMoveVel;
	float _bgOriginMoveVel;
	float _floorHeight;
	float _playerSize;
	float _volume;
	std::string _playerName;
	std::vector<std::string> _highscores;

	sf::Color _playerColor;
	sf::Color _baseColor;
	sf::Color _buttonColor;
	sf::Color _buttonHoverColor;
	sf::Color _missileColor;
	sf::Color _baseExplodeColor;
	sf::Color _baseFadeColor;
	sf::Color _enemyExplodeColor;
	sf::Color _enemyFadeColor;

	sf::RectangleShape colBounds;
	Missiles _missiles;
	EntityR _canon;
	EntityR _bunkerBase;
	EntityC _bunkerTop;
	EntityC _playerFloor;
	std::vector<EntityR> _floor;
	std::vector<EntityC> _bases;
	std::vector<EntityC> _enemies;
	Particles _menuEffect;
	Particles _trails; // comet trails

	SoundEffect _shootSound;
	SoundEffect _explodeSound;
	SoundEffect _loseSound;
	SoundEffect _waveWinSound;
	std::vector<SoundEffect> _hoverSounds;

	ui::Button _quit;
	ui::Button _start;
	ui::Button _settings;
	ui::Button _about;
	ui::Button _highscoresBtn;
	ui::Button _back;
	ui::Button _continue;
	ui::Button _pauseQuit;
	ui::Button _home;
	ui::Button _volumeDown;
	ui::Button _volumeUp;
	ui::Button _lastHovered; // used to detect the button that was last hovered over

	void init();
	void initFloor();
	void initPlayer();
	void initEnemy();
	void initButtons();
	void initText();
	void initSounds();

	void doEvents();
	void reset();
	// Load menus
	void loadHome();
	void loadSettings();
	void loadAbout();
	void loadHighscores();
	void loadPlaying();
	void loadPaused();
	void loadGameOver();
	void loadWin();

	void update();
	void updateBG();
	void updateMenuEffect();
	void updateEnemies();

	void render();
	void renderHome();
	void renderSettings();
	void renderAbout();
	void renderHighScores();
	void renderPlaying();
	void renderPause();
	void renderGameOver();
	void renderWin();
	void renderMenuEffect();
	void renderBG();

	void doHover(ui::Button & button);
	void setVolume();
	void spawnEnemy();
	void removeEnemyAt(size_t index);
	void doCollisions();
	void removeBaseAt(size_t index);
	void nextWave();
	std::vector<std::string> split(std::string string, char splitParam);
	void getHighscores();
	bool addHighscore();
	void writeHighscores();
	void sortHighscores();
public:
	Missile_Command();
	~Missile_Command();

	void run();
};

Missile_Command.cpp (~800 Lines)

#include "init.h"


Missile_Command::Missile_Command(){
	srand((size_t)time(0));
	init();
}


Missile_Command::~Missile_Command(){
	// Destroy
}

void Missile_Command::init(){
	_window.create(sf::VideoMode(SCRW, SCRH), "Missile Command");

	_missileSize = sf::Vector2f(4, 4);
	_explosionExpandVel = 0.8f;
	_explosionFadeVel = 2.2f;
	_missileSpeed = 12.0f;
	_skippedTime = 0;
	_updates = 0;
	_secondSkipped = 0;
	_bgOriginMoveVel = 1.0f;
	_bgMoveVel = _bgOriginMoveVel;
	_enemySpeed = 1.0f;
	_volume = 30;
	_baseExplodeColor = sf::Color(0, 100, 255);
	_baseFadeColor = sf::Color(200, 50, 10);
	_enemyExplodeColor = sf::Color::Yellow;
	_enemyFadeColor = sf::Color::Magenta;
	_playerColor = sf::Color::White;
	_baseColor = sf::Color(56, 78, 90, 200);
	_buttonColor = sf::Color(255, 255, 255, 128);
	_buttonHoverColor = sf::Color((sf::Uint8)(_buttonColor.r / 1.5), (sf::Uint8)(_buttonColor.g / 1.5), (sf::Uint8)(_buttonColor.b / 1.5, 128));
	_missileColor = sf::Color(255, 165, 0);
	_floorHeight = 50;
	_wallSize = sf::Vector2f(_floorHeight, _floorHeight * 2.0f);
	_playerSize = _floorHeight;
	_windowCenter = (sf::Vector2f)_window.getSize() / 2.0f;
	if (!_bgTex.loadFromFile("sprites/bg.png"))
		std::exit(-4);
	_bgSprite1.setTexture(_bgTex);
	_bgSprite2.setTexture(_bgTex);
	_bgSprite1.setPosition(0, 0);
	_bgSprite2.setPosition(_bgSprite1.getPosition().x - _bgTex.getSize().x, 0);

	initFloor();
	initButtons();
	initText();
	initSounds();
	initPlayer();

	_playerCenterLoc = _bunkerTop.getPosition() + sf::Vector2f(_bunkerTop.getRadius(), _bunkerTop.getRadius());
	reset();
	_gameState = GameState::Home; // Temporary -> Home
}

void Missile_Command::initFloor(){
	_floor.resize(3);
	_floor[0] = EntityR(sf::Vector2f((float)_window.getSize().x, _floorHeight), sf::Vector2f(0.0f, (float)_window.getSize().y - _floorHeight), _playerColor); // Main floor
	_floor[1] = EntityR(_wallSize, sf::Vector2f(0, _window.getSize().y - (_floorHeight + _wallSize.y)), _playerColor); // Left wall
	_floor[2] = EntityR(_wallSize, (sf::Vector2f)_window.getSize() - sf::Vector2f(_wallSize.x, _floorHeight + _wallSize.y), _playerColor); // Right wall
	_playerFloor = EntityC(_playerSize * 2.0f, 9, sf::Vector2f(_windowCenter.x - _playerSize * 2.0f, _window.getSize().y - _floorHeight * 2.0f), _playerColor);
}

void Missile_Command::initPlayer(){
	_bunkerBase = EntityR(sf::Vector2f(_playerSize, _playerSize / 2.1f), sf::Vector2f(_windowCenter.x - _playerSize / 2.0f, _playerFloor.getPosition().y - _playerSize / 4.2f), _playerColor);
	_bunkerTop = EntityC(_playerSize / 2.0f, 40, sf::Vector2f(_windowCenter.x - _playerSize / 2.0f, _playerFloor.getPosition().y - _playerSize / 1.5f), _playerColor);
	_canon = EntityR(sf::Vector2f(_playerSize / 5.0f, _playerSize / 1.2f), sf::Vector2f(_windowCenter.x, _bunkerTop.getPosition().y + _bunkerTop.getRadius()), _playerColor);
	_canon.setOrigin(sf::Vector2f(_canon.getSize().x / 2.0f, _canon.getSize().y));

	// Init bases
	_bases.resize(6);
	_bases[0] = EntityC(50, 10, sf::Vector2f(100, 520), _baseColor);
	_bases[1] = EntityC(50, 10, sf::Vector2f(200, 520), _baseColor);
	_bases[2] = EntityC(50, 10, sf::Vector2f(300, 520), _baseColor);
	_bases[3] = EntityC(50, 10, sf::Vector2f(600, 520), _baseColor);
	_bases[4] = EntityC(50, 10, sf::Vector2f(700, 520), _baseColor);
	_bases[5] = EntityC(50, 10, sf::Vector2f(800, 520), _baseColor);
}

void Missile_Command::initEnemy(){
	_enemies.clear();
	_enemyVel.clear();
}

void Missile_Command::initButtons(){
	_start = ui::Button("Start", 50, sf::Vector2f(15, 0), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf");
	_settings = ui::Button("Settings", 50, sf::Vector2f(15, 80), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf");
	_about = ui::Button("About", 50, sf::Vector2f(15, 160), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf");
	_highscoresBtn = ui::Button("Highscores", 50, sf::Vector2f(15, 240), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf");
	_quit = ui::Button("Quit", 50, sf::Vector2f(15, 320), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf");
	_back = ui::Button("Back", 50, sf::Vector2f(15.0f, SCRH - 90.0f), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf");
	_continue = ui::Button("Continue", 50, sf::Vector2f(400, 260), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf");
	_pauseQuit = ui::Button("Home", 50, sf::Vector2f(250, 260), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf");
	_volumeDown = ui::Button("<", 50, sf::Vector2f(15, 40), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf");
	_volumeUp = ui::Button(">", 50, sf::Vector2f(130, 40), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf");
}

void Missile_Command::initText(){
	_font.loadFromFile("fonts/segoeuil.ttf");

	_aboutText.setFont(_font);
	_volumeText.setFont(_font);
	_volumeInfoText.setFont(_font);
	_scoreText.setFont(_font);
	_inGameInfoText.setFont(_font);
	_gameOverText.setFont(_font);
	_winText.setFont(_font);
	_highscoreNamesText.setFont(_font);
	_highscoreScoresText.setFont(_font);
	_ammunitionText.setFont(_font);

	_aboutText.setString("Game is controlled solely through mouse input.\n\n	Programming: Gaius Baltar\n	Sound effects: Gaius Baltar");
	_volumeText.setString(std::to_string(_volume));
	_volumeText.setCharacterSize(50);
	_volumeText.setPosition(sf::Vector2f(65, 50));
	_volumeInfoText.setString("Volume:");
	_volumeInfoText.setCharacterSize(50);
	_volumeInfoText.setPosition(sf::Vector2f(15, 0));
	_scoreText.setCharacterSize(50);
	_scoreText.setPosition(sf::Vector2f(250, 180));
	_inGameInfoText.setCharacterSize(20);
	_gameOverText.setCharacterSize(50);
	_gameOverText.setPosition(sf::Vector2f(250, 100));
	_gameOverText.setString("You lose...");
	_winText.setCharacterSize(50);
	_winText.setPosition(sf::Vector2f(250, 100));
	_winText.setString("You Win!");
	_highscoreNamesText.setCharacterSize(30);
	_highscoreNamesText.setPosition(sf::Vector2f(50, 50));
	_highscoreScoresText.setCharacterSize(30);
	_highscoreScoresText.setPosition(sf::Vector2f(500, 50));
	_ammunitionText.setCharacterSize(50);
	_ammunitionText.setPosition(sf::Vector2f(475, 510));
	_ammunitionText.setColor(sf::Color::Black);
}

void Missile_Command::initSounds(){
	_shootSound = SoundEffect("sounds/shoot.wav", _volume);
	_explodeSound = SoundEffect("sounds/explode.wav", _volume);
	_loseSound = SoundEffect("sounds/lose.wav", _volume);
	_waveWinSound = SoundEffect("sounds/win.wav", _volume);
	_hoverSounds.resize(5);
	for (size_t i = 0; i < _hoverSounds.size(); i++){
		_hoverSounds[i] = SoundEffect("sounds/hover" + std::to_string(i + 1) + ".wav", _volume);
	}
}

void Missile_Command::doEvents(){
	while (_window.pollEvent(_event)){
		if (_event.type == sf::Event::Closed){
			_window.close();
		}
		switch (_gameState){
		case GameState::Home:
			if (_event.type == sf::Event::KeyPressed && _event.key.code == sf::Keyboard::Escape || _quit.isPressed(_event)){
				_window.close();
			}

			if (_start.isPressed(_event))
				loadPlaying();
			if (_settings.isPressed(_event))
				loadSettings();
			if (_about.isPressed(_event))
				loadAbout();
			if (_highscoresBtn.isPressed(_event))
				loadHighscores();
			if (_event.type == sf::Event::MouseMoved){
				doHover(_quit);
				doHover(_start);
				doHover(_settings);
				doHover(_about);
				doHover(_highscoresBtn);
			}
			break;
		case GameState::Settings:
			if (_event.type == sf::Event::KeyPressed && _event.key.code == sf::Keyboard::Escape){
				loadHome();
			}
			if (_volumeDown.isPressed(_event) && _volume > 0){
				_volume -= 1;
				_volumeText.setString(std::to_string((int)_volume));
				setVolume();
			}
			if (_volumeUp.isPressed(_event) && _volume < 100){
				_volume += 1;
				_volumeText.setString(std::to_string((int)_volume));
				setVolume();
			}
			if (_back.isPressed(_event))
				loadHome();
			if (_event.type == sf::Event::MouseMoved){
				doHover(_back);
				doHover(_volumeDown);
				doHover(_volumeUp);
			}
			break;
		case GameState::About:
			if (_event.type == sf::Event::KeyPressed && _event.key.code == sf::Keyboard::Escape){
				loadHome();
			}
			if (_back.isPressed(_event))
				loadHome();
			if (_event.type == sf::Event::MouseMoved){
				doHover(_back);
			}
			break;
		case GameState::Highscores:
			if (_event.type == sf::Event::KeyPressed && _event.key.code == sf::Keyboard::Escape){
				loadHome();
			}
			if (_back.isPressed(_event))
				loadHome();
			if (_event.type == sf::Event::MouseMoved){
				doHover(_back);
			}
			break;
		case GameState::Playing:
			if (_event.type == sf::Event::KeyPressed){
				if (_event.key.code == sf::Keyboard::Space){
					_missiles.explodeAtPosition(_playerFloor.getPosition() + sf::Vector2f(_playerFloor.getRadius(), _playerFloor.getRadius()), 0.5f, 7.0f, sf::Color(155, 115, 0), sf::Color(100, 0, 0));
				}
				if (_event.key.code == sf::Keyboard::Escape)
					loadPaused();
			}
			if (_event.type == sf::Event::MouseButtonPressed){
				if (_event.mouseButton.button == sf::Mouse::Left && _ammunition > 0){
					_shootSound.play();
					_canonAngle = (float)mth::getAngleInRadians(_playerCenterLoc, (sf::Vector2f)sf::Mouse::getPosition(_window));
					_missiles.fireMissile(mth::getVelocity(_canonAngle, _missileSpeed), (sf::Vector2f)sf::Mouse::getPosition(_window));
					_ammunition--;
				}
			}
			break;
		case GameState::Paused:
			if (_event.type == sf::Event::KeyPressed && _event.key.code == sf::Keyboard::Escape){
				loadPlaying();
			}
			if (_continue.isPressed(_event))
				loadPlaying();
			if (_pauseQuit.isPressed(_event))
				loadHome();
			if (_event.type == sf::Event::MouseMoved){
				doHover(_continue);
				doHover(_pauseQuit);
			}
			break;
		case GameState::GameOver:
			if (_event.type == sf::Event::KeyPressed && _event.key.code == sf::Keyboard::Escape){
				loadHome();
			}
			if (_pauseQuit.isPressed(_event))
				loadHome();
			if (_continue.isPressed(_event)){
				reset();
				loadPlaying();
			}
			if (_event.type == sf::Event::MouseMoved){
				doHover(_pauseQuit);
				doHover(_continue);
			}
			break;
		case GameState::Win:
			if (_event.type == sf::Event::KeyPressed && _event.key.code == sf::Keyboard::Escape){
				loadPlaying();
			}
			if (_pauseQuit.isPressed(_event))
				loadHome();
			if (_continue.isPressed(_event)){
				loadPlaying();
			}
			if (_event.type == sf::Event::MouseMoved){
				doHover(_pauseQuit);
				doHover(_continue);
			}
			break;
		default:
			break;
		}
	}
}

void Missile_Command::reset(){
	_wave = 0;
	nextWave();
	_ammunition = 40;
	_score = 0;
	_missiles = Missiles(_missileSize, _playerCenterLoc, _missileColor, sf::Color::Red, _explosionExpandVel, _explosionFadeVel);
	initPlayer();
	initEnemy();
	_menuEffect.clear();
	_trails.clear();

}

void Missile_Command::loadHome(){
	_gameState = GameState::Home;
	_bgMoveVel = _bgOriginMoveVel;
	reset();
}

void Missile_Command::loadSettings(){
	_gameState = GameState::Settings;
	_volumeText.setString(std::to_string((int)_volume));
	_bgMoveVel = _bgOriginMoveVel;
}

void Missile_Command::loadAbout(){
	_gameState = GameState::About;
	_bgMoveVel = _bgOriginMoveVel;
}

void Missile_Command::loadHighscores(){
	_gameState = GameState::Highscores;
	_bgMoveVel = _bgOriginMoveVel;
	getHighscores();
	sortHighscores();
	std::string namesList;
	std::string scoresList;
	for (size_t i = 0; i < _highscores.size() - 1; i += 2){
		namesList += std::to_string((i+2)/2) + ". " + _highscores[i] + "\n";
		scoresList += _highscores[i + 1] + "\n";
	}
	_highscoreNamesText.setString(namesList);
	_highscoreScoresText.setString(scoresList);
}

void Missile_Command::loadPlaying(){
	_gameState = GameState::Playing;
	_menuEffect.clear();
	_bgMoveVel = _bgOriginMoveVel / 3.0f;
}

void Missile_Command::loadPaused(){
	_continue.setString("Continue");
	_gameState = GameState::Paused;
	_bgMoveVel = _bgOriginMoveVel * 2.0f;
}

void Missile_Command::loadGameOver(){
	_gameState = GameState::GameOver;
	_continue.setString("Restart");
	_bgMoveVel = _bgOriginMoveVel * 2.0f;
	_enemies.clear();
	_enemyVel.clear();
	_missiles.clear();
	_score += _ammunition * 10;
	_score += _bases.size() * 100;
	_scoreText.setString("Score: " + std::to_string(_score));
	if (_playerName.size() <= 0){
		std::cout << "\n\n\nPlease enter your name for the highscores list:\n\n\n";
		std::getline(std::cin, _playerName);
	}
	addHighscore();
}

void Missile_Command::loadWin(){
	_gameState = GameState::Win;
	_continue.setString("Continue");
	_bgMoveVel = _bgOriginMoveVel * 2.0f;
	_enemies.clear();
	_enemyVel.clear();
	_missiles.clear();
	_score += _ammunition * 10;
	_score += _bases.size() * 100;
	_ammunition = 40;
	_scoreText.setString("Score: " + std::to_string(_score));
	nextWave();
}

void Missile_Command::update(){
	switch (_gameState){
	case GameState::Home:
		updateBG();
		updateMenuEffect();
		break;
	case GameState::Settings:
		updateBG();
		updateMenuEffect();
		break;
	case GameState::About:
		updateBG();
		updateMenuEffect();
		break;
	case GameState::Highscores:
		updateBG();
		updateMenuEffect();
		break;
	case GameState::Playing:
		updateBG();
		_canon.setRotation(90 + (float)mth::getAngleInDegrees(_playerCenterLoc, (sf::Vector2f)sf::Mouse::getPosition(_window)));
		_inGameInfoText.setString("Score: " + std::to_string(_score) + "	Wave: " + std::to_string(_wave) + "	Enemies remaining: " + std::to_string(_enemyCount - _enemiesSpawned));
		_ammunitionText.setString(std::to_string(_ammunition));
		_missiles.update(_explodeSound);
		updateEnemies();
		doCollisions();
		if (rand() % 1000 <= _wave * 10 && _enemiesSpawned < _enemyCount){
			spawnEnemy();
			_enemiesSpawned++;
		}
		if (_bases.size() <= 0){
			_loseSound.play();
			loadGameOver();
		}
		if (_enemies.size() <= 0 && _enemiesSpawned >= _enemyCount){
			_waveWinSound.play();
			loadWin();
		}
		if (_wave > 10){
			_waveWinSound.play();
			loadGameOver();
			loadHighscores();
		}
		break;
	case GameState::Paused:
		_bgMoveVel = _bgOriginMoveVel * 2.0f;
		updateBG();
		updateMenuEffect();
		break;
	case GameState::GameOver:
		_bgMoveVel = _bgOriginMoveVel * 2.0f;
		updateBG();
		updateMenuEffect();
		break;
	case GameState::Win:
		_bgMoveVel = _bgOriginMoveVel * 2.0f;
		updateBG();
		updateMenuEffect();
		break;
	}
}

void Missile_Command::updateBG(){
	_bgSprite1.setPosition(_bgSprite1.getPosition() + sf::Vector2f(_bgMoveVel, 0));
	_bgSprite2.setPosition(_bgSprite2.getPosition() + sf::Vector2f(_bgMoveVel, 0));
	if (_bgSprite1.getPosition().x > _window.getSize().x)
		_bgSprite1.setPosition(_bgSprite2.getPosition().x - _bgTex.getSize().x, 0);
	if (_bgSprite2.getPosition().x > _window.getSize().x)
		_bgSprite2.setPosition(_bgSprite1.getPosition().x - _bgTex.getSize().x, 0);
}

void Missile_Command::updateMenuEffect(){
	if (rand() % 1000 <= 100){
		_menuEffect.append(sf::Vector2f((float)(rand() % SCRW), (float)(rand() % SCRH)), 500, sf::Color(rand() % 256, rand() % 256, rand() % 256, 20));
	}
	if (_menuEffect.particles.size() > 1000)
		_menuEffect.clear();
}

void Missile_Command::updateEnemies(){
	for (size_t i = 0; i < _enemies.size(); i++){
		_enemies[i].setPosition(_enemies[i].getPosition() + _enemyVel[i]);
		if (rand() % 1000 < 200){
			_trails.append(_enemies[i].getPosition() + sf::Vector2f((float)(rand() % 10), 0.0f), 500, sf::Color(200, rand() % 100 + 150, rand() % 100 + 150));
		}
	}

	for (size_t i = 0; i < _trails.life.size(); i++){
		_trails.life[i]--;
		if (_trails.life[i] <= 0){
			_trails.removeAt(i);
		}
	}
}

void Missile_Command::render(){
	_window.clear(CLEARCOLOR);
	switch (_gameState){
	case GameState::Home:
		renderBG();
		renderMenuEffect();
		renderHome();
		break;
	case GameState::Settings:
		renderBG();
		renderMenuEffect();
		renderSettings();
		break;
	case GameState::About:
		renderBG();
		renderMenuEffect();
		renderAbout();
		break;
	case GameState::Highscores:
		renderBG();
		renderMenuEffect();
		renderHighScores();
		break;
	case GameState::Playing:
		renderBG();
		_window.draw(colBounds);
		renderPlaying();
		break;
	case GameState::Paused:
		renderBG();
		renderMenuEffect();
		renderPlaying();
		renderPause();
		break;
	case GameState::GameOver:
		renderBG();
		renderMenuEffect();
		renderPlaying();
		renderGameOver();
		break;
	case GameState::Win:
		renderBG();
		renderMenuEffect();
		renderPlaying();
		renderWin();
		break;
	}
	_window.display();
}

void Missile_Command::renderHome(){
	_window.draw(_start);
	_window.draw(_settings);
	_window.draw(_about);
	_window.draw(_highscoresBtn);
	_window.draw(_quit);
}

void Missile_Command::renderSettings(){
	_window.draw(_back);
	_window.draw(_volumeDown);
	_window.draw(_volumeUp);
	_window.draw(_volumeText);
	_window.draw(_volumeInfoText);
}

void Missile_Command::renderAbout(){
	_window.draw(_aboutText);
	_window.draw(_back);
}

void Missile_Command::renderHighScores(){
	_window.draw(_back);
	_window.draw(_highscoreNamesText);
	_window.draw(_highscoreScoresText);
}

void Missile_Command::renderPlaying(){
	for (auto item : _enemies)
		_window.draw(item);
	if (_trails.particles.size() > 0)
		_window.draw(&_trails.particles[0], _trails.particles.size(), sf::PrimitiveType::Points);
	_window.draw(_missiles);
	for (auto item : _bases)
		_window.draw(item);
	for (auto item : _floor)
		_window.draw(item);
	_window.draw(_bunkerBase);
	_window.draw(_bunkerTop);
	_window.draw(_canon);
	_window.draw(_playerFloor);
	_window.draw(_ammunitionText);
	_window.draw(_inGameInfoText);
}

void Missile_Command::renderPause(){
	_window.draw(_continue);
	_window.draw(_pauseQuit);
}

void Missile_Command::renderGameOver(){
	_window.draw(_pauseQuit);
	_window.draw(_gameOverText);
	_window.draw(_scoreText);
}

void Missile_Command::renderWin(){
	_window.draw(_pauseQuit);
	_window.draw(_continue);
	_window.draw(_winText);
	_window.draw(_scoreText);
}

void Missile_Command::renderMenuEffect(){
	if (_menuEffect.particles.size() > 0)
		_window.draw(&_menuEffect.particles[0], _menuEffect.particles.size(), sf::PrimitiveType::Triangles);
}

void Missile_Command::renderBG(){
	_window.draw(_bgSprite1);
	_window.draw(_bgSprite2);
}

void Missile_Command::doHover(ui::Button & button){
	if (button.isHovering(_event)){
		if (_lastHovered.getString() != button.getString()){
			button.setButtonFaceColor(_buttonHoverColor);
			_hoverSounds[rand() % _hoverSounds.size()].play();
			_lastHovered.setString(button.getString());
		}
	}
	else{
		if (_lastHovered.getString() == button.getString())
			_lastHovered.setString(" ");
		button.setButtonFaceColor(_buttonColor);
	}
}

void Missile_Command::setVolume(){
	_shootSound.setVolume(_volume);
	_explodeSound.setVolume(_volume);
	_loseSound.setVolume(_volume);
	_waveWinSound.setVolume(_volume);
	for (int i = 0; i < _hoverSounds.size();i++)
		_hoverSounds[i].setVolume(_volume);
}

void Missile_Command::spawnEnemy(){
	if (rand() % 2 == 0){
		_enemies.push_back(EntityC(5, 5, sf::Vector2f((float)(rand() % 490), -10.0f), sf::Color::Red));
		_enemyVel.push_back(sf::Vector2f(_enemySpeed / (rand() % 5 + 1), _enemySpeed));
	}
	else{
		_enemies.push_back(EntityC(5, 5, sf::Vector2f((float)(rand() % 490 + 500), -10.0f), sf::Color::Red));
		_enemyVel.push_back(sf::Vector2f((_enemySpeed / (rand() % 5 + 1)) * -1, _enemySpeed));
	}
}

void Missile_Command::removeEnemyAt(size_t index){
	_enemies.erase(_enemies.begin() + index);
	_enemyVel.erase(_enemyVel.begin() + index);
}

void Missile_Command::doCollisions(){
	// Missiles -> Enemies
	for (auto missile : _missiles.getExplosions()){
		for (size_t i = 0; i < _enemies.size(); i++){
			if (cd::doesIntersect(missile, _enemies[i])){
				_explodeSound.play();
				_missiles.explodeAtPosition(_enemies[i].getPosition() + sf::Vector2f(_enemies[i].getRadius(), _enemies[i].getRadius()), 1.05f, 0.3f, _enemyExplodeColor, _enemyFadeColor);
				_score += 10;
				removeEnemyAt(i);
				i--;
			}
		}
	}

	// Enemies -> Bases
	for (size_t i = 0; i < _enemies.size(); i++){
		if (_enemies[i].getPosition().y > _window.getSize().y - 200){
			for (size_t j = 0; j < _bases.size(); j++){
				if (_enemies.size() > 0 && cd::doesIntersect(_enemies[i], _bases[j])){
					_explodeSound.play();
					_missiles.explodeAtPosition(_bases[j].getPosition() + sf::Vector2f(_bases[j].getRadius(), _bases[j].getRadius()), 1.5f, 3.0f, _baseExplodeColor, _baseFadeColor);
					removeBaseAt(j);
					removeEnemyAt(i);
					_score += 100 / (_bases.size() + 1);
					std::cout << "sup\n";
					i = i - 1 > 0 ? i - 1 : i;
					break;
				}
			}
		}
	}

	// Enemies -> Floor
	for (size_t i = 0; i < _enemies.size(); i++){
		if (_enemies[i].getPosition().y > _window.getSize().y - 200){
			if (_enemies.size() > 0 && _enemies[i].getPosition().y > _window.getSize().y - 60){
				_explodeSound.play();
				_missiles.explodeAtPosition(_enemies[i].getPosition() + sf::Vector2f(_enemies[i].getRadius(), _enemies[i].getRadius()), 1.05f, 0.3f, _enemyExplodeColor, _enemyFadeColor);
				removeEnemyAt(i);
				_score -= 10;
				i = i - 1 > 0 ? i - 1 : i;
				continue;
			}
			else if (_enemies.size() > 0 && cd::doesIntersect(_enemies[i], _playerFloor)){
				_explodeSound.play();
				_missiles.explodeAtPosition(_enemies[i].getPosition() + sf::Vector2f(_enemies[i].getRadius(), _enemies[i].getRadius()), 1.05f, 0.3f, _enemyExplodeColor, _enemyFadeColor);
				removeEnemyAt(i);
				if (_ammunition >= 5)
					_ammunition -= 5;
				else
					_ammunition = 0;
				i = i - 1 > 0 ? i - 1 : i;
				continue;
			}
		}
	}
}

void Missile_Command::removeBaseAt(size_t index){
	_bases.erase(_bases.begin() + index);
}

void Missile_Command::nextWave(){
	_wave++;
	_enemyCount = (_wave * _wave) + (_wave * _wave) + 10;
	_enemySpeed = _wave / 10.0f + 0.5f;
	_enemiesSpawned = 0;
}

std::vector<std::string> Missile_Command::split(std::string string, char splitParam){
	std::vector<std::string> splitString;
	int strBegin = 0;
	for (size_t i = 0; i < string.size(); i++){
		if (string[i] == splitParam && i != 0){
			splitString.push_back(string.substr(strBegin, i));
			if (string.size() > i + 1)
				strBegin = i + 1;
		}
		if (string.size() <= i + 1){
			splitString.push_back(string.substr(strBegin, i));
		}
	}
	return splitString;
}

void Missile_Command::getHighscores(){
	// read file into program
	_highscores.clear();
	std::string line;
	std::ifstream inputStream("highscores.txt");
	if (inputStream.is_open()){
		while (std::getline(inputStream, line)){
			std::vector<std::string> toIns{ split(line, '|') };
			_highscores.insert(_highscores.end(), toIns.begin(), toIns.end());
		}
		inputStream.close();
	}
	for (size_t i = 0; i < _highscores.size() - 1; i+=2){
		std::cout << _highscores[i] << " " << _highscores[i + 1] << "\n";
	}
}

bool Missile_Command::addHighscore(){
	bool isAdded;
	getHighscores();
	// Add score
	_highscores.push_back(_playerName);
	_highscores.push_back(std::to_string(_score));
	// Sort all scores
	sortHighscores();
	if (atoi(_highscores[_highscores.size() - 1].c_str()) == _score)
		isAdded = false;
	else
		isAdded = true;
	// Remove lowest score
	if (_highscores.size() > 20){
		_highscores.resize(_highscores.size() - 2);
	}
	// Write highscores to file
	writeHighscores();
	return isAdded;
}

// write highscores into file
void Missile_Command::writeHighscores(){
	std::ofstream outputStream("highscores.txt");
	if (outputStream.is_open())
	{
		for (size_t i = 0; i < _highscores.size(); i += 2){
			outputStream << _highscores[i] << '|' << _highscores[i + 1] << '\n';
		}
		outputStream.close();
	}
}

void Missile_Command::sortHighscores(){
	// sort highscores
	int j;
	std::string tmp1;
	std::string tmp2;
	for (size_t i = 3; i < _highscores.size(); i += 2){
		j = i;
		while (j > 1 && std::atoi(_highscores[j - 2].c_str()) < std::atoi(_highscores[j].c_str())) {
			tmp1 = _highscores[j];
			tmp2 = _highscores[j - 1];
			_highscores[j] = _highscores[j - 2];
			_highscores[j - 1] = _highscores[j - 3];
			_highscores[j - 3] = tmp2;
			_highscores[j - 2] = tmp1;
			j -= 2;
		}
	}
}

void Missile_Command::run(){
	while (_window.isOpen()){
		const double elapsedTime = _clock.getElapsedTime().asMicroseconds() / 1000.0;
		_skippedTime += elapsedTime;
		_secondSkipped += elapsedTime;
		_clock.restart();

		while (_secondSkipped >= SECOND){
			std::cout << _updates << " Updates at an average interval of " << _secondSkipped / _updates << "ms.\n";
			_updates = 0;
			_secondSkipped -= SECOND;
		}
		while (_skippedTime >= INTERVAL){
			_updates++;
			_skippedTime -= INTERVAL;

			doEvents();
			update();
		}
		render();
	}
}

Entity.h

#pragma once

template<class T>
class Entity : public T
{
public:
	//Constructors
	Entity(sf::Vector2f size, sf::Vector2f pos, sf::Color color) : T(size){
		setPosition(pos);
		setFillColor(color);
	}
	Entity(float radius, size_t pointCount, sf::Vector2f pos, sf::Color color) : T(radius){
		setPointCount(pointCount);
		setPosition(pos);
		setFillColor(color);
	}
	Entity(float width, float height, float x, float y) : T(sf::Vector2f(width, height)){
		setPosition(x, y);
	}
	Entity() : T(){};

	sf::Vector2i getGridPosition() const;
	void setGridPosition(size_t x, size_t y);
	void setOutline(float thickness, const sf::Color & color);
};

// Definitions ---------------------------------------------------------------------------- Definitions

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

struct Particles{
	Particles(){}
	std::vector<sf::Vertex> particles;
	std::vector<float> life;
	void append(sf::Vector2f pos, float life, sf::Color color){
		sf::Vertex vertex(pos, color);
		this->life.push_back(life);
		particles.push_back(vertex);
	}
	void append(sf::Vector2f pos){
		sf::Vertex vertex(pos);
		this->life.push_back(100000.01f);
		particles.push_back(vertex);
	}
	void removeAt(size_t index){
		life.erase(life.begin() + index);
		particles.erase(particles.begin() + index);
	}
	void clear(){
		life.clear();
		particles.clear();
	}
};


typedef Entity<sf::RectangleShape> EntityR;
typedef Entity<sf::CircleShape> EntityC;

template<class T>
sf::Vector2i Entity<T>::getGridPosition() const{
	return sf::Vector2i(getPosition() / BLOCKSIZE);
}

template<class T>
void Entity<T>::setGridPosition(size_t x, size_t y){
	setPosition(x * BLOCKSIZE, y * BLOCKSIZE);
}

template<class T>
void Entity<T>::setOutline(float thickness, const sf::Color & color){
	setOutlineThickness(thickness);
	setOutlineColor(color);
}

Entity.cpp

#include "init.h"

Button.h

#pragma once

namespace ui{

	class Button : public sf::Drawable
	{
		EntityR buttonFace;
		sf::Font font;
		sf::Text text;
	public:
		Button(std::string text, size_t textSize, sf::Vector2f pos, sf::Color textColor, sf::Color buttonFaceColor, std::string font);
		Button& operator=(Button other){
			font = other.font;
			text = other.text;
			buttonFace = other.buttonFace;
			text.setFont(font);
			return *this;
		}
		Button(){}

		std::string getString() const;
		EntityR getButtonFaceObj() const;
		sf::Vector2f getPosition() const;
		sf::Vector2f getButtonFaceSize() const;
		size_t getTextSize() const;
		sf::Color getTextColor() const;
		sf::Color getButtonFaceColor() const;

		void setString(std::string text);
		void setPosition(const sf::Vector2f & pos);
		void setTextSize(size_t textSize);
		void setTextColor(const sf::Color & color);
		void setButtonFaceColor(const sf::Color & color);

		bool isPressed(const sf::Event & event);
		bool isHovering(const sf::Event & event);

		virtual void draw(sf::RenderTarget & target, sf::RenderStates states) const;
	};
}
 

Button.cpp (Advice on how I could improve this class would be great)

#include "init.h"


ui::Button::Button(std::string text, size_t textSize, sf::Vector2f pos, sf::Color textColor, sf::Color buttonFaceColor, std::string font){
	this->font.loadFromFile(font);
	this->text.setFont(this->font);
	setTextSize(textSize);
	setString(text);
	setPosition(pos);
	setTextColor(textColor);
	setButtonFaceColor(buttonFaceColor);
}

std::string ui::Button::getString() const{
	return text.getString();
}

EntityR ui::Button::getButtonFaceObj() const{
	return buttonFace;
}

sf::Vector2f ui::Button::getPosition() const{
	return buttonFace.getPosition();
}

sf::Vector2f ui::Button::getButtonFaceSize() const{
	return buttonFace.getSize();
}

size_t ui::Button::getTextSize() const{
	return text.getCharacterSize();
}

sf::Color ui::Button::getTextColor() const{
	return text.getColor();
}

sf::Color ui::Button::getButtonFaceColor() const{
	return buttonFace.getFillColor();
}

void ui::Button::setString(std::string text){
	this->text.setString(text);
	setTextSize(getTextSize());
}

void ui::Button::setPosition(const sf::Vector2f & pos){
	text.setPosition(pos + sf::Vector2f(10, 10));
	float left = text.getGlobalBounds().left;
	float top = text.getGlobalBounds().top;
	buttonFace.setPosition(left - 10, top - 10);
}

void ui::Button::setTextSize(size_t textSize){
	text.setCharacterSize(textSize);
	float left = text.getGlobalBounds().left;
	float top = text.getGlobalBounds().top;
	float width = text.getGlobalBounds().width;
	float height = text.getGlobalBounds().height;
	buttonFace.setSize(sf::Vector2f(width + 20, height + 20));
	buttonFace.setPosition(left - 10, top - 10);
}

void ui::Button::setTextColor(const sf::Color & color){
	text.setColor(color);
}

void ui::Button::setButtonFaceColor(const sf::Color & color){
	buttonFace.setFillColor(color);
}

bool ui::Button::isPressed(const sf::Event & event){
	if (event.type == sf::Event::MouseButtonPressed){
		if (event.mouseButton.button == sf::Mouse::Button::Left){
			sf::Vector2f mousePos((float)event.mouseButton.x, (float)event.mouseButton.y);
			if (cd::doesIntersect(mousePos, buttonFace))
				return true;
		}
	}
	return false;
}

bool ui::Button::isHovering(const sf::Event & event){
	sf::Vector2f mousePos((float)event.mouseMove.x, (float)event.mouseMove.y);
	if (cd::doesIntersect(mousePos, buttonFace))
		return true;
	return false;
}

void ui::Button::draw(sf::RenderTarget & target, sf::RenderStates states) const{
	target.draw(buttonFace);
	target.draw(text);
}

Missiles.h

#pragma once

class Missiles : public sf::Drawable
{
	std::vector<sf::RectangleShape> missiles;
	std::vector<EntityC> explosions;
	std::vector<sf::Vector2f> missileVelocities;
	std::vector<sf::Vector2f> explodePositions;
	std::vector<float> expandVelocities;
	std::vector<float> fadeVelocities;
	std::vector<sf::Color> explodeColors;
	std::vector<sf::Color> fadeColors;
	sf::RectangleShape model;
	sf::Color standardFadeColor;
	float standardFadeVel;
	float standardExpandVel;
public:
	Missiles(const sf::Vector2f & size, const sf::Vector2f & origin, const sf::Color & color, const sf::Color & fadeColor, float expandVelocity, float fadeVelocity);
	Missiles(){};

	std::vector<EntityC> getExplosions() const{ return explosions; }
	void update(SoundEffect & sound);
	void clear();
	void removeMissileAt(size_t index);
	void removeExplosionAt(size_t index);
	void explodeAtPosition(const sf::Vector2f & pos, float fadeVel, float expandVel, sf::Color color, sf::Color fadeColor);
	void fireMissile(const sf::Vector2f & velocity, const sf::Vector2f & explodePos);

	virtual void draw(sf::RenderTarget & target, sf::RenderStates states) const;
};

Missiles.cpp

#include "init.h"

Missiles::Missiles(const sf::Vector2f & size, const sf::Vector2f & origin, const sf::Color & color, const sf::Color & fadeColor, float expandVelocity, float fadeVelocity){
	model.setSize(size);
	model.setPosition(origin);
	model.setFillColor(color);
	standardFadeVel = fadeVelocity;
	standardExpandVel = expandVelocity;
	standardFadeColor = fadeColor;
	clear();
}

void Missiles::update(SoundEffect & sound){
	// Move missiles
	for (size_t i = 0; i < missiles.size(); i++){
		missiles[i].move(missileVelocities[i]);
	}

	// Test for boundary intersections
	for (size_t i = 0; i < missiles.size(); i++){
		if (cd::boundaryIntersect(missiles[i], EntityR((float)SCRW, (float)SCRH, 0, 0), Side::Top) ||
			cd::boundaryIntersect(missiles[i], EntityR((float)SCRW, (float)SCRH, 0, 0), Side::Bottom) ||
			cd::boundaryIntersect(missiles[i], EntityR((float)SCRW, (float)SCRH, 0, 0), Side::Left) ||
			cd::boundaryIntersect(missiles[i], EntityR((float)SCRW, (float)SCRH, 0, 0), Side::Right))
		{
			removeMissileAt(i);
		}
	}

	// Expand explosions and remove explosions that have completed their cycle
	for (size_t i = 0; i < explosions.size(); i++){
		explosions[i].setRadius(explosions[i].getRadius() + expandVelocities[i]);
		explosions[i].setPosition(explosions[i].getPosition() - sf::Vector2f(expandVelocities[i], expandVelocities[i]));

		if (explodeColors[i].a >= fadeVelocities[i]){
			explodeColors[i].a -= fadeVelocities[i];
			if (explodeColors[i].r > fadeColors[i].r)
				explodeColors[i].r--;
			else if (explodeColors[i].r < fadeColors[i].r)
				explodeColors[i].r++;
			if (explodeColors[i].g > fadeColors[i].g)
				explodeColors[i].g--;
			else if (explodeColors[i].g < fadeColors[i].g)
				explodeColors[i].g++;
			if (explodeColors[i].b > fadeColors[i].b)
				explodeColors[i].b--;
			else if (explodeColors[i].b < fadeColors[i].b)
				explodeColors[i].b++;
			explosions[i].setFillColor(explodeColors[i]);
		}
		else{
			removeExplosionAt(i);
			i = 0;
		}
	}

	// Test if a missile should explode
	bool willExplode = false;
	size_t index = 0;

	for (size_t i = 0; i < missiles.size(); i++){
		sf::Vector2f missilePos = missiles[i].getPosition();
		if (missileVelocities[i].x <= 0 && missileVelocities[i].y <= 0 && missilePos.x <= explodePositions[i].x && missilePos.y <= explodePositions[i].y ||
			missileVelocities[i].x <= 0 && missileVelocities[i].y > 0 && missilePos.x <= explodePositions[i].x && missilePos.y > explodePositions[i].y ||
			missileVelocities[i].x > 0 && missileVelocities[i].y <= 0 && missilePos.x > explodePositions[i].x && missilePos.y <= explodePositions[i].y ||
			missileVelocities[i].x > 0 && missileVelocities[i].y > 0 && missilePos.x > explodePositions[i].x && missilePos.y > explodePositions[i].y){
			willExplode = true;
			index = i;
		}
		if (willExplode)
			break;
	}
	if (willExplode){
		sound.play();
		fadeVelocities.push_back(standardFadeVel);
		fadeColors.push_back(standardFadeColor);
		expandVelocities.push_back(standardExpandVel);
		explodeColors.push_back(model.getFillColor());
		explosions.push_back(EntityC(model.getSize().x/2.0f, 30, explodePositions[index], explodeColors[explodeColors.size() - 1]));
		removeMissileAt(index);
	}
}

void Missiles::clear(){
	missiles.clear();
	explosions.clear();
	missileVelocities.clear();
	explodePositions.clear();
	expandVelocities.clear();
	fadeVelocities.clear();
	explodeColors.clear();
	fadeColors.clear();
}

void Missiles::removeMissileAt(size_t index){
	missiles.erase(missiles.begin() + index);
	missileVelocities.erase(missileVelocities.begin() + index);
	explodePositions.erase(explodePositions.begin() + index);
}

void Missiles::removeExplosionAt(size_t index){
	explosions.erase(explosions.begin() + index);
	explodeColors.erase(explodeColors.begin() + index);
	fadeVelocities.erase(fadeVelocities.begin() + index);
	fadeColors.erase(fadeColors.begin() + index);
	expandVelocities.erase(expandVelocities.begin() + index);
}

void Missiles::explodeAtPosition(const sf::Vector2f & pos, float fadeVel, float expandVel, sf::Color color, sf::Color fadeColor){
	fadeVelocities.push_back(fadeVel);
	fadeColors.push_back(fadeColor);
	expandVelocities.push_back(expandVel);
	explodeColors.push_back(color);
	explosions.push_back(EntityC(model.getSize().x / 2.0f, 30, pos, explodeColors[explodeColors.size() - 1]));
}

void Missiles::fireMissile(const sf::Vector2f & velocity, const sf::Vector2f & explodePos){
	explodePositions.push_back(explodePos);
	missileVelocities.push_back(velocity);
	missiles.push_back(model);
}

void Missiles::draw(sf::RenderTarget & target, sf::RenderStates states) const{
	for (auto item : missiles){
		target.draw(item);
	}
	for (auto item : explosions){
		target.draw(item);
	}
}

Collision_Detection.h

#pragma once

enum class Side;

namespace cd{
	// 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(EntityR entity1, EntityR entity2);
	bool doesIntersect(EntityC entity1, EntityR entity2);
	bool doesIntersect(EntityC entity1, EntityC entity2);
	bool doesIntersect(sf::Vector2f point, EntityR entity);
	// Test if an entity is outside the entity bounds
	bool boundaryIntersect(sf::RectangleShape entity, sf::RectangleShape bounds, Side side);
	bool boundaryIntersect(sf::CircleShape entity, sf::RectangleShape 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 EntityR & entityMoving, const EntityR & entityStatic, sf::Vector2f vel, Side side);
}

Collision_Detection.cpp

#include "init.h"

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

bool cd::doesIntersect(EntityR entity1, EntityR 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 cd::doesIntersect(EntityC entity1, EntityR entity2){
	return false;
}

bool cd::doesIntersect(EntityC entity1, EntityC entity2){
	sf::Vector2f origin1 = entity1.getPosition() + sf::Vector2f(entity1.getRadius(), entity1.getRadius());
	sf::Vector2f origin2 = entity2.getPosition() + sf::Vector2f(entity2.getRadius(), entity2.getRadius());
	float radius1 = entity1.getRadius();
	float radius2 = entity2.getRadius();

	if (sqrt((origin2.x - origin1.x) * (origin2.x - origin1.x) + (origin2.y - origin1.y) * (origin2.y - origin1.y)) < (radius1 + radius2)){
		return true;
	}
	return false;
}

bool cd::doesIntersect(sf::Vector2f point, EntityR entity){
	if (point.x >= entity.getPosition().x &&
		point.x <= entity.getPosition().x + entity.getSize().x &&
		point.y >= entity.getPosition().y &&
		point.y <= entity.getPosition().y + entity.getSize().y)
		return true;
	return false;
}

bool cd::boundaryIntersect(sf::RectangleShape entity, sf::RectangleShape 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 cd::boundaryIntersect(sf::CircleShape entity, sf::RectangleShape bounds, Side side){
	if (side == Side::Top && entity.getPosition().y < bounds.getPosition().y)
		return true;
	else if (side == Side::Bottom && entity.getPosition().y + entity.getRadius() * 2.0f > 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.getRadius() * 2.0f > bounds.getPosition().x + bounds.getSize().x)
		return true;
	return false;
}

bool cd::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 cd::willIntercept(const EntityR & entityMoving, const EntityR & 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 <= Side::Bottom){
		line.A = entityStatic.getPosition() + sf::Vector2f(0, entityStatic.getSize().y * (int)side);
		line.B = entityStatic.getPosition() + sf::Vector2f(entityStatic.getSize().x, entityStatic.getSize().y * (int)side);
		end = sf::Vector2f((float)(int)((vel.y + emCenter.y - b) / m), vel.y + emCenter.y);
		if (side == Side::Top){
			for (float y = 0; y <= vel.y; y += 0.1f){
				if (lineIntersect(line, sf::Vector2f((float)(int)((y + emCenter.y - b) / m), y + emCenter.y), entityMoving.getSize().y))
					return true;
			}
		}
		else if (side == Side::Bottom){
			for (float y = 0; y >= vel.y; y -= 0.1f){
				if (lineIntersect(line, sf::Vector2f((float)(int)((y + emCenter.y - b) / m), y + emCenter.y), entityMoving.getSize().y))
					return true;
			}
		}
	}
	else if (side >= Side::Left){
		int tmpSide = (int)side - (int)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, (float)(int)(m * (vel.x + emCenter.x) + b));
		if (side == Side::Left){
			for (float x = 0; x <= vel.x; x += 0.1f){
				if (lineIntersect(line, sf::Vector2f(x + emCenter.x, (float)(int)(m * (x + emCenter.x) + b)), entityMoving.getSize().x))
					return true;
			}
		}
		else if (side == Side::Right){
			for (float x = 0; x >= vel.x; x -= 0.1f){
				if (lineIntersect(line, sf::Vector2f(x + emCenter.x, (float)(int)(m * (x + emCenter.x) + b)), entityMoving.getSize().x))
					return true;
			}
		}
	}
	return false;
}

Math.h

#pragma once

namespace mth{
	// Basically pi
	const double PI = 3.14159265358979323846264338327950288419716939937510582097494459;
	// Get the angle between two vectors in degrees
	double getAngleInDegrees(const sf::Vector2f & entityStaticCenter, const sf::Vector2f & entityMovingCenter);
	// Get the angle between two vectors in radians
	double getAngleInRadians(const sf::Vector2f & entityStaticCenter, const sf::Vector2f & entityMovingCenter);
	// Calculate directional veloctiy, given radians and global velocity
	sf::Vector2f getVelocity(double radians, double vel);
}

Math.cpp

#include "init.h"

double mth::getAngleInDegrees(const sf::Vector2f & entityStaticCenter, const sf::Vector2f & entityMovingCenter){
	double winkel = atan2((entityMovingCenter.y - (entityStaticCenter.y)), (entityMovingCenter.x - (entityStaticCenter.x)));
	winkel *= 180 / PI;
	return winkel;
}

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

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

SoundEffect.h

#pragma once

class SoundEffect
{
	sf::SoundBuffer buffer;
	sf::Sound sound;
public:
	SoundEffect(std::string filePath, float volume);
	SoundEffect(std::string filePath, sf::Sound sound);
	SoundEffect(){ }
	SoundEffect& operator=(SoundEffect other){
		buffer = other.buffer;
		sound = other.sound;
		sound.setBuffer(buffer);
		return *this;
	}

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

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

SoundEffect.cpp

#include "init.h"

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

SoundEffect::SoundEffect(std::string filePath, sf::Sound sound){
	if (!buffer.loadFromFile(filePath))
		std::exit(-3);
	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();
}

Thank you for your time and for reading!




#5173349 Beginner creating a game by myself

Posted by Gaius Baltar on 13 August 2014 - 08:58 AM

Just use Unity or UDK




#5170632 Snake code review request

Posted by Gaius Baltar on 31 July 2014 - 10:29 AM

I've recently finished programming a clone of the popular "Snake" game in C++ with SFML and Visual Studio 12 and I would like to know if there is anything about the code or it's structure that I could improve. This is the second post I've made on this forum, the first was a Pong review request.
http://www.gamedev.net/topic/659149-basic-pong-code-review-request/
 
Game:
 
fB28dbu.png
 
 
Files:
 
75MeWdl.png
 
Code:
 
main.cpp
 
Spoiler


Snake.h
Spoiler


Snake.cpp
Spoiler


Food.h
Spoiler


Food.cpp
Spoiler


Entity.h
Spoiler


Entity.cpp
Spoiler


SoundEffect.h
Spoiler


SoundEffect.cpp
Spoiler


globals.h
Spoiler



PARTNERS