简体   繁体   中英

How to detect collisions between objects in LibGDX

This is my first post on stack overflow so I apologize in advance if I'm breaking any rules about posting, etc. I have been working on a an asteroids- esque shooting game and I can't figure out how to get the collision detection working between the rocks and the laser.
The source code can be found here . I had to make some changes to the update method of LevelScreen because the original code is dependent on using the BlueJ IDE. I found a fix in this post and got the collision working between the spaceship and the rocks.

The LevelScreen class

    package com.mygdx.game;

import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;

import java.util.ArrayList;

public class LevelScreen extends BaseScreen {

    private Spaceship spaceship;
    private boolean gameOver;
    private boolean rocksNeedRemoved;
    private Rock toRemove;

    private ArrayList<Rock> rocks;
    private ArrayList<Laser> lasers;

    public void initialize() {

        gameOver = false;
        toRemove = null;
        rocksNeedRemoved = false;

        BaseActor space = new BaseActor(0, 0, mainStage);
        space.loadTexture("space.png");
        space.setSize(800, 600);
        BaseActor.setWorldBounds(space);

        spaceship = new Spaceship(400, 300, mainStage);

        rocks = new ArrayList<Rock>();
        lasers = new ArrayList<Laser>();

        rocks.add(new Rock(600, 500, mainStage));
        rocks.add(new Rock(600, 300, mainStage));
        rocks.add(new Rock(600, 100, mainStage));
        rocks.add(new Rock(400, 100, mainStage));
        rocks.add(new Rock(200, 100, mainStage));
        rocks.add(new Rock(200, 300, mainStage));
        rocks.add(new Rock(200, 500, mainStage));
        rocks.add(new Rock(400, 500, mainStage));

        lasers.add(new Laser(400, 500, mainStage));


    }

    public void update(float dt) {


        //Code from book(Throws class not found error)
        /*
        for (BaseActor rockActor : BaseActor.getList(mainStage, 
            "Rock")) {

            if (rockActor.overlaps(spaceship)) {

                if (spaceship.shieldPower <= 0) {

                    Explosion boom = new Explosion(0, 0, 
                        mainStage);
                    boom.centerAtActor(spaceship);
                    spaceship.remove();
                    spaceship.setPosition(-1000, -1000);

                    BaseActor messageLose = new BaseActor(0, 0, 
                        uiStage);
                    messageLose.loadTexture("message- 
                        lose.png");
                    messageLose.centerAtPosition(400, 300);
                    messageLose.setOpacity(0);
                    messageLose.addAction(Actions.fadeIn(1));
                    gameOver = true;
                }
                else {

                    spaceship.shieldPower -= 34;
                    Explosion boom = new Explosion(0, 0, 
                        mainStage);
                    boom.centerAtActor(rockActor);
                    rockActor.remove();
                }
            }

            for (BaseActor laserActor : 
                BaseActor.getList(mainStage, "Laser")) {

                if (laserActor.overlaps(rockActor)) {

                }
                Explosion boom = new Explosion(0, 0, 
                    mainStage);
                boom.centerAtActor(rockActor);
                laserActor.remove();
                rockActor.remove();
            }
        }

        if (!gameOver && BaseActor.count(mainStage, "Rock") == 
            0) {

            BaseActor messageWin = new BaseActor(0, 0, 
                uiStage);
            messageWin.loadTexture("message-win.png");
            messageWin.centerAtPosition(400, 300);
            messageWin.setOpacity(0);
            messageWin.addAction(Actions.fadeIn(1));
            gameOver = true;
        }

    }

         */





        // loop I used to get collision working between rocks 
            and spaceship

        for (Rock each : rocks)
            if (spaceship.overlaps(each) && !each.crashed && 
                spaceship.shieldPower <= 0) {
                Explosion boom = new Explosion(0, 0, 
                    mainStage);
                Explosion boom2 = new Explosion(0, 0, 
                    mainStage);
                boom.centerAtActor(spaceship);
                boom2.centerAtActor(each);

                spaceship.remove();
                spaceship.setPosition(-1000, -1000);
                each.crashed = true;
                each.clearActions();
                each.addAction(Actions.fadeOut(1));

    each.addAction(Actions.after(Actions.removeActor()));
                rocksNeedRemoved = true;
                toRemove = each;

            } else if (spaceship.overlaps(each) && 
                  !each.crashed) {
                Explosion boom = new Explosion(0, 0, 
                    mainStage);
                boom.centerAtActor(each);
                spaceship.shieldPower -= 34;
                each.crashed = true;
                each.clearActions();
                each.addAction(Actions.fadeOut(1));

    each.addAction(Actions.after(Actions.removeActor()));
                rocksNeedRemoved = true;
                toRemove = each;
            }

        //check for collision between rocks and lasers (Not 
          working correctly)

