Collision with a box while jumping....please help


#1

Hi guys, I have a bit of problems with collisions while jumping,

When the Player jumps on the box it acts weird because while staying on top of the box it keeps going up and down, and I can see that Player jump velocity keeps increasing (so it goes down) and decreasing (so it goes up) and also gravity does the same.

No idea how to fix it, if you can help me it will be highly appreciated.

I have copied the important bits of the code.

Many thanks.

Summary

struct SPlayer
{
void Move();
void ApplyBoxCollision();
float Width = 100.0f;
float Height = 100.0f;
float XPosition = (WINDOW_WIDTH * 0.5f) - (Width * 0.5f); //center of the screen
float YPosition = 362;//top of the player
float YDesiredPosition = 362; //Player DesiredStart Position on Y axis (it updates every time Player.Yposition changes). So if I press S to jump at the very beginning of the program coming down the player will go to start position
float XDesiredPosition = 0;
float XPrevDesiredPosition = 0;
float YPrevDesiredPosition = 0;
float XVelocity = 160.0f;
float YVelocity = 160.0f;
float JumpVelocity = -422.0f;
float Gravity = 0;
EPlayerState State = PLAYER_STILL;
SDL_Texture* playerTexturewr = nullptr;
SDL_Texture* playerTexturewl = nullptr;
SDL_Texture* playerTexturejr = nullptr;
SDL_Texture* playerTexturejl = nullptr;
SDL_Texture* playerTextureclimb = nullptr;
SDL_Rect Quad;

};

Summary

void HandleEvents(void)

{
…

            case SDLK_s:
            {
                if (Player.OnLadder == false) //Player can jump only if not on ladder
                    
                {
                    
                    keyS_Down = 1;//key down (it means we are pressing S)
                    keyS_Up = 0;//(Releasing S is disabled)
                    
                    
                    if (spritestill == 2) //was set to 2 when right key is pressed
                    {
                        Player.State = PLAYER_JUMP_RIGHT;
                        
                    }
                    
                    if (spritestill == 1) //was set to 1 when left key is pressed
                        Player.State = PLAYER_JUMP_LEFT;
                    
                    if (Player.State == PLAYER_STILL)
                    {
                        Player.State = PLAYER_JUMP_RIGHT;
                        
                    }
                    
                }
                break;
            }
                
           ......
    
    else if( Event.type == SDL_KEYUP && Event.key.repeat == 0 )
        
    {
       ....
                
           
            case SDLK_s:
            {
               
                    keyS_Down = 1; //important: so player keeps jumping also when released (until it jump before being affected by gravity)
                }
                break;
            }
Summary

void SPlayer::Move()
{
switch (Player.State)
{

    case PLAYER_MOVING_LEFT:
        //converting double DeltaTime in float
        Player.XPosition += -Player.XVelocity*(float)DeltaTime;
        break;
        
        
    case PLAYER_MOVING_RIGHT:
        
        Player.XPosition += Player.XVelocity * (float)DeltaTime;
        break;
        
        
    case PLAYER_MOVING_UP:
       
            Player.YPosition += -Player.YVelocity * (float)DeltaTime;
            break;
       
        
    case PLAYER_MOVING_DOWN:
            Player.YPosition += +Player.YVelocity * (float)DeltaTime;
            break;
        }
        
    default:
        break;
}

}

Summary

