Created
December 3, 2016 21:22
-
-
Save oisincar/5825f75407320cbe32b9c527254b94f3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <clocale> | |
#include <cmath> | |
#include <ncurses.h> | |
#include <unistd.h> | |
#include <vector> | |
#include <ctime> | |
#include <cstdlib> | |
using namespace std; | |
int _height, _width; | |
const float _PLAYER_SPEED = 0.05; | |
const float _ASTEROID_SPEED = 0.2; | |
class Player; | |
class Asteroid; | |
class Bullet; | |
Player *_player; | |
vector<Asteroid *> _asteroids; | |
vector<Bullet *> _bullets; | |
void WaitForTitle(){ | |
vector<string> title; | |
title.push_back( | |
" _______ _______ _______ __________________ _______ _______ _________ ______ _______ "); | |
title.push_back( | |
"( ___ )( ____ \\( ____ \\\\__ __/\\__ __/( ____ )( ___ )\\__ __/( __ \\ ( ____ \\"); | |
title.push_back( | |
"| ( ) || ( \\/| ( \\/ ) ( ) ( | ( )|| ( ) | ) ( | ( \\ )| ( \\/"); | |
title.push_back( | |
"| (___) || (_____ | | | | | | | (____)|| | | | | | | | ) || (_____ "); | |
title.push_back( | |
"| ___ |(_____ )| | | | | | | __)| | | | | | | | | |(_____ )"); | |
title.push_back( | |
"| ( ) | ) || | | | | | | (\\ ( | | | | | | | | ) | ) |"); | |
title.push_back( | |
"| ) ( |/\\____) || (____/\\___) (______) (___| ) \\ \\__| (___) |___) (___| (__/ )/\\____) |"); | |
title.push_back( | |
"|/ \\|\\_______)(_______/\\_______/\\_______/|/ \\__/(_______)\\_______/(______/ \\_______)"); | |
title.push_back(""); | |
title.push_back(""); | |
title.push_back(" Press any key to play!"); | |
title.push_back(""); | |
int st_x = (_width - title[0].size())/2, | |
st_y = (_height - title.size())/2; | |
for(int y = 0; y < title.size(); y++){ | |
string st = title[y]; | |
for (int x = 0; x < st.size(); x++){ | |
mvaddch(y + st_y, x + st_x, st[x]); | |
} | |
} | |
// sleep for a bit to stop accidental restarts of game. | |
wrefresh(stdscr); | |
usleep(500000); | |
char c; | |
do { | |
c = getch(); | |
usleep(10000); | |
} while(c == ERR); | |
erase(); | |
} | |
class GameObject { | |
protected: | |
pair<float, float> pos_; | |
pair<float, float> velocity_; | |
// How the object looks.. | |
vector<string> form_; | |
string collide_chars_; | |
// if we're outside world boundaries wrap to other side.. | |
void WrapWorld() { | |
pos_.first = fmod(pos_.first + _width, _width); | |
pos_.second = fmod(pos_.second + _height, _height); | |
} | |
bool CheckCollisions(){ | |
if (collide_chars_ == "") | |
return false; | |
// collisions with already-rendered objects.. | |
for (int y = 0; y < form_.size(); y++){ | |
for (int x = 0; x < form_[0].size(); x++){ | |
int px = x + pos_.first; | |
int py = y + pos_.second; | |
if (px > 0 && px < _width && | |
py > 0 && py < _height) { | |
char del_c = mvinch(py, px); | |
if (collide_chars_.find(del_c) != string::npos){ | |
mvaddch(py, px, ' '); | |
return true; | |
} | |
} | |
} | |
} | |
return false; | |
} | |
void Render() { | |
int x = pos_.first, y = pos_.second; | |
bool do_delete = false; | |
// Render each char. | |
for (string row : form_){ | |
for (char c : row){ | |
mvaddch(y, x, c); | |
x++; | |
} | |
x = pos_.first; | |
y++; | |
} | |
} | |
public: | |
// returns weither to delete. | |
bool Update() { | |
pos_.first += velocity_.first; | |
pos_.second += velocity_.second; | |
WrapWorld(); | |
if (CheckCollisions()) | |
return true; | |
Render(); | |
return false; | |
} | |
}; | |
class Player : public GameObject { | |
private: | |
vector< vector<string> > all_forms_; | |
pair<int, int> last_input_; | |
public: | |
pair<int, int> getDirection(){ | |
return last_input_; | |
} | |
pair<float, float> getPosition(){ | |
return pos_; | |
} | |
Player(){ | |
pos_ = make_pair(_width/2, _height/2); | |
for (int i = 0; i < 4; i++) all_forms_.push_back( vector<string>() ); | |
all_forms_[0].push_back(" ^\\____"); | |
all_forms_[0].push_back("< o o >--"); | |
all_forms_[0].push_back(" v/----"); | |
all_forms_[2].push_back(" ___/^"); | |
all_forms_[2].push_back("--< o o >"); | |
all_forms_[2].push_back(" ----\\"); | |
all_forms_[1].push_back(" | "); | |
all_forms_[1].push_back(" .^. "); | |
all_forms_[1].push_back(" | | "); | |
all_forms_[1].push_back(" | O | "); | |
all_forms_[1].push_back("<| O |>"); | |
all_forms_[1].push_back(" v "); | |
all_forms_[3].push_back(" ^ "); | |
all_forms_[3].push_back("<| O |>"); | |
all_forms_[3].push_back(" | O | "); | |
all_forms_[3].push_back(" | | "); | |
all_forms_[3].push_back(" 'v' "); | |
all_forms_[3].push_back(" | "); | |
form_ = all_forms_[0]; | |
last_input_ = make_pair(1, 0); | |
collide_chars_ = ".,\\(_)/"; | |
} | |
void HandleInput(pair<int, int> input_vec) { | |
last_input_ = make_pair(input_vec.first, input_vec.second); | |
velocity_.first += (float)input_vec.first * _PLAYER_SPEED; | |
velocity_.second += (float)input_vec.second * _PLAYER_SPEED; | |
if (input_vec.first != 0){ | |
form_ = input_vec.first > 0 ? all_forms_[0] : all_forms_[2]; | |
} | |
else if (input_vec.second != 0){ | |
form_ = input_vec.second > 0 ? all_forms_[3] : all_forms_[1]; | |
} | |
} | |
}; | |
class Asteroid : public GameObject { | |
private: | |
int size_; | |
public: | |
Asteroid(int size){ | |
size_ = size; | |
collide_chars_ = "-|"; | |
if (size == 1){ | |
form_.push_back(" _"); | |
form_.push_back("<_>"); | |
} | |
if (size == 2){ | |
form_.push_back(" __."); | |
form_.push_back("/ \\_"); | |
form_.push_back("\\___/"); | |
} | |
if (size == 3){ | |
form_.push_back(" __."); | |
form_.push_back("/ \\_"); | |
form_.push_back("\\ ,. \\"); | |
form_.push_back(" \\___/"); | |
} | |
do { | |
pos_ = make_pair(rand() % _width, rand() % _height); | |
} while ((pos_.first < _width - _width/6 && pos_.first > _width/6) && | |
(pos_.second < _height - _height/6 || pos_.second > _height/6)); | |
velocity_ = make_pair((float)(500 - rand() % 1000)/5000, (float)((500 - rand() % 1000))/5000); | |
} | |
Asteroid(pair<float, float> pos, int size) : Asteroid(size) { | |
pos_ = pos; | |
} | |
bool AsteroidUpdate() { | |
// if we're about to delete this, spawn more!! | |
if (Update()) { | |
size_-=1; | |
if(size_ > 0){ | |
_asteroids.push_back(new Asteroid(pos_, size_)); | |
_asteroids.push_back(new Asteroid(pos_, size_)); | |
} | |
return true; | |
} | |
return false; | |
} | |
}; | |
class Bullet : public GameObject { | |
private: | |
int lifespan; | |
public: | |
Bullet(pair<float, float> pos, pair<float, float> velocity){ | |
string f = (abs(velocity.first) > abs(velocity.second)) ? "-" : "|"; | |
form_.push_back(f); | |
pos_ = pos; | |
velocity_ = velocity; | |
lifespan = 240; | |
} | |
bool BullUpdate(){ | |
lifespan--; | |
return (lifespan > 0) && Update(); | |
} | |
}; | |
bool GameLoop(){ | |
// do input.. | |
pair<int, int> player_input_vec = make_pair(0, 0); | |
int c; | |
while ((c = getch()) != ERR) { | |
if (c == 'w' || c == KEY_UP) { | |
player_input_vec.second--; | |
} | |
else if (c == 'a' || c == KEY_LEFT) { | |
player_input_vec.first--; | |
} | |
else if (c == 's' || c == KEY_DOWN) { | |
player_input_vec.second++; | |
} | |
else if (c == 'd' || c == KEY_RIGHT) { | |
player_input_vec.first++; | |
} | |
else if (c == ' ') { | |
pair<int, int> acc = _player->getDirection(); | |
float bullSpeed = 0.3; | |
pair<float, float> pos = _player->getPosition(); | |
pos.first += 3; | |
pos.second += 1; | |
pair<float, float> accmul = make_pair((float)acc.first * bullSpeed, (float)acc.second * bullSpeed); | |
Bullet *b = new Bullet(pos, accmul); | |
_bullets.push_back(b); | |
} | |
} | |
// sometimes add an asteroid... | |
if (rand() % 100 == 0){ | |
_asteroids.push_back(new Asteroid(1 + (rand() % 3))); | |
} | |
if (player_input_vec.first != 0 || player_input_vec.second != 0) | |
_player->HandleInput(player_input_vec); | |
erase(); | |
for (int i = 0; i < _bullets.size(); i++){ | |
if (_bullets[i]->BullUpdate()){ | |
_bullets.erase(_bullets.begin()+i); | |
i--; | |
} | |
} | |
for (int i = 0; i < _asteroids.size(); i++){ | |
if (_asteroids[i]->AsteroidUpdate()){ | |
_asteroids.erase(_asteroids.begin()+i); | |
i--; | |
} | |
} | |
if (_player->Update()){ | |
return false; | |
} | |
wrefresh(stdscr); | |
return true; | |
} | |
int main(){ | |
srand (time(NULL)); | |
// ncurses setup... | |
setlocale(LC_ALL, ""); | |
initscr(); | |
// No buffering. | |
cbreak(); | |
noecho(); | |
// Special chars. | |
keypad(stdscr, true); | |
// getch() can return ERR. | |
nodelay(stdscr, TRUE); | |
// No cursor. | |
curs_set(0); | |
srand(time(NULL)); | |
getmaxyx(stdscr, _height, _width); | |
while (true){ | |
WaitForTitle(); | |
_player = new Player(); | |
for (int i = 0; i < 15; i++) | |
_asteroids.push_back(new Asteroid(1 + (rand() % 3))); | |
while(GameLoop()){ | |
usleep(10000); | |
} | |
// cleanup... | |
delete _player; | |
while(!_asteroids.empty()) | |
delete _asteroids.back(), _asteroids.pop_back(); | |
while(!_bullets.empty()) | |
delete _bullets.back(), _bullets.pop_back(); | |
} | |
endwin(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment