MMO游戏技能攻击区域的计算3--效率分析

来源:互联网 发布:融资租赁数据 编辑:程序博客网 时间:2024/05/21 22:39

本文来自肥宝游戏,引用必须注明出处!

对于攻击区域的计算,请看上两遍文章:

MMO游戏技能攻击区域的计算

MMO游戏技能攻击区域的计算2--给地图划分格子

这两篇文章已经对攻击区域进行详细讲解,分为没划分格子和划分格子的情况。这里就不在详述了。

在前面的文章,已经得出结论:由于服务端的承载问题,需要对地图划分格子。

但是划分格子后,通过格子配置,也可以实现对圆形,扇形,矩形等图形的计算。但是在获得简便的计算之后,却是用精度来做代价。

所以今天要对两种方式,做一次效率的分析。

先确定一些基础条件:

1.把地图格子设置为20*20,整个地图就是220*220,分成11*11个格子。

2.每个格子让一个角色站着。

代码篇幅太大,放到末尾了!!!

统计结果:


柱形图:




最后总结:

1测试了几次,发现相差都不大,就不算平均值了,只取某一次的数据。

2对于同一种区域计算,提升执行次数,基本是等比例提升。

3扇形可能会同时出现多个,因为在实际游戏中,可能玩家会站得比较近而打不到的情况,这个时候用一个半径比较小,角度比较大的扇形来补充比较合适。

4格子少的时候效率是很高的,但是格子多了,效率就降低了。

换算一下,一个矩形相当于18个格子的计算量,一个扇形相当于6到七个。

至于什么哪个方式比较时候,我建议是各种方式的代码都需要写,到时候在根据具体格子大大小,还有技能区域的大小,判断一下能用多少个格子来表示攻击区域。在进行选择

5必须提到一点,一开始函数参数没有使用引用,执行时间差不多是现在给出来的数据的3倍!尤其是格子算法函数调用多,造成很大开销,差距更大。所以没啥事要使用引用,否则老是创建新的对象,消耗很大的。

6想不到扇形这些的计算量并不是很大,不要以为算法复杂,计算消耗就大,还是需要实际测试一下,可能出乎你意料!!!!!!

=======================================================================

下面是具体的测试代码

MapManager.h

////  Header.h//  HelloWorld//  关注微信公众号:传说之路,大家共同学习//  Created by feiyin001 on 16/4/3.//  Copyright (c) 2016年 FableGame. All rights reserved.//#ifndef HelloWorld_Header_h#define HelloWorld_Header_h#include <stdio.h>#include <vector>#define PI 3.1412;//圆周率#define CellBase 20;//格子的大小namespace FableGame {        struct SPoint    {        int x;        int y;    };    typedef std::vector<SPoint> SeqSPoint;        static const int rectWidth = 500 ;//矩形区域的宽度,像素    static const int rectHeight = 200 ;//矩形区域的高度,像素    //地图上各种处理都放在这里    class CMapManager    {    public:        //判断两点间是否超过一定距离        static bool isFarThanDistance(SPoint& a, SPoint& b, int distance);                //判断一个点是否在矩形内,这个要求与坐标轴平行        static bool inRect( double minx, double miny, double maxx, double maxy, SPoint& p);        //判断一个点是否在矩形内,        static bool inRectRelat( SPoint& originPoint, SPoint& directionPoint, SPoint& checkPoint);        //判断是否在扇形内        static bool checkInFan( SeqSPoint& angleConfigs,                               SPoint& originPoint,                               SPoint& directionPoint,                               SPoint& checkPoint );                //计算两点之间的距离        static double computeDistance(SPoint& from, SPoint& to);                /**         * 直角坐标--绝对坐标转相对坐标         * originPoint 相对坐标系的原点         * directionPoint 指向x轴方向的点         * changePoint 需要转换的坐标         */        static SPoint changeAbsolute2Relative(SPoint& originPoint, SPoint& directionPoint, SPoint& changePoint);        //这个转换的坐标轴是跟原来的平行的        static SPoint changeAbsolute2Relative(SPoint& originPoint, SPoint& changePoint);                        //======检测是否在格子配置的图形里面======        static bool checkInCell(SeqSPoint& pointConfigs, SPoint& originPoint, SPoint& checkPoint);            };                }#endif



MapManager.cpp

