基于Java的2D空间射击游戏中的碰撞检测

时间:2015-02-17 12:56:30

标签: java android

这个问题背后的背景是我是一个致力于在Android上创建小游戏的小团体的一员。我们选择开发的游戏是一个自上而下的2D射击游戏,其中玩家控制一艘宇宙飞船必须保护自己免受从游戏屏幕顶部向玩家移动的外星生物的攻击,类似于太空入侵者,但不同之处在于它们会产生随机模式。

到目前为止,我们已经能够让游戏运行,让玩家和敌人产生并向正确的方向移动,以及玩家的武器被标记为“射弹”(尽管它目前只是生成它自己而不是播放器命令)。我们遇到的问题是我们试图在射弹和敌人之间的代码中建立一个碰撞事件,这样当他们相遇时,敌人和子弹都会消失。

但是,我们目前在代码中编写的内容似乎并没有使这项工作成功,所以我想知道是否有其他人可以看到我们出错的地方。我在下面列出了相关的代码类。我们非常感谢任何人都能给予的帮助。

碰撞探测器类(保留游戏中所有实体的碰撞检测行为)。

package uk.ac.qub.eeecs.gage.util;

import uk.ac.qub.eeecs.gage.world.GameObject;

/**
 * Collision Detector Helper Library
 * 
 * @version 1.0
 */
public class CollisionDetector {

    /**
     * Type of collision
     */
    public enum CollisionType {
        None, Top, Bottom, Left, Right, destroy //for the platform game, not yours
    };

    /**
     * Determine if the two specified bounding boxes are in collision
     * 
     * @param one
     *            First bounding box
     * @param two
     *            Second bounding box
     * @return boolean true if the boxes overlap, false otherwise
     */
    //is relevant to your game
    public static boolean isCollision(BoundingBox one, BoundingBox two) {
        return (one.x - one.halfWidth < two.x + two.halfWidth
                && one.x + one.halfWidth > two.x - two.halfWidth
                && one.y - one.halfHeight < two.y + two.halfHeight && one.y
                + one.halfHeight > two.y - two.halfHeight); 

        //Do we add the code to set the enemies to disappear/destroy here or in the 
        //individual classes such as the player?
    }

    /**
     * Determine the type of collision between the two bounding boxes.
     * CollisionType.None is returned if there are no collisions.
     * 
     * @param one
     *            First bounding box
     * @param two
     *            Second bounding box
     * @return Collision type
     */

AISpaceship.java类(用于外星人实体及其属性的类)。

package uk.ac.qub.eeecs.game.spaceDemo;

import uk.ac.qub.eeecs.gage.ai.SteeringBehaviours;
import uk.ac.qub.eeecs.gage.engine.ElapsedTime;
import uk.ac.qub.eeecs.gage.util.CollisionDetector;
import uk.ac.qub.eeecs.gage.util.Vector2;
import uk.ac.qub.eeecs.gage.util.CollisionDetector.CollisionType;
import uk.ac.qub.eeecs.gage.world.GameObject;
import uk.ac.qub.eeecs.gage.world.Sprite;

/**
 * AI controlled spaceship
 * 
 * @version 1.0
 */
    public class AISpaceship extends Sprite {

// /////////////////////////////////////////////////////////////////////////
// Properties
// /////////////////////////////////////////////////////////////////////////

/**
 * AI control behaviour
 */

/**
 * Acceleration with which the spaceship can move along
 * the x-axis
 */
private float RUN_ACCELERATION = 150.0f;

public enum ShipBehaviour {
    Turret, Seeker
}

private boolean visible;

private ShipBehaviour mShipBehaviour;

/**
 * Distance at which the spaceship should avoid other game objects
 */
private float separateThresholdShip = 75.0f;
private float separateThresholdAsteroid = 125.0f;

/**
 * Accumulators used to build up the net steering outcome
 */
private Vector2 accAccumulator = new Vector2();
private Vector2 accComponent = new Vector2();



// /////////////////////////////////////////////////////////////////////////
// Constructors
// /////////////////////////////////////////////////////////////////////////

/**
 * Create a AI controlled spaceship
 * 
 * @param startX
 *            x location of the AI spaceship
 * @param startY
 *            y location of the AI spaceship
 * @param shipBehaviour
 *            Steering behaviour to be used by the AI ship
 * @param gameScreen
 *            Gamescreen to which AI belongs
 */

public AISpaceship(float startX, float startY, ShipBehaviour shipBehaviour,
        SteeringDemoGameScreen gameScreen) {
    super(startX, startY, 50.0f, 50.0f, null, gameScreen);

    mShipBehaviour = shipBehaviour;

    visible = true;

    switch (mShipBehaviour) {
    case Turret:
        maxAcceleration = 0.0f;
        maxVelocity = 0.0f;
        mBitmap = gameScreen.getGame().getAssetManager().getBitmap("Turret");
        break;
    case Seeker:
        maxAcceleration = -40.0f;
        maxVelocity = 50.0f;
        mBitmap = gameScreen.getGame().getAssetManager().getBitmap("enemy sprites 7");
        break;
    }
}

// /////////////////////////////////////////////////////////////////////////
// Methods
// /////////////////////////////////////////////////////////////////////////

/*
 * (non-Javadoc)
 * 
 * @see
 * uk.ac.qub.eeecs.gage.world.Sprite#update(uk.ac.qub.eeecs.gage.engine.
 * ElapsedTime)
 */
@Override
public void update(ElapsedTime elapsedTime) {

    switch (mShipBehaviour) {
    case Seeker:
        //Move down towards the player in a straight line
        acceleration.y = RUN_ACCELERATION;

        // Seek towards the player

        // Try to avoid a collision with the playership


        // Try to avoid a collision with the other spaceships           


        // Try to avoid a collision with the asteroids
        SteeringBehaviours.separate(this,
                ((SteeringDemoGameScreen) mGameScreen).getAsteroids(),
                separateThresholdAsteroid, 1.0f, accComponent);
        accAccumulator.add(accComponent);

        // If we are trying to avoid a collision then combine
        // it with the seek behaviour, placing more emphasis on
        // avoiding the collision.          
        if (!accAccumulator.isZero()) {
            acceleration.x = 0.3f * acceleration.x + 0.7f
                    * accAccumulator.x;
            acceleration.y = 0.3f * acceleration.y + 0.7f
                    * accAccumulator.y;
        }

        // Make sure we point in the direction of travel.

        break;
    }

    // Call the sprite's superclass to apply the determine accelerations
    super.update(elapsedTime);

    // Check that our new position has not collided by one of the
    // defined projectiles. If so, then removing any overlap and
    // ensure a valid velocity.
    checkForAndResolveCollisions(projectiles);      
}

/**
 * Check for and then resolve any collision between the AiShip and the
 * player projectiles.
 * 
 * @param projectiles
 *            Array of projectiles to test for collision against
 */
private void checkForAndResolveCollisions(GameObject[] projectiles) {

    CollisionType collisionType;

    // Consider each platform for a collision
    for (GameObject projectile : projectiles) {
        collisionType = 
                CollisionDetector.determineAndResolveCollision(this, Projectile);

        switch (collisionType) {
        case destroy:
            visible = false;
            break;
        }
    }

}

}

Projectile1(该类用于确定所有游戏的射弹及其行为)。

package uk.ac.qub.eeecs.game.spaceDemo;

import uk.ac.qub.eeecs.gage.ai.SteeringBehaviours;
import uk.ac.qub.eeecs.gage.engine.ElapsedTime;
import uk.ac.qub.eeecs.gage.util.Vector2;
import uk.ac.qub.eeecs.gage.world.Sprite;

/**
 * AI controlled spaceship
 * 
 * @version 1.0
 */
public class Projectile1 extends Sprite {

    // /////////////////////////////////////////////////////////////////////////
    // Properties
    // /////////////////////////////////////////////////////////////////////////

    /**
     * AI control behaviour
     */

    /**
     * Acceleration with which the projectile can move along
     * the x-axis
     */
    private float RUN_ACCELERATION = 150.0f;


    public enum ShipBehaviour {
        bullet
    }

    private ShipBehaviour mShipBehaviour;

    /**
     * Distance at which the spaceship should avoid other game objects
     */


    /**
     * Accumulators used to build up the net steering outcome
     */
    private Vector2 accAccumulator = new Vector2();
    private Vector2 accComponent = new Vector2();

    // /////////////////////////////////////////////////////////////////////////
    // Constructors
    // /////////////////////////////////////////////////////////////////////////

    /**
     * Create a AI controlled spaceship
     * 
     * @param startX
     *            x location of the AI spaceship
     * @param startY
     *            y location of the AI spaceship
     * @param shipBehaviour
     *            Steering behaviour to be used by the AI ship
     * @param gameScreen
     *            Gamescreen to which AI belongs
     */
    public Projectile1(float startX, float startY, ShipBehaviour shipBehaviour,
            SteeringDemoGameScreen gameScreen) {
        super(startX, startY, 50.0f, 50.0f, null, gameScreen);

        mShipBehaviour = shipBehaviour;

        switch (mShipBehaviour) {
        case bullet:
            maxAcceleration = 20.0f;
            maxVelocity = 30.0f;
            mBitmap = gameScreen.getGame().getAssetManager().getBitmap("Spaceship2");
            break;

        }
    }

    // /////////////////////////////////////////////////////////////////////////
    // Methods
    // /////////////////////////////////////////////////////////////////////////

    /*
     * (non-Javadoc)
     * 
     * @see
     * uk.ac.qub.eeecs.gage.world.Sprite#update(uk.ac.qub.eeecs.gage.engine.
     * ElapsedTime)
     */
    @Override
    public void update(ElapsedTime elapsedTime) {

        switch (mShipBehaviour) {
        case bullet:
            // Seek towards the player

                acceleration.y = RUN_ACCELERATION;




            break;
        }

        // Call the sprite's superclass to apply the determine accelerations
        super.update(elapsedTime);
    }
}

SterringGameDemo(玩游戏发生级别的主要类别以及玩家,敌人和射弹的行为和相互作用的位置(注意 - 它被称为“SteeringGameDemo”,因为这是我们使用的模板的剩余部分帮助创建课程并且尚未重命名))。

package uk.ac.qub.eeecs.game.spaceDemo;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import uk.ac.qub.eeecs.gage.Game;
import uk.ac.qub.eeecs.gage.engine.AssetStore;
import uk.ac.qub.eeecs.gage.engine.ElapsedTime;
import uk.ac.qub.eeecs.gage.engine.graphics.IGraphics2D;
import uk.ac.qub.eeecs.gage.util.BoundingBox;
import uk.ac.qub.eeecs.gage.util.CollisionDetector;
import uk.ac.qub.eeecs.gage.world.GameObject;
import uk.ac.qub.eeecs.gage.world.GameScreen;
import uk.ac.qub.eeecs.gage.world.LayerViewport;
import uk.ac.qub.eeecs.gage.world.ScreenViewport;
import android.graphics.Color;

/**
 * Simple steering game world 
 * 
 * @version 1.0
 */
public class SteeringDemoGameScreen extends GameScreen {

    // /////////////////////////////////////////////////////////////////////////
    // Properties
    // /////////////////////////////////////////////////////////////////////////

    /**
     * Width and height of the level 
     */
    private final float LEVEL_WIDTH = 480.0f;
    private final float LEVEL_HEIGHT = 280.0f;

    /**
     * Define viewports for this layer and the associated screen projection
     */
    private ScreenViewport mScreenViewport;
    private LayerViewport mLayerViewport;

    /**
     * Define a background object, alongside a player controlled
     * space ship and separate lists of asteroids and AI controlled
     * space ships.
     */

    private GameObject mSpaceBackground;

    private PlayerSpaceship mPlayerSpaceship;


    private final int NUM_ASTEROIDS = 0;
    private List<Asteroid> mAsteroids;

    private final int NUM_SEEKERS = 2;
    private final int NUM_TURRETS = 1;
    private final int NUM_PROJECTILE = 1;
    private List<Projectile1> mProjectile1;
    private List<AISpaceship> mAISpaceships;

    // /////////////////////////////////////////////////////////////////////////
    // Constructors
    // /////////////////////////////////////////////////////////////////////////

    /**
     * Create a simple steering game world
     * 
     * @param game
     *            Game to which this screen belongs
     */
    public SteeringDemoGameScreen(Game game) {
        super("SteeringDemoGameScreen", game);

        // Create the screen viewport
        mScreenViewport = new ScreenViewport(0, 0, game.getScreenWidth(),
                game.getScreenHeight());

        // Create the layer viewport, taking into account the orientation
        // and aspect ratio of the screen.
        if (mScreenViewport.width > mScreenViewport.height)
            mLayerViewport = new LayerViewport(240.0f, 240.0f
                    * mScreenViewport.height / mScreenViewport.width, 240,
                    240.0f * mScreenViewport.height / mScreenViewport.width);
        else
            mLayerViewport = new LayerViewport(240.0f * mScreenViewport.height
                    / mScreenViewport.width, 240.0f, 240.0f
                    * mScreenViewport.height / mScreenViewport.width, 240);

        // Load in the assets used by the steering demo
        AssetStore assetManager = mGame.getAssetManager();
        assetManager.loadAndAddBitmap("Space BG 2", "img/Space BG 2.png");      
        assetManager.loadAndAddBitmap("Asteroid1", "img/Asteroid1.png");
        assetManager.loadAndAddBitmap("Asteroid2", "img/Asteroid2.png");
        assetManager.loadAndAddBitmap("enemy sprites 7", "img/enemy sprites 7.png");
        assetManager.loadAndAddBitmap("Spaceship2", "img/Spaceship2.png");
        assetManager.loadAndAddBitmap("Spaceship3", "img/Spaceship3.png");
        assetManager.loadAndAddBitmap("Spaceship3", "img/Spaceship3.png");
        assetManager.loadAndAddBitmap("Player sprite", "img/Player sprite.png");
        assetManager.loadAndAddBitmap("Turret", "img/Turret.png");

        // Create the space background
        mSpaceBackground = new GameObject(LEVEL_WIDTH / 2.0f,
                LEVEL_HEIGHT / 2.0f, LEVEL_WIDTH, LEVEL_HEIGHT, getGame()
                        .getAssetManager().getBitmap("Space BG 2"), this);

        // Create the player spaceship
        mPlayerSpaceship = new PlayerSpaceship(230, 10, this);



        // Create a number of randomly positioned asteroids
        Random random = new Random();
        mAsteroids = new ArrayList<Asteroid>(NUM_ASTEROIDS);
        for (int idx = 0; idx < NUM_ASTEROIDS; idx++)
            mAsteroids.add(new Asteroid(random.nextFloat() * LEVEL_WIDTH, random.nextFloat() * LEVEL_HEIGHT, this));


        // Create a number of randomly positioned AI controlled ships
        mAISpaceships = new ArrayList<AISpaceship>(NUM_SEEKERS + NUM_TURRETS);
        for (int idx = 0; idx < NUM_SEEKERS; idx++)
            mAISpaceships.add(new AISpaceship(random.nextFloat() * LEVEL_WIDTH,
                    180 + random.nextFloat() * LEVEL_HEIGHT,
                    AISpaceship.ShipBehaviour.Seeker, this));
        for (int idx = 0; idx < NUM_TURRETS; idx++)
            mAISpaceships.add(new AISpaceship(random.nextFloat() * LEVEL_WIDTH,
                    random.nextFloat() * LEVEL_HEIGHT,
                    AISpaceship.ShipBehaviour.Turret, this));

        //Use the above to help spawn the bullets
        mProjectile1 = new ArrayList<Projectile1>(NUM_PROJECTILE);
        for (int idx = 0; idx < NUM_PROJECTILE; idx++)
        mProjectile1.add(new Projectile1(mPlayerSpaceship.position.x, mPlayerSpaceship.position.y,
                Projectile1.ShipBehaviour.bullet, this));

    }

    // /////////////////////////////////////////////////////////////////////////
    // Support methods
    // /////////////////////////////////////////////////////////////////////////

    /**
     * Return the player spaceship 
     * 
     * @return Player spaceship
     */ 
    public PlayerSpaceship getPlayerSpaceship() {
        return mPlayerSpaceship;
    }

    public List<Projectile1> getProjectile1() {
        return mProjectile1;
    }

    /**
     * Return a list of the AI spaceships in the level
     * 
     * @return List of AI controlled spaceships
     */
    public List<AISpaceship> getAISpaceships() {
        return mAISpaceships;
    }

    /**
     * Return a list of asteroids in the the level
     * 
     * @return List of asteroids in the level
     */
    public List<Asteroid> getAsteroids() {
        return mAsteroids;
    }

    // /////////////////////////////////////////////////////////////////////////
    // Update and Draw methods
    // /////////////////////////////////////////////////////////////////////////

    /*
     * (non-Javadoc) fs
     * 
     * @see
     * uk.ac.qub.eeecs.gage.world.GameScreen#update(uk.ac.qub.eeecs.gage.engine
     * .ElapsedTime)
     */
    @Override
    public void update(ElapsedTime elapsedTime) {

        // Update the player spaceship
        mPlayerSpaceship.update(elapsedTime);

        // Ensure the player cannot leave the confines of the world
        BoundingBox playerBound = mPlayerSpaceship.getBound();
        if (playerBound.getLeft() < 0)
            mPlayerSpaceship.position.x -= playerBound.getLeft();
        else if (playerBound.getRight() > LEVEL_WIDTH)
            mPlayerSpaceship.position.x -= (playerBound.getRight() - LEVEL_WIDTH);

        if (playerBound.getBottom() < 0)
            mPlayerSpaceship.position.y -= playerBound.getBottom();
        else if (playerBound.getTop() > LEVEL_HEIGHT)
            mPlayerSpaceship.position.y -= (playerBound.getTop() - LEVEL_HEIGHT);

        // Ensure the enemyships cannot leave the confines of the world


        //Use the above for player and enemies bullets in this class


        //IMPORTANT - THE below code is VITAL for the collision detection and was a
                //added by the tutor. It calls the bounding box and collision detector for the
                //player and enemy ship. Add this to the above section where the bounding box
                // is already called, just below the update method.
                BoundingBox playersBound = mPlayerSpaceship.getBound();
                for (AISpaceship aiSpaceship : mAISpaceships) {
                    BoundingBox aiBound = aiSpaceship.getBound();
                    if(CollisionDetector.isCollision(playersBound, aiBound)) {


                    }
                }


        // Focus the layer viewport on the player


        // Ensure the viewport cannot leave the confines of the world
        if (mLayerViewport.getLeft() < 0)
            mLayerViewport.x -= mLayerViewport.getLeft();
        else if (mLayerViewport.getRight() > LEVEL_WIDTH)
            mLayerViewport.x -= (mLayerViewport.getRight() - LEVEL_WIDTH);

        if (mLayerViewport.getBottom() < 0)
            mLayerViewport.y -= mLayerViewport.getBottom();
        else if (mLayerViewport.getTop() > LEVEL_HEIGHT)
            mLayerViewport.y -= (mLayerViewport.getTop() - LEVEL_HEIGHT);

        // Update each of the AI controlled spaceships
        for (AISpaceship aiSpaceship : mAISpaceships)
            aiSpaceship.update(elapsedTime);

        // Update each of the asteroids
        for (Asteroid asteroid : mAsteroids)
            asteroid.update(elapsedTime);

        // Update each of the Player Projectile1
                for (Projectile1 projectile1 : mProjectile1)
                    projectile1.update(elapsedTime);


    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * uk.ac.qub.eeecs.gage.world.GameScreen#draw(uk.ac.qub.eeecs.gage.engine
     * .ElapsedTime, uk.ac.qub.eeecs.gage.engine.graphics.IGraphics2D)
     */
    @Override
    public void draw(ElapsedTime elapsedTime, IGraphics2D graphics2D) {

        // Create the screen to black and define a clip based on the viewport
        graphics2D.clear(Color.BLACK);
        graphics2D.clipRect(mScreenViewport.toRect());

        // Draw the background first of all
        mSpaceBackground.draw(elapsedTime, graphics2D, mLayerViewport,
                mScreenViewport);

        // Draw each of the asteroids
        for (Asteroid asteroid : mAsteroids)
            asteroid.draw(elapsedTime, graphics2D, mLayerViewport,
                    mScreenViewport);

        // Draw each of the AI controlled spaceships
                for (Projectile1 projectile1 : mProjectile1)
                    projectile1.draw(elapsedTime, graphics2D, mLayerViewport,
                            mScreenViewport);

        // Draw each of the AI controlled spaceships
        for (AISpaceship aiSpaceship : mAISpaceships)
            aiSpaceship.draw(elapsedTime, graphics2D, mLayerViewport,
                    mScreenViewport);

        // Draw the player
        mPlayerSpaceship.draw(elapsedTime, graphics2D, mLayerViewport,
                mScreenViewport);


    }
}

我再次向所有能提供帮助的人表示感谢。

1 个答案:

答案 0 :(得分:0)

之前我做过类似的事。 尝试为每个子弹,敌人或任何你拥有的东西创建一个rectangle。矩形的大小应与所用图形的大小相当。当然,矩形必须与图形一起移动。

您可以使用

检查是否发生了碰撞
if(rectangleA.intersects(rectangleB)){
    doAwesomeStuff();
}

我希望有所帮助。