排斥矢量

时间:2018-03-15 20:49:45

标签: c++ algorithm sfml

我正在尝试在SFML和C ++中为Turrets游戏实现一个基本AI,但我遇到了一些问题。 这个AI遵循Bezier Courve中建立的一些方法点。 首先,这条道路只跟着一个敌人。为此目的,敌人必须计算他的实际位置之间的距离 到他必须选择的下一个航路点。 如果距离小于我们坚持的特定值,那么,我们到达下一个点。这将重复,直到达到最终目的地。 (在提交代码中,忘记var m_go)

好吧,当我们产生几个敌人并且所有人都必须遵循相同的路径时,我们的问题就会出现,因为它产生了一个糟糕的视觉效果(每个人都有另一个上升空间)。 为了解决这个视觉问题,我们决定使用排斥矢量。微积分如下:representation of what we want

如你所见,我们用敌人和他最近邻居之间距离的倒数来计算排斥向量。 然后,我们将其应用于"理论"方向,通过添加它,我们得到一个结果,这是方向 我们的敌人必须遵循不“碰撞”#34;与它的邻居。 但是,我们的问题来自: 这些敌人在曲线中间被摧毁,当我们产生更多的敌人时,它们的速度都会急剧增加(包括那些不能计算重复矢量的敌人)。

1 - 通常情况下,这种分离会在轨迹中间出现吗?

2 - 在没有速度受到影响的情况下,有没有办法控制这个方向?

3 - 这个理论还有其他选择吗?

我提交下面的代码(西班牙文[resultante]中有一个变量,这意味着英文结果):

if (!m_pathCompleted) {
    if (m_currentWP == 14 && m_cambio == true) {
        m_currentWP = 0;
        m_path = m_pathA;
        m_cambio = false;
    }

    if (m_neighbors.size() > 1) {
        for (int i = 0; i < m_neighbors.size(); i++) {
            if (m_enemyId != m_neighbors[i]->GetId()) {

                float l_nvx = m_neighbors[i]->GetSprite().getPosition().x - m_enemySprite.getPosition().x;
                float l_nvy = m_neighbors[i]->GetSprite().getPosition().y - m_enemySprite.getPosition().y;
                float distance = std::sqrt(l_nvx * l_nvx + l_nvy * l_nvy);

                if (distance < MINIMUM_NEIGHBOR_DISTANCE) {
                    l_nvx *= -1;
                    l_nvy *= -1;

                    float l_vx = m_path[m_currentWP].x - m_enemySprite.getPosition().x;
                    float l_vy = m_path[m_currentWP].y - m_enemySprite.getPosition().y;

                    float l_resultanteX = l_nvx + l_vx;
                    float l_resultanteY = l_nvy + l_vy;

                    float l_waypointDistance = std::sqrt(l_resultanteX * l_resultanteX + l_resultanteY * l_resultanteY);

                    if (l_waypointDistance < MINIMUM_WAYPOINT_DISTANCE) {
                        if (m_currentWP == m_path.size() - 1) {
                            std::cout << "\n";
                            std::cout << "[GAME OVER]" << std::endl;
                            m_go = false;
                            m_pathCompleted = true;
                        } else {
                            m_currentWP++;
                        }
                    }

                    if (l_waypointDistance > MINIMUM_WAYPOINT_DISTANCE) {
                        l_resultanteX = l_resultanteX / l_waypointDistance;
                        l_resultanteY = l_resultanteY / l_waypointDistance;
                        m_enemySprite.move(ENEMY_SPEED * l_resultanteX * dt, ENEMY_SPEED * l_resultanteY * dt);
                    }

                } else {

                    float vx = m_path[m_currentWP].x - m_enemySprite.getPosition().x;
                    float vy = m_path[m_currentWP].y - m_enemySprite.getPosition().y;
                    float len = std::sqrt(vx * vx + vy * vy);

                    if (len < MINIMUM_WAYPOINT_DISTANCE) {
                        if (m_currentWP == m_path.size() - 1) {
                            std::cout << "\n";
                            std::cout << "[GAME OVER]" << std::endl;
                            m_go = false;
                            m_pathCompleted = true;
                        } else {
                            m_currentWP++;
                        }
                    }

                    if (len > MINIMUM_WAYPOINT_DISTANCE) {
                        vx = vx / len;
                        vy = vy / len;
                        m_enemySprite.move(ENEMY_SPEED * vx * dt, ENEMY_SPEED * vy * dt);
                    }
                }
            }
        }
    } else {
        float vx = m_path[m_currentWP].x - m_enemySprite.getPosition().x;
        float vy = m_path[m_currentWP].y - m_enemySprite.getPosition().y;

        float len = std::sqrt(vx * vx + vy * vy);

        if (len < MINIMUM_WAYPOINT_DISTANCE) {
            if (m_currentWP == m_path.size() - 1) {
                std::cout << "\n";
                std::cout << "[GAME OVER]" << std::endl;
                m_go = false;
                m_pathCompleted = true;
            } else {
                m_currentWP++;
            }
        }

        if (len > MINIMUM_WAYPOINT_DISTANCE) {

            vx = vx / len;
            vy = vy / len;

            m_enemySprite.move(ENEMY_SPEED * vx * dt, ENEMY_SPEED * vy * dt);
        }
    }
}

1 个答案:

答案 0 :(得分:0)

我将逐一尝试回答您的问题,但首先,我没有在代码中看到任何可怕的错误,因此它可能只是一组非预期的情况。

  

1 - 通常这种分离在中间发生   轨迹?

嗯,你正在根据足够其他人的距离向每个敌人施加排斥力。如果发生奇怪的事情,或者如果你移动它们超过必要的范围,可能会导致与原始轨迹的相当大的偏差。

  

2 - 是否有办法在没有速度的情况下控制这个方向   受到影响?

在这一行

m_enemySprite.move(ENEMY_SPEED * l_resultanteX * dt, ENEMY_SPEED * l_resultanteY * dt);

事实上,我们看到你正在应用基于l_resultante向量的排斥力。该向量直接取决于l_nv(排斥向量),其模块(或长度比例this之间的距离(敌人)正在处理)和other(邻居)。当你将这个向量乘以敌人的速度(一个常数值)时,距离越大,施加的力就越大,它们之间就会有更多的分离。

我建议你:

  • 规范化向量 l_nv更容易):这是强制它拥有模块1.使用此解决方案,每个敌人都会被推送使用相同的力量(基本上ENEMY_SPEED),但方向正确。

  • 反转向量 l_nv稍微强硬):如果应用此向量与距离成反比(模块= 1 /距离)他们会表现相反,如果彼此离得更远,他们就会被推得更少。

还要考虑您是连续施加力量,并且每个处理过的邻居都会使它们生效。这意味着不可取的事情如果你推动一个敌人,这个部队可以将它移动到一个未来的敌人(在for循环中)可能比以前推动更多的位置。如果这种效果连续多次,可能会引发连锁反应,你的敌人被推得越来越多。如果你施加与距离成比例的力,这种效应会被放大。

  

3 - 这个理论还有其他选择吗?

我实际上没有想法,但如果有人想编辑答案并提出建议,我就把这个空间留在这里