173 lines
4.8 KiB
C#
173 lines
4.8 KiB
C#
using DG.Tweening;
|
||
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using TMPro;
|
||
using Unity.VisualScripting;
|
||
using UnityEngine;
|
||
using UnityEngine.AI;
|
||
using Random = UnityEngine.Random;
|
||
|
||
public class Enemy : MonoBehaviour
|
||
{
|
||
[Tooltip("最小生命值百分比")]
|
||
[Range(0, 100)]
|
||
public int minHealthPercent = 30;
|
||
[Tooltip("最大生命值百分比")]
|
||
[Range(0, 100)]
|
||
public int maxHealthPercent = 100;
|
||
[Tooltip("初始化生命值")]
|
||
public int health = 100;
|
||
[Tooltip("爆炸音效")]
|
||
public AudioClip boomClip;
|
||
[Tooltip("爆炸音效的音量")]
|
||
public float boomVolumeScale = 1f;
|
||
[Tooltip("X角度偏移")]
|
||
public float addEulerX = 0f;
|
||
[Tooltip("是否开始的时候修改主材质颜色")]
|
||
public bool isChangeInitColor = false;
|
||
|
||
public List<Color> randomColors = new List<Color>()
|
||
{
|
||
new Color(33f / 255f, 144f /255f, 223f / 255f),
|
||
new Color(13f / 255f, 174f /255f, 58f / 255f),
|
||
new Color(212f / 255f, 128f /255f, 24f / 255f),
|
||
new Color(198f / 255f, 11f /255f, 12f / 255f),
|
||
new Color(187f / 255f, 12f /255f, 164f / 255f),
|
||
new Color(255f / 255f, 51f /255f, 255f / 255f),
|
||
new Color(102f / 255f, 178f /255f, 255f / 255f),
|
||
};
|
||
|
||
public int ToPosIndex { get; set; } = 0;
|
||
|
||
public Action<int> OnReachDestination = null;
|
||
|
||
private NavMeshAgent _agent;
|
||
// 到达目标的距离阈值(根据场景物体大小调整,比如角色半径0.5则设为0.6)
|
||
public float arrivalThreshold = 0.5f;
|
||
|
||
// 是否已到达目标的标记
|
||
private bool _hasReachedDestination = false;
|
||
|
||
private TextMeshPro _textMeshPro;
|
||
private Renderer _renderer;
|
||
private void Awake()
|
||
{
|
||
_renderer = GetComponentInChildren<Renderer>();
|
||
if (isChangeInitColor)
|
||
{
|
||
var color = randomColors[Random.Range(0, randomColors.Count)];
|
||
_renderer.material.color = color;
|
||
}
|
||
_agent = GetComponent<NavMeshAgent>();
|
||
health = Mathf.RoundToInt(health * Random.Range(minHealthPercent, maxHealthPercent + 1) * 0.01f);
|
||
_textMeshPro = GetComponentInChildren<TextMeshPro>();
|
||
//_textMeshPro.color = new Color(1f - color.r, 1f - color.g, 1f - color.b);
|
||
if (_textMeshPro != null)
|
||
{
|
||
_textMeshPro.text = health.ToString();
|
||
}
|
||
arrivalThreshold = _agent.radius * 1.1f; // 根据Agent半径动态设置阈值
|
||
}
|
||
|
||
// Start is called before the first frame update
|
||
void Start()
|
||
{
|
||
|
||
}
|
||
|
||
public void ResetMaterial()
|
||
{
|
||
var color = _renderer.material.color;
|
||
color.a = 1;
|
||
_renderer.material.color = color;
|
||
}
|
||
|
||
public void SetAlphaMaterial()
|
||
{
|
||
var color = _renderer.material.color;
|
||
color.a = 0;
|
||
_renderer.material.color = color;
|
||
}
|
||
|
||
// Update is called once per frame
|
||
void Update()
|
||
{
|
||
// 实时检查是否到达目标
|
||
CheckIfReachedDestination();
|
||
|
||
// 示例:到达目标后的逻辑
|
||
if (_hasReachedDestination)
|
||
{
|
||
if (OnReachDestination != null)
|
||
{
|
||
ToPosIndex++;
|
||
OnReachDestination(ToPosIndex);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查是否到达目标位置
|
||
/// </summary>
|
||
private void CheckIfReachedDestination()
|
||
{
|
||
//// 1. 无目标或无路径时,直接标记为未到达
|
||
//if (!_agent.hasPath || _agent.pathStatus != NavMeshPathStatus.PathComplete)
|
||
//{
|
||
// _hasReachedDestination = false;
|
||
// return;
|
||
//}
|
||
|
||
// 2. 有路径时,检查剩余距离
|
||
// remainingDistance:Agent当前位置到路径终点的剩余距离
|
||
if (_agent.remainingDistance <= arrivalThreshold)
|
||
{
|
||
// 3. 额外检查是否停止移动(避免因障碍物卡住但剩余距离达标)
|
||
//if (!_agent.hasPath || _agent.velocity.sqrMagnitude < 0.01f)
|
||
//{
|
||
_hasReachedDestination = true;
|
||
//}
|
||
}
|
||
else
|
||
{
|
||
_hasReachedDestination = false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 伤害
|
||
/// </summary>
|
||
/// <param name="damage">伤害值</param>
|
||
/// <returns>返回true,表示被击毁,false表示还未被击毁</returns>
|
||
public bool TakeDamage(int damage)
|
||
{
|
||
if (!this.IsDestroyed())
|
||
{
|
||
health -= damage;
|
||
health = Mathf.Max(health, 0);
|
||
if (_textMeshPro != null)
|
||
{
|
||
_textMeshPro.text = health.ToString();
|
||
}
|
||
if (health == 0)
|
||
{
|
||
Respawn();
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
public void Respawn()
|
||
{
|
||
if (boomClip != null)
|
||
{
|
||
AudioTool.AudioSource.PlayOneShot(boomClip, boomVolumeScale);
|
||
}
|
||
gameObject.transform.DOKill(true);
|
||
Global.LockedEnemies.Remove(GetHashCode());
|
||
Global.DespawnEnemy(this);
|
||
}
|
||
}
|