简体   繁体   English

多个矩形的Java 2D Platformer碰撞检测

[英]Java 2D Platformer Collision Detection for multiple Rectangles

I am working on a 2D platformer in Java for an assignment. 我正在用Java开发2D平台程序进行作业。 The assignment specifies I must use an abstract shape class to draw shapes. 作业指定我必须使用抽象形状类来绘制形状。 The problem I am having is getting my collision detection to work with multiple Rectangle Objects which I am using as platforms - I store these in a list. 我遇到的问题是使碰撞检测与作为平台使用的多个Rectangle Objects一起工作-我将它们存储在列表中。 At the moment my collision detection will move my player regardless of which platform I have collided with, so if I collide with a platform from the right it will move me to the top of that platform because it's still checking another platform below me, and will assume I've hit that, therefore moving me to the top of the platform. 目前,无论我与哪个平台发生碰撞,碰撞检测都将移动我的玩家,因此,如果我从右侧与一个平台碰撞,它将使我移动到该平台的顶部,因为它仍在检查我下面的另一个平台,并且会假设我已经达到目标,因此将我带到平台的顶部。 I was wondering how I can change this so that my collision detection also detects which platform I have collided with and collide relative to that platform (as opposed to every platform). 我想知道如何更改此设置,以便碰撞检测还可以检测到与哪个平台发生碰撞并相对于该平台(相对于每个平台)发生碰撞的情况。

Here's what is currently happening: 这是当前正在发生的事情: 在此处输入图片说明

Expected Output: 预期产量:

My player should stop where it is when colliding with platforms. 与平台碰撞时,我的播放器应该停在原地。

My App class: 我的应用程式类别:

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

My input handling class: 我的输入处理类:

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



}

My Player class: 我的玩家班:

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


    }
}

My Rectangle class: 我的矩形课:

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

    }
}

First, define ColorRectangle class that extends Shape and provide logic for drawing: 首先,定义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, define separate class for represent Player and Platform : 其次,为表示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, define class that contains logic of demo application. 第三,定义包含演示应用程序逻辑的类。 Actually, you could split logic for demo and logic for board (including actiona and key listeners), but these classes are very simple, so in given case, no need to split it. 实际上,您可以拆分用于演示的逻辑和用于开发板的逻辑(包括actiona和按键侦听器),但是这些类非常简单,因此在给定的情况下,无需拆分它。

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

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

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