Compare commits
2 commits
63b8195985
...
7b93137216
| Author | SHA1 | Date | |
|---|---|---|---|
| 7b93137216 | |||
| a87b221d87 |
21 changed files with 627 additions and 195 deletions
|
|
@ -0,0 +1,8 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3f1ef90255e065249a86a838844f7be2
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -298,6 +298,7 @@ MonoBehaviour:
|
||||||
queuedMaterial: {fileID: 2100000, guid: f8d951a6841d3f74098bb31255379774, type: 2}
|
queuedMaterial: {fileID: 2100000, guid: f8d951a6841d3f74098bb31255379774, type: 2}
|
||||||
constructingMaterial: {fileID: 2100000, guid: 88f1dd7b174716645953857b38fb6948, type: 2}
|
constructingMaterial: {fileID: 2100000, guid: 88f1dd7b174716645953857b38fb6948, type: 2}
|
||||||
pausedMaterial: {fileID: 0}
|
pausedMaterial: {fileID: 0}
|
||||||
|
defaultPhaseSet: {fileID: 11400000, guid: ed951755c09d6d0479b4fd924b6915da, type: 2}
|
||||||
stageCount: 4
|
stageCount: 4
|
||||||
queuedYScale: 0.15
|
queuedYScale: 0.15
|
||||||
--- !u!65 &6259437393614329336
|
--- !u!65 &6259437393614329336
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 82e418e7a5a804747a9a4865648b7793
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: c8f2a4e1b9d6437052a1e8c4f7b3d069, type: 3}
|
||||||
|
m_Name: DefaultConstructionSet
|
||||||
|
m_EditorClassIdentifier: Assembly-CSharp::TD.Towers.ConstructionPhaseSet
|
||||||
|
phases:
|
||||||
|
- {fileID: 562891720401665892, guid: e7be86c29087e99439507b508425b612, type: 3}
|
||||||
|
- {fileID: 3284400382278582069, guid: c6dabc822d0afb746adc08fb8602c2b4, type: 3}
|
||||||
|
- {fileID: 2161157853692362223, guid: d00c71c0cfc7e8744b9f8c1d48c2d256, type: 3}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ed951755c09d6d0479b4fd924b6915da
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1 &562891720401665892
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 5433206400477731590}
|
||||||
|
- component: {fileID: 3041202948021905482}
|
||||||
|
- component: {fileID: 2318454595080774531}
|
||||||
|
- component: {fileID: 2971339723339766249}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: DefaultConstruction_Phase_1
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &5433206400477731590
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 562891720401665892}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 0.1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!33 &3041202948021905482
|
||||||
|
MeshFilter:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 562891720401665892}
|
||||||
|
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
--- !u!23 &2318454595080774531
|
||||||
|
MeshRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 562891720401665892}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_CastShadows: 1
|
||||||
|
m_ReceiveShadows: 1
|
||||||
|
m_DynamicOccludee: 1
|
||||||
|
m_StaticShadowCaster: 0
|
||||||
|
m_MotionVectors: 1
|
||||||
|
m_LightProbeUsage: 1
|
||||||
|
m_ReflectionProbeUsage: 1
|
||||||
|
m_RayTracingMode: 2
|
||||||
|
m_RayTraceProcedural: 0
|
||||||
|
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||||
|
m_RayTracingAccelStructBuildFlags: 1
|
||||||
|
m_SmallMeshCulling: 1
|
||||||
|
m_ForceMeshLod: -1
|
||||||
|
m_MeshLodSelectionBias: 0
|
||||||
|
m_RenderingLayerMask: 1
|
||||||
|
m_RendererPriority: 0
|
||||||
|
m_Materials:
|
||||||
|
- {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2}
|
||||||
|
m_StaticBatchInfo:
|
||||||
|
firstSubMesh: 0
|
||||||
|
subMeshCount: 0
|
||||||
|
m_StaticBatchRoot: {fileID: 0}
|
||||||
|
m_ProbeAnchor: {fileID: 0}
|
||||||
|
m_LightProbeVolumeOverride: {fileID: 0}
|
||||||
|
m_ScaleInLightmap: 1
|
||||||
|
m_ReceiveGI: 1
|
||||||
|
m_PreserveUVs: 0
|
||||||
|
m_IgnoreNormalsForChartDetection: 0
|
||||||
|
m_ImportantGI: 0
|
||||||
|
m_StitchLightmapSeams: 1
|
||||||
|
m_SelectedEditorRenderState: 3
|
||||||
|
m_MinimumChartSize: 4
|
||||||
|
m_AutoUVMaxDistance: 0.5
|
||||||
|
m_AutoUVMaxAngle: 89
|
||||||
|
m_LightmapParameters: {fileID: 0}
|
||||||
|
m_GlobalIlluminationMeshLod: 0
|
||||||
|
m_SortingLayerID: 0
|
||||||
|
m_SortingLayer: 0
|
||||||
|
m_SortingOrder: 0
|
||||||
|
m_MaskInteraction: 0
|
||||||
|
m_AdditionalVertexStreams: {fileID: 0}
|
||||||
|
--- !u!65 &2971339723339766249
|
||||||
|
BoxCollider:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 562891720401665892}
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_IncludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_ExcludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_LayerOverridePriority: 0
|
||||||
|
m_IsTrigger: 0
|
||||||
|
m_ProvidesContacts: 0
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 3
|
||||||
|
m_Size: {x: 1, y: 1, z: 1}
|
||||||
|
m_Center: {x: 0, y: 0, z: 0}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e7be86c29087e99439507b508425b612
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1 &3284400382278582069
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 3820746952356246079}
|
||||||
|
- component: {fileID: 3350984935134180217}
|
||||||
|
- component: {fileID: 6336690892943026752}
|
||||||
|
- component: {fileID: 2003287843732108245}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: DefaultConstruction_Phase_2
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &3820746952356246079
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 3284400382278582069}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1.5, y: 0.5, z: 1.5}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!33 &3350984935134180217
|
||||||
|
MeshFilter:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 3284400382278582069}
|
||||||
|
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
--- !u!23 &6336690892943026752
|
||||||
|
MeshRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 3284400382278582069}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_CastShadows: 1
|
||||||
|
m_ReceiveShadows: 1
|
||||||
|
m_DynamicOccludee: 1
|
||||||
|
m_StaticShadowCaster: 0
|
||||||
|
m_MotionVectors: 1
|
||||||
|
m_LightProbeUsage: 1
|
||||||
|
m_ReflectionProbeUsage: 1
|
||||||
|
m_RayTracingMode: 2
|
||||||
|
m_RayTraceProcedural: 0
|
||||||
|
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||||
|
m_RayTracingAccelStructBuildFlags: 1
|
||||||
|
m_SmallMeshCulling: 1
|
||||||
|
m_ForceMeshLod: -1
|
||||||
|
m_MeshLodSelectionBias: 0
|
||||||
|
m_RenderingLayerMask: 1
|
||||||
|
m_RendererPriority: 0
|
||||||
|
m_Materials:
|
||||||
|
- {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2}
|
||||||
|
m_StaticBatchInfo:
|
||||||
|
firstSubMesh: 0
|
||||||
|
subMeshCount: 0
|
||||||
|
m_StaticBatchRoot: {fileID: 0}
|
||||||
|
m_ProbeAnchor: {fileID: 0}
|
||||||
|
m_LightProbeVolumeOverride: {fileID: 0}
|
||||||
|
m_ScaleInLightmap: 1
|
||||||
|
m_ReceiveGI: 1
|
||||||
|
m_PreserveUVs: 0
|
||||||
|
m_IgnoreNormalsForChartDetection: 0
|
||||||
|
m_ImportantGI: 0
|
||||||
|
m_StitchLightmapSeams: 1
|
||||||
|
m_SelectedEditorRenderState: 3
|
||||||
|
m_MinimumChartSize: 4
|
||||||
|
m_AutoUVMaxDistance: 0.5
|
||||||
|
m_AutoUVMaxAngle: 89
|
||||||
|
m_LightmapParameters: {fileID: 0}
|
||||||
|
m_GlobalIlluminationMeshLod: 0
|
||||||
|
m_SortingLayerID: 0
|
||||||
|
m_SortingLayer: 0
|
||||||
|
m_SortingOrder: 0
|
||||||
|
m_MaskInteraction: 0
|
||||||
|
m_AdditionalVertexStreams: {fileID: 0}
|
||||||
|
--- !u!65 &2003287843732108245
|
||||||
|
BoxCollider:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 3284400382278582069}
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_IncludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_ExcludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_LayerOverridePriority: 0
|
||||||
|
m_IsTrigger: 0
|
||||||
|
m_ProvidesContacts: 0
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 3
|
||||||
|
m_Size: {x: 1, y: 1, z: 1}
|
||||||
|
m_Center: {x: 0, y: 0, z: 0}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c6dabc822d0afb746adc08fb8602c2b4
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1 &2161157853692362223
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 6591719589271492770}
|
||||||
|
- component: {fileID: 3693505870455731207}
|
||||||
|
- component: {fileID: 2366594505425509977}
|
||||||
|
- component: {fileID: 5474707419433840976}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: DefaultConstruction_Phase_3
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &6591719589271492770
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2161157853692362223}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1.75, y: 1, z: 1.75}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!33 &3693505870455731207
|
||||||
|
MeshFilter:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2161157853692362223}
|
||||||
|
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
--- !u!23 &2366594505425509977
|
||||||
|
MeshRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2161157853692362223}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_CastShadows: 1
|
||||||
|
m_ReceiveShadows: 1
|
||||||
|
m_DynamicOccludee: 1
|
||||||
|
m_StaticShadowCaster: 0
|
||||||
|
m_MotionVectors: 1
|
||||||
|
m_LightProbeUsage: 1
|
||||||
|
m_ReflectionProbeUsage: 1
|
||||||
|
m_RayTracingMode: 2
|
||||||
|
m_RayTraceProcedural: 0
|
||||||
|
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||||
|
m_RayTracingAccelStructBuildFlags: 1
|
||||||
|
m_SmallMeshCulling: 1
|
||||||
|
m_ForceMeshLod: -1
|
||||||
|
m_MeshLodSelectionBias: 0
|
||||||
|
m_RenderingLayerMask: 1
|
||||||
|
m_RendererPriority: 0
|
||||||
|
m_Materials:
|
||||||
|
- {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2}
|
||||||
|
m_StaticBatchInfo:
|
||||||
|
firstSubMesh: 0
|
||||||
|
subMeshCount: 0
|
||||||
|
m_StaticBatchRoot: {fileID: 0}
|
||||||
|
m_ProbeAnchor: {fileID: 0}
|
||||||
|
m_LightProbeVolumeOverride: {fileID: 0}
|
||||||
|
m_ScaleInLightmap: 1
|
||||||
|
m_ReceiveGI: 1
|
||||||
|
m_PreserveUVs: 0
|
||||||
|
m_IgnoreNormalsForChartDetection: 0
|
||||||
|
m_ImportantGI: 0
|
||||||
|
m_StitchLightmapSeams: 1
|
||||||
|
m_SelectedEditorRenderState: 3
|
||||||
|
m_MinimumChartSize: 4
|
||||||
|
m_AutoUVMaxDistance: 0.5
|
||||||
|
m_AutoUVMaxAngle: 89
|
||||||
|
m_LightmapParameters: {fileID: 0}
|
||||||
|
m_GlobalIlluminationMeshLod: 0
|
||||||
|
m_SortingLayerID: 0
|
||||||
|
m_SortingLayer: 0
|
||||||
|
m_SortingOrder: 0
|
||||||
|
m_MaskInteraction: 0
|
||||||
|
m_AdditionalVertexStreams: {fileID: 0}
|
||||||
|
--- !u!65 &5474707419433840976
|
||||||
|
BoxCollider:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2161157853692362223}
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_IncludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_ExcludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_LayerOverridePriority: 0
|
||||||
|
m_IsTrigger: 0
|
||||||
|
m_ProvidesContacts: 0
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 3
|
||||||
|
m_Size: {x: 1, y: 1, z: 1}
|
||||||
|
m_Center: {x: 0, y: 0, z: 0}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d00c71c0cfc7e8744b9f8c1d48c2d256
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
// Assets/_Project/Scripts/Gameplay/BuildSiteVisual.cs
|
// Assets/_Project/Scripts/Gameplay/BuildSiteVisual.cs
|
||||||
using Unity.Collections;
|
|
||||||
using Unity.Netcode;
|
using Unity.Netcode;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using TD.Core;
|
using TD.Core;
|
||||||
|
|
@ -63,27 +62,25 @@ namespace TD.Gameplay
|
||||||
"Suggested: muted/grey-tinted variant of the constructing material.")]
|
"Suggested: muted/grey-tinted variant of the constructing material.")]
|
||||||
[SerializeField] private Material pausedMaterial;
|
[SerializeField] private Material pausedMaterial;
|
||||||
|
|
||||||
[Header("Construction stages")]
|
[Header("Construction phases")]
|
||||||
[Tooltip("Number of discrete growth stages while constructing. 4 matches the " +
|
[Tooltip("Project-default construction-stage visuals used when the tower being built " +
|
||||||
"design doc (1/4 → 2/4 → 3/4 → 4/4 height).")]
|
"doesn't define its own ConstructionPhases. When this (or the tower's set) " +
|
||||||
|
"has phases, the build site swaps between those phase prefabs as it builds. " +
|
||||||
|
"Leave empty to fall back to the legacy cube Y-scale growth below.")]
|
||||||
|
[SerializeField] private ConstructionPhaseSet defaultPhaseSet;
|
||||||
|
|
||||||
|
[Header("Construction stages (cube fallback)")]
|
||||||
|
[Tooltip("FALLBACK ONLY (no phase set assigned): number of discrete growth stages " +
|
||||||
|
"while constructing. 4 = 1/4 → 2/4 → 3/4 → 4/4 height.")]
|
||||||
[SerializeField] private int stageCount = 4;
|
[SerializeField] private int stageCount = 4;
|
||||||
|
|
||||||
[Tooltip("Y-scale applied to scaleTarget when Stage == Queued. Visually " +
|
[Tooltip("FALLBACK ONLY: Y-scale applied to scaleTarget when Stage == Queued. " +
|
||||||
"distinct from any constructing height so the queued ghost reads as " +
|
"Visually distinct from any constructing height so the queued ghost reads " +
|
||||||
"'intent, not progress'.")]
|
"as 'intent, not progress'.")]
|
||||||
[SerializeField] private float queuedYScale = 0.15f;
|
[SerializeField] private float queuedYScale = 0.15f;
|
||||||
|
|
||||||
// ----- Networked state --------------------------------------------
|
// ----- Networked state --------------------------------------------
|
||||||
|
|
||||||
// Replicated definition name so clients can resolve the source TowerDefinition
|
|
||||||
// (matches TowerInstance's pattern). Used for footprint size only — the visual
|
|
||||||
// prefab is the same regardless of tower type for now.
|
|
||||||
private readonly NetworkVariable<FixedString64Bytes> definitionName =
|
|
||||||
new NetworkVariable<FixedString64Bytes>(
|
|
||||||
default,
|
|
||||||
readPerm: NetworkVariableReadPermission.Everyone,
|
|
||||||
writePerm: NetworkVariableWritePermission.Server);
|
|
||||||
|
|
||||||
// Replicated owner slot for color tinting. Mirrors TowerInstance.
|
// Replicated owner slot for color tinting. Mirrors TowerInstance.
|
||||||
private readonly NetworkVariable<PlayerSlot> ownerSlot =
|
private readonly NetworkVariable<PlayerSlot> ownerSlot =
|
||||||
new NetworkVariable<PlayerSlot>(
|
new NetworkVariable<PlayerSlot>(
|
||||||
|
|
@ -232,7 +229,6 @@ namespace TD.Gameplay
|
||||||
|
|
||||||
// ----- Pre-spawn init data (server) -------------------------------
|
// ----- Pre-spawn init data (server) -------------------------------
|
||||||
|
|
||||||
private string pendingDefName;
|
|
||||||
private PlayerSlot pendingOwner = PlayerSlot.None;
|
private PlayerSlot pendingOwner = PlayerSlot.None;
|
||||||
private float pendingBuildTime;
|
private float pendingBuildTime;
|
||||||
private Vector2Int pendingAnchor;
|
private Vector2Int pendingAnchor;
|
||||||
|
|
@ -240,6 +236,17 @@ namespace TD.Gameplay
|
||||||
private int pendingGoldSpent;
|
private int pendingGoldSpent;
|
||||||
private bool hasPendingInit;
|
private bool hasPendingInit;
|
||||||
|
|
||||||
|
// ----- Construction-phase runtime (local, all peers) --------------
|
||||||
|
|
||||||
|
// Resolved on spawn from the tower's ConstructionPhases or the defaultPhaseSet.
|
||||||
|
// When non-null with PhaseCount > 0, the build site swaps between these
|
||||||
|
// instantiated phase prefabs instead of Y-scaling the fallback cube.
|
||||||
|
private ConstructionPhaseSet effectivePhaseSet;
|
||||||
|
private GameObject[] phaseInstances; // one instantiated child per phase
|
||||||
|
private MeshRenderer[][] phaseRenderers; // cached renderers per phase, for tinting
|
||||||
|
private int activePhaseIndex = -1;
|
||||||
|
private bool usePhases;
|
||||||
|
|
||||||
// ----- Lifecycle --------------------------------------------------
|
// ----- Lifecycle --------------------------------------------------
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -261,7 +268,6 @@ namespace TD.Gameplay
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pendingDefName = def != null ? def.name : string.Empty;
|
|
||||||
pendingOwner = owner;
|
pendingOwner = owner;
|
||||||
pendingBuildTime = def != null ? def.BuildTime : 0f;
|
pendingBuildTime = def != null ? def.BuildTime : 0f;
|
||||||
pendingAnchor = anchorTile;
|
pendingAnchor = anchorTile;
|
||||||
|
|
@ -281,7 +287,6 @@ namespace TD.Gameplay
|
||||||
// message so clients see correct values on their first OnNetworkSpawn.
|
// message so clients see correct values on their first OnNetworkSpawn.
|
||||||
if (IsServer && hasPendingInit)
|
if (IsServer && hasPendingInit)
|
||||||
{
|
{
|
||||||
definitionName.Value = new FixedString64Bytes(pendingDefName ?? string.Empty);
|
|
||||||
ownerSlot.Value = pendingOwner;
|
ownerSlot.Value = pendingOwner;
|
||||||
buildTime.Value = pendingBuildTime;
|
buildTime.Value = pendingBuildTime;
|
||||||
anchor.Value = pendingAnchor;
|
anchor.Value = pendingAnchor;
|
||||||
|
|
@ -290,6 +295,10 @@ namespace TD.Gameplay
|
||||||
hasPendingInit = false;
|
hasPendingInit = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolve and instantiate the construction-phase visuals (or fall back to the
|
||||||
|
// cube). Depends on towerTypeId, which is replicated by now on every peer.
|
||||||
|
ResolvePhaseSet();
|
||||||
|
|
||||||
// Subscribe to value changes so visual updates are reactive.
|
// Subscribe to value changes so visual updates are reactive.
|
||||||
currentStage.OnValueChanged += HandleStageChanged;
|
currentStage.OnValueChanged += HandleStageChanged;
|
||||||
|
|
||||||
|
|
@ -344,14 +353,25 @@ namespace TD.Gameplay
|
||||||
|
|
||||||
private void Update()
|
private void Update()
|
||||||
{
|
{
|
||||||
// While constructing, smoothly interpolate Y-scale through the stages
|
// While constructing, advance the visual based on server time. Runs on every
|
||||||
// based on server time. This runs on every peer (server + clients) so
|
// peer so visuals stay synchronized. Paused does NOT update — the visual is
|
||||||
// visuals stay synchronized regardless of who's looking.
|
// frozen at the pause point.
|
||||||
// Paused stage does NOT update — Y-scale is frozen at the pause point.
|
|
||||||
if (currentStage.Value != BuildStage.Constructing) return;
|
if (currentStage.Value != BuildStage.Constructing) return;
|
||||||
|
|
||||||
float yScale = ComputeConstructingYScale();
|
if (usePhases)
|
||||||
ApplyYScale(yScale);
|
{
|
||||||
|
int index = PhaseIndexFromProgress();
|
||||||
|
if (index != activePhaseIndex)
|
||||||
|
{
|
||||||
|
ShowPhase(index);
|
||||||
|
// Renderers changed with the swap — re-apply material + owner tint.
|
||||||
|
ApplyStageMaterialAndTint(BuildStage.Constructing);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: smoothly grow the cube's Y-scale through the stages.
|
||||||
|
ApplyYScale(ComputeConstructingYScale());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----- Server API -------------------------------------------------
|
// ----- Server API -------------------------------------------------
|
||||||
|
|
@ -498,33 +518,117 @@ namespace TD.Gameplay
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyStageVisual(BuildStage stage)
|
private void ApplyStageVisual(BuildStage stage)
|
||||||
|
{
|
||||||
|
if (usePhases)
|
||||||
|
{
|
||||||
|
// Queued shows the first phase; constructing/paused show the phase
|
||||||
|
// matching current progress. ShowPhase repoints tintedRenderers at the
|
||||||
|
// active phase instance, so material + tint are applied AFTER it.
|
||||||
|
int index = stage == BuildStage.Queued ? 0 : PhaseIndexFromProgress();
|
||||||
|
ShowPhase(index);
|
||||||
|
ApplyStageMaterialAndTint(stage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: legacy cube Y-scale growth (no phase set wired).
|
||||||
|
ApplyStageMaterialAndTint(stage);
|
||||||
|
switch (stage)
|
||||||
|
{
|
||||||
|
case BuildStage.Queued: ApplyYScale(queuedYScale); break;
|
||||||
|
case BuildStage.Constructing: ApplyYScale(ComputeConstructingYScale()); break;
|
||||||
|
// ComputePausedYScale uses accumulatedConstructionTime alone when
|
||||||
|
// constructionStartServerTime is -1 (the pause sentinel).
|
||||||
|
case BuildStage.Paused: ApplyYScale(ComputePausedYScale()); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Applies the stage's material + owner tint to whatever renderers are currently
|
||||||
|
// active — the cube fallback, or the active phase instance's renderers. Paused
|
||||||
|
// falls back to the constructing material if no paused material is assigned.
|
||||||
|
private void ApplyStageMaterialAndTint(BuildStage stage)
|
||||||
{
|
{
|
||||||
switch (stage)
|
switch (stage)
|
||||||
{
|
{
|
||||||
case BuildStage.Queued:
|
case BuildStage.Queued:
|
||||||
SwapMaterial(queuedMaterial);
|
SwapMaterial(queuedMaterial); // green ghost — no owner tint
|
||||||
ApplyYScale(queuedYScale);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BuildStage.Constructing:
|
case BuildStage.Constructing:
|
||||||
SwapMaterial(constructingMaterial);
|
SwapMaterial(constructingMaterial);
|
||||||
ApplyOwnerTint();
|
ApplyOwnerTint();
|
||||||
ApplyYScale(ComputeConstructingYScale());
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BuildStage.Paused:
|
case BuildStage.Paused:
|
||||||
// Use paused material if assigned; fall back to constructing
|
|
||||||
// material if not (still readable, just less distinct).
|
|
||||||
SwapMaterial(pausedMaterial != null ? pausedMaterial : constructingMaterial);
|
SwapMaterial(pausedMaterial != null ? pausedMaterial : constructingMaterial);
|
||||||
ApplyOwnerTint();
|
ApplyOwnerTint();
|
||||||
// Freeze Y-scale at whatever the accumulated progress represents.
|
|
||||||
// ComputeConstructingYScale uses accumulatedConstructionTime alone
|
|
||||||
// when constructionStartServerTime is -1 (the pause sentinel).
|
|
||||||
ApplyYScale(ComputePausedYScale());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----- Construction phases ----------------------------------------
|
||||||
|
|
||||||
|
// Resolves the effective phase set (tower's own, else the project default) and
|
||||||
|
// instantiates one inactive child per phase. Sets usePhases=false (cube fallback)
|
||||||
|
// if neither set has any phases. Runs on every peer in OnNetworkSpawn.
|
||||||
|
private void ResolvePhaseSet()
|
||||||
|
{
|
||||||
|
var def = TowerPlacementManager.GetDefinition(towerTypeId.Value);
|
||||||
|
effectivePhaseSet =
|
||||||
|
(def != null && def.ConstructionPhases != null && def.ConstructionPhases.PhaseCount > 0)
|
||||||
|
? def.ConstructionPhases
|
||||||
|
: defaultPhaseSet;
|
||||||
|
|
||||||
|
int n = effectivePhaseSet != null ? effectivePhaseSet.PhaseCount : 0;
|
||||||
|
if (n <= 0)
|
||||||
|
{
|
||||||
|
usePhases = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
usePhases = true;
|
||||||
|
phaseInstances = new GameObject[n];
|
||||||
|
phaseRenderers = new MeshRenderer[n][];
|
||||||
|
|
||||||
|
// Hide the legacy fallback cube — the instantiated phase prefabs replace it.
|
||||||
|
if (scaleTarget != null) scaleTarget.gameObject.SetActive(false);
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
var prefab = effectivePhaseSet.GetPhase(i);
|
||||||
|
if (prefab == null) continue;
|
||||||
|
|
||||||
|
var go = Instantiate(prefab, transform);
|
||||||
|
go.transform.localPosition = Vector3.zero;
|
||||||
|
go.transform.localRotation = Quaternion.identity;
|
||||||
|
go.SetActive(false);
|
||||||
|
|
||||||
|
phaseInstances[i] = go;
|
||||||
|
phaseRenderers[i] = go.GetComponentsInChildren<MeshRenderer>(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activates only phase <paramref name="index"/> and points tintedRenderers at its
|
||||||
|
// renderers so the existing material/tint helpers drive the active phase.
|
||||||
|
private void ShowPhase(int index)
|
||||||
|
{
|
||||||
|
if (phaseInstances == null) return;
|
||||||
|
index = Mathf.Clamp(index, 0, phaseInstances.Length - 1);
|
||||||
|
|
||||||
|
for (int i = 0; i < phaseInstances.Length; i++)
|
||||||
|
if (phaseInstances[i] != null)
|
||||||
|
phaseInstances[i].SetActive(i == index);
|
||||||
|
|
||||||
|
activePhaseIndex = index;
|
||||||
|
tintedRenderers = phaseRenderers[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maps current normalized progress to a phase index (0..PhaseCount-1).
|
||||||
|
private int PhaseIndexFromProgress()
|
||||||
|
{
|
||||||
|
int n = effectivePhaseSet != null ? effectivePhaseSet.PhaseCount : 1;
|
||||||
|
if (n <= 1) return 0;
|
||||||
|
float p = ComputeProgressNormalized();
|
||||||
|
return Mathf.Clamp(Mathf.FloorToInt(p * n), 0, n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
// Stage index 0..stageCount-1 based on elapsed server time PLUS any accumulated
|
// Stage index 0..stageCount-1 based on elapsed server time PLUS any accumulated
|
||||||
// time from previous Constructing runs (resume support).
|
// time from previous Constructing runs (resume support).
|
||||||
// Returned Y-scale is (stageIndex + 1) / stageCount, so stage 0 = 1/4,
|
// Returned Y-scale is (stageIndex + 1) / stageCount, so stage 0 = 1/4,
|
||||||
|
|
|
||||||
|
|
@ -68,8 +68,8 @@ namespace TD.Gameplay
|
||||||
"the prefab based on the player's RaceSelection.")]
|
"the prefab based on the player's RaceSelection.")]
|
||||||
public GameObject BuilderPrefab;
|
public GameObject BuilderPrefab;
|
||||||
|
|
||||||
[Tooltip("STUB (Phase 1.8): tower roster available to this race. TowerRegistry will " +
|
[Tooltip("STUB: tower roster available to this race/builder. The draft pool or " +
|
||||||
"filter to this list when the active player belongs to this race.")]
|
"starting deck will eventually filter to this list for this race.")]
|
||||||
public TowerDefinition[] Towers;
|
public TowerDefinition[] Towers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
// Assets/_Project/Scripts/Gameplay/TowerInstance.cs
|
// Assets/_Project/Scripts/Gameplay/TowerInstance.cs
|
||||||
using Unity.Collections;
|
|
||||||
using Unity.Netcode;
|
using Unity.Netcode;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using TD.Core;
|
using TD.Core;
|
||||||
|
|
@ -32,11 +31,11 @@ namespace TD.Gameplay
|
||||||
/// <see cref="SetOccupied"/> are idempotent writes, so double-stamping is safe.</para>
|
/// <see cref="SetOccupied"/> are idempotent writes, so double-stamping is safe.</para>
|
||||||
///
|
///
|
||||||
/// <para><b>Definition reference replication.</b> TowerDefinition assets live in the
|
/// <para><b>Definition reference replication.</b> TowerDefinition assets live in the
|
||||||
/// project on all clients. We replicate the asset by name via a
|
/// project on all clients. We replicate the tower's <c>TowerTypeId</c> (its index in
|
||||||
/// <see cref="NetworkVariable{T}"/> holding a <c>FixedString64Bytes</c>, then look
|
/// <see cref="TowerPlacementManager"/>'s catalog) via a <see cref="NetworkVariable{T}"/>,
|
||||||
/// up the asset locally. This avoids serializing the full ScriptableObject over the
|
/// then resolve the full asset locally with <see cref="TowerPlacementManager.GetDefinition"/>.
|
||||||
/// network. The lookup uses a <see cref="TowerRegistry"/> singleton that must be
|
/// This avoids serializing the ScriptableObject over the network and reuses the same
|
||||||
/// present in the scene. (Temporary: will be driven by RaceDefinition in Path E.)</para>
|
/// identifier placement and the deck already use — a single source of truth.</para>
|
||||||
///
|
///
|
||||||
/// <para><b>Combat.</b> No combat logic here yet. Combat fields live stubbed on
|
/// <para><b>Combat.</b> No combat logic here yet. Combat fields live stubbed on
|
||||||
/// <see cref="TowerDefinition"/>; they will be consumed by a future
|
/// <see cref="TowerDefinition"/>; they will be consumed by a future
|
||||||
|
|
@ -58,12 +57,13 @@ namespace TD.Gameplay
|
||||||
|
|
||||||
// ----- Networked state ------------------------------------------------
|
// ----- Networked state ------------------------------------------------
|
||||||
|
|
||||||
// The name of the TowerDefinition asset for this tower. Replicated so all
|
// The TowerTypeId (index into TowerPlacementManager's catalog) for this tower.
|
||||||
// clients can look up the full definition locally without sending the whole
|
// Replicated so every client resolves the full definition locally via the catalog —
|
||||||
// ScriptableObject over the wire.
|
// the same identifier placement and the deck already use. 0 = unset/invalid (the
|
||||||
private readonly NetworkVariable<FixedString64Bytes> definitionName =
|
// reserved catalog index). Replaces the old replicate-by-name + TowerRegistry path.
|
||||||
new NetworkVariable<FixedString64Bytes>(
|
private readonly NetworkVariable<int> definitionTypeId =
|
||||||
default,
|
new NetworkVariable<int>(
|
||||||
|
0,
|
||||||
readPerm: NetworkVariableReadPermission.Everyone,
|
readPerm: NetworkVariableReadPermission.Everyone,
|
||||||
writePerm: NetworkVariableWritePermission.Server);
|
writePerm: NetworkVariableWritePermission.Server);
|
||||||
|
|
||||||
|
|
@ -95,8 +95,8 @@ namespace TD.Gameplay
|
||||||
|
|
||||||
// ----- Local resolved state -------------------------------------------
|
// ----- Local resolved state -------------------------------------------
|
||||||
|
|
||||||
// Resolved on every client in OnNetworkSpawn from definitionName.
|
// Resolved on every client in OnNetworkSpawn from definitionTypeId via the catalog.
|
||||||
// Null if the lookup fails (missing TowerRegistry or unknown name).
|
// Null if the lookup fails (TypeId not in the catalog on this peer).
|
||||||
private TowerDefinition resolvedDefinition;
|
private TowerDefinition resolvedDefinition;
|
||||||
|
|
||||||
// ----- Pre-spawn initialization data ----------------------------------
|
// ----- Pre-spawn initialization data ----------------------------------
|
||||||
|
|
@ -192,7 +192,7 @@ namespace TD.Gameplay
|
||||||
hasPendingInit = true;
|
hasPendingInit = true;
|
||||||
|
|
||||||
// Cache the resolved definition on the server immediately — clients
|
// Cache the resolved definition on the server immediately — clients
|
||||||
// will resolve via the registry lookup once definitionName arrives.
|
// resolve from the replicated TowerTypeId via the catalog once it arrives.
|
||||||
resolvedDefinition = def;
|
resolvedDefinition = def;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -206,7 +206,17 @@ namespace TD.Gameplay
|
||||||
// every client sees correct values on its very first OnNetworkSpawn.
|
// every client sees correct values on its very first OnNetworkSpawn.
|
||||||
if (IsServer && hasPendingInit)
|
if (IsServer && hasPendingInit)
|
||||||
{
|
{
|
||||||
definitionName.Value = new FixedString64Bytes(pendingDefinition.name);
|
// Resolve the catalog index for this definition and replicate that.
|
||||||
|
int typeId = 0;
|
||||||
|
var pm = TowerPlacementManager.Instance;
|
||||||
|
if (pm == null || !pm.TryGetTypeId(pendingDefinition, out typeId))
|
||||||
|
{
|
||||||
|
Debug.LogError($"[TowerInstance] Could not resolve a TowerTypeId for " +
|
||||||
|
$"'{pendingDefinition?.name}'. Ensure it is in the " +
|
||||||
|
$"TowerPlacementManager catalog (towerDefinitions).");
|
||||||
|
}
|
||||||
|
|
||||||
|
definitionTypeId.Value = typeId;
|
||||||
anchorTile.Value = pendingAnchor;
|
anchorTile.Value = pendingAnchor;
|
||||||
ownerSlot.Value = pendingOwner;
|
ownerSlot.Value = pendingOwner;
|
||||||
|
|
||||||
|
|
@ -331,27 +341,13 @@ namespace TD.Gameplay
|
||||||
// Already resolved (server path via InitializeServer).
|
// Already resolved (server path via InitializeServer).
|
||||||
if (resolvedDefinition != null) return;
|
if (resolvedDefinition != null) return;
|
||||||
|
|
||||||
string defName = definitionName.Value.ToString();
|
int typeId = definitionTypeId.Value;
|
||||||
if (string.IsNullOrEmpty(defName))
|
resolvedDefinition = TowerPlacementManager.GetDefinition(typeId);
|
||||||
{
|
|
||||||
Debug.LogError($"[TowerInstance] NetworkObject {NetworkObjectId}: " +
|
|
||||||
$"definitionName is empty. Cannot resolve TowerDefinition.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var registry = TowerRegistry.Instance;
|
|
||||||
if (registry == null)
|
|
||||||
{
|
|
||||||
Debug.LogError($"[TowerInstance] NetworkObject {NetworkObjectId}: " +
|
|
||||||
$"No TowerRegistry found in scene. Cannot resolve '{defName}'.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolvedDefinition = registry.Get(defName);
|
|
||||||
if (resolvedDefinition == null)
|
if (resolvedDefinition == null)
|
||||||
{
|
{
|
||||||
Debug.LogError($"[TowerInstance] NetworkObject {NetworkObjectId}: " +
|
Debug.LogError($"[TowerInstance] NetworkObject {NetworkObjectId}: " +
|
||||||
$"TowerRegistry does not contain a definition named '{defName}'.");
|
$"no TowerDefinition for TypeId {typeId}. Is the " +
|
||||||
|
$"TowerPlacementManager catalog populated on this peer?");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,120 +0,0 @@
|
||||||
// Assets/_Project/Scripts/Gameplay/TowerRegistry.cs
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
using TD.Towers;
|
|
||||||
|
|
||||||
namespace TD.Gameplay
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Scene singleton that holds every <see cref="TowerDefinition"/> available in the
|
|
||||||
/// current match and lets any code look one up by asset name.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// <para><b>Why this exists.</b> <see cref="TowerInstance"/> replicates a tower's
|
|
||||||
/// definition by name (a <c>FixedString64Bytes</c> over the network), then resolves
|
|
||||||
/// the full ScriptableObject locally on every client. TowerRegistry is the lookup
|
|
||||||
/// table that makes that resolution possible without hard-coding asset paths.</para>
|
|
||||||
///
|
|
||||||
/// <para><b>Registration.</b> Drag every <see cref="TowerDefinition"/> asset into the
|
|
||||||
/// <c>Definitions</c> list on this component in the inspector. Assets can live anywhere
|
|
||||||
/// in the project — no special folder required.</para>
|
|
||||||
///
|
|
||||||
/// <para><b>Path E upgrade path.</b> In Path E the registry will filter to only the
|
|
||||||
/// definitions belonging to the active match's <c>RaceDefinition</c> rosters. For now
|
|
||||||
/// all assigned assets are registered.</para>
|
|
||||||
///
|
|
||||||
/// <para><b>Plain MonoBehaviour.</b> Not a NetworkBehaviour — the registry is
|
|
||||||
/// identical on every peer (same assets, same names), so there is nothing to sync.</para>
|
|
||||||
/// </remarks>
|
|
||||||
public class TowerRegistry : MonoBehaviour
|
|
||||||
{
|
|
||||||
// ----- Singleton --------------------------------------------------
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The active TowerRegistry. Null before Awake or after the scene unloads.
|
|
||||||
/// Always null-check before use.
|
|
||||||
/// </summary>
|
|
||||||
public static TowerRegistry Instance { get; private set; }
|
|
||||||
|
|
||||||
// ----- Inspector --------------------------------------------------
|
|
||||||
|
|
||||||
[Tooltip("All TowerDefinition assets available in this match. " +
|
|
||||||
"Drag assets here from Assets/_Project/Data/TowerDefinitions/ " +
|
|
||||||
"(or wherever they live). Asset name is used as the registry key.")]
|
|
||||||
[SerializeField] private TowerDefinition[] definitions;
|
|
||||||
|
|
||||||
// ----- Internal lookup table --------------------------------------
|
|
||||||
|
|
||||||
// Keyed by TowerDefinition.name (the asset name, not DisplayName).
|
|
||||||
private readonly Dictionary<string, TowerDefinition> byName
|
|
||||||
= new Dictionary<string, TowerDefinition>();
|
|
||||||
|
|
||||||
// ----- Lifecycle --------------------------------------------------
|
|
||||||
|
|
||||||
private void Awake()
|
|
||||||
{
|
|
||||||
if (Instance != null && Instance != this)
|
|
||||||
{
|
|
||||||
Debug.LogError("[TowerRegistry] Multiple instances detected. " +
|
|
||||||
"Only one TowerRegistry should exist per scene.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Instance = this;
|
|
||||||
|
|
||||||
BuildLookupTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
|
||||||
if (Instance == this) Instance = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----- Public API -------------------------------------------------
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the <see cref="TowerDefinition"/> whose asset name equals
|
|
||||||
/// <paramref name="assetName"/>, or null if no match is found.
|
|
||||||
/// </summary>
|
|
||||||
public TowerDefinition Get(string assetName)
|
|
||||||
{
|
|
||||||
byName.TryGetValue(assetName, out var def);
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns all registered tower definitions. Enumerates the internal
|
|
||||||
/// dictionary values — do not modify the returned collection.
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<TowerDefinition> All => byName.Values;
|
|
||||||
|
|
||||||
// ----- Private ----------------------------------------------------
|
|
||||||
|
|
||||||
private void BuildLookupTable()
|
|
||||||
{
|
|
||||||
byName.Clear();
|
|
||||||
|
|
||||||
if (definitions == null || definitions.Length == 0)
|
|
||||||
{
|
|
||||||
Debug.LogWarning("[TowerRegistry] No TowerDefinition assets assigned. " +
|
|
||||||
"Drag assets into the Definitions list on the TowerRegistry component.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var def in definitions)
|
|
||||||
{
|
|
||||||
if (def == null) continue;
|
|
||||||
|
|
||||||
if (byName.ContainsKey(def.name))
|
|
||||||
{
|
|
||||||
Debug.LogWarning($"[TowerRegistry] Duplicate asset name '{def.name}'. " +
|
|
||||||
$"Only the first entry will be used. Rename one of the assets.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
byName[def.name] = def;
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug.Log($"[TowerRegistry] Registered {byName.Count} tower definition(s).");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: a9dc0fbbe4422bc479ab8db7658c082b
|
|
||||||
32
Assets/_Project/Scripts/Towers/ConstructionPhaseSet.cs
Normal file
32
Assets/_Project/Scripts/Towers/ConstructionPhaseSet.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Assets/_Project/Scripts/Towers/ConstructionPhaseSet.cs
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace TD.Towers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An ordered set of construction-stage visuals a build site transitions between as a
|
||||||
|
/// tower is built — typically 3 assets (early → mid → late). A tower references its own
|
||||||
|
/// set via <see cref="TowerDefinition.ConstructionPhases"/>; build sites fall back to a
|
||||||
|
/// project-default set when a tower doesn't define one.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The entries are <b>shape</b> prefabs only. <c>BuildSiteVisual</c> applies the
|
||||||
|
/// queued (green) / constructing / paused materials and the owner tint on top, so the
|
||||||
|
/// phase assets don't need their own build-state materials. Keep them simple
|
||||||
|
/// (single material) — the build site swaps the active phase's renderer material.
|
||||||
|
/// </remarks>
|
||||||
|
[CreateAssetMenu(fileName = "ConstructionPhaseSet", menuName = "TD/Construction Phase Set")]
|
||||||
|
public class ConstructionPhaseSet : ScriptableObject
|
||||||
|
{
|
||||||
|
[Tooltip("Ordered construction-stage prefabs. Shown in sequence as the build " +
|
||||||
|
"progresses — e.g. 3 entries = early / mid / late thirds of the build.")]
|
||||||
|
[SerializeField] private GameObject[] phases;
|
||||||
|
|
||||||
|
/// <summary>Number of construction phases in this set.</summary>
|
||||||
|
public int PhaseCount => phases != null ? phases.Length : 0;
|
||||||
|
|
||||||
|
/// <summary>The phase prefab at <paramref name="index"/>, or null if out of range.</summary>
|
||||||
|
public GameObject GetPhase(int index)
|
||||||
|
=> (phases != null && index >= 0 && index < phases.Length) ? phases[index] : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/_Project/Scripts/Towers/ConstructionPhaseSet.cs.meta
Normal file
11
Assets/_Project/Scripts/Towers/ConstructionPhaseSet.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c8f2a4e1b9d6437052a1e8c4f7b3d069
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -68,6 +68,11 @@ namespace TD.Towers
|
||||||
"replace with a real mesh when art is available.")]
|
"replace with a real mesh when art is available.")]
|
||||||
public GameObject TowerPrefab;
|
public GameObject TowerPrefab;
|
||||||
|
|
||||||
|
[Tooltip("Optional per-tower construction-stage visuals shown while this tower is " +
|
||||||
|
"being built. Leave empty to use the project-default set assigned on the " +
|
||||||
|
"BuildSiteVisual prefab.")]
|
||||||
|
public ConstructionPhaseSet ConstructionPhases;
|
||||||
|
|
||||||
[Tooltip("Icon shown on this tower's tile in the HUD build menu. Auto-generated from " +
|
[Tooltip("Icon shown on this tower's tile in the HUD build menu. Auto-generated from " +
|
||||||
"the TowerPrefab by the 'TD/Generate Tower Icons' menu item, or assign a " +
|
"the TowerPrefab by the 'TD/Generate Tower Icons' menu item, or assign a " +
|
||||||
"Sprite manually. Null falls back to the grey placeholder icon.")]
|
"Sprite manually. Null falls back to the grey placeholder icon.")]
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ Unity **6.4 (6000.4.4f1)**, URP, IL2CPP, .NET Standard 2.1, Linear color space,
|
||||||
- **Visuals are placeholder** throughout (primitive/cone towers, sourced enemy models). See roadmap art TODOs.
|
- **Visuals are placeholder** throughout (primitive/cone towers, sourced enemy models). See roadmap art TODOs.
|
||||||
- **Enemies lack idle animation support** — needs adding across all enemy prefabs.
|
- **Enemies lack idle animation support** — needs adding across all enemy prefabs.
|
||||||
- **Tower footprint visuals don't fill their 2×2 space** — the cone/mesh sits centered and reads smaller than the tile area it occupies; should visually reflect the full footprint.
|
- **Tower footprint visuals don't fill their 2×2 space** — the cone/mesh sits centered and reads smaller than the tile area it occupies; should visually reflect the full footprint.
|
||||||
- **Two redundant tower lists:** `TowerPlacementManager.towerDefinitions[]` (by-index catalog) and `TowerRegistry.definitions[]` (by-name, for instance resolution). Candidate for consolidation.
|
- **Tower catalog is now a single source of truth:** `TowerPlacementManager.towerDefinitions[]` (by-index, = `TowerTypeId`). `TowerInstance` replicates that index and resolves via `TowerPlacementManager.GetDefinition`. *(The old by-name `TowerRegistry` was removed 2026-06-24 — add new towers only to `towerDefinitions` + `DraftPool`.)*
|
||||||
- **Catalog index 0 is a reserved sentinel** (valid `TowerTypeId`s start at 1) — easy to forget when wiring the catalog in the inspector.
|
- **Catalog index 0 is a reserved sentinel** (valid `TowerTypeId`s start at 1) — easy to forget when wiring the catalog in the inspector.
|
||||||
- **Catalog-index identifiers aren't session-stable** — blocks cross-match persistence until a stable ID is added.
|
- **Catalog-index identifiers aren't session-stable** — blocks cross-match persistence until a stable ID is added.
|
||||||
- **Paint system frozen**; **Race vs Builder** naming unresolved; the gold **"Buy Roll available any time"** rule is provisional and may change.
|
- **Paint system frozen**; **Race vs Builder** naming unresolved; the gold **"Buy Roll available any time"** rule is provisional and may change.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue