Compare commits

...

3 commits

Author SHA1 Message Date
Ben Calegari
c5c02ecc7e Fix cone make it look nice 2026-06-23 23:12:50 -07:00
Ben Calegari
4f57499e40 Seige tower 2026-06-23 23:12:48 -07:00
Ben Calegari
430e66bfbf Replace square with cone for Basic Arrow Tower. 2026-06-23 23:12:32 -07:00
24 changed files with 1079 additions and 105 deletions

View file

@ -24,6 +24,11 @@ MonoBehaviour:
SourcePrefabToOverride: {fileID: 0}
SourceHashToOverride: 0
OverridingTargetPrefab: {fileID: 0}
- Override: 0
Prefab: {fileID: 6482414459531823157, guid: 85ad5cd50543454891b343720f3048d6, type: 3}
SourcePrefabToOverride: {fileID: 0}
SourceHashToOverride: 0
OverridingTargetPrefab: {fileID: 0}
- Override: 0
Prefab: {fileID: 116861493430507844, guid: 3398cc5831880954487717577f61b6d7, type: 3}
SourcePrefabToOverride: {fileID: 0}

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cf1fa78cd62d44dd9882bb2d76bf1443
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/_Project/Art/Sprites/Towers/arrow.png (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1,101 @@
fileFormatVersion: 2
guid: afe216737d1b46e783889299bda1c252
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
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: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/_Project/Art/Sprites/Towers/siege.png (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1,101 @@
fileFormatVersion: 2
guid: 1423e4bda9704c3b826b0eb847c29c1c
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
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: []
outline: []
physicsShape: []
bones: []
spriteID: 7d2e9f1c4a6b3d850800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View file

@ -10,11 +10,11 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 7b353a757b6e6774d97e6fb8ba138fcc, type: 3}
m_Name: BasicTower
m_Name: BasicArrowTower
m_EditorClassIdentifier: Assembly-CSharp::TD.Towers.TowerDefinition
DisplayName: Basic Arrow
Description: Targets ground and air. Fires single-target arrows. The bread and butter
of any maze.
DisplayName: Basic Arrow Tower
Description: Single-target tower that fires arrows at ground and air enemies. The
backbone of any maze.
FootprintSize: {x: 2, y: 2}
GoldCost: 25
BuildTime: 0.5
@ -35,3 +35,4 @@ MonoBehaviour:
ProjectilePrefab: {fileID: 2664719039363295382, guid: dc2e4a4108e03874a8b2dab88dcc8fba, type: 3}
ProjectileSpeed: 15
UpgradePaths: []
Icon: {fileID: 21300000, guid: afe216737d1b46e783889299bda1c252, type: 3}

View file

@ -0,0 +1,38 @@
%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: 7b353a757b6e6774d97e6fb8ba138fcc, type: 3}
m_Name: SiegeCannonTower
m_EditorClassIdentifier: Assembly-CSharp::TD.Towers.TowerDefinition
DisplayName: Siege Cannon Tower
Description: Lobs a ballistic shell that deals splash damage where it lands. Targets
ground enemies only.
FootprintSize: {x: 2, y: 2}
GoldCost: 50
BuildTime: 0.5
TowerPrefab: {fileID: 6482414459531823157, guid: 85ad5cd50543454891b343720f3048d6, type: 3}
DamageType: 0
TargetPriority: 0
TargetType: 1
GroundedOnly: 1
Damage: 25
Range: 16
FireRate: 0.8
SplashRadius: 3
ChainCount: 0
ChainRange: 0
SlowFactor: 0
DotDamagePerSecond: 0
EffectDuration: 0
ProjectilePrefab: {fileID: 2664719039363295382, guid: dc2e4a4108e03874a8b2dab88dcc8fba, type: 3}
ProjectileSpeed: 10
UpgradePaths: []
Icon: {fileID: 21300000, guid: 1423e4bda9704c3b826b0eb847c29c1c, type: 3}

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 04219895bbea4fb9a94fd62fef35bf2a
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,321 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &39352475684176306
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 5753294230586596248}
- component: {fileID: 5360241685303413176}
m_Layer: 8
m_Name: SelectionVolume
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &5753294230586596248
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 39352475684176306}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1283036264165444500}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!65 &5360241685303413176
BoxCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 39352475684176306}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 1
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Size: {x: 1, y: 1, z: 1}
m_Center: {x: 0, y: 0, z: 0}
--- !u!1 &6482414459531823157
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1283036264165444500}
- component: {fileID: 6869333096494165105}
- component: {fileID: 4028055828417179692}
- component: {fileID: 5594214090440991794}
- component: {fileID: 7630870068340451557}
- component: {fileID: 9137031893466587143}
- component: {fileID: 805962841523123163}
- component: {fileID: 8853488620519990682}
- component: {fileID: 5360241685303413177}
m_Layer: 0
m_Name: Tower_BasicArrow
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1283036264165444500
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6482414459531823157}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 2, y: 1, z: 2}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 5753294230586596248}
- {fileID: 7547850274173754846}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!33 &6869333096494165105
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6482414459531823157}
m_Mesh: {fileID: 0}
--- !u!23 &4028055828417179692
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6482414459531823157}
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 &5594214090440991794
BoxCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6482414459531823157}
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}
--- !u!114 &7630870068340451557
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6482414459531823157}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject
GlobalObjectIdHash: 2767478135
InScenePlacedSourceGlobalObjectIdHash: 0
DeferredDespawnTick: 0
Ownership: 1
AlwaysReplicateAsRoot: 0
SynchronizeTransform: 1
ActiveSceneSynchronization: 0
SceneMigrationSynchronization: 0
SpawnWithObservers: 1
DontDestroyWithOwner: 0
AutoObjectParentSync: 1
SyncOwnerTransformWhenParented: 1
AllowOwnerToParent: 0
--- !u!114 &9137031893466587143
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6482414459531823157}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fb111fc88b3d6a340a3abde5a1502af3, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.TowerInstance
ShowTopMostFoldoutHeaderGroup: 1
tintedRenderers:
- {fileID: 4028055828417179692}
--- !u!114 &805962841523123163
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6482414459531823157}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 7eb6cce6cd96b23478b7d2173cebf74d, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::TD.Combat.TowerCombat
ShowTopMostFoldoutHeaderGroup: 1
enemyLayerMask:
serializedVersion: 2
m_Bits: 1024
--- !u!114 &8853488620519990682
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6482414459531823157}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c0edb0c5206ca454bbd7c300c6cc7574, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::TD.Combat.TowerRangeIndicator
rangeProjector: {fileID: 8255517343120954594}
projectionDepth: 50
--- !u!114 &5360241685303413177
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6482414459531823157}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 93bc533262394e1e8b122bbfad89391a, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::TD.Visuals.ConeMesh
sides: 4
radius: 0.7071068
height: 1.5
angularOffsetDegrees: 45
--- !u!1 &7580197837852108944
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7547850274173754846}
- component: {fileID: 8255517343120954594}
m_Layer: 0
m_Name: RangeIndicator
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &7547850274173754846
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7580197837852108944}
serializedVersion: 2
m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: 0.7071068}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1283036264165444500}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &8255517343120954594
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7580197837852108944}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0777d029ed3dffa4692f417d4aba19ca, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.DecalProjector
m_Material: {fileID: 2100000, guid: f99227cbde481ce47a2527e6bca709d2, type: 2}
m_DrawDistance: 1000
m_FadeScale: 0.9
m_StartAngleFade: 180
m_EndAngleFade: 180
m_UVScale: {x: 1, y: 1}
m_UVBias: {x: 0, y: 0}
m_RenderingLayerMask:
serializedVersion: 0
m_Bits: 1
m_ScaleMode: 0
m_Offset: {x: 0, y: 0, z: 0.5}
m_Size: {x: 1, y: 1, z: 1}
m_FadeFactor: 1
m_VisibleInScene: 1
version: 1
m_DecalLayerMask: 1

