(client)feat:实现子弹定义以及生成,实现初始化动画,实现血条 #43

Merged
TheRedApricot merged 7 commits from zzdxxz/Gen_Hack-and-Slash-Roguelite-zzdxxz:temp811 into main 2025-08-19 20:22:12 +08:00
78 changed files with 2711 additions and 2283 deletions
Showing only changes of commit ed7ecdb226 - Show all commits

View File

@ -0,0 +1,111 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &92380775595425480
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 697189026367054479, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
propertyPath: m_LocalPosition.x
value: -0.80437
objectReference: {fileID: 0}
- target: {fileID: 697189026367054479, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
propertyPath: m_LocalPosition.y
value: -3.38364
objectReference: {fileID: 0}
- target: {fileID: 697189026367054479, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 697189026367054479, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 697189026367054479, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 697189026367054479, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 697189026367054479, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 697189026367054479, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 697189026367054479, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 697189026367054479, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 887327274103887133, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
propertyPath: m_Name
value: CharacterPrefab Variant
objectReference: {fileID: 0}
- target: {fileID: 1550000129210799929, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
propertyPath: entity
value:
objectReference: {fileID: 1108911649520063592}
- target: {fileID: 3332598847335032684, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
propertyPath: entity
value:
objectReference: {fileID: 1108911649520063592}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents:
- targetCorrespondingSourceObject: {fileID: 887327274103887133, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
insertIndex: 2
addedObject: {fileID: 1108911649520063592}
m_SourcePrefab: {fileID: 100100000, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
--- !u!1 &943601596972592085 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 887327274103887133, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
m_PrefabInstance: {fileID: 92380775595425480}
m_PrefabAsset: {fileID: 0}
--- !u!114 &1108911649520063592
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 943601596972592085}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 757576bb4354ac54da09868e1be02eec, type: 3}
m_Name:
m_EditorClassIdentifier:
animatorPrefab: {fileID: 2113064398104960506, guid: ea9af70ce0f4c8b4a9de58ac63074156, type: 3}
imagePrefab: {fileID: 1922746734790246249, guid: a6657f26d735fab4690c8185980fda29, type: 3}
healthBarPrefab: {fileID: 8215007830330368681}
direction: {x: 0, y: 0, z: 0}
body: {fileID: 2750404322221410198}
affiliation:
canSelect: 1
hitBarUIShowTime: 5
--- !u!1 &2750404322221410198 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 2838206730318674270, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
m_PrefabInstance: {fileID: 92380775595425480}
m_PrefabAsset: {fileID: 0}
--- !u!114 &8215007830330368681 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 8307348883874536545, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
m_PrefabInstance: {fileID: 92380775595425480}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 605f185650fe46d89a6e0d60fb8fb11c, type: 3}
m_Name:
m_EditorClassIdentifier:

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5218adfb8e855a9459df63de8b2f323c
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -97,7 +97,6 @@ GameObject:
m_Component:
- component: {fileID: 697189026367054479}
- component: {fileID: 3332598847335032684}
- component: {fileID: 7300440714681954677}
- component: {fileID: 1550000129210799929}
- component: {fileID: 1724818962207668775}
- component: {fileID: 4717642781780051128}
@ -138,28 +137,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: b20b1846b9ef47db83c2ac8c4c4e82cb, type: 3}
m_Name:
m_EditorClassIdentifier:
entity: {fileID: 7300440714681954677}
entity: {fileID: 0}
outline: {fileID: 1550000129210799929}
--- !u!114 &7300440714681954677
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 887327274103887133}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fbde354e0bcc4409b3378ee9b698ddc0, type: 3}
m_Name:
m_EditorClassIdentifier:
animatorPrefab: {fileID: 2113064398104960506, guid: ea9af70ce0f4c8b4a9de58ac63074156, type: 3}
imagePrefab: {fileID: 1922746734790246249, guid: a6657f26d735fab4690c8185980fda29, type: 3}
healthBarPrefab: {fileID: 8307348883874536545}
direction: {x: 0, y: 0, z: 0}
body: {fileID: 2838206730318674270}
affiliation:
canSelect: 1
hitBarUIShowTime: 5
--- !u!114 &1550000129210799929
MonoBehaviour:
m_ObjectHideFlags: 0
@ -176,7 +155,7 @@ MonoBehaviour:
outlineRenderer: {fileID: 3992139212329961548}
outlineCollider: {fileID: 1724818962207668775}
progressBarPrefab: {fileID: 8307348883874536545}
entity: {fileID: 7300440714681954677}
entity: {fileID: 0}
--- !u!70 &1724818962207668775
CapsuleCollider2D:
m_ObjectHideFlags: 0

