Java简单游戏开发之碰撞检测

news/2024/9/19 23:44:09

前言

                  不久之前在论坛上有人发贴,使用java编写的超级马里奥如何实现碰撞检测,笔者自己以前

             也做过Tank大战。里面同样涉及到碰撞检测,翻翻U盘里的东西还在,什么时候也给共享出来。

             这篇文章就简单游戏中的碰撞检测做一个简单的总结。首先需声明的是这里只是2D的碰撞检测。

    碰撞检测

                 对于形状之间如何来判断是否是碰撞的这要根据具体的形状来定。在新手练手的小游戏中,

            物体形状一般可以设定为矩形区域,这类规则图形。它的碰撞检测可以通过java API中的

            Rectangle类来实现碰撞的检测。

      规则图形碰撞检测(Rectangle)

                 首先我们查看API关于Rectangle类的介绍:它就是指定坐标空间的一个区域,这个区域是通过

             指定左上角x、y坐标和去高度和宽度来确定的。

                 接下来看起具体的方法public Rectangle intersection(Rectangle r),这个方法就是碰撞检测的

              关键了,如果两个Rectangle对象有交集,那么他们就有碰撞了。而每个形状我们都可以得到他们

              的Rectangle对象,这样图形的碰撞检测也就得以实现了。

                                   

                  看下具体实现源码:

 

[java] view plaincopy
  1. /* 判断子弹是否击中障碍物 */  
  2. public boolean isHit(com.Alex.map.Map map) {  
  3.     boolean flag = true;// 代表没有撞到  
  4.     // 分类别的得到所有的障碍物  
  5.     List<Stuff> stuffList = new Vector<Stuff>();  
  6.     stuffList.addAll(map.getBricks());  
  7.     stuffList.addAll(map.getIrons());  
  8.     stuffList.addAll(map.getWaters());  
  9.     for (int i = 0; i < stuffList.size(); i++) {  
  10.         Stuff a = stuffList.get(i);  
  11.         Rectangle tankRectangle = new Rectangle(bullet2.getRec());  
  12.         Rectangle stuffRectangle = new Rectangle(a.getX(), a.getY(), 2020);  
  13.         if (stuffRectangle.intersects(tankRectangle)) {  
  14.             flag = false;// 撞到了  
  15.             break;  
  16.   
  17.         }  
  18.   
  19.     }  
  20.     return flag;  
  21. }  

               上述这个例子就是判断Tank发出的子弹是否对地图中的障碍物有碰撞,如果有的话

 

          就做相关的操作(子弹爆炸、障碍物消失)。上述代码中子弹对象有一个getRec()方法就是

          得到子弹图形的Rectangle对象,具体实现就是根据其坐标和width、height来生成的。

               采用此种方法进行碰撞检测需要注意,对于图片的实现处理应该尽量的去掉图标边角

          的空白,不然实际效果可以产生肉眼可辨的误差。也就是说Rectangle尽量的包住图形

          且Rectangle的区域尽量小。这种碰撞检测的方法被称之为多矩形碰撞。

                           

                 一旦有一个矩形数组中的矩形与另外一个矩形数组的矩形发生碰撞就可认为发生了

            多矩形碰撞。其中多圆形碰撞也是同样的道理,只是包裹的图形区域是圆形罢了。

            不过仔细思考多矩形碰撞同样会有误差,虽然这种误差十分小。

                      

                    

       像素级别的碰撞检测

                         像素级别的碰撞检测算得上是最精确的碰撞检测方法了。

                        首先遍历算出一张位图所有的像素点坐标,然后与另外一张位图上的所有点坐标进行对比,

                    一旦有一个像素点的坐标相同,就立刻取出这两个坐标相同的像素点,通过位运算取出这两个

                    像素点的最高位(透明度)进行对比,如果两个像素点都是非透明像素则判定这两张位图发生

                    碰撞。

                         介绍了像素碰撞之后可以得到两个结论:

                           1、像素碰撞很精确,不论位图之间是否带有透明像素,都可以精确判断;

                           2、正是因为像素碰撞的这种高精确判定,从而也会造成代码效率明显降低!

                      假设两张100×100 大小的位图利用像素级检测碰撞,仅是遍历两张位图的像素点就要循环

                     100×100×2=20000 句逻辑代码;况且还要对筛选出来的相同坐标的像素点进行遍历对比其

                     透明值!这种效率可想而知!

                     当然,这里的像素碰撞只是大致提供一种思路,肯定还可以进行代码优化;但是不论再优的

                    代码,使用像素级进行碰撞检测终会导致整个程序的运行效率大大降低。因此像素级别的碰

                    撞检测在游戏开发中是尽量避免使用的!

        规则图形碰撞检测2

 

               对于子弹和障碍物的碰撞检测,采用上述第一种方法就可以简单的实现了,不过子弹是圆形的

           有没有更加精确的碰撞检测方法呢?也就是实现圆形和矩形的碰撞检测嘛。

               这里我们需要简单的运行下几何数学的知识,给个简单的图就会明白了。

                 

              小圆有个运动轨迹,轨迹的线如果和他对着的正方形的相对某一象限的边有焦点,那么

         就能碰撞,边就是那一个象限的边(还要把圆半径算进去),具体代码就不实现了,读者可

         自己尝试着去实现。 

       不规则图形碰撞检测

          这里直接转载一篇文章:

         http://www.cnblogs.com/Kurodo/archive/2012/08/08/2628688.html