void Update(void) {

HandleEvents(); //check events every time we update…

// Calculate the deltatime every time we update....
NewTime        = SDL_GetTicks(); //time in msecs running since this call
DeltaTime    = (NewTime - OldTime) / 1000.0; //convert msecs in seconds
OldTime        = NewTime;.....

…

if(keyS_Down == 1 ) //it means is true that I pressed S (the jump key)
{

    Player.Gravity = 1022.0f;
    Player.JumpVelocity = Player.JumpVelocity += Player.Gravity * (float)DeltaTime;
    Player.YPosition += Player.JumpVelocity * (float)DeltaTime;
    
     
    if (Player.YPosition >= Player.YDesiredPosition)
    {
        Player.Gravity = 0;
        Player.JumpVelocity = -422.0f;
        Player.YPosition = Player.YDesiredPosition; 

/* every time the player gets down it is set to the current YDesiredPosition that is updated every time except when jumping*/
keyS_Down = 0;
Player.State = PLAYER_STILL;
}

}

if (keyS_Down && keyL_Down)
{
    Player.State = PLAYER_JUMP_LEFT;
    Player.XPosition -= 2.5f; //jump on the left
    
}


if (keyS_Down && keyR_Down)
{
    Player.State = PLAYER_JUMP_RIGHT;
    Player.XPosition += 2.5f; //jump on the right
    
}


Player.ApplyBoxCollision();
Summary

void SPlayer::ApplyBoxCollision()
{

for( int i = 0; i<2; i++)
   if ((QuadVsQuad(Player.Quad, Block[i].Quad) == true))
{
    blockCollision = 1;
   
    Player.XPrevDesiredPosition = Player.XDesiredPosition;
    Player.YPrevDesiredPosition = Player.YDesiredPosition;
    
    
    //move back if we have collisions
    switch (Player.State)
    {
        case PLAYER_MOVING_LEFT:
            Player.XPosition += +Player.XVelocity*(float)DeltaTime;
            break;
            
        case PLAYER_MOVING_RIGHT:
            Player.XPosition += -Player.XVelocity * (float)DeltaTime;
            break;
            
        case PLAYER_MOVING_UP:
            Player.YPosition += +Player.YVelocity * (float)DeltaTime;
            break;
            
        case PLAYER_MOVING_DOWN:
            Player.YPosition += -Player.YVelocity * (float)DeltaTime;
            break;
            
        case PLAYER_JUMP_RIGHT:
            Player.YPosition = Player.YPosition -50; //to get on top of the box
            Player.Gravity = 0;
            Player.JumpVelocity = 0;
            KeyD_Down = 0;
            break;
        
        case PLAYER_JUMP_LEFT:
            Player.YPosition = Player.YPosition - 50; // top get on top of the box
            Player.Gravity = 0;
            Player.JumpVelocity = 0;
            break;
        default:
            break;
    }
    
    //update player quad after collision
    Player.Quad = {static_cast<int>(Player.XPosition), static_cast<int>(Player.YPosition) , static_cast<int>(Player.Width), static_cast<int>(Player.Height)};
    
}
else
    blockCollision = 0;

}


#2

Hi there!

Do you mind compiling an executable file that I can execute and see the error that’s occurring?
Upload the executable (and needed textures and other files) to a dropbox, github or similar.

Also, do you have a github or similar where your complete code can be viewed? It’s very hard to read your code in this thread, because of incorrect padding etc.


#3

Hi Naith,

Thanks for getting back to me!

I do not have a github so I have uploaded the full project here:
It’s only a main.cpp and few textures, being on Mac I think is the easiest way:
Please let me know if you need anything else.

http://s000.tinyupload.com/?file_id=92063577363443914594

The problem at the moments are collisions with boxes (the player cannot walk on top of them because the player keeps jumping), and also when player climbs up the ladder sometimes it works and sometimes is not working properly. Also still need to find out how to efficiently implement the floor, I mean is working but no idea if is the right way in case I need to climb a ladder (like the one i added in the code) and get to the upper floor.

On top of the second screen not visible there is a background “bg3up.png”, I’d like to implement something like ScrollingUp and ScrollingDown while player is reaching a DistanceToWindowEdge in the same way your implementation of the horizontal scrolling is working, I tried in the past but did not work, if you have any tips for that as well please let me know.

Many thanks again, I really appreciate your help!
Any suggestions are more than welcome :slight_smile:


#4

Sorry but there’s too much of a mess in your code at the moment, so I’m afraid I won’t be able to help you in this case.

You really need to split up your code into separate classes and source files (*.h and corresponding *.cpp). As of now, there’s too much code to have in a single source file, since you have multiple classes in the same file etc. As the code grows larger and larger in your single source file, it will get harder and harder to maintain the code and keep control of it.

If you make yourself a small framework, you’ll be able to use that framework for the next game you’re developing and don’t have to write the same code all over again.
Start with creating a window class which creates the SDL_Window and the SDL_Renderer for you.
When that’s finished and works properly, start creating a texture class, which holds an SDL_Texture, some variables containing the texture size, a variable containing the blend mode etc.
When that is finished and works properly, maybe create an input handler class, which handles input from the keyboard and the mouse etc.
After that, create a game class, which initiates/creates all the above classes and handle those. So in your game class, that’s where your specific game will get created/constructed and where your game data (textures, quads, fonts etc) is being created and handled.
Finally, in your main.cpp, create the game class, which gets updated and rendered by your main.cpp.

By structuring your code like this, it will get easier to extend your code and you’ll also have much more control over all the different parts of your code/framework.

About the game you’re currently making; when you’re finished creating your small framework above, and you are about to start developing the game, you really should look up a concept called tiling. Since you want your game character to be able to walk on boxes, climb ladders etc, I assume your level will consist of multiple boxes and stuff, and I therefore think you should use tiling when creating your level.
There’s a good tutorial on Lazyfoo’s website which should give you enough information to creating your tile level. http://lazyfoo.net/tutorials/SDL/39_tiling/index.php


#5

I had some time free so I actually created a small game framework for you, which you can use when you want to create a game. Create a new project on your computer (with Visual Studio or whatever you’re using) and then copy the source files into your project.
Go through the files and make sure that you understand everything. If there’s something you need explained, just ask and I will try to explain further.

I have added some example code for using the texture class and input handler class. I have also added some comments explaining how to structure your code (where to create stuff, where to destroy stuff etc).

The source files can be downloaded from here: https://www.dropbox.com/sh/wcxohky81hkhgdl/AADFitbKrx8XVJZ2rHYV8Aksa?dl=0

Enjoy :smiley:


#6

Hi Naith,

Thank you very much for your tips and you are totally right about splitting the code, that’s something I need to do!

Code is growing and getting messy and I need to learn how to organise it in a clear way, never found that in c++ books so any suggestion or tutorial is welcome.

Did you manage to run the program?

Few questions, being a beginner they might be a bit naive :slight_smile:

About tiles: I read that chapter while I was studying sdl2 and is very interesting but still not sure if I can achieve the same without using them, I mean: Are tiles crucial for a 2d platform?

Also: I noticed that you used struct instead of classes, is there a particular reason when it comes to game development?

About the collision with box : the important bits of the code are the ones at the top of this topic, by looking only at that small part do you maybe know why player keeps jumping while colliding with the box?

Many thanks again Naith!


#7

Many thanks mate, you are the best!

I wrote that reply before checking your new reply.

I will have a look at it and let you know tomorrow or the day after because I am away atm.

Many thanks again. :wink::+1:


#8

No worries. I think you’ll find it being easier to structure your code with the help of the framework.

Regarding your questions:

  1. In my opinion, tiles are crucial when it comes to 2D platformers, since it makes it easy to do collision detection against ground and other objects, since the ground etc are (usually) boxes and box vs box-collision is easy and fast (performance wise).

  2. I use structs when I want to collect some data about an object (for example a texture, the texture’s size etc) and don’t planning on having any functions for that data. If I need to have some data and some functions for it, I use a class instead. So yeah, I only use a struct when I need a container for data and when functions are needed, I use a class.
    In the end it’s just a matter of personal taste, since you can use functions inside a struct aswell, since a struct is just a class but with public member variables and functions, which of course can be made private, protected etc, just like a class.

  3. At first, when I build your code and executed it, I didn’t understand what you meant by the jumping, since no jumping was occuring. I then realized that the issue occur when colliding with a box from the side(s) and the reason the issue occur I think has to do with the velocity not being set to 0 or something. When the player box collides with another box, the player box should be moved back to a position where it’s not colliding anymore and the player velocity should be set to 0.


#9

Hi Naith, thanks for the answers, it makes sense!

About the number 3, I meant this: (i took a video, you perform jumping by pressing S).

As you can see, it keeps jumping while on top of the boxes…


#10

Oh, I see now. That got to be something with how much you’re moving the player box back (in height) when collision occurs.

I don’t know if you’ve already downloaded the framework code but I added some code so you should re-download it if you downloaded it earlier.


#11

I move Player up of 50.0f (by subtracting 50 from its current position), so It can be on top of the box, but still no idea why it keeps jumping:

Summary

void SPlayer::ApplyBoxCollision()
{

for( int i = 0; i<2; i++)
if ((QuadVsQuad(Player.Quad, Block[i].Quad) == true))
{
blockCollision = 1;

Player.XPrevDesiredPosition = Player.XDesiredPosition;
Player.YPrevDesiredPosition = Player.YDesiredPosition;


//move back if we have collisions
switch (Player.State)
{
    case PLAYER_MOVING_LEFT:
        Player.XPosition += +Player.XVelocity*(float)DeltaTime;
        break;
        
    case PLAYER_MOVING_RIGHT:
        Player.XPosition += -Player.XVelocity * (float)DeltaTime;
        break;
        
    case PLAYER_MOVING_UP:
        Player.YPosition += +Player.YVelocity * (float)DeltaTime;
        break;
        
    case PLAYER_MOVING_DOWN:
        Player.YPosition += -Player.YVelocity * (float)DeltaTime;
        break;
        
    case PLAYER_JUMP_RIGHT:
        Player.YPosition = Player.YPosition -50; //to get on top of the box
        Player.Gravity = 0;
        Player.JumpVelocity = 0;
        KeyD_Down = 0;
        break;
    
    case PLAYER_JUMP_LEFT:
        Player.YPosition = Player.YPosition - 50; // top get on top of the box
        Player.Gravity = 0;
        Player.JumpVelocity = 0;
        break;
    default:
        break;
}

//update player quad after collision
Player.Quad = {static_cast<int>(Player.XPosition), static_cast<int>(Player.YPosition) , static_cast<int>(Player.Width), static_cast<int>(Player.Height)};

}
else
blockCollision = 0;
}

Many thanks, redownloading it now! :slight_smile:


#12

Hi Thinker!

I downloaded your code in a coffee-break. I set up a makefile and it builds with a few warnings, but…
My SDL2_image won’t load your assets.

file climb.png 
climb.png: Adobe Photoshop Image, 128 x 64, RGBA, 4x 8-bit channels

So this doesn’t look like a valid png to me. It’s some layered stuff which could bring issues.

Could you be so kind and seprate source assets from the assets that are actually used in your game?
Maybe it is a good time to tinker with github =)

