java - 从 Java 小程序移植到 Android 应用程序后,碰撞检测系统无法工作

标签 java android collision-detection

因为我一直在移植我使用tutorials制作的java小程序从 xda 开发网站我遇到了很多问题。我一直在努力把事情一件一件地解决,以尽量减少错误。这个碰撞检测问题已被证明是我无法解决的问题。它的工作方式是在主 Sprite 发射的子弹上以及敌人周围放置矩形。当矩形相交时,子弹应该消失,敌人应该死亡。

有消息告诉我 android 的矩形函数可能是一个问题。如图this链接,有四种不同的交叉测试。我的碰撞检测系统代码本质上与教程中使用的代码相同。另外,我什至不确定矩形是否位于正确的位置,是否位于屏幕上,因为我无法使用“drawRect”函数绘制矩形。元组值应该是正确的,因为所有内容都是从桌面游戏版本复制的。

编辑:所有内容都是从桌面版本复制的,但我必须更改与矩形有关的所有内容,因为我无法再使用 java.awt.Rectangle。所有与矩形相关的代码都使用android.graphics.Rect。

tl;dr:从 Java 小程序到 Android 应用程序的碰撞检测仅进行微小的更改将无法工作。

这是移植的代码:

package com.kilobolt.robotgame;

import android.graphics.Rect;

public class Projectile {

    private int x, y, speedY;
    private boolean visible;

    private Rect r;

    public Projectile(int startX, int startY) 
    {
        x = startX;
        y = startY;
        speedY = 7;
        visible = true;

        r = new Rect(0,0,0,0);
    }

    public void update()
    {
        y -= speedY;
        r.set(x, y, 4, 10);
        if (y < 0) {
           visible = false;
           r=null;
        }
        if (visible){
            checkCollision();
        }
    }

    private void checkCollision()
    {
        if(Rect.intersects(r, GameScreen.xguy1.xrect1) && GameScreen.xguy1IsAlive == true)
        {
        visible = false;
        GameScreen.score += 10;
        GameScreen.xguy1IsAlive = false;
        System.out.println("1st enemy Collision");
        }
        else if(Rect.intersects(r, GameScreen.xguy2.xrect2) && GameScreen.xguy2IsAlive == true)
        {
            visible = false;
            GameScreen.score += 10;
            GameScreen.xguy2IsAlive = false;
            System.out.println("2nd enemy Collision - RIGHT");
        }
        else if(Rect.intersects(r, GameScreen.xguy3.xrect3) && GameScreen.xguy3IsAlive == true)
        {
            visible = false;
            GameScreen.score += 10;
            GameScreen.xguy3IsAlive = false;
            System.out.println("3rd enemy Collision");
        }

        if(GameScreen.xguy1IsAlive == false && GameScreen.xguy2IsAlive == false 
                && GameScreen.xguy3IsAlive == false)
        {
            GameScreen.allEnemiesAreDead = true;
        }

//      if(r.intersect(GameScreen.saucer.sRect))
//      {
//          visible = false;
//          GameScreen.score += 100;
//          GameScreen.saucerIsAlive = false;
//          System.out.println("you hit the alien!");
//      }

    }


    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public int getSpeedY() {
        return speedY;
    }

    public boolean isVisible() {
        return visible;
    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    public void setSpeedY(int speedY) {
        this.speedY = speedY;
    }

    public void setVisible(boolean visible) {
        this.visible = visible;
    }

}

...................................................... ....

package com.kilobolt.robotgame;

import android.graphics.Rect;
import java.util.ArrayList;

public class Enemy 
{
    private int maxHealth, currentHealth, power, speedX, speedY, centerX, centerY;
    private Background bg = GameScreen.getBg1();
    public  Rect xrect1 = new Rect(0,0,0,0);
    public  Rect xrect2 = new Rect(0,0,0,0);
    public  Rect xrect3 = new Rect(0,0,0,0);
    private boolean isMovingRight = true;
    private boolean isMovingLeft = false;
    private boolean xguy1IsShooting = false;
    private boolean xguy2IsShooting = false;
    private boolean xguy3IsShooting = false;
//  private ArrayList<EnemyProjectile> eProjectiles = new ArrayList<EnemyProjectile>();

