0
\$\begingroup\$

I am in the early stages of creating a Java 2d platformer / sidescroller game where the Entity class requires (at this point) basic Rectangle bounds collision detection.

In my code I check to see if the static Rectangle bounds of the Player object intersects with the Rectangle bounds of Entity Object in the array "entities[]" in the Screen class. My method of implementation is rendering a rectangle on the top, bottom, left, and right sides of each Entity.

My code is almost fully working since it does provide collision detection, however this is only true for the last Entity Object in the Array. Every Entity object besides the last one has NO collision detection, even though the Rectangle objects are properly positioned and rendered.

For example if I call the method "addEntities(3)" in my Screen class Constructor, only the 3rd and final Entity will actually utilize the collision detection.

I know the collision detection works because I have adjusted the "checkCollision()" method to check a specific index of the Entity array that isn't the last one. The Rectangle bounds are also rendered to the screen over each Entity sprite properly, so I know the Rectangle object of each Entity is there.

Here is some of my code for the Screen class, which is the intermediary between the Entitiy and the Game class:

public Screen (int width, int height) {
    this.width = width;
    this.height = height;
    addEntities(2);                  // amount of entities to spawn
}
public void tick() {
    checkCollision();                // checks collision 
}

public void render(Graphics g) {     // renders all entities based on size of array
    for (int i = 0; i < this.entitySize; i++) {
        entities[i].render(g);
    }
}
                                     // 
public void addEntities(int entitySize) {   // adds entities to the Screen
    this.entitySize = entitySize;

    entities = new Entity[entitySize];
    int renderX, renderY;
    for (int i = 0; i < entitySize; i++) {
        renderX = (i* 64) + 300;
        renderY = 300;
        entities[i] = new Entity(renderX, renderY, topFloorMob, topFloorSheet, 64, 64); // adds Entities to the proper index of Array 'entities[]'
    }
}

public void checkCollision() {       // checks if bounds of the Player Rectangles intersect the bounds of the Entity Array Rectangles
    for (int i = 0; i < entitySize; i++) {
        if (Player.topBorder.intersects(entities[i].getBottomBounds()))  Player.topCollision = true;

        else  Player.topCollision = false;

        if (Player.bottomBorder.intersects(entities[i].getTopBounds()))  Player.bottomCollision = true;

        else Player.bottomCollision = false;

        if (Player.leftBorder.intersects(entities[i].getRightBounds()))  Player.leftCollision = true;

        else  Player.leftCollision = false;

        if (Player.rightBorder.intersects(entities[i].getLeftBounds()))  Player.rightCollision = true;

        else  Player.rightCollision = false;

    }
}

}

Here is some of the Entity class code:

