我目前正在尝试为自己的游戏开发一个AI,该AI需要将每个小兵向敌方小兵移动特定距离,我目前正在计算所有敌方小兵之间的距离,然后我会计算当前的奴才和最接近的奴才之间的角度,然后我将应用公式:
x = minion.x + cos(angle) * distance;
z = minion.z + sin(angle) * distance;
问题在于移动似乎是随机的,它并不总是朝着敌人移动,而是随机地移动 我将在下面提供代码
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class EnemyAI : MonoBehaviour {
private float tolerance = 1.2f;
public NavMeshSurface navMesh;
private List<GameObject> board;
private List<Vector3> minionDesiredLocations;
private int currentMinionIndex = 0;
private enum State {
Draw,
Place,
GetBoard,
Move,
MinionMoving
}
private State state = State.Draw;
public GameObject PlaceCard(List<GameObject> hand)
{
//Generate a random integer to see what card to play
int randomIndex = (int) UnityEngine.Random.Range(0, hand.Count - 1);
Debug.Log("AI Generated Index: " + randomIndex);
return hand[randomIndex];
}
private bool MoveMinion(GameObject minion, List<GameObject> enemyMinions)
{
NavMeshAgent minionAgent = minion.GetComponent<NavMeshAgent>();
Card minionCard = minion.transform.Find("Card").GetComponent<Card>();
Vector3 maPosition = minion.transform.position;
//Finding the closest position of the enemy minion
float minDistance = 100.0f;
Vector3 closestMinionPosition = Vector3.negativeInfinity;
foreach (GameObject enemyMinion in enemyMinions)
{
//Calculating distance beetween the enemy AI minion and the enemy
float distance = Vector3.Distance(minion.transform.position, enemyMinion.transform.position);
if (distance <= minDistance)
{
minDistance = distance;
//Attacking the minion is close to the one
if (minDistance <= minionCard.cardRange)
{
float xRange = UnityEngine.Random.Range(-tolerance, tolerance);
float yRange = UnityEngine.Random.Range(-tolerance, tolerance);
closestMinionPosition = enemyMinion.transform.position + new Vector3(xRange, 0, yRange);
minionDesiredLocations[currentMinionIndex] = closestMinionPosition;
minionAgent.SetDestination(closestMinionPosition);
NavMeshHit hit;
if (NavMesh.SamplePosition(closestMinionPosition, out hit, 1.0f, NavMesh.AllAreas))
{
minionDesiredLocations[currentMinionIndex] = hit.position;
minionAgent.SetDestination(hit.position);
return true;
}
}
else
{
//Calculating angle beetween the minion and the target
float angle = GetAngle(minion.transform.position, enemyMinion.transform.position);
float randomDistance = UnityEngine.Random.Range((float)minionCard.cardRange / 2, (float)minionCard.cardRange * 2);
randomDistance = 1.0f;
float x = minion.transform.position.x + (float)Math.Cos(angle) * randomDistance;
float z = minion.transform.position.z + (float)Math.Sin(angle) * randomDistance;
closestMinionPosition = new Vector3(x, 0, z);
NavMeshHit hit;
if (NavMesh.SamplePosition(closestMinionPosition, out hit, 3.0f, NavMesh.AllAreas))
{
minionDesiredLocations[currentMinionIndex] = hit.position;
minionAgent.SetDestination(hit.position);
return true;
}
}
}
}
return false;
}
public bool PerformTurn(GameController gameController)
{
switch (state)
{
case State.Draw:
currentMinionIndex = 0;
gameController.drawCard(1);
state = State.Place;
break;
case State.Place:
//Getting the hand
List<GameObject> hand = gameController.GetHand(1);
//Generate a random integer to see what card to play
int randomIndex = (int)UnityEngine.Random.Range(0, hand.Count - 1);
gameController.PlaceMinion(randomIndex);
state = State.GetBoard;
break;
case State.GetBoard:
board = gameController.GetBoard(1);
minionDesiredLocations = GenerateActualLocations(board);
currentMinionIndex = 0;
state = State.Move;
break;
case State.Move:
//If we have moved all minions
if (currentMinionIndex >= board.Count)
{
Debug.Log("[IA] Passing turn");
state = State.Draw;
gameController.NextPlayer();
return true;
}
else if(MoveMinion(board[currentMinionIndex], gameController.GetBoard(0)))
{
gameController.SetCameraTo(board[currentMinionIndex].transform.position);
MoveMinion(board[currentMinionIndex], gameController.GetBoard(0));
state = State.MinionMoving;
}
break;
case State.MinionMoving:
Vector3 actualMinionPosition = board[currentMinionIndex].transform.position;
Vector3 desiredMinionLocation = minionDesiredLocations[currentMinionIndex];
actualMinionPosition = new Vector3(actualMinionPosition.x, 0, actualMinionPosition.z);
desiredMinionLocation = new Vector3(desiredMinionLocation.x, 0, desiredMinionLocation.z);
if (actualMinionPosition == desiredMinionLocation)
{
Debug.Log("Next Minion");
currentMinionIndex++;
state = State.Move;
}
//Debug lines
if (Input.GetKey(KeyCode.P))
{
Debug.Log("Next Minion");
currentMinionIndex++;
state = State.Move;
}
break;
}
//Continue turn proccessing
return false;
}
private List<Vector3> GenerateActualLocations(List<GameObject> board)
{
List<Vector3> l = new List<Vector3>();
foreach (GameObject minion in board)
{
l.Add(minion.transform.position);
}
return l;
}
private float GetAngle(Vector3 minion, Vector3 target)
{
return Vector3.Angle(minion, target);
}
}
答案 0 :(得分:0)
感谢您的帮助,我终于找到了解决方案。 我所做的就是打电话给
agent.SetDestination(enemyMinion.transform.position)
此后,我存储了代理的起始位置,并在逻辑循环内部,请检查起始位置与实际位置之间的距离,只要该距离大于小仆可以行走的距离,我只需停止NavMeshAgent
这是更新的代码,以防万一有人需要
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class EnemyAI : MonoBehaviour {
private float tolerance = 1.2f;
public NavMeshSurface navMesh;
private List<GameObject> board;
private List<Vector3> minionDesiredLocations;
private Vector3 startMinionLocation;
private int currentMinionIndex = 0;
private enum State {
Draw,
Place,
GetBoard,
Move,
MinionMoving
}
private State state = State.Draw;
public GameObject PlaceCard(List<GameObject> hand)
{
//Generate a random integer to see what card to play
int randomIndex = (int) UnityEngine.Random.Range(0, hand.Count - 1);
Debug.Log("AI Generated Index: " + randomIndex);
return hand[randomIndex];
}
private bool MoveMinion(GameObject minion, List<GameObject> enemyMinions)
{
NavMeshAgent minionAgent = minion.GetComponent<NavMeshAgent>();
Card minionCard = minion.transform.Find("Card").GetComponent<Card>();
Vector3 maPosition = minion.transform.position;
//Finding the closest position of the enemy minion
float minDistance = 100.0f;
Vector3 closestMinionPosition = Vector3.negativeInfinity;
foreach (GameObject enemyMinion in enemyMinions)
{
//Calculating distance beetween the enemy AI minion and the enemy
float distance = Vector3.Distance(minion.transform.position, enemyMinion.transform.position);
if (distance <= minDistance)
{
minDistance = distance;
//Attacking the minion is close to the one
float xRange = UnityEngine.Random.Range(-tolerance, tolerance);
float yRange = UnityEngine.Random.Range(-tolerance, tolerance);
closestMinionPosition = enemyMinion.transform.position + new Vector3(xRange, 0, yRange);
minionDesiredLocations[currentMinionIndex] = closestMinionPosition;
minionAgent.SetDestination(closestMinionPosition);
NavMeshHit hit;
if (NavMesh.SamplePosition(closestMinionPosition, out hit, 1.0f, NavMesh.AllAreas))
{
minionDesiredLocations[currentMinionIndex] = hit.position;
minionAgent.isStopped = false;
minionAgent.SetDestination(hit.position);
startMinionLocation = minion.transform.position;
return true;
}
}
}
return false;
}
public bool PerformTurn(GameController gameController)
{
switch (state)
{
case State.Draw:
currentMinionIndex = 0;
gameController.drawCard(1);
state = State.Place;
break;
case State.Place:
//Getting the hand
List<GameObject> hand = gameController.GetHand(1);
//Generate a random integer to see what card to play
int randomIndex = (int)UnityEngine.Random.Range(0, hand.Count - 1);
gameController.PlaceMinion(randomIndex);
state = State.GetBoard;
break;
case State.GetBoard:
board = gameController.GetBoard(1);
minionDesiredLocations = GenerateActualLocations(board);
currentMinionIndex = 0;
state = State.Move;
break;
case State.Move:
//If we have moved all minions
if (currentMinionIndex >= board.Count)
{
Debug.Log("[IA] Passing turn");
state = State.Draw;
gameController.NextPlayer();
return true;
}
else if(MoveMinion(board[currentMinionIndex], gameController.GetBoard(0)))
{
gameController.SetCameraTo(board[currentMinionIndex].transform.position);
MoveMinion(board[currentMinionIndex], gameController.GetBoard(0));
state = State.MinionMoving;
}
break;
case State.MinionMoving:
Vector3 actualMinionPosition = board[currentMinionIndex].transform.position;
float distance = Vector3.Distance(startMinionLocation, actualMinionPosition);
Card card = board[currentMinionIndex].transform.Find("Card").GetComponent<Card>();
NavMeshAgent agent = board[currentMinionIndex].GetComponent<NavMeshAgent>();
if (distance >= card.cardRange)
{
agent.isStopped = true;
currentMinionIndex++;
state = State.Move;
}
//Debug lines
if (Input.GetKey(KeyCode.P))
{
Debug.Log("Next Minion");
currentMinionIndex++;
state = State.Move;
}
break;
}
//Continue turn proccessing
return false;
}
private List<Vector3> GenerateActualLocations(List<GameObject> board)
{
List<Vector3> l = new List<Vector3>();
foreach (GameObject minion in board)
{
l.Add(minion.transform.position);
}
return l;
}
private float GetAngle(Vector3 minion, Vector3 target)
{
return Vector3.Angle(minion, target);
}
}