我试图为我的僵尸游戏中的敌人实施植绒算法,这样他们就可以聚集在一起,同时避免相互碰撞。截至目前,他们总是直接向玩家移动,如果玩家移动很多,可以使他们叠加在一起。
这让我得到了一些关于成群小僵尸的反馈,这些僵尸最终都堆叠起来,因为玩家射杀了他们(他们是一次击中的杀戮),而且因为他们之上还有更多,他们一直在告诉我看起来子弹没有击中。
我一直在研究使用植绒算法,但问题是我的游戏不使用矢量来进行敌人移动。我只是将敌人的位置作为(x,y)对,并且在更新时,他们使用atan2计算他们的面部,然后根据这个theta的cos和sin值更新他们的位置。
我可以添加向量移动,但这需要大量的重构,所以我更愿意看看是否有某种方法可以实现这种算法。这是我现在的算法。我知道有几个缺陷,但我预计至少会看到一些不同的行为 - 但僵尸仍然完全相同。
public void move(GameState gs, int delta) {
theta = Calculate.Hypotenuse(position, Globals.player.getPosition());
int neighbors = 0;
float force = 0.0f;
for(Enemy e : ((EnemyController)gs.getEntity("enemyController")).getAliveEnemies()) {
if(!e.equals(this)) {
float dist = Calculate.Distance(position, e.getPosition());
if(dist < getSeparationDistance()) {
// Add separation strength to theta.
force += Zumby.SEPARATION_STRENGTH;
neighbors++;
} else if(dist < getCohesionDistance()) {
// Add cohesion strength to theta.
force += Zumby.COHESION_STRENGTH;
neighbors++;
}
}
}
if(neighbors > 0) {
force /= neighbors;
theta += force;
}
if(!moveBlocked) {
position.x += (float)Math.cos(theta) * Zumby.SPEED * delta;
position.y += (float)Math.sin(theta) * Zumby.SPEED * delta;
}
moveBlocked = false;
bounds.setCenterX(position.x);
bounds.setCenterY(position.y);
}
我感谢任何帮助。
答案 0 :(得分:0)
我对你的问题感到困惑。
没有矢量的植绒算法?
但你确实使用了矢量数学
position.x += (float)Math.cos(theta) * Zumby.SPEED * delta;
position.y += (float)Math.sin(theta) * Zumby.SPEED * delta;
您正在将极坐标向量{theta, Zumby.SPEED * delta}
的笛卡尔形式添加到笛卡尔坐标position
您可以随时将极地转换为笛卡尔并返回,如下所示。
// description of polar and cartesian vector objects
polar = {angle, distance}
cartesian = {x, y}
// From polar to cartesian
cartesian.x = Math.cos(polar.angle) * polar.distance;
cartesian.y = Math.sin(polar.angle) * polar.distance;
// and cartesian to polar
polar.angle = Math.atan2(cartesian.y, cartesian.x);
polar.distance = Math.sqrt(cartesian.y * cartesian.y + cartesian.x * cartesian.x);
以及其他一些向量函数(缩短名称c = {x,y}
为笛卡尔,p = {a,d}
为极a
为角度,d
为距离)。
// cartesian
float length = Math.sqrt(c.x * c.x + c.y * c.y);
if (length > 0) {
c.x /= length;
c.y /= length;
} else {
c.x = 1.0; // default vector or throw an error
c.y = 0.0;
}
// polar is too easy
p.d = 1.0;
// rotate where rotate is the rotation in radians
// cartesian
float dx = Math.cos(rotate);
float dy = Math.cos(rotate);
// c1 is a new vector
c1.x = c.x * dx - c.y * dy;
c1.y = c.x * dy + c.y * dx;
// polar is again too easy
p.a += rotate;
// scale is the scaling
// cartesian scale or multiply
c.x *= scale;
c.y *= scale;
// inverse or divide
c.x /= scale;
c.y /= scale;
// polar
p.d *= scale;
// inverse
p.d /= scale;
// adding vector
// cartesian
c.x += c1.x;
c.y += c1.y;
// polar not too easy
float x = Math.cos(p.a) * p.d + Math.cos(p1.a) * p1.d;
float y = Math.sin(p.a) * p.d + Math.sin(p1.a) * p1.d;
p.a = Math.atan2(y,x);
p.d = Math.sqrt(x * x + y * y);
您可以使用可以使用笛卡尔向量的极向量执行所有相同的操作。有些形式比另一种形式更容易。
在两个表单之间进行转换非常容易,因此您无需重构所有代码。如果你有一个你不知道极地方法的操作,只需转换为笛卡儿,执行操作然后转换回极地。