首页 文章

用于多个矩形的Java 2D平台碰撞检测

提问于
浏览
1

我正在使用Java中的2D平台进行分配 . 赋值指定我必须使用抽象形状类来绘制形状 . 我遇到的问题是让我的碰撞检测与我用作平台的多个矩形对象一起工作 - 我将它们存储在一个列表中 . 目前我的碰撞检测将移动我的播放器,无论我碰到哪个平台,所以如果我从右边的平台发生碰撞,它会将我移动到该平台的顶部,因为它仍在检查我下面的另一个平台,并且假设我已经达到了这一点,因此将我带到了平台的顶端 . 我想知道如何改变这一点,以便我的碰撞检测还能检测到我碰撞的平台并相对于该平台发生碰撞(与每个平台相对) .

这是目前正在发生的事情:

预期产出:

我的播放器应该在与平台发生碰撞时停在原处 .

我的App类:

package A2;

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;

public class App extends JFrame {

    public App() {
        final Player player = new Player(200, 100);

        final ArrayList<Rectangle> platforms = new ArrayList<>();

        platforms.add(new Rectangle(100, 500, 400 ,10));
        platforms.add(new Rectangle(500, 100, 10 ,400));




        JPanel mainPanel = new JPanel() {
            public void paintComponent(Graphics g) {
                super.paintComponent(g);
                player.draw(g);

                for(Rectangle r : platforms){
                    r.draw(g);
                }

            }
        };

        mainPanel.addKeyListener(new InputControl(this, player, platforms));
        mainPanel.setFocusable(true);
        add(mainPanel);

        setLayout(new GridLayout());
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setSize(600, 600);
    }

    public static void main(String[] args) {
        App app = new App();
        app.setVisible(true);
    }
}



abstract class Shape {
    public void draw(Graphics g) { }
}

我的输入处理类:

package A2;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;

import static java.awt.event.KeyEvent.*;

public class InputControl implements ActionListener, KeyListener {
    App app;
    Player player;
    Timer time = new Timer(5, this);
    ArrayList<Rectangle> platforms;
    ArrayList<Integer> keyList = new ArrayList<>();

    boolean keyReleased = false;
    boolean keyPressed = false;
    boolean[] keyUp = new boolean[256];
    boolean[] keyDown = new boolean[256];

    boolean topCollision = false;
    boolean rightCollision = false;
    boolean leftCollision = false;
    boolean botCollision = false;
    boolean onGround = false;

    private static final double GRAVITY = 2;
    private static final int MAX_FALL_SPEED = 5;

    double Xoverlap = 0;
    double Yoverlap = 0;
    boolean collision = false;



    public InputControl(App app, Player player, ArrayList<Rectangle> platforms) {
        this.app = app;
        this.player = player;
        this.platforms = platforms;
        time.start();
    }

    public void gravity(){
        if(player.yVelocity > MAX_FALL_SPEED){
            player.yVelocity = MAX_FALL_SPEED;
        }
        player.yVelocity += GRAVITY;
    }

    public void momentum(){}


    public void actionPerformed(ActionEvent e) {

        Rectangle2D offset = player.getOffsetBounds();

        for(int i = 0; i < platforms.size(); i++) {
            Rectangle r = platforms.get(i);
            //If collision
            if (offset.intersects(r.obj.getBounds2D())) {
                //Collision on Y axis
                if (offset.getX() + offset.getWidth() > r.obj.getX() &&
                        offset.getX() < r.obj.getX() + r.obj.getWidth() &&
                        offset.getY() + offset.getHeight() > r.obj.getY() &&
                        offset.getY() + player.yVelocity < r.obj.getY() + r.obj.getHeight()) {
                    player.y -= (offset.getY() + offset.getHeight()) - r.obj.getY();
                }
                //Collision on X axis
                if (offset.getX() + offset.getWidth() + player.xVelocity > r.obj.getX() &&
                        offset.getX() + player.xVelocity < r.obj.getX() + r.obj.getWidth() &&
                        offset.getY() + offset.getHeight() > r.obj.getY() &&
                        offset.getY() < r.obj.getY() + r.obj.getHeight()) {
                    player.x -= (offset.getX() + offset.getHeight()) - r.obj.getX();

                }
            }
            else {
                player.x += player.xVelocity;
                player.y += player.yVelocity;
            }
        }


        player.x += player.xVelocity;
        player.y += player.yVelocity;

        app.repaint();
    }

    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode() >= 0 && e.getKeyCode() < 256) {
            keyDown[e.getKeyCode()] = true;
            keyUp[e.getKeyCode()] = false;
            keyPressed = true;
            keyReleased = false;
        }
        if (keyDown[VK_UP]) {
            player.yVelocity = -1;

        }
        if (keyDown[VK_RIGHT]){
            player.xVelocity = 1;

        }
        if (keyDown[VK_LEFT]) {
            player.xVelocity = -1;

        }
        if (keyDown[VK_DOWN]) {
            player.yVelocity = 1;

        }
    }

    public void keyReleased(KeyEvent e) {
        if(e.getKeyCode() >= 0 && e.getKeyCode() < 256) {
            keyDown[e.getKeyCode()] = false;
            keyUp[e.getKeyCode()] = true;
            keyPressed = false;
            keyReleased = true;
        }
        if(keyUp[VK_RIGHT] || keyUp[VK_LEFT]){
            player.xVelocity = 0;
        }
        if(keyUp[VK_UP]){
            player.yVelocity = 0;
        }

    }
    public void keyTyped(KeyEvent e) { }



}

我的玩家类:

package A2;

import java.awt.*;
import java.awt.geom.Rectangle2D;

