An snippet of my code from main.cpp
playerEntity::handle()
{
if( event.type == SDL_KEYDOWN )
{
switch( event.key.keysym.sym )
{
case SDLK_q:
running = false;
paused = true;
break;
case SDLK_ESCAPE:
paused = !paused;
break;
}
}
if( keystate[SDLK_UP] )
{
if( isJumping == false && isFreeFalling == false )
{
isJumping = true;
}
}
if( keystate[SDLK_LEFT] ) player.hitbox.x--;
if( keystate[SDLK_RIGHT] ) player.hitbox.x++;
if( player.hitbox.x < 0 ) {player.hitbox.x = 0;}
else if( player.hitbox.x > screen.WIDTH - player.hitbox.w ) {player.hitbox.x = screen.WIDTH - player.hitbox.w;}
if( player.hitbox.y < 0 ) {player.hitbox.y = 0;}
else if( player.hitbox.y > screen.HEIGHT - player.hitbox.h ) {player.hitbox.y = screen.HEIGHT - player.hitbox.h;}
}
Where playerEntity is defined in a header file:
#ifndef PLAYERENTITY_H
#define PLAYERENTITY_H
class playerEntity
{
private:
int jumpHeight;
int jump;
bool isJumping;
bool isFalling;
bool isFreeFalling;
SDL_Event event;
Uint8 *keystate;
public:
playerEntity();
void jump();
void handle();
void fall();
int health;
int damage;
SDL_Rect hitbox;
bool evolved;
};
#endif
And when I try to compile I get the errors:
ISO c++ forbids declaration of 'handle' with no type [-fpermissive]
prototype for 'int playerEntity::handle()' does not match any in class 'playerEntity'
error: candidate is: void playerEntity::handle().
I am still new to header files and classes, how do I fix the errors?
you should replace
playerEntity::handle()
with
void playerEntity::handle()
Write
void playerEntity::handle()
C++ requires the return type (which in this case is the nontype void) to be mentioned in the function's definition—an important type-safety measure.
By the way, you should probably move the definition of playerEntity::handle() from main.cpp to a new file, playerEntity.cpp. Other files are possible, too, but few good programmers would leave this definition in main.cpp. Unfortunately—well, actually fortunately—this will put you through several hours of the urgently necessary pain of learning separate compilation and linking.
Good luck.
Related
I wrote a simple test application to prove that the threads work:
// Test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
class clsTest {
private:
uintptr_t muintHandle;
static unsigned int __stdcall fnThread(void* pData) {
while( 1 ) {
_sleep(1000);
printf("In fnThread, handle = %d\n", *(uintptr_t*)pData);
}
return 0;
}
public:
clsTest() {
muintHandle = _beginthreadex(0, 0, &clsTest::fnThread, (void*)&muintHandle, 0, 0);
printf("clsTest(), after beginthreadex, handle = %u\n", muintHandle);
}
};
int _tmain(int argc, _TCHAR* argv[]) {
clsTest* pT = NULL;
while(1) {
printf("From _tmain\n");
if ( pT == NULL ) {
pT = new clsTest();
}
_sleep(1000);
}
return 0;
}
The output from this application is:
From _tmain
clsTest(), after beginthreadex, handle = 112
In fnThread, handle = 112
From _tmain
In fnThread, handle = 112
From _tmain
In fnThread, handle = 112
From _tmain
In fnThread, handle = 112
From _tmain
In fnThread, handle = 112
From _tmain
In fnThread, handle = 112
...
Continuously which is exactly what I would expect to see...Now in a much larger project I have a base class:
typedef enum {
eIdle = 0, //Thread is not working at all
eStarted, //Thread has been started but is not fully operational yet
eRunning, //Thread is working normally
ePausing, //Thread is requested to enter the paused state
ePaused, //Thread is paused
eTerminating //Termination has been requested but not completed yet
} eThreadStates;
class clsOpenLDVthread {
protected:
volatile eThreadStates meState;
CRITICAL_SECTION mCritControl; // critical section for thread control
char mszName[80];
HANDLE mhEvent, mhThread;
virtual bool blnStart() = 0;
public:
clsOpenLDVthread(LPCSTR pszName);
~clsOpenLDVthread();
bool inline blnIsRunning();
bool inline blnIsStopped();
bool inline blnIsStopping();
bool inline blnIsStarting();
bool inline blnIsPausing();
bool inline blnIsPaused();
bool blnPause(bool blnState);
virtual bool blnStop();
};
clsOpenLDVthread::clsOpenLDVthread(LPCSTR pszName) : meState(eIdle)
, mhThread(NULL) {
::InitializeCriticalSection(&mCritControl); //Get a critical section
//Get a unique name for signaling event
sprintf(mszName, "%s%d", pszName, ::GetCurrentProcessId());
//Get the event object
mhEvent = ::CreateEvent(NULL, FALSE, FALSE, mszName);
}
clsOpenLDVthread::~clsOpenLDVthread() {
if ( blnIsPaused() ) {
blnPause(false);
}
if ( blnIsRunning() ) {
blnStop();
}
if ( mhEvent ) {
::CloseHandle(mhEvent);
mhEvent = NULL;
}
::DeleteCriticalSection(&mCritControl);
}
bool clsOpenLDVthread::blnIsPaused() {
return meState == ePaused;
}
bool clsOpenLDVthread::blnIsPausing() {
return meState == ePausing;
}
bool clsOpenLDVthread::blnIsRunning() {
return meState == eRunning;
}
bool clsOpenLDVthread::blnIsStarting() {
return meState == eStarted;
}
bool clsOpenLDVthread::blnIsStopped() {
return meState == eIdle;
}
bool clsOpenLDVthread::blnIsStopping() {
return meState == eTerminating;
}
bool clsOpenLDVthread::blnPause(bool blnState) {
bool blnResult = mhThread != NULL;
if ( blnResult ) {
if ( blnState ) {
unsigned uintCountDown = 10u;
if ( blnIsRunning() || blnIsPausing() ) {
meState = ePausing;
while( blnIsPausing() && -- uintCountDown ) {
::SetEvent(mhEvent);
//Give thread chance to run and pause
_sleep(751);
}
blnResult = blnIsPaused();
}
} else {
if ( blnIsPaused() ) {
meState = eRunning;
//this will need replacing...mhThread->ResumeThread();
}
blnResult = true;
}
}
return blnResult;
}
bool clsOpenLDVthread::blnStop() {
bool blnResult = meState == eIdle;
unsigned uintCountDown = 100u;
if ( blnIsPaused() ) {
blnPause(false);
}
if ( blnIsRunning() ) {
meState = eTerminating;
while( !blnIsStopped() && --uintCountDown ) {
if ( mhEvent ) {
::SetEvent(mhEvent);
}
//Give thread a change to run and terminate
_sleep(501);
}
blnResult = blnIsStopped();
mhThread = NULL;
}
return blnResult;
}
Finally a derived class that implements the thread class and provides the blnStart method:
class clsOpenLDVrdr : public clsOpenLDVthread {
public:
//Maximum size of uplink data per single transfer
static const unsigned mscuBuffersize;
private:
//The thread's main routine
static void msgReaderThread(LPVOID lpParam);
public:
clsOpenLDVrdr();
virtual ~clsOpenLDVrdr();
//Call this to start the thread, see clsOpenLDVthread for more operations
virtual bool blnStart();
};
const unsigned clsOpenLDVrdr::mscuBuffersize = MAX_OPENLDV_DATA;
clsOpenLDVrdr::clsOpenLDVrdr() : clsOpenLDVthread(_T("EvOpenLDVrdr")) {
}
clsOpenLDVrdr::~clsOpenLDVrdr() {
}
bool clsOpenLDVrdr::blnStart() {
bool blnResult = false;
if ( blnIsStopped() ) {
meState = eStarted;
//Create the thread
mhThread = (HANDLE)_beginthread(&clsOpenLDVrdr::msgReaderThread
,0, NULL);
blnResult = mhThread != NULL;
while( blnResult && (meState == eStarted) ) {
//Give the thread chance to start and initialize
_sleep(501);
}
}
return blnResult && (meState == eRunning);
}
void clsOpenLDVrdr::msgReaderThread(LPVOID lpParam) {
OutputDebugString("msgReaderThread\n");
}
An instance of the class clsOpenLDVrdr is created and the blnStart method called:
clsOpenLDVrdr* pobjReader = new clsOpenLDVrdr();
pobjReader->blnStart();
I can see in the debugger that "blnStart" is being called and stepping into it everything is executed...but the thread never runs.
Also tried using _beginthreadex instead of _beginthread:
mhThread = (HANDLE)_beginthreadex(0, 0, pfnThread, pobParam, 0, 0);
No difference. There is some kind of incompatibility problem here as the simple example I created at the start of this post works and there isn't much difference between the two versions. Except maybe the way its used...the first simple example was created as a Windows console application. The project I'm having difficulty with is in a DLL.
I'm attaching to the DLL with the debugger and stepping through the code which works until it gets to the loop after the beginthread call then it just loops forever and never gets into the thread.
I just tried the following, adding a standalone thread with a standard C function:
unsigned __stdcall threadTest(void* pobjData) {
OutputDebugString("threadTest\n");
return 0;
}
I then modify the "_beginthread" call as follows:
mhThread = (HANDLE)_beginthreadex(0, 0, threadTest, pobjParam, 0, 0);
Sadly the result is the same, the threadTest function is not called. But a valid handle is returned.
Found this:
unable to call a thread in dll file
Looks interesting and may explain the strange behaviour I'm experiencing.
Solved...I didn't realise at first but for some reason the existing DLL had a call to:
DisableThreadLibraryCalls(hInstance);
This prevents the threads from running. Having commented this out everything now works.
I was viewing the file agents.h on my windows OS,and I wanted to see the c++ code without comments.i striped them out to see the code more clearly with my old program but i was surprised that it took like 2 seconds to finish.the size of the file is 605KB,so it isn't so bad.Why is it that slow.I suspect it is the function ftell() that is doing it,but i can't really tell.Is it branching that is slowing or ftell()?, if ftell(),then what is a better way to throw the FILE pointer back?
EDIT
#include <stdio.h>
#include <time.h>
#define NOT_COMMENT (!DOUBLESLASH_Comment && !ASTERISK_SLASH_Comment)
int main(int argc,char *argv[])
{
clock_t t1 = clock();
FILE *input , *output;
if( fopen_s(&input,argv[1],"r") )
{
printf("error opening file %s\n",argv[1]);
return 0;
}
if( fopen_s(&output,argv[2],"w") )
{
printf("error opening file %s\n",argv[2]);
return 0;
}
char c , d;
//escape flag
bool DOUBLESLASH_Comment = 0 , ASTERISK_SLASH_Comment = 0 , flag = 0;
/* single quotes / double quotes */
int s_QUOTED = 0 , d_QUOTED = 0;
while( (c=getc(input)) != EOF )
{
switch(c)
{
case '\\':
{
if( NOT_COMMENT )
{
if( flag == 1 )
flag = 0;
else
flag = 1;
}
}break;
case '\'':
{
if( NOT_COMMENT && !d_QUOTED )
{
if( !flag )
{
s_QUOTED++;
}
}
}break;
case '"':
{
if( NOT_COMMENT && !flag )
{
if( !s_QUOTED )
{
d_QUOTED++;
}
}
}break;
case '/':
{
if( NOT_COMMENT && !d_QUOTED )
{
if( (d=getc(input)) == '*' )
{
ASTERISK_SLASH_Comment = 1;
}
else if( d == '/' )
{
DOUBLESLASH_Comment = 1;
}
else
{
if( d != EOF )
{
ungetc(d,input);
}
}
}
}break;
case '*':
{
if( ASTERISK_SLASH_Comment )
{
if( (d=getc(input)) == '/')
{
if( (c=getc(input)) == EOF )
return 0;
ASTERISK_SLASH_Comment = 0;
}
else
{
if( d != EOF )
{
ungetc(d,input);
}
}
}
}break;
case '\n':
{
if( DOUBLESLASH_Comment )
{
DOUBLESLASH_Comment = 0;
}
}break;
}
if( NOT_COMMENT && c != '\\' ) flag = 0;
if( d_QUOTED == 2 ) d_QUOTED = 0;
if( s_QUOTED == 2 ) s_QUOTED = 0;
if( NOT_COMMENT )
{
fprintf(output,"%c",c);
}
}
fclose(input);
fclose(output);
clock_t t2 = clock();
double elapsed = (double)(t2 - t1) / CLOCKS_PER_SEC;
printf("time elapsed : %f\n",elapsed);
}
Without actually measuring the speed of your code in a profiler (and with the file you use as input, since one I use may have a different set of comments, etc that trigger a different behaviour), it's hard to say for sure. But it looks like you use fseek( ... ) simply to move back one character. In which case writing your own function for a one character lookahead would be a much better choice.
Something like this:
char lookahead = ' ';
bool havelookahead = false;
char getNextChar(FILE *input)
{
if (havelookahead)
{
havelookahead = false;
return lookahead;
}
return getc(input);
}
char peekChar(FILE *input)
{
if (!havelookahead)
{
lookahead = getc(input);
havelookahead = true;
}
return lookahead;
}
Then replace your getc with getNextChar in the beginning of the loop, and where you check the next character with peekChar (followed by a dummy getNextChar() to consume it).
This is a useful pattern in general for parsing - both at character level and at token level, so it's good learning to understand how this works.
You can also use the standard ungetc to "put back" your character that you looked at.
Whether this makes your code run significantly faster or not is hard to say, as I said in the beginning.
I cannot compile your code, so I cannot make tests. But I suspect that the bottleneck is fseek rather than ftell. Rejecting a character is a common task in parsing files... and should be implemented by the library or some intermediate layer with some buffering. In this case (rejection of a single character) you can use ungetc to achieve that.
So you should replace
fseek( file , ( ftell(file) - 1 ) , SEEK_SET );
with
ungetc('*', file); // ungetc('/', file); the second time.
I know this question has answers in stackoverflow, but still i can't resolv my problem, I don't see the error. I'm using vector and I think I'm using it correctly, I'm not doing any free or malloc/calloc or something. However, I'm sure the problem comes with vector, doing something wrong.
The most strange part is debbuging the program, it ocurrs in two or three differents sites.
I compile the code with SDL2 and the default gcc on linux. I'm using Netbeans, using the command
g++ -std=c++11 -g -Wall -c -g -MMD -MP -MF "path/src/game/Game.o.d" -o path/src/game/Game.o src/game/Game.cpp
and linking with -lSDL2 -lSDL2_image
The error, one of this
malloc(): memory corruption (fast): 0x0000000000d86d50 ***
corrupted double-linked list: 0x00000000013fb5d0 ***
or less usual: [link][1]
Valgrind show something like this but I don't know how to use it: [link][2]
I put here the most important code, but I leave you the complete project to see if you want. Hope you can help me. I'm not sure if I'm doing something wrong or the problem come on other way.
[Link to project][3]
Main.cpp
#include ... //some includes
using namespace std;
Shape* shape;
TableBoard board;
Square* square;
Command* command;
void keyDown(SDL_Event &evento) {
if (evento.type == SDL_KEYDOWN) {
SDL_Keycode key = evento.key.keysym.sym;
command = nullptr;
switch (key) {
case SDLK_LEFT:
command = new LeftRight(board, *shape, Direction::LEFT);
shape->addCommand(command);
break;
case SDLK_RIGHT:
command = new LeftRight(board, *shape, Direction::RIGHT);
shape->addCommand(command);
break;
case SDLK_DOWN:
command = new FallToGround(board, *shape);
shape->addCommand(command);
break;
case SDLK_ESCAPE:
exit(0);
}
}
}
void newShape() {
if (shape == nullptr || !shape->isCanFall()) {
shape = new LShape(*square);
board.addShape(shape);
shape->setCanFall(true);
Command* command = new Fall(board, *shape);
shape->addCommand(command);
}
}
int main(int argc, char** argv) {
Window pantalla;
SDL_Event evento;
board = TableBoard(pantalla.getWindow(), 20, 10);
Board meassureBoard = board.getMeassureBoard();
SDL_Texture* image = IMG_LoadTexture(pantalla.getPantalla(),
"resources/images/blue_bold.png");
//creo una celda, le paso datos de table y que él se pinte
square = new Square();
square = new Square();
square->setGraphics(meassureBoard, image);
square->setX(3);
square->setY(1);
bool letsQuit = false;
Timer timer{};
timer.start();
newShape();
while (!letsQuit) {
pantalla.clear();
shape->executeCommands();
shape->clearCommandsFinished();
board.paint(pantalla.getPantalla());
board.drawLines(pantalla.getPantalla());
pantalla.actualizar();
while (SDL_PollEvent(&evento)) {
if (evento.type == SDL_QUIT) { // Si es de salida
letsQuit = true;
} else {
keyDown(evento);
}
}
newShape();
if (timer.delta() < 16) {
SDL_Delay(16 - timer.delta());
}
timer.restart();
}
return 0;
}
Part of Shape (parent class of LShape)
void Shape::executeCommands() {
for(vector<Command*>::iterator it = commands.begin(); it != commands.end(); ++it) {
(*it)->execute();
}
}
void Shape::clearCommandsFinished() {
vector<int> remove;
int index=0;
for(vector<Command*>::iterator it = commands.begin(); it != commands.end(); ++it) {
if ((*it)->isAlive() != true) {
remove.push_back(index);
}
index++;
}
for(vector<int>::iterator it = remove.begin(); it != remove.end(); ++it) {
commands.erase(commands.begin()+(*it));
}
}
Part of command Fall, left and right is similar. Here gives the error
void Fall::execute() {
if (isAlive() && timer.delta() >= milisecondsFalling) {
timer.restart();
bool canMove = true;
vector<Square> squares = shape->nextMove(0, 1);
if (shape->isCanFall()) {
int number=shape->getNUMBER_OF_SQUARES();
for (int i = 0; i < number && canMove; i++) {
//check the range
if (squares[i].getX() < 0
|| squares[i].getX() > board.getNumberColumns() - 1
|| squares[i].getY() < 0
|| squares[i].getY() > board.getNumberRows() - 1) {
canMove = false;
} else {
if (board.isFilled(shape, squares[i])) {
canMove = false;
}
}
}
//if we can move, move it definitively
if (canMove) {
shape->move(0, 1);
board.updateBoard();
}else{
shape->setCanFall(false);
}
} else {
alive = false;
} //-> AT THIS EXACTLY MOMENT GIVE THE ERROR!! NOT AFTER, NOT BEFORE
}
}
Not important, but gives error here too. Parts of the window class
void Window::actualizar() {
// Mostramos la pantalla
SDL_RenderPresent(renderer); //EXACTLY POINT WHERE THROW THE ERROR, less frecuent
}
void Window::inicializacion() {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
cout << "No se pudo iniciar SDL: " << SDL_GetError() << endl;
exit(1);
}
atexit(SDL_Quit);
pantalla = SDL_CreateWindow("Tetris", //CREATED AS PRIVATE IN HEADER INSIDE CLASS: SDL_Window *pantalla;
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
window.w, window.h,
0);
renderer = SDL_CreateRenderer(pantalla, -1, SDL_RENDERER_ACCELERATED);
this->clear();
if (pantalla == NULL) {
cout << "Error iniciando el entorno gráfico: " << SDL_GetError() << endl;
exit(1);
}
this->pantalla=pantalla;
}
Window::Window() {
window.w=1024;
window.h= 768;
inicializacion();
}
Edit: links deleted. Problem solved
I'm not going to debug this entire thing (which would be utterly non productive for either of us). I took a brief look at your source base, and spotted this:
vector<Square> Shape::nextMove(int x, int y)
{
//make a copy to not really moving the squares
vector<Square> clone(numberSquares);
for (int i = 0; i <= numberSquares; i++) { // <<=== HERE
clone[i] = *(new Square(squares[i]));
}
//get the next move
moveShape(clone, x, y);
//return the modified squares
return clone;
}
That <= is indexing one-past the size of your source and destination vectors, which is BAD. Making matters worse, the code within the for-loop is a blatant memory leak. The entire function should be reduced to this:
vector<Square> Shape::nextMove(int x, int y)
{
vector<Square> clone = squares;
moveShape(clone, x, y);
return clone;
}
Best of luck
I am trying to make a custom app library with SDL as apart of an academic project, and I ran into an issue..
Basically, everything works fine, it compiles, does what I expect it to do, but... its extremely slow, the first element is reacting quite quickly, other elements within the set are completely unresponsive (i need to click them 20 times for the to react, they work just slow)
Below the function that draws the elements from a vector type container, the return 1 means that the handle function ran into an unexpected error or the user X'ed out the window.
Any advice on how to make this react faster?
void StoreDraw::setCamera(size_t input)
{
rectangle.x = containerArray[input].elementLocX;
rectangle.y = containerArray[input].elementLocY;
rectangle.h = containerArray[input].elementPicture->h;
rectangle.w = containerArray[input].elementPicture->w;
}
bool StoreDraw::vectorDraw()
{
/* Draw FloatingElements */
for(size_t i = 0; i < containerArray.size(); i++)
{
if(SDL_PollEvent(&event))//containerArray[i].event
{
if(event.type == SDL_MOUSEBUTTONDOWN)
{
if(event.button.button == SDL_BUTTON_LEFT)
{
locationX = event.button.x;
locationY = event.button.y;
printf("X:%d\tY:%d\n", locationX, locationY);
if(!containerArray[i].handleEvent(locationX, locationY)){drawEnvironment();}
}
}
if(event.type == SDL_QUIT)
{
return 1;
}
}
}
SDL_Flip(screen);
return 0;
}
bool StoreDraw::drawEnvironment()
{
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0,0,0));
SDL_BlitSurface(background, NULL, screen, NULL);
for(size_t i = 0; i < containerArray.size(); i++)
{
setCamera(i);
SDL_BlitSurface(containerArray[i].elementPicture, NULL, screen, &rectangle);
}
SDL_Flip(screen);
}
bool FloatingElement::handleEvent(int x, int y)
{
printf("Object responding.\n");
if((x > elementLocX) && (x < (elementLocX + (elementPicture->w))) && (y > elementLocY) && (y < (elementLocY + (elementPicture->h))))
{
x = (x - (elementPicture->w)/2);
y = (y - (elementPicture->h)/2);
setLocation(x,y);
printf("Object responding.\n");
return 0;
}
return 1;
}
As far as I can see, the problem is how frequently you are checking for events. When you call vectorDraw() it polls the events and acts as intended, but the events eventually end and the function returns. I think there should be a main loop in the code that always checks for events and calls functions when necessary, while vectorDraw() only checks the location of a click and calls the handleEvent() of the container array.
Edit:
I think I found the problem. This is how you're doing now:
bool StoreDraw::vectorDraw()
{
/* Draw FloatingElements */
for(size_t i = 0; i < containerArray.size(); i++)
{
if(SDL_PollEvent(&event))//containerArray[i].event
{
if(event.type == SDL_MOUSEBUTTONDOWN)
{
if(event.button.button == SDL_BUTTON_LEFT)
{
// Check Events
}
}
if(event.type == SDL_QUIT)
{
return 1;
}
}
}
SDL_Flip(screen);
return 0;
}
int main() {
while( ::quit == false ) {
while(SDL_PollEvent(&event) == 1) {
if( event.type != SDL_QUIT ) {
if( event.type == SDL_MOUSEBUTTONDOWN) {
storeDraw::vectorDraw();
}
} else {
quit = true;
break;
}
}
}
}
}
So, what is happening:
After the main loop polls the event, it calls vectorDraw() and vectorDraw() polls events again. By doing so, vectorDraw() doesn't get the information of the click it called, as it was already polled in the main loop. Without the information, it doesn't act upon it.
So, in order to solve the problem, you can change the functions to be somewhat like this:
bool StoreDraw::vectorDraw(SDL_Event event)
{
/* Draw FloatingElements */
for(size_t i = 0; i < containerArray.size(); i++)
{
// Check Events
}
SDL_Flip(screen);
return 0;
}
int main() {
while( ::quit == false ) {
while(SDL_PollEvent(&event) == 1) {
if( event.type != SDL_QUIT ) {
if( event.type == SDL_MOUSEBUTTONDOWN) {
if(event.button.button == SDL_BUTTON_LEFT)
{
storeDraw::vectorDraw(event);
}
}
} else {
quit = true;
break;
}
}
}
}
}
Now, only the main loop polls events and acts on them if possible. And vectorDraw() doesn't poll them anymore, only acts upon them if they meet it's criteria (left mouse button down, in this case). Now the event checking should act as intended.
const int jumpHeight = 10;
//Non-Const variables
bool running = true;
bool isJumping = false;
bool isFalling = false;
int jump = 0;
Uint8 *keystate = NULL;
//Structs
typedef struct entity {
SDL_Rect hitbox;
} playerType, enemyType;
playerType player;
enemyType basicEnemy[10];
//Main Function
int main( int argc, char* argv[] )
{
while( running )
{
keystate = SDL_GetKeyState(NULL);
if( keystate[SDLK_UP] )
{
if(isJumping != true)
{
isJumping = true;
}
}
if( keystate[SDLK_LEFT] ) player.hitbox.x -= 1;
if( keystate[SDLK_RIGHT] ) player.hitbox.y += 1;
//Window collision
if( player.hitbox.x < 0 ) {player.hitbox.x = 0;}
else if( player.hitbox.x > SCREEN_WIDTH - player.hitbox.w ) {player.hitbox.x = SCREEN_WIDTH - player.hitbox.w;}
if( player.hitbox.y < 0 ) {player.hitbox.y = 0;}
else if( player.hitbox.y > SCREEN_HEIGHT - player.hitbox.h ) {player.hitbox.y = SCREEN_HEIGHT - player.hitbox.h;}
//Jumping
if( isJumping == true )
{
if( jump >= jumpHeight || isFalling == true )
{
jump--;
player.hitbox.y--;
isFalling = true;
}else if( jump <= 0 && isFalling == true )
{
jump - 0;
isFalling = false;
isJumping = false;
}else {
jump++;
player.hitbox.y++;
}
}
}
}
This is my current code in my game (the parts related to jumping anyway). When I press the Up key my character goes to the top of the window and stays there. Where have I gone wrong?
I compile with g++ -o myprogram.exe mysource.cpp -lmingw32 -lSDLmain -lSDL -lSDL_image -static-libgcc -static-libstdc++.
Walking you through how the code is supposed to work:
Press Up: isJumping becomes true, and then the player is raised to the max height, then goes down again to where it started (later I will add collision checking)
He's going to the top of the window because of this code here:
if (jump >= jumpHeight || isFalling == true) {
jump--;
player.hitbox.y--;
isFalling = true;
}
Once this condition has been met, it will run for the rest of the loop and the conditions will never be false. To fix it, you need to check if jump is 0 after you decrement it. If it's 0, set isFalling to false and isJumping to false.
Also, do note that when you increase the y, you're making the unit go lower on the window because SDL windows have origins starting from the top left corner and the Y axis is downward.
Replace all increments of y with decrements and vice versa.