public class Entity {
public int renderX, renderY;
protected Sprite sprite;
protected SpriteSheet sheet;
protected Rectangle topBorder, bottomBorder, leftBorder, rightBorder;
protected int sizeX, sizeY; // sizes of entity

public Entity(int renderX, int renderY, Sprite sprite, SpriteSheet sheet, int sizeX, int sizeY) {
    this.renderX = renderX;
    this.renderY = renderY;
    this.sprite = sprite;
    this.sheet = sheet;
    this.sizeX = sizeX; 
    this.sizeY = sizeY; 
    setBounds();    
}

public void setBounds() {
    setTopBounds();
    setBottomBounds();
    setLeftBounds();
    setRightBounds();
}

public Rectangle setTopBounds() {
    return topBorder = new Rectangle(renderX, renderY, sizeX, sizeY - (sizeY - 4)); 
}
public Rectangle setLeftBounds() {
    return leftBorder = new Rectangle(renderX, renderY, sizeX - (sizeX - 4), sizeY);    
}

public Rectangle setRightBounds() {
    return rightBorder = new Rectangle(renderX + (sizeX - 3), renderY, sizeX - (sizeX - 4), sizeY);
}

public Rectangle setBottomBounds() {
    return bottomBorder = new Rectangle(renderX, renderY + (sizeY - 3), sizeX, sizeY - (sizeY - 4));
}   

public void render(Graphics g) {
    sprite.render(g, renderX, renderY);
    g.fillRect((int)topBorder.getX(), (int) topBorder.getY(), (int) topBorder.getWidth(), (int) topBorder.getHeight());
    g.fillRect((int)leftBorder.getX(), (int) leftBorder.getY(), (int) leftBorder.getWidth(), (int) leftBorder.getHeight());
    g.fillRect((int)rightBorder.getX(), (int) rightBorder.getY(), (int) rightBorder.getWidth(), (int) rightBorder.getHeight());
    g.fillRect((int)bottomBorder.getX(), (int) bottomBorder.getY(), (int) bottomBorder.getWidth(), (int) bottomBorder.getHeight());
}

public void tick() {    
}

public Rectangle getTopBounds() {
    return topBorder;   
}
public Rectangle getLeftBounds() {
    return leftBorder;
}

public Rectangle getRightBounds() {
    return rightBorder;
}

public Rectangle getBottomBounds() {
    return bottomBorder;
}

And finally here is some of the code for my Player class, which is nearly identical to the Entity class (not properly formatted inheritance at this stage of the project, but it will be fixed later):

public class Player {
public static int renderX, renderY;
public static Sprite sprite;
public static SpriteSheet sheet;
public static  Rectangle topBorder;
public static Rectangle bottomBorder;
public static Rectangle leftBorder;
public static Rectangle rightBorder;
public static boolean topCollision = false, bottomCollision = false, leftCollision = false, rightCollision = false;
public static int sizeX, sizeY; 

public static boolean moveUp = true, moveDown = true, moveLeft = true, moveRight = true;

public Player(int renderX, int renderY, Sprite sprite, SpriteSheet sheet, int sizeX, int sizeY) {
    Player.renderX = renderX;
    Player.renderY = renderY;
    Player.sprite = sprite;
    Player.sheet = sheet;
    Player.sizeX = sizeX; 
    Player.sizeY = sizeY;   
    setBounds();    
}

public void setBounds() {
    setTopBounds();
    setBottomBounds();
    setLeftBounds();
    setRightBounds();
}

public void render(Graphics g) {
    sprite.render(g, renderX, renderY);
    g.fillRect((int)topBorder.getX(), (int) topBorder.getY(), (int) topBorder.getWidth(), (int) topBorder.getHeight());
    g.fillRect((int)leftBorder.getX(), (int) leftBorder.getY(), (int) leftBorder.getWidth(), (int) leftBorder.getHeight());
    g.fillRect((int)rightBorder.getX(), (int) rightBorder.getY(), (int) rightBorder.getWidth(), (int) rightBorder.getHeight());
    g.fillRect((int)bottomBorder.getX(), (int) bottomBorder.getY(), (int) bottomBorder.getWidth(), (int) bottomBorder.getHeight());
}

public void tick() {    
    checkForCollision();
    setBounds();
}

public void checkForCollision() {
    if( topCollision = true) moveUp = false;
    if( bottomCollision = true) moveDown = false;
    if( leftCollision = true) moveLeft = false;
    if( rightCollision = true) moveRight = false;
}

public static Rectangle setTopBounds() {
    return topBorder = new Rectangle(renderX, renderY, sizeX, sizeY - (sizeY - 4)); 
}
public static  Rectangle setLeftBounds() {
    return leftBorder = new Rectangle(renderX, renderY, sizeX - (sizeX - 4), sizeY);    
}

public static Rectangle setRightBounds() {
    return rightBorder = new Rectangle(renderX + (sizeX - 3), renderY, sizeX - (sizeX - 4), sizeY);
}

public static Rectangle setBottomBounds() {
    return bottomBorder = new Rectangle(renderX, renderY + (sizeY - 3), sizeX, sizeY - (sizeY - 4));
}   

}

I think the problem arises from the logic used in the Screen class method "checkCollision()", but I am not entirely sure. I will post more code of the main Game class if necessary.

I would like some understanding as to how the collision detection only works for the last Entity of the array, otherwise my code fully works. If there is a better way of implementing this, feel free to leave feedback.

*[EDIT] Added a Collision ID integer associated with the index of the Entity array used by the checkCollision() method to detect whether a collision has occurred and at which index corresponding to the tiles rendered on the Screen.

\$\endgroup\$
  • \$\begingroup\$ [SOLVED]: The problem was in my logic. The checkCollision() method in the Screen class was always resetting the Collision boolean variables to false due to the "else collision = false" statements, because the for loop was iterating through each entity without checking to see if there is already current directional collision. For this reason the last object of the array had priority in retaining the collision states simply because it was the last one in the loop. Fixed with revised logic and addition of a collisionID to only scan recent directional collision with the recently collided entity \$\endgroup\$ – Ryan Nov 3 '17 at 22:02
  • 2
    \$\begingroup\$ Welcome to GDSE! Here, if a user manages to solve their own issue, they're more than welcome to write an answer and accept it when the time limit allows it. So I suggest you make an answer out of that comment, and come back in a couple of days and mark it as accepted :) \$\endgroup\$ – Vaillancourt Nov 4 '17 at 2:14
1
\$\begingroup\$

[SOLVED]: Added a CollisionID attached to the "i" variable iteration of each index of the Entities array when collision has been detected. This effectively pinpoints the actual location of the collision rather than detecting if any collision had been done on any tile. The CollisionID variable is used in the .intersects(entities[collisionID]) line to check if the previously detected collision is no longer true, rather than resetting the Player.bottomCollision state (which affects gravitation and movement) to false by default due to other tiles not having collision.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.