首先,我为在这里抛出这么多代码而道歉。虽然我认为可能有 5% 对这个问题很重要,但我宁愿不遗余力。
我对 Unity 比较陌生,我正在制作一个游戏原型,你可以在其中放置军队与另一个玩家,他们在类似于 Mage 和 Monsters 的 2D 平面上战斗。
我正在用两个单元进行测试,每队一个,似乎无论如何,第 2 队总是先击中并且总是赢得战斗 - 没有可变性。虽然我打算增加暴击率等等,但如果 Team2 总是先击中,他们就有先天优势。
这些单位共享完全相同的统计数据。
我尽我所能确保两个单元同时初始化,并且在这种情况下它们不会启动。然而,无论 Unit2(Team2 的)是什么,总是先开始,先命中,因此获胜。
这是我的 BaseUnit 代码,它是 this repo:
public class BaseUnit : MonoBehaviour
{
public UnitData unitData;
public int baseHealth;
public int health;
public int level;
public int damage;
public float range;
public float attackSpeed;
public float movementSpeed;
public Team myTeam;
public bool IsReady = false;
public bool IsPlaying = false;
protected BaseUnit currentTarget = null;
protected bool HasEnemy => currentTarget != null;
protected bool IsInRange => currentTarget != null && Vector3.Distance(this.transform.position, currentTarget.transform.position) <= range;
protected bool dead = false;
protected bool canAttack = true;
protected float waitBetweenAttack;
void Start()
{
baseHealth = unitData.health;
health = baseHealth;
level = unitData.level;
damage = unitData.damage;
range = unitData.range;
attackSpeed = unitData.attackSpeed;
movementSpeed = unitData.movementSpeed;
UnitManager.Instance.OnRoundStart += OnRoundStart;
UnitManager.Instance.OnRoundEnd += OnRoundEnd;
UnitManager.Instance.OnUnitDied += OnUnitDied;
IsReady = true;
}
protected virtual void OnRoundStart() {
Debug.Log(gameObject.name + " OnRoundStart!");
IsPlaying = true;
}
protected virtual void OnRoundEnd() { }
protected virtual void OnUnitDied(BaseUnit diedUnit) { }
protected void FindTarget() {
var allEnemies = UnitManager.Instance.GetUnitsAgainst(myTeam);
float minDistance = Mathf.Infinity;
BaseUnit entity = null;
foreach (BaseUnit be in allEnemies) {
if (Vector3.Distance(be.transform.position, this.transform.position) <= minDistance) {
minDistance = Vector3.Distance(be.transform.position, this.transform.position);
entity = be;
}
}
currentTarget = entity;
}
protected void GetInRange() {
if (Mathf.Abs(Vector3.Distance(currentTarget.transform.position, this.transform.position)) > range) {
var step = movementSpeed * Time.deltaTime;
this.transform.position = Vector3.MoveTowards(this.transform.position, currentTarget.transform.position, step);
}
}
public void TakeDamage(int incomingDamage) { // Maybe add damage type eventually
baseHealth -= incomingDamage;
if (baseHealth <= 0 && !dead) {
dead = true;
UnitManager.Instance.UnitDead(this);
}
}
protected virtual void Attack() {
if (!canAttack) {
return;
}
waitBetweenAttack = 1 / attackSpeed;
StartCoroutine(WaitCoroutine());
}
IEnumerator WaitCoroutine()
{
canAttack = false;
yield return new WaitForSeconds(waitBetweenAttack);
canAttack = true;
}
}
My MeleeUnit 这是每个单位使用的类别:
public class MeleeUnit : BaseUnit
{
protected override void OnRoundStart() {
base.OnRoundStart();
Debug.Log("Melee OnRoundStart for " + gameObject.name);
FindTarget();
}
public void Update() {
if (!IsPlaying) {
return;
}
if (!HasEnemy) {
FindTarget();
}
if (IsInRange) {
if (canAttack) {
Attack();
currentTarget.TakeDamage(damage);
}
}
}
public void FixedUpdate() {
if (!IsPlaying) {
return;
}
if (!HasEnemy) {
return;
}
if (!IsInRange) {
GetInRange();
}
}
}
最后是 UnitManager 类:
public class UnitManager : Manager<UnitManager>
{
private string teamOneTag = "Team1";
private string teamTwoTag = "Team2";
public List<BaseUnit> teamOne = new List<BaseUnit>();
public List<BaseUnit> teamTwo = new List<BaseUnit>();
public bool IsPlaying = false;
public Action OnRoundStart;
public Action OnRoundEnd;
public Action<BaseUnit> OnUnitDied;
private void Start()
{
Debug.Log(gameObject.name + " starting");
PopulateTeam(teamOne, teamOneTag);
PopulateTeam(teamTwo, teamTwoTag);
StartCoroutine(WaitForAllObjectsToBeReady());
}
private bool UnitsAreReady() {
foreach (BaseUnit unit in teamOne) {
if (!unit.IsReady) {
return false;
}
}
foreach (BaseUnit unit in teamTwo) {
if (!unit.IsReady) {
return false;
}
}
return true;
}
IEnumerator WaitForAllObjectsToBeReady()
{
while (!UnitsAreReady()) {
Debug.Log("Waiting for 0.5 seconds.");
yield return new WaitForSeconds(0.5f);
}
Debug.Log("Invoking OnRoundStart.");
OnRoundStart?.Invoke();
}
public void UnitDead(BaseUnit unit) {
teamOne.Remove(unit);
teamTwo.Remove(unit);
Debug.Log("Deleting " + unit.gameObject.name);
OnUnitDied?.Invoke(unit);
Destroy(unit.gameObject);
}
private void PopulateTeam(List<BaseUnit> team, string tag) {
var teamUnits = GameObject.FindGameObjectsWithTag(tag);
foreach (var unit in teamUnits) {
team.Add(unit.GetComponent<BaseUnit>());
}
}
public List<BaseUnit> GetUnitsAgainst(Team against) {
return against == Team.Team1
? teamTwo : teamOne;
}
}
关于如何正确处理此类事情的任何意见,以便哪支球队可能获胜存在一些差异?
谢谢
也许您可以尝试添加 3 或 4 个团队,看看会发生什么。我仍在阅读代码(如果您的团队成长或遇到问题,您可以为自己和其他任何人添加一些评论)但是如果您可以像这样进行一些故障查找,也许您可以弄清楚发生了什么。
如果你确实添加了 4 个团队并且轮次顺序是 4,3,2,1 那么我会假设这些单位是按升序初始化的,然后调用 WaitForAllObjectsToBeReady() 协程并且从中返回的顺序被取消(因为1 首先调用它,然后是 2,然后是 3,然后是 4,一旦 4 准备就绪,它就位于列表的顶部,是最近准备好的)?