对于矩形碰撞,很多人都知道。但面对多边形图形,大多数采用多矩形覆盖的方式。
但是我不是很喜欢这种方式,我所采用的是利用一个经典算法:
SAT 一种可以快速检测不规则的凸多边形是否碰撞的算法
给出两个凸多边形体,如果我们能找到一个轴线,使两物体在此轴线上的投影不重叠,则这
       两个物体之间没有发生碰撞,这个轴线叫做Separating Axis(红色轴线)。

         

 

          

 

               对于2D来说,红色线就是垂直与多边形边的轴。 

 

                           

 

             因此,如果我们要检查两多边形是否碰撞,就去检查两多边形在每个所有可能的轴上的投影

          是否重叠。 

              

 

[java] view plaincopy
    1. /// 检测2个矩形是否发生碰撞  
    2.   
    3. /// </summary>  
    4.   
    5. /// <returns></returns>  
    6.   
    7. public static bool IsIntersect (Vector2[] A, Vector2[] B)  
    8.   
    9.  {  
    10.   
    11.     Vector2 AX, AY, BX, BY;  
    12.   
    13.     AX = new Vector2();  
    14.   
    15.     AY = new Vector2();  
    16.   
    17.     BX = new Vector2();  
    18.   
    19.     BY = new Vector2();  
    20.   
    21.       
    22.   
    23.     AX.X = A[0].X - A[1].X;  
    24.   
    25.     AX.Y = A[0].Y - A[1].Y;                
    26.   
    27.     AY.X = A[0].X - A[3].X;               
    28.   
    29.     AY.Y = A[0].Y - A[3].Y;                
    30.   
    31.     BX.X = B[0].X - B[1].X;               
    32.   
    33.     BX.Y = B[0].Y - B[1].Y;                
    34.   
    35.     BY.X = B[0].X - B[3].X;               
    36.   
    37.     BY.Y = B[0].Y - B[3].Y;                
    38.   
    39.     //对于AX上:               
    40.   
    41.     if (Tmp(AX, A, B)) return false;               
    42.   
    43.     if (Tmp(AY, A, B)) return false;              
    44.   
    45.     if (Tmp(BX, A, B)) return false;               
    46.   
    47.     if (Tmp(BY, A, B)) return false;               
    48.   
    49.     return true;          
    50.   
    51. }  
    52.   
    53.             
    54.   
    55. private static bool Tmp(Vector2 IS,Vector2[] A,Vector2[] B)  
    56.   
    57.  {  
    58.   
    59.     float[] v = new float[4];   
    60.   
    61.     for (int i = 0; i < 4; i++)  
    62.   
    63.     {                   
    64.   
    65.         float tmp = (IS.X * A[i].X + IS.Y * A[i].Y) / (IS.X * IS.X + IS.Y * IS.Y);  
    66.   
    67.                  v[i] = tmp * IS.X * IS.X + tmp * IS.Y * IS.Y;              
    68.   
    69.     }  
    70.   
    71.     float[] vv = new float[4];  
    72.   
    73.     for (int i = 0; i < 4; i++)  
    74.   
    75.     {  
    76.   
    77.         float tmp = (IS.X * B[i].X + IS.Y * B[i].Y) / (IS.X * IS.X + IS.Y * IS.Y);  
    78.   
    79.                   vv[i] = tmp * IS.X * IS.X + tmp * IS.Y * IS.Y;  
    80.   
    81.     }  
    82.   
    83.     if (Math.Max(Math.Max(v[0], v[1]),Math.Max(v[2],v[3])) >Math.Min(Math.Min(vv[0],vv[1]),Math.Min(vv[2],vv[3])) && Math.Min(Math.Min(v[0],v[1]),Math.Min(v[2],v[3])) < Math.Max(Math.Max(vv[0],vv[1]),Math.Max(vv[2],vv[3]))) {  
    84.   
    85.      return false;   
    86.   
    87.     }//表示暂时不知道是否碰撞               
    88.   
    89.     else return true;//表示知道未碰撞  
    90.   
    91. }  