Regarding to your problem:
I do game-“objects” like a player also in a struct.
Since I scale on different sizes and devices, I use floats and doubles (depends on CPU) to keep track of stuff. But if it comes to intersection I use the SDL_Rect like:
SDL_HasIntersection(&player.dst, &ground.dst);

struct vec2{
	float x;
	float y;
};

struct rect{
	struct vec2 pos;
	struct vec2 size;
};

struct area_dyn{
	SDL_Texture *Texture;
	SDL_Rect dst;
	SDL_Rect src;
	struct rect rect_d;
	float speed_velc;	//current (scaled) velocity
	float speed_velr;	//ref velocity
	float speed_cur;
	float speed_ref;
	float angle;
};

Hope this helps. I mean ofc since you are on C++ you may setup a class, but my point is, I do the math on floats with fraction but the testing with ints (SDL_Rect). Just don’t forget to round and update the dst-rect if you touched position or size from your floats.

s_entity->dst.y=roundf(s_entity->rect_d.position.y);

void player_move_up(void)
{
    player.rect_d.position.y+=player.speed_cur*dt;
    //some other nasty stuff
    player.dst.y=roundf(player.rect_d.position.y);
}

Hope this helps,
-Cass aka Acry


#13

Thanks folks!

Sorry for the delay, I am away for work and I will be back home tomorrow night and finally check everything you wrote to help me and share my thoughts.

