```
feat(Animation): 添加技能动画状态和过渡 - 在base人类型士控制器中添加skill动画状态 - 添加从默认状态到技能状态的过渡条件 - 配置技能动画的状态转换参数 - 在蓝色怪物override controller中添加技能动画覆盖 fix(Model): 修复模型导入设置和骨骼位置 - 将人类型士Idle模型材质导入模式从2改为1 - 调整蓝色怪物怒吼动画的最后一帧从85到65 - 修正模型骨骼位置数据,统一缩放比例 - 更新蓝色怪物模型的全局缩放从0.023到2.3 docs(Codely): 删除剪贴板图片文件 ```
This commit is contained in:
1 parent
2728c1d2cc
commit
21aceb6c04
44 files changed
+23820
-173
No files matched your search
@@ -0,0 +1,48 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class ArcherHunterSkill : UnitSkill
|
||||
{
|
||||
[Min(0f)]
|
||||
public float splitShotRadius = 3f;
|
||||
|
||||
public override void ReleaseSkill()
|
||||
{
|
||||
GameObject mainTarget = unit.Target;
|
||||
if (mainTarget == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject nearbyOpponent = FindNearbyOpponent(mainTarget);
|
||||
unit.FireSkillProjectile(nearbyOpponent != null ? nearbyOpponent : mainTarget);
|
||||
}
|
||||
|
||||
private GameObject FindNearbyOpponent(GameObject mainTarget)
|
||||
{
|
||||
string opponentTag = unit.OpponentTag;
|
||||
if (string.IsNullOrEmpty(opponentTag))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
GameObject nearbyOpponent = null;
|
||||
float nearestSqrDistance = splitShotRadius * splitShotRadius;
|
||||
GameObject[] opponents = GameObject.FindGameObjectsWithTag(opponentTag);
|
||||
foreach (GameObject opponent in opponents)
|
||||
{
|
||||
if (opponent == mainTarget || opponent == unit.gameObject || opponent.transform.root == unit.transform.root)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float sqrDistance = (opponent.transform.position - mainTarget.transform.position).sqrMagnitude;
|
||||
if (sqrDistance <= nearestSqrDistance)
|
||||
{
|
||||
nearestSqrDistance = sqrDistance;
|
||||
nearbyOpponent = opponent;
|
||||
}
|
||||
}
|
||||
|
||||
return nearbyOpponent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: XihKsyuuUn77QGunzckB2vzutslS+vzIIEIFotxpCnDDkhI1D3gAz4c=
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class BlueMonsterSkill : UnitSkill
|
||||
{
|
||||
[Min(0f)]
|
||||
public float attackSpeedIncrease = 0.2f;
|
||||
|
||||
[Min(1f)]
|
||||
public float attackSpeedLimit = 2f;
|
||||
|
||||
public override void ReleaseSkill()
|
||||
{
|
||||
unit.PlaySkillAnimation(OnRoarFinished);
|
||||
}
|
||||
|
||||
private void OnRoarFinished()
|
||||
{
|
||||
unit.MultiplyAttackSpeed(1f + attackSpeedIncrease, attackSpeedLimit);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: Wnof4X6tBy2Re/WkcDIIR8jLFhw4f9ah/x/XNbUMHqlzFHdChoNCy/I=
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -7,6 +7,7 @@ public class Projectile : MonoBehaviour
|
||||
private float damage;
|
||||
private float speed;
|
||||
private float lifetime;
|
||||
private bool registerEnergyOnHit;
|
||||
private bool initialized;
|
||||
private bool hasHit;
|
||||
|
||||
@@ -15,13 +16,15 @@ public class Projectile : MonoBehaviour
|
||||
float damageAmount,
|
||||
GameObject ownerObject,
|
||||
float moveSpeed,
|
||||
float lifeTime)
|
||||
float lifeTime,
|
||||
bool registerEnergy = true)
|
||||
{
|
||||
target = targetObject;
|
||||
damage = damageAmount;
|
||||
owner = ownerObject;
|
||||
speed = moveSpeed;
|
||||
lifetime = lifeTime;
|
||||
registerEnergyOnHit = registerEnergy;
|
||||
initialized = true;
|
||||
hasHit = false;
|
||||
|
||||
@@ -112,7 +115,7 @@ public class Projectile : MonoBehaviour
|
||||
|
||||
hasHit = true;
|
||||
healthBar.TakeDamage(damage);
|
||||
if (owner != null)
|
||||
if (registerEnergyOnHit && owner != null)
|
||||
{
|
||||
UnitBase unit = owner.GetComponent<UnitBase>();
|
||||
if (unit != null)
|
||||
|
||||
@@ -85,6 +85,11 @@ public class UnitBase : MonoBehaviour
|
||||
//当前攻击开始时间,用于在没有结束 Event 时释放攻击状态。
|
||||
private float attackStartTime;
|
||||
|
||||
private bool isPlayingSkill;
|
||||
private float attackSpeedMultiplier = 1f;
|
||||
private UnitSkill unitSkill;
|
||||
private System.Action skillFinishedCallback;
|
||||
|
||||
|
||||
//状态枚举
|
||||
public enum State
|
||||
@@ -96,7 +101,10 @@ public class UnitBase : MonoBehaviour
|
||||
Track,
|
||||
|
||||
//攻击状态
|
||||
Attack
|
||||
Attack,
|
||||
|
||||
//技能状态
|
||||
Skill
|
||||
}
|
||||
|
||||
|
||||
@@ -111,6 +119,7 @@ public class UnitBase : MonoBehaviour
|
||||
animator = GetComponent<Animator>();
|
||||
controller = GetComponent<CharacterController>();
|
||||
worldHealthBar = GetComponent<WorldHealthBar>();
|
||||
unitSkill = GetComponent<UnitSkill>();
|
||||
|
||||
// 位移和朝向由 CharacterController 与 UnitBase 控制,避免攻击动画的根运动叠加旋转。
|
||||
animator.applyRootMotion = false;
|
||||
@@ -133,6 +142,14 @@ public class UnitBase : MonoBehaviour
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPlayingSkill)
|
||||
{
|
||||
animator.SetInteger("speed", 0);
|
||||
applyGravity();
|
||||
CheckSkillAnimationFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
//查找场景中距离自己最近的敌对目标
|
||||
target = FindNearestOpponent();
|
||||
if (target != null)
|
||||
@@ -158,6 +175,12 @@ public class UnitBase : MonoBehaviour
|
||||
applyGravity();
|
||||
}
|
||||
|
||||
public GameObject Target => target;
|
||||
|
||||
public string OpponentTag => GetOpponentTag();
|
||||
|
||||
public float AttackSpeedMultiplier => attackSpeedMultiplier;
|
||||
|
||||
//根据自身Tag找到敌对Tag
|
||||
private string GetOpponentTag()
|
||||
{
|
||||
@@ -287,11 +310,11 @@ public class UnitBase : MonoBehaviour
|
||||
float animationDuration = GetAttackAnimationDuration();
|
||||
if (animationDuration <= 0f || attackDuration <= 0f)
|
||||
{
|
||||
animator.speed = 1f;
|
||||
animator.speed = attackSpeedMultiplier;
|
||||
return;
|
||||
}
|
||||
|
||||
animator.speed = animationDuration / attackDuration;
|
||||
animator.speed = animationDuration / attackDuration * attackSpeedMultiplier;
|
||||
}
|
||||
|
||||
//攻击
|
||||
@@ -365,6 +388,25 @@ public class UnitBase : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
public void FireSkillProjectile(GameObject opponent)
|
||||
{
|
||||
if (opponent == null || projectilePrefab == null || projectileSpawnPoint == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject projectileObject = Instantiate(
|
||||
projectilePrefab,
|
||||
projectileSpawnPoint.position,
|
||||
projectileSpawnPoint.rotation);
|
||||
Projectile projectile = projectileObject.GetComponent<Projectile>();
|
||||
if (projectile != null)
|
||||
{
|
||||
// 技能箭不再次积攒能量,避免技能触发递归。
|
||||
projectile.Initialize(opponent, attackPower, gameObject, projectileSpeed, projectileLifetime, false);
|
||||
}
|
||||
}
|
||||
|
||||
// 普通攻击命中后积攒能量,满能量时清空能量并调用技能占位方法。
|
||||
private void AddAttackEnergy()
|
||||
{
|
||||
@@ -382,9 +424,51 @@ public class UnitBase : MonoBehaviour
|
||||
ReleaseSkill();
|
||||
}
|
||||
|
||||
// 技能占位方法,后续由具体单位脚本重写。
|
||||
protected virtual void ReleaseSkill()
|
||||
private void ReleaseSkill()
|
||||
{
|
||||
if (unitSkill != null)
|
||||
{
|
||||
unitSkill.ReleaseSkill();
|
||||
}
|
||||
}
|
||||
|
||||
public void PlaySkillAnimation(System.Action onFinished)
|
||||
{
|
||||
if (isPlayingSkill)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
skillFinishedCallback = onFinished;
|
||||
isPlayingSkill = true;
|
||||
state = State.Skill;
|
||||
animator.speed = 1f;
|
||||
animator.SetInteger("speed", 0);
|
||||
animator.SetTrigger("skill");
|
||||
attackStartTime = Time.time;
|
||||
}
|
||||
|
||||
public void MultiplyAttackSpeed(float multiplier, float limit)
|
||||
{
|
||||
attackSpeedMultiplier = Mathf.Min(
|
||||
attackSpeedMultiplier * multiplier,
|
||||
limit);
|
||||
animator.speed = attackSpeedMultiplier;
|
||||
}
|
||||
|
||||
private void CheckSkillAnimationFinished()
|
||||
{
|
||||
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
|
||||
if (!stateInfo.IsName("skill") || stateInfo.normalizedTime < 1f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
isPlayingSkill = false;
|
||||
state = State.Alert;
|
||||
animator.speed = attackSpeedMultiplier;
|
||||
skillFinishedCallback?.Invoke();
|
||||
skillFinishedCallback = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -429,8 +513,8 @@ public class UnitBase : MonoBehaviour
|
||||
|
||||
private void FinishAttack()
|
||||
{
|
||||
//攻击动画结束后恢复Animator速度。
|
||||
animator.speed = 1f;
|
||||
//攻击动画结束后恢复当前攻速倍率。
|
||||
animator.speed = attackSpeedMultiplier;
|
||||
|
||||
//攻击动画结束后,目标仍在攻击范围内则立即进行下一次攻击。
|
||||
target = FindNearestOpponent();
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
using UnityEngine;
|
||||
|
||||
public abstract class UnitSkill : MonoBehaviour
|
||||
{
|
||||
protected UnitBase unit;
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
unit = GetComponent<UnitBase>();
|
||||
}
|
||||
|
||||
public abstract void ReleaseSkill();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: Wn4W5CmsUi1oF9d3d5TAjp/LRDE99tRbr3RNsqRATY5Z50wvV7oZtfs=
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in new issue
Block a user