(client) feat:添加消息定义,添加故事定义及其运算,武器动画可用,装备UI可用以及切换武器 fix:修复快速攻击导致协程释放出错卡死,重构为计时器,修复类型转换错误导致报错

This commit is contained in:
m0_75251201
2025-09-08 00:13:12 +08:00
parent 15cdd2b244
commit 379ed07773
39 changed files with 8353 additions and 937 deletions

View File

@ -12,7 +12,7 @@ namespace Entity
public override void SetTarget(Vector3 pos)
{
base.SetTarget(pos);
RotateTransformToDirection(transform, direction);
Utils.RotateTool.RotateTransformToDirection(transform, direction);
}
protected override void AutoBehave()
@ -41,19 +41,6 @@ namespace Entity
attributes.health -= 1;
}
// 旋转对象到指定方向
public static void RotateTransformToDirection(Transform transform, Vector3 targetDirection)
{
// 确保目标方向不是零向量
if (targetDirection == Vector3.zero)
return;
// 计算当前向上方向与目标方向之间的角度
var angle = Mathf.Atan2(targetDirection.y, targetDirection.x) * Mathf.Rad2Deg;
// 应用旋转
transform.rotation = Quaternion.Euler(0f, 0f, angle);
}
}
}

View File

@ -31,7 +31,7 @@ namespace Entity
public override void Init(EntityDef entityDef)
{
Inventory = new Inventory(this, 3);
Inventory.OnInventoryChanged += InventoryChange;
CurrentSelected = 0;
base.Init(entityDef);
}
@ -64,7 +64,12 @@ namespace Entity
public override WeaponResource GetCurrentWeapon()
{
var currentSelectItem = Inventory.GetSlot(CurrentSelected);
return (WeaponResource)currentSelectItem?.Item;
return currentSelectItem?.Item as WeaponResource;
}
private void InventoryChange()
{
InitWeaponAnimator();
}
}
}

View File

@ -76,6 +76,8 @@ namespace Entity
/// </summary>
public Vector3 direction;
public Vector3 attackDirection;
/// <summary>
/// 实体的身体部分,用于挂载动画和图像节点。
/// </summary>
@ -137,7 +139,10 @@ namespace Entity
public bool IsDead => attributes.health <= 0;
public bool IsShowingHealthBarUI => _hitBarUIShowTimer > 0;
public bool IsAttacking => _attackCoroutine != null;
public bool IsAttacking => _attackTimer > 0;
private float _attackTimer = 0;
private float _attackDetectionTime = 0;
private WeaponResource currentAttackWeapon;
/// <summary>
/// 当实体受到伤害时触发的事件。
@ -170,9 +175,7 @@ namespace Entity
/// 当前实体的状态
/// </summary>
private EntityState _currentState = EntityState.Idle;
// 协程引用
private Coroutine _attackCoroutine;
[SerializeField] private float _hitBarUIShowTime = 5;
@ -200,19 +203,19 @@ namespace Entity
{
if (weaponAnimator && weaponAnimator.transform.childCount > 0)
{
foreach (GameObject child in weaponAnimator.transform)
foreach (Transform child in weaponAnimator.transform)
{
Destroy(child);
Destroy(child.gameObject);
}
}
var currentWeapon = GetCurrentWeapon();
if (currentWeapon?.AttackAnimationDef == null)
if (currentWeapon?.AttackAnimation == null)
return;
weaponItem=GameObjectCreate.SpriteAnimator(currentWeapon.Icon.ToArray(), weaponAnimator.transform);
weaponItem.SetFPS(currentWeapon.FPS);
weaponAttackAnimation = GameObjectCreate.SpriteAnimator(currentWeapon.AttackAnimationDef.ToArray(),
weaponAttackAnimation = GameObjectCreate.SpriteAnimator(currentWeapon.AttackAnimation.ToArray(),
weaponAnimator.transform);
weaponAttackAnimation.SetFPS(currentWeapon.FPS);
weaponAttackAnimation.gameObject.SetActive(false);
@ -330,7 +333,7 @@ namespace Entity
{
AutoBehave();
}
if (IsShowingHealthBarUI)
{
_hitBarUIShowTimer -= Time.deltaTime;
@ -339,6 +342,30 @@ namespace Entity
HideHealthBar();
}
}
if (_attackTimer > 0)
{
_attackTimer -= Time.deltaTime;
if (currentAttackWeapon != null && _attackTimer <= _attackDetectionTime)
{
if (currentAttackWeapon.Type == WeaponType.Melee)
{
ExecuteMeleeAttack(currentAttackWeapon);
}
else
{
ExecuteRangedAttack(currentAttackWeapon);
}
currentAttackWeapon = null;
}
if (_attackTimer <= 0)
{
SetBodyTexture(EntityState.Idle, _currentOrientation);
}
}
}
/// <summary>
@ -358,21 +385,39 @@ namespace Entity
return;
}
// 启动基于武器的攻击协程
_attackCoroutine = StartCoroutine(AttackFlow(currentWeapon));
StartAttack(currentWeapon);
}
private void StartAttack(WeaponResource weaponResource)
{
_attackTimer = weaponResource.AttackCooldown;
_attackDetectionTime = weaponResource.AttackDetectionTime;
if (weaponResource.AttackAnimationTime > 0)
{
TemporaryAnimationManager.Instance.GenerateTemporaryAnimation(
weaponResource.AttackAnimation.ToArray(), Position,transform, weaponResource.AttackAnimationTime,
weaponResource.FPS);
}
if (weaponResource.UseEntityAttackAnimation)
{
SetBodyTexture(
weaponResource.Type == WeaponType.Melee ? EntityState.MeleeAttack : EntityState.RangedAttack,
_currentOrientation);
}
else
{
HideCurrentBodyTexture();
}
currentAttackWeapon = weaponResource;
}
public virtual void SetBodyTexture(EntityState state, Orientation orientation)
public void SetBodyTexture(EntityState state, Orientation orientation)
{
if (bodyNodes.TryGetValue(_currentState, out var stateNode))
{
if (stateNode.TryGetValue(_currentOrientation, out var node))
{
node.SetActive(false);
}
}
HideCurrentBodyTexture();
if (IsAttacking && !currentAttackWeapon.UseEntityAttackAnimation)
return;
if (bodyNodes.TryGetValue(state, out var showStateNode))
{
if (showStateNode.TryGetValue(orientation, out var showNode))
@ -385,13 +430,22 @@ namespace Entity
_currentOrientation = orientation;
}
public void HideCurrentBodyTexture()
{
if (!bodyNodes.TryGetValue(_currentState, out var stateNode)) return;
if (stateNode.TryGetValue(_currentOrientation, out var node))
{
node.SetActive(false);
}
}
/// <summary>
/// 根据方向尝试移动实体。
/// </summary>
public virtual void TryMove()
{
if (IsAttacking)
return;
// if (IsAttacking)
// return;
transform.position += direction * (attributes.moveSpeed * Time.deltaTime);
SetBodyTexture(EntityState.Walking, _currentOrientation);
_walkingTimer = 2;
@ -428,8 +482,15 @@ namespace Entity
OnEntityDied?.Invoke(this);
}
ShowHealthBar(); // 无论是否死亡都更新血条UI
TemporaryAnimationManager.Instance.GenerateTemporaryAnimation(hit.ToString(), Position);
if (Setting.Instance.CurrentSettings.showHealthBarByHit)
{
ShowHealthBar();
}
if (Setting.Instance.CurrentSettings.showHitNumber)
{
TemporaryAnimationManager.Instance.GenerateTemporaryAnimation(hit.ToString(), Position);
}
}
public void ShowHealthBar()
@ -488,6 +549,10 @@ namespace Entity
}
SetBodyTexture(_currentState, ori);
if (!PlayerControlled)
{
attackDirection=direction;
}
}
/// <summary>
@ -523,6 +588,12 @@ namespace Entity
/// </summary>
protected virtual void UpdatePlayerControls()
{
if (Input.GetMouseButton(0))
{
var mousePos = MousePosition.GetWorldPosition();
attackDirection = new Vector3(mousePos.x,mousePos.y) - Position;
}
// 获取当前键盘输入状态2D 移动,只使用 X 和 Y 轴)
var inputDirection = Vector2.zero;
@ -566,89 +637,9 @@ namespace Entity
// 调用 TryMove 方法处理实际移动逻辑
TryMove();
}
// NEW: ShakeInDirectionCoroutine 签名修改以接收持续时间
private IEnumerator ShakeInDirectionCoroutine(float duration)
{
var originalPosition = transform.position; // 记录原始位置
// 在攻击动画持续时间内进行抖动效果
transform.position += direction * 0.5f;
yield return new WaitForSeconds(duration);
transform.position = originalPosition;
}
// NEW: AttackFlow 现在接收 WeaponResource 参数
protected IEnumerator AttackFlow(WeaponResource weapon) // 将可见性改为 protected允许子类访问
{
// STEP 4: 等待到攻击判定时间
var elapsedTime = 0f;
while (elapsedTime < weapon.AttackCooldown)
{
if (IsDead)
{
/* 如果实体在此期间死亡,立刻中断 */
break;
}
elapsedTime += Time.deltaTime;
yield return null; // 等待一帧
}
// 如果实体在等待期间死亡,清理并退出
if (IsDead)
{
CleanupAttack(weapon);
yield break;
}
ExecuteWeaponAction(weapon);
var remainingAnimationTime = weapon.AttackAnimationTime - elapsedTime;
if (remainingAnimationTime > 0)
{
yield return new WaitForSeconds(remainingAnimationTime);
}
else if (weapon.AttackAnimationTime > 0)
{
yield return new WaitForSeconds(weapon.AttackAnimationTime - elapsedTime);
}
// STEP 7: 清理攻击状态
CleanupAttack(weapon);
}
private void CleanupAttack(WeaponResource weapon)
{
if (wearponAttackAnimationNodeRoot)
{
Destroy(wearponAttackAnimationNodeRoot);
wearponAttackAnimationNodeRoot = null;
}
_attackCoroutine = null;
}
protected virtual void ExecuteWeaponAction(WeaponResource weapon) // 将可见性改为 protected允许子类重写
{
if (weapon == null) return; // 安全检查
switch (weapon.Type)
{
case WeaponType.Melee:
ExecuteMeleeAttack(weapon);
break;
case WeaponType.Ranged:
ExecuteRangedAttack(weapon);
break;
default:
Debug.LogWarning($"未知武器类型: {weapon.Type} for {name}");
break;
}
}
private void ExecuteMeleeAttack(WeaponResource weapon)
{
if (weapon.Attributes == null)
@ -690,13 +681,7 @@ namespace Entity
// 获取子弹方向。这里使用实体当前的移动方向作为子弹发射方向
// 更复杂的逻辑可能根据鼠标位置、目标位置等确定
var bulletDirection = direction; // 实体当前的朝向
if (PlayerControlled && Input.GetMouseButton(0)) // 玩家控制时,如果鼠标按下,尝试朝鼠标方向发射
{
var mouseWorldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
mouseWorldPos.z = transform.position.z; // 保持Z轴一致
bulletDirection = (mouseWorldPos - transform.position).normalized;
}
var bulletDirection = attackDirection; // 实体当前的朝向
// 如果没有明确的方向,给一个默认值以防万一
if (bulletDirection == Vector3.zero) bulletDirection = Vector3.down;

View File

@ -12,6 +12,7 @@ namespace Entity
public class Pickup : Entity
{
public ItemResource itemResource;
protected override void AutoBehave()
{
}
@ -49,6 +50,7 @@ namespace Entity
var animator = animatorObj.GetComponent<SpriteAnimator>();
animator.SetSprites(texture.ToArray());
}
SetBodyTexture(EntityState.Idle, Orientation.Down);
}