(client) feat:支持定义实体的碰撞体大小和偏移;建筑支持定义实体建筑和瓦片建筑,建筑支持指定按钮回调;添加存档管理器;Dev支持设置是否暂停;实体允许定义事件组;添加基地界面 (#57)

Co-authored-by: m0_75251201 <m0_75251201@noreply.gitcode.com>
Reviewed-on: http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite/pulls/57
This commit is contained in:
2025-09-28 15:02:57 +08:00
parent 87a8abe86c
commit aff747be17
232 changed files with 39203 additions and 4161 deletions

View File

@@ -5,9 +5,9 @@ using Item;
using Managers;
using Prefab;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Parsing;
using UnityEngine;
using Utils;
@@ -19,18 +19,7 @@ namespace Entity
/// </summary>
public class Entity : MonoBehaviour, ITick
{
/// <summary>
/// 动画预制体,用于管理实体的动画逻辑。
/// </summary>
public SpriteAnimator animatorPrefab;
/// <summary>
/// 图像预制体,用于管理实体的静态图像显示。
/// </summary>
public ImagePrefab imagePrefab;
public ProgressBarPrefab healthBarPrefab;
public EntityPrefab entityPrefab;
public EntityDef entityDef;
/// <summary>
@@ -40,7 +29,7 @@ namespace Entity
public SpriteAnimator weaponItem;
public SpriteAnimator weaponAttackAnimation;
/// <summary>
/// 人工智能行为树,定义实体的行为逻辑。
/// </summary>
@@ -96,7 +85,7 @@ namespace Entity
public bool canSelect = true;
public string currentDimensionId = null;
public string currentDimensionId;
@@ -110,18 +99,18 @@ namespace Entity
if (value)
{
currentJob = null;
// 逻辑修改只有当存在一个不同的焦点实体时才将其PlayerControlled设为false
if (Program.Instance.FocusedEntity && Program.Instance.FocusedEntity != this)
{
Program.Instance.FocusedEntity.PlayerControlled = false;
}
Program.Instance.SetFocusedEntity(this);
gameObject.tag="Player";
}
// 逻辑修改:确保只有当自身是焦点实体时才取消焦点,避免不必要的逻辑执行
else if (Program.Instance.FocusedEntity == this)
{
Program.Instance.SetFocusedEntity(null);
gameObject.tag = "Untagged";
}
}
get => Program.Instance.FocusedEntity == this;
@@ -142,8 +131,8 @@ namespace Entity
public bool IsShowingHealthBarUI => _hitBarUIShowTimer > 0;
public bool IsAttacking => _attackTimer > 0;
private float _attackTimer = 0;
private float _attackDetectionTime = 0;
private float _attackTimer;
private float _attackDetectionTime;
private WeaponResource currentAttackWeapon;
/// <summary>
@@ -158,11 +147,8 @@ namespace Entity
/// </summary>
public event Action<Entity> OnEntityDied;
private bool _warning = false;
private bool _warning;
private GameObject wearponAttackAnimationNodeRoot = null;
/// <summary>
/// 存储不同朝向下的身体节点对象。
/// </summary>
@@ -171,19 +157,38 @@ namespace Entity
/// <summary>
/// 当前实体的朝向。
/// </summary>
private Orientation _currentOrientation = Orientation.Down;
public Orientation CurrentOrientation { get; private set; } = Orientation.Down;
/// <summary>
/// 当前实体的状态
/// </summary>
private EntityState _currentState = EntityState.Idle;
public EntityState CurrentState { get; private set; } = EntityState.Idle;
public AudioSource Audio;
[SerializeField] private float _hitBarUIShowTime = 5;
private float _hitBarUIShowTimer = 0;
private int _walkingTimer = 0;
private float _hitBarUIShowTimer;
private int _walkingTimer;
private List<(Func<Entity, bool>,string)> _conditionalEvents=new();
/// <summary>
/// 初始化实体的基本属性和行为树。
@@ -192,13 +197,14 @@ namespace Entity
public virtual void Init(EntityDef entityDef)
{
attributes = new Attributes(entityDef.attributes);
aiTree = AI.BehaviorTree.ConvertToAIBase(entityDef.behaviorTree);
aiTree = BehaviorTree.ConvertToAIBase(entityDef.behaviorTree);
affiliation = entityDef.affiliation?.defName;
InitBody(entityDef.drawingOrder);
this.entityDef = entityDef;
HideHealthBar();
InitWeaponAnimator();
InitConditionalEvents(entityDef.eventDef?.GetAllConditionalEvents());
}
protected virtual void InitWeaponAnimator()
@@ -231,7 +237,9 @@ namespace Entity
protected virtual void InitBody(DrawingOrderDef drawingOrder)
{
// 预缓存枚举值(避免每次循环重复调用 Enum.GetValues
var states = Enum.GetValues(typeof(EntityState)).Cast<EntityState>().ToArray();
var states = Enum.GetValues(typeof(EntityState)).Cast<EntityState>().ToList();
states.Remove(EntityState.Death);
var orientations = Enum.GetValues(typeof(Orientation)).Cast<Orientation>().ToArray();
// 预初始化字典结构(减少内层循环的字典检查)
foreach (var state in states)
@@ -250,15 +258,15 @@ namespace Entity
GameObject targetObj;
if (nodeDef == null)
{
if (imagePrefab && Managers.PackagesImageManager.Instance.defaultSprite != null)
if (PackagesImageManager.Instance.defaultSprite)
{
targetObj = Instantiate(imagePrefab.gameObject, body.transform);
targetObj = Instantiate(GameObjectCreate.ImagePrefab.gameObject, body.transform);
targetObj.name = $"{state}_{orientation}_Default";
targetObj.transform.localPosition = Vector3.zero;
var imagePrefabCom = targetObj.GetComponent<ImagePrefab>();
if (imagePrefabCom)
{
imagePrefabCom.SetSprite(Managers.PackagesImageManager.Instance.defaultSprite);
imagePrefabCom.SetSprite(PackagesImageManager.Instance.defaultSprite);
}
else
{
@@ -313,21 +321,37 @@ namespace Entity
}
protected void InitConditionalEvents(ConditionalEvent[] conditionalEvents)
{
if(conditionalEvents==null)return;
_conditionalEvents.Clear();
foreach (var conditionalEvent in conditionalEvents)
{
var condition = ConditionDelegateFactory.CreateConditionDelegate(conditionalEvent.parameter,
typeof(Entity), typeof(ConditionFunctions));
if(condition==null)continue;
_conditionalEvents.Add((condition, conditionalEvent.defName));
}
}
/// <summary>
/// 更新实体的逻辑,包括玩家控制和自动行为。
/// </summary>
public virtual void Tick()
{
//行走动画切换
if (_walkingTimer > 0)
{
_walkingTimer -= 1;
if (_walkingTimer <= 0)
{
SetBodyTexture(EntityState.Idle, _currentOrientation);
SetBodyTexture(EntityState.Idle, CurrentOrientation);
}
}
//行为控制
if (PlayerControlled)
{
UpdatePlayerControls();
@@ -336,7 +360,7 @@ namespace Entity
{
AutoBehave();
}
//血条显示
if (IsShowingHealthBarUI)
{
_hitBarUIShowTimer -= Time.deltaTime;
@@ -345,7 +369,7 @@ namespace Entity
HideHealthBar();
}
}
//攻击控制
if (_attackTimer > 0)
{
_attackTimer -= Time.deltaTime;
@@ -366,7 +390,15 @@ namespace Entity
if (_attackTimer <= 0)
{
SetBodyTexture(EntityState.Idle, _currentOrientation);
SetBodyTexture(EntityState.Idle, CurrentOrientation);
}
}
//条件事件控制
foreach (var conditionalEvent in _conditionalEvents)
{
if (conditionalEvent.Item1(this))
{
EventManager.Instance.Action(conditionalEvent.Item2, this);
}
}
}
@@ -407,7 +439,7 @@ namespace Entity
{
SetBodyTexture(
weaponResource.Type == WeaponType.Melee ? EntityState.MeleeAttack : EntityState.RangedAttack,
_currentOrientation);
CurrentOrientation);
}
else
{
@@ -430,14 +462,14 @@ namespace Entity
}
}
_currentState = state;
_currentOrientation = orientation;
CurrentState = state;
CurrentOrientation = orientation;
}
public void HideCurrentBodyTexture()
{
if (!bodyNodes.TryGetValue(_currentState, out var stateNode)) return;
if (stateNode.TryGetValue(_currentOrientation, out var node))
if (!bodyNodes.TryGetValue(CurrentState, out var stateNode)) return;
if (stateNode.TryGetValue(CurrentOrientation, out var node))
{
node.SetActive(false);
}
@@ -451,7 +483,7 @@ namespace Entity
// if (IsAttacking)
// return;
transform.position += direction * (attributes.moveSpeed * Time.deltaTime);
SetBodyTexture(EntityState.Walking, _currentOrientation);
SetBodyTexture(EntityState.Walking, CurrentOrientation);
_walkingTimer = 2;
}
@@ -551,7 +583,7 @@ namespace Entity
ori = direction.x > 0 ? Orientation.Right : Orientation.Left;
}
SetBodyTexture(_currentState, ori);
SetBodyTexture(CurrentState, ori);
if (!PlayerControlled)
{
attackDirection=direction;
@@ -598,7 +630,7 @@ namespace Entity
if (weaponItem)
RotateTool.RotateTransformToDirection(weaponItem.transform, attackDirection);
}
if (Input.GetKeyDown(KeyCode.V))
{
weaponItem.gameObject.SetActive(!weaponItem.gameObject.activeSelf);
@@ -631,7 +663,6 @@ namespace Entity
{
TryAttack();
}
// 如果有输入方向,则设置目标位置并尝试移动
if (inputDirection == Vector2.zero) return;
// 归一化方向向量,确保对角线移动速度一致
@@ -698,9 +729,9 @@ namespace Entity
// 假设 EntityManage.Instance.GenerateBulletEntity 方法存在
// (需要一个 EntityManage 单例来实现子弹生成)
if (EntityManage.Instance != null && Program.Instance != null)
if (EntityManager.Instance != null && Program.Instance != null)
{
EntityManage.Instance.GenerateBulletEntity(
EntityManager.Instance.GenerateBulletEntity(
Program.Instance.FocusedDimensionId,
weapon.Bullet,
transform.position, // 子弹的生成位置
@@ -718,5 +749,15 @@ namespace Entity
{
return null;
}
public void ExecuteEvent(EntityEventType type)
{
var eventDefs = entityDef?.eventDef?.GetEventsByType(type);
if (eventDefs == null || eventDefs.Length == 0) return;
foreach (var eventDef in eventDefs)
{
EventManager.Instance.Action(eventDef,this);
}
}
}
}