diff --git a/Client/Assets/Prefab/DevMenu.prefab b/Client/Assets/Prefab/DevMenu.prefab index a497621..28a9f5b 100644 --- a/Client/Assets/Prefab/DevMenu.prefab +++ b/Client/Assets/Prefab/DevMenu.prefab @@ -610,7 +610,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!224 &4227482396833377269 RectTransform: m_ObjectHideFlags: 0 @@ -670,6 +670,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: c83e72721411938449d92dd48c76480d, type: 3} m_Name: m_EditorClassIdentifier: + actionButton: 0 menuContent: {fileID: 4435203021089737161} textTemplate: {fileID: 2137672851208466200, guid: 4572fd0db4eb91d4588451064f59c91b, type: 3} buttonTemplate: {fileID: 3166707847097429176, guid: f0afd08be12de0d43af753af4f618da4, type: 3} diff --git a/Client/Assets/Scenes/Start.unity b/Client/Assets/Scenes/Start.unity index 2ce56da..072fa55 100644 --- a/Client/Assets/Scenes/Start.unity +++ b/Client/Assets/Scenes/Start.unity @@ -364,7 +364,8 @@ Transform: m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 - m_Children: [] + m_Children: + - {fileID: 788852947} m_Father: {fileID: 1109852279} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &603423466 @@ -450,6 +451,7 @@ GameObject: - component: {fileID: 661053191} - component: {fileID: 661053192} - component: {fileID: 661053193} + - component: {fileID: 661053194} m_Layer: 0 m_Name: Outline m_TagString: Untagged @@ -541,6 +543,131 @@ MonoBehaviour: m_EditorClassIdentifier: body: {fileID: 382708044} outlineRenderer: {fileID: 661053192} + outlineCollider: {fileID: 0} +--- !u!70 &661053194 +CapsuleCollider2D: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 661053190} + m_Enabled: 1 + serializedVersion: 3 + m_Density: 1 + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_ForceSendLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ForceReceiveLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ContactCaptureLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_CallbackLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_IsTrigger: 0 + m_UsedByEffector: 0 + m_CompositeOperation: 0 + m_CompositeOrder: 0 + m_Offset: {x: 0, y: 0} + m_Size: {x: 1, y: 1} + m_Direction: 0 +--- !u!1 &788852946 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 788852947} + - component: {fileID: 788852948} + m_Layer: 0 + m_Name: Square + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &788852947 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 788852946} + 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: 382708045} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!212 &788852948 +SpriteRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 788852946} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 0 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 9dfc825aed78fcd4ba02077103263b40, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 0 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_Sprite: {fileID: 7482667652216324306, guid: 311925a002f4447b3a28927169b83ea6, type: 3} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_FlipX: 0 + m_FlipY: 0 + m_DrawMode: 0 + m_Size: {x: 1, y: 1} + m_AdaptiveModeThreshold: 0.5 + m_SpriteTileMode: 0 + m_WasSpriteAssigned: 1 + m_MaskInteraction: 0 + m_SpriteSortPoint: 0 --- !u!1001 &1002040475 PrefabInstance: m_ObjectHideFlags: 0 @@ -685,8 +812,9 @@ GameObject: m_Component: - component: {fileID: 1109852279} - component: {fileID: 1109852280} + - component: {fileID: 1109852281} m_Layer: 0 - m_Name: EntityPrefab + m_Name: CharacterPrefab m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -721,7 +849,23 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 757576bb4354ac54da09868e1be02eec, type: 3} m_Name: m_EditorClassIdentifier: - playerControlled: 0 + direction: {x: 0, y: 0, z: 0} + canSelect: 1 + body: {fileID: 382708044} +--- !u!114 &1109852281 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1109852278} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b20b1846b9ef47db83c2ac8c4c4e82cb, type: 3} + m_Name: + m_EditorClassIdentifier: + entity: {fileID: 1109852280} + outline: {fileID: 661053193} --- !u!1001 &1147017152 PrefabInstance: m_ObjectHideFlags: 0 diff --git a/Client/Assets/Scripts/AI.meta b/Client/Assets/Scripts/AI.meta new file mode 100644 index 0000000..ad6178b --- /dev/null +++ b/Client/Assets/Scripts/AI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5760fa63a6a454c4ba22c0780f247ef2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Client/Assets/Scripts/AI/AIBase.cs b/Client/Assets/Scripts/AI/AIBase.cs index e835155..a51f57b 100644 --- a/Client/Assets/Scripts/AI/AIBase.cs +++ b/Client/Assets/Scripts/AI/AIBase.cs @@ -33,8 +33,12 @@ namespace AI { } - public class WanderNode : AIBase + public class RandomWander : AIBase { + public override JobBase GetJob(Entity.Entity target) + { + return new WanderJob(); + } } public class ConditionalAI : AIBase { diff --git a/Client/Assets/Scripts/AI/JobBase.cs b/Client/Assets/Scripts/AI/JobBase.cs index 56c003c..34609e5 100644 --- a/Client/Assets/Scripts/AI/JobBase.cs +++ b/Client/Assets/Scripts/AI/JobBase.cs @@ -1,12 +1,13 @@ using Base; using Unity.VisualScripting; +using UnityEngine; namespace AI { public abstract class JobBase { public Entity.Entity entity; - private int timeoutTicks = 1000; + private int timeoutTicks = 100; public bool Running=>timeoutTicks > 0; public virtual void StartJob(Entity.Entity target) @@ -33,6 +34,28 @@ namespace AI timeoutTicks = 0; } } - + public class WanderJob : JobBase + { + public override void StartJob(Entity.Entity target) + { + base.StartJob(target); + Vector3 move=new(Random.Range(-10,10), Random.Range(-10,10)); + var targetPosition=entity.transform.position+move; + entity.SetTarget(targetPosition); + entity.IsChase = false; + } + + protected override void UpdateJob() + { + entity.TryMove(); + } + + override public void StopJob() + { + base.StopJob(); + entity.IsChase = true; + } + + } } \ No newline at end of file diff --git a/Client/Assets/Scripts/AI/JobBase.cs.meta b/Client/Assets/Scripts/AI/JobBase.cs.meta new file mode 100644 index 0000000..03a4ed9 --- /dev/null +++ b/Client/Assets/Scripts/AI/JobBase.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d2497fdaa11d3554287c58d696dab7e9 \ No newline at end of file diff --git a/Client/Assets/Scripts/Camera.meta b/Client/Assets/Scripts/CameraControl.meta similarity index 100% rename from Client/Assets/Scripts/Camera.meta rename to Client/Assets/Scripts/CameraControl.meta diff --git a/Client/Assets/Scripts/Camera/CameraControl.cs b/Client/Assets/Scripts/CameraControl/CameraControl.cs similarity index 88% rename from Client/Assets/Scripts/Camera/CameraControl.cs rename to Client/Assets/Scripts/CameraControl/CameraControl.cs index 3c61192..31f0868 100644 --- a/Client/Assets/Scripts/Camera/CameraControl.cs +++ b/Client/Assets/Scripts/CameraControl/CameraControl.cs @@ -1,6 +1,6 @@ using UnityEngine; -namespace Camera +namespace CameraControl { public class CameraControl:MonoBehaviour,Base.ITick { diff --git a/Client/Assets/Scripts/Camera/CameraControl.cs.meta b/Client/Assets/Scripts/CameraControl/CameraControl.cs.meta similarity index 100% rename from Client/Assets/Scripts/Camera/CameraControl.cs.meta rename to Client/Assets/Scripts/CameraControl/CameraControl.cs.meta diff --git a/Client/Assets/Scripts/Data/AttributesDefine.cs b/Client/Assets/Scripts/Data/AttributesDefine.cs index 434e732..c6023f5 100644 --- a/Client/Assets/Scripts/Data/AttributesDefine.cs +++ b/Client/Assets/Scripts/Data/AttributesDefine.cs @@ -5,7 +5,7 @@ namespace Data public class AttributesDef : Define { public int health = 10; - public int moveSpeed = 1; + public float moveSpeed = 1; public int attack = 1; public int defense = 0; public int attackSpeed = 2; diff --git a/Client/Assets/Scripts/Entity/Character.cs b/Client/Assets/Scripts/Entity/Character.cs index 3be43dc..8ea0579 100644 --- a/Client/Assets/Scripts/Entity/Character.cs +++ b/Client/Assets/Scripts/Entity/Character.cs @@ -1,25 +1,28 @@ using System; using System.Linq; +using AI; using Base; using Data; using UnityEngine; namespace Entity { - public class Character : Entity,ITick + public class Character : Entity { public CharacterDef characterDef; public GameObject body; + + private void Start() + { + aiTree = new RandomWander(); + runtimeAttributes = new AttributesDef(); + } + public void Init() { if (characterDef == null) return; } - - public new void Tick() - { - base.Tick(); - } } } \ No newline at end of file diff --git a/Client/Assets/Scripts/Entity/Entity.cs b/Client/Assets/Scripts/Entity/Entity.cs index fecd20a..c098ce0 100644 --- a/Client/Assets/Scripts/Entity/Entity.cs +++ b/Client/Assets/Scripts/Entity/Entity.cs @@ -3,46 +3,60 @@ using AI; using Base; using Data; using UnityEngine; +using UnityEngine.Serialization; namespace Entity { public abstract class Entity:MonoBehaviour,ITick { - public string name; - public bool playerControlled = false; public AIBase aiTree; public JobBase currentJob; public AttributesDef runtimeAttributes; public Vector3 direction; + + public bool canSelect = true; + public bool IsChase { set; get; } = true; + public bool PlayerControlled + { + set + { + if (!value) + { + IsChase = true; + } + _isPlayerControlled = value; + } + get => _isPlayerControlled; + } + + private bool _isPlayerControlled = false; private const int WarningInterval = 5000; - private int warningTicks = 0; + private int _warningTicks = 0; public void Tick() { - if (currentJob == null || !currentJob.Running) + if (PlayerControlled) { - currentJob = aiTree.GetJob(this); - if (currentJob == null) - { - if (warningTicks<=0) - { - Debug.LogWarning($"{GetType().Name}类型的{name}没有分配到任何工作,给行为树末尾添加等待行为,避免由于没有工作导致无意义的反复查找工作导致性能问题"); - warningTicks += WarningInterval; - } - - warningTicks--; - return; - } + UpdatePlayerControls(); + } + else + { + AutoBehave(); } - - currentJob.Update(); } public virtual void TryAttck() { } + /// + /// 往对应朝向移动moveSpeed*deltaTime的距离 + /// + public virtual void TryMove() + { + transform.position+=direction * (runtimeAttributes.moveSpeed * Time.deltaTime * (IsChase ? 1 : 0.5f)); + } public virtual void OnHit(Entity from) { @@ -50,6 +64,80 @@ namespace Entity if (hit < 0) hit = from.runtimeAttributes.attack / 100; runtimeAttributes.health -= hit; + + currentJob.StopJob(); + } + + public virtual void SetTarget(Vector3 pos) + { + direction = (pos - transform.position).normalized; + } + + public virtual void Kill(float delay = 0) + { + Destroy(gameObject,delay); + } + + private void AutoBehave() + { + if (currentJob == null || !currentJob.Running) + { + currentJob = aiTree.GetJob(this); + if (currentJob == null) + { + if (_warningTicks<=0) + { + Debug.LogWarning($"{GetType().Name}类型的{name}没有分配到任何工作,给行为树末尾添加等待行为,避免由于没有工作导致无意义的反复查找工作导致性能问题"); + _warningTicks += WarningInterval; + } + + _warningTicks--; + return; + } + currentJob.StartJob(this); + } + + currentJob.Update(); + } + + private void UpdatePlayerControls() + { + // 获取当前键盘输入状态 + var inputDirection = new Vector3(); + + // 检测 WASD 输入 + if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow)) + { + inputDirection += Vector3.forward; // 向前移动 + } + if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow)) + { + inputDirection += Vector3.back; // 向后移动 + } + if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow)) + { + inputDirection += Vector3.left; // 向左移动 + } + if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow)) + { + inputDirection += Vector3.right; // 向右移动 + } + + // 如果有输入方向,则设置目标位置并尝试移动 + if (inputDirection != Vector3.zero) + { + // 归一化方向向量,确保对角线移动速度一致 + inputDirection = inputDirection.normalized; + + // 设置目标位置(假设当前位置为 transform.position) + Vector3 targetPosition = transform.position + inputDirection; + + // 调用 SetTarget 方法设置目标位置 + SetTarget(targetPosition); + + // 调用 TryMove 方法处理实际移动逻辑 + TryMove(); + } } } } \ No newline at end of file diff --git a/Client/Assets/Scripts/Entity/Outline.cs b/Client/Assets/Scripts/Entity/Outline.cs index 58daafc..1295aca 100644 --- a/Client/Assets/Scripts/Entity/Outline.cs +++ b/Client/Assets/Scripts/Entity/Outline.cs @@ -6,12 +6,18 @@ namespace Entity { public GameObject body; public SpriteRenderer outlineRenderer; + public CapsuleCollider2D outlineCollider; - public void Show() + public void Init() { var size = GetSize(); - outlineRenderer.gameObject.SetActive(true); outlineRenderer.size = size; + outlineCollider.direction = size.x > size.y ? CapsuleDirection2D.Horizontal : CapsuleDirection2D.Vertical; + outlineCollider.size = size; + } + public void Show() + { + outlineRenderer.gameObject.SetActive(true); } public void Hide() diff --git a/Client/Assets/Scripts/Prefab/EntityPrefab.cs b/Client/Assets/Scripts/Prefab/EntityPrefab.cs index eaa7c50..e2be6dc 100644 --- a/Client/Assets/Scripts/Prefab/EntityPrefab.cs +++ b/Client/Assets/Scripts/Prefab/EntityPrefab.cs @@ -1,5 +1,6 @@ using System; using AI; +using Base; using Data; using Entity; using Unity.VisualScripting; @@ -10,10 +11,16 @@ namespace Prefab public class EntityPrefab : MonoBehaviour { public Entity.Entity entity; + public Outline outline; + + public void Init(Data.PawnDef pawnDef) { entity.runtimeAttributes = pawnDef.attributes.Clone(); entity.aiTree = ConvertToAIBase(pawnDef.behaviorTree); + + outline.Init(); + outline.Hide(); } public static AIBase ConvertToAIBase(BehaviorTreeDef behaviorTreeDef) {