需要帮助在c#游戏代码
我正在制作一个统一的塔防游戏,但我卡住了。我希望我的枪或炮塔面对敌人,直到他们超出范围,但每0.5秒后它会更新并面对其范围内的另一个敌人,尽管第一个敌人也在范围内。需要帮助在c#游戏代码
这里是我的代码:
void Start()
{
InvokeRepeating("UpdateTarget", 0f , 0.5f);
}
void UpdateTarget()
{
GameObject[] enemies = GameObject.FindGameObjectsWithTag(enemyTag);
float shortestDistance = Mathf.Infinity;
GameObject nearestEnemy = null;
foreach (GameObject enemy in enemies)
{
float distanceToEnemy = Vector3.Distance(transform.position, enemy.transform.position);
if (distanceToEnemy < shortestDistance)
{
shortestDistance = distanceToEnemy;
nearestEnemy = enemy;
}
}
if (nearestEnemy != null && shortestDistance <= range)
{
target = nearestEnemy.transform;
}
else
{
target = null;
}
}
GameObject.FindGameObjectsWithTag对性能的影响更大,我会建议你创建一个圆撞机2D并将其设置为触发,当OnTriggerEnter2D被称为可以获取敌人然后举起一面旗帜,以便其他敌人在此之后不会被触发,当对该敌人调用OnTriggerExit2D时,您可以开始寻找另一个敌人或选择其中一个仍然在该碰撞者半径内的敌人。
private bool _foundEnemy;
private Enemy _currentEnemy;
private void OnTriggerEnter2D(Collider2D collision)
{
if (_foundEnemy) return;
_currentEnemy = collision.GetComponent<Enemy>();
// your code here
_foundEnemy = true;
}
private void OnTriggerExit2D(Collider2D collision)
{
if(_currentEnemy!=null && collision.GetComponent<Enemy>() == _currentEnemy)
_foundEnemy = false;
}
你必须包括在UpdateTarget一个测试,应先检查,如果nearestEnemy仍然在范围和在这种情况下退出该功能,否则寻找新的目标。
逻辑应该是这个样子:
//keep old target?
if(nearestEnemy != null)
{
//calculate distance of current target here..
if(distance <= range)
return; //keep this enemy as target
}
//here comes your code for finding a new target...
如果你有一个敌人靠近,那么它就成为最近的敌人,很好。你射击它,它停止移动(出于任何原因)。另一个敌人通过它靠近你,它将永远不会是最近的敌人,因为第一个敌人还在登记。 – Everts
你是不是你想达到什么样的行为完全清楚,但似乎是锁定目标,直到它死了,然后才切换到另一个目标。这是你的代码中的一个简单的修复;但我发现了几个其他问题:
- 冗余代码,如块和变量。
- 非常多的例子如何失败要遵循Single Responsibility Principle。
- 您不需要“其中一个或另一个”方法,因为其他答案正在显示。你可以得到这两个行为与一个简单的
boolean flag
作为交换机。
这里是一些注释代码占所有这些东西,希望提供可以学习,从参考:
//Defines how to get and compare distance; used during sorting
public class DistanceComparer<T> : IComparer<T> where T : GameObject {
public int Compare(T a, T b) {
return Vector3.Distance(a.transform.position, b.transform.position);
}
}
public var bool lockToTargetUntilDead = true; //Should lock to target till it's dead (true)? Or switch to nearest if the nearest changes (false)?
//Finds nearest enemy
GameObject FindNearestEnemy() {
var enemies = GameObject.FindGameObjectsWithTag(enemyTag);
if (enemies==null || enemies.Length==0) return null; //No enemies anywhere
Array.Sort(enemies, new DistanceComparer()); //Sort enemies by distance
return enemies[0]; //Return closest enemy
}
//Determines if enemy is within range (Note: If enemy is null, it's not in range =P)
bool IsWithinRange(GameObject enemy) {
return enemy != null && Vector3.Distance(transform.position, enemy.transform.position) <= range;
}
//Updates target
void UpdateTarget() {
var nearestEnemy = FindNearestEnemy();
if(!IsWithinRange(nearestEnemy)) { //No enemies within range...
if(target != null) target = null; //Forget current target.
return; //Return-early.
}
if(lockToTargetUntilDead && target!=null) return; //If locking to current target and it ain't dead yet, return-early
target = nearestEnemy; //If not locking to target, or doesn't have a target, new target!
}
void Start() {
InvokeRepeating("UpdateTarget", 0f , 0.5f);
}
也许一开始你应该检查是否已经有一个积极的目标,如果是的话,不要改变它。例如:if(target!= null && Vector3.Distance(transform.position,target.transform.position)
是的,这听起来像是他们不希望它不断地改变目标,所以保持一个“主动目标”变量将是一个好方法。另外,我强烈建议添加一个包围炮塔范围的箱子对撞机,并用它来限制你必须搜索的敌人数量。 https://unity3d.com/learn/tutorials/topics/physics/colliders-triggers可能是有趣的。 Unity内置了强大的空间索引功能,所以很愚蠢的是不利用它。如果甚至有内置的“最近邻居”算法,我也不会感到惊讶。 – drsimonz