我正在尝试在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);
}
}
}
答案 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 - 这个理论还有其他选择吗?
我实际上没有想法,但如果有人想编辑答案并提出建议,我就把这个空间留在这里