关于个人对Linecast的一些理解和应用
首先申明下自己是一个刚学unity3d和c#的小白,如果接下来有什么理解不正确的地方以及可以改进的地方,欢迎大佬帮助我成长。
因为目前正在做一个坦克大战的游戏模仿,所以用到了碰撞检测。但是看了一些博客,发现讲的不是特别详细,所以决定写这篇博客,一方面是希望自己能坚持学习下去,另一方面给比我还萌新的同学一个参考。
linecast直线投射是一种碰撞检测的方法,在程序中的应用为初始化 private RaycastHit2D hit, 暂时取消物体本身的碰撞器boxCollider.enabled = false(检测完毕恢复),然后调用
hit = Physics2D.Linecast(start, end, blockingLayer) 进行碰撞检测。其中start是线在世界空间的开始点,end为线在世界空间的结束点,blockingLayer是unity3d里面设置的能够被检测到的图层。需要注意的是:这个线段的出发点是绑定这个脚本的物体的中点,如下图:
从这个图中其实我们就能够发现一个问题,那就是中心点到物体边界的这段距离并没有加入进来,这样会导致的一个结果就是物体会嵌入到要碰撞检测的物体里面。如下图:
从上图可以知道物体已经嵌入到了障碍物中,但是linecast并没有检测到碰撞器,那是不是将中心点到边界的这段距离加上就可以了呢?答案也不是。情况见下图:
所以linecast的中心点到边界的距离到底预留多少合适或者什么时候可以不预留(不预留就是加上中心点到边界的距离),这个得看你设置的角色的移动一次的距离,总的来说是设置的移动一次的距离越小,那么中心点到边界可以预留的值也就越小,当移动一次的距离非常小时,那么边界的值可以不用做预留,因为这时候的间隙小于移动一次的距离已经可以忽略不计。需要注意的是你预留了多少值,就代表你的角色能够嵌入到障碍物多少值,而角色移动一次的距离减去你预留的值就是角色和障碍物之间会保持的最大间距。以目前我的坦克大战的角色为例:我的角色移动一次的距离为0.167,我的角色和障碍物的碰撞器都为正方形边长为1,那么角色中心点到边界的距离为0.5,我加上的中心点到边界的值为0.45,所以我的角色的嵌入不会超过0.05,角色与障碍物的间距不超过0.117,附上角色移动的嵌入位置坐标:
由图可知,嵌入的距离为0.0159967,但在图中很难看出来。以上为本次个人对linecast的一些理解。接下将分享下自己对linecast的一点应用,针对的情况如下图:
很多情况下一条射线并不能解决问题,当出现中点超过障碍物边界的时候,碰撞检测无法成功,角色能嵌入到障碍物中去。所以在这次的学习游戏开发中,我使用了三条射线。当角色左右移动时,改变射线的起点及结束点的y值两次(一加,一减),实现逻辑上的上下两端检测,当角色上下移动时,改变射线的起点及结束点x值两次,实现逻辑上的左右两端检测。(为什么是逻辑上的?因为实际发射的还是中心点,只是效果等同于在两端发射了射线。)
首先附上代码(代码比较繁琐,还有很大提升空间):
private bool ismove(float xDir, float yDir)
{
boxCollider.enabled = false;
Vector2 start = this.transform.position;
Vector2 end = (start + new Vector2(xDir, yDir) * beilv);
hit = Physics2D.Linecast(start, end, blockingLayer);
boxCollider.enabled = true;
if (hit.transform == null)
{
if (xDir != 0)
{
boxCollider.enabled = false;
Vector2 startl = this.transform.position;
startl += new Vector2(0, jiance);
Vector2 endl = (start + new Vector2(xDir, yDir) * beilv) + new Vector2(0, jiance);
Vector2 startr = this.transform.position;
startr += new Vector2(0, -jiance);
Vector2 endr = (start + new Vector2(xDir, yDir) * beilv) - new Vector2(0, jiance);
hitl = Physics2D.Linecast(startl, endl, blockingLayer);
hitr= Physics2D.Linecast(startr, endr, blockingLayer);
boxCollider.enabled = true;
if (hitl.transform == null && hitr.transform == null)
{
Move(xDir, yDir);
return true;
}
else
{
cantmove(xDir, yDir);
return false;
}
}
else
{
boxCollider.enabled = false;
Vector2 startl = this.transform.position;
startl += new Vector2(jiance, 0);
Vector2 endl = (start + new Vector2(xDir, yDir) * beilv) + new Vector2(jiance, 0 );
Vector2 startr = this.transform.position;
startr += new Vector2(-jiance, 0);
Vector2 endr = (start + new Vector2(xDir, yDir) * beilv) -new Vector2(jiance, 0);
hitl= Physics2D.Linecast(startl, endl, blockingLayer);
hitr= Physics2D.Linecast(startr, endr, blockingLayer);
boxCollider.enabled = true;
if (hitl.transform == null && hitr.transform == null)
{
Move(xDir, yDir);
return true;
}
else
{
cantmove(xDir, yDir);
return false;
}
}
}
else
{
cantmove(xDir, yDir);
return false;
}
}
xDir及yDir为 Input.GetAxisRaw()函数乘以相应的自己设置的移动速度,定义了三个2d射线碰撞检测器分别为hit,hitl,hitr,变量beilv为3.7,2.7*0.167=0.4509约为0.45即中心点距离边界预留0.05,变量jiance为中心点上下左右平移的距离0.4。首先在中点检测是否碰撞,如果没有碰撞再判定角色的移动方向,然后分别平移中点到两端进行碰撞检测,如果两端都没有碰撞到物体则执行移动函数,其余情况全部执行不能移动函数。大致思想如此,具体的数值设定根据自己的设计做出相应调整即可。
以上,祝好。