////  MapManager.cpp//  HelloWorld//  关注微信公众号:传说之路,大家共同学习//  Created by feiyin001 on 16/4/3.//  Copyright (c) 2016年 FableGame. All rights reserved.//#include "MapManager.h"#include <math.h>using namespace FableGame;//判断两点间是否超过一定距离bool CMapManager::isFarThanDistance(SPoint& a, SPoint& b, int distance){    //求出相对距离xy    int x = (a.x - b.x) * CellBase;//坐标点都是格子的坐标点,所以要乘以格子的长度    int y = (a.y - b.y) * CellBase;    if(x * x + y * y > distance *distance) return true;//超过距离(勾股定理)    return false;//未超过}//判断一个点是否在矩形内,这个要求与坐标轴平行bool CMapManager::inRect( double minx, double miny, double maxx, double maxy, SPoint& p){    //判断点p的xy是否在矩形上下左右之间    if(p.x >= minx && p.x <= maxx && p.y >= miny && p.y <= maxy) return true;    return false;}//计算两点之间的距离double CMapManager::computeDistance(SPoint& from, SPoint& to){    return (sqrt(pow(to.x - from.x, 2) + pow(to.y - from.y, 2)))* CellBase;}//直角坐标--绝对坐标转相对坐标SPoint CMapManager::changeAbsolute2Relative(                                            SPoint& originPoint,//相对坐标系的原点                                            SPoint& directionPoint,//指向x轴方向的点                                            SPoint& changePoint)//需要转换的坐标{    //originPoint为图中A点,directionPoint为图中B点,changePoint为图中C点    SPoint rePoint;    if (originPoint.x == directionPoint.x && originPoint.y == directionPoint.y)//方向点跟原点重合,就用平行于原坐标的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 / CellBase;//相对坐标x        rePoint.y = sqrt(a*a - a * cosA * a * cosA) / CellBase;//相对坐标y    }    return rePoint;}bool CMapManager::inRectRelat( SPoint& originPoint, SPoint& directionPoint, SPoint& checkPoint){    //检测每一个角色是否在矩形内。    SPoint rePoint = changeAbsolute2Relative(originPoint, directionPoint, checkPoint);//相对坐标    //skillWidth为图中宽度,skillLong为图中长度    int skillWidth = rectWidth/CellBase;//矩形攻击区域的宽度    int skillLong = rectHeight/CellBase;//矩形攻击区域的高度    //宽度是被AB平分的,从A点开始延伸长度    return inRect(0, - skillWidth/2, skillLong, skillWidth/2, rePoint);//相对坐标下攻击范围}SPoint CMapManager::changeAbsolute2Relative(SPoint& originPoint, SPoint& changePoint){    SPoint rePoint;    rePoint.x = changePoint.x - originPoint.x;    rePoint.y = changePoint.y - originPoint.y;    return rePoint;}bool CMapManager::checkInFan(                             SeqSPoint& angleConfigs,                             SPoint& originPoint,                             SPoint& directionPoint,                             SPoint& checkPoint ){    //先求主目标的单位向量    SPoint rePoint = CMapManager::changeAbsolute2Relative(originPoint, directionPoint);//攻击者与主目标的向量    double longB = sqrt(rePoint.x * rePoint.x + rePoint.y * rePoint.y) ;//长度    rePoint.x /= longB;    rePoint.y /= longB;//求单位向量    for (SeqSPoint::iterator anIter = angleConfigs.begin();         anIter != angleConfigs.end();         anIter++)    {        if (CMapManager::isFarThanDistance(                                           originPoint,                                           checkPoint,                                           anIter->y))//检测是否在扇形的半径范围外        {            return false;        }                //然后求出检测点的向量        SPoint rePointC = CMapManager::changeAbsolute2Relative(originPoint, checkPoint);//图中C点相对坐标        double longC = sqrt(rePointC.x * rePointC.x + rePointC.y * rePointC.y);//长度        rePointC.x /= longC;        rePointC.y /= longC;//求单位向量                //根据向量的点击来求角度        double jiaodu = acos(rePoint.x * rePointC.x + rePoint.y * rePointC.y) * 180 /PI;//实际的角度大小        double angleBeta = anIter->x;                if ( jiaodu < angleBeta)        {//相差的角度小于配置的角度,所以受到攻击。要注意,这里的角度都是在0°到360°之间            return true;//在角度范围内        }        }    return false;}bool CMapManager::checkInCell(SeqSPoint& pointConfigs, SPoint& originPoint, SPoint& checkPoint){    SPoint rePoint = changeAbsolute2Relative(originPoint, checkPoint);//计算出相对位置    //判断是否跟配置某一点相同    for (SeqSPoint::iterator iter = pointConfigs.begin();//检测是否重合的点         iter != pointConfigs.end() ;         iter++)    {        if (iter->x == rePoint.x && iter->y == rePoint.y) {            return true;        }    }    return false;}



main.cpp