Many many thanks again! :slight_smile:


#14

Hi Acry,

Just back yesterday from a work trip, so finally I have access to my computer and Xcode, not the company one!

About the png:

You are right, I checked the hexes and the png file signature was a psd!

I fixed that png and I have uploaded a new version of the game here:

http://s000.tinyupload.com/index.php?file_id=07023750129261943350

Let me know if you have problems in compiling it

-Could you be so kind and seprate source assets from the assets that are actually used in your game?
Maybe it is a good time to tinker with github =)

I have an account but never used, so yes I should give it a go, what do you mean with separate source assets from the ones used in the game?

Tried now to fix the jumping, following your suggestion and the ones of Naith but still no luck, I need to start implementing tiles collisions like Naith suggested and reorganise the code.

Going now through the SDL Framework Naith sent me, looks great now let;s see if I can fully understand how to use it.

Many thanks folks


#15

Alright I was able to build, run and test this time.
There were still a few non png files in there. Dunno why you can run that.
In
CreateTexture()
I added the parameter rpath in the error check to figure out which files are not working
std::cout << "Failed to create SDL surface. " << rPath << " " << IMG_GetError() << std::endl;

I am pretty sure you don’t need:
SDL_SetColorKey()
there, cause your using png that supports alpha transparency.

What I mean by saying seperate your source-assets is:

  • Have a folder for the assets //Those are used in game and only those.
  • Have a folder for source-assets //Like psd files, those need exports or other things done in order to be used in the program
  • Have a folder for concept Art //Ideas which may be implemented and used in game
  • Have a folder for logic sketches //sketches to understand physics like collision

