简体   繁体   English

如何有效地实现2D游戏的碰撞?

[英]How can I effectively implement collision for a 2D game?

I just started a new 2D game using Java, LWJGL, and Slick Util but I can't seem to figure out a good way to make collision detection. 我刚刚使用Java,LWJGL和Slick Util开始了一个新的2D游戏,但是我似乎还没有找到进行碰撞检测的好方法。 If I wanted to, it would be easy to detect collision between 2 entities with the Rectangle intersect method, but it can only check the collision with a certain area you specify. 如果需要的话,使用Rectangle intersect方法可以很容易地检测2个实体之间的碰撞,但是它只能检查与您指定的特定区域之间的碰撞。 I have thought that I could make a list of every entity and its coordinates as its created and then run the intersect method through the list, but then it would check for collision with every entity on the entire map for every time the game updated and I think that would be too inefficient. 我以为我可以列出每个实体及其创建时的坐标,然后通过该列表运行intersect方法,但是每次游戏更新时,它将检查与整个地图上每个实体的碰撞,因此我认为那太低效了。

Does anyone know a more efficient way to create collision detection? 有谁知道创建碰撞检测的更有效方法? If there was some way i could check if there was an entity at every point the character moved that would probably be the best. 如果有某种方法,我可以检查角色移动的每个点是否有实体,那可能是最好的。

If I have not enough information or I made this sound too confusing please tell me and I can try to clarify things. 如果我没有足够的信息,或者我听起来太混乱,请告诉我,我可以尝试澄清。 Also as a side question, what are the benefits of using slick util or slick 2D over one another. 另一个附带的问题是,与其他人相比,使用slick util或slick 2D有什么好处。 Thanks for the help! 谢谢您的帮助!

The usual way to solve this is a scene graph, a hierarchical system of the objects of the game world. 解决此问题的常用方法是场景图,即游戏世界中对象的层次系统。

You might want to look at this and this . 您可能想看看这个这个

Shortened: you logically group your objects under nodes and assign the nodes a bounding rectangle that encompasses all its sub-nodes and leaves(objects). 缩短:您可以在逻辑上将对象分组到节点下,并为节点分配一个包围其所有子节点和叶子(对象)的边界矩形。 Everything is grouped again under one main node to access the tree. 将所有内容再次分组到一个主节点下以访问树。 Now you can test a object for collision with a node, usually starting from the main node. 现在,您可以测试对象是否与节点发生冲突,通常是从主节点开始。 If you get a hit you check its sub-nodes and leaves. 如果遇到问题,请检查其子节点和叶子。

This will take some time to implement but can cut down on CPU usage if the tree structure/grouping is done right. 这将花费一些时间来实现,但是如果树结构/分组正确完成,则可以减少CPU使用率。 It has also the benefit that you can implement local transforms which makes moving objects relative to each other easier. 它还具有好处,您可以实现局部转换,从而使相对于彼此移动的对象更加容易。

Because I hate "The usual way", I made an array of all the coordinates and then checked if a single point hit the coordinate. 因为我讨厌“通常的方式”,所以我对所有坐标进行了数组处理,然后检查单个点是否命中坐标。

Here is a slight modification of my code to demonstrate (It is in 3D): 这是我的代码的稍作修改以进行演示(以3D形式显示):