View file

@ -70,7 +70,7 @@ GameObject:
- component: {fileID: 805962841523123163}
- component: {fileID: 8853488620519990682}
m_Layer: 0
m_Name: Tower_Basic
m_Name: Tower_SiegeCannon
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -86,7 +86,7 @@ Transform:
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 2, y: 1, z: 2}
m_LocalScale: {x: 2, y: 0.5, z: 2}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 5753294230586596248}
@ -100,7 +100,7 @@ MeshFilter:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6482414459531823157}
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0}
--- !u!23 &4028055828417179692
MeshRenderer:
m_ObjectHideFlags: 0
@ -181,9 +181,9 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
m_Name:
m_Name:
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject
GlobalObjectIdHash: 2767478135
GlobalObjectIdHash: 3344551122
InScenePlacedSourceGlobalObjectIdHash: 0
DeferredDespawnTick: 0
Ownership: 1
@ -206,7 +206,7 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fb111fc88b3d6a340a3abde5a1502af3, type: 3}
m_Name:
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.TowerInstance
ShowTopMostFoldoutHeaderGroup: 1
tintedRenderers:
@ -221,7 +221,7 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 7eb6cce6cd96b23478b7d2173cebf74d, type: 3}
m_Name:
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::TD.Combat.TowerCombat
ShowTopMostFoldoutHeaderGroup: 1
enemyLayerMask:
@ -237,7 +237,7 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c0edb0c5206ca454bbd7c300c6cc7574, type: 3}
m_Name:
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::TD.Combat.TowerRangeIndicator
rangeProjector: {fileID: 8255517343120954594}
projectionDepth: 50
@ -283,7 +283,7 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0777d029ed3dffa4692f417d4aba19ca, type: 3}
m_Name:
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.DecalProjector
m_Material: {fileID: 2100000, guid: f99227cbde481ce47a2527e6bca709d2, type: 2}
m_DrawDistance: 1000

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 85ad5cd50543454891b343720f3048d6
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -632,8 +632,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -1371,8 +1371,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -2379,8 +2379,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -2983,8 +2983,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -3161,8 +3161,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -4477,8 +4477,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -6479,8 +6479,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -6657,8 +6657,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -6905,8 +6905,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -7795,8 +7795,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -7973,8 +7973,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -8541,8 +8541,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -9075,8 +9075,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -9679,8 +9679,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -10247,8 +10247,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -11137,8 +11137,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -11315,8 +11315,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -12205,8 +12205,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -13489,8 +13489,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -13805,8 +13805,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -13983,8 +13983,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -14514,8 +14514,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -15124,8 +15124,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -15892,8 +15892,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -16172,8 +16172,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -16706,8 +16706,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -17308,8 +17308,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -17486,8 +17486,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -17799,8 +17799,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -18061,8 +18061,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -18307,8 +18307,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -19657,8 +19657,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -19774,6 +19774,7 @@ MonoBehaviour:
- {fileID: 11400000, guid: 0f693e29ca953e1439e10cb8f12e4b30, type: 2}
- {fileID: 11400000, guid: c4a1f7e92b6d8a4e3f0c9b1d6e5a2f80, type: 2}
- {fileID: 11400000, guid: d5b2e8fa3c7e9b5f4a1d0c2e7f6b3a91, type: 2}
- {fileID: 11400000, guid: 04219895bbea4fb9a94fd62fef35bf2a, type: 2}
startingDeck:
- {fileID: 11400000, guid: d5b2e8fa3c7e9b5f4a1d0c2e7f6b3a91, type: 2}
- {fileID: 11400000, guid: 0f693e29ca953e1439e10cb8f12e4b30, type: 2}
@ -19909,6 +19910,7 @@ MonoBehaviour:
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.TowerRegistry
definitions:
- {fileID: 11400000, guid: 0f693e29ca953e1439e10cb8f12e4b30, type: 2}
- {fileID: 11400000, guid: 04219895bbea4fb9a94fd62fef35bf2a, type: 2}
--- !u!1 &1547583984
GameObject:
m_ObjectHideFlags: 0
@ -20625,8 +20627,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -21229,8 +21231,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -21407,8 +21409,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -21941,8 +21943,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -22475,8 +22477,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -23123,8 +23125,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -25020,8 +25022,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -25554,8 +25556,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -26181,8 +26183,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -27139,8 +27141,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -27387,8 +27389,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -27565,8 +27567,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -27743,8 +27745,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2
@ -28347,8 +28349,8 @@ Mesh:
m_CookingOptions: 30
m_BakedConvexCollisionMesh:
m_BakedTriangleCollisionMesh:
'm_MeshMetrics[0]': 1
'm_MeshMetrics[1]': 1
m_MeshMetrics[0]: 1
m_MeshMetrics[1]: 1
m_MeshOptimizationFlags: 1
m_StreamData:
serializedVersion: 2