    //Behavioral Methods
    public void update() {
    //centerX += speedY;
    //moveRight();
    //moveLeft();
    //changeMovement();
    //autoFire();
    speedY = bg.getSpeedY();
    speedX = 1;
    //setBounds??? 
    xrect1.set(centerX + 74, centerY - 18, 14, 14);
    xrect2.set(centerX + 134, centerY - 18, 14, 14); 
    xrect3.set(centerX + 19 , centerY - 18, 14, 14);
    }

//  public void autoFire()
//  {
//      int num = 1 + (int)(Math.random() * ((250 - 1) + 1));
//      //System.out.println(num);
//      if(num == 4 || num == 6 || num == 8 && xguy1IsShooting == false)
//      {
//          if(GameScreen.xguy1IsAlive == true)
//          {
//              //xguy1Attack();
//          }
//      }
//      if(num == 1 || num == 3 || num == 5 && xguy2IsShooting == false)
//      {
//          if(GameScreen.xguy2IsAlive == true)
//          {
//              //xguy2Attack();
//          }
//      }
//      if(num == 12 || num == 15 || num == 17 && xguy3IsShooting == false)
//      {
//          if(GameScreen.xguy3IsAlive == true)
//          {
//              //xguy3Attack();
//          }
//      }
//  }

    public void moveRight()
    {
        if(isMovingRight == true)
        {
            centerX += speedX;
            if(centerX >= 630)
            {
                isMovingRight = false;
                isMovingLeft = true;
            }
        }
    }
    public void moveLeft()
    {
        if(isMovingLeft == true)
        {
            centerX -= speedX;
            if(centerX <= 10)
            {
                isMovingLeft = false;
                isMovingRight = true;
            }
        }
    }
    public void changeMovement()
    {
        //causes delayed death - xguys only die after going right
        if(centerX >= 630)
        {
            isMovingRight = false;
        }
        if(isMovingRight == false)
        {
            isMovingLeft = true;
        }
    }
    public void die() 
    {

    }
//  public void xguy1Attack() 
//  {
//      EnemyProjectile e = new EnemyProjectile(centerX - 10, centerY - 6);
//      eProjectiles.add(e);
//      xguy1IsShooting = false;
//  }
//  public void xguy2Attack()
//  {
//      EnemyProjectile e = new EnemyProjectile(centerX + 50, centerY - 6);
//      eProjectiles.add(e);
//      xguy2IsShooting = false;
//  }
//  
//  public void xguy3Attack()
//  {
//      EnemyProjectile e = new EnemyProjectile(centerX - 70, centerY - 6);
//      eProjectiles.add(e);
//      xguy3IsShooting = false;
//  }

    public int getMaxHealth() {
        return maxHealth;
    }

    public int getCurrentHealth() {
        return currentHealth;
    }

    public int getPower() {
        return power;
    }

    public int getSpeedY() {
        return speedY;
    }

    public int getCenterX() {
        return centerX;
    }

    public int getCenterY() {
        return centerY;
    }

    public Background getBg() {
        return bg;
    }

    public void setMaxHealth(int maxHealth) {
        this.maxHealth = maxHealth;
    }

    public void setCurrentHealth(int currentHealth) {
        this.currentHealth = currentHealth;
    }

    public void setPower(int power) {
        this.power = power;
    }

    public void setSpeedX(int speedX) {
        this.speedY = speedX;
    }

    public void setCenterX(int centerX) {
        this.centerX = centerX;
    }

    public void setCenterY(int centerY) {
        this.centerY = centerY;
    }

    public void setBg(Background bg) {
        this.bg = bg;
    }

//  public ArrayList getEProjectiles() {
//      return eProjectiles;
//      }
}

...................................................... ........

package com.kilobolt.robotgame;

import com.kilobolt.robotgame.BasicEnemy;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import android.graphics.Color;
import android.graphics.Paint;

import com.kilobolt.framework.Game;
import com.kilobolt.framework.Graphics;
import com.kilobolt.framework.Image;
import com.kilobolt.framework.Input.TouchEvent;
import com.kilobolt.framework.Screen;

public class GameScreen extends Screen {
    enum GameState {
        Ready, Running, Paused, GameOver
    }

