```
feat(gameplay): 调整单位属性和纹理设置并优化主角移动系统 - 修改多个纹理资源的最大尺寸从2048降至512,并添加PlayableAds平台设置 - 调整第一、二章多个单位的移动速度、攻击力和攻击持续时间参数 - 重命名精锐士兵预制体名称,移除"新"字后缀 - 降低精锐士兵的攻击力和攻击持续时间 - 为主角战斗组件添加detectRange字段,实现寻敌和攻击范围分离 - 重构主角移动系统,从点击移动改为自动巡逻模式,增加栓绳机制防止远离基地 - 实现巡逻和追击状态切换,在发现敌人时停止巡逻进行攻击 -
This commit is contained in:
1 parent
769aea30f3
commit
8d43961f67
28 files changed
+443
-125
No files matched your search
Binary file not shown.
|
Before Width: | Height: | Size: 2.6 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.6 MiB |
@@ -72,7 +72,7 @@ TextureImporter:
|
|||||||
platformSettings:
|
platformSettings:
|
||||||
- serializedVersion: 3
|
- serializedVersion: 3
|
||||||
buildTarget: DefaultTexturePlatform
|
buildTarget: DefaultTexturePlatform
|
||||||
maxTextureSize: 2048
|
maxTextureSize: 512
|
||||||
maxPlaceholderSize: 32
|
maxPlaceholderSize: 32
|
||||||
resizeAlgorithm: 0
|
resizeAlgorithm: 0
|
||||||
textureFormat: -1
|
textureFormat: -1
|
||||||
@@ -140,6 +140,20 @@ TextureImporter:
|
|||||||
ignorePlatformSupport: 0
|
ignorePlatformSupport: 0
|
||||||
androidETC2FallbackOverride: 0
|
androidETC2FallbackOverride: 0
|
||||||
forceMaximumCompressionQuality_BC6H_BC7: 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:
|
spriteSheet:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
sprites: []
|
sprites: []
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ TextureImporter:
|
|||||||
platformSettings:
|
platformSettings:
|
||||||
- serializedVersion: 3
|
- serializedVersion: 3
|
||||||
buildTarget: DefaultTexturePlatform
|
buildTarget: DefaultTexturePlatform
|
||||||
maxTextureSize: 2048
|
maxTextureSize: 512
|
||||||
maxPlaceholderSize: 32
|
maxPlaceholderSize: 32
|
||||||
resizeAlgorithm: 0
|
resizeAlgorithm: 0
|
||||||
textureFormat: -1
|
textureFormat: -1
|
||||||
@@ -140,6 +140,20 @@ TextureImporter:
|
|||||||
ignorePlatformSupport: 0
|
ignorePlatformSupport: 0
|
||||||
androidETC2FallbackOverride: 0
|
androidETC2FallbackOverride: 0
|
||||||
forceMaximumCompressionQuality_BC6H_BC7: 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:
|
spriteSheet:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
sprites: []
|
sprites: []
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ TextureImporter:
|
|||||||
platformSettings:
|
platformSettings:
|
||||||
- serializedVersion: 3
|
- serializedVersion: 3
|
||||||
buildTarget: DefaultTexturePlatform
|
buildTarget: DefaultTexturePlatform
|
||||||
maxTextureSize: 2048
|
maxTextureSize: 512
|
||||||
maxPlaceholderSize: 32
|
maxPlaceholderSize: 32
|
||||||
resizeAlgorithm: 0
|
resizeAlgorithm: 0
|
||||||
textureFormat: -1
|
textureFormat: -1
|
||||||
@@ -140,6 +140,20 @@ TextureImporter:
|
|||||||
ignorePlatformSupport: 0
|
ignorePlatformSupport: 0
|
||||||
androidETC2FallbackOverride: 0
|
androidETC2FallbackOverride: 0
|
||||||
forceMaximumCompressionQuality_BC6H_BC7: 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:
|
spriteSheet:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
sprites: []
|
sprites: []
|
||||||
|
|||||||
@@ -189,15 +189,15 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3}
|
m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
speed: 3
|
speed: 1.8
|
||||||
gravity: -20
|
gravity: -20
|
||||||
range: 500
|
range: 500
|
||||||
detectRange: 200
|
detectRange: 200
|
||||||
attackRange: 1
|
attackRange: 1
|
||||||
modelFacingOffset: 0
|
modelFacingOffset: 0
|
||||||
useRootMotion: 1
|
useRootMotion: 1
|
||||||
attackPower: 28
|
attackPower: 30
|
||||||
attackDuration: 1
|
attackDuration: 1.2
|
||||||
attackType: 0
|
attackType: 0
|
||||||
projectilePrefab: {fileID: 0}
|
projectilePrefab: {fileID: 0}
|
||||||
projectileSpawnPoint: {fileID: 0}
|
projectileSpawnPoint: {fileID: 0}
|
||||||
|
|||||||
@@ -206,15 +206,15 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3}
|
m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
speed: 5
|
speed: 1.8
|
||||||
gravity: -20
|
gravity: -20
|
||||||
range: 500
|
range: 500
|
||||||
detectRange: 200
|
detectRange: 200
|
||||||
attackRange: 6
|
attackRange: 6
|
||||||
modelFacingOffset: 90
|
modelFacingOffset: 90
|
||||||
useRootMotion: 0
|
useRootMotion: 0
|
||||||
attackPower: 34
|
attackPower: 40
|
||||||
attackDuration: 1.33
|
attackDuration: 1.5
|
||||||
attackType: 2
|
attackType: 2
|
||||||
projectilePrefab: {fileID: 1754121762047325928, guid: e59aafedb502e65409f16e33cee0eed6,
|
projectilePrefab: {fileID: 1754121762047325928, guid: e59aafedb502e65409f16e33cee0eed6,
|
||||||
type: 3}
|
type: 3}
|
||||||
|
|||||||
@@ -200,15 +200,15 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3}
|
m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
speed: 3
|
speed: 1.5
|
||||||
gravity: -20
|
gravity: -20
|
||||||
range: 18
|
range: 18
|
||||||
detectRange: 20
|
detectRange: 20
|
||||||
attackRange: 6
|
attackRange: 6
|
||||||
modelFacingOffset: 45
|
modelFacingOffset: 45
|
||||||
useRootMotion: 1
|
useRootMotion: 1
|
||||||
attackPower: 42
|
attackPower: 90
|
||||||
attackDuration: 1.82
|
attackDuration: 2.4
|
||||||
attackType: 2
|
attackType: 2
|
||||||
projectilePrefab: {fileID: 3410584434205606752, guid: ea38dfd40c228456e8e1c98952673009,
|
projectilePrefab: {fileID: 3410584434205606752, guid: ea38dfd40c228456e8e1c98952673009,
|
||||||
type: 3}
|
type: 3}
|
||||||
|
|||||||
@@ -261,15 +261,15 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3}
|
m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
speed: 2.5
|
speed: 1.4
|
||||||
gravity: -20
|
gravity: -20
|
||||||
range: 18
|
range: 18
|
||||||
detectRange: 20
|
detectRange: 20
|
||||||
attackRange: 1.2
|
attackRange: 1.2
|
||||||
modelFacingOffset: 45
|
modelFacingOffset: 45
|
||||||
useRootMotion: 1
|
useRootMotion: 1
|
||||||
attackPower: 24
|
attackPower: 20
|
||||||
attackDuration: 1.54
|
attackDuration: 1.8
|
||||||
attackType: 0
|
attackType: 0
|
||||||
projectilePrefab: {fileID: 0}
|
projectilePrefab: {fileID: 0}
|
||||||
projectileSpawnPoint: {fileID: 0}
|
projectileSpawnPoint: {fileID: 0}
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ PrefabInstance:
|
|||||||
- target: {fileID: 919132149155446097, guid: 62d9f853c067ff443bd2a3aa382ab563,
|
- target: {fileID: 919132149155446097, guid: 62d9f853c067ff443bd2a3aa382ab563,
|
||||||
type: 3}
|
type: 3}
|
||||||
propertyPath: m_Name
|
propertyPath: m_Name
|
||||||
value: "\u7CBE\u9510\u58EB\u5175\u65B0"
|
value: "\u7CBE\u9510\u58EB\u5175"
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 919132149155446097, guid: 62d9f853c067ff443bd2a3aa382ab563,
|
- target: {fileID: 919132149155446097, guid: 62d9f853c067ff443bd2a3aa382ab563,
|
||||||
type: 3}
|
type: 3}
|
||||||
@@ -255,8 +255,8 @@ MonoBehaviour:
|
|||||||
attackRange: 1.2
|
attackRange: 1.2
|
||||||
modelFacingOffset: 0
|
modelFacingOffset: 0
|
||||||
useRootMotion: 1
|
useRootMotion: 1
|
||||||
attackPower: 68
|
attackPower: 55
|
||||||
attackDuration: 2.22
|
attackDuration: 1.6
|
||||||
attackType: 0
|
attackType: 0
|
||||||
projectilePrefab: {fileID: 0}
|
projectilePrefab: {fileID: 0}
|
||||||
projectileSpawnPoint: {fileID: 0}
|
projectileSpawnPoint: {fileID: 0}
|
||||||
|
|||||||
@@ -313,15 +313,15 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3}
|
m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
speed: 5
|
speed: 2.2
|
||||||
gravity: -20
|
gravity: -20
|
||||||
range: 500
|
range: 500
|
||||||
detectRange: 200
|
detectRange: 200
|
||||||
attackRange: 5
|
attackRange: 5
|
||||||
modelFacingOffset: 0
|
modelFacingOffset: 0
|
||||||
useRootMotion: 0
|
useRootMotion: 0
|
||||||
attackPower: 12
|
attackPower: 15
|
||||||
attackDuration: 0.8
|
attackDuration: 0.9
|
||||||
attackType: 2
|
attackType: 2
|
||||||
projectilePrefab: {fileID: 1754121762047325928, guid: e59aafedb502e65409f16e33cee0eed6,
|
projectilePrefab: {fileID: 1754121762047325928, guid: e59aafedb502e65409f16e33cee0eed6,
|
||||||
type: 3}
|
type: 3}
|
||||||
|
|||||||
@@ -148,15 +148,15 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3}
|
m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
speed: 4
|
speed: 2.5
|
||||||
gravity: -20
|
gravity: -20
|
||||||
range: 18
|
range: 18
|
||||||
detectRange: 20
|
detectRange: 20
|
||||||
attackRange: 1.1
|
attackRange: 1.1
|
||||||
modelFacingOffset: 0
|
modelFacingOffset: 0
|
||||||
useRootMotion: 1
|
useRootMotion: 1
|
||||||
attackPower: 38
|
attackPower: 32
|
||||||
attackDuration: 0.95
|
attackDuration: 1
|
||||||
attackType: 0
|
attackType: 0
|
||||||
projectilePrefab: {fileID: 0}
|
projectilePrefab: {fileID: 0}
|
||||||
projectileSpawnPoint: {fileID: 0}
|
projectileSpawnPoint: {fileID: 0}
|
||||||
|
|||||||
@@ -132,15 +132,15 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3}
|
m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
speed: 2.1
|
speed: 1.1
|
||||||
gravity: -20
|
gravity: -20
|
||||||
range: 500
|
range: 500
|
||||||
detectRange: 200
|
detectRange: 200
|
||||||
attackRange: 1.1
|
attackRange: 1.1
|
||||||
modelFacingOffset: 90
|
modelFacingOffset: 90
|
||||||
useRootMotion: 1
|
useRootMotion: 1
|
||||||
attackPower: 72
|
attackPower: 110
|
||||||
attackDuration: 2.5
|
attackDuration: 2.8
|
||||||
attackType: 0
|
attackType: 0
|
||||||
projectilePrefab: {fileID: 0}
|
projectilePrefab: {fileID: 0}
|
||||||
projectileSpawnPoint: {fileID: 0}
|
projectileSpawnPoint: {fileID: 0}
|
||||||
|
|||||||
@@ -173,15 +173,15 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3}
|
m_Script: {fileID: 11500000, guid: b91aa6ae607324ce19fc46225a44e70a, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
speed: 2
|
speed: 1.6
|
||||||
gravity: -20
|
gravity: -20
|
||||||
range: 18
|
range: 18
|
||||||
detectRange: 20
|
detectRange: 20
|
||||||
attackRange: 1
|
attackRange: 1
|
||||||
modelFacingOffset: 0
|
modelFacingOffset: 0
|
||||||
useRootMotion: 0
|
useRootMotion: 0
|
||||||
attackPower: 20
|
attackPower: 16
|
||||||
attackDuration: 1.8
|
attackDuration: 1.6
|
||||||
attackType: 0
|
attackType: 0
|
||||||
projectilePrefab: {fileID: 0}
|
projectilePrefab: {fileID: 0}
|
||||||
projectileSpawnPoint: {fileID: 0}
|
projectileSpawnPoint: {fileID: 0}
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ MonoBehaviour:
|
|||||||
type: 3}
|
type: 3}
|
||||||
manaCost: 2
|
manaCost: 2
|
||||||
cooldownTime: 1
|
cooldownTime: 1
|
||||||
productionInterval: 8
|
productionInterval: 6
|
||||||
buildingCost: 100
|
buildingCost: 100
|
||||||
baseMaxHealth: 100
|
baseMaxHealth: 300
|
||||||
baseAttackPower: 50
|
baseAttackPower: 30
|
||||||
baseMoveSpeed: 3
|
baseMoveSpeed: 1.8
|
||||||
healthPerLevel: 10
|
healthPerLevel: 30
|
||||||
attackPerLevel: 5
|
attackPerLevel: 3
|
||||||
moveSpeedPerLevel: 0
|
moveSpeedPerLevel: 0
|
||||||
@@ -20,11 +20,11 @@ MonoBehaviour:
|
|||||||
type: 3}
|
type: 3}
|
||||||
manaCost: 3
|
manaCost: 3
|
||||||
cooldownTime: 1
|
cooldownTime: 1
|
||||||
productionInterval: 10
|
productionInterval: 8
|
||||||
buildingCost: 100
|
buildingCost: 120
|
||||||
baseMaxHealth: 80
|
baseMaxHealth: 200
|
||||||
baseAttackPower: 60
|
baseAttackPower: 40
|
||||||
baseMoveSpeed: 3.5
|
baseMoveSpeed: 1.8
|
||||||
healthPerLevel: 8
|
healthPerLevel: 20
|
||||||
attackPerLevel: 6
|
attackPerLevel: 3
|
||||||
moveSpeedPerLevel: 0
|
moveSpeedPerLevel: 0
|
||||||
@@ -19,9 +19,11 @@ MonoBehaviour:
|
|||||||
unitPrefab: {fileID: 0}
|
unitPrefab: {fileID: 0}
|
||||||
manaCost: 3
|
manaCost: 3
|
||||||
cooldownTime: 1
|
cooldownTime: 1
|
||||||
baseMaxHealth: 145
|
productionInterval: 8
|
||||||
baseAttackPower: 36
|
buildingCost: 120
|
||||||
baseMoveSpeed: 3.5
|
baseMaxHealth: 200
|
||||||
healthPerLevel: 7.25
|
baseAttackPower: 15
|
||||||
attackPerLevel: 1.8
|
baseMoveSpeed: 2.2
|
||||||
|
healthPerLevel: 20
|
||||||
|
attackPerLevel: 1
|
||||||
moveSpeedPerLevel: 0
|
moveSpeedPerLevel: 0
|
||||||
@@ -21,10 +21,10 @@ MonoBehaviour:
|
|||||||
manaCost: 6
|
manaCost: 6
|
||||||
cooldownTime: 1
|
cooldownTime: 1
|
||||||
productionInterval: 12
|
productionInterval: 12
|
||||||
buildingCost: 100
|
buildingCost: 150
|
||||||
baseMaxHealth: 70
|
baseMaxHealth: 160
|
||||||
baseAttackPower: 100
|
baseAttackPower: 90
|
||||||
baseMoveSpeed: 3
|
baseMoveSpeed: 1.5
|
||||||
healthPerLevel: 7
|
healthPerLevel: 16
|
||||||
attackPerLevel: 10
|
attackPerLevel: 7
|
||||||
moveSpeedPerLevel: 0
|
moveSpeedPerLevel: 0
|
||||||
@@ -19,9 +19,11 @@ MonoBehaviour:
|
|||||||
unitPrefab: {fileID: 0}
|
unitPrefab: {fileID: 0}
|
||||||
manaCost: 4
|
manaCost: 4
|
||||||
cooldownTime: 1
|
cooldownTime: 1
|
||||||
baseMaxHealth: 360
|
productionInterval: 10
|
||||||
baseAttackPower: 38
|
buildingCost: 150
|
||||||
baseMoveSpeed: 3.8
|
baseMaxHealth: 380
|
||||||
healthPerLevel: 18
|
baseAttackPower: 32
|
||||||
attackPerLevel: 1.9
|
baseMoveSpeed: 2.5
|
||||||
|
healthPerLevel: 38
|
||||||
|
attackPerLevel: 3
|
||||||
moveSpeedPerLevel: 0
|
moveSpeedPerLevel: 0
|
||||||
@@ -20,9 +20,11 @@ MonoBehaviour:
|
|||||||
type: 3}
|
type: 3}
|
||||||
manaCost: 4
|
manaCost: 4
|
||||||
cooldownTime: 1
|
cooldownTime: 1
|
||||||
baseMaxHealth: 150
|
productionInterval: 10
|
||||||
baseAttackPower: 40
|
buildingCost: 150
|
||||||
baseMoveSpeed: 2.5
|
baseMaxHealth: 900
|
||||||
healthPerLevel: 15
|
baseAttackPower: 20
|
||||||
attackPerLevel: 4
|
baseMoveSpeed: 1.4
|
||||||
|
healthPerLevel: 90
|
||||||
|
attackPerLevel: 2
|
||||||
moveSpeedPerLevel: 0
|
moveSpeedPerLevel: 0
|
||||||
@@ -19,9 +19,11 @@ MonoBehaviour:
|
|||||||
unitPrefab: {fileID: 0}
|
unitPrefab: {fileID: 0}
|
||||||
manaCost: 7
|
manaCost: 7
|
||||||
cooldownTime: 1
|
cooldownTime: 1
|
||||||
baseMaxHealth: 820
|
productionInterval: 20
|
||||||
baseAttackPower: 72
|
buildingCost: 250
|
||||||
baseMoveSpeed: 2.5
|
baseMaxHealth: 1400
|
||||||
healthPerLevel: 41
|
baseAttackPower: 110
|
||||||
attackPerLevel: 3.6
|
baseMoveSpeed: 1.1
|
||||||
|
healthPerLevel: 140
|
||||||
|
attackPerLevel: 9
|
||||||
moveSpeedPerLevel: 0
|
moveSpeedPerLevel: 0
|
||||||
@@ -20,9 +20,11 @@ MonoBehaviour:
|
|||||||
type: 3}
|
type: 3}
|
||||||
manaCost: 5
|
manaCost: 5
|
||||||
cooldownTime: 1
|
cooldownTime: 1
|
||||||
baseMaxHealth: 120
|
productionInterval: 12
|
||||||
baseAttackPower: 80
|
buildingCost: 180
|
||||||
baseMoveSpeed: 3.5
|
baseMaxHealth: 420
|
||||||
healthPerLevel: 12
|
baseAttackPower: 55
|
||||||
attackPerLevel: 8
|
baseMoveSpeed: 2
|
||||||
|
healthPerLevel: 42
|
||||||
|
attackPerLevel: 4
|
||||||
moveSpeedPerLevel: 0
|
moveSpeedPerLevel: 0
|
||||||
@@ -19,9 +19,11 @@ MonoBehaviour:
|
|||||||
unitPrefab: {fileID: 0}
|
unitPrefab: {fileID: 0}
|
||||||
manaCost: 1
|
manaCost: 1
|
||||||
cooldownTime: 1
|
cooldownTime: 1
|
||||||
baseMaxHealth: 170
|
productionInterval: 5
|
||||||
baseAttackPower: 22
|
buildingCost: 80
|
||||||
baseMoveSpeed: 4
|
baseMaxHealth: 340
|
||||||
healthPerLevel: 8.5
|
baseAttackPower: 16
|
||||||
attackPerLevel: 1.1
|
baseMoveSpeed: 1.6
|
||||||
|
healthPerLevel: 34
|
||||||
|
attackPerLevel: 1
|
||||||
moveSpeedPerLevel: 0
|
moveSpeedPerLevel: 0
|
||||||
@@ -7,6 +7,9 @@ public class MainCharacterCombat : MonoBehaviour
|
|||||||
[Min(0f)]
|
[Min(0f)]
|
||||||
public float attackRange = 8f;
|
public float attackRange = 8f;
|
||||||
|
|
||||||
|
[Min(0f)]
|
||||||
|
public float detectRange = 10f;
|
||||||
|
|
||||||
[Min(0f)]
|
[Min(0f)]
|
||||||
public float attackPower = 50f;
|
public float attackPower = 50f;
|
||||||
|
|
||||||
@@ -86,13 +89,39 @@ public class MainCharacterCombat : MonoBehaviour
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (movement == null || movement.IsMoving || animator == null)
|
if (animator == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 巡逻中也能发现敌人;发现后停止巡逻,没有敌人则恢复巡逻
|
||||||
target = FindNearestEnemy();
|
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;
|
return;
|
||||||
}
|
}
|
||||||
@@ -165,7 +194,7 @@ public class MainCharacterCombat : MonoBehaviour
|
|||||||
|
|
||||||
if (movement != null)
|
if (movement != null)
|
||||||
{
|
{
|
||||||
movement.StopMovement();
|
movement.SetPatrolEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attacking)
|
if (attacking)
|
||||||
@@ -334,8 +363,7 @@ public class MainCharacterCombat : MonoBehaviour
|
|||||||
|
|
||||||
private bool IsInsideMovementBounds(Vector3 position)
|
private bool IsInsideMovementBounds(Vector3 position)
|
||||||
{
|
{
|
||||||
return movement == null || (position.x >= movement.xLimits.x && position.x <= movement.xLimits.y
|
return movement == null || movement.IsWithinLeash(position);
|
||||||
&& position.z >= movement.zLimits.x && position.z <= movement.zLimits.y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckSummonFinished()
|
private void CheckSummonFinished()
|
||||||
@@ -466,10 +494,18 @@ public class MainCharacterCombat : MonoBehaviour
|
|||||||
animator.SetInteger("speed", 0);
|
animator.SetInteger("speed", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private float GetHorizontalDistance(Vector3 position)
|
||||||
|
{
|
||||||
|
Vector3 offset = position - transform.position;
|
||||||
|
offset.y = 0f;
|
||||||
|
return offset.magnitude;
|
||||||
|
}
|
||||||
|
|
||||||
private GameObject FindNearestEnemy()
|
private GameObject FindNearestEnemy()
|
||||||
{
|
{
|
||||||
|
// 索敌范围使用较小的 detectRange,主角不主动远离基地寻找敌人
|
||||||
GameObject nearest = null;
|
GameObject nearest = null;
|
||||||
float nearestDistance = attackRange * attackRange;
|
float nearestDistance = detectRange * detectRange;
|
||||||
|
|
||||||
foreach (GameObject enemy in GameObject.FindGameObjectsWithTag("Enemy"))
|
foreach (GameObject enemy in GameObject.FindGameObjectsWithTag("Enemy"))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,49 +1,91 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.EventSystems;
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 主角自动巡逻移动:不再支持点击地面移动(避免与拖动屏幕、建筑放置的输入冲突)。
|
||||||
|
/// 没有敌人时在己方主建筑周围小范围来回走动,所有移动被限制在基地附近(栓绳范围)。
|
||||||
|
/// 战斗组件发现敌人后调用 SetPatrolEnabled(false) 停止巡逻进行攻击。
|
||||||
|
/// </summary>
|
||||||
public class MainCharacterDebugMovement : MonoBehaviour
|
public class MainCharacterDebugMovement : MonoBehaviour
|
||||||
{
|
{
|
||||||
[Header("电脑调试移动")]
|
[Header("巡逻移动")]
|
||||||
[Min(0f)]
|
[Min(0f)]
|
||||||
public float moveSpeed = 4f;
|
public float moveSpeed = 4f;
|
||||||
|
|
||||||
[Min(0f)]
|
[Min(0f)]
|
||||||
public float clickStopDistance = 0.08f;
|
public float patrolStopDistance = 0.15f;
|
||||||
|
|
||||||
[Header("移动范围")]
|
[Min(0f)]
|
||||||
public bool limitToBattlePlatform = true;
|
public float patrolPause = 1.5f;
|
||||||
public Vector2 xLimits = new Vector2(-7.5f, 7.5f);
|
|
||||||
public Vector2 zLimits = new Vector2(-14f, 14f);
|
[Header("巡逻区域(以主建筑为锚点)")]
|
||||||
|
[Min(0f)]
|
||||||
|
public float patrolRadius = 5f;
|
||||||
|
|
||||||
|
[Min(0f)]
|
||||||
|
public float leashRadius = 8f;
|
||||||
|
|
||||||
|
public string friendlyBuildingTag = "Friend";
|
||||||
|
|
||||||
private Animator animator;
|
private Animator animator;
|
||||||
private Vector3 clickTarget;
|
private Transform baseAnchor;
|
||||||
private bool hasClickTarget;
|
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()
|
private void Start()
|
||||||
{
|
{
|
||||||
animator = GetComponent<Animator>();
|
animator = GetComponent<Animator>();
|
||||||
clickTarget = transform.position;
|
fallbackAnchor = transform.position;
|
||||||
|
baseAnchor = FindMainBase();
|
||||||
SetWalking(false);
|
SetWalking(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Update()
|
private void Update()
|
||||||
{
|
{
|
||||||
HandleClickTarget();
|
if (!patrolEnabled)
|
||||||
|
|
||||||
if (!hasClickTarget)
|
|
||||||
{
|
{
|
||||||
|
UpdateChase();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pauseTimer > 0f)
|
||||||
|
{
|
||||||
|
pauseTimer -= Time.deltaTime;
|
||||||
|
IsMoving = false;
|
||||||
SetWalking(false);
|
SetWalking(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 toTarget = clickTarget - transform.position;
|
if (!hasPatrolTarget)
|
||||||
|
{
|
||||||
|
patrolTarget = GetNextPatrolPoint();
|
||||||
|
hasPatrolTarget = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 toTarget = patrolTarget - transform.position;
|
||||||
toTarget.y = 0f;
|
toTarget.y = 0f;
|
||||||
|
|
||||||
if (toTarget.magnitude <= clickStopDistance)
|
if (toTarget.magnitude <= patrolStopDistance)
|
||||||
{
|
{
|
||||||
hasClickTarget = false;
|
hasPatrolTarget = false;
|
||||||
|
pauseTimer = patrolPause;
|
||||||
|
IsMoving = false;
|
||||||
SetWalking(false);
|
SetWalking(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -51,32 +93,122 @@ public class MainCharacterDebugMovement : MonoBehaviour
|
|||||||
Move(toTarget.normalized);
|
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<BuildingHealth>() == 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EventSystem.current != null && EventSystem.current.IsPointerOverGameObject())
|
patrolEnabled = enabled;
|
||||||
|
if (!enabled)
|
||||||
{
|
{
|
||||||
return;
|
hasPatrolTarget = false;
|
||||||
|
pauseTimer = 0f;
|
||||||
|
IsMoving = false;
|
||||||
|
SetWalking(false);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
|
|
||||||
if (!Physics.Raycast(ray, out RaycastHit hit))
|
|
||||||
{
|
{
|
||||||
return;
|
hasChaseTarget = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
clickTarget = hit.point;
|
public void SetChaseTarget(Vector3 position)
|
||||||
clickTarget.y = transform.position.y;
|
{
|
||||||
hasClickTarget = true;
|
chaseTarget = position;
|
||||||
|
chaseTarget.y = transform.position.y;
|
||||||
|
hasChaseTarget = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearChaseTarget()
|
||||||
|
{
|
||||||
|
hasChaseTarget = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopMovement()
|
public void StopMovement()
|
||||||
{
|
{
|
||||||
hasClickTarget = false;
|
hasPatrolTarget = false;
|
||||||
|
hasChaseTarget = false;
|
||||||
|
IsMoving = false;
|
||||||
SetWalking(false);
|
SetWalking(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,19 +217,19 @@ public class MainCharacterDebugMovement : MonoBehaviour
|
|||||||
direction.y = 0f;
|
direction.y = 0f;
|
||||||
if (direction.sqrMagnitude <= 0.001f)
|
if (direction.sqrMagnitude <= 0.001f)
|
||||||
{
|
{
|
||||||
|
IsMoving = false;
|
||||||
SetWalking(false);
|
SetWalking(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IsMoving = true;
|
||||||
SetWalking(true);
|
SetWalking(true);
|
||||||
transform.position += direction * moveSpeed * Time.deltaTime;
|
transform.position += direction * moveSpeed * Time.deltaTime;
|
||||||
if (limitToBattlePlatform)
|
|
||||||
{
|
// 栓绳:任何情况下都不能完全离开基地
|
||||||
Vector3 position = transform.position;
|
Vector3 clamped = ClampToLeash(transform.position);
|
||||||
position.x = Mathf.Clamp(position.x, xLimits.x, xLimits.y);
|
clamped.y = transform.position.y;
|
||||||
position.z = Mathf.Clamp(position.z, zLimits.x, zLimits.y);
|
transform.position = clamped;
|
||||||
transform.position = position;
|
|
||||||
}
|
|
||||||
|
|
||||||
transform.rotation = Quaternion.LookRotation(direction, Vector3.up);
|
transform.rotation = Quaternion.LookRotation(direction, Vector3.up);
|
||||||
}
|
}
|
||||||
@@ -109,4 +241,4 @@ public class MainCharacterDebugMovement : MonoBehaviour
|
|||||||
animator.SetInteger("speed", walking ? 1 : 0);
|
animator.SetInteger("speed", walking ? 1 : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
- [2026-09-09 13:43:50] 能量恢复速度应该更慢一些,用户建议改为 3 秒恢复 1 格。**Why:** 1 秒 1 格太快,不利于战斗节奏控制。**How to apply:** 召唤系统能量恢复速率应偏慢,给玩家资源压力。
|
- [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-09 20:37:24] 用户希望提前实现数据架构而非临时方案,即使当前阶段功能简单。**Why:** 用户有 10 年后端开发经验,理解数据分层的重要性,希望逐步完善而非推倒重来。**How to apply:** 对于有明确扩展方向的功能(升级、存档、联网),优先设计可扩展架构并临时写死数据,而非等需求明确后再重构。
|
||||||
- [2026-09-10 18:38:45] 正交俯视视角(38-43°)下,垂直墙面几乎看不见(只能看到墙顶),因为墙面平行于视线方向被自身遮挡。适合的装饰物:高耸物体(旗帜、石柱)、有明显剪影的物体(木箱、碎石堆)、对比色强的物体;不适合:低矮平面物(矮墙、栅栏)、细长水平物(绳索)。**Why:** 这是正交俯视视角的固有盲区,无法通过调整角度完全解决(角度太平会牺牲战场全局视野)。**How to apply:** 场景装饰设计时优先使用垂直高度≥2米的物体,避免依赖水平或低矮结构。
|
- [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
|
### Project
|
||||||
- [2026-08-28 14:26:56] 弓箭手远程箭矢的设计要求:保持发射时高度水平飞行,命中目标后直接结算伤害并销毁,不产生实体物理击退。**Why:** 当前玩法希望远程攻击是命中判定而非物理推动。**How to apply:** 后续调整箭矢、Projectile 或弓箭手攻击逻辑时保持这一行为。
|
- [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: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-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-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
|
### Reference
|
||||||
- [2026-09-09 12:23:17] 飞行物脚本 Projectile.cs 负责锁敌追踪、碰撞检测和伤害结算。箭矢预制体 ArrowProjectile_White.prefab 已配置 Projectile 组件和 CapsuleCollider(Is Trigger)。远程单位需在攻击动画松弦帧添加 OnAttackEffect Event,并在 UnitBase 中设置 attackType=RangedProjectile、projectilePrefab、projectileSpawnPoint。
|
- [2026-09-09 12:23:17] 飞行物脚本 Projectile.cs 负责锁敌追踪、碰撞检测和伤害结算。箭矢预制体 ArrowProjectile_White.prefab 已配置 Projectile 组件和 CapsuleCollider(Is Trigger)。远程单位需在攻击动画松弦帧添加 OnAttackEffect Event,并在 UnitBase 中设置 attackType=RangedProjectile、projectilePrefab、projectileSpawnPoint。
|
||||||
+5
-3
@@ -50,9 +50,11 @@
|
|||||||
### 3.1 主角职责
|
### 3.1 主角职责
|
||||||
|
|
||||||
- 主角可以普通攻击;
|
- 主角可以普通攻击;
|
||||||
- 主角可以由玩家手动移动;
|
- 主角全程由 AI 自动控制,不支持点击地面手动移动(避免与拖动屏幕、建筑放置的输入冲突);
|
||||||
- 玩家没有主动操作时,主角自动巡逻并攻击附近敌人;
|
- 没有敌人时,主角在己方主建筑周围小范围来回巡逻;
|
||||||
- 主角可以手动释放技能;
|
- 索敌范围较小:只有敌人进入主角附近一定范围内才会被发现并攻击,不主动远离基地寻找敌人;
|
||||||
|
- 巡逻和追击都被限制在基地附近区域,主角不能完全离开基地;
|
||||||
|
- 主角可以手动释放技能(通过 UI 技能按钮,不占用地面点击操作);
|
||||||
- 主角技能冷却较长,主要用于辅助、补刀和改变局部战况;
|
- 主角技能冷却较长,主要用于辅助、补刀和改变局部战况;
|
||||||
- 主角不是主要战斗力,不能替代建筑生产的军队;
|
- 主角不是主要战斗力,不能替代建筑生产的军队;
|
||||||
- 主角的价值是提升玩家参与感,并在关键时刻提供战术干预。
|
- 主角的价值是提升玩家参与感,并在关键时刻提供战术干预。
|
||||||
|
|||||||
@@ -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 扩大,而不是继续压低移速;
|
||||||
|
- 主角(召唤师)数值不在本表内,主角定位是辅助,等装备系统定型后单独设计。
|
||||||
Reference in new issue
Block a user