214 lines
6.8 KiB
C#
214 lines
6.8 KiB
C#
using DG.Tweening;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using UnityEngine;
|
||
using UnityEngine.AI;
|
||
using UnityEngine.InputSystem;
|
||
|
||
public class EnemyManager : MonoBehaviour
|
||
{
|
||
public float attackRadius = 5f;
|
||
public Transform[] startLoc = new Transform[] { };
|
||
public Transform[] pathesLoc = new Transform[] { };
|
||
[Tooltip("每只怪出现的间隔")]
|
||
public float enemyAppearDuration = 0.1f;
|
||
//public Transform endLoc;
|
||
|
||
public Transform[] enemyPrefabList = new Transform[] { };
|
||
|
||
//private List<Transform> _enemies = new List<Transform>();
|
||
// Start is called before the first frame update
|
||
private bool _isAttacking = false;
|
||
|
||
|
||
/// <summary>
|
||
/// 怪物攻击的当前波次
|
||
/// </summary>
|
||
private int _currAttackIndex = 0;
|
||
|
||
///// <summary>
|
||
///// 当前版怪物攻击的总波次
|
||
///// </summary>
|
||
//public int enemyAttackIndex = 20;
|
||
|
||
/// <summary>
|
||
/// 每波怪物的攻击间隔,单位秒
|
||
/// </summary>
|
||
public float attackInterval = 10f;
|
||
|
||
/// <summary>
|
||
/// 怪物移动速度
|
||
/// </summary>
|
||
public float enemyMoveSpeed = 1f;
|
||
|
||
|
||
[Tooltip("每波怪的个数")]
|
||
public float initEachEnemyCount = 50;
|
||
|
||
private Camera _cam;
|
||
|
||
|
||
private void Awake()
|
||
{
|
||
_cam = Camera.main;
|
||
}
|
||
|
||
void Start()
|
||
{
|
||
_isAttacking = true;
|
||
StartCoroutine(EnemyStartAttack());
|
||
}
|
||
|
||
// Update is called once per frame
|
||
//void Update()
|
||
//{
|
||
|
||
//}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
StopAllCoroutines();
|
||
}
|
||
|
||
private IEnumerator EnemyStartAttack()
|
||
{
|
||
yield return new WaitForSeconds(2f); // Adjust the interval as needed
|
||
while (_isAttacking)
|
||
{
|
||
if (_currAttackIndex >= enemyPrefabList.Length)
|
||
{
|
||
_currAttackIndex = 0;
|
||
}
|
||
for (int i = 0; i < initEachEnemyCount; i++)
|
||
{
|
||
//var pos = new Vector3(Random.Range(0f, Screen.width), Random.Range(Screen.height + 125f, Screen.height + 353f), _cam.nearClipPlane - _cam.transform.position.z);
|
||
var enemyComp = SpawnEnemy(Mathf.FloorToInt(Random.value * enemyPrefabList.Length));
|
||
//float duration = Mathf.Max(0.2f, Random.value / _currAttackIndex * 10);
|
||
//if (i % 5 == 0)
|
||
//{
|
||
// yield return new WaitForSeconds(1f); // Adjust the interval as needed
|
||
//}
|
||
//else
|
||
//{
|
||
if (enemyComp != null)
|
||
{
|
||
yield return null; // Adjust the interval as needed
|
||
enemyComp.ResetMaterial();
|
||
}
|
||
yield return new WaitForSeconds(enemyAppearDuration); // Adjust the interval as needed
|
||
//}
|
||
}
|
||
_currAttackIndex++;
|
||
yield return new WaitForSeconds(attackInterval); // Adjust the interval as needed
|
||
}
|
||
}
|
||
|
||
public Enemy SpawnEnemy(int enemyIndex)
|
||
{
|
||
if (enemyIndex < 0 || enemyIndex >= enemyPrefabList.Length)
|
||
{
|
||
Debug.LogError("Invalid enemy index: " + enemyIndex);
|
||
return null;
|
||
}
|
||
//var fromPos = _cam.ScreenToWorldPoint(spawnPosition);
|
||
//spawnPosition.y = 350;//移动到指定位置
|
||
//var toPos = _cam.ScreenToWorldPoint(spawnPosition);
|
||
var pos = Vector3.zero;
|
||
var enemy = Instantiate(enemyPrefabList[enemyIndex], Vector3.zero, Quaternion.identity);
|
||
//if (startLoc.Length == 0 && pathesLoc.Length > 0)
|
||
//{
|
||
var startPos = startLoc.Last().position;
|
||
var bounds = enemy.GetComponentInChildren<Collider>().bounds;
|
||
//float angle = Mathf.PI * 2 * Random.value; // 修正角度计算逻辑
|
||
float x = Random.Range(0, Screen.width);
|
||
float y = Screen.height + 100;
|
||
pos = new Vector3(x, y, _cam.transform.position.z);
|
||
bool isLeft = pos.x < Screen.width * 0.5f;
|
||
pos = _cam.ScreenToWorldPoint(pos);
|
||
pos.y = pathesLoc.Last().position.y;
|
||
pos.z = startPos.z;
|
||
//往中聚拢怪物尺寸的长度
|
||
if (isLeft)
|
||
{
|
||
pos.x += bounds.size.magnitude * 0.5f;
|
||
}
|
||
else
|
||
{
|
||
pos.x -= bounds.size.magnitude * 0.5f;
|
||
}
|
||
|
||
//pathesLoc.Last().position + new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * attackRadius;
|
||
//}
|
||
//else
|
||
//{
|
||
// pos = startLoc[Random.Range(0, startLoc.Length)].position;
|
||
//}
|
||
|
||
enemy.position = pos;
|
||
|
||
|
||
var enemyComp = enemy.GetComponent<Enemy>();
|
||
enemy.eulerAngles = new Vector3(enemy.eulerAngles.x + enemyComp.addEulerX, enemy.eulerAngles.y + 180, enemy.eulerAngles.z);
|
||
//Debug.Log(enemy.eulerAngles);
|
||
Global.Enemies.Add(enemyComp);
|
||
// 初始化时将物体移动到最近的NavMesh点
|
||
NavMeshHit initHit;
|
||
if (NavMesh.SamplePosition(enemy.position, out initHit, 8.0f, NavMesh.AllAreas))
|
||
{
|
||
enemy.position = initHit.position;
|
||
}
|
||
else
|
||
{
|
||
Debug.LogWarning("init failed!");
|
||
}
|
||
|
||
var destPos = pathesLoc[enemyComp.ToPosIndex].position;
|
||
destPos = new Vector3(enemy.position.x, destPos.y, destPos.z);
|
||
|
||
ToDestination(enemyComp, destPos);
|
||
|
||
enemyComp.SetAlphaMaterial();
|
||
return enemyComp;
|
||
//enemy.DOMove(toPos, enemyMoveSpeed)
|
||
// .SetEase(Ease.Linear) // 强制匀速,无加速减速
|
||
// .SetSpeedBased(); // 标记为可回收,完成后回收到池; // 关键:将第二个参数视为“速度”而非“时间”
|
||
}
|
||
|
||
private void ToDestination(Enemy enemy, Vector3 position)
|
||
{
|
||
if (enemy.ToPosIndex >= pathesLoc.Length)
|
||
{
|
||
return;
|
||
}
|
||
var screenPt = _cam.WorldToScreenPoint(position);
|
||
Ray ray = _cam.ScreenPointToRay(screenPt);
|
||
if (Physics.Raycast(ray, out RaycastHit hit, 1000))
|
||
{
|
||
// 2. 确保射线击中的点在NavMesh上(采样最近的有效NavMesh点)
|
||
NavMeshHit navHit;
|
||
if (NavMesh.SamplePosition(hit.point, out navHit, 3.0f, NavMesh.AllAreas))
|
||
{
|
||
var agent = enemy.GetComponent<UnityEngine.AI.NavMeshAgent>();
|
||
agent.speed = enemyMoveSpeed;
|
||
// 3. 设置NavMeshAgent的目标位置
|
||
agent.SetDestination(navHit.position);
|
||
enemy.OnReachDestination = (toPosIndex) =>
|
||
{
|
||
if (toPosIndex >= pathesLoc.Length)
|
||
{
|
||
enemy.OnReachDestination = null;
|
||
Global.DespawnEnemy(enemy);
|
||
return;
|
||
}
|
||
ToDestination(enemy, pathesLoc[toPosIndex].position);
|
||
};
|
||
}
|
||
else
|
||
{
|
||
Debug.LogWarning("射线击中的位置不在NavMesh烘焙区域内!");
|
||
}
|
||
}
|
||
}
|
||
}
|