如何在LibGDX中检测物体之间的碰撞?

问题描述 投票:0回答:1

这是我第一次在stack overflow上发帖,所以如果我违反了任何关于发帖的规则,我提前道歉。 我一直在研究一个小行星------。似是而非 射击游戏,我不知道如何让岩石和激光之间的碰撞检测工作。源代码可以在下面找到 此处. 我不得不对LevelScreen的更新方法做了一些修改,因为原来的代码是依赖于使用BlueJ IDE的。我在这里找到了一个修复方法 岗位 并在飞船和岩石之间进行了碰撞。

LevelScreen类

    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;
    }
}

飞船级。

    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());


    }
}

激光级

    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);
    }

}

岩石级

    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);
    }
}

BaseActor类的边界和重叠方法。

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);
    }

所以我想真正的问题是,我如何去检查岩石ArrayList和玩家发射的激光之间的碰撞?在这一点上,我只想完成游戏,即使它没有使用最佳实践。 我试着用下面描述的方法 此处 并没有收到任何错误,但也没有激光器和岩石之间的碰撞。即使我手动添加一个激光器到激光器ArrayList中。最后一个 岗位 我发现让我相信我需要类似getAllLasers()的东西,但我不是100%确定如何去做。如果只是学习Box2D或Quadtree会不会更容易?

我意识到这是一个复杂的问题,想提前感谢你花时间阅读它。我很乐意提供你所需要的任何更多信息。

java arraylist libgdx collision-detection game-development
1个回答
1
投票

你已经有了 Rectangle 这两个实体的边界,这就是你所需要的。你可以使用 Rectangle.overlaps()

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

确保你得到的是一个更新的rectanglebounds。在这两行中添加额外的 RockLaser getBounds() 方法。

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

如果你的演员按比例或旋转,你应该更新 bounds 据此


0
投票

我想问题可能出在更新你的演员界限上,我找不到你在哪里更新它。我写了一个类似的游戏,我改变了 Bound在每一步更新时,演员的数量都会增加,而且在某些台词中效果很好......。

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

或者,如果你使用其他方法,检查你的边界在时间上的变化。

© www.soinside.com 2019 - 2024. All rights reserved.