LibGdx - Tile Game Collision Detection - java

I'm working on a tile 2d-side platformer game. I have done some stuff so far.
I'm working on a basic collision detection using rectangles of libgdx so considering
I have only grass block for now I made a single block world in Java (file reader is not ready)
the problem is my detection only works the first time in other words if I spawn my colliding
to a block it detects collision and do so. Although if i spawn my player top of the block
with out colliding player falls forever.
Here is the code world.update(); =>
public void update() {
Iterator<block> cb = Blocks.iterator();
while (cb.hasNext()) {
block b = cb.next();
if (b.getBounds().overlaps(player.getBounds())) {
if (player.getPosition().x >= b.getPosition().x + 32) {
//RIGHT
player.getVelocity().x = 0;
} else if (player.getPosition().x + 32 <= b.getPosition().x) {
//Left
player.getVelocity().x = 0;
}
//All Y
player.getVelocity().y = 0;
}
if (!b.getBounds().overlaps(player.getBounds())) {
player.getVelocity().y = -gravity;
}
}
}

Your while loop is applying gravity for every block your player does not intersect with. So if you have 10 blocks, and the player intersects just 1, you'll still apply gravity 9 times. You should only apply the gravity change to the player once.
Set a flag (boolean hitSomething = false) before your loop, then set it to true (hitSomething = true) if the player hits any block. Then, after the loop, if hitSomething is false, apply gravity to the player.
Stepping through the update method with a debugger is a good way to figure out what your code is doing in cases like this. It should be quicker than waiting for Stack Overflow to debug your code, too.

Related

How to make a player only be able to jump a certain height in Java?

