GameUnity 2.0 文档(四) 网格+四叉树 最优碰撞检测
在写之前,必须对 前一篇文档补充一下。
Camera2DAngle类是 摄像机旋转 2d人物360度,PlayerMove是人物移动。
这两个类 都可以 360 ° 场景旋转人物也跟着旋转。
但不能同时用。 前者更倾向于 不移动的 人物。后者倾向于 移动的人物。 但精度 前者 高于 后者。具体根据项目需求 选择。
今天 介绍的类 CollisionDetection 碰撞检测类
public GameObject GridPrefab;//网格块材料
public int RangeLength;//网格块范围
public bool showGrid;//是否显示
第一个参数,是网格的图形,你可以用 任何模型 作为一个网格的形状。当然这不是必须要显示的
第二个参数,取值为0--max,当0的时候,就是九宫格,1的时候是 25宫格,2的时候49宫格,3的时候81宫格,规律是 (2n+1)(2n+1);
第三个参数,是否显示,如果不选,则第一个参数 不需要填写。
下面我们来看看效果
说明下,添加位置和disk相同。我用cube作为网格形状,我选择的范围是0和1,也就是9和25宫格,我让他显示,当然,最好建议不要选择显示,这样会影响效率。
这张是我旋转之后的图,看的出人物方向还是面对面过来的。
有人问,为何范围一定要 9,25,49,81这类的。其实 大家仔细想下就知道,我要让 人物 永远保证在中心点,那么 奇数 *奇数才能确保这样。
网格计算是协程方式,测试在2000左右手机下,同屏显示 300人 走动碰撞检测保证在35帧以上。低端手机 也能满足同屏 100+人 不卡。
下一篇,AI。
链接:http://pan.baidu.com/s/1G5DAA 密码:v2kl
最优网格四叉法代码
前一阵子,我想想,其实给一点代码也没什么,所以就放一部分 代码大家看看。
这个是 其原理图,我自己画的,画工一般。概念就是 人物在填充里面 是 只检测 绿色填充,而走到红蓝线 开始检测不同 的临界区。
同时,为了记录和检索不要那么频繁,也优化过了。
检测精度非常高,比如人物在2 这个点,图上有,那么他检测的 首先是 0,然后是 2的对角。然后2的两边。
如果人物在0 那么他只检测0;同时还有方向的约束,可以优先检索顺序。
测试下来,比触发碰撞 效率高2倍。如果做游戏,优化最大,几乎达到 一半的 无碰撞性能。
using UnityEngine;
using System.Collections;
using UnityEngine.UI; public class ceshi : MonoBehaviour
{
float widths, heights;
public float x1;
public float x2;
public float y1;
public float y2; private int w;
private int h;
public bool stop;
void Start()
{ }
void OnEnable()
{
stop = true;
Vector2 v = Camera.main.WorldToScreenPoint(this.transform.position);
widths = Screen.width / ;
heights = Screen.height / ;
w = (int)(v.x / widths);
h = (int)(v.y / heights);
//初始化 人物 坐标 对应的 网格 位置,并保存到 网格内
OnInstet(w, h);
}
//插入数据
void OnInstet(int w, int h)
{
Vector2 VectorGrid = new Vector2(w, h);
ArrayList arrlist = GameModel.getInstance().GridList[VectorGrid]; if (!arrlist.Contains(transform.name))
{
GameModel.getInstance().GridList[VectorGrid].Add(transform.name);
}
else
{
int Indexs = GameModel.getInstance().GridList[VectorGrid].IndexOf(transform.name);
GameModel.getInstance().GridList[VectorGrid].RemoveAt(Indexs);
}
} bool sortGird(int w, int h)
{
ArrayList arr = new ArrayList();
if (w < )
{
w = ;
}
if (h < )
{
h = ;
}
if (w > )
{
w = ;
}
if (h > )
{
h = ;
}
Vector2 VectorGrid = new Vector2(w, h);
arr = GameModel.getInstance().GridList[VectorGrid];
if (OnSetArmy(arr))
{
return true;
}
return false;
} bool OnSetArmy(ArrayList arr)
{
if (arr.Count > )
{
for (int i = ; i < arr.Count; i++)
{
if (arr[i] != this.transform.name)//如果不是自己
{ stop = false;//停止检测
return true;
}
}
}
return false;
}
//查询数据
void OnFindData(int vector)
{
//根据人物 角度 选择 从 哪个开始
switch (vector)
{
case : //中间
sortGird(w, h);
break;
case : //左上
if (sortGird(w, h))//自己
{
break;
} if (sortGird(w - , h + )) { break; }//左上对角
if (sortGird(w - , h)) { break; }//左
if (sortGird(w, h + )) { break; }//上
//找出一个 就跳转
break;
case : //右上
if (sortGird(w, h)) { break; }//自己
if (sortGird(w + , h + )) { break; }//右上对角
if (sortGird(w + , h)) { break; }//右
if (sortGird(w, h + )) { break; }//上
break;
case : //左下
if (sortGird(w, h)) { break; }//自己
if (sortGird(w - , h - )) { break; }//左下对角
if (sortGird(w - , h)) { break; }//左
if (sortGird(w, h - )) { break; }//下
break;
case : //右下
if (sortGird(w, h)) { break; }//自己
if (sortGird(w + , h - )) { break; }//右下对角
if (sortGird(w - , h)) { break; }//右
if (sortGird(w, h - )) { break; }//下
break;
case : //上
if (sortGird(w, h)) { break; }//自己
if (sortGird(w, h + )) { break; }//上
break;
case : //右
if (sortGird(w, h)) { break; }//自己
if (sortGird(w + , h)) { break; }//右
break;
case : //下
if (sortGird(w, h)) { break; }//自己
if (sortGird(w, h - )) { break; }//下
break;
case : //左
if (sortGird(w, h)) { break; }//自己
if (sortGird(w - , h)) { break; }//左
break;
default: break;
} } private bool top;
private bool bottom;
private bool left;
private bool right; //判断是否在临界点
void OnRectPostion(bool tops = true, bool bottoms = true, bool lefts = true, bool rights = true)
{
top = tops;
bottom = bottoms;
left = lefts;
right = rights;
} //存储网格数据
void Storage()
{
Vector2 v = Camera.main.WorldToScreenPoint(this.transform.position);
int w_new = (int)(v.x / widths);
int h_new = (int)(v.y / heights);
int ww = w, hh = h;
if (w_new != w)
{
if (w_new < w)
{
int w1 = (int)(v.x) % (int)(widths);
if (w1 < x2)
{
//进入了下一个格子 存储数据
OnRectPostion();//判断是否在临界点
ww = w_new;
// print("111");
}
else
{
//偏左 进入临界点
left = false;
}
}
else
{
int w1 = (int)(v.x) % (int)(widths);
if (w1 > x1)
{ //进入了下一个格子
OnRectPostion();
ww = w_new;
// print("222");
}
else
{
// 偏右 进入临界点
right = false;
}
}
}
/////////////////////////////////////////////////////////////
if (h_new != h)
{
if (h_new < h)
{
int h1 = (int)(v.y) % (int)(heights);
if (h1 < y2)
{
//进入了下一个格子
OnRectPostion();
hh = h_new;
// print("333");
}
else
{
//偏上 进入临界点
top = false;
}
}
else
{
int h1 = (int)(v.y) % (int)(heights);
if (h1 > y1)
{ //进入了下一个格子
OnRectPostion();
hh = h_new;
// print("444");
}
else
{
//偏下 进入临界点
bottom = false;
}
}
}
///////////////
OnInstet(w, h);//删除老数据
OnInstet(ww, hh);//添加新数据
w = ww;
h = hh; //换新 }
//查询人物网格内的碰撞
void FindGrid()
{
//如果在上面
if (!top)
{
if (!left)//左上
{
OnFindData();
}
else if (!right)//右上
{
OnFindData();
}
else
{ //上
OnFindData();
} return;
} //如果在下面
if (!bottom)
{
if (!left)//左下
{
OnFindData();
}
else if (!right)//右下
{
OnFindData();
}
else
{ //下
OnFindData();
} return;
}
//如果在左边
if (!left)
{
if (!top)//左上
{
OnFindData();
}
else if (!bottom)//左下
{
OnFindData(); }
else //左边
{
OnFindData();
}
return;
}
//如果在右边
if (!right)
{
if (!top)//右上
{
OnFindData();
}
else if (!bottom)//右下
{
OnFindData();
}
else //右边
{
OnFindData();
}
return;
}
//不在临界点
if (top && bottom && left && right)
{
OnFindData();
}
}
void Update()
{
//存储坐标 和 找出临界点
Storage();
///////////////////////////
//判断临界点 的位置,找出 需要 检索的 格子。
if (stop)
{
FindGrid();
}
}
}
GameUnity 2.0 文档(四) 网格+四叉树 最优碰撞检测的更多相关文章
- GameUnity 2.0 文档(三) 纸片人八方向
DirectSprite类 有别于 上篇文档出现的 AnimationSprite类 (从头播放到尾) 这个类根据 path的图,如果是 8*8 64个图 八方向,可以设置长宽和 角度 角度 代表 8 ...
- GameUnity 2.0 文档(五) 人工智能之---------------Flocking算法 (聚集,分散,列队 )
AI是游戏的灵魂,是人物的智商,是让玩家觉得游戏是否幼稚的重要判断功能,下面我将介绍国外流行,国内不行的,ai算法. 主要介绍 Flocking 和 Reciprocal Velocity Obs ...
- GameUnity 2.0 文档(二) 纸片人系统
本想快速的 把 之前写的类库,一股脑的 给大家 ,但又觉得,如 msdn那样的 文档,并不能给 初学者 所能接受. 因为 大部分人 对 api 还是比较陌生,也不愿意 去研究和组合. 那么 今天我选用 ...
- GameUnity 2.0 文档(一) 事件机制
新版本和旧版本一样,有socket事件和内部事件.区别在于,你只要一个监听就可以 消息协议规则: 用类名标记协议的好处是什么? 是利用反射机制来处理每个消息. 程序启动的时候,会读取所有类名,并字典保 ...
- 中文翻译:pjsip文档(四)之ICE Session的使用方法
1:pjsip教程(一)之PJNATH简介 2:pjsip教程(二)之ICE穿越打洞:Interactive Connectivity Establishment简介 3:pjsip教程(三)之ICE ...
- vue mand-mobile按2.0文档默认安装的是1.6.8版本
vue mand-mobile按2.0文档默认安装的是1.6.8版本 npm list mand-mobilebigbullmobile@1.0.0 E:\webcode\bigbullmobile` ...
- Beautiful Soup 4.2.0 文档
Beautiful Soup 4.2.0 文档 Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方 ...
- css2.0文档查阅及字体样式
css2.0文档查阅下载 网址:http://soft.hao123.com/soft/appid/9517.html <html xmlns="http://www.w3.o ...
- c#中操作word文档-四、对象模型
转自:http://blog.csdn.net/ruby97/article/details/7406806 Word对象模型 (.Net Perspective) 本文主要针对在Visual St ...
随机推荐
- shp文件显示
开发环境 Win7, VS2010 Sp1 QGIS 2.01 #include <qgsapplication.h> #include <qgsproviderregistry.h ...
- Windows系统新建gitignore文件出现“必须键入文件名”错误的解决办法
今天打算把本地的项目用git推送到github上去,但是有的信息我又不想把它加入到版本控制系统中去,例如.classpath文件和.class文件等等,这个时候我就想到了使用.gitignore文件把 ...
- 关于NLog的target和Layout
这个没啥好说的,都是用别人的东西,看文档就行了,写的很详细. https://github.com/NLog/NLog/wiki/Configuration-file https://github.c ...
- hitTest:withEvent:方法流程
此方法可实现点击穿透.点击下层视图功能. 一. hitTest:withEvent:调用过程 iOS系统检测到手指触摸(Touch)操作时会将其放入当前活动Application的事件队列,UIApp ...
- redis的常用命令
键值得相关命令: keys * 返回满足给定patternd的所有key exists 确认一个key是否存在 del 删除一个key expire 设置一个key的过期时间 ttl 查看过期时间还有 ...
- Windows文件监视器 1.0 绿色版
软件名称:软件名称: Windows文件监视器 软件语言: 简体中文 授权方式: 免费软件 运行环境: Win7 / Vista / Win2003 / WinXP / Win2008 软件大小: 1 ...
- 简单的javasrcipt选项卡
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta char ...
- lucene 索引创建步骤
一.步骤: 1.存储位置:1)文件: Directory dir= FSDirectory.open(new File("D:\\LuceneIndex")); 2)内存: new ...
- Day06 杂乱与4个对象
1.杂乱 -- 数据库的分页操作 -- 分页使用的是rownum 例1: select rownum,empno,ename from emp ; 结果: 例2: select r,empno,ena ...
- c语言_头文件
传统 C++ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <assert.h> //设定插入点 #include <ctyp ...