for (CannonBall can : GameServer.ballss){ //Go through all cannonballs
                    if (can.owner != cl){ //Can.owner is the ship, cl is the player the cannonball is being checked with to see if colliding.
                    int distancex = (int) (can.x - cl.z);
                    int distancez = (int) (can.z - cl.x);
                    final int distancey = (int) (can.y - cl.y);

                    double xRot = Math.cos(Math.toRadians(cl.rotation)) * (distancex - 0) - Math.sin(Math.toRadians(cl.rotation)) * (distancez - 0) + 0;
                    double zRot = Math.sin(Math.toRadians(cl.rotation)) * (distancex - 0) - Math.cos(Math.toRadians(cl.rotation)) * (distancez - 0) + 0;
                    distancex = (int) xRot;
                    distancez = (int) zRot;
                    try{

                        if (true){ //Skip different coordinates for different ships for demonstration purposes
                            i = GameServer.coords[GameServer.DELTA + distancex][GameServer.DELTA + distancez][GameServer.DELTA + (distancey)];
                        }
                        if (i == 1){
                            if (can.owner != cl){   
                            remcan.add(can);
                            if (can.type == 0){
                                double damage = (100 + Math.random()*25);
                                if (cl.type == 1){
                                    damage/=2;
                                }
                                if (cl.type == 2){
                                    damage*=2;
                                }
                                cl.damage-=damage;
                            }
                            if (can.type == 1){
                                double damage = (Math.random() * 500);
                                if (cl.type == 1){
                                    damage/=2;
                                }
                                if (cl.type == 2){
                                    damage*=2;
                                }
                                cl.damage-=damage;
                            }else{
                                double damage = (100 + Math.random()*25);
                                if (cl.type == 1){
                                    damage/=2;
                                }
                                if (cl.type == 2){
                                    damage*=2;
                                }
                                cl.damage-=damage;
                            }
                            crash = true;
                            if (cl.damage < 1){
                                if (!cl.sinking){
                                cl.sinking = true;


                               }

                            }
                        }
                        }
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    }

GameServer.coords is an int[][][], which is given coordinates like so: GameServer.coords是一个int [] [] [],其坐标如下所示:

public static int[][][] coords;
public void CollisionSetup(){
    try{
        File f = new File("res/coords.txt");
        String coords = readTextFile(f.getAbsolutePath());

        for (int i = 0; i < coords.length();){
            int i1 = i;
            for (; i1 < coords.length(); i1++){
                if (String.valueOf(coords.charAt(i1)).contains(",")){
                    break;
                }
            }
            String x = coords.substring(i, i1).replace(",", "");
            i = i1;
            i1 = i + 1;
            for (; i1 < coords.length(); i1++){
                if (String.valueOf(coords.charAt(i1)).contains(",")){
                    break;
                }
            }
            String y = coords.substring(i, i1).replace(",", "");;
            i = i1;
            i1 = i + 1;
            for (; i1 < coords.length(); i1++){
                if (String.valueOf(coords.charAt(i1)).contains(",")){
                    break;
                }
            }
            String z = coords.substring(i, i1).replace(",", "");;
            i = i1 + 1;
                //buildx.append(String.valueOf(coords.charAt(i)));
                ////System.out.println(x);
                ////System.out.println(y);
                ////System.out.println(z);
                //x = String.valueOf((int)Double.parseDouble(x));
                //y = String.valueOf((int)Double.parseDouble(y));
                //z = String.valueOf((int)Double.parseDouble(z));
            double sx = Double.valueOf(x);
            double sy =  Double.valueOf(y);
            double sz = Double.valueOf(z);
            javax.vecmath.Vector3f cor = new javax.vecmath.Vector3f(Float.parseFloat(x), Float.parseFloat(y), Float.parseFloat(z));
            //if (!arr.contains(cor)){
            if (cor.y > 0)
                arr.add(new javax.vecmath.Vector3f(cor));


            if (!ship.contains(new Vector3f((int) sx, (int) sy, (int) sz)))
                ship.add(new Vector3f((int) sx, (int) sy, (int) sz));
                Float.parseFloat(z)));
            }
    }
 public void setUpPhysics() {
        //coords = new int[20][20];

        coords = new int[80][80][80];
        coords1 = new int[80][80];
        //coords[-5 + DELTA][7 + DELTA] = 11;
        for (javax.vecmath.Vector3f vec : arr){
            coords[DELTA+(int) vec.x][DELTA+(int) vec.z][DELTA + (int) vec.y] = 1; //This is line 124
            coords1[DELTA+(int) vec.x][DELTA+(int) vec.z] = 1;
        }
  }

Though it has limitations on collision interaction, it works for cannonballs colliding with a ship and checking the front of a ship to see if it has hit another ship. 尽管它在碰撞交互方面有局限性,但它适用于炮弹与飞船碰撞并检查飞船的正面以查看它是否撞到了另一艘飞船。 Also, it uses barely any CPU. 而且,它几乎不使用任何CPU。

No idea on the opinions of other programmers on such a method. 不知道其他程序员对这种方法的看法。

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

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