EDIT: Please, if you’ve been here without being able to solve this, or don’t want to because it’s too long or my code is horrible to look at, please say so! Try to at least leave something I can use, even if you haven’t found the philosophers stone 8)
Hey guys.
I’m writing a sidescroller with JumpingJack from KGPJ as reference.
I’m stuck with two types of collisions:
- Jumping, and hitting your head against something.
- Falling, and stopping when hitting ground below you. (this one works, but I think
the way I’m doing it is wrong - you’ll see what I mean).
I’ll just go over the structure of this, so you know enough to consider the problem.
Think of Mario. My world is made of bricks in the same way as Mario. You walk around on
these. The blocks are stored in an ArrayList[column] array.
In each of these ArrayLists are the blocks found in that columns, but in no order.
A block has it’s own class, and instance where it’s x-World-coord (I’ll explain this!),
and it’s y-coord (that is just the y-coord on screen (the coordinate system used
when rendering stuff)), because the world will only scroll with the x-axis.
The world has it’s own set of pixel-coordinates, but this is not important right now as
the world doesn’t scroll so they are equal to the on-screen-coordinates.
Here’s the problem:
When falling, the sprite has an increasing speed, so it might move with more than 1 pixel per update.
I need to do a check, if the sprite will land inside a block in the next planned move.
If it will, I need to calculate how long it WILL travel, so it will land on it’s feet on top of the block.
The same basicly applies to jumping.
I got a working method for checking if a coordinate is inside a block.
Here’s the solution provided in KGPJ for JumpingJack:
public int checkBrickTop(int xWorld, int yWorld, int step)
/* The sprite is moving downwards. It checks its next position
(xWorld, yWorld) to see if it will enter a brick from above.
If it does, then its step value is reduced to smallStep
so it will only drop enough to touch the top of the brick.
*/
{
if (insideBrick(xWorld, yWorld)) {
int yMapWorld = yWorld - (pHeight - height);
int mapY = (int) (yMapWorld / Constants.brickHeight); // map y- index
int topOffset = yMapWorld - (mapY * Constants.brickHeight);
int smallStep = step - topOffset;
// System.out.println("top smallStep: " + smallStep);
return smallStep;
}
return step; // no change
} // end of checkBrickTop()
I changed it a little bit to match my own game, but the logic is the same.
This works as intended (falling, and the method above).
Now, when jumping and moving upwards I should be able to use almost the same method right?
This is the one rewritten from JumpingJack, to match my game just as the above method.
public int checkBrickBase(int xWorld, int yWorld, int step)
/* The sprite is moving upwards. It checks its next position
(xWorld, yWorld) to see if it will enter a brick from below.
If it does, then its step value is reduced to smallStep
so it will only rise to touch the base of the brick.*/
{
if (insideBrick(xWorld, yWorld)) {
int yMapWorld = yWorld - (pHeight - height);
int mapY = (int) (yMapWorld / Constants.brickHeight); // map y- index
int topOffset = yMapWorld - (mapY * Constants.brickHeight);
int smallStep = step - (Constants.brickHeight - topOffset);
// System.out.println("base smallStep: " + smallStep);*/
return smallStep;//smallStep;
}
return step; // no change
} // end of checkBrickBase()
This one however does not work. Depending on how, and when I’m calling this I get different results
- all wrong (not stopping the jump when hitting as it should).
This makes me think that either both these methods are wrong, or my updating of the jumping.
Here is how I use the methods:
public void update(int delta) {
if (isMovingRight) {
xWorld += moveSize;
locX += moveSize;
} else if (isMovingLeft) {
xWorld -= moveSize;
locX -= moveSize;
}
if (!isRising) {
if (!bricksMan.insideBrick(xWorld + (getWidth() / 2),
yWorld + getHeight()))
/* If this happens then there is not ground under Karl */ {
// increase falling speed
yVelocity += 0.5;
double fallDistance = bricksMan.checkBrickTop(
(int) xWorld + (getWidth() / 2),
(int) yWorld + (getHeight() + (int) yVelocity), (int) yVelocity);
yWorld += fallDistance;
locY += fallDistance;
} else {
/* ground has been hit */
yVelocity = 0;
}
} else if (isRising)// is rising
{
if (yVelocity > -10) // is moving towards air
{
if (!bricksMan.insideBrick(xWorld + (getWidth() / 2), yWorld)) {
/* There is air above Karl */
yVelocity -= -0.5;
double riseDistance = bricksMan.checkBrickBase(
(int) xWorld + (getWidth() / 2),
(int) yWorld + (int) yVelocity, (int) yVelocity);
System.out.println("riseDistance and yVelocity: " +riseDistance+" "+yVelocity);
yWorld += riseDistance;
locY += riseDistance;
} else {
yVelocity = 0; // stop getting any higher!!
isRising = false;
}
}
if (yVelocity >= 0.0) // nothing was hit, but we ran out of velocity
{
isRising = false;
yVelocity = 0;
}
}
}
NOTES:
- locY and the yWorld-fields are the same right now, since the world is not scrolling!
- Karl is the player.
- yVelocity is a double.
- collisions on the x-axis is dealt with before calling update().
- when jumping yVelocity is set to -9.5, and isRising it set to true.
I tried to implement the falling, and jumping part of the collision detection in the same way,
but it appears I haven’t as only the falling works right.
Can you spot the problem with the code?
I’ll happily supply any more info about the logic if anything it unclear to you
TL;DR VERSION:
Please read the text