144217evhufeiswwymecy5.png
  GameRes游资网授权发布 文 / 肥宝传说之路

  游戏技能攻击区域的计算,关乎服务端的效率。需要确保正确,简洁地计算攻击区域,才能快速寻找攻击对象。

  今天只讨论地图上距离的问题。

  一般情况下攻击区域分为以下几种:

  1.点对点,对个人进行攻击

  2.射线攻击,其实就是矩形区域

  3.扇形攻击

  4.圆形攻击

  当然,还有其他情况,例如多区域和其他奇奇怪怪的形状。不过考虑的实际观赏价值,和精度的问题,多区域,只考虑圆形和扇形,其他形状也不考虑了。

  释放技能需要几个事物,攻击者,主要被攻击者(也可能是攻击地点),其他围观的群众

 

 

  1. class CPoint//点的定义
  2. {
  3. double x;
  4. double y;
  5. }
  6. typedef std::vector<CPoint> SeqCPoint;
  7. double skillDistance = 123;//技能释放距离
  8. CPoint attackerPoint;//攻击者位置
  9. CPoint defenserPoint;//被攻击者位置或技能释放点
  10. SeqCPoint otherRoles;//其他需要检测的角色

  判断一个点是否在矩形内是很简单的,如下:

 

 

  1. //判断点是否在矩阵内
    • bool inRect( double minx, double miny, double maxx, double maxy, CPoint p)
      • {
        • if(p.x >= minx p.x <= maxx p.y >= miny p.y <= maxy) return true;
          • return false;
            • }

  3.扇形区域

  攻击者对前方角度α,长度为L的区域进行攻击。如下图,攻击目标为B,要计算旁边的C是否也受到攻击

 

 

  1. //计算两点之间的距离
    • double computeDistance(CPoint from, CPoint to)
      • {
        • return sqrt(pow(to.x - from.x, 2) + pow(to.y - from.y, 2));
          • }
            • /**
              • * 直角坐标--绝对坐标转相对坐标
                • * originPoint 相对坐标系的原点
                  • * directionPoint 指向x轴方向的点
                    • * changePoint 需要转换的坐标
                      • */
                        • CPoint changeAbsolute2Relative(CPoint originPoint, CPoint directionPoint, CPoint changePoint)
                          • {
                            • //originPoint为图中A点,directionPoint为图中B点,changePoint为图中C点
                              • CPoint rePoint;
                                • if (originPoint == directionPoint)//方向点跟原点重合,就用平行于原坐标的x轴来算就行了
                                  • {//AB点重合,方向指向哪里都没所谓,肯定按原来的做方便
                                    • rePoint.x = changePoint.x - originPoint.x;
                                      • rePoint.y = changePoint.y - originPoint.y;
                                        • }
                                          • else
                                            • {
                                              • //计算三条边
                                                • //计算三条边
                                                  • double a = computeDistance(directionPoint, changePoint);
                                                    • double b = computeDistance(changePoint, originPoint);
                                                      • double c = computeDistance(directionPoint, originPoint);
                                                        •  
                                                        • double cosA = (b*b + c*c - a*a) / 2*b*c;//余弦
                                                          • rePoint.x = a * cosA ;//相对坐标x
                                                            • rePoint.y = sqrt(a*a - rePoint.x*rePoint.x);//相对坐标y
                                                              • }
                                                                • return rePoint;
                                                                  • }
                                                                    • for(SeqCPoint::iterator iter = otherRoles.begin();
                                                                      • iter != otherRoles.end();
                                                                        • iter ++)
                                                                          • {
                                                                            • //检测每一个角色是否在矩形内。
                                                                              • CPoint rePoint = changeAbsolute2Relative(attackerPoint, defenserPoint, *iter);//相对坐标
                                                                                • //skillWidth为图中宽度,skillLong为图中长度
                                                                                  • //宽度是被AB平分的,从A点开始延伸长度
                                                                                    • bool beAttack = inRect(0, - skillWidth/2, skillLong, skillWidth/2, rePoint);//相对坐标下攻击范围不用算了,跟目标的相对坐标算一下
                                                                                      • if (beAttack)
                                                                                        • {
                                                                                          • //受到攻击,攻击处理
                                                                                            • }
                                                                                              • }

  今天发现还有一种方法,就是利用向量的点积,可以百度一下。

 

 

  1. void changeXYToPolarCoordinate(Common::CPoint p, double r, double angle)
    • {
      • r = sqrt(p.x*p.x + p.y*p.y);//半径
        • angle = atan2(p.y , p.x) * 180/PI;//计算出来的是弧度,转成角度,atan2的范围是-π到π之间
          • angle = (angle + 360)%360;
            • }
              • CPoint changeAbsolute2Relative(CPoint originPoint, CPoint changePoint)
                • {
                  • CPoint rePoint;
                    • rePoint.x = changePoint.x - originPoint.x;
                      • rePoint.y = changePoint.y - originPoint.y;
                        • return rePoint;
                          • }
                            • double baseR, baseAngle;
                              • CPoint rePoint = changeAbsolute2Relative(attackerPoint, defenserPoint);//图中B点的相对坐标
                                • changeXYToPolarCoordinate(rePoint, baseR, baseAngle);//转变成极坐标,baseAngle是角度
                                  • for(SeqCPoint::iterator iter = otherRoles.begin();
                                    • iter != otherRoles.end();
                                      • iter ++)
                                        • {
                                          • CPoint rePointC = changeAbsolute2Relative(attackerPoint, iter2);//图中C点相对坐标
                                            • double cr = 0;//极坐标半径
                                              • double cangle = 0;//极坐标角度
                                                • changeXYToPolarCoordinate(rePointC, cr, cangle);
                                                  • if (cr > R)//超过技能半径就无法攻击到了
                                                    • {
                                                      • continue;
                                                        • }
                                                          • if ( abs(cangle - baseAngle) < β/2 )//相差的角度小于配置的角度,所以受到攻击。要注意,这里的角度都是在0°到360°之间
                                                            • {
                                                              • //受到攻击
                                                                • }
                                                                  • }

  判断是否在攻击者半径范围内就行了。

144213sicin7e6tid6wi6v.png
  对于多个圆形区域的计算

 

 

  1. for(SeqCPoint::iterator iter = otherRoles.begin();
    • iter != otherRoles.end();
      • iter ++)
        • {
          • CPoint rePointC = changeAbsolute2Relative(attackerPoint, iter2);//图中C点相对坐标
            • double cr = sqrt(rePointC.x*rePoint.x + rePointC.y*rePointC.y); //点到圆心的距离
              • if (cr <= R)//超过技能半径就无法攻击到了
                • {
                  • //受到攻击
                    • }
                      • }
复制代码
  本质上还是一样,用一个for循环,计算出圆心的位置,然后计算点到圆心的距离就完成了。

  相关阅读MMO游戏数值建模-明澈流风-V1.0

锐亚教育

锐亚教育,游戏开发论坛|游戏制作人|游戏策划|游戏开发|独立游戏|游戏产业|游戏研发|游戏运营| unity|unity3d|unity3d官网|unity3d 教程|金融帝国3|8k8k8k|mcafee8.5i|游戏蛮牛|蛮牛 unity|蛮牛