View File

@ -130,6 +130,18 @@ PrefabInstance:
propertyPath: m_IsActive
value: 1
objectReference: {fileID: 0}
- target: {fileID: 1550000129210799929, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
propertyPath: entity
value:
objectReference: {fileID: 8780386748333639840}
- target: {fileID: 1550000129210799929, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
propertyPath: progressBarPrefab
value:
objectReference: {fileID: 0}
- target: {fileID: 3332598847335032684, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
propertyPath: entity
value:
objectReference: {fileID: 8780386748333639840}
- target: {fileID: 3992139212329961548, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
propertyPath: m_Enabled
value: 0
@ -139,15 +151,44 @@ PrefabInstance:
value: Default
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_RemovedGameObjects:
- {fileID: 1328271255896522146, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
m_AddedGameObjects:
- targetCorrespondingSourceObject: {fileID: 5549544358816209289, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
insertIndex: -1
addedObject: {fileID: 5706548514770437405}
m_AddedComponents: []
m_AddedComponents:
- targetCorrespondingSourceObject: {fileID: 887327274103887133, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
insertIndex: 2
addedObject: {fileID: 8780386748333639840}
m_SourcePrefab: {fileID: 100100000, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
--- !u!4 &978302365984264250 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 5549544358816209289, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
m_PrefabInstance: {fileID: 4652308439801383347}
m_PrefabAsset: {fileID: 0}
--- !u!1 &5530484753491532974 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 887327274103887133, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
m_PrefabInstance: {fileID: 4652308439801383347}
m_PrefabAsset: {fileID: 0}
--- !u!114 &8780386748333639840
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5530484753491532974}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fbde354e0bcc4409b3378ee9b698ddc0, type: 3}
m_Name:
m_EditorClassIdentifier:
animatorPrefab: {fileID: 0}
imagePrefab: {fileID: 0}
healthBarPrefab: {fileID: 0}
direction: {x: 0, y: 0, z: 0}
body: {fileID: 0}
affiliation:
canSelect: 1
hitBarUIShowTime: 5

View File

@ -283,9 +283,11 @@ MonoBehaviour:
m_EditorClassIdentifier:
isGlobal: 1
entityLevel: {fileID: 1891846098}
entityPrefab: {fileID: 3332598847335032684, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
entityPrefab: {fileID: 3420474218334607780, guid: 5218adfb8e855a9459df63de8b2f323c, type: 3}
buildingLevel: {fileID: 651025902}
buildingPrefab: {fileID: 5615006624229444611, guid: d7b9277d8e6ac4541800044bdb0da063, type: 3}
bulletLevel: {fileID: 466785510}
bulletPrefab: {fileID: 8687677644466399534, guid: 29b2450a8636a104586e36333878f4d9, type: 3}
defaultEntityPrefab: {fileID: 7975757421877276383, guid: 89661daa5f100c64783f0ad9cd37a7ff, type: 3}
--- !u!4 &164739122
Transform:
@ -381,6 +383,37 @@ Transform:
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &466785510
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 466785511}
m_Layer: 0
m_Name: BulletLevel
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &466785511
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 466785510}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1423222968}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &603423466
GameObject:
m_ObjectHideFlags: 0
@ -1042,6 +1075,7 @@ Transform:
m_Children:
- {fileID: 1891846100}
- {fileID: 651025903}
- {fileID: 466785511}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1468918169

View File

@ -77,7 +77,7 @@ namespace AI
public class TrackPlayerJob : JobBase
{
private EntityPrefab currentTarget; // 当前追踪的目标玩家
private List<EntityPrefab> players; // 玩家实体列表
private LinkedList<EntityPrefab> players; // 玩家实体列表
public override void StartJob(Entity.Entity target)
{
@ -87,13 +87,13 @@ namespace AI
protected override void UpdateJob()
{
if (currentTarget == null || currentTarget.entity.IsDead)
if (!currentTarget || currentTarget.entity.IsDead)
{
// 如果当前目标无效,则重新查找最近的玩家
UpdateTarget();
}
if (currentTarget != null)
if (currentTarget)
{
var targetPosition = new Vector3(currentTarget.Position.x, currentTarget.Position.y, 0);
entity.SetTarget(targetPosition);
@ -114,7 +114,7 @@ namespace AI
currentTarget = GetNearestPlayer(players);
}
private EntityPrefab GetNearestPlayer(List<EntityPrefab> players)
private EntityPrefab GetNearestPlayer(LinkedList<EntityPrefab> players)
{
EntityPrefab nearestPlayer = null;
float minDistance = float.MaxValue;
@ -144,7 +144,7 @@ namespace AI
protected override void UpdateJob()
{
if (player == null || !IsPlayerInRange())
if (!player || !IsPlayerInRange())
{
StopJob(); // 如果玩家不在范围内,停止攻击工作
return;
@ -167,11 +167,11 @@ namespace AI
base.StartJob(target);
// 查找最近的玩家作为目标
List<EntityPrefab> players = Managers.EntityManage.Instance.FindEntitiesByFaction("Player");
LinkedList<EntityPrefab> players = Managers.EntityManage.Instance.FindEntitiesByFaction("Player");
player = GetNearestPlayer(players);
}
private EntityPrefab GetNearestPlayer(List<EntityPrefab> players)
private EntityPrefab GetNearestPlayer(LinkedList<EntityPrefab> players)
{
EntityPrefab nearestPlayer = null;
float minDistance = float.MaxValue;
@ -197,7 +197,7 @@ namespace AI
private bool IsPlayerValid(EntityPrefab player)
{
return player != null && !player.entity.IsDead;
return player && !player.entity.IsDead;
}
}
public class RangedAttackJob : JobBase
@ -206,7 +206,7 @@ namespace AI
protected override void UpdateJob()
{
if (player == null || !IsPlayerValid(player))
if (!player || !IsPlayerValid(player))
{
StopJob(); // 如果当前目标无效,停止工作
return;
@ -256,11 +256,11 @@ namespace AI
base.StartJob(target);
// 查找最近的玩家作为目标
List<EntityPrefab> players = Managers.EntityManage.Instance.FindEntitiesByFaction("Player");
var players = Managers.EntityManage.Instance.FindEntitiesByFaction("Player");
player = GetNearestPlayer(players);
}
private EntityPrefab GetNearestPlayer(List<EntityPrefab> players)
private EntityPrefab GetNearestPlayer(LinkedList<EntityPrefab> players)
{
EntityPrefab nearestPlayer = null;
float minDistance = float.MaxValue;
@ -286,7 +286,7 @@ namespace AI
private bool IsPlayerValid(EntityPrefab player)
{
return player != null && !player.entity.IsDead;
return player && !player.entity.IsDead;
}
private const float MaxTrackDistance = 20f; // 最大追踪距离

View File

@ -1,6 +1,6 @@
namespace Data
{
public class BuildingDef : PawnDef
public class BuildingDef : EntityDef
{
public float slowDown = 0f;
}

View File

@ -0,0 +1,8 @@
namespace Data
{
public class BulletDef:EntityDef
{
public string className;
public string value;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3f32fe058231409aaef631564bc51317
timeCreated: 1755173999

View File

@ -7,7 +7,7 @@ using UnityEngine;
namespace Data
{
public class CharacterDef : PawnDef
public class CharacterDef : EntityDef
{
}

View File

@ -5,7 +5,7 @@ using System.Xml.Linq;
namespace Data
{
public class PawnDef : Define
public class EntityDef : Define
{
public AttributesDef attributes;
public DrawingOrderDef drawingOrder;

View File

@ -1,6 +1,6 @@
namespace Data
{
public class MonsterDef:PawnDef
public class MonsterDef:EntityDef
{
}

View File

@ -5,6 +5,12 @@ namespace Entity
{
public class Bullet : Entity
{
public override void SetTarget(Vector3 pos)
{
base.SetTarget(pos);
RotateTransformToDirection(transform, direction);
}
protected override void AutoBehave()
{
TryMove();
@ -13,6 +19,19 @@ namespace Entity
private void OnTriggerEnter2D(Collider2D other)
{
other.GetComponent<Entity>()?.OnHit(this);
attributes.health -= 1;
}
// 旋转对象到指定方向
public static void RotateTransformToDirection(Transform transform, Vector3 targetDirection)
{
// 默认向上方向
Vector3 upDirection = Vector3.up;
// 计算旋转角度
float angle = Mathf.Atan2(targetDirection.x, targetDirection.y) * Mathf.Rad2Deg;
// 设置旋转
transform.rotation = Quaternion.Euler(0, 0, angle);
}
}
}

View File

@ -23,5 +23,16 @@ namespace Entity
return;
}
public override void TryAttack()
{
if (IsAttacking)
return;
if (!Managers.DefineManager.Instance.defines.TryGetValue(nameof(BulletDef), out var def))
return;
var buttonDef = def.Values.First();
Vector3 dir = Utils.MousePosition.GetWorldPosition();
Managers.EntityManage.Instance.GenerateBulletEntity((BulletDef)buttonDef, Position,
dir - Position);
}
}
}

View File

@ -134,7 +134,7 @@ namespace Entity
// 协程引用
private Coroutine attackCoroutine;
protected PawnDef entityDef;
protected EntityDef entityDef;
public float hitBarUIShowTime = 5;
@ -144,14 +144,14 @@ namespace Entity
/// <summary>
/// 初始化实体的基本属性和行为树。
/// </summary>
/// <param name="pawnDef">实体的定义数据。</param>
public virtual void Init(PawnDef pawnDef)
/// <param name="entityDef">实体的定义数据。</param>
public virtual void Init(EntityDef entityDef)
{
attributes = pawnDef.attributes.Clone();
aiTree = Utils.BehaviorTree.ConvertToAIBase(pawnDef.behaviorTree);
affiliation = pawnDef.affiliation;
InitBody(pawnDef.drawingOrder);
entityDef = pawnDef;
attributes = entityDef.attributes.Clone();
aiTree = Utils.BehaviorTree.ConvertToAIBase(entityDef.behaviorTree);
affiliation = entityDef.affiliation;
InitBody(entityDef.drawingOrder);
this.entityDef = entityDef;
HideHealthBar();
}
@ -288,9 +288,18 @@ namespace Entity
/// <param name="orientation">新的朝向。</param>
public virtual void SetOrientation(Orientation orientation)
{
bodyNodes[currentOrientation]?.SetActive(false);
// 禁用当前朝向的节点
if (bodyNodes.TryGetValue(currentOrientation, out var currentNode))
{
currentNode.SetActive(false);
}
// 设置新的朝向
currentOrientation = orientation;
bodyNodes[orientation]?.SetActive(true);
// 激活新朝向的节点
if (bodyNodes.TryGetValue(orientation, out var newNode))
{
newNode.SetActive(true);
}
}
/// <summary>
@ -475,20 +484,13 @@ namespace Entity
public void DetectAndAttackEnemies()
{
const int attackRange = 3;
var attackCount = 3;
// 获取攻击范围内的所有碰撞体使用LayerMask过滤掉非敌人
var attackCount = attributes.attackTargetCount;
// 获取攻击范围内的所有碰撞体
var hits = Physics2D.OverlapCircleAll(
transform.position,
attackRange,
attributes.attackRange,
LayerMask.GetMask("Entity"));
// 或者使用标签过滤(如果敌人有特定标签)
// Collider2D[] hits = Physics2D.OverlapCircleAll(transform.position, attackRange);
Debug.Log($"Found {hits.Length} potential targets in attack range");
foreach (var hit in hits)
{
if (attackCount <= 0) break;

View File

@ -9,22 +9,27 @@ namespace Managers
{
public class EntityManage : Utils.MonoSingleton<EntityManage>, ITick
{
public Dictionary<string, List<EntityPrefab>> factionEntities = new();
public Dictionary<string, LinkedList<EntityPrefab>> factionEntities = new();
public GameObject entityLevel;
public EntityPrefab entityPrefab;
public GameObject buildingLevel;
public EntityPrefab buildingPrefab;
public GameObject bulletLevel;
public EntityPrefab bulletPrefab;
public EntityPrefab defaultEntityPrefab;
public List<EntityPrefab> FindEntitiesByFaction(string factionKey)
public LinkedList<EntityPrefab> FindEntitiesByFaction(string factionKey)
{
if (factionEntities.TryGetValue(factionKey, out var entities))
{
return entities; // 如果找到,返回对应的实体列表
}
return new List<EntityPrefab>(); // 如果未找到,返回一个空列表
return new(); // 如果未找到,返回一个空列表
}
public void Tick()
{
foreach (var faction in factionEntities)
@ -43,6 +48,7 @@ namespace Managers
itike.Tick();
}
}
// 删除所有标记为死亡的实体
foreach (var entityToRemove in entitiesToRemove)
{
@ -53,149 +59,175 @@ namespace Managers
}
/// <summary>
/// 根据给定的PawnDef生成一个实体对象。
/// 根据给定的Def生成实体对象(内部通用方法)
/// </summary>
/// <param name="pawnDef">定义实体属性的PawnDef对象。</param>
/// <param name="pos">实体生成的位置。</param>
/// <remarks>
/// 1. 如果entityPrefab或pawnDef为null则不会生成实体。
/// 2. 实体将被创建在entityLevel.transform下。
/// 3. 使用EntityPrefab组件初始化实体。
/// </remarks>
public void GenerateEntity(Data.PawnDef pawnDef, Vector3 pos)
/// <param name="prefab">要实例化的预制体</param>
/// <param name="parent">生成的父级Transform</param>
/// <param name="pos">生成位置</param>
/// <param name="def">实体定义对象</param>
/// <param name="extraInit">额外的初始化操作(如子弹方向设置)</param>
/// <returns>成功时返回EntityPrefab组件失败时返回null</returns>
private EntityPrefab GenerateEntityInternal(
GameObject prefab,
Transform parent,
Vector3 pos,
Data.EntityDef def, // 所有Def类型需继承自BaseDef
Action<EntityPrefab> extraInit = null)
{
// 检查 entityPrefab 是否为空
if (!entityPrefab)
{
Debug.LogError("Error: entityPrefab is null. Please assign a valid prefab.");
GenerateDefaultEntity(pos);
return;
}
// 检查 pawnDef 是否为空
if (pawnDef == null)
{
Debug.LogError("Error: PawnDef is null. Cannot generate entity without a valid PawnDef.");
GenerateDefaultEntity(pos);
return;
}
GameObject instantiatedEntity = null; // 用于跟踪已实例化的对象
GameObject instantiatedEntity = null;
try
{
// 实例化实体对象
instantiatedEntity = Instantiate(entityPrefab.gameObject, pos, Quaternion.identity, entityLevel.transform);
// 实例化实体
instantiatedEntity = Instantiate(prefab, pos, Quaternion.identity, parent);
// 获取 EntityPrefab 组件
// 获取并验证EntityPrefab组件
var entityComponent = instantiatedEntity.GetComponent<EntityPrefab>();
// 检查 EntityPrefab 组件是否存在
if (!entityComponent)
{
throw new InvalidOperationException($"Error: EntityPrefab component not found on the instantiated object: {instantiatedEntity.name}");
throw new InvalidOperationException(
$"EntityPrefab component missing on: {instantiatedEntity.name}");
}
// 初始化实体组件
entityComponent.Init(pawnDef);
// 初始化核心数据
entityComponent.Init(def);
// 确保派系键存在,并初始化对应的列表
var factionKey = pawnDef.attributes.label ?? "default"; // 使用 null 合并运算符简化代码
// 执行类型特有的额外初始化
extraInit?.Invoke(entityComponent);
// 管理派系列表
var factionKey = def.attributes.label ?? "default";
if (!factionEntities.ContainsKey(factionKey))
{
factionEntities[factionKey] = new List<EntityPrefab>();
factionEntities[factionKey] = new LinkedList<EntityPrefab>();
}
factionEntities[factionKey].Add(entityComponent);
factionEntities[factionKey].AddLast(entityComponent);
return entityComponent;
}
catch (System.Exception ex)
{
// 如果有已实例化的对象,则销毁它
if (instantiatedEntity)
// 清理失败实例
if (instantiatedEntity) Destroy(instantiatedEntity);
Debug.LogError($"Entity generation failed: {ex.Message}\n{ex.StackTrace}");
return null;
}
}
/// <summary>
/// 根据PawnDef生成普通实体
/// </summary>
public void GenerateEntity(Data.EntityDef entityDef, Vector3 pos)
{
Destroy(instantiatedEntity); // 删除已创建的对象
}
// 捕获并记录任何异常
Debug.LogError($"An error occurred while generating the entity: {ex.Message}\nStack Trace: {ex.StackTrace}");
// 调用默认生成方法
// 验证关键参数
if (!entityPrefab)
{
Debug.LogError("entityPrefab is null! Assign a valid prefab.");
GenerateDefaultEntity(pos);
}
return;
}
if (entityDef == null)
{
Debug.LogError("EntityDef is null! Cannot generate entity.");
GenerateDefaultEntity(pos);
return;
}
// 调用通用生成逻辑
var result = GenerateEntityInternal(
entityPrefab.gameObject,
entityLevel.transform,
pos,
entityDef
);
if (!result) GenerateDefaultEntity(pos);
}
/// <summary>
/// 生成建筑实体位置使用Vector3Int
/// </summary>
public void GenerateBuildingEntity(Data.BuildingDef buildingDef, Vector3Int pos)
{
// 检查 entityPrefab 是否为空
if (!entityPrefab)
// 修正:检查正确的预制体 (buildingPrefab)
if (!buildingPrefab)
{
Debug.LogError("Error: entityPrefab is null. Please assign a valid prefab.");
Debug.LogError("buildingPrefab is null! Assign a valid prefab.");
GenerateDefaultEntity(pos);
return;
}
// 检查 pawnDef 是否为空
if (buildingDef == null)
{
Debug.LogError("Error: PawnDef is null. Cannot generate entity without a valid PawnDef.");
Debug.LogError("BuildingDef is null! Cannot generate building.");
GenerateDefaultEntity(pos);
return;
}
GameObject instantiatedEntity = null; // 用于跟踪已实例化的对象
var worldPos = new Vector3(pos.x, pos.y, pos.z);
try
{
// 实例化实体对象
instantiatedEntity = Instantiate(buildingPrefab.gameObject, pos, Quaternion.identity, buildingLevel.transform);
var result = GenerateEntityInternal(
buildingPrefab.gameObject,
buildingLevel.transform,
worldPos,
buildingDef
);
// 获取 EntityPrefab 组件
var entityComponent = instantiatedEntity.GetComponent<EntityPrefab>();
// 检查 EntityPrefab 组件是否存在
if (!entityComponent)
{
throw new InvalidOperationException($"Error: EntityPrefab component not found on the instantiated object: {instantiatedEntity.name}");
if (!result) GenerateDefaultEntity(pos);
}
// 初始化实体组件
entityComponent.Init(buildingDef);
// 确保派系键存在,并初始化对应的列表
var factionKey = buildingDef.attributes.label ?? "default"; // 使用 null 合并运算符简化代码
if (!factionEntities.ContainsKey(factionKey))
/// <summary>
/// 生成子弹实体(含方向设置)
/// </summary>
public void GenerateBulletEntity(Data.BulletDef bulletDef, Vector3 pos, Vector3 dir)
{
factionEntities[factionKey] = new List<EntityPrefab>();
}
factionEntities[factionKey].Add(entityComponent);
}
catch (System.Exception ex)
// 修正:检查正确的预制体 (bulletPrefab)
if (!bulletPrefab)
{
// 如果有已实例化的对象,则销毁它
if (instantiatedEntity)
{
Destroy(instantiatedEntity); // 删除已创建的对象
}
// 捕获并记录任何异常
Debug.LogError($"An error occurred while generating the entity: {ex.Message}\nStack Trace: {ex.StackTrace}");
// 调用默认生成方法
Debug.LogError("bulletPrefab is null! Assign a valid prefab.");
GenerateDefaultEntity(pos);
}
return;
}
if (bulletDef == null)
{
Debug.LogError("BulletDef is null! Cannot generate bullet.");
GenerateDefaultEntity(pos);
return;
}
var result = GenerateEntityInternal(
bulletPrefab.gameObject,
bulletLevel.transform,
pos,
bulletDef,
// 子弹特有的方向设置
entityComponent => entityComponent.entity.SetTarget(pos + dir)
);
if (!result) GenerateDefaultEntity(pos);
}
/// <summary>
/// 生成默认实体(错误回退)
/// </summary>
public void GenerateDefaultEntity(Vector3 pos)
{
var entity = Instantiate(defaultEntityPrefab.gameObject, pos, Quaternion.identity, entityLevel.transform);
var entity = Instantiate(defaultEntityPrefab, pos, Quaternion.identity, entityLevel.transform);
var entityComponent = entity.GetComponent<EntityPrefab>();
const string factionKey = "default";
if (!factionEntities.ContainsKey(factionKey))
{
factionEntities[factionKey] = new List<EntityPrefab>();
factionEntities[factionKey] = new LinkedList<EntityPrefab>();
}
entityComponent.DefaultInit();
factionEntities[factionKey].Add(entityComponent);
factionEntities[factionKey].AddLast(entityComponent);
}
protected override void OnStart()
{
factionEntities.Clear();

View File

@ -377,7 +377,7 @@ namespace Managers
// 尝试解析编号
if (int.TryParse(suffix, out var number))
{
sprites.Add((number, Value: value));
sprites.Add((number, value));
}
}
}

View File

@ -26,9 +26,9 @@ namespace Prefab
}
}
public void Init(Data.PawnDef pawnDef)
public void Init(Data.EntityDef entityDef)
{
entity.Init(pawnDef);
entity.Init(entityDef);
outline.Init();
outline.Hide();

View File

@ -141,13 +141,13 @@ namespace UI
return instantiatedComponent;
}
private void GenerateEntityCallback(PawnDef pawnDef)
private void GenerateEntityCallback(EntityDef entityDef)
{
entityPlacementUI.currentAction = () =>
{
Managers.EntityManage.Instance.GenerateEntity(pawnDef, Utils.MousePosition.GetWorldPosition());
Managers.EntityManage.Instance.GenerateEntity(entityDef, Utils.MousePosition.GetWorldPosition());
};
entityPlacementUI.Prompt = $"当前生成器:\n名称{pawnDef.label}\n描述{pawnDef.description}";
entityPlacementUI.Prompt = $"当前生成器:\n名称{entityDef.label}\n描述{entityDef.description}";
entityPlacementUI.snapEnabled = false;
Base.UIInputControl.Instance.Show(entityPlacementUI);
}

View File

@ -21,12 +21,19 @@
<BulletDef>
<defName>yellowBullet</defName>
<moveSpeed>10</moveSpeed>
<texture>
<path>Resources\Item\YellowBullet.png</path>
</texture>
<attributes>
<health>1</health>
<moveSpeed>20</moveSpeed>
</attributes>
<drawingOrder>
<texturePath>Resources\Item</texturePath>
<pixelsPerUnit>20</pixelsPerUnit>
<drawingOrder_down>
<node name="YellowBullet"/>
</drawingOrder_down>
</drawingOrder>
<behaviorTree>
<Node className="ContinuousMove"/>
<Node className="JobGiver_ContinuousMove"/>
</behaviorTree>
</BulletDef>

View File

Before

Width:  |  Height:  |  Size: 137 B

After

Width:  |  Height:  |  Size: 137 B