    GameState state = GameState.Ready;

    // Variable Setup

    private static Background bg1, bg2;
    private static Ship ship;
    public static BasicEnemy xguy1, xguy2, xguy3;
//
    private Image character, damaged1, damaged2, background, startScreen, xguy, vxguy, explode1, explode2, explode3, explode4, explode5,
    explode6, explode7, explode8, explode9, explode10, explode11, explode12, xexplode, xexplode2, flyingSaucer;
    private Animation anim, xanim;

    public static int score = 0;
    public static int lives = 3;

    static boolean xguy1IsAlive = true;
    static boolean xguy2IsAlive = true;
    static boolean xguy3IsAlive = true;

    static boolean saucerIsAlive = true;
    static boolean allEnemiesAreDead = false;

    static boolean saucerTime = false;
    static boolean saucerIsMoving = false; 
    static boolean startScreenOn = true;

    Paint paint, paint2;

    public GameScreen(Game game) {
        super(game);

        // Initialize game objects here

        bg1 = new Background(0, 0);
        bg2 = new Background(0, -480);
        ship = new Ship();
        xguy1 = new BasicEnemy(420, 100);
        xguy2 = new BasicEnemy(480, 100);
        xguy3 = new BasicEnemy(360, 100);

        character = Assets.character;
        damaged1 = Assets.character2;
        damaged1 = Assets.character3;

        xguy = Assets.xguy;

        xanim = new Animation();
        xanim.addFrame(xguy, 250);
        xanim.addFrame(vxguy, 250);

        // Defining a paint object
        paint = new Paint();
        paint.setTextSize(30);
        paint.setTextAlign(Paint.Align.CENTER);
        paint.setAntiAlias(true);
        paint.setColor(Color.WHITE);

        paint2 = new Paint();
        paint2.setTextSize(100);
        paint2.setTextAlign(Paint.Align.CENTER);
        paint2.setAntiAlias(true);
        paint2.setColor(Color.WHITE);

    }


    @Override
    public void update(float deltaTime) {
        List<TouchEvent> touchEvents = game.getInput().getTouchEvents();

        if (state == GameState.Ready)
            updateReady(touchEvents);
        if (state == GameState.Running)
            updateRunning(touchEvents, deltaTime);
        if (state == GameState.Paused)
            updatePaused(touchEvents);
        if (state == GameState.GameOver)
            updateGameOver(touchEvents);
    }

    private void updateReady(List<TouchEvent> touchEvents) {

        // This example starts with a "Ready" screen.
        // When the user touches the screen, the game begins.
        // state now becomes GameState.Running.
        // Now the updateRunning() method will be called!

        if (touchEvents.size() > 0)
            state = GameState.Running;
    }

    private void updateRunning(List<TouchEvent> touchEvents, float deltaTime) {

        // This is identical to the update() method

        // 1. All touch input is handled here:
        int len = touchEvents.size();
        for (int i = 0; i < len; i++) {
            TouchEvent event = touchEvents.get(i);
            if (event.type == TouchEvent.TOUCH_DOWN) {

                if (inBounds(event, 735, 415, 65, 65)) {
                    ship.moveRight();
                    ship.setMovingRight(true);
                    System.out.println("sucess");
                }
                if (inBounds(event, 0, 415, 65, 65)) {
                    ship.moveLeft();
                    ship.setMovingLeft(true);
                    System.out.println("sucess");
                }               
                else if (inBounds(event, 0, 350, 65, 65)) {
                    ship.shoot();
                }
                else if (inBounds(event, 735, 350, 65, 65)) {
                    ship.shoot();
                }
//              else if (inBounds(event, 0, 415, 65, 65)
//                      ) {
////                    currentSprite = Assets.characterDown;
////                    robot.setDucked(true);
////                    robot.setSpeedX(0);
//
//              }

                if (event.x > 400) {
                    //...

                }

            }

            if (event.type == TouchEvent.TOUCH_UP) {

                if (inBounds(event, 0, 415, 65, 65)) {
//                  //...

                }
                if (inBounds(event, 735, 415, 65, 65)) {
                    ship.stopRight();
                }
                if (inBounds(event, 0, 415, 65, 65)) {
                    ship.stopLeft();
                }

//              if (inBounds(event, 0, 0, 35, 35)) {
//                  pause();
//
//              }

                if (event.x > 400) {
                    //...
                }
            }

        }

        // 2. Check miscellaneous events like death:
//
//      if (livesLeft == 0) {
//          state = GameState.GameOver;
//      }

        // 3. Call individual update() methods here.
        // This is where all the game updates happen.
        ship.update();

        ArrayList projectiles = ship.getProjectiles();
        for (int i = 0; i < projectiles.size(); i++) {
            Projectile p = (Projectile) projectiles.get(i);
            if (p.isVisible() == true) {
                p.update();
            } else {
                projectiles.remove(i);
            }
        }


        xguy1.update();
        xguy2.update();
        xguy3.update();
        bg1.update();
        bg2.update();
        animate();
//...game over state here...
    }

    private boolean inBounds(TouchEvent event, int x, int y, int width,
            int height) {
        if (event.x > x && event.x < x + width - 1 && event.y > y
                && event.y < y + height - 1)
            return true;
        else
            return false;
    }

    private void updatePaused(List<TouchEvent> touchEvents) {
        int len = touchEvents.size();
        for (int i = 0; i < len; i++) {
            TouchEvent event = touchEvents.get(i);
            if (event.type == TouchEvent.TOUCH_UP) {
                if (inBounds(event, 0, 0, 800, 240)) {

                    if (!inBounds(event, 0, 0, 35, 35)) {
                        resume();
                    }
                }

                if (inBounds(event, 0, 240, 800, 240)) {
                    nullify();
                    goToMenu();
                }
            }
        }
    }

    private void updateGameOver(List<TouchEvent> touchEvents) {
        int len = touchEvents.size();
        for (int i = 0; i < len; i++) {
            TouchEvent event = touchEvents.get(i);
            if (event.type == TouchEvent.TOUCH_DOWN) {
                if (inBounds(event, 0, 0, 800, 480)) {
                    nullify();
                    game.setScreen(new MainMenuScreen(game));
                    return;
                }
            }
        }

    }

    @Override
    public void paint(float deltaTime) {
        Graphics g = game.getGraphics();

        g.drawImage(Assets.background, bg1.getBgX(), bg1.getBgY());
        g.drawImage(Assets.background, bg2.getBgX(), bg2.getBgY());

        ArrayList projectiles = ship.getProjectiles();
        for (int i = 0; i < projectiles.size(); i++) {
            Projectile p = (Projectile) projectiles.get(i);
            g.drawRect(p.getX()-34, p.getY()+10, 4, 10, Color.RED);
        }
//      // First draw the game elements.
//
        g.drawImage(Assets.character, ship.getCenterX() - 24,
                ship.getCenterY() - 24);
        if(xguy1IsAlive == true)
        {
            g.drawImage(xanim.getImage(), xguy1.getCenterX()-16, xguy1.getCenterY()-12);
        }
        if(xguy2IsAlive == true)
        {
            g.drawImage(xanim.getImage(), xguy2.getCenterX()-16, xguy2.getCenterY()-12);
        }
        if(xguy3IsAlive == true)
        {
            g.drawImage(xanim.getImage(), xguy3.getCenterX()-16, xguy3.getCenterY()-12);
        }
        g.drawRect(xguy1.getCenterX() + 74, xguy1.getCenterX() - 18, 14,  14, 0);

        // Example:
        // g.drawImage(Assets.background, 0, 0);
        // g.drawImage(Assets.character, characterX, characterY);

        // Secondly, draw the UI above the game elements.
        if (state == GameState.Ready)
            drawReadyUI();
        if (state == GameState.Running)
            drawRunningUI();
        if (state == GameState.Paused)
            drawPausedUI();
        if (state == GameState.GameOver)
            drawGameOverUI();

    }

