Alright so i'm making a vertical side scroller where you are an '8' character traveling downward while avoiding my randomly generated walls (the "generation" function) on the left and right sides of the screen, and made of 'X's. you can collide with this wall 4 times before losing.
When you collide with the wall you can no longer move, and are basically are stuck in that column of the screen until you pop out into an open space, known as a ' ' (space) character. You lose one life for each INITIAL collision with the X wall, and do not lose another until you have popped out and been freed from it.
As an added touch i have made it so after you collide while traveling down the randomly generated map (or rather as the walls move uppward while your character stays put) the X chars you've collided with are deleted. However I am having trouble getting the INITIAL COLLISION with the wall to be detected correctly. the result is the playe incorrectly losing 4 lives after hitting 1 wall and traveling throug it. This is due to some odd reason for the "numb_collisions", which is used to count how many collisions have occured since initial collision (if it's 0 it means it IS the initial collision occuring= -1 shield), keeps getting reset to 0. The detect_collision function seems to having some sort of problems as the returned value is allowing the if statement to pretend there is no collision, reseting "numb_coll" to 0 and screwing the lives/shields up. All this nonsense is located at the bottom of the main function
Finally the Screen.Insert() *function and others like it simply saves the data into a vector which represents the console window. It is later used to print the "screen" to the console at a set rate (long double speed), as seen in the for loop after the map drawings in the main function *
not Finally.. but i believe that te numb_coll problem has something to do with the time and framrate. When running full speed i quickly die upon entering a wall as numb_coll doesn't change or gets changed back to 0 somehow. When putting a stop in my msVS++ it works perfectly... and when holding F5 (shortcut for "continue") it partly works but numb_coll still gets set to 0 every 3 or 4 X's down in the wall...
I hope this is enough explination, Thanks for any Help, and LOOK AT PREVIOUS POST ABOUT COLLISION DETECTION FOR MORE SPECIFIC FUNCTION PROBLEMS otherwise, heres all the code: Thanks again!
#include <iostream>
#include <time.h> // or "ctime"
#include <stdio.h> // for
#include <cstdlib>
// Windows stuff
#include <Windows.h> // GOD DAMMNIT WINDOWS WHY????
#include <conio.h>
// Ncurses
#include<curses.h>
// STL stuff
#include <algorithm>
#include <string>
#include <vector>
//String/Int conversion
#include <sstream>
// gives access to rand function
#include <cstdlib>
//gives access to time functions
#include <ctime>
// mySTOPWATCH i think i'm gonna cry.... =')
#include <myStopwatch.h> // for keeping times
#include <myMath.h> // numb_digits() and digit_val();
using namespace std;
enum{ NUMB_LINES= 24, SEC= 1000}; // time stuff
enum{TIME= 345, HEALTH = 346, MAP= 247}; // for Refresh() command
enum{NONE= 256}; // for Refresh() transition
enum{NEW = 590, OLD = 591}; // for the old/new screen command
// Some nCurses setup
int r = 0,
c = 0; // current row and column (upper-left is (0,0))
const int nrows = 56, // number of rows in window
ncols = 79; // number of columns in window
// Timer Setup
Stopwatch myStopwatch(3, START);
/////////////////////////// RandNumb() ///////////////////////////////////////
int RandNumb(int scope){
srand(GetTickCount());
return rand() % scope;};
////////////////////////// GeneratePathStart() ///////////////////////////////
void GeneratePathStart(vector<string>& buff){
int wall= RandNumb(80)/2,
space = (RandNumb(75)/2)+5,
wall2= 80- (wall+space);
buff.push_back("");
for(;wall> 0; wall--){
buff[0].push_back('X');}
for(;space> 0; space--){
buff[0].push_back(' ');}
for(; wall2 > 0; wall2--){
buff[0].push_back('X');}
};
////////////////////////// GeneratePath() ////////////////////////////////////
void GeneratePath( vector<string>& buff){// the buff is the seed too
int wall= RandNumb(80)/2,
space = (RandNumb(75)/2)+5,
wall2= 80-(space+wall);
int swall= 0;
for(char i= '0'; i!= ' ';swall++)
i= buff[buff.size()-1][swall+1];
int sspace= 0; int I= swall+1;
for(char i= '0'; i!= 'X';sspace++, I++)
i= buff[buff.size()-1][I];
int swall2 = 80-(sspace+swall);
// now the actual generation
int cwall= wall-swall;
int cspace= space-sspace;
int cwall2= wall2-swall2;
for(;cwall!= 0 || cspace!= 0 /*|| cwall2 != 0*/;){
buff.push_back("");
//cwall
if(cwall!= 0){
if(cwall>0){
swall++;
cwall--;}
else{ // cwall is negative
swall--;
cwall++;}}
for(int w= 0; w <swall; w++)
buff[buff.size()-1].push_back('X');
// cspace
if(cspace!= 0){
if(cspace>0){
sspace++;
cspace--;}
else{ // cspace is negative
sspace--;
cspace++;}}
for(int s= 0; s <sspace; s++)
buff[buff.size()-1].push_back(' ');
// cwall2
//if(cwall2!= 0){
// if(cwall2>0){
// wall2++;
// cwall2--;}
// else{ // cspace is negative
// wall2--;
// cwall2++;}}
for(int w2= 0; w2 <80- (swall+sspace); w2++)
buff[buff.size()-1].push_back('X');
}}// end of function
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// Sprite Class ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Sprite
{
private:
string name;
char symbol;
float shield;
int location[2];
bool alive;
public:
///////////////////// Get and SET all the privates ///////
Sprite(){};
Sprite(string a_name, char a_symbol, float a_health){
name = a_name;
symbol = a_symbol;
shield = a_health;};
char get_symbol() {return symbol;};
void set_symbol(char sym) {symbol = sym;};
float get_shield() {return shield;};
void set_shield(float numb) {shield = numb;};
void add_shield (float numb) {shield += numb;};
void destroy_shield() {shield--; if(shield<0) alive= false;}
string get_name() {return name;};
string set_name(string aName) {name = aName;};
int* get_location(){return location;};
void set_location(int X, int Y) {
location[0] = X;
location[1] = Y;};
bool Alive() {return alive;};
void SetLife(bool f) {alive= f;};
//////////////////////////////// Move ////////////
bool move(int X, int Y) {
location[0] += X;
location[1] += Y;
return true;};
};// end of sprite
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////// Player Class ///////////////////////////////////////////////////////////////////////////////////////////////////////////
class Player : public Sprite
{
public:
Player(string name,int X, int Y, float health){
set_symbol('8');
set_name(name);
set_location(X,Y);
set_shield(100);};
private:
// none?
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////// Map class ///////////////////////////////////////////////////////////////////////////////////////////////////
class Map
{
private:
/////////////////////////////////////////// Map Variables ///////////////
string name;
vector <string> contents;
vector <string> save;
public:
Map(){};
Map(string* lines, int i, string name= "map"){name = name;
contents.resize(56);
Insert(lines, i);};
~Map(){};
/////////////////////////////////////////// generate ////////////////////
void generate(){GeneratePath(contents);};
/////////////////////////////////////////// Return() ////////////////////
string Name() {return name;};
vector <string> Contents() {return contents;};
string Contents(int Y) {return contents[Y];};
char Contents(int Y, int X) {return contents[Y][X];};
vector <string> Save() {return save;};
int size() {return contents.size();};
/////////////////////////////////////////// Insert() ////////////////////
// string* to an array of 24 strings;
void Insert(string* lines, int i)
{contents.assign(lines, lines+i);}; //insert lines 1-24
void Insert(string astring, int Y) {contents[Y] = astring;};
void Insert(char achar, int X, int Y){contents[Y][X] = achar;};
void Saveline(string line) {save.push_back(line);};
};
///////////////////////// SCREEN CLASS ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Screen
{
private:
/////////////////////////////////////////// Screen Variables ///////////////
string _name;
vector <string> new_map;
vector <string> old_map;
vector <Sprite*> sprites_p;
public:
Screen(string name){_name = name;
new_map.resize(nrows);
old_map.resize(nrows);};
~Screen(){};
//////////////////////////////////////////// Get contents ///////////////////////////
vector <string> get_contents(int comm= NEW) {switch(comm){ case NEW: return new_map; break;
case OLD: return old_map; break;}};
string get_contents (int Y, int comm= NEW) {switch(comm){ case NEW: return new_map[Y]; break;
case OLD: return old_map[Y]; break;}};
char get_contents (int X, int Y, int comm= NEW){switch(comm){ case NEW: return new_map[Y][X]; break;
case OLD: return old_map[Y][X]; break;}};
//////////////////////////////////////////// Refresh ///////////////////////////
void Refresh(int command= ALL, int transition= NONE)
{
//old_map = new_map; // update the old map
for(int r= 0; r< nrows; r++){ move(r,0);
addstr((char*)new_map[r].c_str());} // make sure this works later
// Insert Time
if(command== ALL || command== TIME){
enum{ time_loc_y= 22,
time_loc_x= 38 };
mvaddstr(time_loc_y, time_loc_x, myStopwatch.ClockTime().c_str());}
refresh();}; // end of function
/////////////////////////////////////////// Insert ////////////////////////
/////////////////// Map
void Insert(Map& map, int y1, int y2) {for ( int mc = y1, nm= 0; mc< map.size() && mc< y2; mc++, nm++){
new_map[nm] = map.Contents(mc);}
};
/////////////////// string
void Insert(string astring, int Y) {new_map[Y] = astring;};
///////////////////// char
void Insert(char achar, int X, int Y) {new_map[Y][X] = achar;};
//////////////////// sprite
void Insert(Sprite& sprite) {new_map[sprite.get_location()[1]][sprite.get_location()[0]] = sprite.get_symbol();
sprites_p.push_back(&sprite);}; // save a pointer to the sprite
/////////////////////////////////////////// Collision Detection ///////////
bool check_collision(Sprite& sprite,int X, int Y, char& buff)
{
////////////////////// check whats already there /////
char newloc = new_map[sprite.get_location()[1]+Y]
[sprite.get_location()[0]+X];
if(newloc == '|' || newloc == '/' || newloc == '_' || newloc == '=' || newloc == 'X' || newloc == '-' || newloc == 'x' ) {
buff = newloc;
sprite.destroy_shield();
return true;}
else return false;
};
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////// MAIN //////////////////////////////////// MAIN ////////////////////////////////////////////////////////////////////////
int main()
{
cout << "Maximize the screen for optimum experience!... type ok when done" << endl;
char response; cin >> response;
WINDOW *wnd;
wnd = initscr(); // curses call to initialize window and curses mode
//cbreak(); // curses call to set no waiting for Enter key
noecho(); // curses call to set no echoing
//curs_set(a number); (0 = invisible, 1 = normal, 2 = very visible)
int row,col; getmaxyx(stdscr,row,col); /* get the number of rows and columns */
clear(); // curses call to clear screen, send cursor to position (0,0)
Screen theScreen("ascreen");
string splashScreen[24] = { // HERE"S THE SPLASH !
// 1 2 3 4 5 6 7 8
// 123456789 123456789 123456789 123456789
// 0123456789 123456789 123456789 123456789 1234567
/* 0 */ "________________________________________________________________________________",
/* 1 */ "|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|",
/* 2 */ "|XXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|",
/* 3 */ "|XXXXXX / XXXXXXXXXXXXXXXXXXXXX xXXXXXXXXXX XXXXXXXXXXXx xXXXXXXx xXXX|",
/* 4 */ "|XXXXX /0} XXXXXXXXXXXXXXXXX /XXXXx XXXXXXx /X xXXXXXXXXX XXXXXX XXX|",
/* 5 */ "|XXXX /000} XXXXXXXXXXXXXX /XXXXXXXx XXXXX /X XXXXXXXX /X XXXX /X XX|",
/* 6 */ "|XXX XXXXXXXXXXXX /XXXXXXXXxx XXXX /XXX XXXXXXX /XX XXXX |X XX|",
/* 7 */ "|XX /XXXXXX XXXXXXXXXX /XXXXXXXXXXXXXXXX /XXX XXXXXX |XXX XX /X xX|",
/* 8 */ "|X /XXXXXXXX X*X*X*XXX /XXXXx xXX XXXXX |XXX /XXX X|",
/* 9 */ "|XXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXX XX /XXXXX XXXX |XXXX /XXXX X|",
/* 10 */ "|XXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXX Xx /XXXXXXX xXXX |XXXXx /XXXX X|",
/* 11*/ "|XXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXx /XXXXXXX xXX XXXXXxxXXXX x|",
/* 12 */ "|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|",
/* 13 */ "|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxxxxxxxxxxxxxxxxXXXX|",
/* 14 */ "|XXX XXxXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXX|",
/* 15 */ "|XXX XXXx XX/ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX_____XX XXXXXXXXXXXXXXXX|",
/* 16 */ "|XXX XXX / XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX|",
/* 17 */ "|XXX /0] XX/ XXXXx xXX XXXXXXXXXXX xXXX xXXXX xXXX|",
/* 18 */ "|XXX XX/ XXXXX XXXXXXXX xXXX XXX XXXXXX XXXXXXX xXXX|",
/* 19 */ "|XXXXXXXX XXXXXXX XXx xXX XXXXXX XXX xXXX xXXXX XXXXXXXXXXXXXXXX|",
/* 20 */ "|XXXXXXXXXXXXXXXXX XXXX XX XXXXXX XXX XXXXXX XXXXXXX XXXXXXXXXXXXXXXX|",
/* 21 */ "|XXXXXXXXXXXXXXXXXx xXXxxXXXXXXxxXXX xXXXXXX xXXXXXXX XXX|",
/* 22 */ "|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxxxxxxxxxxxxxxxxxxXXX|",
/* 23 */ "|______________________________________________________________________________|",};
string _lines_[56] = {
// 1 2 3 4 5 6 7 8
// 123456789 123456789 123456789 123456789
// 0123456789 123456789 123456789 123456789 1234567
/* 0 */ "________________________________________________________________________________",
/* 1 */ "|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|",
/* 2 */ "|XXXXXXXX XXXXXXXXXXXXX XXXXXXXXXXXX XXXXXXXX|",
/* 3 */ "|XXXXX XXXXXXXXXXXXXXXX XXXXXXXXX XXXXXXXXXX XXXXXXXX|",
/* 4 */ "|XXXX XXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXX XXXXXXXX|",
/* 5 */ "|XXX XXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXX XXXXXXXX|",
/* 6 */ "|XX XXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXX XXXXXXX XXXXXXXX|",
/* 7 */ "|XX XXXXXXXX XXXXXXX XXXXXXXXXXXXXXXXX XXXXXXX XXXXXXXX|",
/* 8 */ "|XXX XXXXXXXXXX XXXXX XXXXXXXXXXXXXXXXXXX XXXXXX XXXXXXXX|",
/* 9 */ "|XXXX XXXXXXXXXXXX XXXXX XXXXXXXXXXXXXXXXXXX XXXXXX XXXXXXXX|",
/* 10 */ "|XXXXX XXXXXXXXXXX XXXXX XXXXXXXXXXXXXXXXXXX XXXXXX XXXXXXXX|",
/* 11 */ "|XXXXXXX XXXXXXXXX XXXXXX XXXXXXXXXXXXXXXXX XXXXXXX XXXXXXXX|",
/* 12 */ "|XXXXXXXX XXXXXXX XXXXXX XXXXXXXXXXXXXXXXX XXXXXXX XXXXXXXX|",
/* 13 */ "|XXXXXXXXXX XXXXX XXXXXXX XXXXXXXXXXXXXXX XXXXXXXX___XXXXXXXX|",
/* 14 */ "|XXXXXXXXXXX XXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXxxxXXXXXXXX|",
/* 15 */ "|XXXXXXXXXXXX XXXXXXXXXXXX XXXXXXXXX XXXXXXXXXXx xXXXXXXX|",
/* 16 */ "|XXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXX XXXXXXXXXXXx xXXXXXXX|",
/* 17 */ "|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|",
/* 18 */ "| MOVE USING 'WASD' |=| avoid the walls |=| SURVIVE!! |=| press 'O' quit|",
/* 19 */ "|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|",
/* 20 */ "|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|",
/* 21 */ "|XXX XXX|",
/* 22 */ "|XXX XXX|",
/* 23 */ "|XXX XXX|",
/* 0 */ "|XXX XXX|",
/* 1 */ "|XXX XXX|",
/* 2 */ "|XXX XXX|",
/* 3 */ "|XXX XXX|",
/* 4 */ "|XXX XXX|",
/* 5 */ "|XXX XXX|",
/* 6 */ "|XXX XXX|",
/* 7 */ "|XXX XXX|",
/* 8 */ "|XXX XXX|",
/* 9 */ "|XXXX XXXX|",
/* 10 */ "|XXXXX XXXXX|",
/* 11*/ "|XXXXXX XXXXXX|",
/* 12 */ "|XXXXXXX XXXXXXX|",
/* 13 */ "|XXXXXXXX XXXXXXXX|",
/* 14 */ "|XXXXXXXXX XXXXXXXXX|",
/* 15 */ "|XXXXXXXXXX XXXXXXXXXX|",
/* 16 */ "|XXXXXXXXXXX XXXXXXXXXXX|",
/* 17 */ "|XXXXXXXXXXX XXXXXXXXXXX|",
/* 18 */ "|XXXXXXXXXXXX XXXXXXXXXXXX|",
/* 19 */ "|XXXXXXXXXXXX XXXXXXXXXXXX|",
/* 20 */ "|XXXXXXXXXXXXX XXXXXXXXXXXXX|",
/* 21 */ "|XXXXXXXXXXXXX XXXXXXXXXXXXX|",
/* 22 */ "|XXXXXXXXXXXXXX XXXXXXXXXXXXXX|",
/* 23 */ "|XXXXXXXXXXXXXX XXXXXXXXXXXXXX|"
/* 24 */ "|XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX|",
/* 25 */ "|XXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXX|",
/* 26 */ "|XXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXX|",
/* 27 */ "|XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXX|",
/* 28 */ "|XXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX|",
/* 29 */ "|XXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXX|",
/* 30 */ "|XXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX|",
/* 31*/ "|XXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXX|",
/* 32 */ "|XXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXX|",
};
////////////////////////////////// Splash Screen /////////////////////////////
Map splashScreen_map(splashScreen, 24);
theScreen.Insert(splashScreen_map, 0, nrows);
theScreen.Refresh(MAP);
myStopwatch.Wait(3);
myStopwatch.Restart();
/////////////////////////////////////////////////////////////////////////////////
Map L1(_lines_, nrows, "L1");
theScreen.Insert(L1, 0, nrows);
Sprite player("Player",'8', 5); //(8, 12, 16);
player.set_location(47, 22);
////////////////////// Check if new line is needed;
double refreshes= 0;
int newlines= 0;
const double speed= .1;
int numb_coll= 0;
bool dead= false;
///////////////////////// start of the for loop
for (bool quit = false; quit != true && dead== false;)
{ double newTime= myStopwatch.ElapsedTime()- refreshes;
if(newTime >= speed){
theScreen.Insert(L1, 0+newlines, nrows+newlines);
refreshes+= speed;
newlines++;
if(L1.size()<= nrows+newlines+2)
L1.generate();}
///////////////// Keypress ///////////
int xMove = 0;
int yMove = 0;
if (kbhit()){
int key = getch();
key = toupper(key); // makes whatever key uppercase
int stepSize = 1;
bool validPress = true;
switch(key){
// update health here............
case 'W': yMove = -stepSize;break;
case 'S': yMove = stepSize; break;
case 'A': xMove = -stepSize;break;
case 'D': xMove = stepSize; break;
case 'P': getch(); break;
case 'O': quit = true;
default: validPress = false;}
if(validPress == true){/*do something here or i might not need it.....*/}
} /* end of if(kbhit())*/
char coll; // the buffer for the collided char
theScreen.check_collision(player, xMove, yMove, coll);
if(coll== 'X'){
if(player.Alive()== false){}
// do something about it
// if there is life
else{
for(int I= 0; I< numb_coll && numb_coll< player.get_location()[1]; I++){
theScreen.Insert(' ',player.get_location()[0], player.get_location()[1]-(I+1));}
if(numb_coll>0)
player.add_shield(1);
numb_coll++;
theScreen.Insert(player);}}
else if(coll != 'X'){
theScreen.Insert(' ', player.get_location()[0],player.get_location()[1]);// get rid of old player placing
player.move(xMove, yMove); // put in new charater placing
theScreen.Insert(player);
numb_coll= 0;}
theScreen.Refresh();}// so refresh and restart the for loop
if(dead== true){
// theScreen.Insert(a gameover map);
}
endwin(); // curses call to restore the original window and leave
return 0;
}