|
|
using System.Collections;
|
|
|
using System.Collections.Generic;
|
|
|
using UnityEngine;
|
|
|
|
|
|
public class AI : Character
|
|
|
{
|
|
|
public List<Cell> frontier = new List<Cell>();
|
|
|
public List<Cell> explored = new List<Cell>();
|
|
|
public int sensingRange = 6; //感知范围
|
|
|
public int attackRange = 1; //攻击范围
|
|
|
public int attackCost = 4; //攻击消耗
|
|
|
public AISkill skill;
|
|
|
Character goal = null;
|
|
|
Cell cell;
|
|
|
float timer = 0.5f;
|
|
|
public IEnumerator ApplyAI()
|
|
|
{
|
|
|
//Debug.Log("StartAI");
|
|
|
if(FindNearestEnemy() > sensingRange) //观测周围是否有敌人
|
|
|
yield return null;
|
|
|
//Debug.Log("The goal is " + goal.transform.position.x + "," + goal.transform.position.y);
|
|
|
RaycastHit2D hit = Physics2D.Raycast(transform.position,Vector2.up,1.0f,LayerMask.GetMask("Cells"));
|
|
|
cell = hit.collider.GetComponent<Cell>();
|
|
|
cell.parent = null;
|
|
|
cell.gCost = 0;
|
|
|
cell.hCost = 1000;
|
|
|
frontier.Add(cell);
|
|
|
yield return StartCoroutine(SearchEnemy()); //发现敌人并向敌人移动
|
|
|
//TestThePath(path);
|
|
|
}
|
|
|
IEnumerator SearchEnemy()
|
|
|
{
|
|
|
int nearestCell = 1000;
|
|
|
List<Cell> path = new List<Cell>();
|
|
|
Cell endNode = null;
|
|
|
while(frontier.Count != 0)
|
|
|
{
|
|
|
Cell node = LowestCost(); //总是找出fCost最低的节点
|
|
|
//Debug.Log("Node =" + node.transform.position.x + "," + node.transform.position.y);
|
|
|
frontier.Remove(node);
|
|
|
//若找到目标所在Cell,则返回其父结点
|
|
|
if(node.currentCharacter != null && node.currentCharacter.groupNumber != groupNumber)
|
|
|
{
|
|
|
//Debug.Log(node.transform.position.x + "," + node.transform.position.y);
|
|
|
endNode = node.parent;
|
|
|
break;
|
|
|
}
|
|
|
//Debug.Log("node is " + node.transform.position.x + "," +node.transform.position.y + " hCost is " + node.hCost);
|
|
|
//找到离目标预测最近的单元格
|
|
|
if(node.hCost < nearestCell)
|
|
|
{
|
|
|
endNode = node;
|
|
|
nearestCell = node.hCost;
|
|
|
}
|
|
|
explored.Add(node);
|
|
|
List<Cell> neighbors = node.GetNeighbor();
|
|
|
foreach (var neighbor in neighbors)
|
|
|
{
|
|
|
if(!frontier.Contains(neighbor) && !explored.Contains(neighbor))
|
|
|
{
|
|
|
if(neighbor.currentCharacter != null && neighbor.currentCharacter.groupNumber == groupNumber)
|
|
|
continue;
|
|
|
neighbor.parent = node;
|
|
|
neighbor.CalculateCosts(goal.transform.position);
|
|
|
if(neighbor.gCost <= maxMovement)
|
|
|
frontier.Add(neighbor);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
// if(endNode != null)
|
|
|
// Debug.Log("endNode is " + endNode.transform.position.x + "," +endNode.transform.position.y);
|
|
|
int count = 0;
|
|
|
// if(!found)
|
|
|
// endNode = frontier[frontier.Count - 1];
|
|
|
while(endNode != null)
|
|
|
{
|
|
|
path.Add(endNode);
|
|
|
endNode = endNode.parent;
|
|
|
count ++;
|
|
|
if(count > 10) break;
|
|
|
}
|
|
|
frontier.Clear();
|
|
|
explored.Clear();
|
|
|
//if(found == true)
|
|
|
{
|
|
|
for(int i = 0; i < attackRange - 1; i++)
|
|
|
path.RemoveAt(0);
|
|
|
path.Reverse();
|
|
|
if(path.Count > 0)
|
|
|
path.RemoveAt(0);
|
|
|
//Debug.Log("path.Count = " + path.Count);
|
|
|
}
|
|
|
yield return StartCoroutine(ActionAI(path));
|
|
|
}
|
|
|
void TestThePath(List<Cell> path) //测试用函数
|
|
|
{
|
|
|
Debug.Log("The path :");
|
|
|
foreach(var node in path)
|
|
|
{
|
|
|
Debug.Log(node.transform.position.x + "," + node.transform.position.y);
|
|
|
}
|
|
|
}
|
|
|
int FindNearestEnemy() //找到最近距离的敌人
|
|
|
{
|
|
|
int minDistance = 1000;
|
|
|
GameObject[] pieces = GameManager.instance.pieces;
|
|
|
foreach(var piece in pieces)
|
|
|
{
|
|
|
Character character = piece.GetComponent<Character>();
|
|
|
int distance = GameSettlement.Manhattan(transform.position,character.transform.position);
|
|
|
if(character.groupNumber != groupNumber && distance < minDistance)
|
|
|
{
|
|
|
minDistance = distance;
|
|
|
goal = character;
|
|
|
}
|
|
|
}
|
|
|
//Debug.Log("minDistance = " + minDistance);
|
|
|
return minDistance;
|
|
|
}
|
|
|
Cell LowestCost() //找出frontier里fCost最低的节点
|
|
|
{
|
|
|
Cell lowestCost = frontier[0];
|
|
|
foreach(var node in frontier)
|
|
|
{
|
|
|
if(node.fCost < lowestCost.fCost)
|
|
|
lowestCost = node;
|
|
|
}
|
|
|
return lowestCost;
|
|
|
}
|
|
|
IEnumerator ActionAI(List<Cell> path)
|
|
|
{
|
|
|
Selected();
|
|
|
//移动阶段
|
|
|
foreach(var node in path)
|
|
|
{
|
|
|
Vector2 position1 = cell.transform.position;
|
|
|
Vector2 position2 = node.transform.position;
|
|
|
float deltaX = position2.x - position1.x;
|
|
|
float deltaY = position2.y - position1.y;
|
|
|
Vector2 deviation = new Vector2(deltaX,deltaY);
|
|
|
yield return StartCoroutine(Move(deviation, 0.1f));
|
|
|
cell = node;
|
|
|
}
|
|
|
//攻击阶段
|
|
|
if(GameSettlement.Manhattan(goal.transform.position,transform.position) <= attackRange)
|
|
|
while(currentMovement >= attackCost)
|
|
|
{
|
|
|
yield return new WaitForSeconds(0.2f);
|
|
|
AIAttack();
|
|
|
}
|
|
|
yield return new WaitForSeconds(2 * timer);
|
|
|
Cancel();
|
|
|
}
|
|
|
void AIAttack()
|
|
|
{
|
|
|
if(skill.CheckRequest(currentMana, currentMovement, goal))
|
|
|
{
|
|
|
Debug.Log("AISkill released");
|
|
|
skill.ApplySkill(this, goal);
|
|
|
return;
|
|
|
}
|
|
|
int damage = GameSettlement.AIAttackSettlement(this, goal);
|
|
|
goal.ChangeHealth(damage);
|
|
|
goal.ChangePoise(-str);
|
|
|
ChangeMovement(-attackCost);
|
|
|
ChangeMana(inte/3 + san/5);
|
|
|
//buffManager.ApplyActiveSpecial(goal);
|
|
|
goal.buffManager.ApplyPassiveSpecial(this);
|
|
|
}
|
|
|
public override void Selected() //AI不需要武器
|
|
|
{
|
|
|
if(GameManager.instance.selected != null) return;
|
|
|
if(GameManager.instance.currentGroup != groupNumber)
|
|
|
return;
|
|
|
animator.SetFloat("selected", 1);
|
|
|
GameManager.instance.SetSelected(gameObject.GetComponent<Character>());
|
|
|
movementBar.SetMovementActive(true);
|
|
|
}
|
|
|
public override void Cancel() //AI不需要武器
|
|
|
{
|
|
|
animator.SetFloat("selected", 0);
|
|
|
GameManager.instance.SetSelected(null);
|
|
|
movementBar.SetMovementActive(false);
|
|
|
}
|
|
|
protected override void OnMouseOver()
|
|
|
{
|
|
|
//鼠标右键点击查看角色信息
|
|
|
if(Input.GetMouseButton(1) && GameManager.instance.GetSelected() == null)
|
|
|
{
|
|
|
GameManager.instance.CheckDetailInformation(str,inte,dex,san,vig,def,
|
|
|
currentHealth,maxHealth,currentPoise,maxPoise,currentMana,maxMana);
|
|
|
}
|
|
|
}
|
|
|
}
|