我已经有一段时间了,现在一直试图找出一种有效的方法,看看是否有东西在其他东西的视线范围内。一个很好的例子就是如果能够看到你的话,有一个向你发射火箭的球体 - 但显然不是你在墙后面。
以下是我一般的做法:
function cast(end:GameObject, walls:Array, accuracy:uint=10):Object
{
var xp:Number = skin.x;
var yp:Number = skin.y;
var ang:Number = Math.atan2(end.skin.y - yp, end.skin.x - xp);
var xvel:Number = Math.cos(ang)*accuracy;
var yvel:Number = Math.sin(ang)*accuracy;
var i:uint = 0;
for(i; i<800/accuracy; i+=accuracy)
{
xp += xvel;
yp += yvel;
var j:GameObject;
for each(j in walls)
{
if(j.skin.hitTestPoint(xp, yp))
return {visible:false, x:xp, y:yp};
}
}
return {visible:true};
}
使用它基本上是:
var sight:Object = cast(player, impassable);
if(sight.visible) trace('can see');
else trace('cant see - collision at ' + sight.x + ", " + sight.y);
可行,但正如我们所知,每增加一枚新火箭或无法通过的物体数量增加,这将会非常缓慢。
我假设有一种非常简单有效的方法,我错过了 - 我的意思是,所有的游戏都会(暗黑破坏神等)与数百个不做任何事情的敌人一起做,除非你可见。
想法?
答案 0 :(得分:4)
我的意思是,所有游戏都是这样做的(暗黑破坏神等) 有数百个不做的敌人 什么,除非你可见。
像暗黑破坏神一样的游戏使用基于磁贴的引擎,以减少计算碰撞,视线和AI行为所需的计算次数;基于磁贴的引擎诞生于您对游戏引擎的确切顾虑。
给定绝对坐标,找出任何敌人所在的特定图块并将其转换为地图上的x,y坐标是微不足道的。一旦你拥有了这个区块,就不应该太难以缩小你需要运行的“检查”的数量,以便弄清楚是否有另一个对象。
进一步采用基于磁贴的引擎,寻路在基于磁贴的游戏引擎中也非常有用,可以很容易地完成你的任务;路径距离和/或复杂性可以让您轻松判断2个对象是否可以相互“看到”。 (如果您需要走四十步,或者在迷宫般的路径中,对象彼此不可见)可能会有机会。
基于平铺的引擎彻底减少了您开始考虑的开销问题。
答案 1 :(得分:1)
保存自己必须编写这么多代码并尝试使用Box2d物理引擎进行光线投射,为你做了很多艰苦的工作,你不需要担心速度,因为box2d已经优化但是如果你坚持编码你自己的瓦片肯定是要走的路,也许有一个*寻路移动和布莱恩说射击就足够了。但是,如果您需要考虑cells.gif场景,那么只需更改磁贴搜索的条件。
答案 2 :(得分:0)
对于碰撞,维护某种网格(或空间树,但网格应该足够精细)通常是有意义的,每个单元知道其中的对象,以便您可以直接在特定空间中查找对象。 / p>
然后编写一个例程,检索所有相关的单元以进行碰撞,在这种情况下,检查沿光线的所有单元格。在检索它们时,请对其中的对象执行碰撞检查。
这段代码基本上应该这样做:
function rayCollision(start:Point, dest:Point, grid:CollisionGrid, ignore:* = null):CollisionData {
var direction:Point = new Point(dest.x - start.x, dest.y - start.y);
if (direction.length == 0) return null;//just in case
const limit:Number = direction.length;
direction.normalize(grid.cellSize);
var pos:Point = start;
var cur:Array, last:Array = null, tested:Dictionary = new Dictionary();
if (!(ignore is Function)) {
if (ignore is ICollidable) tested[ignore] = true;
else for each (var entry:* in ignore) tested[entry] = true;//assume it is a collection
}
var collision:CollisionData = null;
while (grid.containsPoint(pos) && (pos.subtract(start).length < limit) {//stop when you're off the grid or out of range
cur = grid.getCellByPoint(pos);
if (cur == last) continue;//cell already checked, skip
last = cur;
for each (var object:ICollidable in cur) {
if (tested[object] || (ignore && ignore(object))) continue;//object already checked or should be ignored, skip
tested[object] = true;
collision = object.collideWithLine(start, dest);
if (collision) return collision;
}
pos = pos.add(direction);
}
return null;
}
CollisionData
应该包含坐标和对象。 ICollidable
是任何可碰撞的接口,应该单独实现,因为例如线和墙之间的碰撞应该相当容易计算。
实际上,你应该把它变成CollisionGrid
的方法,所以你只需要去myGrid.rayCast(start, end, theCaster)
,你就可以方便地在你想要的任何东西之间投射光线。
好运的细节;)