////  main.cpp//  HelloWorld//  关注微信公众号:传说之路,大家共同学习//  Created by feiyin001 on 16/4/3.//  Copyright (c) 2016年 FableGame. All rights reserved.//#include <iostream>#include "stdio.h"#include "stdlib.h"#include "time.h"#include "MapManager.h"using namespace FableGame;int main(int argc, const char * argv[]) {            //==========先确定一些基础的内容================    int skillDistance = 1000;//技能释放距离        SPoint attackerPoint;//攻击者位置    attackerPoint.x = 0;//攻击者位置    attackerPoint.y = 1;//攻击者位置        SPoint defenserPoint;//被攻击者位置或技能释放点    defenserPoint.x = 8;//被攻击者位置或技能释放点    defenserPoint.y = 8;//被攻击者位置或技能释放点        SeqSPoint otherRoles;//其他需要检测的角色    //其他角色位置,为了方便测试,在每个格子都放一个人吧。    //otherRoles其他需要检测的角色    for (int i = 0; i <= 10; i++) {        for (int j = 0; j <= 10; j++) {            SPoint p;            p.x = i;            p.y = j;            otherRoles.push_back(p);        }    }        int count = 1000000;//提高执行次数有助于减低一些公共开销的时间的比例    std::cout << "Fable Game! 执行次数次数"<<count<<std::endl;    //=====啥都不做,看看时间=========    {                clock_t startTime = clock();//开始时间        int i = 0;        while (i < count) {            i++;        }        clock_t endTime = clock();//结束时间        std::cout << "什么都不做,就循环1000次的时间:"<< (endTime-startTime)/1000 <<"毫秒"<<std::endl;        //除以1000,是因为MacBook中使用微秒的,这里用毫秒把    }    //=====点对点的检测=========    {        clock_t startTime = clock();//开始时间        int i = 0;        while (i < count) {            i++;            for (SeqSPoint::iterator iter = otherRoles.begin(); iter != otherRoles.end(); iter++) {                if (CMapManager::isFarThanDistance(attackerPoint, *iter, skillDistance)) {                    //在攻击范围内的点,可以进行攻击                }            }        }                clock_t endTime = clock();//结束时间         std::cout << "点对点的检测,使用时间:"<< (endTime-startTime)/1000 <<"毫秒"<<std::endl;        //除以1000,是因为MacBook中使用微秒的,这里用毫秒把    }    //=====扇形=========    {        SeqSPoint angleConfigs;//扇形的配置        for (int cellNum = 1; cellNum <= 3; cellNum++) {            SPoint p;//p点的具体值在这里没意义的,但是这里想让它跑完整个循环            p.x = 60;//角度            p.y = 1000;//半径            angleConfigs.push_back(p);                    clock_t startTime = clock();//开始时间            int i = 0;            while (i < count) {                i++;                for (SeqSPoint::iterator iter = otherRoles.begin();                     iter != otherRoles.end();                     iter++) {                    if (CMapManager::checkInFan(angleConfigs, attackerPoint, defenserPoint, *iter)) {                    //在扇形范围内的点,可以进行攻击                    }                }            }                    clock_t endTime = clock();//结束时间            std::cout << "扇形算法的检测,扇形的个数"<<angleConfigs.size()<<"使用时间:"<< (endTime-startTime)/1000 <<"毫秒"<<std::endl;            //除以1000,是因为MacBook中使用微秒的,这里用毫秒把        }    }    //=====矩形=========    {        clock_t startTime = clock();//开始时间        int i = 0;        while (i < count) {            i++;            for (SeqSPoint::iterator iter = otherRoles.begin(); iter != otherRoles.end(); iter++) {                if (CMapManager::inRectRelat(attackerPoint, defenserPoint, *iter)) {                    //在矩形范围内的点,可以进行攻击                }            }        }                clock_t endTime = clock();//结束时间        std::cout << "矩形算法的检测,使用时间:"<< (endTime-startTime)/1000 <<"毫秒"<<std::endl;        //除以1000,是因为MacBook中使用微秒的,这里用毫秒把    }    //=====圆形=========    {        clock_t startTime = clock();//开始时间        int i = 0;        while (i < count) {            i++;            for (SeqSPoint::iterator iter = otherRoles.begin(); iter != otherRoles.end(); iter++) {                if (CMapManager::isFarThanDistance(attackerPoint, *iter, skillDistance)) {                    //在攻击范围内的点,可以进行攻击                }            }        }                clock_t endTime = clock();//结束时间        std::cout << "圆形算法的检测,使用时间:"<< (endTime-startTime)/1000 <<"毫秒"<<std::endl;        //除以1000,是因为MacBook中使用微秒的,这里用毫秒把    }    //==========================================================    //================通过格子的配置来实现各种形状===================    //==========================================================    {        SeqSPoint pointConfigs;        for (int cellNum = 1; cellNum <= 20; cellNum++) {            SPoint p;//p点的具体值在这里没意义的,但是这里想让它跑完整个循环            p.x = 10000;            p.y = 10000;            pointConfigs.push_back(p);                        clock_t startTime = clock();//开始时间            int i = 0;            while (i < count) {                i++;                for ( SeqSPoint::iterator iter = otherRoles.begin(); iter != otherRoles.end(); iter++) {                    if (CMapManager::checkInCell(pointConfigs, attackerPoint, *iter) ) {                        //在攻击范围内的点,可以进行攻击                    }                }            }                        clock_t endTime = clock();//结束时间            std::cout << "格子算法的检测,格子数"<<pointConfigs.size()<<"使用时间:"                << (endTime-startTime)/1000 <<"毫秒"<<std::endl;            //除以1000,是因为MacBook中使用微秒的,这里用毫秒把        }            }       return 0;}




1 0
原创粉丝点击