没有矢量的植绒算法?

时间:2018-04-12 01:04:23

标签: java algorithm game-physics

我试图为我的僵尸游戏中的敌人实施植绒算法,这样他们就可以聚集在一起,同时避免相互碰撞。截至目前,他们总是直接向玩家移动,如果玩家移动很多,可以使他们叠加在一起。

这让我得到了一些关于成群小僵尸的反馈,这些僵尸最终都堆叠起来,因为玩家射杀了他们(他们是一次击中的杀戮),而且因为他们之上还有更多,他们一直在告诉我看起来子弹没有击中。

我一直在研究使用植绒算法,但问题是我的游戏不使用矢量来进行敌人移动。我只是将敌人的位置作为(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);
}

我感谢任何帮助。

1 个答案:

答案 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);

使用哪种

您可以使用可以使用笛卡尔向量的极向量执行所有相同的操作。有些形式比另一种形式更容易。

在两个表单之间进行转换非常容易,因此您无需重构所有代码。如果你有一个你不知道极地方法的操作,只需转换为笛卡儿,执行操作然后转换回极地。