【问题标题】:How can I effectively implement collision for a 2D game?如何有效地实现 2D 游戏的碰撞?
【发布时间】:2014-09-15 22:38:49
【问题描述】:

我刚刚使用 Java、LWJGL 和 Slick Util 开始了一个新的 2D 游戏,但我似乎无法找到进行碰撞检测的好方法。 如果我愿意,使用 Rectangle intersect 方法很容易检测到 2 个实体之间的碰撞,但它只能检查与您指定的某个区域的碰撞。 我以为我可以列出每个实体及其创建时的坐标,然后通过列表运行 intersect 方法,但是每次游戏更新时它都会检查与整个地图上的每个实体的碰撞,我认为那太低效了。

有人知道创建碰撞检测的更有效方法吗?如果有某种方法我可以检查角色移动的每个点是否有一个实体,这可能是最好的。

如果我没有足够的信息或者我让这听起来太混乱,请告诉我,我可以尝试澄清事情。另外一个问题是,使用 slick util 或 slick 2D 相互之间有什么好处。感谢您的帮助!

【问题讨论】:

    标签: java collision-detection lwjgl


    【解决方案1】:

    解决这个问题的常用方法是场景图,即游戏世界对象的分层系统。

    您可能想查看thisthis

    缩短:您在逻辑上将对象分组到节点下,并为节点分配一个包含其所有子节点和叶子(对象)的边界矩形。一切都再次分组在一个主节点下以访问树。现在您可以测试对象与节点的碰撞,通常从主节点开始。如果你得到一个命中,你检查它的子节点和叶子。

    这将需要一些时间来实现,但如果树结构/分组正确完成,可以减少 CPU 使用率。它还有一个好处是您可以实现局部变换,这使得相对于彼此移动对象更容易。

    【讨论】:

      【解决方案2】:

      因为我讨厌“惯用方式”,所以我将所有坐标组成了一个数组,然后检查是否有单个点击中坐标。

      这里是我的代码稍作修改来演示(它是 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 是一个 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;
              }
        }
      

      虽然它对碰撞交互有限制,但它适用于炮弹与一艘船相撞并检查一艘船的前部以查看它是否击中了另一艘船。此外,它几乎不使用任何 CPU。

      不知道其他程序员对这种方法的看法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多