View file

@ -1842,6 +1842,7 @@ MonoBehaviour:
towerDefinitions:
- {fileID: 0}
- {fileID: 11400000, guid: 0f693e29ca953e1439e10cb8f12e4b30, type: 2}
- {fileID: 11400000, guid: 04219895bbea4fb9a94fd62fef35bf2a, type: 2}
--- !u!4 &1507514109
Transform:
m_ObjectHideFlags: 0
@ -1903,6 +1904,7 @@ MonoBehaviour:
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.TowerRegistry
definitions:
- {fileID: 11400000, guid: 0f693e29ca953e1439e10cb8f12e4b30, type: 2}
- {fileID: 11400000, guid: 04219895bbea4fb9a94fd62fef35bf2a, type: 2}
--- !u!1 &1597884408
GameObject:
m_ObjectHideFlags: 0

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2bef66c4dde743cc87f8272b863c12d4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,190 @@
// Assets/_Project/Scripts/Editor/Towers/TowerIconGenerator.cs
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using TD.Towers;
namespace TD.Towers.Editor
{
/// <summary>
/// Editor utility that renders each <see cref="TowerDefinition"/>'s prefab to a square
/// thumbnail PNG and assigns it back to the definition's <c>Icon</c> field, so the HUD
/// build menu shows "how the building looks when built" on each tower tile.
/// </summary>
/// <remarks>
/// Run via <b>TD &gt; Generate Tower Icons</b>. Uses <see cref="PreviewRenderUtility"/>
/// (synchronous, controllable) rather than the async <c>AssetPreview</c> API so the whole
/// pass completes within the menu callback. Generated PNGs are written to
/// <c>Assets/_Project/Art/Sprites/Towers/</c>, imported as Sprites, and wired onto the
/// matching asset. Re-running regenerates and overwrites in place.
/// </remarks>
public static class TowerIconGenerator
{
private const string OutputFolder = "Assets/_Project/Art/Sprites/Towers";
private const int IconSize = 128;
[MenuItem("TD/Generate Tower Icons")]
public static void GenerateAll()
{
EnsureFolder(OutputFolder);
string[] guids = AssetDatabase.FindAssets("t:TowerDefinition");
if (guids.Length == 0)
{
Debug.LogWarning("[TowerIconGenerator] No TowerDefinition assets found.");
return;
}
int generated = 0;
try
{
foreach (string guid in guids)
{
string defPath = AssetDatabase.GUIDToAssetPath(guid);
var def = AssetDatabase.LoadAssetAtPath<TowerDefinition>(defPath);
if (def == null || def.TowerPrefab == null)
{
Debug.LogWarning($"[TowerIconGenerator] Skipping '{defPath}' — " +
"missing TowerDefinition or TowerPrefab.");
continue;
}
Texture2D icon = RenderPrefabIcon(def.TowerPrefab);
if (icon == null) continue;
string pngPath = $"{OutputFolder}/{def.name}.png";
File.WriteAllBytes(pngPath, icon.EncodeToPNG());
Object.DestroyImmediate(icon);
AssetDatabase.ImportAsset(pngPath, ImportAssetOptions.ForceSynchronousImport);
ConfigureAsSprite(pngPath);
var sprite = AssetDatabase.LoadAssetAtPath<Sprite>(pngPath);
AssignIcon(def, sprite);
generated++;
}
}
finally
{
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
Debug.Log($"[TowerIconGenerator] Generated {generated} tower icon(s) into {OutputFolder}.");
}
// ----- Rendering --------------------------------------------------
private static Texture2D RenderPrefabIcon(GameObject prefab)
{
var pru = new PreviewRenderUtility();
GameObject instance = null;
try
{
instance = Object.Instantiate(prefab);
instance.hideFlags = HideFlags.HideAndDontSave;
pru.AddSingleGO(instance);
if (!TryGetWorldBounds(instance, out Bounds bounds))
{
Debug.LogWarning($"[TowerIconGenerator] '{prefab.name}' has no renderers to capture.");
return null;
}
// 3/4 view framed to the prefab's combined bounds.
const float fov = 30f;
float radius = Mathf.Max(bounds.extents.magnitude, 0.01f);
float distance = radius / Mathf.Sin(Mathf.Deg2Rad * fov * 0.5f) * 1.15f;
Quaternion dir = Quaternion.Euler(20f, 135f, 0f);
var cam = pru.camera;
cam.fieldOfView = fov;
cam.transform.rotation = dir;
cam.transform.position = bounds.center - dir * Vector3.forward * distance;
cam.nearClipPlane = 0.01f;
cam.farClipPlane = distance * 4f;
cam.clearFlags = CameraClearFlags.SolidColor;
cam.backgroundColor = new Color(0f, 0f, 0f, 0f); // transparent
pru.lights[0].intensity = 1.2f;
pru.lights[0].transform.rotation = Quaternion.Euler(40f, 40f, 0f);
pru.lights[1].intensity = 0.6f;
pru.ambientColor = new Color(0.35f, 0.35f, 0.35f, 1f);
var rect = new Rect(0, 0, IconSize, IconSize);
pru.BeginPreview(rect, GUIStyle.none);
pru.camera.Render();
Texture rendered = pru.EndPreview();
var result = new Texture2D(IconSize, IconSize, TextureFormat.RGBA32, false);
RenderTexture prev = RenderTexture.active;
RenderTexture.active = rendered as RenderTexture;
result.ReadPixels(rect, 0, 0);
result.Apply();
RenderTexture.active = prev;
return result;
}
finally
{
if (instance != null) Object.DestroyImmediate(instance);
pru.Cleanup();
}
}
private static bool TryGetWorldBounds(GameObject go, out Bounds bounds)
{
var renderers = go.GetComponentsInChildren<Renderer>();
bounds = default;
bool any = false;
foreach (var r in renderers)
{
// Skip projector/decal-style renderers that don't represent the tower body.
if (r is MeshRenderer || r is SkinnedMeshRenderer)
{
if (!any) { bounds = r.bounds; any = true; }
else { bounds.Encapsulate(r.bounds); }
}
}
return any;
}
// ----- Asset wiring -----------------------------------------------
private static void ConfigureAsSprite(string pngPath)
{
var importer = AssetImporter.GetAtPath(pngPath) as TextureImporter;
if (importer == null) return;
importer.textureType = TextureImporterType.Sprite;
importer.spriteImportMode = SpriteImportMode.Single;
importer.alphaIsTransparency = true;
importer.mipmapEnabled = false;
importer.SaveAndReimport();
}
private static void AssignIcon(TowerDefinition def, Sprite sprite)
{
if (sprite == null) return;
var so = new SerializedObject(def);
so.FindProperty("Icon").objectReferenceValue = sprite;
so.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(def);
}
private static void EnsureFolder(string assetFolder)
{
if (AssetDatabase.IsValidFolder(assetFolder)) return;
string[] parts = assetFolder.Split('/');
string current = parts[0]; // "Assets"
for (int i = 1; i < parts.Length; i++)
{
string next = $"{current}/{parts[i]}";
if (!AssetDatabase.IsValidFolder(next))
AssetDatabase.CreateFolder(current, parts[i]);
current = next;
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: de83f68d5958449185d2a0c8199c41ec
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -68,6 +68,11 @@ namespace TD.Towers
"replace with a real mesh when art is available.")]
public GameObject TowerPrefab;
[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 " +
"Sprite manually. Null falls back to the grey placeholder icon.")]
public Sprite Icon;
// -------------------------------------------------------------------
// Combat
// -------------------------------------------------------------------

View file

@ -858,6 +858,15 @@ namespace TD.UI
Debug.LogWarning("[HUDController] No TowerPlacementController assigned.");
});
// Show the tower's thumbnail on the icon placeholder. Falls back to the grey
// placeholder square when no Icon is assigned (see CreatePaintButton for the pattern).
if (def.Icon != null)
{
var icon = btn.Q<VisualElement>(null, "cmd-icon-placeholder");
if (icon != null)
icon.style.backgroundImage = new StyleBackground(def.Icon);
}
btn.RegisterCallback<MouseEnterEvent>(_ => ShowTooltip(def));
btn.RegisterCallback<MouseLeaveEvent>(_ => ClearTooltip());
return btn;

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 16f3da2efd0d4431888e3f04056646c2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,132 @@
// Assets/_Project/Scripts/Visuals/ConeMesh.cs
using UnityEngine;
namespace TD.Visuals
{
/// <summary>
/// Procedurally generates a cone mesh and assigns it to the GameObject's
/// <see cref="MeshFilter"/>. Unity ships no built-in cone primitive, so this
/// fills that gap for tower visuals (e.g. the Basic Arrow Tower).
/// </summary>
/// <remarks>
/// <b>Visual only.</b> No networking, no collision — the mesh is purely cosmetic.
/// The existing MeshRenderer + material (and any owner/paint tinting via
/// <c>TowerInstance.tintedRenderers</c>) keep working unchanged.
///
/// <b>Pivot.</b> The cone is centred on the local origin: its base ring sits at
/// <c>y = -height/2</c> and its apex at <c>y = +height/2</c>, matching the vertical
/// extents of a unit cube so it sits on a build tile the same way the old cube did.
///
/// <b>Edit-time.</b> <c>[ExecuteAlways]</c> rebuilds the mesh in the editor so the
/// cone is visible without entering play mode. The generated mesh is flagged
/// <c>HideFlags.DontSave</c> so it is never written out as a project asset.
/// </remarks>
[ExecuteAlways]
[RequireComponent(typeof(MeshFilter))]
public class ConeMesh : MonoBehaviour
{
[Tooltip("Number of radial segments around the base. Higher = smoother circle.")]
[Range(3, 64)]
[SerializeField] private int sides = 16;
[Tooltip("Radius of the cone's base in local units.")]
[Min(0.001f)]
[SerializeField] private float radius = 0.5f;
[Tooltip("Height of the cone from base to apex in local units.")]
[Min(0.001f)]
[SerializeField] private float height = 1f;
[Tooltip("Rotation of the base ring around the vertical axis, in degrees. With a low " +
"side count this makes a pyramid; e.g. sides = 4 with a 45° offset and " +
"radius 0.7071 yields a square-based pyramid whose faces align to the X/Z axes.")]
[SerializeField] private float angularOffsetDegrees = 0f;
private Mesh mesh;
private void OnEnable() => Rebuild();
private void OnValidate()
{
// OnValidate can fire before OnEnable in the editor; guard the component.
if (isActiveAndEnabled) Rebuild();
}
private void OnDisable()
{
// Clean up the generated mesh so it doesn't linger when the object is destroyed.
if (mesh != null)
{
if (Application.isPlaying) Destroy(mesh);
else DestroyImmediate(mesh);
mesh = null;
}
}
private void Rebuild()
{
var filter = GetComponent<MeshFilter>();
if (filter == null) return;
if (mesh == null)
{
mesh = new Mesh { name = "ProceduralCone", hideFlags = HideFlags.DontSave };
}
BuildCone(mesh);
filter.sharedMesh = mesh;
}
private void BuildCone(Mesh target)
{
target.Clear();
float halfHeight = height * 0.5f;
// Vertex layout:
// [0 .. sides-1] base ring
// [sides] apex
// [sides + 1] base centre (for the bottom cap)
int baseRingStart = 0;
int apexIndex = sides;
int baseCentreIndex = sides + 1;
var vertices = new Vector3[sides + 2];
for (int i = 0; i < sides; i++)
{
float angle = (i / (float)sides) * Mathf.PI * 2f
+ angularOffsetDegrees * Mathf.Deg2Rad;
vertices[baseRingStart + i] = new Vector3(
Mathf.Cos(angle) * radius,
-halfHeight,
Mathf.Sin(angle) * radius);
}
vertices[apexIndex] = new Vector3(0f, halfHeight, 0f);
vertices[baseCentreIndex] = new Vector3(0f, -halfHeight, 0f);
// Side faces (base ring -> apex) + base cap (fan from centre).
// Wind both so they face outward / downward respectively.
var triangles = new int[sides * 3 * 2];
int t = 0;
for (int i = 0; i < sides; i++)
{
int next = (i + 1) % sides;
// Side triangle, outward-facing.
triangles[t++] = baseRingStart + i;
triangles[t++] = apexIndex;
triangles[t++] = baseRingStart + next;
// Base cap triangle, downward-facing.
triangles[t++] = baseCentreIndex;
triangles[t++] = baseRingStart + next;
triangles[t++] = baseRingStart + i;
}
target.vertices = vertices;
target.triangles = triangles;
target.RecalculateNormals();
target.RecalculateBounds();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 93bc533262394e1e8b122bbfad89391a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: