简体   繁体   English

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

[英]Collision detection in a java based 2D space shooter game

The context behind the this question is that I am part of a small group working to create a small game on Android. 这个问题背后的背景是我是一个致力于在Android上创建小游戏的小团体的一员。 The game we have chosen to develop is a top-down 2D shooter where the player controls a spaceship that must defend itself from alien creatures that move towards the player from the top of the gamescreen, similar to space invader, but different in that they spawn in random patterns. 我们选择开发的游戏是一个自上而下的2D射击游戏,其中玩家控制一艘宇宙飞船必须保护自己免受从游戏屏幕顶部向玩家移动的外星生物的攻击,类似于太空入侵者,但不同之处在于它们会产生随机模式。

So far, we have been able to get the game running, have the player and enemies to spawn and move in the right direction, as well as the player's weapon which is labelled as "projectile" (although it currently just spawns on its own and not on the player command). 到目前为止,我们已经能够让游戏运行,让玩家和敌人产生并向正确的方向移动,以及玩家的武器被标记为“射弹”(尽管它目前只是自己产生并且不在播放器命令上)。 The issue we have though is that we are trying to set up a collision event in the code between the projectile and the enemies so that when they meet, the enemy and bullet both disappear. 我们遇到的问题是我们试图在射弹和敌人之间的代码中建立一个碰撞事件,这样当他们相遇时,敌人和子弹都会消失。

However, what we have currently written in the code does not seem to make this work, so I was wondering if perhaps anyone else could see where we are going wrong. 但是,我们目前在代码中编写的内容似乎并没有使这个工作,所以我想知道是否有其他人可以看到我们出错的地方。 I've listed the relevant classes of code below. 我在下面列出了相关的代码类。 We would greatly appreciate any help anyone can give. 我们非常感谢任何人都能给予的帮助。

Collision Detector class( Holds the behavoir for collision detection for all entities in the game). 碰撞检测器类(保持游戏中所有实体的碰撞检测行为)。

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 class (class used for emeny alien entities and their properties). 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 (The class used to determine all the game's projectiles and their behavoir). 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 (The main class for the level on which the game play occurs and where the player, enemies and projectiles behave and interact with each other (note-it is called "SteeringGameDemo" because this is a leftover from a template we used to help make the class and has not been renamed yet)). 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);


    }
}

Again, I say thank you to anyone who can help. 我再次感谢能够提供帮助的任何人。

I've done something similar before. 我之前做过类似的事。 Try to create a rectangle for every Bullet, Enemy or whatever you've got. 尝试为每个子弹,敌人或任何你拥有的东西创建一个矩形 The rectangles should have a size thats about the size of the graphics used. 矩形的大小应与所用图形的大小相当。 Of course the rectangles have to move with the graphics. 当然,矩形必须与图形一起移动。

You can check if a collision occured simply with 您可以检查是否发生了碰撞

if(rectangleA.intersects(rectangleB)){
    doAwesomeStuff();
}

I hope that helps. 我希望有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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