        for (int i = rocks.size() - 1; i >= 0; i--) {
            Rock rock = rocks.get(i);
            for (int j = lasers.size() - 1; j >= 0; j--) {
                Laser laser = lasers.get(j);

    if(rock.getBounds().overlaps(laser.getBounds())) {
                    Explosion boom = new Explosion(0, 0, 
                        mainStage);
                    boom.centerAtActor(rock);
                    rock.crashed = true;
                    rock.clearActions();
                    rock.addAction(Actions.fadeOut(1));

    rock.addAction(Actions.after(Actions.removeActor()));
                    rocksNeedRemoved = true;
                    toRemove = rock;
                }
            }
        }

    }







    //override default InputProcessor method
    public boolean keyDown(int keycode) {

        if (keycode == Keys.X)
            spaceship.warp();

        if (keycode == Keys.SPACE)
            spaceship.shoot();

        return false;
    }
}

The Spaceship class.

    package com.mygdx.game;

import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.math.MathUtils;

public class Spaceship extends BaseActor {

    private Thrusters thrusters;
    private Shield shield;
    public int shieldPower;

    public Spaceship(float x, float y, Stage s) {

        super(x, y, s);

        loadTexture("spaceship.png");
        setBoundaryPolygon(8);

        setAcceleration(100);
        setMaxSpeed(100);
        setDeceleration(10);

        thrusters = new Thrusters(0, 0, s);
        addActor(thrusters);
        thrusters.setPosition(-thrusters.getWidth(), 
            getHeight() / 2 - thrusters.getHeight() / 2);

        shield = new Shield(0, 0, s);
        addActor(shield);
        shield.centerAtPosition(getWidth() / 2, getHeight() / 
            2);
        shieldPower = 100;

    }

    public void act(float dt) {

        super.act(dt);

        float degreesPerSecond = 160; //rotation speed
        if (Gdx.input.isKeyPressed(Keys.LEFT))
            rotateBy(degreesPerSecond * dt);
        if (Gdx.input.isKeyPressed(Keys.RIGHT))
            rotateBy(-degreesPerSecond * dt);

        if (Gdx.input.isKeyPressed(Keys.UP)) {
            accelerateAtAngle(getRotation());
            thrusters.setVisible(true);
        }
        else {
            thrusters.setVisible(false);
        }

        shield.setOpacity(shieldPower / 100f);
        if (shieldPower <= 0)
            shield.setVisible(false);

        applyPhysics(dt);

        wrapAroundWorld();
    }

    public void warp() {

        if(getStage() == null)
            return;

        Warp warp1 = new Warp(0, 0, this.getStage());
        warp1.centerAtActor(this);
        setPosition(MathUtils.random(800), 
            MathUtils.random(600));
        Warp warp2 = new Warp(0, 0, this.getStage());
        warp2.centerAtActor(this);
    }

    public void shoot() {

        if (getStage() == null)
            return;

        Laser laser = new Laser(0, 0, this.getStage());
        laser.centerAtActor(this);
        laser.setRotation(this.getRotation());
        laser.setMotionAngle(this.getRotation());


    }
}

The Laser class.

    package com.mygdx.game;

import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.Action;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;

public class Laser extends BaseActor {

    Rectangle bounds;

    public Laser(float x, float y, Stage s) {

        super(x, y, s);
        bounds = new Rectangle((int)getX(), (int)getY(), 
             (int)getWidth(), (int)getHeight());






        loadTexture("laser.png");

        addAction(Actions.delay(1));
        addAction(Actions.after(Actions.fadeOut(0.5f)));
        addAction(Actions.after(Actions.removeActor()));

        setSpeed(400);
        setMaxSpeed(400);
        setDeceleration(0);
    }

    public void act(float dt) {

        super.act(dt);
        applyPhysics(dt);
        wrapAroundWorld();
    }

