复杂形状的碰撞检测 [英] Collision detection with complex shapes

查看:27
本文介绍了复杂形状的碰撞检测的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想制作一个游戏,每个关卡都从图像加载.我想在 Photoshop 中绘制整个关卡,然后将其设置为背景并让玩家在上面走动.我想要另一个不可见的图像越过顶部,它在我想要碰撞的所有地方都是黑色的.

我不想使用瓷砖的原因,因为矩形碰撞等会更容易,因为会有复杂的角落,而不是所有的东西都是矩形.

这是个好主意吗,是否可以轻松实现?这会占用大量 CPU 资源还是有更好的方法来做到这一点?

关卡图像

红色显示的障碍

解决方案

.. 会有复杂的角,并不是所有的东西都是矩形的.

这可以通过绘制和处理ShapeArea 实例来实现.E.G.

  • Yellow 是一个小动画播放器".
  • 图像的边界代表包含玩家路径的墙壁(它从它们反弹回来).
  • 障碍物未发生碰撞时涂成绿色,否则涂成红色.

import java.awt.*;导入 java.awt.event.*;导入 java.awt.geom.*;导入 java.awt.image.BufferedImage;导入 javax.swing.*;类形状碰撞{私有 BufferedImage img;私人区域[]障碍=新区域[4];私人区域墙;整数 x;输入 y;int xDelta = 3;int yDelta = 2;/** 判断两个Area实例是否相交的方法*/public boolean doAreasCollide(Area area1, Area area2) {布尔碰撞 = 假;区域碰撞 1 = 新区域(区域 1);碰撞1.减去(区域2);如果 (!collide1.equals(area1)) {碰撞=真;}区域碰撞 2 = 新区域(区域 2);碰撞2.减去(区域1);如果 (!collide2.equals(area2)) {碰撞=真;}返回碰撞;}形状碰撞(){整数 w = 400;整数 h = 200;img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);最终 JLabel imageLabel = new JLabel(new ImageIcon(img));x = w/2;y = h/2;//圆圈障碍 [0] = 新区域(新 Ellipse2D.Double(40, 40, 30, 30));int[] xTriangle = {330,360,345};int[] yTriangle = {60,60,40};//三角形障碍物[1] = 新区域(新多边形(xTriangle,yTriangle,3));int[] xDiamond = {60,80,60,40};int[] yDiamond = {120,140,​​160,140};//钻石障碍物[2] = 新区域(新多边形(xDiamond,yDiamond,4));int[] xOther = {360,340,360,340};int[] yOther = {130,110,170,150};//其他障碍[3] = 新区域(新多边形(xOther,yOther,4));墙壁 = 新区域(新矩形(0,0,w,h));ActionListener 动画 = 新 ActionListener() {@覆盖public void actionPerformed(ActionEvent e) {动画();imageLabel.repaint();}};定时器 timer = new Timer(50, animate);定时器开始();JOptionPane.showMessageDialog(null, imageLabel);定时器停止();}公共无效动画(){Graphics2D g = img.createGraphics();g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);g.setColor(Color.BLUE);g.fillRect(0, 0, img.getWidth(), img.getHeight());x+=xDelta;y+=yDelta;整数 s = 15;Area player = new Area(new Ellipse2D.Double(x, y, s, s));//边缘碰撞的酸测试;如果(doAreasCollide(玩家,墙壁)){if ( x+s>img.getWidth() || x<0 ) {xDelta *= -1;}if(y+s>img.getHeight() || y<0 ) {yDelta *= -1;}}g.setColor(颜色.橙色);对于(区域障碍物:障碍物){如果(doAreasCollide(障碍物,玩家)){g.setColor(Color.RED);} 别的 {g.setColor(Color.GREEN);}g.fill(障碍物);}g.setColor(Color.YELLOW);g.fill(玩家);g.dispose();}公共静态无效主(字符串 [] args){可运行 r = 新可运行(){@覆盖公共无效运行(){新的形状碰撞();}};//应该在 EDT 上创建和更新 Swing GUI//http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.htmlSwingUtilities.invokeLater(r);}}

编辑

<块引用>

让它检测所有的红色并将其设置为碰撞边界

在启动时,使用平滑锯齿状路径问题中的来源获得红色轮廓像素(参见 getOutline(Color target, BufferedImage bi) 方法).将该Area 存储为启动时的单一障碍.

I am wanting to make a game that has each level loaded from an image. I want to draw up the whole level in Photoshop, and then set it as the background and allow the player to walk over it. I want another invisible image to go over top which will be black in all places that I want to collide with.

The reason I don't want to use tiles, which are much easier with rectangle collision and such, is because there will be complex corners and not everything will be rectangle.

Is this a good idea, and is it possible to do easily? Would this be a big CPU hog or is there a better way to do this?

Level image

Obstacles shown in red

解决方案

..there will be complex corners and not everything will be rectangle.

This could be achieved by drawing and dealing with Shape and Area instances. E.G.

  • Yellow is a little animated 'player'.
  • The bounds of the image represent walls that contain the path of the player (it bounces off them).
  • Obstacles are painted green when not in collision, red otherwise.

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

class ShapeCollision {

    private BufferedImage img;
    private Area[] obstacles = new Area[4];
    private Area walls;

    int x; 
    int y;
    int xDelta = 3;
    int yDelta = 2;

    /** A method to determine if two instances of Area intersect */
    public boolean doAreasCollide(Area area1, Area area2) {
        boolean collide = false;

        Area collide1 = new Area(area1);
        collide1.subtract(area2);
        if (!collide1.equals(area1)) {
            collide = true;
        }

        Area collide2 = new Area(area2);
        collide2.subtract(area1);
        if (!collide2.equals(area2)) {
            collide = true;
        }

        return collide;
    }

    ShapeCollision() {
        int w = 400;
        int h = 200;
        img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        final JLabel imageLabel = new JLabel(new ImageIcon(img));
        x = w/2;
        y = h/2;

        //circle 
        obstacles[0] = new Area(new Ellipse2D.Double(40, 40, 30, 30));

        int[] xTriangle = {330,360,345};
        int[] yTriangle = {60,60,40};
        //triangle 
        obstacles[1] = new Area(new Polygon(xTriangle, yTriangle, 3));

        int[] xDiamond = {60,80,60,40};
        int[] yDiamond = {120,140,160,140};
        //diamond 
        obstacles[2] = new Area(new Polygon(xDiamond, yDiamond, 4));

        int[] xOther = {360,340,360,340};
        int[] yOther = {130,110,170,150};
        // other 
        obstacles[3] = new Area(new Polygon(xOther, yOther, 4));

        walls = new Area(new Rectangle(0,0,w,h));

        ActionListener animate = new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                animate();
                imageLabel.repaint();
            }
        };
        Timer timer = new Timer(50, animate);

        timer.start();
        JOptionPane.showMessageDialog(null, imageLabel);
        timer.stop();
    }

    public void animate() {
        Graphics2D g = img.createGraphics();
        g.setRenderingHint(
                RenderingHints.KEY_ANTIALIASING, 
                RenderingHints.VALUE_ANTIALIAS_ON);

        g.setColor(Color.BLUE);
        g.fillRect(0, 0, img.getWidth(), img.getHeight());
        x+=xDelta;
        y+=yDelta;
        int s = 15;
        Area player = new Area(new Ellipse2D.Double(x, y, s, s));

        // Acid test of edge collision;
        if (doAreasCollide(player,walls)) {
            if ( x+s>img.getWidth() || x<0 ) {
                xDelta *= -1;
            } 
            if(y+s>img.getHeight() || y<0 ) {
                yDelta *= -1;
            }
        }
        g.setColor(Color.ORANGE);
        for (Area obstacle : obstacles) {
            if (doAreasCollide(obstacle, player)) {
                g.setColor(Color.RED);
            } else {
                g.setColor(Color.GREEN);
            }
            g.fill(obstacle);
        }

        g.setColor(Color.YELLOW);
        g.fill(player);


        g.dispose();
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
                new ShapeCollision();
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
        SwingUtilities.invokeLater(r);
    }
}

Edit

make it detect all the red color and set that as the collision bounds

At start-up, use the source seen in the Smoothing a jagged path question to get an outline of the red pixels (see the getOutline(Color target, BufferedImage bi) method). Store that Area as the single obstacle on start-up.

这篇关于复杂形状的碰撞检测的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