Here is my code:
void MainGame::ProcessInput()
{SDL_Event Evnt;
while (SDL_PollEvent(&Evnt));
{switch(Evnt.type)
{case SDL_QUIT: {_GameState = GameState::EXIT;}
break;
case SDL_MOUSEMOTION: {}
break;
case SDL_KEYDOWN: {_InputManager.PressedKey(Evnt.key.keysym.scancode);}
break;
case SDL_KEYUP: {_InputManager.ReleasedKey(Evnt.key.keysym.scancode);}
break;
case 771: {std::cout << "Info1 = " << Evnt.key.keysym.scancode << std::endl;
_InputManager.PressedKey(Evnt.key.keysym.scancode); }
break;
}
}
}
So in this code, if I push up, down, left and right arrows, KEYDOWN is working properly. If I hit any letters on my keyboard, it will only return code 771. Here I made a test including 771 in my switch. When I hit letters, it does go to 771 and print a silly number like 30445778. And this number change every time I re-run the program. Man what's going on here?!? please help me
The problem you are facing is an additional ; after your while condition. Citing SDL wiki, your code should be written as follows:
while (1) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
/* handle your event here */
}
/* do some other stuff here -- draw your app, etc. */
}
Note that there's no semicolon after while.
However, although the code you've written does not do what you want it to do, it's still correct from C++ point of view.
This line:
while (SDL_PollEvent(&Evnt));
will enter a loop that will iterate up until the point SDL_PollEvent returns 0, while doing nothing.
After that, your switch statement will only run once, processing the last polled event (disregarding its type). In the same time, your switch statement is not ready to handle most of the event types.
I'm writing a basic snake game as console application in c++. It's based on two-dimensional array of "tile" structures. My problem is: when pressing button to change the direction the snake is going it doesn't work immidiately but waits for next "tick" instead. The function that manages game itself looks like this:
void board::play()
{
display();
while(1)
{
getInput();
delay(0.5);
getInput();
resetCursor();
tick();
display();
}
}
display() is pretty self-explanatory, displays whole board in console window.
delay() as well, it's function which gets number of seconds as a float and waits this much time before proceeding
getInput() looks like this:
void board::getInput()
{
int input;
if(kbhit())
{
input=getch();
if(input==KEY_LEFT)
turnLeft();
if(input==KEY_RIGHT)
turnRight();
if(input==KEY_UP)
turnUp();
if(input==KEY_DOWN)
turnDown();
}
}
resetCursor() sets the cursor to 0,0 coordinate so each time the board will write over itself and not one under another
And now for the game itself: class board contains amongst others field int direction. The tiles themselves contain a counter, which counts down by 1 with each move, and when reaches 0 the tile becomes empty. If the counter is equal to the lenght of a snake the tile is considered a head.
The tick()function does just that: decreases all counters by 1, remembers where head was and spawns a new head in the field next to previous one in direction specified. It looks like this:
void board::tick()
{
int posx, posy;
for(int i=0; i<boardSize; i++)
{
for(int j=0; j<boardSize; j++)
{
if(tab[i][j].getCounter()==lenght)
{
posx=i;
posy=j;
}
tab[i][j].tick();
}
}
switch(direction)
{
case UP: tab[posx-1][posy].addSnake(lenght);
break;
case DOWN: tab[posx+1][posy].addSnake(lenght);
break;
case LEFT: tab[posx][posy-1].addSnake(lenght);
break;
case RIGHT: tab[posx][posy+1].addSnake(lenght);
break;
}
}
Problem is, as stated before, that game waits one "tick" before changing direction when it should do so immediately after pressing associated button, e.g. when turning from UP to LEFT it does one more move up and only after that moves left.
It seems to me that you have an extra getInput() call. Could it be the problem?
while(1)
{
getInput(); // <--
delay(0.5);
getInput(); // <--
resetCursor();
tick();
display();
}
Solved.
Turns out there were too many things put into buffer, as the program started going crazy if you mashed controls randomly during waiting time. I solved it by replacing
if(kbhit())
{
input=getch();
//reactions
}
with
while(kbhit())
{
input=getch();
}
//reactions
It now checks every signal in the buffer and reacts only to the last one, so the delay is eliminated.
I have made a simple score4 game. It was a project so I made a CLI IO system.
Wanting to upgrade in the furure I made the whole IO Interface (move choosing, board show) a bunch of virtual functions in a class. So I made the CLI Interface just by implementing those functions with iostream usage. I initialize this Interface like this:
IOInterface *ii = new IOConsoleInterface();
Now I want to make wxWidgets Interface of the game and run it with a -gui switch. I made the frames quite easily but now that I want to finally connect the pieces, when I initialize the GUI it enters an infinite loop and doesnt return to the Score4 game loop.
The game loop calls ii functions so i dont need the control in the wxWidgets. I want it just to be there and do the stuff it is ordered to do by the game loop.
thank you in advance
Edit: The Score4 wasn't a wx Application. I just want to apply some wxGUI classes to it.
Edit2: The game loop code:
"ii" is InputInterface, an object that takes information
like move and play-again answer
"oi" is OutpuInterface, an object that draws the board and
tells the player that it is his turn
void Mechanics::gameLoop(){
bool newGame = true;
int gameCounter = 0;
while(newGame){
short choice = 0;
short turn;
gameCounter++;
currentPlayer = decideStart(gameCounter);
board.clear();
oi->refreshTable(board, p1,p2);
for (turn = 1; turn <= ROWS*COLS; turn++){
oi->playerPrompt(currentPlayer);
do{
if (currentPlayer->isAI == 0)
choice = ii->getPlayersMove(currentPlayer);
else{
GameInstance gi = exportGameInstance();
choice = currentPlayer->chooseMove(gi); // AI's movement
}
} while (!(board.checkMoveValidity(choice))); //breaks when move is valid--> when condition is >0
board.move(choice,currentPlayer);
oi->moveAnimation(choice,currentPlayer);
oi->refreshTable(board, p1,p2);
if (board.winConditionCheck(currentPlayer))
break;
changeCurrentPlayer();
}
if (turn > ROWS*COLS) //draw
oi->draw_conclusion();
else
oi->win_loss_conclusion(true,currentPlayer);
newGame = ii->newGamePrompt();
}
delete ii;
delete oi;
// GAME ENDS HERE
}
You need to run the event loop in the GUI application, there is no (reasonable) way around that. So while you can initialize wxWidgets without entering the event loop using e.g. wxEntryStart(), you still do need to run it later.
If you want to have both console and GUI interfaces the best would be to run the event loop in both cases, except you'd run your own event loop in the former case and wx one in the latter.
I know that in order to kill invaders in C++, I need to make a collider.
However, nothing will ever kill the invaders in that game.
Here's the code in the header:
bool DoCollision(float Xbpos, float Ybpos, int BulWidth, int BulHeight, float Xipos, float Yipos, int InvWidth, int InvHeight);
This is the function I'm initializing:
bool Game::DoCollision(float Xbpos, float Ybpos, int BulWidth, int BulHeight, float Xipos, float Yipos, int InvWidth, int InvHeight) {
if (Xbpos+BulWidth < Xipos || Xbpos > Xipos+InvWidth) return false;
if (Ybpos+BulHeight < Yipos || Ybpos > Yipos+InvHeight) return false;
return true;
}
And this is what happens if somebody presses the space key:
if (code == 57) { //Space
myKeyInvader.MeBullet.Active = true;
myKeyInvader.MeBullet.Xpos = myKeyInvader.Xpos + 10;
myKeyInvader.MeBullet.Ypos = myKeyInvader.Ypos - 10;
myKeyInvader.MeBullet.yvuel = 0.2;
myKeyInvader.MeBullet.BulletP->CopyTo(m_Screen,myKeyInvader.Xpos,myKeyInvader.Ypos);
if (DoCollision(Invaders[counter].MyBullet.Xbpos,Invaders[counter].MyBullet.Ybpos,Invaders[counter].MyBullet.BulWidth,
Invaders[counter].MyBullet.BulHeight,Invaders[counter].Xipos,Invaders[counter].Yipos,Invaders[counter].InvWidth,Invaders[counter].InvHeight)) {
//myKeyInvader.Ypos = 100;
Invaders[counter].Active = false;
printf("Collide!\n");
}
}
Does anybody know what's going wrong?
The problem isn't C++. The problem is how you are using it. The only way you'll get a kill with your code as written is if the invader is right on top of you. But that's too late. The alien invader has already killed you.
What you need to do is make those bullets into objects that you propagate over time, just like your invaders are objects that you propagate over time. The response to the user pressing a space key should be to add a new instance of a bullet to the set of active bullets. Each of those active bullets has a position that changes with time. On each time step, you should advance the states of the active invaders per the rules that dictate how invaders move and advance the states of the active bullets per the rules that dictate how bullets move. Remove bullets when they reach the top of the screen, and if an alien invader reaches the bottom of the screen, game over.
After propagating, removing off-screen bullets, and checking for game over, you want to check for collisions between each of the N bullets with each of the M invaders. When a collision is detected, remove the bullet from the set of active bullets and delete the alien invader from the set of active invaders. And of course you'll want some nifty graphics to show the user that another alien bit the dust.
Aside: Being an NxM problem, this check might be the biggest drain on CPU usage. You can speed this up with some simple heuristics.
You could manage the collections of alien invaders and bullets yourself, carefully using new and delete so as to prevent your invaders and bullets from killing your program with a memory leak. You don't have to do this. C++ gives you some nifty tools to manage these collections. Use one of the C++ standard library collections instead of rolling your own collection. For example, std::vector<AlienInvader> invaders; or std::list<AlienInvader> invaders, and the same for bullets. You'll be deleting from the middle a lot, which suggests that std::list or std::deque might be more appropriate than std::vector here.
You test the collision for the fired item just when they are created
Shouldn't be the test collision done in the main loop for each existing item at each frame ?
Don't worry, C++ has got all you need to kill invaders :)))
It's not easy to give advice based on so little code, but here the only logical error seems to be you test for collision only when space is pressed; you should test for it in an outside loop probably:
if (code == 57) { //Space
myKeyInvader.MeBullet.Active = true;
myKeyInvader.MeBullet.Xpos = myKeyInvader.Xpos + 10;
myKeyInvader.MeBullet.Ypos = myKeyInvader.Ypos - 10;
myKeyInvader.MeBullet.yvuel = 0.2;
myKeyInvader.MeBullet.BulletP->CopyTo(m_Screen,myKeyInvader.Xpos,myKeyInvader.Ypos);
}
From a logical point of view, pressing Space should fire a bullet: the starting position for the bullet is set, and so is its speed on the Y axis (so that it goes up).
The code that check for collision should go outside of this if block. In fact, this block of code is executed only if you're still pressing space -that is: still firing-. Should collision be checked only if you're "still firing"? Do the fact that you fired a bullet and started waiting for it to destroy the invader interfere in some way with the fact that this bullet can reach the invader and, indeed, destroy it? Of course not!
if (DoCollision(Invaders[counter].MyBullet.Xbpos,Invaders[counter].MyBullet.Ybpos,Invaders[counter].MyBullet.BulWidth,
Invaders[counter].MyBullet.BulHeight,Invaders[counter].Xipos,Invaders[counter].Yipos,Invaders[counter].InvWidth,Invaders[counter].InvHeight)) {
//myKeyInvader.Ypos = 100;
Invaders[counter].Active = false;
printf("Collide!\n");
}
You want collision to be checked in an outside loop, the same that probably also contains the checks for key presses. In this way, even if you're just looking at the screen and waiting, the program keeps testing the condition and, when it's fulfilled, code associated with the event of collision is executed (that is: an invader is "inactivated").
You say //Space , is that what it is or should it be 32 (if ASCII) instead of 57? Does the program flow into the if==57 block?
Your code looks fine, but you need two loops around the collision checker: one for checking all invaders (not just one of them) and another one to check at every bullet position along its trajectory, not just the moment when it leaves the gun.
I will assume we have an auxiliary function that moves the bullet and returns whether it is still inside the screen:
bool BulletIsInScreen();
Then we can write the loops:
if (code == 57) { // Space
while (BulletIsInScreen()) {
for (size_t i = 0; i < counter; ++i) { // counter is the number of invaders,
// according to your comment to your own answer
myKeyInvader.MeBullet.Active = true;
myKeyInvader.MeBullet.Xpos = myKeyInvader.Xpos + 10;
myKeyInvader.MeBullet.Ypos = myKeyInvader.Ypos - 10;
myKeyInvader.MeBullet.yvuel = 0.2;
myKeyInvader.MeBullet.BulletP->CopyTo(m_Screen,myKeyInvader.Xpos,myKeyInvader.Ypos);
if (DoCollision(Invaders[i].MyBullet.Xbpos, Invaders[i].MyBullet.Ybpos,
Invaders[i].MyBullet.BulWidth, Invaders[i].MyBullet.BulHeight,
Invaders[i].Xipos, Invaders[i].Yipos,
Invaders[i].InvWidth, Invaders[i].InvHeight)) {
//myKeyInvader.Ypos = 100;
Invaders[i].Active = false;
printf("Collide!\n");
}
}
}
}
Now this should work as expected.
I am currently working on a way to load a bunch of different NPCs from a file and loading it into my game. I have everything working correctly with arrays but I would like to change it to using a vector since I can change the size in case I need more NPCs than the space available in the array and so I don't just have a mostly empty array if I dont need many NPCs at the current time. Note that the following code is from a testing program, not my actual programming. I made it so I dont mess with the complete project by accident.
int main()
{
char input;
bool Running = true;
NPC Creatures[MAX_NPCS];
//InitCreatures loads the X, Y and Type from the file. I know with vectors I have to
//resize it as I go along, Which would be included in the function.
if(Creatures[MAX_NPCS].InitCreatures(Creatures) == false)
{
Creatures[MAX_NPCS].CleanUp(Creatures);
return 0;
}
while(Running == true)
{
cout << "(C)heck an NPC, (A)ttack and NPC or (E)xit the program\n";
cin >> input;
switch(input)
{
case 'C': Creatures[MAX_NPCS].Check(Creatures); break;
case 'c': Creatures[MAX_NPCS].Check(Creatures); break;
//The Check function just shows the X, Y and Type of the NPC
case 'A': Creatures[MAX_NPCS].Attack(Creatures); break;
case 'a': Creatures[MAX_NPCS].Attack(Creatures); break;
//Attack shows X, Y and type and then removes that NPC from the array.
case 'E': Running = false; break;
case 'e': Running = false; break;
default: cout << "That was not a valid input\n"; break;
}
}
Creatures[MAX_NPCS].CleanUp(Creatures);
cout << "Exiting\n";
system("PAUSE");
return 0;
}
Really the only problem I am having is getting Main to run the NPC Class functions from a vector instead of using the Array like I have now. I can easily change the other things in the functions I'm calling to accept the vector and handle it correctly.
When trying to use a vector to run the functions I was only able to call them when I had something like this:
Creatures[1].Attack(Creatures);
Of course when I call them like that the values don't return correctly and I usually get an error and Besides I don't know how many NPCs will be loaded for the current map, if Any.
Any help with this would be appreciated. I realize I am a newbie when it comes to programming, especially when it comes to Vectors. If my function code is needed I will gladly post it.
You could just create a vector and have the first element in there to be able to call the InitCreatures function (you could also overwrite the first creature later).
vector<NPC> Creatures(1);
Creatures[0].InitCreatures(Creatures);
I'm assuming that in class you have the parameter passed by reference.
bool InitCreatures(vector<NPC>& x) { ... }
But since you give creatures as a parameter to every function you have (do you need it in check or attack?) - wouldn't it be better to have a class to hold the NPC vector?