    public Rectangle getBounds() {
        return bounds;
    }

    private void setXY(float pX,float pY) {
        setPosition(pX, pY);
        bounds.setX((int)pX);
        bounds.setY((int)pY);
    }

}

The Rock class

    package com.mygdx.game;

import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.Action;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.math.MathUtils;
import com.mygdx.game.BaseActor;

public class Rock extends BaseActor {


    public boolean crashed;
    Rectangle bounds;

    public Rock(float x, float y, Stage s) {

        super(x, y, s);

        bounds = new Rectangle((int)getX(), (int)getY(), 
            (int)getWidth(), (int)getHeight());



        loadTexture("rock.png");

        float random = MathUtils.random(30);

        addAction(Actions.forever(Actions.rotateBy(30 + random, 
            1)));

        setSpeed(50 + random);
        setMaxSpeed(50 + random);
        setDeceleration(0);
        setMotionAngle(MathUtils.random(360));

        crashed = false;
    }

    public void act(float dt) {


        super.act(dt);
        applyPhysics(dt);
        wrapAroundWorld();
    }



    public boolean isCrashed() {
        return crashed;
    }

    public void crashed() {

        crashed = true;
        clearActions();
        addAction(Actions.fadeOut(1));
        addAction(Actions.after(Actions.removeActor()));

    }
    public Rectangle getBounds() {
        return bounds;
    }

    private void setXY(float pX,float pY) {
        setPosition(pX, pY);
        bounds.setX((int)pX);
        bounds.setY((int)pY);
    }
}

Boundary and overlap methods from BaseActor class

public void setBoundaryPolygon(int numSides) {

        float w = getWidth();
        float h = getHeight();
        float[] vertices = new float[2 * numSides];

        for(int i = 0; i < numSides; i ++) {

            float angle = i * 6.28f / numSides;
            //x coordinate
            vertices[2 * i] = w / 2 * MathUtils.cos(angle) + w / 2;
            //y coordinate
            vertices[2 * i + 1] = h / 2 * MathUtils.sin(angle) + h / 2;

        }

        boundaryPolygon = new Polygon(vertices);
    }

    public Polygon getBoundaryPolygon() {

        boundaryPolygon.setPosition(getX(), getY());
        boundaryPolygon.setOrigin(getOriginX(), getOriginY());
        boundaryPolygon.setRotation(getRotation());
        boundaryPolygon.setScale(getScaleX(), getScaleY());
        return boundaryPolygon;
    }

    public boolean overlaps(BaseActor other) {

        Polygon poly1 = this.getBoundaryPolygon();
        Polygon poly2 = other.getBoundaryPolygon();

        //initial text to improve performance
        if(!poly1.getBoundingRectangle().overlaps(poly2.getBoundingRectangle()))
            return false;

        return Intersector.overlapConvexPolygons(poly1, poly2);
    }

So I guess the real question would be how would I go about checking for collisions between the rocks ArrayList and the lasers fired by the player? At this point I just want to finish the game even if it's not using best practices. I tried using the method described here and received no errors but also no collision between lasers and rock. Even if I manually add a laser to the lasers ArrayList. This last post I found leads me to believe I need something like a getAllLasers() but I'm not 100% sure how to go about that. Would it be easier to just learn Box2D or Quadtree?

I realize this is a complex problem and want to thank you in advance for taking taking the time to read it. I'm happy to provide any more information you need.

You already have Rectangle bounds for both of this entities, this is all you need. You can use Rectangle.overlaps()

for(Laser laser: lasers){
   for(Rock rock: rocks){
      if(laser.getBounds().overlaps(rock.getBounds())){
         //collided! 
      }
   }
}

Make sure you are getting a updated rectangle/bounds. Add this extra line in both Rock and Laser getBounds() method:

public Rectangle getBounds() {
   bounds.set(getX(),getY(),getWidth(),getHeight());
   return bounds;
}

if your actors scales or rotate you should update bounds accordingly

I think problem may be with update your actors bounds, i can't find where you update it. I wrote similiar game and i change Bound s of actors on each update step and all works well in some lines...

public void update() {
...
        // changing bounds
        bounds = new Rectangle(position.x,position.y,
                actorWidth,
                actorHeight);
}

Or if you use other approach check that your bounds changing in time

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM