So I have a 2d map array printed out. I have 0's set as a space and 1 set as a wall. I have variables such as traps and health as well as the player. However, I am having trouble implementing a score as the two collide. I was wondering how I can detect when a player and life collide which would increment the health variable by 1. Right now it increments every time I move.
Thank you!
These are my variable functions
void putplayer()
{
setcolor(9);
gotoxy( player.x +mazex, player.y +mazey);
cout<<playersymbol;
setcolor(7);
}
void puttreasure()
{
setcolor(14);
gotoxy(treasure.x +mazex, treasure.y +mazey);
cout<<treasuresymbol;
setcolor(7);
}
void puttraps()
{
setcolor(14);
gotoxy( traps.x +mazex, traps.y +mazey);
cout<<trapssymbol;
setcolor(7);
}
void putlives()
{
setcolor(14);
gotoxy( lives.x +mazex, lives.y +mazey);
cout<<livessymbol;
setcolor(7);
}
void moveleft()
{
gotoxy(31,7);
cout<<"left key move player left \n\n";
if (maze[player.y][player.x-1]==0) player.x = player.x -1;
}
Then my Main, however some code I took out as it might not be relevant
int main()
{
DWORD mode; /* Preserved console mode */
INPUT_RECORD event; /* Input event */
BOOL EXITGAME = FALSE; /* Program termination flag */
// unsigned int counter = 0; /* The number of times 'Esc' is pressed */
/* Get the console input handle */
HANDLE hstdin = GetStdHandle( STD_INPUT_HANDLE );
/* Preserve the original console mode */
GetConsoleMode( hstdin, &mode );
/* Set to no line-buffering, no echo, no special-key-processing */
SetConsoleMode( hstdin, 0 );
srand ( time(NULL) ); //initialize the random seed
// Variables
int health = 0;
// Declare variable positions
player.x=1;
player.y=1;
treasure.x = 1;
treasure.y = 3;
traps.x = 1;
traps.y = 7;
lives.x = 1;
lives.y = 9;
clrscr();
setcolor(15);
while (!EXITGAME)
{
if (WaitForSingleObject( hstdin, 0 ) == WAIT_OBJECT_0) /* if kbhit */
{
DWORD count; /* ignored */
/* Get the input event */
ReadConsoleInput( hstdin, &event, 1, &count );
/* Only respond to key release events */
if ((event.EventType == KEY_EVENT)
&& !event.Event.KeyEvent.bKeyDown)
clrscr();
putmenu();
gotoxy(6,20);
cout<<"Lives: " << health;
Sleep(100);
switch (event.Event.KeyEvent.wVirtualKeyCode)
{
case VK_ESCAPE:
EXITGAME = TRUE;
break;
case VK_LEFT:
// left key move player left
moveleft();
break;
case VK_RIGHT:
// right key move player right
moveright();
break;
case VK_UP:
// up key move player up
moveup();
break;
case VK_DOWN:
// down key move player down
movedown();
break;
case VK_A:
// left key move player left
moveleft();
break;
case VK_D:
// right key move player right
moveright();
break;
case VK_W:
// up key move player up
moveup();
break;
case VK_S:
// down key move player down
movedown();
break;
}//switch
putplayer();
puttreasure();
puttraps();
putlives();
}
if(maze[player.x][player.y] = maze[lives.x][lives.y]){
health++;
}
else if(maze[player.x][player.y] = maze[traps.x][traps.y]){
health--;
}
}
gotoxy(1,23);cout<<" ";
SetConsoleMode( hstdin, mode );
return 0;
}
You have the code
if(maze[player.x][player.y] = maze[lives.x][lives.y])
which sets the maze[player.x][player.y] to the value at maze[lives.x][lives.y], and then evaluates it (it will evaluate to true if 1 (wall), false if 0 (space)). I think you meant to have something like
if((player.x == lives.x) && (player.y == lives.y))
which will (as far as I can tell) evaluate if the player and the lives are at the same location.
Related
In my game right now I am trying to make a menu you can access when you press 'q', but currently I am having some issues. I think it switches to the CompScreen view and then back to the currentroom view quickly, I may be wrong. I am getting the cout CompMenu, HELP, and hello readings so I know it is running through the programs, but when I press q I remain in the same spot, nothing happening.
EventManager.h
#ifndef EventManager_h
#define EventManager_h
#endif /* EventManager_h */
int windowWidth = 5000;//width of window
int windowHeight = 5000;//height of window
sf::View leveltwo(sf::FloatRect(x, y, 5000, 5000));
sf::View start(sf::FloatRect(0, 0, 2500, 1500));
sf::View ComputerScreen(sf::FloatRect(50000, 50000, 5000, 5000));
sf::RenderWindow window(sf::VideoMode(windowWidth, windowHeight ), "Awesome Game" );
Character player("/Users/danielrailic/Desktop/Xcode /NewGame/ExternalLibs/Sprites/Player.png");
bool InMenu = false;
enum Levels{
StartRoom, LevelTwo
};
Levels room = StartRoom;
int currentroom;
void WhatRoom(int TheLevel){
switch (room){
case StartRoom:
currentroom = 1;
window.setView(start);
if (TheLevel == 2){
room = LevelTwo;
}
break;
case LevelTwo:
currentroom = 2;
window.setView(leveltwo);
break;
}
};
enum States{
compmenu, mainmenu, NoMenu
};
States menu = NoMenu;
void CompMenu(){
window.setView(ComputerScreen);
cout << "HELP";
InMenu = true;
}
void WhatMenu(int TheMenu){
switch (menu){
case compmenu:
cout << "CompMenu";
CompMenu();
break;
case mainmenu:
break;
case NoMenu:
if (TheMenu == 2){
menu = compmenu;
}
break;
if (TheMenu == 3){
menu = mainmenu;
}
break;
}
}
main.cpp (inside int main)
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Q) and InMenu == false){
WhatMenu(2);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Q) and InMenu == true){
InMenu = false;
WhatRoom(currentroom);
cout << "hello";
}
If you have any questions or need to see more of the code let me know. Thanks.
I think you've missed else after first if block so it may be executed immediately because InMenu may be changed to true at that point:
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Q) and InMenu == true){
Also you should handle the situation when key is pressed for a long time (to react only when it enters pressed state) and get rid of all the global variables because they are already creating quite a mess.
I've built a generic wrapper for the curses form object to use with a large
simulation project that I'm working on.
Basically, I instantiate an generic_form object, add some fields and their
descriptions to it, and then give it focus and get user input with a fill_form() routine.
Because each generic_form object can be used more than once, that is, that fill_form() may be called more than once per instantiation, I need to clear the field buffers at the beginning of the fill_form() routine. Currently, I'm using this at the beginning of the routine:
//clear the field buffers in case there's junk in them
for (std::vector<FIELD*>::iterator clear_iter = fields.begin();
clear_iter != fields.end(); clear_iter++)
{
if (*clear_iter != nullptr)
{
set_field_buffer(*clear_iter, 0, " ");
}
}
However, it throws a floating point exception at the set_field_buffer line on the second call to the fill_form() routine. Moreover, the set_field_buffer line doesn't seem to actually be doing anything, at least not clearing the buffer, because without calling free_field at the end of the routine, and instead in the object destructor, the fields buffers remain the same on each subsequent call.
Here's the entirety of the (ugly, in-development) fill_form() routine for brevity:
void generic_form::fill_form()
{
//fields.push_back(NULL);
if (fields.size() == 1)
{
fields.push_back(NULL);
form = new_form(static_cast<FIELD**>(fields.data()));
fields.erase((fields.end() - 1));
assert(fields.size() == 1);
}
else
{
form = new_form(static_cast<FIELD**>(fields.data()));
}
WINDOW* form_win = derwin(screen, fields.size() + 1, largest_desc + 6, ypos,
xpos);
set_form_win(form, form_win);
set_form_sub(form, form_win);
//clear the field buffers in case there's junk in them
for (std::vector<FIELD*>::iterator clear_iter = fields.begin();
clear_iter != fields.end(); clear_iter++)
{
if (*clear_iter != nullptr)
{
set_field_buffer(*clear_iter, 0, " ");
}
}
post_form(form);
for (int x = 0; x < descriptions.size(); x++)
{
mvwprintw(form_win, x, 0, descriptions.at(x).c_str());
}
wmove(form_win, 0, largest_desc + 1);
touchwin(screen);
wrefresh(form_win);
/* Loop through to get user requests */
int ch;
while((ch = getch()) != '\n')//KEY_F(1))
{ switch(ch)
{
case KEY_DOWN:
/* Go to next field */
form_driver(form, REQ_NEXT_FIELD);
/* Go to the end of the present buffer */
/* Leaves nicely at the last character */
form_driver(form, REQ_END_LINE);
break;
case KEY_UP:
/* Go to previous field */
form_driver(form, REQ_PREV_FIELD);
form_driver(form, REQ_END_LINE);
break;
case KEY_LEFT:
form_driver(form, REQ_PREV_CHAR);
break;
case KEY_RIGHT:
form_driver(form, REQ_NEXT_CHAR);
break;
// Delete the char before cursor
case KEY_BACKSPACE:
case 127:
form_driver(form, REQ_DEL_PREV);
break;
// Delete the char under the cursor
case KEY_DC:
form_driver(form, REQ_DEL_CHAR);
break;
default:
/* If this is a normal character, it gets */
/* Printed */
form_driver(form, ch);
break;
}
}
form_driver(form, REQ_VALIDATION);
for (int x = 0; x < fields.size() && first_run; x++)
{
//store the int_inputs from the forms
if ((fields.at(x) != nullptr) && (field_type(fields.at(x)) ==
TYPE_INTEGER))
{
int_inputs.push_back(std::atoi(field_buffer((fields.at(x)), 0)));
}
if ((fields.at(x) != nullptr) && (field_type(fields.at(x)) ==
TYPE_ALPHA))
{
str_inputs.push_back(field_buffer((fields.at(x)), 0));
}
}
first_run = false;
/* Un post form and free the memory */
unpost_form(form);
free_form(form);
for (int x = 0; x < fields.size(); x++)
{
free_field(fields.at(x));
}
delwin(form_win);
}
Long story short/TLDR:
How to I clear or reset a field buffer in ncurses, without deleting and re-adding it?
You can clean field buffer using form_driver ()
Excerpt man form_driver
REQ_CLR_EOL
Clear to end of line from cursor.
REQ_CLR_EOF
Clear to end of field from cursor.
REQ_CLR_FIELD
Clear the entire field.
To elaborate this a bit more :-), I'm using code similar to following for clearing fields:
#include <stdio.h>
#include <stdlib.h>
#include <form.h>
enum f_name_l
{
f_name, f_surname, f_last
};
int main (void)
{
int ch = 0, i = 0;
FIELD *field[3], *save_field;
FORM *my_form;
initscr ();
start_color ();
noecho ();
raw ();
keypad (stdscr, TRUE);
refresh ();
field[f_name] = new_field (1, 10, 0, 25, 0, 0);
field[f_surname] = new_field (1, 10, 2, 25, 0, 0);
field[f_last] = NULL;
set_field_back (field[f_name], A_UNDERLINE);
set_field_back (field[f_surname], A_UNDERLINE);
my_form = new_form (field);
post_form (my_form);
// Form labels
mvprintw (0, 1, "Name: ");
mvprintw (2, 1, "Surname: ");
mvprintw (4, 1, "F5 to clear active field. F6 to clear form.");
pos_form_cursor (my_form);
refresh ();
// ^q to exit
while ((ch = getch ()) != 17)
{
switch (ch)
{
case KEY_UP:
form_driver (my_form, REQ_PREV_FIELD);
break;
case KEY_DOWN:
form_driver (my_form, REQ_NEXT_FIELD);
break;
case KEY_F(5):
form_driver (my_form, REQ_CLR_FIELD);
break;
case KEY_F(6):
save_field = current_field (my_form);
for (i = 0; i < f_last; i++)
{
set_current_field (my_form, field[i]);
form_driver (my_form, REQ_CLR_FIELD);
}
set_current_field (my_form, save_field);
break;
default:
form_driver (my_form, ch);
break;
}
form_driver (my_form, REQ_VALIDATION);
}
endwin ();
return EXIT_SUCCESS;
}
But seeing post from Thomas Dickey I start to feel like my life is a lie :-).
So I have most of my game finish up however, I want to save the score and name of the player to a text file and display it. So far the user input works and does save to a text file named score.txt however the input is invisible and you can't see what you are typing. Does anyone know why this is happening?
Main
int main()
{
DWORD mode; /* Preserved console mode */
INPUT_RECORD event; /* Input event */
BOOL EXITGAME = FALSE; /* Program termination flag */
unsigned int counter = 0; /* The number of times 'Esc' is pressed */
/* Get the console input handle */
HANDLE hstdin = GetStdHandle( STD_INPUT_HANDLE );
/* Preserve the original console mode */
GetConsoleMode( hstdin, &mode );
/* Set to no line-buffering, no echo, no special-key-processing */
SetConsoleMode( hstdin, 0 );
srand ( time(NULL) ); //initialize the random seed
// Variables
int health = 2;
// Declare variable positions
player.x=1;
player.y=1;
treasure.x = 20;
treasure.y = 5;
treasure.z= 0;
traps.x = 1;
traps.y = 7;
traps.z = 0;
lives.x = 1;
lives.y = 9;
ofstream file;
int score = 0;
string name;
string line;
/*
while(treasure.z < 2)
{
treasure.x = (rand() % 24);
treasure.y = (rand() % 16);
if(treasure.x == 0 && treasure.y == 0)
{
treasure.z++;
}
}
while(traps.z < 3)
{
traps.x = (rand() % 24);
traps.y = (rand() % 16);
if(traps.x == 0 && traps.y == 0)
{
traps.z++;
}
}
while(lives.z < 2)
{
lives.x = (rand() % 24);
lives.y = (rand() % 16);
}
*/
clrscr();
setcolor(15);
while (!EXITGAME)
{
if (WaitForSingleObject( hstdin, 0 ) == WAIT_OBJECT_0) /* if kbhit */
{
DWORD count; /* ignored */
/* Get the input event */
ReadConsoleInput( hstdin, &event, 1, &count );
/* Only respond to key release events */
if ((event.EventType == KEY_EVENT)
&& !event.Event.KeyEvent.bKeyDown)
clrscr();
putmenu();
gotoxy(6,20);
cout<<"Lives: " << health;
gotoxy(6,22);
cout<<"Score: " << score;
Sleep(50);
switch (event.Event.KeyEvent.wVirtualKeyCode)
{
case VK_ESCAPE:
clrscr();
putend();
EXITGAME = TRUE;
break;
case VK_LEFT:
// left key move player left
moveleft();
break;
case VK_RIGHT:
// right key move player right
moveright();
break;
case VK_UP:
// up key move player up
moveup();
break;
case VK_DOWN:
// down key move player down
movedown();
break;
case VK_A:
// left key move player left
moveleft();
break;
case VK_D:
// right key move player right
moveright();
break;
case VK_W:
// up key move player up
moveup();
break;
case VK_S:
// down key move player down
movedown();
break;
}//switch
puttreasure();
puttraps();
putlives();
putplayer();
if((player.x == lives.x) && (player.y == lives.y))
{
health++;
lives.x = 0;
lives.y = 0;
}
if((player.x == traps.x) && (player.y == traps.y))
{
health--;
traps.x = 0;
traps.y = 0;
}
if((player.x == treasure.x)&& (player.y == treasure.y))
{
score += 100;
EXITGAME = true;
}
else if(health == 0)
{
EXITGAME = true;
}
if(EXITGAME == true)
{
score = score + (health * 100);
}
}
}
if(EXITGAME == true)
{
// clear screen
clrscr();
}
setcolor(10);
cout << "Enter your name ";
cin >> name;
ofstream out("score.txt");
out << name;
out << "\n";
out << score;
out.close();
/* if(file.is_open())
{
while( getline (file, line))
cout << line << '\n';
}*/
gotoxy(1,23);cout<<" ";
SetConsoleMode( hstdin, mode );
return 0;
}
/* Set to no line-buffering, no echo, no special-key-processing */
You turned off echo - means that the user wont see what they type
Hey so I'm working on a project/2d game and I'm having some odd behavior from SDL which I'm sure is probably something I'm not understanding. The function ProcessKeys is called and works fine for all the key press downs except SDLK_SPACE and I cannot for the life of me figure out why.
What is even more bizarre is that the SDL_KEYUP switch of SDLK_SPACE works great. I tried using some debugging code to print out which key is being pressed and when you press space down nothing registers. Every other key on the keyboard registers in my debug statement at the top of the SDL_KEYDOWN case.
If anyone can see what is going on I would really appreciate it.
And if you need to see where its being called let me know.
SDLKeyboard::KeyState SDLKeyboard::ProcessKeys(SDL_Event * event)
{
switch(event->type)
{
/* Look for a keypress */
case SDL_KEYDOWN:
{
std::cout << "Key currently pressed" << event->key.keysym.sym << std::endl;
/* Check the SDLKey values and move change the coords */
switch(event->key.keysym.sym)
{
case SDLK_LEFT:
{ // rotate the ship left
c.setIsTurningLeft(true);
return this->keystate = LeftPressed;
// add code when user presses left
break;
}
case SDLK_RIGHT:
{
// rotate the ship right
c.setIsTurningRight(true);
return this->keystate = RightPressed;
// add code when user presses right
break;
}
case SDLK_UP:
{
// accleration
c.setIsAccelerating(true);
return this->keystate = UpPressed;
// add code when user presses up
break;
}
case SDLK_SPACE:
{
// shoot
c.setIsShooting(true);
std::cout << "keystate = " << this->keystate;
return this->keystate = SpacePressed;
// add code when user presses space
break;
}
default:
{
return this->keystate = NotPressed;
break;
}
}
break;
}
/* We must also use the SDL_KEYUP events to zero the x */
/* and y velocity variables. But we must also be */
/* careful not to zero the velocities when we shouldn't*/
case SDL_KEYUP:
{
std::cout << "Key currently pressed" << event->key.keysym.sym << std::endl;
switch(event->key.keysym.sym)
{
case SDLK_LEFT:
{ /* We check to make sure the ship is moving */
/* to the left. If it is then we zero the */
/* velocity. If the ship is moving to the */
/* right then the right key is still press */
/* so we don't touch the velocity */
c.setIsTurningLeft(false);
return this->keystate = LeftReleased;
// code to do things when left isn't pushed anymore but still moving left
break;
}
case SDLK_RIGHT:
{ // code to do things when right isn't pushed anymore but still moving right
c.setIsTurningRight(false);
return this->keystate = RightReleased;
break;
}
case SDLK_UP:
{ // code to do things when up isn't pushed anymore but still moving up
c.setIsAccelerating(false);
return this->keystate = UpReleased;
break;
}
case SDLK_SPACE:
{ // accleration
c.setIsShooting(false);
return this->keystate = SpaceReleased;
// add code when user presses up
break;
}
default:
break;
}
break;
}
default:
{
return this->keystate = NotPressed;
break;
}
}
}
EDIT:
Here is the example requested. The other thing that I've noticed is the latency in response isn't that great. Like if you press a key sometimes the console doesn't print the corresponding key. Probably has to do with the issue I'm having with the space as well.
void GUI::TakeInput(SDL_Event *e)
{
while (SDL_PollEvent(e))
OnEvent(e);
}
void SDLEvent::OnEvent(SDL_Event * event)
{
switch(event->type)
{
case SDL_KEYDOWN:
{
OnKeyDown(event->key.keysym.sym);
break;
}
case SDL_KEYUP:
{
OnKeyUp(event->key.keysym.sym);
break;
}
case SDL_MOUSEMOTION:
{
OnMouseMove(event->motion.x,event->motion.y);
break;
}
case SDL_MOUSEBUTTONDOWN:
{
OnMouseButtonDown(event->button.button, event->button.x,event->button.y);
break;
}
case SDL_MOUSEBUTTONUP:
{
OnMouseButtonUp(event->button.button, event->button.x,event->button.y);
break;
}
case SDL_QUIT: {
OnExit();
break;
}
case SDL_SYSWMEVENT: {
//Ignore
break;
}
case SDL_WINDOWEVENT_RESIZED: {
OnResize();
break;
}
case SDL_WINDOWEVENT_EXPOSED: {
OnExpose();
break;
}
default: {
OnUser(event->user.type,event->user.code,event->user.data1,event->user.data2);
break;
}
}
}
void GUI::Play()
{
Uint32 start_ticks = SDL_GetTicks();
TakeInput(this->setup->GetEvent());
this->keyboard->ProcessKeys(this->setup->GetEvent());
this->setup->RenderBegin();
this->ship->drawBackBuffer();
this->ship->renderSprite();
Uint32 end_ticks = SDL_GetTicks();
int sleep_delay = (1000 / 60) - (end_ticks-start_ticks);
if (sleep_delay > 0) {
SDL_Delay(sleep_delay);
}
}
If you are only writing event->key.keysym.sym on the console, you should know that the spacebar key produces an almost invisible character.
Try this instead:
std::cout << "<" << event->key.keysym.sym << ">"
So you can see whataver invisible character printed between angle brackets.
I'm new to ncurses and we have a project to create a game of our choice.
The idea of my game is to have a spaceship and have enemies attack from the top.
I only started the code and I already ran into a problem, when i use the space bar to shoot a bullet, the bullet will travel, however i am unable to move my ship at the same time the bullet is moving.
#include<ncurses.h>
typedef struct
{/*define a structure for player information*/
int row;
int col;
}playerinfo;
int changeRow(int x,int m, int c)
{
if(x+m==22 || x+m==0 )
{
beep();
return x;
}
return x+m;
}
int changeColumn(int y,int n, int r)
{
if(y+n==72 || y+n==0 )
{
beep();
return y;
}
return y+n;
}
int main(){
initscr();
start_color();
assume_default_colors(COLOR_GREEN, COLOR_BLACK);
noecho();
cbreak();
curs_set(0); /* turn cursor display off */
timeout(0);
keypad(stdscr,TRUE); /* allow keypad keys to be used */
playerinfo playership;
playership.row= 10;
playership.col= 15;
char player[] =" X ";
char player2[]=" |o| ";
char player3[]=" xX| |Xx ";
char player4[]=" X | | X ";
char player5[]=" X__-|-__X ";
char bullet = '.';
int key = 0;
int i=0;
bool moving= false;
mvprintw(playership.row,playership.col,player);
mvprintw(playership.row+1,playership.col,player2);
mvprintw(playership.row+2,playership.col,player3);
mvprintw(playership.row+3,playership.col,player4);
mvprintw(playership.row+4,playership.col,player5);
timeout(0);
while(key!='q'){
usleep(17000);
mvprintw(playership.row,playership.col," ");
mvprintw(playership.row+5,playership.col," ");
key = getch ();
switch(key){
case KEY_UP: playership.row=changeRow(playership.row,-1,playership.col); /* move up */
break;
case KEY_DOWN: playership.row=changeRow(playership.row,+1,playership.col); /* move down */
break;
case KEY_LEFT:playership.col=changeColumn(playership.col,-1,playership.row); /* move left */
break;
case KEY_RIGHT:playership.col=changeColumn(playership.col,+1,playership.row); /* move right */
break;
case ' ': moving=true; break;
default: break; /* do nothing if other keys */
}
mvprintw(playership.row,playership.col,player);
mvprintw(playership.row+1,playership.col,player2);
mvprintw(playership.row+2,playership.col,player3);
mvprintw(playership.row+3,playership.col,player4);
mvprintw(playership.row+4,playership.col,player5);
if (moving==true){
for( i=0; i <24; i++){
refresh; mvprintw(playership.row-i-2,playership.col+5,"%c", bullet); mvprintw(playership.row,playership.col,player);
refresh();usleep(12000); mvprintw(playership.row-i-1,playership.col+5," ");} moving=false; }
refresh();
}
echo(); /* turn echo back on */
endwin(); /* End curses mode */
return 0;
}
That is because you nested the "firing" code inside your game loop, so all input stops while you do that animation. You need to change your logic to a kind of state machine:
switch(key)
{
// ...
case ' ':
if( !bullet_active )
{
bullet_active = true;
bullet_pos = 0;
}
break;
}
if( bullet_active ) {
// TODO: Draw bullet at bullet_pos
if( ++bullet_pos == 24 ) bullet_active = false;
}