转载于:https://www.cnblogs.com/mfryf/archive/2013/05/24/3098109.html


https://dhexx.cn/news/show-18571.html

相关文章

split+ Pattern切割字符串

今天在对一个String对象进行拆分的时候&#xff0c;总是无法到达预计的结果。呈现数据的时候出现异常&#xff0c;后来debug之后才发现&#xff0c;错误出在String spilt上&#xff0c;于是开始好好研究下这东西&#xff0c;开始对api里的split(String regex, int limit)比较感…

linux进程管理命令之ps -ef与ps aux详解--

[rootlocalhost ~]# ps -ef | more UID PID PPID C STIME TTY TIME CMD root 2 0 0 Jul30 ? 00:00:00 [kthreadd] root 3 2 0 Jul30 ? 00:00:06 [ksoftirqd/0] root 5 2 0 Jul30 ? 00:00:00 [kworker/0:0H] root 7 2 0 Jul30 ? 00:00:04 [migration/0] root 8 2 0 Jul30 ?…

简单理解Java GC与幽灵引用

1. Strong Reference StrongReference 是 Java 的默认引用实现,它会尽可能长时间的存活于 JVM 内&#xff0c; 当没有任何对象指向它时Java GC 执行后将会被回收 Test public void strongReference() { Object referent new Object(); /** * 通过赋值创建 StrongRef…

android 断点续传原理,Android多线程断点续传下载原理

步骤:1.在本地创建一个与服务器端一样大小的空白文件;确定服务器端文件的大小:发送一个请求,得到content-length;创建空白文件,设置文件的大小:RandomAccessFile2.在设置线程的个数;创建int类型的变量;3.计算子线程下载数据的范围;blockSize length / threadCount;4.计算子线程…

程序移植到VS2010,编译成功但是无法启动lib文件

今天遇到的这个问题&#xff0c;是由于解决方案下有多个项目&#xff0c;其中包含生成库的项目&#xff0c;也有可执行程序的项目 解决方法&#xff1a;邮件解决方案&#xff0c;属性-通用属性-启动项目进行设置就OK了&#xff0c;我的是设置单启动项目为包含可执行程序的项目。…

android wifi打开流程,Android Wifi流程

我试图跟踪wifi设置代码.我的目的是在将WIFI按钮切换为ON后知道从应用程序到内核层的流程.我们转到Android的“设置”页面,然后切换WLAN(WIFI)按钮你的wifi应该启用.>我发现此页面对应于WifiSettings.java.在此文件中,当您将按钮从OFF切换为ON时&#xff1a;private void up…

linux系统 处理海量数据之cut命令 对数据进行列的提取--

cut应用场景&#xff1a;通常对数据进行列的提取 语法&#xff1a;cut [选项]...[file] 选项&#xff1a; -d #指定分割符 -f #指定截取区域 -c #以字符为单位进行分割 注意&#xff1a;不加-d选项&#xff0c;默认为制表符&#xff0c;不是空格 以:为分隔符&#xff0c;截取出…

通用用户权限管理系统组件V3.9功能改进说明 - 操作权限项定义简化

在通用权限管理系统组件V3.9中对操作权限项定义进行了一次大胆的简化&#xff0c;现在定义模块菜单的同时可以定义操作权限项目&#xff0c;这样不用菜单与操作权限分离了&#xff0c;可以集中展示&#xff0c;实用效果更加友善。 下面是定义菜单或者操作权限项目的参考页面 设…

html 10 margin 重叠

留意&#xff0c;父子元素&#xff0c;margin重叠影响的是margin-top上的。取两者中的最大值&#xff0c;水平和bottom不受影响&#xff0c; 重叠的时候子元素的margin-top消失 父元素如果加了padding属性&#xff0c;不会重叠。子元素如果有float&#xff0c;父子不重叠 CSS 外…

android studio如何换jdk,Android Studio怎样更改JDK和SDK的路径?

【BZOJ-1458】士兵占领 最大流1458: 士兵占领 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 782 Solved: 456[Submit][Status][Discuss] ...HDU 5973 Game of Taking Stones 威佐夫博弈&plus;大数题目链接: http://acm.hdu.edu.cn/showproblem.php?pid5973 Game of T…