diff --git a/.codely/clipboard/clipboard-1789225137952.png b/.codely/clipboard/clipboard-1789225137952.png deleted file mode 100644 index 72d0491..0000000 Binary files a/.codely/clipboard/clipboard-1789225137952.png and /dev/null differ diff --git a/.codely/clipboard/clipboard-1789377053304.png b/.codely/clipboard/clipboard-1789377053304.png new file mode 100644 index 0000000..5b807c6 Binary files /dev/null and b/.codely/clipboard/clipboard-1789377053304.png differ diff --git a/Assets/Model/第一章/地图装饰物/城堡破损旗帜/城堡破损旗帜.png.meta b/Assets/Model/第一章/地图装饰物/城堡破损旗帜/城堡破损旗帜.png.meta index ad64da5..ec261c1 100644 --- a/Assets/Model/第一章/地图装饰物/城堡破损旗帜/城堡破损旗帜.png.meta +++ b/Assets/Model/第一章/地图装饰物/城堡破损旗帜/城堡破损旗帜.png.meta @@ -72,7 +72,7 @@ TextureImporter: platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 + maxTextureSize: 512 maxPlaceholderSize: 32 resizeAlgorithm: 0 textureFormat: -1 @@ -140,6 +140,20 @@ TextureImporter: ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: PlayableAds + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] diff --git a/Assets/Model/第一章/法师/法师.png.meta b/Assets/Model/第一章/法师/法师.png.meta index 7baf3c8..46ad663 100644 --- a/Assets/Model/第一章/法师/法师.png.meta +++ b/Assets/Model/第一章/法师/法师.png.meta @@ -72,7 +72,7 @@ TextureImporter: platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 + maxTextureSize: 512 maxPlaceholderSize: 32 resizeAlgorithm: 0 textureFormat: -1 @@ -140,6 +140,20 @@ TextureImporter: ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: PlayableAds + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] diff --git a/Assets/Model/第二章/弓箭猎人 1/texture_pbr_20250901.png.meta b/Assets/Model/第二章/弓箭猎人 1/texture_pbr_20250901.png.meta index 205ab19..cc24e3d 100644 --- a/Assets/Model/第二章/弓箭猎人 1/texture_pbr_20250901.png.meta +++ b/Assets/Model/第二章/弓箭猎人 1/texture_pbr_20250901.png.meta @@ -72,7 +72,7 @@ TextureImporter: platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 + maxTextureSize: 512 maxPlaceholderSize: 32 resizeAlgorithm: 0 textureFormat: -1 @@ -140,6 +140,20 @@ TextureImporter: ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: PlayableAds + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] diff --git a/Assets/Prefabs/第一章/人类士兵.prefab b/Assets/Prefabs/第一章/人类士兵.prefab index 7f5b2ed..66287d6 100644 --- a/Assets/Prefabs/第一章/人类士兵.prefab +++ b/Assets/Prefabs/第一章/人类士兵.prefab @@ -189,15 +189,15 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3} m_Name: m_EditorClassIdentifier: - speed: 3 + speed: 1.8 gravity: -20 range: 500 detectRange: 200 attackRange: 1 modelFacingOffset: 0 useRootMotion: 1 - attackPower: 28 - attackDuration: 1 + attackPower: 30 + attackDuration: 1.2 attackType: 0 projectilePrefab: {fileID: 0} projectileSpawnPoint: {fileID: 0} diff --git a/Assets/Prefabs/第一章/弓箭手.prefab b/Assets/Prefabs/第一章/弓箭手.prefab index 95a309b..41db9f2 100644 --- a/Assets/Prefabs/第一章/弓箭手.prefab +++ b/Assets/Prefabs/第一章/弓箭手.prefab @@ -206,15 +206,15 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3} m_Name: m_EditorClassIdentifier: - speed: 5 + speed: 1.8 gravity: -20 range: 500 detectRange: 200 attackRange: 6 modelFacingOffset: 90 useRootMotion: 0 - attackPower: 34 - attackDuration: 1.33 + attackPower: 40 + attackDuration: 1.5 attackType: 2 projectilePrefab: {fileID: 1754121762047325928, guid: e59aafedb502e65409f16e33cee0eed6, type: 3} diff --git a/Assets/Prefabs/第一章/法师.prefab b/Assets/Prefabs/第一章/法师.prefab index f5cd159..6602143 100644 --- a/Assets/Prefabs/第一章/法师.prefab +++ b/Assets/Prefabs/第一章/法师.prefab @@ -200,15 +200,15 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3} m_Name: m_EditorClassIdentifier: - speed: 3 + speed: 1.5 gravity: -20 range: 18 detectRange: 20 attackRange: 6 modelFacingOffset: 45 useRootMotion: 1 - attackPower: 42 - attackDuration: 1.82 + attackPower: 90 + attackDuration: 2.4 attackType: 2 projectilePrefab: {fileID: 3410584434205606752, guid: ea38dfd40c228456e8e1c98952673009, type: 3} diff --git a/Assets/Prefabs/第一章/盾卫.prefab b/Assets/Prefabs/第一章/盾卫.prefab index 9e71d47..e47037e 100644 --- a/Assets/Prefabs/第一章/盾卫.prefab +++ b/Assets/Prefabs/第一章/盾卫.prefab @@ -261,15 +261,15 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3} m_Name: m_EditorClassIdentifier: - speed: 2.5 + speed: 1.4 gravity: -20 range: 18 detectRange: 20 attackRange: 1.2 modelFacingOffset: 45 useRootMotion: 1 - attackPower: 24 - attackDuration: 1.54 + attackPower: 20 + attackDuration: 1.8 attackType: 0 projectilePrefab: {fileID: 0} projectileSpawnPoint: {fileID: 0} diff --git a/Assets/Prefabs/第一章/精锐士兵.prefab b/Assets/Prefabs/第一章/精锐士兵.prefab index cfc0529..878a6e7 100644 --- a/Assets/Prefabs/第一章/精锐士兵.prefab +++ b/Assets/Prefabs/第一章/精锐士兵.prefab @@ -135,7 +135,7 @@ PrefabInstance: - target: {fileID: 919132149155446097, guid: 62d9f853c067ff443bd2a3aa382ab563, type: 3} propertyPath: m_Name - value: "\u7CBE\u9510\u58EB\u5175\u65B0" + value: "\u7CBE\u9510\u58EB\u5175" objectReference: {fileID: 0} - target: {fileID: 919132149155446097, guid: 62d9f853c067ff443bd2a3aa382ab563, type: 3} @@ -255,8 +255,8 @@ MonoBehaviour: attackRange: 1.2 modelFacingOffset: 0 useRootMotion: 1 - attackPower: 68 - attackDuration: 2.22 + attackPower: 55 + attackDuration: 1.6 attackType: 0 projectilePrefab: {fileID: 0} projectileSpawnPoint: {fileID: 0} diff --git a/Assets/Prefabs/第二章/弓箭猎人.prefab b/Assets/Prefabs/第二章/弓箭猎人.prefab index 6d08944..92441ff 100644 --- a/Assets/Prefabs/第二章/弓箭猎人.prefab +++ b/Assets/Prefabs/第二章/弓箭猎人.prefab @@ -313,15 +313,15 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3} m_Name: m_EditorClassIdentifier: - speed: 5 + speed: 2.2 gravity: -20 range: 500 detectRange: 200 attackRange: 5 modelFacingOffset: 0 useRootMotion: 0 - attackPower: 12 - attackDuration: 0.8 + attackPower: 15 + attackDuration: 0.9 attackType: 2 projectilePrefab: {fileID: 1754121762047325928, guid: e59aafedb502e65409f16e33cee0eed6, type: 3} diff --git a/Assets/Prefabs/第二章/狼人.prefab b/Assets/Prefabs/第二章/狼人.prefab index 6401b5b..6a1b1ec 100644 --- a/Assets/Prefabs/第二章/狼人.prefab +++ b/Assets/Prefabs/第二章/狼人.prefab @@ -148,15 +148,15 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3} m_Name: m_EditorClassIdentifier: - speed: 4 + speed: 2.5 gravity: -20 range: 18 detectRange: 20 attackRange: 1.1 modelFacingOffset: 0 useRootMotion: 1 - attackPower: 38 - attackDuration: 0.95 + attackPower: 32 + attackDuration: 1 attackType: 0 projectilePrefab: {fileID: 0} projectileSpawnPoint: {fileID: 0} diff --git a/Assets/Prefabs/第二章/石巨人.prefab b/Assets/Prefabs/第二章/石巨人.prefab index e2b0e1f..325f3cf 100644 --- a/Assets/Prefabs/第二章/石巨人.prefab +++ b/Assets/Prefabs/第二章/石巨人.prefab @@ -132,15 +132,15 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3} m_Name: m_EditorClassIdentifier: - speed: 2.1 + speed: 1.1 gravity: -20 range: 500 detectRange: 200 attackRange: 1.1 modelFacingOffset: 90 useRootMotion: 1 - attackPower: 72 - attackDuration: 2.5 + attackPower: 110 + attackDuration: 2.8 attackType: 0 projectilePrefab: {fileID: 0} projectileSpawnPoint: {fileID: 0} diff --git a/Assets/Prefabs/第二章/蓝色怪物.prefab b/Assets/Prefabs/第二章/蓝色怪物.prefab index ee8306f..5005f6f 100644 --- a/Assets/Prefabs/第二章/蓝色怪物.prefab +++ b/Assets/Prefabs/第二章/蓝色怪物.prefab @@ -173,15 +173,15 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3} m_Name: m_EditorClassIdentifier: - speed: 2 + speed: 1.6 gravity: -20 range: 18 detectRange: 20 attackRange: 1 modelFacingOffset: 0 useRootMotion: 0 - attackPower: 20 - attackDuration: 1.8 + attackPower: 16 + attackDuration: 1.6 attackType: 0 projectilePrefab: {fileID: 0} projectileSpawnPoint: {fileID: 0} diff --git a/Assets/Resources/Data/人类士兵Data.asset b/Assets/Resources/Data/人类士兵Data.asset index 25f8026..c29a2f6 100644 --- a/Assets/Resources/Data/人类士兵Data.asset +++ b/Assets/Resources/Data/人类士兵Data.asset @@ -20,11 +20,11 @@ MonoBehaviour: type: 3} manaCost: 2 cooldownTime: 1 - productionInterval: 8 + productionInterval: 6 buildingCost: 100 - baseMaxHealth: 100 - baseAttackPower: 50 - baseMoveSpeed: 3 - healthPerLevel: 10 - attackPerLevel: 5 + baseMaxHealth: 300 + baseAttackPower: 30 + baseMoveSpeed: 1.8 + healthPerLevel: 30 + attackPerLevel: 3 moveSpeedPerLevel: 0 diff --git a/Assets/Resources/Data/弓箭手Data.asset b/Assets/Resources/Data/弓箭手Data.asset index 9c103f3..2c33d85 100644 --- a/Assets/Resources/Data/弓箭手Data.asset +++ b/Assets/Resources/Data/弓箭手Data.asset @@ -20,11 +20,11 @@ MonoBehaviour: type: 3} manaCost: 3 cooldownTime: 1 - productionInterval: 10 - buildingCost: 100 - baseMaxHealth: 80 - baseAttackPower: 60 - baseMoveSpeed: 3.5 - healthPerLevel: 8 - attackPerLevel: 6 + productionInterval: 8 + buildingCost: 120 + baseMaxHealth: 200 + baseAttackPower: 40 + baseMoveSpeed: 1.8 + healthPerLevel: 20 + attackPerLevel: 3 moveSpeedPerLevel: 0 diff --git a/Assets/Resources/Data/弓箭猎人Data.asset b/Assets/Resources/Data/弓箭猎人Data.asset index 8673b18..efa1cd9 100644 --- a/Assets/Resources/Data/弓箭猎人Data.asset +++ b/Assets/Resources/Data/弓箭猎人Data.asset @@ -19,9 +19,11 @@ MonoBehaviour: unitPrefab: {fileID: 0} manaCost: 3 cooldownTime: 1 - baseMaxHealth: 145 - baseAttackPower: 36 - baseMoveSpeed: 3.5 - healthPerLevel: 7.25 - attackPerLevel: 1.8 + productionInterval: 8 + buildingCost: 120 + baseMaxHealth: 200 + baseAttackPower: 15 + baseMoveSpeed: 2.2 + healthPerLevel: 20 + attackPerLevel: 1 moveSpeedPerLevel: 0 diff --git a/Assets/Resources/Data/法师Data.asset b/Assets/Resources/Data/法师Data.asset index 41d2f12..b4f05e7 100644 --- a/Assets/Resources/Data/法师Data.asset +++ b/Assets/Resources/Data/法师Data.asset @@ -21,10 +21,10 @@ MonoBehaviour: manaCost: 6 cooldownTime: 1 productionInterval: 12 - buildingCost: 100 - baseMaxHealth: 70 - baseAttackPower: 100 - baseMoveSpeed: 3 - healthPerLevel: 7 - attackPerLevel: 10 + buildingCost: 150 + baseMaxHealth: 160 + baseAttackPower: 90 + baseMoveSpeed: 1.5 + healthPerLevel: 16 + attackPerLevel: 7 moveSpeedPerLevel: 0 diff --git a/Assets/Resources/Data/狂暴狼人Data.asset b/Assets/Resources/Data/狂暴狼人Data.asset index 7451154..7a561af 100644 --- a/Assets/Resources/Data/狂暴狼人Data.asset +++ b/Assets/Resources/Data/狂暴狼人Data.asset @@ -19,9 +19,11 @@ MonoBehaviour: unitPrefab: {fileID: 0} manaCost: 4 cooldownTime: 1 - baseMaxHealth: 360 - baseAttackPower: 38 - baseMoveSpeed: 3.8 - healthPerLevel: 18 - attackPerLevel: 1.9 + productionInterval: 10 + buildingCost: 150 + baseMaxHealth: 380 + baseAttackPower: 32 + baseMoveSpeed: 2.5 + healthPerLevel: 38 + attackPerLevel: 3 moveSpeedPerLevel: 0 diff --git a/Assets/Resources/Data/盾卫Data.asset b/Assets/Resources/Data/盾卫Data.asset index be830d4..1c456b5 100644 --- a/Assets/Resources/Data/盾卫Data.asset +++ b/Assets/Resources/Data/盾卫Data.asset @@ -20,9 +20,11 @@ MonoBehaviour: type: 3} manaCost: 4 cooldownTime: 1 - baseMaxHealth: 150 - baseAttackPower: 40 - baseMoveSpeed: 2.5 - healthPerLevel: 15 - attackPerLevel: 4 + productionInterval: 10 + buildingCost: 150 + baseMaxHealth: 900 + baseAttackPower: 20 + baseMoveSpeed: 1.4 + healthPerLevel: 90 + attackPerLevel: 2 moveSpeedPerLevel: 0 diff --git a/Assets/Resources/Data/石巨人Data.asset b/Assets/Resources/Data/石巨人Data.asset index e3e9d66..c75c445 100644 --- a/Assets/Resources/Data/石巨人Data.asset +++ b/Assets/Resources/Data/石巨人Data.asset @@ -19,9 +19,11 @@ MonoBehaviour: unitPrefab: {fileID: 0} manaCost: 7 cooldownTime: 1 - baseMaxHealth: 820 - baseAttackPower: 72 - baseMoveSpeed: 2.5 - healthPerLevel: 41 - attackPerLevel: 3.6 + productionInterval: 20 + buildingCost: 250 + baseMaxHealth: 1400 + baseAttackPower: 110 + baseMoveSpeed: 1.1 + healthPerLevel: 140 + attackPerLevel: 9 moveSpeedPerLevel: 0 diff --git a/Assets/Resources/Data/精锐士兵Data.asset b/Assets/Resources/Data/精锐士兵Data.asset index 0a998ec..da55c0a 100644 --- a/Assets/Resources/Data/精锐士兵Data.asset +++ b/Assets/Resources/Data/精锐士兵Data.asset @@ -20,9 +20,11 @@ MonoBehaviour: type: 3} manaCost: 5 cooldownTime: 1 - baseMaxHealth: 120 - baseAttackPower: 80 - baseMoveSpeed: 3.5 - healthPerLevel: 12 - attackPerLevel: 8 + productionInterval: 12 + buildingCost: 180 + baseMaxHealth: 420 + baseAttackPower: 55 + baseMoveSpeed: 2 + healthPerLevel: 42 + attackPerLevel: 4 moveSpeedPerLevel: 0 diff --git a/Assets/Resources/Data/蓝色怪物Data.asset b/Assets/Resources/Data/蓝色怪物Data.asset index 5762b9c..a5152cb 100644 --- a/Assets/Resources/Data/蓝色怪物Data.asset +++ b/Assets/Resources/Data/蓝色怪物Data.asset @@ -19,9 +19,11 @@ MonoBehaviour: unitPrefab: {fileID: 0} manaCost: 1 cooldownTime: 1 - baseMaxHealth: 170 - baseAttackPower: 22 - baseMoveSpeed: 4 - healthPerLevel: 8.5 - attackPerLevel: 1.1 + productionInterval: 5 + buildingCost: 80 + baseMaxHealth: 340 + baseAttackPower: 16 + baseMoveSpeed: 1.6 + healthPerLevel: 34 + attackPerLevel: 1 moveSpeedPerLevel: 0 diff --git a/Assets/Script/MainCharacterCombat.cs b/Assets/Script/MainCharacterCombat.cs index e83d958..0eb423b 100644 --- a/Assets/Script/MainCharacterCombat.cs +++ b/Assets/Script/MainCharacterCombat.cs @@ -7,6 +7,9 @@ public class MainCharacterCombat : MonoBehaviour [Min(0f)] public float attackRange = 8f; + [Min(0f)] + public float detectRange = 10f; + [Min(0f)] public float attackPower = 50f; @@ -86,13 +89,39 @@ public class MainCharacterCombat : MonoBehaviour return; } - if (movement == null || movement.IsMoving || animator == null) + if (animator == null) { return; } + // 巡逻中也能发现敌人;发现后停止巡逻,没有敌人则恢复巡逻 target = FindNearestEnemy(); - if (target == null || attackCooldown > 0f) + if (target == null) + { + if (movement != null) + { + movement.ClearChaseTarget(); + movement.SetPatrolEnabled(true); + } + return; + } + + if (movement != null) + { + movement.SetPatrolEnabled(false); + + // 寻敌范围内但超出攻击范围:主动走近敌人再攻击(受基地栓绳限制) + float targetDistance = GetHorizontalDistance(target.transform.position); + if (targetDistance > attackRange) + { + movement.SetChaseTarget(target.transform.position); + return; + } + + movement.ClearChaseTarget(); + } + + if (attackCooldown > 0f) { return; } @@ -165,7 +194,7 @@ public class MainCharacterCombat : MonoBehaviour if (movement != null) { - movement.StopMovement(); + movement.SetPatrolEnabled(false); } if (attacking) @@ -334,8 +363,7 @@ public class MainCharacterCombat : MonoBehaviour private bool IsInsideMovementBounds(Vector3 position) { - return movement == null || (position.x >= movement.xLimits.x && position.x <= movement.xLimits.y - && position.z >= movement.zLimits.x && position.z <= movement.zLimits.y); + return movement == null || movement.IsWithinLeash(position); } private void CheckSummonFinished() @@ -466,10 +494,18 @@ public class MainCharacterCombat : MonoBehaviour animator.SetInteger("speed", 0); } + private float GetHorizontalDistance(Vector3 position) + { + Vector3 offset = position - transform.position; + offset.y = 0f; + return offset.magnitude; + } + private GameObject FindNearestEnemy() { + // 索敌范围使用较小的 detectRange,主角不主动远离基地寻找敌人 GameObject nearest = null; - float nearestDistance = attackRange * attackRange; + float nearestDistance = detectRange * detectRange; foreach (GameObject enemy in GameObject.FindGameObjectsWithTag("Enemy")) { diff --git a/Assets/Script/MainCharacterDebugMovement.cs b/Assets/Script/MainCharacterDebugMovement.cs index 6680b18..ab64c09 100644 --- a/Assets/Script/MainCharacterDebugMovement.cs +++ b/Assets/Script/MainCharacterDebugMovement.cs @@ -1,49 +1,91 @@ using UnityEngine; -using UnityEngine.EventSystems; +/// +/// 主角自动巡逻移动:不再支持点击地面移动(避免与拖动屏幕、建筑放置的输入冲突)。 +/// 没有敌人时在己方主建筑周围小范围来回走动,所有移动被限制在基地附近(栓绳范围)。 +/// 战斗组件发现敌人后调用 SetPatrolEnabled(false) 停止巡逻进行攻击。 +/// public class MainCharacterDebugMovement : MonoBehaviour { - [Header("电脑调试移动")] + [Header("巡逻移动")] [Min(0f)] public float moveSpeed = 4f; [Min(0f)] - public float clickStopDistance = 0.08f; + public float patrolStopDistance = 0.15f; - [Header("移动范围")] - public bool limitToBattlePlatform = true; - public Vector2 xLimits = new Vector2(-7.5f, 7.5f); - public Vector2 zLimits = new Vector2(-14f, 14f); + [Min(0f)] + public float patrolPause = 1.5f; + + [Header("巡逻区域(以主建筑为锚点)")] + [Min(0f)] + public float patrolRadius = 5f; + + [Min(0f)] + public float leashRadius = 8f; + + public string friendlyBuildingTag = "Friend"; private Animator animator; - private Vector3 clickTarget; - private bool hasClickTarget; + private Transform baseAnchor; + private Vector3 fallbackAnchor; + private Vector3 patrolTarget; + private Vector3 chaseTarget; + private bool hasPatrolTarget; + private bool hasChaseTarget; + private float pauseTimer; + private bool patrolEnabled = true; - public bool IsMoving => hasClickTarget; + public bool IsMoving { get; private set; } + + private Vector3 AnchorPosition + { + get + { + Vector3 position = baseAnchor != null ? baseAnchor.position : fallbackAnchor; + position.y = transform.position.y; + return position; + } + } private void Start() { animator = GetComponent(); - clickTarget = transform.position; + fallbackAnchor = transform.position; + baseAnchor = FindMainBase(); SetWalking(false); } private void Update() { - HandleClickTarget(); - - if (!hasClickTarget) + if (!patrolEnabled) { + UpdateChase(); + return; + } + + if (pauseTimer > 0f) + { + pauseTimer -= Time.deltaTime; + IsMoving = false; SetWalking(false); return; } - Vector3 toTarget = clickTarget - transform.position; + if (!hasPatrolTarget) + { + patrolTarget = GetNextPatrolPoint(); + hasPatrolTarget = true; + } + + Vector3 toTarget = patrolTarget - transform.position; toTarget.y = 0f; - if (toTarget.magnitude <= clickStopDistance) + if (toTarget.magnitude <= patrolStopDistance) { - hasClickTarget = false; + hasPatrolTarget = false; + pauseTimer = patrolPause; + IsMoving = false; SetWalking(false); return; } @@ -51,32 +93,122 @@ public class MainCharacterDebugMovement : MonoBehaviour Move(toTarget.normalized); } - private void HandleClickTarget() + private void UpdateChase() { - if (!Input.GetMouseButtonDown(0) || Camera.main == null) + if (!hasChaseTarget) + { + IsMoving = false; + SetWalking(false); + return; + } + + Vector3 toTarget = chaseTarget - transform.position; + toTarget.y = 0f; + + if (toTarget.magnitude <= patrolStopDistance) + { + IsMoving = false; + SetWalking(false); + return; + } + + // 追击同样受栓绳限制,不会完全离开基地 + Move(toTarget.normalized); + } + + private Transform FindMainBase() + { + Transform firstBuilding = null; + foreach (GameObject candidate in GameObject.FindGameObjectsWithTag(friendlyBuildingTag)) + { + if (candidate == null || candidate.transform.root == transform.root) + { + continue; + } + + if (candidate.GetComponentInParent() == null) + { + continue; + } + + // 主建筑按名称优先匹配;找不到时退回第一个己方建筑 + if (candidate.name.Contains("主要") || candidate.name.Contains("基地")) + { + return candidate.transform; + } + + if (firstBuilding == null) + { + firstBuilding = candidate.transform; + } + } + + return firstBuilding; + } + + private Vector3 GetNextPatrolPoint() + { + Vector2 offset = Random.insideUnitCircle * patrolRadius; + return ClampToLeash(AnchorPosition + new Vector3(offset.x, 0f, offset.y)); + } + + private Vector3 ClampToLeash(Vector3 position) + { + Vector3 offset = position - AnchorPosition; + offset.y = 0f; + if (offset.magnitude > leashRadius) + { + offset = offset.normalized * leashRadius; + } + + return AnchorPosition + offset; + } + + public bool IsWithinLeash(Vector3 position) + { + Vector3 offset = position - AnchorPosition; + offset.y = 0f; + return offset.magnitude <= leashRadius; + } + + public void SetPatrolEnabled(bool enabled) + { + if (patrolEnabled == enabled) { return; } - if (EventSystem.current != null && EventSystem.current.IsPointerOverGameObject()) + patrolEnabled = enabled; + if (!enabled) { - return; + hasPatrolTarget = false; + pauseTimer = 0f; + IsMoving = false; + SetWalking(false); } - - Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); - if (!Physics.Raycast(ray, out RaycastHit hit)) + else { - return; + hasChaseTarget = false; } + } - clickTarget = hit.point; - clickTarget.y = transform.position.y; - hasClickTarget = true; + public void SetChaseTarget(Vector3 position) + { + chaseTarget = position; + chaseTarget.y = transform.position.y; + hasChaseTarget = true; + } + + public void ClearChaseTarget() + { + hasChaseTarget = false; } public void StopMovement() { - hasClickTarget = false; + hasPatrolTarget = false; + hasChaseTarget = false; + IsMoving = false; SetWalking(false); } @@ -85,19 +217,19 @@ public class MainCharacterDebugMovement : MonoBehaviour direction.y = 0f; if (direction.sqrMagnitude <= 0.001f) { + IsMoving = false; SetWalking(false); return; } + IsMoving = true; SetWalking(true); transform.position += direction * moveSpeed * Time.deltaTime; - if (limitToBattlePlatform) - { - Vector3 position = transform.position; - position.x = Mathf.Clamp(position.x, xLimits.x, xLimits.y); - position.z = Mathf.Clamp(position.z, zLimits.x, zLimits.y); - transform.position = position; - } + + // 栓绳:任何情况下都不能完全离开基地 + Vector3 clamped = ClampToLeash(transform.position); + clamped.y = transform.position.y; + transform.position = clamped; transform.rotation = Quaternion.LookRotation(direction, Vector3.up); } @@ -109,4 +241,4 @@ public class MainCharacterDebugMovement : MonoBehaviour animator.SetInteger("speed", walking ? 1 : 0); } } -} \ No newline at end of file +} diff --git a/CODELY.md b/CODELY.md index c595116..097cc02 100644 --- a/CODELY.md +++ b/CODELY.md @@ -20,6 +20,7 @@ - [2026-09-09 13:43:50] 能量恢复速度应该更慢一些,用户建议改为 3 秒恢复 1 格。**Why:** 1 秒 1 格太快,不利于战斗节奏控制。**How to apply:** 召唤系统能量恢复速率应偏慢,给玩家资源压力。 - [2026-09-09 20:37:24] 用户希望提前实现数据架构而非临时方案,即使当前阶段功能简单。**Why:** 用户有 10 年后端开发经验,理解数据分层的重要性,希望逐步完善而非推倒重来。**How to apply:** 对于有明确扩展方向的功能(升级、存档、联网),优先设计可扩展架构并临时写死数据,而非等需求明确后再重构。 - [2026-09-10 18:38:45] 正交俯视视角(38-43°)下,垂直墙面几乎看不见(只能看到墙顶),因为墙面平行于视线方向被自身遮挡。适合的装饰物:高耸物体(旗帜、石柱)、有明显剪影的物体(木箱、碎石堆)、对比色强的物体;不适合:低矮平面物(矮墙、栅栏)、细长水平物(绳索)。**Why:** 这是正交俯视视角的固有盲区,无法通过调整角度完全解决(角度太平会牺牲战场全局视野)。**How to apply:** 场景装饰设计时优先使用垂直高度≥2米的物体,避免依赖水平或低矮结构。 +- [2026-09-14 18:24:56] 用户认可"参考游戏是基地离得远、镜头更远、单位推进慢"的观感方向(2026-09-14 数值改慢后反馈"好多了")。**Why:** 之前双方距离近+移速快,单位两三秒就接触,战斗缺乏观察窗口。**How to apply:** 后续地图/镜头调整优先加长双方距离、拉远摄像机;数值宁慢勿快。 ### Project - [2026-08-28 14:26:56] 弓箭手远程箭矢的设计要求:保持发射时高度水平飞行,命中目标后直接结算伤害并销毁,不产生实体物理击退。**Why:** 当前玩法希望远程攻击是命中判定而非物理推动。**How to apply:** 后续调整箭矢、Projectile 或弓箭手攻击逻辑时保持这一行为。 @@ -41,6 +42,8 @@ - [2026-09-10 18:38:13] 第一关地图(Level1-1.scene)已采用"皇室战争"风格简化设计:移除所有边界矮墙(俯视角只能看到墙顶),改用旗帜+石柱交替排列标识边界(X=±5.5,Z轴8个位置交替);保留中间战道掩体(木箱×6、碎石堆×4);天空改为纯色蓝灰色+线性雾效(起始40m,结束100m);摄像机添加边界Clamp限制(X: -7~7, Z: -32~93,宽松模式),主角靠近边界时摄像机停止跟随;光照调整为从后上方照射(50°, 0°, 0°),角色正面清晰可见。**Why:** 正交俯视视角下垂直墙面几乎看不见(只能看到墙顶),旗帜+石柱有高度和轮廓,视觉识别强。**How to apply:** 后续关卡延续此风格,避免使用低矮平面装饰物。 - [2026-09-10 18:38:32] 召唤逻辑已优化碰撞处理:当目标位置被占用时,自动螺旋搜索周围空位(左右搜索8次×前后3层×2方向,约102个候选点);如果所有位置都被占用,自动退还能量豆并取消召唤,避免浪费能量。参数:summonSearchCount=8, summonDepthSearchCount=3, summonSearchStep=0.8f, summonDepthSearchStep=1f。 - [2026-09-11 14:55:27] 敌人血条颜色问题已修复:WorldHealthBar 在 Awake() 时根据 GameObject.tag 判断颜色,WaveSpawner 在 Instantiate() 后设置标签会导致时序错误(血条已创建成绿色)。解决方案:直接在敌人 Prefab 上设置 Enemy 标签,确保 Awake() 时标签已正确。已修改狼人/蓝色怪物/弓箭猎人/石巨人四个 Prefab。**Why:** 血条颜色在对象创建时确定,后设置标签无法自动刷新。**How to apply:** 后续新增敌人 Prefab 时直接在 Prefab 上设置 Enemy 标签,不依赖运行时代码设置。 +- [2026-09-14 16:00:19] 2026-09-13 玩法大转向:从闯关推图改为"建筑生产+自动作战+主角辅助"的对攻玩法(见《召唤之战-核心玩法.md》)。旧闯关玩法由用户在另一台电脑的分支保存,当前 main 按新玩法开发。提交 beab4cf 已实现:GoldSystem/GoldMine 金币经济、Barracks 兵营产兵、BuildingPlacementManager 建筑摆放、CharacterData 新增 productionInterval/buildingCost、UnitBase/Projectile 支持攻击建筑、CoreBattleTest.scene 验证场景、CameraFollow 重写(WASD/鼠标/触摸拖动+缩放)。胜负目标改为摧毁对方主建筑。**How to apply:** 后续开发以建筑/经济/产兵系统为主线,能量豆召唤相关旧逻辑仅作为历史参考。 +- [2026-09-14 18:24:46] 2026-09-14 性能实测(9 个角色 Prefab):大多数 5~8k 三角面/22 骨骼/512 贴图,性能没问题;两个待处理异常——蓝色怪物 34408 面(是量产低价单位,建议减面到 8k 左右)、法师贴图 2048x2048(建议缩到 512)。另建议设计层限制每方场上单位上限(约15)保性能与 2.5D 可读性,并确认方向光关实时阴影,最终以低端安卓真机小游戏包为准。**How to apply:** 后续做性能优化或新增量产型敌人时按此基准控制面数。 ### Reference - [2026-09-09 12:23:17] 飞行物脚本 Projectile.cs 负责锁敌追踪、碰撞检测和伤害结算。箭矢预制体 ArrowProjectile_White.prefab 已配置 Projectile 组件和 CapsuleCollider(Is Trigger)。远程单位需在攻击动画松弦帧添加 OnAttackEffect Event,并在 UnitBase 中设置 attackType=RangedProjectile、projectilePrefab、projectileSpawnPoint。 diff --git a/召唤之战-核心玩法.md b/召唤之战-核心玩法.md index b5e51df..91eea9a 100644 --- a/召唤之战-核心玩法.md +++ b/召唤之战-核心玩法.md @@ -50,9 +50,11 @@ ### 3.1 主角职责 - 主角可以普通攻击; -- 主角可以由玩家手动移动; -- 玩家没有主动操作时,主角自动巡逻并攻击附近敌人; -- 主角可以手动释放技能; +- 主角全程由 AI 自动控制,不支持点击地面手动移动(避免与拖动屏幕、建筑放置的输入冲突); +- 没有敌人时,主角在己方主建筑周围小范围来回巡逻; +- 索敌范围较小:只有敌人进入主角附近一定范围内才会被发现并攻击,不主动远离基地寻找敌人; +- 巡逻和追击都被限制在基地附近区域,主角不能完全离开基地; +- 主角可以手动释放技能(通过 UI 技能按钮,不占用地面点击操作); - 主角技能冷却较长,主要用于辅助、补刀和改变局部战况; - 主角不是主要战斗力,不能替代建筑生产的军队; - 主角的价值是提升玩家参与感,并在关键时刻提供战术干预。 diff --git a/角色数值设计.md b/角色数值设计.md new file mode 100644 index 0000000..c0aabe1 --- /dev/null +++ b/角色数值设计.md @@ -0,0 +1,91 @@ +# 角色数值设计 + +> 当前版本:第一版数值基准(配合建筑对攻玩法) +> +> 数值目标:放慢战斗节奏、拉长存活时间,让"建造时机"和"兵种组合"有观察和反应的窗口。 + +## 一、设计基准 + +以**人类士兵**为锚点单位(DPS = 25),确定全表数值关系: + +| 目标 | 数值 | +|---|---| +| 基础近战互杀时间 | 12~15 秒 | +| 脆皮远程被近战击杀 | 6~9 秒 | +| 坦克(盾卫)承受基础近战输出 | 35 秒以上 | +| 超重坦克(石巨人)承受基础近战输出 | 55 秒以上 | +| 单位穿越中场距离(约 25~30 单位) | 12~17 秒 | + +衍生规则: + +- 攻击力 = 单次伤害;DPS = 攻击力 ÷ 普攻间隔; +- 越贵的单位 DPS/生存越强,但必须有明显短板(速度、攻速或费用); +- 远程单位攻击范围 5~6,近战 1.0~1.2; +- 移动速度整体压在 1.1~2.5,宁可慢不可快(快了会放大两边距离近的问题)。 + +## 二、基础属性表(1 级) + +| 角色 | 定位 | 生命 | 攻击力 | 普攻间隔(秒/次) | DPS | 攻击范围 | 移动速度 | +|---|---|---|---|---|---|---|---| +| 人类士兵 | 基础近战 | 300 | 30 | 1.2 | 25 | 1.0 | 1.8 | +| 盾卫 | 重装坦克 | 900 | 20 | 1.8 | 11 | 1.2 | 1.4 | +| 弓箭手 | 远程输出 | 200 | 40 | 1.5 | 27 | 6.0 | 1.8 | +| 法师 | 远程爆发 | 160 | 90 | 2.4 | 38 | 6.0 | 1.5 | +| 精锐士兵 | 近战强袭 | 420 | 55 | 1.6 | 34 | 1.2 | 2.0 | +| 弓箭猎人 | 持续远程 | 200 | 15 | 0.9 | 17 | 5.0 | 2.2 | +| 狂暴狼人 | 快速突袭 | 380 | 32 | 1.0 | 32 | 1.1 | 2.5 | +| 蓝色怪物 | 低价肉盾 | 340 | 16 | 1.6 | 10 | 1.0 | 1.6 | +| 石巨人 | 超重坦克 | 1400 | 110 | 2.8 | 39 | 1.1 | 1.1 | + +注:Prefab 实际有 9 个角色(第一章 5 个 + 第二章 4 个),全部列出,未上场的可先不用。 + +## 三、兵营生产与费用 + +| 角色 | 生产间隔(秒/个) | 建造费用(金币) | +|---|---|---| +| 人类士兵 | 6 | 100 | +| 蓝色怪物 | 5 | 80 | +| 弓箭手 | 8 | 120 | +| 弓箭猎人 | 8 | 120 | +| 盾卫 | 10 | 150 | +| 狂暴狼人 | 10 | 150 | +| 法师 | 12 | 150 | +| 精锐士兵 | 12 | 180 | +| 石巨人 | 20 | 250 | + +经济节奏参考:金矿产出速率定稿后,按"一座金矿约支撑 1.5 个中级兵营持续运转"回推。 + +## 四、击杀时间参考(以人类士兵 DPS 25 进攻) + +| 目标 | 击杀时间 | +|---|---| +| 法师(160) | 6.4 秒 | +| 弓箭手 / 弓箭猎人(200) | 8 秒 | +| 人类士兵(300) | 12 秒 | +| 蓝色怪物(340) | 13.6 秒 | +| 狂暴狼人(380) | 15.2 秒 | +| 精锐士兵(420) | 16.8 秒 | +| 盾卫(900) | 36 秒 | +| 石巨人(1400) | 56 秒 | + +## 五、升级成长建议 + +- 生命成长:每级约基础值的 10%(如人类士兵 +30/级); +- 攻击成长:每级约基础值的 8%(如人类士兵 +2.5/级,取整 +3); +- 移动速度:不随等级成长; +- 关键等级节点(10/20/30 级)再考虑技能强化,不体现在基础数值里。 + +## 六、数值落地位置(改数值看这里) + +| 数值 | 所在文件 | +|---|---| +| 生命 / 攻击力 / 移动速度 / 生产间隔 / 建造费用 | `Assets/Resources/Data/<角色名>Data.asset`(CharacterData) | +| 普攻间隔(attackDuration)/ 攻击范围(attackRange)/ 攻击类型 | `Assets/Prefabs/第N章/<角色名>.prefab`(UnitBase 组件) | +| 兵营生产逻辑 | `Barracks.cs`(按 1 级属性初始化单位) | + +修改任一角色时,本表同步更新。 + +## 七、遗留调整项(数值之外) + +- 当前 CoreBattleTest 地图双方距离仍偏近、镜头偏近,参考游戏是"基地远离 + 镜头更远"的观感;数值放缓后如果仍显拥挤,优先做地图加长和摄像机 bounds 扩大,而不是继续压低移速; +- 主角(召唤师)数值不在本表内,主角定位是辅助,等装备系统定型后单独设计。