Above is to make things easier, to avoid the mess.

In general it is always a good idea to seprate sources from builds, not that important anymore since we have Version Control Systems (VCS) nowadays, but still - good practice.

In the code it looks similar to this:

Background[0].pTexture = CreateTexture("./assets/bg.png");
Background[1].pTexture = CreateTexture("./assets/bg2.png");
Background[2].pTexture = CreateTexture("./assets/bg3.png");
Background[3].pTexture = CreateTexture("./assets/bg4.png");
Background[4].pTexture = CreateTexture("./assets/bg5.png");
Background[5].pTexture = CreateTexture("./assets/bg3up.png");

Do all error checks for surface and textures in the CreateTexture-function.
if(!Background[0].pTexture) return false;

so create() becomes load and then you can make an init or set function to define stuff like:

gSpriteClipswr[ 0 ].w = 64;
what you stuffed in in the else-statement.

Fix your warnings =)

Player.JumpVelocity = Player.JumpVelocity += Player.Gravity * (float)DeltaTime;

See what is wrong there?

If you want to fix unused main parameter just void cast those:

(void)argc;
(void)argv;

Your case checks based on switch are quite messy.
Check: http://en.cppreference.com/w/cpp/language/switch
Too many curly brackets there, plus some redundant checks.

IMO you should not look into any engine yet, way too early. Your Code became already quite huge and complex. You should check a few platformer tutorials and set up a way easier testbed.

2018-04-15-115531_548x274_scrot

Fix your physics first, like gravity and velocity, then collisions.

In ApplyBoxCollision()

//Test collison against all boxes
for( int i = 0; i<2; i++){
   if ((QuadVsQuad(Player.Quad, Block[i].Quad) == true))
  blockCollision = 1;
}

You can simply return if there was no collision.

if (blockCollision == 0)
  return;

Or, even better, call collision handler, cause you test and apply if in this function.
if ((QuadVsQuad(Player.Quad, Block[i].Quad) == true))

  handleCollision(i) ;

Your code acts correct, you have collision with a box all the time, if you are on a box.
I know it’s not intended.

Sorry that I dont have a 4 lines solution for you to fix your code, but hope my efforts will help in the future.
I am not good in C++ and don’t want to be either.

If I have more time today I set up such testbed as described in my sketch.

Regards Cass.


#16

/Thanks -pretty sure you don’t need:
SDL_SetColorKey()
there, cause your using png that supports alpha transparency.
/

That’s correct, I noticed that as well :wink:

About the assets:

Everything needs to be reorganised, I totally agree with you on that.

About the warning fixes: Could you clarify what is wrong?

I am 99.9% sure the way I have implemented Jumping and the If condition check with YDesiredPosition when Player is descending from that jumping has something wrong.
Probably is that bit that does not let the player stay on boxes after collision (indeed it keeps jumping).
I still need to understand how to fix it though.
JumpVelocity, Gravity, Delta: seems to me I cannot stop them completely when Player collides with the boxes! :confused:

if (Player.YPosition >= Player.YDesiredPosition)

  • Game Engine

My intention is to build a useful framework not an engine because I still lack the experience to develop one.
Naith gave me a great example to start with, the code is very well organised and flexible, it takes care of all the initialisation through pointers and destruction of resources as well, still need to figure out how to implement everything from my actual part of the code but I’m learning a lot by reading that! Thanks again Naith!

-Int blockCollosion

I noticed that it works only for box 1 and not for box 0,
No idea why…, need to fix it, but you are right is really messy and it’s better with a collision handler!

Thank you for your help, still need to find out how to fix that collisions with boxes so the player can move on top and fall down after the collision but I guess the solution is near.