diff --git a/Assets/GameMain/DataTables/Entity.txt b/Assets/GameMain/DataTables/Entity.txt index 773b0a3..bd1e86b 100644 --- a/Assets/GameMain/DataTables/Entity.txt +++ b/Assets/GameMain/DataTables/Entity.txt @@ -10,5 +10,6 @@ 202 武器手枪 WeaponHandgun 203 武器斧头 WeaponSlash 204 武器闪电 WeaponLightning + 205 武器长枪 WeaponLance 10001 金币实体 CoinEntity 10002 经验实体 ExpEntity diff --git a/Assets/GameMain/DataTables/Goods.txt b/Assets/GameMain/DataTables/Goods.txt index 3a18b18..7b83641 100644 --- a/Assets/GameMain/DataTables/Goods.txt +++ b/Assets/GameMain/DataTables/Goods.txt @@ -1,5 +1,4 @@ -# 商品表 -# Id GoodsType GoodsTypeId +# Id 列1 GoodsType GoodsTypeId # int GoodsType int # 商品编号 策划备注 商品类型 商品对应物品Id 101 道具:药 Prop 101 @@ -26,3 +25,4 @@ 122 Prop 120 123 Weapon 3 124 Weapon 4 + 125 Weapon 5 diff --git a/Assets/GameMain/DataTables/Weapon.txt b/Assets/GameMain/DataTables/Weapon.txt index 9c72174..5075f13 100644 --- a/Assets/GameMain/DataTables/Weapon.txt +++ b/Assets/GameMain/DataTables/Weapon.txt @@ -1,8 +1,8 @@ -# 武器表 -# Id EntityTypeId Title IconAssetName Rarity Price PriceRandomPercent Attack Cooldown AttackRange AttackSoundId Pramas Modifiers +# Id 列1 EntityTypeId Title IconAssetName Rarity Price PriceRandomPercent Attack Cooldown AttackRange AttackSoundId Pramas Modifiers # int int string string RarityType int float int float float int string[] StatModifier[] # 武器编号 策划备注 武器实体编号 武器名 图标资源名 道具品质 武器价格 价格浮动 伤害 冷却 范围 攻击音效编号 额外参数 额外属性 1 玩家武器 201 小刀 Almighty_Icon White 120 0.05 100 1.5 5 10000 {"hitRadius":2} [] 2 202 手枪 Almighty_Icon White 130 0.05 120 1 15 10000 {} [] - 3 203 斧头 Almighty_Icon White 100 0.1 150 2 5 10000 {"SectorAngle":120} [] + 3 203 斧头 Almighty_Icon White 100 0.1 150 2 5 10000 {"sectorAngle":120} [] 4 204 闪电 Almighty_Icon White 150 0.08 80 3 12 10000 {"hitRadius":3} [] + 5 205 长枪 Almighty_Icon White 100 0.1 100 1.5 7 10000 {"hitRadius":0.3,"thrustDistance":1.2,"pierceLength":0.3} diff --git a/Assets/GameMain/Entities/WeaponLance.prefab b/Assets/GameMain/Entities/WeaponLance.prefab new file mode 100644 index 0000000..6cf8f57 --- /dev/null +++ b/Assets/GameMain/Entities/WeaponLance.prefab @@ -0,0 +1,225 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &6354441506395502586 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8872382261416578947} + - component: {fileID: 1092941560137749238} + - component: {fileID: 2293075059394330032} + m_Layer: 11 + m_Name: Cylinder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8872382261416578947 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6354441506395502586} + serializedVersion: 2 + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 0, z: 0.4} + m_LocalScale: {x: 0.5, y: 0.3, z: 0.5} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 5097192555115739519} + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!33 &1092941560137749238 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6354441506395502586} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2293075059394330032 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6354441506395502586} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: c4f37184fcb9306428d7d002f7dca96d, 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: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!1 &6722279723536450523 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4238244161129684256} + - component: {fileID: 8136283925019532162} + - component: {fileID: 452598937405325984} + - component: {fileID: 6200741578935482964} + m_Layer: 11 + m_Name: Cylinder 1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4238244161129684256 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6722279723536450523} + serializedVersion: 2 + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 0, z: 0.7} + m_LocalScale: {x: 0.2, y: 0.3, z: 0.2} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 5097192555115739519} + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!33 &8136283925019532162 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6722279723536450523} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &452598937405325984 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6722279723536450523} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, 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: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!136 &6200741578935482964 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6722279723536450523} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!1 &7825103691467368365 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5097192555115739519} + m_Layer: 11 + m_Name: WeaponLance + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5097192555115739519 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7825103691467368365} + 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: + - {fileID: 8872382261416578947} + - {fileID: 4238244161129684256} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Assets/GameMain/Entities/WeaponLance.prefab.meta b/Assets/GameMain/Entities/WeaponLance.prefab.meta new file mode 100644 index 0000000..541f6e3 --- /dev/null +++ b/Assets/GameMain/Entities/WeaponLance.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 11143001bcbdc864b8d8fe2083142e5a +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameMain/Scripts/DataTable/DRWeapon.cs b/Assets/GameMain/Scripts/DataTable/DRWeapon.cs index edf6b37..b2346c1 100644 --- a/Assets/GameMain/Scripts/DataTable/DRWeapon.cs +++ b/Assets/GameMain/Scripts/DataTable/DRWeapon.cs @@ -122,7 +122,7 @@ namespace DataTable /// private Dictionary DeserializeParams(string rawParams) { - var dict = new Dictionary(); + var dict = new Dictionary(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrWhiteSpace(rawParams)) { return dict; @@ -143,7 +143,7 @@ namespace DataTable continue; } - dict[pair.Key.ToLower()] = pair.Value.ToString(); + dict[pair.Key] = pair.Value.ToString(); } } catch (Exception exception) diff --git a/Assets/GameMain/Scripts/Definition/Enum/WeaponType.cs b/Assets/GameMain/Scripts/Definition/Enum/WeaponType.cs index f8c9520..cddd437 100644 --- a/Assets/GameMain/Scripts/Definition/Enum/WeaponType.cs +++ b/Assets/GameMain/Scripts/Definition/Enum/WeaponType.cs @@ -7,5 +7,6 @@ namespace Definition.Enum WeaponHandgun = 2, WeaponSlash = 3, WeaponLightning = 4, + WeaponLance = 5, } } diff --git a/Assets/GameMain/Scripts/Entity/EntityData/Enemy/EnemyData.cs b/Assets/GameMain/Scripts/Entity/EntityData/Enemy/EnemyData.cs index 117a255..490eb8c 100644 --- a/Assets/GameMain/Scripts/Entity/EntityData/Enemy/EnemyData.cs +++ b/Assets/GameMain/Scripts/Entity/EntityData/Enemy/EnemyData.cs @@ -59,7 +59,7 @@ namespace Entity.EntityData return false; } - return _drEnemy.Params.TryGetValue(key.ToLower(), out value); + return _drEnemy.Params.TryGetValue(key, out value); } } } diff --git a/Assets/GameMain/Scripts/Entity/EntityData/Weapon/WeaponData.cs b/Assets/GameMain/Scripts/Entity/EntityData/Weapon/WeaponData.cs index b47958a..4483584 100644 --- a/Assets/GameMain/Scripts/Entity/EntityData/Weapon/WeaponData.cs +++ b/Assets/GameMain/Scripts/Entity/EntityData/Weapon/WeaponData.cs @@ -37,7 +37,7 @@ namespace Entity.EntityData return false; } - return Params.TryGetValue(key.ToLower(), out value); + return Params.TryGetValue(key, out value); } protected TParams ParseParams() where TParams : new() diff --git a/Assets/GameMain/Scripts/Entity/EntityData/Weapon/WeaponLanceData.cs b/Assets/GameMain/Scripts/Entity/EntityData/Weapon/WeaponLanceData.cs new file mode 100644 index 0000000..c3c3cce --- /dev/null +++ b/Assets/GameMain/Scripts/Entity/EntityData/Weapon/WeaponLanceData.cs @@ -0,0 +1,56 @@ +using System; +using Definition.Enum; + +namespace Entity.EntityData +{ + [Serializable] + public sealed class WeaponLanceParamsData + { + /// + /// 枪尖命中半径。 + /// + public float HitRadius { get; set; } + + /// + /// 武器模型前刺的位移距离。 + /// + public float ThrustDistance { get; set; } + + /// + /// 实际判定的前刺长度。 + /// + public float PierceLength { get; set; } + + /// + /// 判定起点相对武器当前位置的前置偏移。 + /// + public float ForwardOffset { get; set; } + + /// + /// 追踪目标时的转向速度。 + /// + public float RotateSpeed { get; set; } + + /// + /// 向前突刺阶段耗时。 + /// + public float AttackDuration { get; set; } + + /// + /// 收枪返回阶段耗时。 + /// + public float ReturnDuration { get; set; } + } + + [Serializable] + public class WeaponLanceData : WeaponData + { + public WeaponLanceParamsData ParamsData { get; } + + public WeaponLanceData(int entityId, int ownerId, CampType ownerCamp) + : base(entityId, WeaponType.WeaponLance, ownerId, ownerCamp) + { + ParamsData = ParseParams(); + } + } +} diff --git a/Assets/GameMain/Scripts/Entity/EntityData/Weapon/WeaponLanceData.cs.meta b/Assets/GameMain/Scripts/Entity/EntityData/Weapon/WeaponLanceData.cs.meta new file mode 100644 index 0000000..f16bacc --- /dev/null +++ b/Assets/GameMain/Scripts/Entity/EntityData/Weapon/WeaponLanceData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4d1a821e8ee1a9a4b912b70b0a1616eb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponBase.cs b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponBase.cs index 754a296..3a4fd7c 100644 --- a/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponBase.cs +++ b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponBase.cs @@ -37,7 +37,7 @@ namespace Entity.Weapon protected ITargetSelector TargetSelector { get; set; } protected Dictionary _states; - + protected WeaponStateBase _currentState; protected EntityBase _target; @@ -50,7 +50,7 @@ namespace Entity.Weapon private StatComponent _attackStatComponent; private System.Action _attackStatCallback; - + private static readonly List s_EmptyCandidates = new(); #region Lifecycle @@ -304,11 +304,4 @@ namespace Entity.Weapon public abstract void OnLeave(); public override string ToString() => State.ToString(); } - - - - - -} - - +} \ No newline at end of file diff --git a/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponHandgun/WeaponHandgun.cs b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponHandgun/WeaponHandgun.cs index cae096f..22bd47d 100644 --- a/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponHandgun/WeaponHandgun.cs +++ b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponHandgun/WeaponHandgun.cs @@ -46,22 +46,15 @@ namespace Entity.Weapon { FaceTargetImmediately(); - Vector3 fireOrigin = CachedTransform.TransformPoint(_fireOriginOffset); - Vector3 fireDirection = CachedTransform.forward; - float maxDistance = Mathf.Max(0.1f, _weaponData.AttackRange); - - if (Physics.Raycast(fireOrigin, fireDirection, out RaycastHit hit, maxDistance, _hitMask, - QueryTriggerInteraction.Collide)) + if (!TryResolveAttackTarget(out TargetableObject targetable, out Vector3 hitPosition)) { - TargetableObject targetable = hit.collider.GetComponentInParent(); - if (targetable != null && targetable.Available && !targetable.IsDead) - { - _attackEffect?.Play(this, hit.point, targetable, 0f); - _isAttacking = true; - AIUtility.PerformCollision(targetable, this); - _isAttacking = false; - } + return; } + + _attackEffect?.Play(this, hitPosition, targetable, 0f); + _isAttacking = true; + AIUtility.PerformCollision(targetable, this); + _isAttacking = false; } protected override void Check() @@ -95,6 +88,40 @@ namespace Entity.Weapon CachedTransform.rotation = Quaternion.LookRotation(directionToTarget.normalized, Vector3.up); } + private bool TryResolveAttackTarget(out TargetableObject targetable, out Vector3 hitPosition) + { + targetable = _target as TargetableObject; + hitPosition = CachedTransform.position; + if (targetable == null || !targetable.Available || targetable.IsDead) + { + return false; + } + + Transform targetTransform = targetable.CachedTransform; + if (targetTransform == null) + { + return false; + } + + hitPosition = targetTransform.position; + + Vector3 fireOrigin = CachedTransform.TransformPoint(_fireOriginOffset); + Vector3 directionToTarget = targetTransform.position - fireOrigin; + float maxDistance = Mathf.Max(0.1f, _weaponData.AttackRange); + if (directionToTarget.sqrMagnitude > Mathf.Epsilon && + Physics.Raycast(fireOrigin, directionToTarget.normalized, out RaycastHit hit, maxDistance, _hitMask, + QueryTriggerInteraction.Collide)) + { + TargetableObject raycastTarget = hit.collider.GetComponentInParent(); + if (raycastTarget == targetable) + { + hitPosition = hit.point; + } + } + + return true; + } + #region Lifecycle protected override bool OnWeaponShow(object userData) diff --git a/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance.meta b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance.meta new file mode 100644 index 0000000..4d75326 --- /dev/null +++ b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aee5d5037e73e894cac11712e321b930 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.AttackState.cs b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.AttackState.cs new file mode 100644 index 0000000..394b447 --- /dev/null +++ b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.AttackState.cs @@ -0,0 +1,31 @@ +namespace Entity.Weapon +{ + public partial class WeaponLance + { + private class AttackState : WeaponStateBase + { + private WeaponLance _weapon; + + public override WeaponStateType State => WeaponStateType.Attack; + public override void OnInit(WeaponBase weapon) => _weapon = weapon as WeaponLance; + + public override void OnEnter() + { + _weapon._currAttackTimer = 0f; + _weapon.Attack(); + } + + public override void OnUpdate(float elapseSeconds, float realElapseSeconds) + { + if (!_weapon._isAttacking) + { + _weapon.TransitionTo(WeaponStateType.Check_InRange); + } + } + + public override void OnLeave() + { + } + } + } +} diff --git a/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.AttackState.cs.meta b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.AttackState.cs.meta new file mode 100644 index 0000000..2ad423b --- /dev/null +++ b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.AttackState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d9991ee189b733b4e9d40395357f5ef2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.CheckInRangeState.cs b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.CheckInRangeState.cs new file mode 100644 index 0000000..2d1d3d2 --- /dev/null +++ b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.CheckInRangeState.cs @@ -0,0 +1,49 @@ +namespace Entity.Weapon +{ + public partial class WeaponLance + { + private class CheckInRangeState : WeaponStateBase + { + private WeaponLance _weapon; + + public override WeaponStateType State => WeaponStateType.Check_InRange; + public override void OnInit(WeaponBase weapon) => _weapon = weapon as WeaponLance; + + public override void OnEnter() + { + if (_weapon._currAttackTimer >= _weapon._weaponData.Cooldown) + { + _weapon.TransitionTo(WeaponStateType.Attack); + } + } + + public override void OnUpdate(float elapseSeconds, float realElapseSeconds) + { + _weapon.Check(); + _weapon.RotateToTarget(elapseSeconds); + _weapon._currAttackTimer += elapseSeconds; + + if (_weapon._target == null || !_weapon._target.Available) + { + _weapon.TransitionTo(WeaponStateType.Idle); + return; + } + + if (!_weapon.IsInRange(_weapon._target, _weapon._sqrRange)) + { + _weapon.TransitionTo(WeaponStateType.Check_OutRange); + return; + } + + if (_weapon._currAttackTimer >= _weapon._weaponData.Cooldown) + { + _weapon.TransitionTo(WeaponStateType.Attack); + } + } + + public override void OnLeave() + { + } + } + } +} diff --git a/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.CheckInRangeState.cs.meta b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.CheckInRangeState.cs.meta new file mode 100644 index 0000000..3e6f575 --- /dev/null +++ b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.CheckInRangeState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 01edc8bb0ff46a14d8028e03af932b52 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.CheckOutRangeState.cs b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.CheckOutRangeState.cs new file mode 100644 index 0000000..93bf972 --- /dev/null +++ b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.CheckOutRangeState.cs @@ -0,0 +1,39 @@ +namespace Entity.Weapon +{ + public partial class WeaponLance + { + private class CheckOutRangeState : WeaponStateBase + { + private WeaponLance _weapon; + + public override WeaponStateType State => WeaponStateType.Check_OutRange; + public override void OnInit(WeaponBase weapon) => _weapon = weapon as WeaponLance; + + public override void OnEnter() + { + } + + public override void OnUpdate(float elapseSeconds, float realElapseSeconds) + { + _weapon.Check(); + _weapon.RotateToTarget(elapseSeconds); + _weapon._currAttackTimer += elapseSeconds; + + if (_weapon._target == null || !_weapon._target.Available) + { + _weapon.TransitionTo(WeaponStateType.Idle); + return; + } + + if (_weapon.IsInRange(_weapon._target, _weapon._sqrRange)) + { + _weapon.TransitionTo(WeaponStateType.Check_InRange); + } + } + + public override void OnLeave() + { + } + } + } +} diff --git a/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.CheckOutRangeState.cs.meta b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.CheckOutRangeState.cs.meta new file mode 100644 index 0000000..416d391 --- /dev/null +++ b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.CheckOutRangeState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8009ad2c332a956438e3357ed5e30eb6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.IdleState.cs b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.IdleState.cs new file mode 100644 index 0000000..f0ab6f0 --- /dev/null +++ b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.IdleState.cs @@ -0,0 +1,33 @@ +namespace Entity.Weapon +{ + public partial class WeaponLance + { + public class IdleState : WeaponStateBase + { + private WeaponLance _weapon; + + public override WeaponStateType State => WeaponStateType.Idle; + public override void OnInit(WeaponBase weapon) => _weapon = weapon as WeaponLance; + + public override void OnEnter() + { + } + + public override void OnUpdate(float elapseSeconds, float realElapseSeconds) + { + _weapon.Check(); + _weapon.RotateToOrigin(elapseSeconds); + _weapon._currAttackTimer += elapseSeconds; + + if (_weapon._target != null && _weapon._target.Available) + { + _weapon.TransitionTo(WeaponStateType.Check_OutRange); + } + } + + public override void OnLeave() + { + } + } + } +} diff --git a/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.IdleState.cs.meta b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.IdleState.cs.meta new file mode 100644 index 0000000..4ad5fa9 --- /dev/null +++ b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.IdleState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4c9e98f5381e579469dcdac7bf3e1e25 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.cs b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.cs new file mode 100644 index 0000000..2a94a49 --- /dev/null +++ b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.cs @@ -0,0 +1,325 @@ +using System.Collections.Generic; +using CustomUtility; +using Definition.DataStruct; +using Definition.Enum; +using DG.Tweening; +using Entity.EntityData; +using UnityEngine; +using UnityGameFramework.Runtime; + +namespace Entity.Weapon +{ + public partial class WeaponLance : WeaponBase + { + // 长枪专用数据,包含强类型 ParamsData。 + [SerializeField] private WeaponLanceData _weaponData; + + private Quaternion _cachedRotation; + // 朝向目标时的旋转速度,可被 ParamsData.RotateSpeed 覆盖。 + [SerializeField] private float _rotateSpeed = 5f; + + private Sequence _attackSequence; + private Transform _attackParent; + + // 前刺动画耗时。 + [SerializeField] private float _attackDuration = 0.12f; + // 收枪返回耗时。 + [SerializeField] private float _returnDuration = 0.18f; + + [SerializeField] private LayerMask _hitMask = ~0; + [SerializeField] private int _maxHitColliders = 32; + + private IWeaponAttackEffect _attackEffect; + private Collider[] _hitResults; + private readonly HashSet _hitEntityIds = new(); + + // 枪尖判定半径。 + private float _hitRadius; + // 从判定起点向前延伸的有效刺击长度。 + private float _pierceLength; + // 判定起点相对武器当前位置的前移量。 + private float _forwardOffset; + // 武器模型本身向前突刺的位移长度。 + private float _thrustDistance; + + public override ImpactData GetImpactData() + { + return new ImpactData(_weaponData.OwnerCamp, _weaponData.Attack, AttackStat); + } + + protected override void BuildStates() + { + RegisterState(new IdleState()); + RegisterState(new CheckInRangeState()); + RegisterState(new CheckOutRangeState()); + RegisterState(new AttackState()); + } + + protected override void Attack() + { + StopAttackTween(false); + FaceTargetImmediately(); + + _isAttacking = true; + _attackParent = CachedTransform.parent; + CachedTransform.SetParent(null); + + Vector3 targetPos = CachedTransform.position + CachedTransform.forward * _thrustDistance; + _attackSequence = DOTween.Sequence(); + _attackSequence.Append(CachedTransform.DOMove(targetPos, _attackDuration).SetEase(Ease.OutQuad)); + _attackSequence.AppendCallback(() => + { + Vector3 strikeCenter = GetStrikeCenter(); + _attackEffect?.Play(this, strikeCenter, _target, _hitRadius); + ApplyPierceDamage(); + + if (_attackParent != null) + { + CachedTransform.SetParent(_attackParent); + } + }); + _attackSequence.Append(CachedTransform.DOLocalMove(Vector3.zero, _returnDuration).SetEase(Ease.InQuad)); + _attackSequence.AppendCallback(() => + { + _isAttacking = false; + _attackSequence = null; + _attackParent = null; + }); + } + + protected override void Check() + { + _target = SelectTarget(_sqrRange); + } + + private void RotateToTarget(float elapseSeconds) + { + if (_target == null || !_target.Available) return; + + Vector3 directionToTarget = _target.CachedTransform.position - CachedTransform.position; + directionToTarget.y = 0f; + if (directionToTarget.sqrMagnitude <= Mathf.Epsilon) return; + + Quaternion targetRotation = Quaternion.LookRotation(directionToTarget.normalized, Vector3.up); + CachedTransform.rotation = + Quaternion.Slerp(CachedTransform.rotation, targetRotation, _rotateSpeed * elapseSeconds); + } + + private void RotateToOrigin(float elapseSeconds) + { + CachedTransform.rotation = + Quaternion.Slerp(CachedTransform.rotation, _cachedRotation, _rotateSpeed * elapseSeconds); + } + + private void FaceTargetImmediately() + { + if (_target == null || !_target.Available) return; + + Vector3 directionToTarget = _target.CachedTransform.position - CachedTransform.position; + directionToTarget.y = 0f; + if (directionToTarget.sqrMagnitude <= Mathf.Epsilon) return; + + CachedTransform.rotation = Quaternion.LookRotation(directionToTarget.normalized, Vector3.up); + } + + private Vector3 GetStrikeStart() + { + Vector3 forward = CachedTransform.forward; + forward.y = 0f; + if (forward.sqrMagnitude <= Mathf.Epsilon) + { + forward = Vector3.forward; + } + + forward.Normalize(); + return CachedTransform.position + forward * _forwardOffset; + } + + private Vector3 GetStrikeEnd() + { + Vector3 start = GetStrikeStart(); + Vector3 forward = CachedTransform.forward; + forward.y = 0f; + if (forward.sqrMagnitude <= Mathf.Epsilon) + { + forward = Vector3.forward; + } + + forward.Normalize(); + return start + forward * _pierceLength; + } + + private Vector3 GetStrikeCenter() + { + return Vector3.Lerp(GetStrikeStart(), GetStrikeEnd(), 0.5f); + } + + private void ApplyPierceDamage() + { + if (_hitRadius <= 0f || _pierceLength <= 0f) return; + + Vector3 strikeStart = GetStrikeStart(); + Vector3 strikeEnd = GetStrikeEnd(); + Vector3 strikeDirection = strikeEnd - strikeStart; + strikeDirection.y = 0f; + if (strikeDirection.sqrMagnitude <= Mathf.Epsilon) return; + + strikeDirection.Normalize(); + float halfAngle = Mathf.Rad2Deg * Mathf.Atan2(_hitRadius, Mathf.Max(0.01f, _pierceLength)); + if (TryQueueSectorCollisionQuery(strikeStart, _pierceLength, in strikeDirection, halfAngle, + Mathf.Max(1, _maxHitColliders))) + { + _hitEntityIds.Clear(); + return; + } + + int capacity = Mathf.Max(1, _maxHitColliders); + float broadPhaseRadius = _pierceLength * 0.5f + _hitRadius; + Vector3 broadPhaseCenter = Vector3.Lerp(strikeStart, strikeEnd, 0.5f); + + if (_hitResults == null || _hitResults.Length != capacity) + { + _hitResults = new Collider[capacity]; + } + + int hitCount = Physics.OverlapSphereNonAlloc(broadPhaseCenter, broadPhaseRadius, _hitResults, _hitMask, + QueryTriggerInteraction.Collide); + + _hitEntityIds.Clear(); + for (int i = 0; i < hitCount; i++) + { + Collider collider = _hitResults[i]; + if (collider == null) continue; + + TargetableObject targetable = collider.GetComponentInParent(); + if (targetable == null || !targetable.Available || targetable.IsDead) continue; + if (!_hitEntityIds.Add(targetable.Id)) continue; + + if (!IsTargetInsidePierce(targetable, strikeStart, strikeDirection)) continue; + + AIUtility.PerformCollision(targetable, this); + } + } + + private bool IsTargetInsidePierce(TargetableObject targetable, Vector3 strikeStart, Vector3 strikeDirection) + { + Vector3 toTarget = targetable.CachedTransform.position - strikeStart; + toTarget.y = 0f; + + float projection = Vector3.Dot(toTarget, strikeDirection); + if (projection < 0f || projection > _pierceLength) return false; + + Vector3 closestPoint = strikeStart + strikeDirection * projection; + Vector3 delta = targetable.CachedTransform.position - closestPoint; + delta.y = 0f; + return delta.sqrMagnitude <= _hitRadius * _hitRadius; + } + + protected override bool OnWeaponShow(object userData) + { + _weaponData = RequireWeaponData(userData); + if (_weaponData == null) return false; + WeaponData = _weaponData; + + _currAttackTimer = 0f; + _sqrRange = _weaponData.AttackRange * _weaponData.AttackRange; + _cachedRotation = CachedTransform.rotation; + + WeaponLanceParamsData paramsData = _weaponData.ParamsData; + _hitRadius = paramsData != null && paramsData.HitRadius > 0f + ? Mathf.Max(0.1f, paramsData.HitRadius) + : 0.45f; + _thrustDistance = paramsData != null && paramsData.ThrustDistance > 0f + ? paramsData.ThrustDistance + : _weaponData.AttackRange; + _pierceLength = paramsData != null && paramsData.PierceLength > 0f + ? paramsData.PierceLength + : Mathf.Max(_weaponData.AttackRange, _thrustDistance); + _forwardOffset = paramsData != null && paramsData.ForwardOffset > 0f + ? paramsData.ForwardOffset + : 0f; + + if (paramsData != null && paramsData.RotateSpeed > 0f) + { + _rotateSpeed = paramsData.RotateSpeed; + } + + if (paramsData != null && paramsData.AttackDuration > 0f) + { + _attackDuration = paramsData.AttackDuration; + } + + if (paramsData != null && paramsData.ReturnDuration > 0f) + { + _returnDuration = paramsData.ReturnDuration; + } + + int colliderCapacity = Mathf.Max(1, _maxHitColliders); + if (_hitResults == null || _hitResults.Length != colliderCapacity) + { + _hitResults = new Collider[colliderCapacity]; + } + + _attackEffect = new KnifeRangeAttackEffect(); + + if (_weaponData.OwnerCamp == CampType.Player) + { + gameObject.layer = LayerMask.NameToLayer("PlayerWeapon"); + _hitMask = LayerMask.GetMask("Enemy"); + } + else if (_weaponData.OwnerCamp == CampType.Enemy) + { + gameObject.layer = LayerMask.NameToLayer("EnemyWeapon"); + _hitMask = LayerMask.GetMask("Player"); + } + + return true; + } + + protected override void OnWeaponHide(object userData) + { + StopAttackTween(true); + _attackEffect = null; + } + + protected override void OnWeaponAttach(EntityLogic parentEntity, Transform parentTransform, object userData) + { + BindAttackStatFromOwner(parentEntity); + } + + protected override void OnWeaponDetach(EntityLogic parentEntity, object userData) + { + StopAttackTween(true); + ReleaseAttackStatSubscription(); + } + + protected override void OnEnabledChanged(bool enabled) + { + if (!enabled) + { + StopAttackTween(true); + } + } + + private void StopAttackTween(bool resetTransform) + { + if (_attackSequence != null) + { + _attackSequence.Kill(); + _attackSequence = null; + } + + _isAttacking = false; + + if (resetTransform && _attackParent != null) + { + CachedTransform.SetParent(_attackParent); + CachedTransform.localPosition = Vector3.zero; + CachedTransform.rotation = _cachedRotation; + } + + _attackParent = null; + _hitEntityIds.Clear(); + } + } +} diff --git a/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.cs.meta b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.cs.meta new file mode 100644 index 0000000..b54effa --- /dev/null +++ b/Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLance/WeaponLance.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f90612be7695ee549b39473c9b706122 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameMain/Scripts/Procedure/Game/GameStateBattle.cs b/Assets/GameMain/Scripts/Procedure/Game/GameStateBattle.cs index b6a4ba2..2e3f13b 100644 --- a/Assets/GameMain/Scripts/Procedure/Game/GameStateBattle.cs +++ b/Assets/GameMain/Scripts/Procedure/Game/GameStateBattle.cs @@ -92,14 +92,9 @@ namespace Procedure GameEntry.Entity.HideEntity(entity.Id); } - var enemyProjectiles = GameEntry.Entity.GetEntityGroup("EnemyProjectile")?.GetAllEntities(); - if (enemyProjectiles != null) - { - foreach (var projectile in enemyProjectiles) - { - GameEntry.Entity.HideEntity(projectile.Id); - } - } + HideEntityGroup("Bullet"); + HideEntityGroup("Projectile"); + HideEntityGroup("EnemyProjectile"); } public override void OnDestroy(IFsm procedureOwner) @@ -108,6 +103,21 @@ namespace Procedure _procedureGame = null; } + private static void HideEntityGroup(string groupName) + { + var entityGroup = GameEntry.Entity.GetEntityGroup(groupName); + var entities = entityGroup?.GetAllEntities(); + if (entities == null) + { + return; + } + + foreach (var entity in entities) + { + GameEntry.Entity.HideEntity(entity.Id); + } + } + #endregion } } diff --git a/Assets/GameMain/Scripts/Simulation/Presentation/SimulationWorld.HitPresentation.cs b/Assets/GameMain/Scripts/Simulation/Presentation/SimulationWorld.HitPresentation.cs index d2776e7..4c681ff 100644 --- a/Assets/GameMain/Scripts/Simulation/Presentation/SimulationWorld.HitPresentation.cs +++ b/Assets/GameMain/Scripts/Simulation/Presentation/SimulationWorld.HitPresentation.cs @@ -104,18 +104,8 @@ namespace Simulation private void PlayHitMarker(ProjectileHitPresentationEventArgs args) { - EntityBase targetEntity = TryGetEntityById(args.TargetEntityId); - if (targetEntity == null || !targetEntity.Available) - { - return; - } - - _projectileHitMarkerEffect ??= new HandgunHitMarkerAttackEffect( - Mathf.Max(0.01f, _world._projectileHitMarkerSize), - _world._projectileHitMarkerYOffset, - Mathf.Max(0.01f, _world._projectileHitMarkerDuration), - _world._projectileHitMarkerColor); - _projectileHitMarkerEffect.Play(null, args.HitPosition, targetEntity, 0f); + // Projectile hit markers were reusing the handgun marker effect and were + // visually indistinguishable from handgun lock/hit feedback. } private void PlayHitEffect(ProjectileHitPresentationEventArgs args) @@ -142,4 +132,4 @@ namespace Simulation } } } -} \ No newline at end of file +} diff --git a/Assets/GameMain/Scripts/UI/GameScene/Controller/DisplayItemInfoFormController.cs b/Assets/GameMain/Scripts/UI/GameScene/Controller/DisplayItemInfoFormController.cs index 19ce4dc..47019ee 100644 --- a/Assets/GameMain/Scripts/UI/GameScene/Controller/DisplayItemInfoFormController.cs +++ b/Assets/GameMain/Scripts/UI/GameScene/Controller/DisplayItemInfoFormController.cs @@ -139,19 +139,7 @@ namespace UI { return; } - - if (Context == null) - { - Log.Error("DisplayItemInfoFormController.DisplayItemInfoHide() Context is null."); - return; - } - - if (Form == null) - { - Log.Error("DisplayItemInfoFormController.DisplayItemInfoHide() Form is null."); - return; - } - + if (args.Force) { GameEntry.UIRouter.CloseUI(UIFormType.DisplayItemInfoForm); @@ -159,11 +147,8 @@ namespace UI return; } - if (_locked && !IsCurrentFormSender(sender) && sender is not DisplayItem) - { - return; - } - + if (_locked && !args.Force) return; + GameEntry.UIRouter.CloseUI(UIFormType.DisplayItemInfoForm); _locked = false; } diff --git a/Assets/GameMain/Scripts/UI/GameScene/Controller/ShopFormController.cs b/Assets/GameMain/Scripts/UI/GameScene/Controller/ShopFormController.cs index 59b2a7b..97924b3 100644 --- a/Assets/GameMain/Scripts/UI/GameScene/Controller/ShopFormController.cs +++ b/Assets/GameMain/Scripts/UI/GameScene/Controller/ShopFormController.cs @@ -199,6 +199,12 @@ namespace UI #region UI Methods + public override void CloseUI() + { + base.CloseUI(); + GameEntry.Event.Fire(this, DisplayItemInfoHideEventArgs.Create(true)); + } + public int? OpenUI(ShopFormRawData rawData) { ShopFormContext context = BuildContext(rawData); @@ -535,4 +541,4 @@ namespace UI #endregion } -} +} \ No newline at end of file diff --git a/Assets/GameMain/Scripts/UI/GameScene/UseCase/ShopFormUseCase.cs b/Assets/GameMain/Scripts/UI/GameScene/UseCase/ShopFormUseCase.cs index b7f37d5..32d6ac8 100644 --- a/Assets/GameMain/Scripts/UI/GameScene/UseCase/ShopFormUseCase.cs +++ b/Assets/GameMain/Scripts/UI/GameScene/UseCase/ShopFormUseCase.cs @@ -397,6 +397,8 @@ namespace UI return new WeaponSlashData(entityId, ownerId, ownerCamp); case WeaponType.WeaponLightning: return new WeaponLightningData(entityId, ownerId, ownerCamp); + case WeaponType.WeaponLance: + return new WeaponLanceData(entityId, ownerId, ownerCamp); default: return null; } diff --git a/Assets/GameMain/Scripts/UI/GameScene/View/DisplayItemInfoForm.cs b/Assets/GameMain/Scripts/UI/GameScene/View/DisplayItemInfoForm.cs index 0e49b07..0b15368 100644 --- a/Assets/GameMain/Scripts/UI/GameScene/View/DisplayItemInfoForm.cs +++ b/Assets/GameMain/Scripts/UI/GameScene/View/DisplayItemInfoForm.cs @@ -199,7 +199,7 @@ namespace UI public void OnCancelButtonClick() { - GameEntry.Event.Fire(this, DisplayItemInfoHideEventArgs.Create()); + GameEntry.Event.Fire(this, DisplayItemInfoHideEventArgs.Create(true)); } } } diff --git a/Assets/GameMain/Scripts/Utility/ItemDescUtility.cs b/Assets/GameMain/Scripts/Utility/ItemDescUtility.cs index 313a308..35f582d 100644 --- a/Assets/GameMain/Scripts/Utility/ItemDescUtility.cs +++ b/Assets/GameMain/Scripts/Utility/ItemDescUtility.cs @@ -4,16 +4,23 @@ using DataTable; using Definition.DataStruct; using Entity.EntityData; using Entity.Weapon; +using System; using UnityGameFramework.Runtime; namespace CustomUtility { public static class ItemDescUtility { - private static readonly Dictionary _paramsDict = new() + private static readonly Dictionary _paramsDict = new(StringComparer.OrdinalIgnoreCase) { - {"hitradius", "伤害范围"}, - {"sectorangle", "攻击角度"} + {"hitRadius", "伤害范围"}, + {"sectorAngle", "攻击角度"}, + {"pierceLength", "前戳距离"}, + {"thrustDistance", "枪尖长度"}, + {"forwardOffset", "前置偏移"}, + {"rotateSpeed", "转向速度"}, + {"attackDuration", "突刺时长"}, + {"returnDuration", "收枪时长"} }; public static string CreatePropDescription(StatModifier[] modifiers) @@ -89,6 +96,11 @@ namespace CustomUtility sb.Append(modifiersDesc); } + if (@params == null || @params.Count == 0) + { + return sb.ToString(); + } + foreach (var kvp in @params) { if (!_paramsDict.TryGetValue(kvp.Key, out string value)) @@ -102,4 +114,4 @@ namespace CustomUtility return sb.ToString(); } } -} \ No newline at end of file +} diff --git a/Assets/Launcher.unity b/Assets/Launcher.unity index ebdc71f..d1fd2c2 100644 --- a/Assets/Launcher.unity +++ b/Assets/Launcher.unity @@ -731,7 +731,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 11499388, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3} propertyPath: m_EditorResourceMode - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 11499388, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3} propertyPath: m_JsonHelperTypeName diff --git a/数据表/Entity/Entity.xlsx b/数据表/Entity/Entity.xlsx index 6e9a339..12ab48e 100644 Binary files a/数据表/Entity/Entity.xlsx and b/数据表/Entity/Entity.xlsx differ diff --git a/数据表/Entity/Weapon.xlsx b/数据表/Entity/Weapon.xlsx index 15e9b26..e3c5955 100644 Binary files a/数据表/Entity/Weapon.xlsx and b/数据表/Entity/Weapon.xlsx differ diff --git a/数据表/Goods.xlsx b/数据表/Goods.xlsx index 1740ccc..ccdf210 100644 Binary files a/数据表/Goods.xlsx and b/数据表/Goods.xlsx differ