    public void animate() {
        //anim.update(10);
        xanim.update(50);
    }

    private void nullify() {

        // Set all variables to null. You will be recreating them in the
        // constructor.
        paint = null;
        bg1 = null;
        bg2 = null;
        ship = null;
        xguy1 = null;
        xguy2 = null;
        xguy3 = null;
//      currentSprite = null;
        character = null;
        damaged1 = null;
        damaged2 = null;
        xguy = null;
        vxguy = null;
//      anim = null;
        xanim = null;

        // Call garbage collector to clean up memory.
        System.gc();

    }

    private void drawReadyUI() {
        Graphics g = game.getGraphics();

        g.drawARGB(155, 0, 0, 0);
        g.drawString("Tap to Start.", 400, 240, paint);

    }

    private void drawRunningUI() {
        Graphics g = game.getGraphics();
        g.drawImage(Assets.right, 735, 415, 0, 0, 65, 65);
        g.drawImage(Assets.left, 0, 415, 0, 0, 65, 65);
        g.drawImage(Assets.reticle, 0, 350, 0, 0, 65, 65);
        g.drawImage(Assets.reticle, 735, 350, 0, 0, 65, 65);
    }

    private void drawPausedUI() {
        Graphics g = game.getGraphics();
        // Darken the entire screen so you can display the Paused screen.
        g.drawARGB(155, 0, 0, 0);
        g.drawString("Resume", 400, 165, paint2);
        g.drawString("Menu", 400, 360, paint2);

    }

    private void drawGameOverUI() {
        Graphics g = game.getGraphics();
        g.drawRect(0, 0, 1281, 801, Color.BLACK);
        g.drawString("GAME OVER.", 400, 240, paint2);
        g.drawString("Tap to return.", 400, 290, paint);

    }

    @Override
    public void pause() {
        if (state == GameState.Running)
            state = GameState.Paused;

    }

    @Override
    public void resume() {
        if (state == GameState.Paused)
            state = GameState.Running;
    }

    @Override
    public void dispose() {

    }

    @Override
    public void backButton() {
        pause();
    }

    private void goToMenu() {
        // TODO Auto-generated method stub
        game.setScreen(new MainMenuScreen(game));

    }

    public static Background getBg1() {
        // TODO Auto-generated method stub
        return bg1;
    }

    public static Background getBg2() {
        // TODO Auto-generated method stub
        return bg2;
    }

    public static Ship getShip() {
        // TODO Auto-generated method stub
        return ship;
    }

}

最佳答案

我敢打赌,您的问题是由于 2 个矩形类之间的 API 差异造成的。

比较android.graphics.Rectjava.awt.Rectangle我发现了一些差异,例如方法参数的含义。

例如,android 矩形使用左和,awt 矩形使用左和宽度

在类 Projectile 函数 update 中的代码中,您调用 r.set(..) 并且我很确定您是传递宽度和高度作为最后一个参数,而不是右侧和底部。

所以你现有的代码:

r.set(x, y, 4, 10);

应移植到:

r.set(x, y, x+4, y+10);

关于java - 从 Java 小程序移植到 Android 应用程序后,碰撞检测系统无法工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17771142/

相关文章:

android - 从右到左语言的滑动标签布局

java - 通过扩展 Rectangle 类以使用其 contains 和 intersects 方法来实现碰撞检测

javascript - 动画期间的 jQuery 碰撞检测

java - 实现 onSaveInstanceState 并自定义它以在旋转屏幕后保存文本后应用程序崩溃

java - 错误消息 “Illegal Start of Expression”?

java - 静态和非静态访问值

java - 在 MPS 中运行原始文本文件

java - 如何在android中实现searchview过滤器?

android - 为什么objectAnimator不调用setter方法

java - 这个奇怪的区域减法问题的原因是什么?