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 扩大,而不是继续压低移速;
+- 主角(召唤师)数值不在本表内,主角定位是辅助,等装备系统定型后单独设计。