fix:每个boss调整

This commit is contained in:
bzx
2026-01-29 17:34:43 +08:00
parent 2545986005
commit 5ec04dade1
90 changed files with 158090 additions and 155925 deletions

View File

@@ -30,6 +30,11 @@ public class DeathKnightChargeAtk : Action
StartCoroutine(SkillFlow());
}
public override TaskStatus OnUpdate()
{
return isFinished ? TaskStatus.Success : TaskStatus.Running;
}
IEnumerator SkillFlow()
{
// ===== Phase 1冲刺 =====

View File

@@ -278,8 +278,8 @@ public class FrogEggAttack : Action
public class FrogIdleMove : Action
{
[Header("Move Area (Fan Shape)")]
public float moveRadius = 10f; // 可移动半径
public float moveAngle = 90f; // 扇形角度(玩家正前方)
private float moveRadius = 40f; // 可移动半径
private float moveAngle = 90f; // 扇形角度(玩家正前方)
[Header("Stay")]
public float stayTime = 1.5f; // 到点后停留时间
@@ -290,6 +290,10 @@ public class FrogIdleMove : Action
[Header("Distance To Player")]
public float minPlayerDistance = 6f; // 离玩家最近距离
public float maxPlayerDistance = 15f; // 离玩家最远距离
[Header("Patrol")]
public float minMoveStep = 5f; // 每次移动的最小距离(关键)
private FrogBoss boss;
private Transform player;
@@ -380,24 +384,23 @@ public class FrogIdleMove : Action
isStaying = false;
Vector3 bossPos = transform.position;
Vector3 toPlayer = player.position - bossPos;
toPlayer.y = 0;
Vector3 playerPos = player.position;
Vector3 forward = toPlayer.normalized;
const int MAX_TRY = 20;
const int MAX_TRY = 15;
for (int i = 0; i < MAX_TRY; i++)
{
// 🎯 玩家前方扇形
float angle = Random.Range(-moveAngle * 0.5f, moveAngle * 0.5f);
Vector3 dir = Quaternion.Euler(0, angle, 0) * forward;
// 🎯 玩家为中心选点(而不是 boss
float angle = Random.Range(0f, 360f);
float dist = Random.Range(moveRadius * 0.4f, moveRadius);
Vector3 candidate = bossPos + dir * dist;
float radius = Random.Range(minPlayerDistance, maxPlayerDistance);
// 👉 与玩家距离限制
float playerDist = Vector3.Distance(candidate, player.position);
if (playerDist < minPlayerDistance || playerDist > maxPlayerDistance)
Vector3 offset = Quaternion.Euler(0, angle, 0) * Vector3.forward * radius;
Vector3 candidate = playerPos + offset;
candidate.y = bossPos.y;
// 👉 保证和当前点“足够远”
if (Vector3.Distance(candidate, bossPos) < minMoveStep)
continue;
// 👉 A* 校正
@@ -410,12 +413,13 @@ public class FrogIdleMove : Action
}
}
// 🛑 兜底:原地小偏移,避免卡死
curTarget = bossPos + Random.insideUnitSphere * 0.5f;
curTarget.y = bossPos.y;
// 🛑 兜底:往侧前方大步走
Vector3 fallbackDir = Vector3.Cross(Vector3.up, (playerPos - bossPos)).normalized;
curTarget = bossPos + fallbackDir * minMoveStep;
boss.aiPath.isStopped = false;
}
#endregion
}

View File

@@ -15,7 +15,6 @@ public class OctopusTentacleAtk : Action
{
boss = GetComponent<OctopusBoss>();
isFinished = false;
boss.ResetSkill1();
StartCoroutine(Attack());
}

View File