So, for a school project, I've been trying to get a jumping mechanism down. However, the problem I've been having is that the player is able to just float around, rather than having to fall down after reaching a certain jump height.
I have tried many things, including the normal idea of when the up key is pressed, setting jumping equal to true, and then in the actionPerformed method, setting the yVelocity to -4. But, when the jump key is clicked, I record the yPosition at the time, and when the current yPosition is less than the original position - 50, I set the yVelocity equal to 0, and the fallVelocity to 1.
This is the code in my actionPerformed method:
if (jumping) {
if (yPos <= homeY - 50) {
yVel = 0;
fallVel = 1;
falling = true;
jumping = false;
System.out.println("bye");
} else {
yVel = -JUMP_SPEED;
}
}
yPos += yVel + fallVel;
'''
This is the code in the keyPressed method:
if (!jumping && !falling) {
jumping = true;
homeY = yPos;
count = 0;
}
So, I expect the result to be a player that goes up 50 pixels, and then starts falling down. But in the program, the player just sort of keeps on floating, as long as the up key is pressed.
Jumping does not really work properly as an up/down switch imo. The best approach is to use gravity (which is very easy to add).
To add gravity just modify the player velocity each tick. This should be run on a fixed time update loop to make consistent gravity at different frame rates:
// Play with this number for rate of gravity
player.ySpeed -= 4.9; // Gravity = 9.8m/s^2
Then for your jumping just add to the player ySpeed. This will create a natural parabolic jump.
if (jumpWasPressed) {
player.ySpeed += 50; // play with this number for jump height
}
This approach does assume you have a hotbox for your "ground" object to stop the player from falling through the ground

Draw circles permanetly given an if statement - Processing

I have an if statement which checks for collision as such:
if (BallY == y && BallX == x) // check for collision
{
x = 80; // reset x to initial
y = 240; // reset y to initial
z = 100; //reset z to initial
}
I have a for loop inside this if statement as such:
if (BallY == y && BallX == x) // check for collision
{
x = 80; // reset x to initial
y = 240; // reset y to initial
z = 100; //reset z to initial
for (int i=50; i<width; i+=80)
{
fill(250,0,0);
ellipse(i, 50, 70, 70);
}
}
So the point is to draw a line of circles on the top of the screen once the collision occurs. This code however, only draws them for a split second then they disappear. How would I make them stay given that a collision has occurred?
You might want to use a boolean value that tracks whether the ball has collided. Set it to true when you detect a collision, and then check the value to decide what to draw. Here's a simplified example:
boolean drawRed = false;
void draw() {
if (mouseY > height/2) {
drawRed = true;
}
if (drawRed) {
background(255, 0, 0);
}
}
This code draws a gray background by default, but then turns to red if the mouse goes in the lower half of the window. It stays red even if you move the mouse back to the top part.
This is just a simple example, but the idea is the same: use a variable to track the state of the sketch, set that variable when your condition is met, and check that variable to decide what to draw.
By the way, your collision detection is a little bit suspicious. You probably don't want to check whether the ball is at an exact location. Instead you probably want to check whether the ball overlaps some area. Here is a guide on collision detection in Processing that might be useful.
If you still can't get it working, please narrow your problem down to a MCVE instead of posting disconnected snippets or your full sketch. Good luck!

Near perfect collision in LibGdx Java

I am trying to get the collision in my game to be exactly perfect. What I am testing is if you hit a wall with the player, you come to a stop. I only implemented the collision code for when the player hits the left side of a wall(when the wall is on the right side of the player). Here is the code.
if(entityOnRight){
if(player.getPositionCorner(SquareMapTuples.BOTTOM_RIGHT).x -
ent.getPositionCorner(SquareMapTuples.BOTTOM_LEFT).x > -.9f)
player.setMovementBooleans(false, false, false, false);
else
player.setMovementBooleans(true, false, false, false);
}
Note: If I go very slow, it will stop the player where I desire it to be stopped, but going fast, it won't do the collision the way I want
Essentially, the code states if the wall is on the right side, it will check the bottom right corner of the rectangle of the player, subtract the bottom left corner of the wall, and check if the distance between the two is 0.001. 0.001 is almost an unnoticeable distance, hence why I used that value. Here is the code for player.setMovementBooleans
public void setMovementBooleans(boolean canMoveRight, boolean canMoveLeft, boolean canMoveUp, boolean canMoveDown){
this.canMoveRight = canMoveRight;
if(canMoveRight == false && moveRight)
vel.x = 0;
}
The canMoveRight boolean in the Player class (not in parameters) is what allows you to be able to move, moveRight is when you are trying to move right. Here is some code that will better explain how these booleans interact:
//If you clicked right arrow key and you're not going
//Faster then the max speed
if(moveRight && !(vel.x >= 3)){
vel.x += movementSpeed;
}else if(vel.x >= 0 && !moveRight){
vel.x -= movementSpeed * 1.5f;
System.out.println("stopping");
//Make sure it goes to rest
if(vel.x - movementSpeed * 1.5f < 0)
vel.x = 0;
}
and:
if(Gdx.input.isKeyPressed(Keys.D) && canMoveRight)
moveRight = true;
else
moveRight = false;
So to give a summary, if you click the "D" key, it allows you to start moving. However if the boolean canMoveRight is false, it won't move you. Here is an image showing what happens (The player is yellow, the wall is green)
As you can see, the player goes much further then I want it to. It should stop at this point:
Any help with figuring out how to accomplish this is extremely appreciated!
Maybe the way you tried it is a bit too complicated :-). I suggest a simpler way from scratch: make the map and the player a com.badlogic.gdx.math.Rectangle instance. Now, in the following part of the code you make a check, whether after the move the player would still be inside the map, if yes then allow the move, if not, then don't allow:
if(Gdx.input.isKeyPressed(Keys.D){
float requestedX, requestedY;
//calculate the requested coordinates
Rectangle newPlayerPositionRectangle = new Rectangle(requestedX, requestedY, player.getWidth(), player.getHeight());
if (newPlayerPositionRectangle.overlaps(map) {
//move the player
} else {
//move the player only to the edge of the map and stop there
}
}
The best way to handle those collisions would be to use a physics engine like Box2D which already comes packed with Libgdx. When a collision occurs in Box2D a event gets fired and you can easly handle that event. So you should probably take a look here.
Another alternative to achieve this without physics would be to use logical rectanlges representing the player and walls (can also be polyline) and use Intersector class of libgdx.
which is here.

Collision in 2D game

I'm trying to make a little game, where you have a little cube you can control with the arrows. When the cube intersects with another block object, I want it to go back and stop by the edge of the block object. So basically I want my block to stop when it intersects the block object, instead, it moves a bit in to it, and then when I move it again it jumps back. How can I make it so first checks if it will intersect, and if it will not move into it?
My drawing class extends JPanel and I'm painting with paintComponent.
if(keyCode == e.VK_RIGHT) {
if(xRightCollision()){
hero.x -= xVel;
}
else {
hero.x += xVel;
}
}
So let's say the cube is at the edge of the block object, but it's not intersecting it yet, so I press right and it moves into it, I press right again and it jumps back 5 pixels(xVel = 5).
public boolean xRightCollision(){
for(int i = 0; i < obstacles.size(); i++) {
if (hero.intersects(obstacles.get(i))) {
return true;
}
}
return false;
}
I've actually tried a similar thing with paint() on the JFrame, and since you have to call repaint() there, I could check first and then repaint. I don't really understand how paintComponent works since you can't control when it should be repainted.
Just use a temporary value to check, if the cube intersects with an obstacle, and reset to the original position, if necessary:
if(keyCode == e.VK_RIGHT) {
//backup of the cubes position
int tmp = hero.x;
//move the hero to the right
hero.x += xVel;
if(xRightCollision())
//cube intersects with an obstacle -> restore original position
hero.x = tmp;
}

Slick2d collision detection with Tiles using rectangles

i'm quite stuck. Before I do anything, heres the code:
if(inAir&&!falling&&!jumping){
if(py<600){
if (!(isBlocked(xminusd, py) || isBlocked(xminus, py + 32 - 1))) {
falling=true;
}else{
py-=2;
inAir=false;
}
}
}
for(int g = 0;g<Map.r.size();g++){
if(rect.intersects(Map.r.get(g))||Map.r.get(g).contains(rect)||rect.contains(Map.r.get(g))||Map.r.get(g).intersects(rect)){
System.out.println("Intersecting!");
inAir= false;
hasjumped=false;
onPlat = true;
falling = false;
jumping = false;
py-=4;
break;
}else{
onPlat = false;
if(inAir==false&&!onPlat){
inAir = true;
onPlat = false;
}
}
}
Now the problem is, i'm trying to make collision detection with a certain type of tile, by creating rectangles for each tile, and if the player collides with it it stops all movement.(falling wise at least). But i've run into a problem. I've used an array list, to create all my rectangles, and i'm using a for loop to check each rectangle. Problem is, if it checks a rectangle and i'm not colliding with that rectangle currently, it immidiatly starts falling, then resetting, because it finds the rectangle i'm colliding with. The problem is im using a for loop to cycle through each rectangle... I'm really stuck on how to do collision detection with platform tiles. Anyone have any help to provide? Please be descriptive.
It doesn't look like it matters which rectangle you are colliding with so try abstracting by making a function that returns true or false if it is colliding with any block and put that in your else if statement. that way if you are still colliding it wont start falling while cycling through the rest of your blocks
Something like
...
if(colliding())
{
//stop falling
}
else
{
//start falling
}
....
boolean colliding(){
for(int g = 0;g<Map.r.size();g++){
//check for collision if true return true
}
return false;
}
EDIT:
The reason this works is because as you are going through the for loop it keeps the object falling while it determines that it should stop. By moving the falling logic away from the collision logic we can determine if it is colliding and then take the appropriate action.

Categories