zoukankan      html  css  js  c++  java
  • Unity3D-游戏中的技能碰撞检测

    在游戏战斗中,我们会用到各种各样的碰撞检测,来判断是否打中了目标

    比如扇形检测/圆形检测

    还有矩形检测,王者荣耀里后羿的大招就是一个很长的矩形碰撞体

    这些在Unity3D引擎中其实都封装好了一些Collider组件去检测碰撞,但是我最近写帧同步算法的时候,发现U3D中的碰撞算法执行顺序不可控,会导致不同步的现象,所以就只好苦逼的自己写碰撞检测算法了。

    我们游戏是一个3D动作类游戏,大概的碰撞可以分为几类

    1. 圆柱体(把人/怪物的碰撞设定位一个圆柱体,U3D里是胶囊体,是为了解决一些边缘精度问题,但是我们游戏里的话圆柱就够用了)
    2. 球体
    3. 立方体

    需要检测的碰撞有

    1.检测圆柱体跟球体的碰撞

    2.立方体跟圆柱体的碰撞

    具体实现:

    1.球体跟圆柱体碰撞检测

     1     /// <summary>
     2     /// 检测球体跟圆柱体碰撞
     3     /// </summary>
     4     /// <param name="x1">球体X</param>
     5     /// <param name="y1">球体Y</param>
     6     /// <param name="z1">球体Z</param>
     7     /// <param name="r1">球体半径</param>
     8     /// <param name="x2">圆柱体X</param>
     9     /// <param name="y2">圆柱体Y</param>
    10     /// <param name="z2">圆柱体Z</param>
    11     /// <param name="r2">圆柱半径</param>
    12     /// <param name="h2">圆柱体高度</param>
    13     public static bool CheckCircleAndCylinderCollider(float x1, float y1, float z1, float r1,
    14     float x2, float y2, float z2, float r2, float h2)
    15     {
    16         float dx = x2 - x1;
    17         float dy = y2 - y1;
    18         float dz = z2 - z1;
    19         float disSqua = (dx * dx) + (dz * dz);
    20         float rSqua = (r1 + r2) * (r1 + r2);
    21         bool heightCheck = Math.Abs(y1 - y2) < r1 + h2 / 2;
    22         return heightCheck && disSqua < rSqua;
    23     }

    1.检测两个圆有没有相交

    2.检测Y轴的距离是否小于球半径+圆柱体高度的一半

    这里是把球体也当成了圆柱体进行检测,好处就是:效率高。 缺点是:不精确,没有考虑X,Z轴的旋转

    但由于我们游戏中圆柱体不会有X,Z轴的旋转,所以这样的做法是最高效的

    精确性问题:把圆柱体变成胶囊体,两端用两个球体来计算检测,这样会更精确,同时性能也会降低

    2.立方体跟圆柱体的碰撞

    这里先把问题简化成矩形跟圆形的碰撞检测

    计算方法是先找到矩形上离圆形最短距离u,然后再比较u是否小于圆形的半径r

    1. 首先利用绝对值把 p - c 转移到第一象限,下图显示不同象限的圆心也能映射至第一象限,这不影响相交测试的结果:

    2. 然后,把 v 减去 h,负数的分量设置为0,就得到圆心与矩形最短距离的矢量 u。下图展示了4种情况,红色的u是结果。

     最后要比较u和r的长度,若距离少于r,则两者相交。可以只求u的长度平方是否小于r的平方 

    具体做法可以参考这里:https://www.zhihu.com/question/24251545

    对于AABB包围盒,这样就已经可以检测碰撞了,但是如果矩形是旋转的OBB包围盒呢?

    我这里是实现了一个OBB的包围盒类,记录了坐标,角度,碰撞检测的时候先把圆的角度旋转到OBB的坐标系里

    利用旋转公式:

    x2 = x * Mathf.Cos(rad) - z * Mathf.Sin(rad);
    
    z2= x * Mathf.Sin(rad) + z * Mathf.Cos(rad);

    然后再用那篇文章里说的方式计算矩形跟圆是否相交

    最后再通过两者 Y轴的距离 < (圆柱体高度+立方体的高度)/2 ,如果小于则相交

    这种方法的优势:效率高,而且精确

    缺点是这个3D的OBB只能沿Y轴旋转,不过也够用了 

    如果像王者荣耀类型的游戏,感觉不需要扩展到3D,2D检测应该就够用了

  • 相关阅读:
    [剑指Offer] 10.矩形覆盖
    [剑指Offer] 9.变态跳台阶
    [剑指Offer] 8.跳台阶
    [剑指Offer] 7.斐波那契数列
    ArtifactTransferException: Failure to transfer org.apache.openejb:javaee-api:jar:5.0-1
    -Dmaven.multiModuleProjectDirectory system property is not set. Check $M2_HO 解决办法
    java中判断list是否为空的用法
    PL/SQL快速选中一行并执行
    substring的用法
    Oracle---------sql 中取值两列中值最大的一列
  • 原文地址:https://www.cnblogs.com/lijiajia/p/6718812.html
Copyright © 2011-2022 走看看