@@ -236,23 +236,31 @@ public class TortoiseFireballAttack : Action
public class TortoiseDrillingAttack : Action
{
private TortoiseBoss boss;
private Transform player;
private bool isFinished;
public float moveDuration = 20f;
public float maxChaseDistance = 12f; // 超过这个距离才开始校正
public float chaseStrength = 0.5f; // 校正强度(越小越自然)
public override void OnStart()
{
boss = GetComponent<TortoiseBoss>();
player = GameManager.Ins.player.transform;
isFinished = false;
boss.ResetSkill2();
boss.ResetSkill1();
StartCoroutine(Drilling());
}
public override TaskStatus OnUpdate()
{
return isFinished ? TaskStatus.Success : TaskStatus.Running;
}
IEnumerator Drilling()
{
// 1⃣ 钻地
@@ -267,19 +275,23 @@ public class TortoiseDrillingAttack : Action
isFinished = true;
}
public IEnumerator DrillBounceMove(float duration)
{
float timer = 0f;
Vector3 moveDir = Random.insideUnitSphere;
// ⭐ 第一次方向:直奔玩家
Vector3 moveDir = player.position - transform.position;
moveDir.y = 0;
if (moveDir.sqrMagnitude < 0.01f)
moveDir = transform.forward;
moveDir.Normalize();
// ⚠️ 只开一次
boss.skill3Effect.SetActive(true);
boss.skill3Collider.enabled = true;
GameManager.Ins.PlaySound3D("1.25",transform,true);
GameManager.Ins.PlaySound3D("1.25", transform, true);
while (timer < duration)
{
timer += Time.deltaTime;
@@ -287,9 +299,30 @@ public class TortoiseDrillingAttack : Action
if (boss.isDead)
yield break;
// 🧲 距离玩家过远时 → 轻微方向校正
Vector3 toPlayer = player.position - transform.position;
toPlayer.y = 0;
float distToPlayer = toPlayer.magnitude;
if (distToPlayer > maxChaseDistance)
{
Vector3 desiredDir = toPlayer.normalized;
// 轻微修正,不是强追踪
moveDir = Vector3.Lerp(
moveDir,
desiredDir,
chaseStrength * Time.deltaTime
);
moveDir.y = 0;
moveDir.Normalize();
}
Vector3 nextPos =
transform.position + moveDir * boss.drillMoveSpeed * Time.deltaTime;
// 🔥 撞墙反弹
if (Physics.Raycast(
transform.position,
moveDir,
@@ -310,5 +343,4 @@ public class TortoiseDrillingAttack : Action
}
}
}

View File

@@ -51,6 +51,7 @@ public class DeathKnightBoss : Enemy
{
item.SetActive(false);
}
transform.LookAt(GameManager.Ins.player.transform.position.ReflectVectorXOZ());
}
public override void Update()
@@ -153,6 +154,16 @@ public class DeathKnightBoss : Enemy
GameManager.Ins.PlaySound3D("1.59",transform,true);
}
public override void Hit()
{
if(enemyState!= EnemyState.Idle)
return;
base.Hit();
int hitIndex = Random.Range(0, 100);
string hitStr=hitIndex>=50 ?"isHit1":"isHit2";
bossManAnim.SetTrigger(hitStr);
}
public float rotateSpeed = 90f;
public IEnumerator RotateToPlayer()
{
@@ -247,6 +258,8 @@ public class DeathKnightBoss : Enemy
// ===== 4⃣ 加入本体(永远存在)=====
allChargers.Add(gameObject);
GameManager.Ins.PlaySound3D("1.54",transform,true);
yield return new WaitForSeconds(3f);
Slash();
houseAnim.SetInteger("state", 2);

View File

@@ -100,6 +100,11 @@ public class Enemy : MonoBehaviour
currentAttack = null;
}
public virtual void Hit()
{
GameManager.Ins.PlaySound3D("1.17",transform);
}
public virtual void Init()
{
behaviourTree=GetComponent<BehaviorTree>();
@@ -115,27 +120,27 @@ public class Enemy : MonoBehaviour
{
Data = data;
}
public void ApplyDamage(float value, object info, Transform _sender)
{
ChangeHp(value, info,_sender);
}
public virtual void ChangeHp(float value, object info, Transform _sender)
{
health -= value;
if(_sender.GetComponent<EnemyBullet>()!=null)
return;
Damage(value,(bool)info);
Damage(value,(bool)info,_sender);
if (health <= 0&& !isDead)
{
Dead();
}
else if (enemyState== EnemyState.Idle)
{
Hit();
}
}
public void Damage(float value, bool info)
public void Damage(float value, bool info,Transform pos)
{
if(isDead)
return;
bloodSlider.CreateDamagePre(value, info);
bloodSlider.CreateDamagePre(value, info,pos);
bloodSlider.SetValue2(health,maxHealth);
}
@@ -173,9 +178,9 @@ public class Enemy : MonoBehaviour
}, dieTime);
}
public void ChangeState(int newState)
public void ChangeState(EnemyState newState)
{
enemyState = (EnemyState)newState;
enemyState = newState;
}
public float Health { get; set; }

View File

@@ -144,19 +144,19 @@ public class EnemyComponent : MonoBehaviour, IDamagable
/// </summary>
public void TakeDamage(float damage, bool isBao, Transform target)
{
// 自身血量减少
hp -= damage;
// 通知父体每次受击减少血量
if (parentEnemy != null && !isQteComponent)
parentEnemy.ChangeHp(damage, isBao, target);
// 血量不足时,触发死亡
if (hp <= 0f)
{
hp = 0f;
Die();
}
// // 自身血量减少
// hp -= damage;
//
// // 通知父体每次受击减少血量
// if (parentEnemy != null && !isQteComponent)
// parentEnemy.ChangeHp(damage, isBao, target);
//
// // 血量不足时,触发死亡
// if (hp <= 0f)
// {
// hp = 0f;
// Die();
// }
}
/// <summary>

View File

@@ -4,6 +4,7 @@ using System.Collections.Generic;
using DG.Tweening;
using DragonLi.Core;
using UnityEngine;
using Random = UnityEngine.Random;
public class FrogBoss : Enemy
{
@@ -25,6 +26,8 @@ public class FrogBoss : Enemy
public GameObject[] bossCrystals;
private float rotateSpeed = 180f; // 越大转得越快(插值系数)
public List<FrogBugEnemy> GetAliveTentacles()
{
@@ -43,6 +46,7 @@ public class FrogBoss : Enemy
{
item.SetActive(false);
}
transform.LookAt(GameManager.Ins.player.transform.position.ReflectVectorXOZ());
}
public override void Update()
@@ -52,6 +56,23 @@ public class FrogBoss : Enemy
{
skill1Timer += Time.deltaTime;
skill2Timer += Time.deltaTime;
Transform player = GameManager.Ins.player.transform;
if (!player) return;
Vector3 dir = player.position - transform.position;
dir.y = 0;
if (dir.sqrMagnitude < 0.0001f)
return;
Quaternion targetRot = Quaternion.LookRotation(dir);
transform.transform.rotation = Quaternion.RotateTowards(
transform.transform.rotation,
targetRot,
rotateSpeed * Time.deltaTime
);
}
}
@@ -128,6 +149,16 @@ public class FrogBoss : Enemy
GameManager.Ins.PlaySound3D("1.20", transform, true);
}
public override void Hit()
{
if(enemyState!= EnemyState.Idle)
return;
base.Hit();
int hitIndex = Random.Range(0, 100);
string hitStr=hitIndex>=50 ?"isHit1":"isHit2";
bossAnim.SetTrigger(hitStr);
}
public void TongueAttack()
{
bossAnim.SetInteger("State", 3);

View File

@@ -132,13 +132,8 @@ public class FrogBugEnemy : Enemy
model.SetActive(true);
yield return new WaitForSeconds(2);
egg.SetActive(false);
enemyState = EnemyState.NormalAttack;
}
void HandleMoveAndAttack()
{
float dist = Vector3.Distance(transform.position, player.position);

View File

@@ -13,11 +13,16 @@ public class OctopusBoss : Enemy
public Transform sprayRoot; // 喷射旋转节点(嘴巴)
public GameObject sprayEx; // 喷射特效(带 Trigger
public Transform hand;
public Animator handAnimator;
public float sprayDuration = 5f;
public float sprayAngle = 40f;
public GameObject clipQuadObj;
public GameObject[] bossCrystals;
private float rotateSpeed = 180f; // 越大转得越快(插值系数)
private void Start()
{
foreach (var item in tentacles)
@@ -27,6 +32,7 @@ public class OctopusBoss : Enemy
sprayEx.SetActive(false);
teleportPoints = GameInit.Ins.allBossPos;
bloodSlider.gameObject.SetActive(false);
transform.LookAt(GameManager.Ins.player.transform.position.ReflectVectorXOZ());
foreach (var item in bossCrystals)
{
item.SetActive(false);
@@ -41,6 +47,23 @@ public class OctopusBoss : Enemy
skill1Timer += Time.deltaTime;
skill2Timer += Time.deltaTime;
teleportTimer += Time.deltaTime;
Transform player = GameManager.Ins.player.transform;
if (!player) return;
Vector3 dir = player.position - hand.position;
dir.y = 0;
if (dir.sqrMagnitude < 0.0001f)
return;
Quaternion targetRot = Quaternion.LookRotation(dir);
hand.transform.rotation = Quaternion.RotateTowards(
hand.transform.rotation,
targetRot,
rotateSpeed * Time.deltaTime
);
}
}
@@ -61,7 +84,7 @@ public class OctopusBoss : Enemy
{
base.Show();
GameManager.Ins.CreateEnemySkillTip(transform.position.ReflectVectorXOZ(),3.5f);
transform.position = new Vector3(0, -8, 0);
transform.position = new Vector3(transform.position.x, -8, transform.position.z);
transform.DOMoveY(0, 4f).OnComplete(() =>
{
isShowEnd = true;
@@ -83,6 +106,13 @@ public class OctopusBoss : Enemy
bloodSlider.gameObject.SetActive(true);
}
public override void Hit()
{
if(enemyState!= EnemyState.Idle)
return;
base.Hit();
handAnimator.SetTrigger("hit");
}
public override void ChangeHp(float value, object info, Transform _sender)
{

View File

@@ -13,13 +13,7 @@ public class Tentacle : Enemy
public GameObject model;
public GameObject atkEx;
public AnimationClip idleAnim;
public AnimationClip atkAnim;
public AnimationClip spikeAnim;
public AnimationClip dieAnim;
public AnimationClip hitAnim;
public Animation anim;
public Animator animator;
public EnemyBoneHit[] skill1BoneHits;
public EnemyBoneHit[] skill1ExBoneHits;
@@ -28,8 +22,7 @@ public class Tentacle : Enemy
private Vector3 _startPos;
private bool isAttacking;
private Quaternion _originRot;
private float rotateSpeed = 360f; // 每秒旋转角度
private float rotateSpeed = 180f; // 每秒旋转角度
private void Start()
{
_startPos = transform.position;
@@ -46,6 +39,7 @@ public class Tentacle : Enemy
{
item.gameObject.SetActive(false);
}
bloodSlider.gameObject.SetActive(false);
skill1ExBoneHits[0].transform.localScale=new Vector3(skill1ExBoneHits[0].transform.localScale.x, 10, skill1ExBoneHits[0].transform.localScale.z);
skill1ExBoneHits[0].transform.localPosition=new Vector3(skill1ExBoneHits[0].transform.localPosition.x,0, 10);
}
@@ -61,19 +55,18 @@ public class Tentacle : Enemy
isShowEnd = false;
}
public void EndShow()
public override void EndShow()
{
enemyState = EnemyState.Idle;
bloodSlider.gameObject.SetActive(true);
}
void PlayIdle()
{
if(isDead)
return;
anim.clip = idleAnim;
anim.wrapMode = WrapMode.Loop;
anim.Play();
animator.SetInteger("state",0);
enemyState = EnemyState.Idle;
GameManager.Ins.PlaySound3D("1.18",transform);
}
@@ -93,26 +86,19 @@ public class Tentacle : Enemy
yield return new WaitForSeconds(0.8f);
// 2⃣ 播放攻击动画
anim.clip = atkAnim;
anim.wrapMode = WrapMode.Once;
anim.Play();
animator.SetInteger("state",1);
BeginAttack();
// 3⃣ 等到第 45 帧
float hitTime = 45f / atkAnim.frameRate;
yield return new WaitForSeconds(hitTime);
enemyState = EnemyState.NormalAttack;
yield return new WaitForSeconds(1.72f);
GameManager.Ins.PlaySound3D("1.9",transform,true);
// 4⃣ 攻击判定 / 特效
DoAttackHit(isFurious);
// 5⃣ 等动画播完
float remainTime = atkAnim.length - hitTime;
if (remainTime > 0)
yield return new WaitForSeconds(remainTime);
yield return new WaitForSeconds(3.2f);
// ⭐ 攻击结束后转回
yield return RotateBack();
//yield return RotateBack();
// 6⃣ 切回 Idle
PlayIdle();
@@ -121,6 +107,33 @@ public class Tentacle : Enemy
isAttacking = false;
}
int GetCurrentFrame(int layer = 0)
{
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(layer);
AnimatorClipInfo[] clipInfos = animator.GetCurrentAnimatorClipInfo(layer);
if (clipInfos.Length == 0)
return 0;
AnimationClip clip = clipInfos[0].clip;
float normalizedTime = stateInfo.normalizedTime % 1f; // 防止循环动画溢出
float currentTime = normalizedTime * clip.length;
int currentFrame = Mathf.FloorToInt(currentTime * clip.frameRate);
return currentFrame;
}
float GetCurrentClipLength(int layer = 0)
{
AnimatorClipInfo[] clipInfos = animator.GetCurrentAnimatorClipInfo(layer);
if (clipInfos.Length == 0)
return 0f;
return clipInfos[0].clip.length;
}
IEnumerator RotateToPlayer()
{
Transform player = GameManager.Ins.player.transform;
@@ -174,6 +187,7 @@ public class Tentacle : Enemy
{
// 开启攻击特效
atkEx.SetActive(true);
enemyState = EnemyState.SpikeAttack;
foreach (var item in skill1BoneHits)
{
item.gameObject.SetActive(true);
@@ -204,13 +218,18 @@ public class Tentacle : Enemy
});
}
public override void Hit()
{
if(enemyState!= EnemyState.Idle)
return;
animator.SetTrigger("hit");
}
public void Spike(Vector3 pos)
{
model.SetActive(true);
model.transform.position = new Vector3(pos.x, downIndex, pos.z);
anim.clip = spikeAnim;
anim.wrapMode = WrapMode.Once;
anim.Play();
animator.SetInteger("state",2);
BeginAttack();
foreach (var item in skill2BoneHits)
{
@@ -252,9 +271,6 @@ public class Tentacle : Enemy
if(enemyState== EnemyState.Show)
return;
base.ChangeHp(value, info, _sender);
// anim.clip = hitAnim;
// anim.wrapMode = WrapMode.Once;
// anim.Play();
if(isDead)
return;
GameManager.Ins.PlaySound3D("1.10",transform);
@@ -264,12 +280,31 @@ public class Tentacle : Enemy
{
base.Dead();
health = 0;
anim.clip = dieAnim;
anim.wrapMode = WrapMode.Once;
anim.Play();
animator.SetBool("isDie",true);
GameManager.Ins.PlaySound3D("1.11",transform,true);
transform.parent = null;
StopAllCoroutines();
}
public override void Update()
{
base.Update();
Transform player = GameManager.Ins.player.transform;
if (!player) return;
Vector3 dir = player.position - transform.position;
dir.y = 0;
if (dir.sqrMagnitude < 0.0001f)
return;
Quaternion targetRot = Quaternion.LookRotation(dir);
transform.rotation = Quaternion.RotateTowards(
transform.rotation,
targetRot,
rotateSpeed * Time.deltaTime
);
}
}

View File

@@ -5,6 +5,7 @@ using DarkTonic.MasterAudio;
using DG.Tweening;
using DragonLi.Core;
using UnityEngine;
using Random = UnityEngine.Random;
public class TortoiseBoss : Enemy
{
@@ -42,6 +43,7 @@ public class TortoiseBoss : Enemy
skill3Effect.SetActive(false);
skill3Collider.GetComponent<Collider>().enabled = false;
skill3Collider.SetDamage(Data.Atk_3);
transform.LookAt(GameManager.Ins.player.transform.position.ReflectVectorXOZ());
foreach (var item in bossCrystals)
{
item.SetActive(false);
@@ -109,6 +111,16 @@ public class TortoiseBoss : Enemy
GameManager.Ins.PlaySound3D("1.29",transform,true);
}
public override void Hit()
{
if(enemyState!= EnemyState.Idle)
return;
base.Hit();
int hitIndex = Random.Range(0, 100);
string hitStr=hitIndex>=50 ?"isHit1":"isHit2";
bossAnim.SetTrigger(hitStr);
}
public IEnumerator Drilling()
{
// 关闭导航 & 主碰撞

View File

@@ -32,6 +32,8 @@ public class GameInit : MonoBehaviour
/// </summary>
public GamePlace gamePlace;
public GameKey gameId;
[NonSerialized]
public Player self;
@@ -52,6 +54,7 @@ public class GameInit : MonoBehaviour
private void Start()
{
gameId = GameKey.XMen2;
CloseLine();
}

View File

@@ -88,6 +88,7 @@ public enum GameKey
Loong=9, //巨龙猎人
MRCS=10,//火力对决
SXDMystery=11,//三星堆之谜
XMen2=12,//银河守护者2异形
}
public class GameManager : MonoBehaviour
@@ -198,7 +199,7 @@ public class GameManager : MonoBehaviour
if(GameInit.Ins.gamePlace== GamePlace.Jiangsu_Xvzhou_Suning_Guangchang_1)
loginInfo.shop = 37;
#endif
loginInfo.gameId = 12;
loginInfo.gameId = (int)GameInit.Ins.gameId;
string authJson = JsonUtility.ToJson(loginInfo);
Debug.Log("发送数据 -> " + authJson);
request.RawData = System.Text.Encoding.UTF8.GetBytes(authJson);

View File

@@ -59,7 +59,7 @@ public class PlayerBullet : MonoBehaviour
{
if(GameManager.Ins.PlayerBulletDataDic.Count>0)
_damages = GameManager.Ins.PlayerBulletDataDic[(int)bulletType].Damage;
int randomDamage = Random.Range(_damages[0]*2, _damages[1]*2);
int randomDamage = Random.Range(_damages[0], _damages[1]);
randomDamage += (Mathf.FloorToInt(GameManager.Ins.buffAtk * randomDamage));
isCriticalHit=randomDamage > (_damages[1] - (_damages[1] - _damages[0]) * 0.35f);
return randomDamage;

View File

@@ -26,12 +26,11 @@ public class BloodSlider : MonoBehaviour
blood1.fillAmount = 1;
blood2.fillAmount = 1;
}
public void CreateDamagePre(float damage, bool criticalHit)
public void CreateDamagePre(float damage, bool criticalHit,Transform uIPos)
{
GameObject damageUI = Instantiate(damageUIPre, transform);
GameObject damageUI = Instantiate(damageUIPre, uIPos.position, Quaternion.identity);
float offsetX = Random.Range(-100f, 100f);
float offsetY = Random.Range(-40f, 25f);
damageUI.transform.localPosition = damageUIPos.localPosition+new Vector3(offsetX,offsetY,0);
damageUI.GetComponent<DamageUI>().ShowDamage(damage, criticalHit);
}

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using DamageNumbersPro;
@@ -16,4 +17,9 @@ public class DamageUI : MonoBehaviour
damageNumberMesh.leftText = damage.ToString();
damageNumberMeshRed.number = damage;
}
private void Update()
{
transform.LookAt(GameInit.Ins.playerCam.transform);
}
}