public class Player extends Shape {
    public double xVelocity;
    public double yVelocity;
    public double x;
    public double y;

    public double width = 60;
    public double height = 60;
    public double weight = 5;

    public  Rectangle2D obj;


    public Player(double x, double y) {
        this.x = x;
        this.y = y;
        obj = new Rectangle2D.Double(x, y, width, height);
    }

    public Rectangle2D getOffsetBounds(){
        return new Rectangle2D.Double( x, y, width, height);

    }

    public void draw(Graphics g) {
        Color c =new Color(1f,0f,0f,0.2f );
        obj = new Rectangle2D.Double(x, y, width, height);
        g.setColor(Color.BLACK);
        Graphics2D g2 = (Graphics2D)g;
        g2.fill(obj);
        g.drawString("(" + String.valueOf(x) + ", " + String.valueOf(y) + ")", 10, 20);
        g.drawString("X Speed: " + String.valueOf(xVelocity) + " Y Speed: " + String.valueOf(yVelocity) + ")", 10, 35);
        g.setColor(c);


    }
}

我的Rectangle类:

package A2;

import java.awt.*;
import java.awt.geom.Rectangle2D;

public class Rectangle extends Shape {
    public double width;
    public double height;
    public double x;
    public double y;
    boolean hasCollided = false;

    public Rectangle2D obj;

    public Rectangle(double x, double y, double width, double height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        obj = new Rectangle2D.Double(x, y, width, height);
    }

    public void draw(Graphics g) {
        g.setColor(Color.ORANGE);
        Graphics2D g2 = (Graphics2D)g;
        g2.fill(obj);

    }
}

1 回答

  • 0

    First, 定义 ColorRectangle 类,它扩展了 Shape 并为绘图提供了逻辑:

    // extends java.awt.Shape
    abstract class ColorRectangle extends Rectangle {
    
        private static final long serialVersionUID = -3626687047605407698L;
        private final Color color;
    
        protected ColorRectangle(int x, int y, int width, int height, Color color) {
            super(x, y, width, height);
            this.color = color;
        }
    
        public void draw(Graphics2D g) {
            g.setColor(color);
            g.fillRect(x, y, width, height);
        }
    }
    

    Second, 为表示 PlayerPlatform 定义单独的类:

    public final class Player extends ColorRectangle {
    
        private static final long serialVersionUID = -3909362955417024742L;
    
        public Player(int width, int height, Color color) {
            super(0, 0, width, height, color);
        }
    }
    
    public final class Platform extends ColorRectangle {
    
        private static final long serialVersionUID = 6602359551348037628L;
    
        public Platform(int x, int y, int width, int height, Color color) {
            super(x, y, width, height, color);
        }
    
        public boolean intersects(Player player, int offsX, int offsY) {
            return intersects(player.x + offsX, player.y + offsY, player.width, player.height);
        }
    }
    

    Third, 定义包含演示应用程序逻辑的类 . 实际上,你可以为板(包括actiona和key listeners)拆分逻辑演示和逻辑,但是这些类非常简单,所以在给定的情况下,不需要拆分它 .

    public class CollisionDetectionDemo extends JFrame {
    
        public CollisionDetectionDemo() {
            setLayout(new GridLayout());
            add(new MainPanel());
            setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            setSize(600, 600);
        }
    
        private static class MainPanel extends JPanel implements ActionListener, KeyListener {
    
            private static final long serialVersionUID = 8771401446680969350L;
            private static final int OFFS = 5;
    
            private final Player player = new Player(60, 60, Color.BLACK);
            private final List<Platform> platforms = Arrays.asList(
                    new Platform(100, 500, 400, 10, Color.ORANGE),
                    new Platform(500, 100, 10, 410, Color.RED),
                    new Platform(150, 300, 100, 10, Color.BLUE),
                    new Platform(150, 100, 100, 10, Color.GREEN));
    
            private MainPanel() {
                player.x = 200;
                player.y = 200;
                new Timer(5, this).start();
    
                setFocusable(true);
                addKeyListener(this);
            }
    
            private void drawPlayerPosition(Graphics g) {
                g.setColor(Color.BLACK);
                g.drawString(String.format("(%d, %d)", player.x, player.y), 10, 20);
            }
    
            private void movePlayer(int offsX, int offsY) {
                if (!intersects(player, offsX, offsY)) {
                    player.x += offsX;
                    player.y += offsY;
                }
            }
    
            private boolean intersects(Player player, int offsX, int offsY) {
                for (Platform platform : platforms)
                    if (platform.intersects(player, offsX, offsY))
                        return true;
    
                return false;
            }
    
            @Override
            public void paintComponent(Graphics g) {
                super.paintComponent(g);
    
                Color color = g.getColor();
                drawPlayerPosition(g);
                player.draw((Graphics2D)g);
                platforms.forEach(platform -> platform.draw((Graphics2D)g));
                g.setColor(color);
            }
    
            @Override
            public void actionPerformed(ActionEvent event) {
                repaint();
            }
    
            @Override
            public void keyTyped(KeyEvent event) {
            }
    
            @Override
            public void keyPressed(KeyEvent event) {
                if (event.getKeyCode() == VK_UP)
                    movePlayer(0, -OFFS);
                else if (event.getKeyCode() == VK_DOWN)
                    movePlayer(0, OFFS);
                else if (event.getKeyCode() == VK_LEFT)
                    movePlayer(-OFFS, 0);
                else if (event.getKeyCode() == VK_RIGHT)
                    movePlayer(OFFS, 0);
            }
    
            @Override
            public void keyReleased(KeyEvent event) {
            }
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> new CollisionDetectionDemo().setVisible(true));
        }
    }
    

相关问题