Adding Text Mesh Pro, new enemies, new enemy waves, new HUD functionality, New animators, a retry function, and floating text for gold earned and lives lost.
This commit is contained in:
parent
3287e8ea43
commit
f6cc6a7102
110 changed files with 62003 additions and 251 deletions
8
Assets/_Project/Art/Animators/Enemies.meta
Normal file
8
Assets/_Project/Art/Animators/Enemies.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 93a96a8b7e15d504798f1e8b430c76e8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!91 &9100000
|
||||
AnimatorController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: EnemySkeletonAnimator
|
||||
serializedVersion: 6
|
||||
m_AnimatorParameters:
|
||||
- m_Name: Die
|
||||
m_Type: 9
|
||||
m_DefaultFloat: 0
|
||||
m_DefaultInt: 0
|
||||
m_DefaultBool: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
m_AnimatorLayers:
|
||||
- serializedVersion: 5
|
||||
m_Name: Base Layer
|
||||
m_StateMachine: {fileID: 1620617716871135161}
|
||||
m_Mask: {fileID: 0}
|
||||
m_Motions: []
|
||||
m_Behaviours: []
|
||||
m_BlendingMode: 0
|
||||
m_SyncedLayerIndex: -1
|
||||
m_DefaultWeight: 0
|
||||
m_IKPass: 0
|
||||
m_SyncedLayerAffectsTiming: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
m_EvaluateTransitionsOnStart: 1
|
||||
--- !u!1102 &1182561839893906908
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Skeleton@Death01_A
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: -4847777627775502037, guid: 254689aa2c1fc52488b6438382c952c8, type: 3}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!1107 &1620617716871135161
|
||||
AnimatorStateMachine:
|
||||
serializedVersion: 7
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Base Layer
|
||||
m_ChildStates:
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: 6235073201492022766}
|
||||
m_Position: {x: 370, y: -40, z: 0}
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: 1182561839893906908}
|
||||
m_Position: {x: 360, y: 180, z: 0}
|
||||
m_ChildStateMachines: []
|
||||
m_AnyStateTransitions: []
|
||||
m_EntryTransitions: []
|
||||
m_StateMachineTransitions: {}
|
||||
m_StateMachineBehaviours: []
|
||||
m_AnyStatePosition: {x: 50, y: 20, z: 0}
|
||||
m_EntryPosition: {x: 50, y: 120, z: 0}
|
||||
m_ExitPosition: {x: 800, y: 120, z: 0}
|
||||
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
|
||||
m_DefaultState: {fileID: 6235073201492022766}
|
||||
--- !u!1101 &4222458529535344503
|
||||
AnimatorStateTransition:
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_Conditions:
|
||||
- m_ConditionMode: 1
|
||||
m_ConditionEvent: Die
|
||||
m_EventTreshold: 0
|
||||
m_DstStateMachine: {fileID: 0}
|
||||
m_DstState: {fileID: 1182561839893906908}
|
||||
m_Solo: 0
|
||||
m_Mute: 0
|
||||
m_IsExit: 0
|
||||
serializedVersion: 3
|
||||
m_TransitionDuration: 0.1
|
||||
m_TransitionOffset: 0
|
||||
m_ExitTime: 0.5833334
|
||||
m_HasExitTime: 0
|
||||
m_HasFixedDuration: 1
|
||||
m_InterruptionSource: 0
|
||||
m_OrderedInterruption: 1
|
||||
m_CanTransitionToSelf: 1
|
||||
--- !u!1102 &6235073201492022766
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: HumanM@Run01_Forward
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions:
|
||||
- {fileID: 4222458529535344503}
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 3094330708855449807, guid: 6deac83e30d8acd4cbb8c7d8a11545bd, type: 3}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f58771ae35073b248ad74dc8df86202a
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 9100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -10,7 +10,7 @@ MonoBehaviour:
|
|||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: c0d2521d49d21fe4380434f5951944d1, type: 3}
|
||||
m_Name: EnemyDefinition
|
||||
m_Name: 01_SkeletonDefinition
|
||||
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyDefinition
|
||||
DisplayName: Basic Bitch
|
||||
MaxHp: 100
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
%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: c0d2521d49d21fe4380434f5951944d1, type: 3}
|
||||
m_Name: 02_RedSkeletonDefinition
|
||||
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyDefinition
|
||||
DisplayName: Reddy Boi
|
||||
MaxHp: 500
|
||||
MoveSpeed: 3
|
||||
IsFlying: 0
|
||||
GoldReward: 15
|
||||
LivesCost: 1
|
||||
EnemyPrefab: {fileID: 1455822126534880203, guid: 51ab567e92e18f34eb7848588e3c4479, type: 3}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6e0d4bffb987ed448a76fd2a7d31cb38
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -16,7 +16,7 @@ MonoBehaviour:
|
|||
Description:
|
||||
FootprintSize: {x: 2, y: 2}
|
||||
GoldCost: 25
|
||||
BuildTime: 4
|
||||
BuildTime: 0.5
|
||||
TowerPrefab: {fileID: 6482414459531823157, guid: 1511641f145758b469e64376d2a0d434, type: 3}
|
||||
DamageType: 0
|
||||
TargetPriority: 0
|
||||
|
|
|
|||
19
Assets/_Project/Data/WaveDefinitions/Wave2Definition.asset
Normal file
19
Assets/_Project/Data/WaveDefinitions/Wave2Definition.asset
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
%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: 48e93688dc0fb5b4cbe7be9a241b4421, type: 3}
|
||||
m_Name: Wave2Definition
|
||||
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.WaveDefinition
|
||||
PrepTime: 10
|
||||
Entries:
|
||||
- EnemyType: {fileID: 11400000, guid: 6e0d4bffb987ed448a76fd2a7d31cb38, type: 2}
|
||||
Count: 50
|
||||
SpawnInterval: 0.5
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 190e39db44aa0794aa808fd60976f7c4
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -51,7 +51,7 @@ MonoBehaviour:
|
|||
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject
|
||||
GlobalObjectIdHash: 472470935
|
||||
GlobalObjectIdHash: 2050641840
|
||||
InScenePlacedSourceGlobalObjectIdHash: 0
|
||||
DeferredDespawnTick: 0
|
||||
Ownership: 1
|
||||
|
|
|
|||
|
|
@ -1,229 +0,0 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &1455822126534880203
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3374291962137961512}
|
||||
- component: {fileID: 6900825049490657874}
|
||||
- component: {fileID: 3838554347222657907}
|
||||
- component: {fileID: 2827184357573667590}
|
||||
- component: {fileID: 3180894108125880274}
|
||||
- component: {fileID: 5830540397649648793}
|
||||
- component: {fileID: 2892684246239657319}
|
||||
- component: {fileID: 8213527798879671990}
|
||||
- component: {fileID: 3283904430289710888}
|
||||
m_Layer: 10
|
||||
m_Name: EnemyPlaceholder
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &3374291962137961512
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 19.2967, y: 0.5, z: 17.39775}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!33 &6900825049490657874
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!23 &3838554347222657907
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
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 &2827184357573667590
|
||||
BoxCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
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 &3180894108125880274
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
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: 1257430264
|
||||
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 &5830540397649648793
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: e96cb6065543e43c4a752faaa1468eb1, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.Components.NetworkTransform
|
||||
ShowTopMostFoldoutHeaderGroup: 1
|
||||
NetworkTransformExpanded: 0
|
||||
AutoOwnerAuthorityTickOffset: 1
|
||||
PositionInterpolationType: 0
|
||||
RotationInterpolationType: 0
|
||||
ScaleInterpolationType: 0
|
||||
PositionLerpSmoothing: 1
|
||||
PositionMaxInterpolationTime: 0.1
|
||||
RotationLerpSmoothing: 1
|
||||
RotationMaxInterpolationTime: 0.1
|
||||
ScaleLerpSmoothing: 1
|
||||
ScaleMaxInterpolationTime: 0.1
|
||||
AuthorityMode: 0
|
||||
TickSyncChildren: 0
|
||||
UseUnreliableDeltas: 0
|
||||
SyncPositionX: 1
|
||||
SyncPositionY: 1
|
||||
SyncPositionZ: 1
|
||||
SyncRotAngleX: 1
|
||||
SyncRotAngleY: 1
|
||||
SyncRotAngleZ: 1
|
||||
SyncScaleX: 1
|
||||
SyncScaleY: 1
|
||||
SyncScaleZ: 1
|
||||
PositionThreshold: 0.001
|
||||
RotAngleThreshold: 0.01
|
||||
ScaleThreshold: 0.01
|
||||
UseQuaternionSynchronization: 0
|
||||
UseQuaternionCompression: 0
|
||||
UseHalfFloatPrecision: 0
|
||||
InLocalSpace: 0
|
||||
SwitchTransformSpaceWhenParented: 0
|
||||
Interpolate: 1
|
||||
SlerpPosition: 0
|
||||
--- !u!114 &2892684246239657319
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 21dea26768768b8449a8924f638557be, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyHealth
|
||||
ShowTopMostFoldoutHeaderGroup: 1
|
||||
--- !u!114 &8213527798879671990
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 292d1b92cd49dc74f8dfd74cdbe4ece7, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyStatus
|
||||
ShowTopMostFoldoutHeaderGroup: 1
|
||||
--- !u!114 &3283904430289710888
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fd6c02bbcc13fb14a9d596d9a2544dcc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyMovement
|
||||
ShowTopMostFoldoutHeaderGroup: 1
|
||||
341
Assets/_Project/Prefabs/Enemies/EnemySkeleton.prefab
Normal file
341
Assets/_Project/Prefabs/Enemies/EnemySkeleton.prefab
Normal file
|
|
@ -0,0 +1,341 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &1455822126534880203
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3374291962137961512}
|
||||
- component: {fileID: 3180894108125880274}
|
||||
- component: {fileID: 5830540397649648793}
|
||||
- component: {fileID: 2892684246239657319}
|
||||
- component: {fileID: 8213527798879671990}
|
||||
- component: {fileID: 3283904430289710888}
|
||||
- component: {fileID: 3756613737869398948}
|
||||
- component: {fileID: 6036713598566100742}
|
||||
m_Layer: 10
|
||||
m_Name: EnemySkeleton
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &3374291962137961512
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
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:
|
||||
- {fileID: 3204018639052561865}
|
||||
- {fileID: 1842595068747212269}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &3180894108125880274
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
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: 1257430264
|
||||
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 &5830540397649648793
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: e96cb6065543e43c4a752faaa1468eb1, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.Components.NetworkTransform
|
||||
ShowTopMostFoldoutHeaderGroup: 1
|
||||
NetworkTransformExpanded: 0
|
||||
AutoOwnerAuthorityTickOffset: 1
|
||||
PositionInterpolationType: 0
|
||||
RotationInterpolationType: 0
|
||||
ScaleInterpolationType: 0
|
||||
PositionLerpSmoothing: 1
|
||||
PositionMaxInterpolationTime: 0.1
|
||||
RotationLerpSmoothing: 1
|
||||
RotationMaxInterpolationTime: 0.1
|
||||
ScaleLerpSmoothing: 1
|
||||
ScaleMaxInterpolationTime: 0.1
|
||||
AuthorityMode: 0
|
||||
TickSyncChildren: 0
|
||||
UseUnreliableDeltas: 0
|
||||
SyncPositionX: 1
|
||||
SyncPositionY: 1
|
||||
SyncPositionZ: 1
|
||||
SyncRotAngleX: 1
|
||||
SyncRotAngleY: 1
|
||||
SyncRotAngleZ: 1
|
||||
SyncScaleX: 1
|
||||
SyncScaleY: 1
|
||||
SyncScaleZ: 1
|
||||
PositionThreshold: 0.001
|
||||
RotAngleThreshold: 0.01
|
||||
ScaleThreshold: 0.01
|
||||
UseQuaternionSynchronization: 0
|
||||
UseQuaternionCompression: 0
|
||||
UseHalfFloatPrecision: 0
|
||||
InLocalSpace: 0
|
||||
SwitchTransformSpaceWhenParented: 0
|
||||
Interpolate: 1
|
||||
SlerpPosition: 0
|
||||
--- !u!114 &2892684246239657319
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 21dea26768768b8449a8924f638557be, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyHealth
|
||||
ShowTopMostFoldoutHeaderGroup: 1
|
||||
definition: {fileID: 11400000, guid: 4e85a539eac1ed64cbd972db4914ca3d, type: 2}
|
||||
deathAnimator: {fileID: 8833486512991012787}
|
||||
deathAnimationDuration: 1.5
|
||||
sinkDuration: 1.5
|
||||
sinkDepth: 1.5
|
||||
--- !u!114 &8213527798879671990
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 292d1b92cd49dc74f8dfd74cdbe4ece7, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyStatus
|
||||
ShowTopMostFoldoutHeaderGroup: 1
|
||||
--- !u!114 &3283904430289710888
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fd6c02bbcc13fb14a9d596d9a2544dcc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyMovement
|
||||
ShowTopMostFoldoutHeaderGroup: 1
|
||||
--- !u!114 &3756613737869398948
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: e8d0727d5ae3244e3b569694d3912374, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.Components.NetworkAnimator
|
||||
ShowTopMostFoldoutHeaderGroup: 1
|
||||
NetworkAnimatorExpanded: 0
|
||||
AuthorityMode: 0
|
||||
m_Animator: {fileID: 8833486512991012787}
|
||||
TransitionStateInfoList:
|
||||
- IsCrossFadeExit: 0
|
||||
Layer: 0
|
||||
OriginatingState: -797153096
|
||||
DestinationState: -908201951
|
||||
TransitionDuration: 0.1
|
||||
TriggerNameHash: 20298039
|
||||
TransitionIndex: 0
|
||||
AnimatorParameterEntries:
|
||||
ParameterEntries:
|
||||
- name: Die
|
||||
NameHash: 20298039
|
||||
Synchronize: 1
|
||||
ParameterType: 9
|
||||
AnimatorParametersExpanded: 0
|
||||
--- !u!136 &6036713598566100742
|
||||
CapsuleCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
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: 2
|
||||
m_Radius: 0.5
|
||||
m_Height: 2
|
||||
m_Direction: 1
|
||||
m_Center: {x: 0, y: 1, z: 0}
|
||||
--- !u!1 &6643184210540843465
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1842595068747212269}
|
||||
- component: {fileID: 9502913309531327}
|
||||
m_Layer: 8
|
||||
m_Name: SelectionTrigger
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &1842595068747212269
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6643184210540843465}
|
||||
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: 3374291962137961512}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!136 &9502913309531327
|
||||
CapsuleCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6643184210540843465}
|
||||
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: 2
|
||||
m_Radius: 0.5
|
||||
m_Height: 2
|
||||
m_Direction: 1
|
||||
m_Center: {x: 0, y: 1, z: 0}
|
||||
--- !u!1001 &3169492382559779362
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
serializedVersion: 3
|
||||
m_TransformParent: {fileID: 3374291962137961512}
|
||||
m_Modifications:
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalPosition.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalPosition.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalPosition.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalRotation.w
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalRotation.x
|
||||
value: -0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalRotation.y
|
||||
value: -0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalRotation.z
|
||||
value: -0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 919132149155446097, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_Name
|
||||
value: Skeleton
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5866666021909216657, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_Controller
|
||||
value:
|
||||
objectReference: {fileID: 9100000, guid: f58771ae35073b248ad74dc8df86202a, type: 2}
|
||||
- target: {fileID: 5866666021909216657, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_ApplyRootMotion
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
m_SourcePrefab: {fileID: 100100000, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
--- !u!4 &3204018639052561865 stripped
|
||||
Transform:
|
||||
m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
m_PrefabInstance: {fileID: 3169492382559779362}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
--- !u!95 &8833486512991012787 stripped
|
||||
Animator:
|
||||
m_CorrespondingSourceObject: {fileID: 5866666021909216657, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
m_PrefabInstance: {fileID: 3169492382559779362}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
345
Assets/_Project/Prefabs/Enemies/EnemySkeletonRed.prefab
Normal file
345
Assets/_Project/Prefabs/Enemies/EnemySkeletonRed.prefab
Normal file
|
|
@ -0,0 +1,345 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &1455822126534880203
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3374291962137961512}
|
||||
- component: {fileID: 3180894108125880274}
|
||||
- component: {fileID: 5830540397649648793}
|
||||
- component: {fileID: 2892684246239657319}
|
||||
- component: {fileID: 8213527798879671990}
|
||||
- component: {fileID: 3283904430289710888}
|
||||
- component: {fileID: 3756613737869398948}
|
||||
- component: {fileID: 6036713598566100742}
|
||||
m_Layer: 10
|
||||
m_Name: EnemySkeletonRed
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &3374291962137961512
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
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:
|
||||
- {fileID: 3204018639052561865}
|
||||
- {fileID: 5017011123106101695}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &3180894108125880274
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
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: 1060825988
|
||||
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 &5830540397649648793
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: e96cb6065543e43c4a752faaa1468eb1, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.Components.NetworkTransform
|
||||
ShowTopMostFoldoutHeaderGroup: 1
|
||||
NetworkTransformExpanded: 0
|
||||
AutoOwnerAuthorityTickOffset: 1
|
||||
PositionInterpolationType: 0
|
||||
RotationInterpolationType: 0
|
||||
ScaleInterpolationType: 0
|
||||
PositionLerpSmoothing: 1
|
||||
PositionMaxInterpolationTime: 0.1
|
||||
RotationLerpSmoothing: 1
|
||||
RotationMaxInterpolationTime: 0.1
|
||||
ScaleLerpSmoothing: 1
|
||||
ScaleMaxInterpolationTime: 0.1
|
||||
AuthorityMode: 0
|
||||
TickSyncChildren: 0
|
||||
UseUnreliableDeltas: 0
|
||||
SyncPositionX: 1
|
||||
SyncPositionY: 1
|
||||
SyncPositionZ: 1
|
||||
SyncRotAngleX: 1
|
||||
SyncRotAngleY: 1
|
||||
SyncRotAngleZ: 1
|
||||
SyncScaleX: 1
|
||||
SyncScaleY: 1
|
||||
SyncScaleZ: 1
|
||||
PositionThreshold: 0.001
|
||||
RotAngleThreshold: 0.01
|
||||
ScaleThreshold: 0.01
|
||||
UseQuaternionSynchronization: 0
|
||||
UseQuaternionCompression: 0
|
||||
UseHalfFloatPrecision: 0
|
||||
InLocalSpace: 0
|
||||
SwitchTransformSpaceWhenParented: 0
|
||||
Interpolate: 1
|
||||
SlerpPosition: 0
|
||||
--- !u!114 &2892684246239657319
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 21dea26768768b8449a8924f638557be, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyHealth
|
||||
ShowTopMostFoldoutHeaderGroup: 1
|
||||
definition: {fileID: 0}
|
||||
deathAnimator: {fileID: 8833486512991012787}
|
||||
deathAnimationDuration: 1.5
|
||||
sinkDuration: 1.5
|
||||
sinkDepth: 1.5
|
||||
--- !u!114 &8213527798879671990
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 292d1b92cd49dc74f8dfd74cdbe4ece7, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyStatus
|
||||
ShowTopMostFoldoutHeaderGroup: 1
|
||||
--- !u!114 &3283904430289710888
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fd6c02bbcc13fb14a9d596d9a2544dcc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyMovement
|
||||
ShowTopMostFoldoutHeaderGroup: 1
|
||||
--- !u!114 &3756613737869398948
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: e8d0727d5ae3244e3b569694d3912374, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.Components.NetworkAnimator
|
||||
ShowTopMostFoldoutHeaderGroup: 1
|
||||
NetworkAnimatorExpanded: 0
|
||||
AuthorityMode: 0
|
||||
m_Animator: {fileID: 8833486512991012787}
|
||||
TransitionStateInfoList:
|
||||
- IsCrossFadeExit: 0
|
||||
Layer: 0
|
||||
OriginatingState: -797153096
|
||||
DestinationState: -908201951
|
||||
TransitionDuration: 0.1
|
||||
TriggerNameHash: 20298039
|
||||
TransitionIndex: 0
|
||||
AnimatorParameterEntries:
|
||||
ParameterEntries:
|
||||
- name: Die
|
||||
NameHash: 20298039
|
||||
Synchronize: 1
|
||||
ParameterType: 9
|
||||
AnimatorParametersExpanded: 0
|
||||
--- !u!136 &6036713598566100742
|
||||
CapsuleCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1455822126534880203}
|
||||
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: 2
|
||||
m_Radius: 0.5
|
||||
m_Height: 2
|
||||
m_Direction: 1
|
||||
m_Center: {x: 0, y: 1, z: 0}
|
||||
--- !u!1 &5361867751622119598
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 5017011123106101695}
|
||||
- component: {fileID: 140866112790896139}
|
||||
m_Layer: 8
|
||||
m_Name: SelectionTrigger
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &5017011123106101695
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5361867751622119598}
|
||||
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: 3374291962137961512}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!136 &140866112790896139
|
||||
CapsuleCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5361867751622119598}
|
||||
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: 2
|
||||
m_Radius: 0.5
|
||||
m_Height: 2
|
||||
m_Direction: 1
|
||||
m_Center: {x: 0, y: 1, z: 0}
|
||||
--- !u!1001 &3169492382559779362
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
serializedVersion: 3
|
||||
m_TransformParent: {fileID: 3374291962137961512}
|
||||
m_Modifications:
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalPosition.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalPosition.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalPosition.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalRotation.w
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalRotation.x
|
||||
value: -0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalRotation.y
|
||||
value: -0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalRotation.z
|
||||
value: -0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: -6751714270944945574, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: 'm_Materials.Array.data[0]'
|
||||
value:
|
||||
objectReference: {fileID: 2100000, guid: fa982eef7eda30e4ca8a94a76eb41d7c, type: 2}
|
||||
- target: {fileID: 919132149155446097, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_Name
|
||||
value: Skeleton
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5866666021909216657, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_Controller
|
||||
value:
|
||||
objectReference: {fileID: 9100000, guid: f58771ae35073b248ad74dc8df86202a, type: 2}
|
||||
- target: {fileID: 5866666021909216657, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
propertyPath: m_ApplyRootMotion
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
m_SourcePrefab: {fileID: 100100000, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
--- !u!4 &3204018639052561865 stripped
|
||||
Transform:
|
||||
m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
m_PrefabInstance: {fileID: 3169492382559779362}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
--- !u!95 &8833486512991012787 stripped
|
||||
Animator:
|
||||
m_CorrespondingSourceObject: {fileID: 5866666021909216657, guid: 8ed68a3a383765a4bb2001de21d699c1, type: 3}
|
||||
m_PrefabInstance: {fileID: 3169492382559779362}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 51ab567e92e18f34eb7848588e3c4479
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/_Project/Prefabs/UI.meta
Normal file
8
Assets/_Project/Prefabs/UI.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c9561520c6855f24db188dd9ee37b2c3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
199
Assets/_Project/Prefabs/UI/FloatingTextPrefab.prefab
Normal file
199
Assets/_Project/Prefabs/UI/FloatingTextPrefab.prefab
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &421102339442651947
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 701392066674882920}
|
||||
- component: {fileID: 1369542009851832211}
|
||||
- component: {fileID: 9051992960569913537}
|
||||
- component: {fileID: 4844901775730304629}
|
||||
m_Layer: 0
|
||||
m_Name: FloatingTextPrefab
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &701392066674882920
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 421102339442651947}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 0.5, y: 0.5, z: 0.5}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 20, y: 5}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!23 &1369542009851832211
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 421102339442651947}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 0
|
||||
m_ReceiveShadows: 0
|
||||
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: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, 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!114 &9051992960569913537
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 421102339442651947}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshPro
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: +0
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 4
|
||||
m_fontSizeBase: 4
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 2
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_characterHorizontalScale: 1
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 0
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 0
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
_SortingLayer: 0
|
||||
_SortingLayerID: 0
|
||||
_SortingOrder: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_renderer: {fileID: 1369542009851832211}
|
||||
m_maskType: 0
|
||||
--- !u!114 &4844901775730304629
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 421102339442651947}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e505af421a8fd24e9b8f3d8786beba8, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::TD.UI.FloatingText
|
||||
text: {fileID: 9051992960569913537}
|
||||
floatSpeed: 1.5
|
||||
lifetime: 1.2
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e5002bdc91043d24994f0b1cb578de56
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1590,7 +1590,8 @@ MonoBehaviour:
|
|||
ShowTopMostFoldoutHeaderGroup: 1
|
||||
waveDefinitions:
|
||||
- {fileID: 11400000, guid: 65f66289ea1233b4897f46cd997d9c7a, type: 2}
|
||||
startingLives: 20
|
||||
- {fileID: 11400000, guid: 190e39db44aa0794aa808fd60976f7c4, type: 2}
|
||||
startingLives: 40
|
||||
--- !u!1 &1464027360
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
@ -1980,6 +1981,51 @@ Transform:
|
|||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &1731269685
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1731269687}
|
||||
- component: {fileID: 1731269686}
|
||||
m_Layer: 0
|
||||
m_Name: DevTools
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &1731269686
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1731269685}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 468de2ce61e73ce4595ba4792874b076, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::TD.Dev.DevWaveControls
|
||||
hotkey: 94
|
||||
--- !u!4 &1731269687
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1731269685}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 18.96448, y: 0.5, z: 62.07733}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &1949204941
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
@ -2441,3 +2487,4 @@ SceneRoots:
|
|||
- {fileID: 902199262}
|
||||
- {fileID: 1380211462}
|
||||
- {fileID: 1149980841}
|
||||
- {fileID: 1731269687}
|
||||
|
|
|
|||
8
Assets/_Project/Scripts/Dev.meta
Normal file
8
Assets/_Project/Scripts/Dev.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 638c60741b05f49409f16991a160f0fa
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
76
Assets/_Project/Scripts/Dev/DevWaveControls.cs
Normal file
76
Assets/_Project/Scripts/Dev/DevWaveControls.cs
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
// Assets/_Project/Scripts/Dev/DevWaveControls.cs
|
||||
using Unity.Netcode;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using TD.Gameplay;
|
||||
|
||||
namespace TD.Dev
|
||||
{
|
||||
/// <summary>
|
||||
/// Editor / testing convenience: shows an OnGUI button in the top-left
|
||||
/// corner that force-advances the wave on the server. Add this component
|
||||
/// to any GameObject in the scene (e.g. a "DevTools" empty) during testing,
|
||||
/// disable or remove for shipping builds.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The button calls <see cref="WaveManager.ForceAdvanceToNextWave"/>, which
|
||||
/// despawns active enemies, stops the current wave's coroutine, and starts
|
||||
/// the next wave with no prep delay.
|
||||
///
|
||||
/// Server-side only — the OnGUI button is gated to <c>NetworkManager.IsServer</c>
|
||||
/// so clients connected to a remote host don't see it. The hotkey path is
|
||||
/// also server-gated to avoid surprising results when pressed on a client.
|
||||
/// </remarks>
|
||||
public class DevWaveControls : MonoBehaviour
|
||||
{
|
||||
[Tooltip("Keyboard shortcut to force-advance to the next wave. " +
|
||||
"Uses the new Input System (UnityEngine.InputSystem.Key). " +
|
||||
"Set to Key.None to use the OnGUI button only.")]
|
||||
[SerializeField] private Key hotkey = Key.F9;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (hotkey == Key.None) return;
|
||||
|
||||
var kb = Keyboard.current;
|
||||
if (kb == null) return; // no keyboard connected (e.g. headless server)
|
||||
if (!kb[hotkey].wasPressedThisFrame) return;
|
||||
|
||||
TryForceNextWave();
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
// Only show the button on the server (host or dedicated). Clients
|
||||
// calling this from afar would no-op anyway.
|
||||
if (NetworkManager.Singleton == null || !NetworkManager.Singleton.IsServer)
|
||||
return;
|
||||
|
||||
// Anchored below the top HUD bar so it doesn't overlap gold/wave/lives.
|
||||
const float topOffset = 90f;
|
||||
GUI.Box(new Rect(10, topOffset, 180, 60), "Dev: Wave Controls");
|
||||
if (GUI.Button(new Rect(20, topOffset + 25, 160, 28), "Force Next Wave"))
|
||||
TryForceNextWave();
|
||||
}
|
||||
|
||||
private void TryForceNextWave()
|
||||
{
|
||||
if (NetworkManager.Singleton == null || !NetworkManager.Singleton.IsServer)
|
||||
{
|
||||
Debug.LogWarning("[DevWaveControls] Force-advance requested off the server. Ignored.");
|
||||
return;
|
||||
}
|
||||
|
||||
var wm = WaveManager.Instance;
|
||||
if (wm == null)
|
||||
{
|
||||
Debug.LogWarning("[DevWaveControls] WaveManager.Instance is null. " +
|
||||
"Is the scene running with a WaveManager network-spawned?");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log("[DevWaveControls] Forcing next wave.");
|
||||
wm.ForceAdvanceToNextWave();
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/_Project/Scripts/Dev/DevWaveControls.cs.meta
Normal file
2
Assets/_Project/Scripts/Dev/DevWaveControls.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 468de2ce61e73ce4595ba4792874b076
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
// Assets/_Project/Scripts/Gameplay/EnemyHealth.cs
|
||||
using System.Collections;
|
||||
using Unity.Netcode;
|
||||
using UnityEngine;
|
||||
using TD.Core;
|
||||
|
|
@ -19,13 +20,47 @@ namespace TD.Gameplay
|
|||
/// DoT ticks from <c>EnemyStatus</c> also carry an owner so the credit
|
||||
/// follows the source tower, not the DoT applicator.
|
||||
///
|
||||
/// <b>Death flow (server-only):</b> <see cref="TakeDamage"/> clamps HP to 0,
|
||||
/// fires <see cref="OnDied"/>, then calls <c>NetworkObject.Despawn</c>.
|
||||
/// Subscribers must not touch the NetworkObject after <see cref="OnDied"/> returns.
|
||||
/// <b>Death flow (server-only):</b> <see cref="TakeDamage"/> clamps HP to 0
|
||||
/// and fires <see cref="OnDied"/> immediately so wave bookkeeping and gold
|
||||
/// award happen the moment HP hits zero. The component then disables
|
||||
/// <see cref="EnemyMovement"/> and all child <c>Collider</c>s, triggers the
|
||||
/// <c>Die</c> animator parameter (synced via <c>NetworkAnimator</c>), waits
|
||||
/// <see cref="deathAnimationDuration"/> seconds, sinks the transform
|
||||
/// <see cref="sinkDepth"/> units over <see cref="sinkDuration"/> seconds,
|
||||
/// and finally calls <c>NetworkObject.Despawn</c>.
|
||||
/// </remarks>
|
||||
[RequireComponent(typeof(NetworkObject))]
|
||||
public class EnemyHealth : NetworkBehaviour
|
||||
public class EnemyHealth : NetworkBehaviour, ISelectable
|
||||
{
|
||||
// ----- Inspector ------------------------------------------------------
|
||||
|
||||
[Header("Identity")]
|
||||
[Tooltip("The EnemyDefinition this prefab represents. Drives the HUD info " +
|
||||
"panel (name, speed, gold bounty) when the enemy is selected. " +
|
||||
"Must be assigned on the prefab so it's available on every peer " +
|
||||
"without needing a registry lookup.")]
|
||||
[SerializeField] private EnemyDefinition definition;
|
||||
|
||||
/// <summary>The static definition this enemy was spawned from.</summary>
|
||||
public EnemyDefinition Definition => definition;
|
||||
|
||||
[Header("Death sequence")]
|
||||
[Tooltip("Animator that plays the death animation. Trigger parameter 'Die' " +
|
||||
"is set on death. Leave null to skip the death animation.")]
|
||||
[SerializeField] private Animator deathAnimator;
|
||||
|
||||
[Tooltip("Seconds to hold after the Die trigger fires before the corpse starts sinking. " +
|
||||
"Should match the death animation clip's duration.")]
|
||||
[SerializeField] private float deathAnimationDuration = 2f;
|
||||
|
||||
[Tooltip("Seconds spent sinking into the ground.")]
|
||||
[SerializeField] private float sinkDuration = 1.5f;
|
||||
|
||||
[Tooltip("How far (world units) the corpse sinks before despawning.")]
|
||||
[SerializeField] private float sinkDepth = 1.5f;
|
||||
|
||||
private static readonly int DieHash = Animator.StringToHash("Die");
|
||||
|
||||
// ----- Pre-spawn init (server-local) ----------------------------------
|
||||
|
||||
private float pendingMaxHp = 100f;
|
||||
|
|
@ -121,6 +156,16 @@ namespace TD.Gameplay
|
|||
MaxHp = hp.Value;
|
||||
}
|
||||
|
||||
public override void OnNetworkDespawn()
|
||||
{
|
||||
// If this enemy was the locally-selected ISelectable, clear the
|
||||
// selection so the HUD doesn't keep displaying a stale corpse.
|
||||
// SelectionState is a local UI singleton, safe to query on any peer.
|
||||
var sel = SelectionState.Instance;
|
||||
if (sel != null && sel.IsSelected(this))
|
||||
sel.Clear();
|
||||
}
|
||||
|
||||
// ----- Server API -----------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -148,8 +193,64 @@ namespace TD.Gameplay
|
|||
|
||||
private void HandleDeath()
|
||||
{
|
||||
// Fire OnDied immediately so the wave count decrements and gold is
|
||||
// awarded the moment HP hits zero — the corpse animation and sink
|
||||
// play out asynchronously after that.
|
||||
OnDied?.Invoke(this);
|
||||
NetworkObject.Despawn();
|
||||
|
||||
// Stop pathing and remove from tower targeting / selection.
|
||||
var movement = GetComponent<EnemyMovement>();
|
||||
if (movement != null) movement.enabled = false;
|
||||
|
||||
foreach (var col in GetComponentsInChildren<Collider>())
|
||||
col.enabled = false;
|
||||
|
||||
// Trigger the death animation on all peers (NetworkAnimator syncs it).
|
||||
if (deathAnimator != null)
|
||||
deathAnimator.SetTrigger(DieHash);
|
||||
|
||||
StartCoroutine(DeathSequence());
|
||||
}
|
||||
|
||||
// ----- ISelectable ----------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Enemy display name. Pulls from <see cref="definition"/> when assigned;
|
||||
/// falls back to "Enemy" so the HUD never shows an empty portrait label
|
||||
/// even if a prefab is missing its definition reference.
|
||||
/// </summary>
|
||||
public string DisplayName =>
|
||||
definition != null && !string.IsNullOrEmpty(definition.DisplayName)
|
||||
? definition.DisplayName
|
||||
: "Enemy";
|
||||
|
||||
public SelectableKind Kind => SelectableKind.Enemy;
|
||||
public Transform SelectionTransform => transform;
|
||||
|
||||
// Used by SelectionVisualizer to size the selection ring. Tuned small
|
||||
// because enemy capsules are roughly 0.6-0.8 wide; if you change enemy
|
||||
// mesh sizes substantially, derive this from a collider bounds instead.
|
||||
public float SelectionRadius => 0.4f;
|
||||
|
||||
private IEnumerator DeathSequence()
|
||||
{
|
||||
// Hold while the death animation plays.
|
||||
yield return new WaitForSeconds(deathAnimationDuration);
|
||||
|
||||
// Sink phase. Server moves the transform; NetworkTransform replicates it.
|
||||
float t = 0f;
|
||||
Vector3 startPos = transform.position;
|
||||
Vector3 endPos = startPos + Vector3.down * sinkDepth;
|
||||
|
||||
while (t < sinkDuration)
|
||||
{
|
||||
t += Time.deltaTime;
|
||||
transform.position = Vector3.Lerp(startPos, endPos, t / sinkDuration);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
if (NetworkObject != null && NetworkObject.IsSpawned)
|
||||
NetworkObject.Despawn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ namespace TD.Gameplay
|
|||
private List<Vector2Int> remainingPath = new List<Vector2Int>();
|
||||
private PlayerSlot currentZone = PlayerSlot.None;
|
||||
private EnemyStatus status;
|
||||
private bool hasReachedGoal;
|
||||
|
||||
// ----- Events ---------------------------------------------------------
|
||||
|
||||
|
|
@ -139,12 +140,20 @@ namespace TD.Gameplay
|
|||
|
||||
float effectiveSpeed = moveSpeed * (status != null ? status.GetSpeedMultiplier() : 1f);
|
||||
Vector3 targetWorld = GridCoordinates.GridToWorld(remainingPath[0]);
|
||||
Vector3 toTarget = targetWorld - transform.position;
|
||||
|
||||
// XZ-only delta. Some enemy prefabs (e.g. the skeleton) have their root
|
||||
// sitting above Y=0; if we measured 3D distance, the Y offset would push
|
||||
// it permanently above the snap threshold and waypoints would never
|
||||
// complete. Tile arrival is a horizontal-plane concept anyway.
|
||||
Vector3 toTarget = targetWorld - transform.position;
|
||||
toTarget.y = 0f;
|
||||
|
||||
if (toTarget.sqrMagnitude <= WaypointSnapSq)
|
||||
{
|
||||
// Snap to the tile center then handle the waypoint transition.
|
||||
transform.position = targetWorld;
|
||||
// Snap XZ to the tile center. Preserve Y so we don't drag a visual
|
||||
// pivot down through the plane.
|
||||
transform.position = new Vector3(
|
||||
targetWorld.x, transform.position.y, targetWorld.z);
|
||||
AdvanceWaypoint();
|
||||
}
|
||||
else
|
||||
|
|
@ -187,11 +196,16 @@ namespace TD.Gameplay
|
|||
|
||||
private void HandleGoalReached()
|
||||
{
|
||||
if (hasReachedGoal) return; // belt-and-suspenders: never fire twice
|
||||
hasReachedGoal = true;
|
||||
|
||||
var health = GetComponent<EnemyHealth>();
|
||||
int livesCost = health != null ? health.LivesCost : 1;
|
||||
|
||||
OnReachedGoal?.Invoke(this, livesCost);
|
||||
NetworkObject.Despawn();
|
||||
|
||||
if (NetworkObject != null && NetworkObject.IsSpawned)
|
||||
NetworkObject.Despawn();
|
||||
}
|
||||
|
||||
// ----- Path invalidation ----------------------------------------------
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using Unity.Netcode;
|
|||
using UnityEngine;
|
||||
using TD.Core;
|
||||
using TD.Levels;
|
||||
using TD.UI;
|
||||
|
||||
namespace TD.Gameplay
|
||||
{
|
||||
|
|
@ -66,10 +67,11 @@ namespace TD.Gameplay
|
|||
|
||||
// ----- Server-local runtime state ---------------------------------
|
||||
|
||||
private int remainingLives;
|
||||
private int activeEnemyCount;
|
||||
private bool spawningComplete;
|
||||
private int currentWaveIndex = -1; // -1 = not yet started
|
||||
private int remainingLives;
|
||||
private int activeEnemyCount;
|
||||
private bool spawningComplete;
|
||||
private int currentWaveIndex = -1; // -1 = not yet started
|
||||
private Coroutine activeWaveCoroutine;
|
||||
|
||||
// ----- NGO lifecycle ----------------------------------------------
|
||||
|
||||
|
|
@ -127,6 +129,13 @@ namespace TD.Gameplay
|
|||
|
||||
// ----- Public accessors -------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Total number of waves in this match. Same on every peer because
|
||||
/// <see cref="waveDefinitions"/> is a serialized prefab field, identical
|
||||
/// on host and clients. Returns 0 if the array is unassigned.
|
||||
/// </summary>
|
||||
public int TotalWaves => waveDefinitions?.Length ?? 0;
|
||||
|
||||
/// <summary>
|
||||
/// Number of times enemies have leaked out of the given player's zone.
|
||||
/// Replicated — safe to call on any peer.
|
||||
|
|
@ -148,7 +157,7 @@ namespace TD.Gameplay
|
|||
|
||||
// ----- Wave coroutine ---------------------------------------------
|
||||
|
||||
private void StartNextWave()
|
||||
private void StartNextWave(bool skipPrep = false)
|
||||
{
|
||||
currentWaveIndex++;
|
||||
|
||||
|
|
@ -166,13 +175,63 @@ namespace TD.Gameplay
|
|||
activeEnemyCount = 0;
|
||||
spawningComplete = false;
|
||||
|
||||
StartCoroutine(RunWave(waveDefinitions[currentWaveIndex]));
|
||||
activeWaveCoroutine = StartCoroutine(
|
||||
RunWave(waveDefinitions[currentWaveIndex], skipPrep));
|
||||
}
|
||||
|
||||
private IEnumerator RunWave(WaveDefinition def)
|
||||
// ----- Dev / cheats -----------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Dev cheat: skip the rest of the current wave (despawn any remaining
|
||||
/// enemies, kill the prep timer) and start the next wave immediately.
|
||||
/// Server-only — silently no-ops on clients. Safe to call during prep,
|
||||
/// mid-spawn, or while enemies are alive.
|
||||
/// </summary>
|
||||
public void ForceAdvanceToNextWave()
|
||||
{
|
||||
// Prep phase — players build while the countdown ticks.
|
||||
yield return new WaitForSeconds(def.PrepTime);
|
||||
if (!IsServer) return;
|
||||
|
||||
// Stop the current wave's coroutine (cancels prep timer + remaining spawns).
|
||||
if (activeWaveCoroutine != null)
|
||||
{
|
||||
StopCoroutine(activeWaveCoroutine);
|
||||
activeWaveCoroutine = null;
|
||||
}
|
||||
|
||||
// Despawn anything still running around. Iterate a snapshot since
|
||||
// EnemyHealth.HandleDeath will despawn the NetworkObject, mutating
|
||||
// the live collection.
|
||||
var spawnManager = NetworkManager.Singleton?.SpawnManager;
|
||||
if (spawnManager != null)
|
||||
{
|
||||
var snapshot = new System.Collections.Generic.List<NetworkObject>(
|
||||
spawnManager.SpawnedObjectsList);
|
||||
foreach (var no in snapshot)
|
||||
{
|
||||
if (no == null || !no.IsSpawned) continue;
|
||||
var movement = no.GetComponent<EnemyMovement>();
|
||||
if (movement == null) continue;
|
||||
|
||||
// Unsubscribe so the despawn doesn't deduct lives or fire side effects.
|
||||
var h = no.GetComponent<EnemyHealth>();
|
||||
UnsubscribeEnemy(h);
|
||||
no.Despawn();
|
||||
}
|
||||
}
|
||||
|
||||
// Reset bookkeeping and start the next wave's RunWave coroutine,
|
||||
// skipping the prep timer so spawning starts immediately.
|
||||
activeEnemyCount = 0;
|
||||
spawningComplete = false;
|
||||
StartNextWave(skipPrep: true);
|
||||
}
|
||||
|
||||
private IEnumerator RunWave(WaveDefinition def, bool skipPrep = false)
|
||||
{
|
||||
// Prep phase — players build while the countdown ticks. Skipped when
|
||||
// a dev cheat forces the wave to start immediately.
|
||||
if (!skipPrep)
|
||||
yield return new WaitForSeconds(def.PrepTime);
|
||||
|
||||
// Spawn phase.
|
||||
if (def.Entries != null)
|
||||
|
|
@ -209,6 +268,13 @@ namespace TD.Gameplay
|
|||
{
|
||||
if (zone.Spawners == null || zone.Spawners.Length == 0) continue;
|
||||
|
||||
// Skip zones whose owning slot is empty. Until a lobby exists,
|
||||
// this means a 1-player test session only spawns enemies in
|
||||
// Player 1's zone; Player 2/3/... zones stay quiet until those
|
||||
// slots are actually filled. PlayerMatchState.GetForSlot returns
|
||||
// null for unoccupied slots (and for PlayerSlot.None).
|
||||
if (PlayerMatchState.GetForSlot(zone.Owner) == null) continue;
|
||||
|
||||
// Use the first spawner in the zone. Future: round-robin through Spawners.
|
||||
SpawnEnemy(def, zone.Spawners[0].TilePosition);
|
||||
}
|
||||
|
|
@ -264,6 +330,13 @@ namespace TD.Gameplay
|
|||
?.AwardGold(health.GoldReward);
|
||||
}
|
||||
|
||||
// Show a "+N" gold popup above the corpse on every peer. Capture the
|
||||
// position here on the server — by the time the RPC fires on clients
|
||||
// the death sequence will be moving the corpse, but the spawn point
|
||||
// is good enough and we want the popup to anchor where the kill happened.
|
||||
if (health.GoldReward > 0)
|
||||
ShowGoldRewardClientRpc(health.transform.position, health.GoldReward);
|
||||
|
||||
UnsubscribeEnemy(health);
|
||||
DecrementAndCheckComplete();
|
||||
}
|
||||
|
|
@ -278,6 +351,13 @@ namespace TD.Gameplay
|
|||
|
||||
private void HandleEnemyReachedGoal(EnemyMovement movement, int livesCost)
|
||||
{
|
||||
// Capture the leak position BEFORE the enemy NetworkObject despawns
|
||||
// (HandleGoalReached on the enemy calls Despawn right after firing the
|
||||
// event we're handling here). Show the "-N" popup on every peer.
|
||||
Vector3 leakPos = movement.transform.position;
|
||||
if (livesCost > 0)
|
||||
ShowLifeLossClientRpc(leakPos, livesCost);
|
||||
|
||||
UnsubscribeEnemy(movement.GetComponent<EnemyHealth>());
|
||||
|
||||
remainingLives = Mathf.Max(0, remainingLives - livesCost);
|
||||
|
|
@ -293,6 +373,22 @@ namespace TD.Gameplay
|
|||
DecrementAndCheckComplete();
|
||||
}
|
||||
|
||||
// ----- Floating-text ClientRpcs -----------------------------------
|
||||
|
||||
// Fired on every peer (server + clients) so each one spawns its own local
|
||||
// FloatingText. The spawned GameObjects are not networked — purely visual.
|
||||
[ClientRpc]
|
||||
private void ShowGoldRewardClientRpc(Vector3 worldPos, int amount)
|
||||
{
|
||||
FloatingTextSpawner.Instance?.SpawnGoldReward(worldPos, amount);
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
private void ShowLifeLossClientRpc(Vector3 worldPos, int amount)
|
||||
{
|
||||
FloatingTextSpawner.Instance?.SpawnLifeLoss(worldPos, amount);
|
||||
}
|
||||
|
||||
// ----- Helpers ----------------------------------------------------
|
||||
|
||||
private void UnsubscribeEnemy(EnemyHealth health)
|
||||
|
|
|
|||
75
Assets/_Project/Scripts/UI/FloatingText.cs
Normal file
75
Assets/_Project/Scripts/UI/FloatingText.cs
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// Assets/_Project/Scripts/UI/FloatingText.cs
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TD.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// One-shot world-space text that floats upward and fades out, then destroys itself.
|
||||
/// Spawned by <see cref="FloatingTextSpawner"/> for kill-reward and life-loss feedback.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <b>Prefab setup:</b> a GameObject with a <c>TextMeshPro</c> (3D, NOT TextMeshProUGUI)
|
||||
/// component as a child or root, this script, and no Canvas required — TMP renders in
|
||||
/// world space natively. The text auto-billboards toward the main camera each frame.
|
||||
///
|
||||
/// Lifetime, float speed, and fade are tuned on the prefab. The spawner only sets
|
||||
/// content + color.
|
||||
/// </remarks>
|
||||
public class FloatingText : MonoBehaviour
|
||||
{
|
||||
[Tooltip("The TextMeshPro component that renders the text. Auto-located in children " +
|
||||
"if left empty.")]
|
||||
[SerializeField] private TMP_Text text;
|
||||
|
||||
[Tooltip("World units per second the text drifts upward.")]
|
||||
[SerializeField] private float floatSpeed = 1.5f;
|
||||
|
||||
[Tooltip("Seconds the text remains visible before the GameObject is destroyed.")]
|
||||
[SerializeField] private float lifetime = 1.2f;
|
||||
|
||||
private float elapsed;
|
||||
private Color baseColor;
|
||||
|
||||
/// <summary>Sets content and color. Call once immediately after Instantiate.</summary>
|
||||
public void Init(string content, Color color)
|
||||
{
|
||||
if (text == null) text = GetComponentInChildren<TMP_Text>();
|
||||
if (text != null)
|
||||
{
|
||||
text.text = content;
|
||||
text.color = color;
|
||||
}
|
||||
baseColor = color;
|
||||
elapsed = 0f;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
if (elapsed >= lifetime)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
// Drift upward.
|
||||
transform.position += Vector3.up * floatSpeed * Time.deltaTime;
|
||||
|
||||
// Fade alpha linearly from 1 → 0 over the lifetime.
|
||||
if (text != null)
|
||||
{
|
||||
float alpha = 1f - (elapsed / lifetime);
|
||||
var c = baseColor;
|
||||
c.a = alpha;
|
||||
text.color = c;
|
||||
}
|
||||
|
||||
// Billboard to the main camera. Using the camera's forward (rather than
|
||||
// position-difference) keeps the text upright even when the camera tilts.
|
||||
var cam = Camera.main;
|
||||
if (cam != null)
|
||||
transform.rotation = Quaternion.LookRotation(cam.transform.forward);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/_Project/Scripts/UI/FloatingText.cs.meta
Normal file
2
Assets/_Project/Scripts/UI/FloatingText.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4e505af421a8fd24e9b8f3d8786beba8
|
||||
107
Assets/_Project/Scripts/UI/FloatingTextSpawner.cs
Normal file
107
Assets/_Project/Scripts/UI/FloatingTextSpawner.cs
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
// Assets/_Project/Scripts/UI/FloatingTextSpawner.cs
|
||||
using UnityEngine;
|
||||
|
||||
namespace TD.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Scene singleton that spawns <see cref="FloatingText"/> instances above
|
||||
/// world positions for gold-reward and life-loss feedback.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <b>Why a singleton:</b> the spawner is shared by every caller (kills, leaks,
|
||||
/// future status pop-ups) and holds inspector-tunable colors and a prefab
|
||||
/// reference. Plain <c>MonoBehaviour</c> — visual-only, no networking required.
|
||||
///
|
||||
/// <b>Who calls this:</b> <see cref="TD.Gameplay.WaveManager"/> invokes
|
||||
/// <see cref="SpawnGoldReward"/> and <see cref="SpawnLifeLoss"/> via ClientRpc
|
||||
/// so every peer shows the popup locally.
|
||||
///
|
||||
/// <b>Inspector setup:</b> drop this on any scene GameObject (e.g. a
|
||||
/// <c>FloatingTextSpawner</c> empty), assign the floating-text prefab, tune
|
||||
/// colors to match the HUD.
|
||||
/// </remarks>
|
||||
public class FloatingTextSpawner : MonoBehaviour
|
||||
{
|
||||
// ----- Singleton --------------------------------------------------
|
||||
|
||||
public static FloatingTextSpawner Instance { get; private set; }
|
||||
|
||||
// ----- Inspector --------------------------------------------------
|
||||
|
||||
[Tooltip("Prefab to instantiate for each pop-up. Must have a FloatingText " +
|
||||
"component and a TextMeshPro renderer.")]
|
||||
[SerializeField] private FloatingText prefab;
|
||||
|
||||
[Tooltip("Color used for kill-reward gold pop-ups. Tune to match the HUD's " +
|
||||
"gold label color.")]
|
||||
[SerializeField] private Color goldColor = new Color(1f, 0.84f, 0.2f);
|
||||
|
||||
[Tooltip("Color used for life-loss pop-ups (enemies reaching the goal).")]
|
||||
[SerializeField] private Color livesColor = new Color(0.95f, 0.25f, 0.25f);
|
||||
|
||||
[Tooltip("Default vertical offset above the source position. Tunes how high " +
|
||||
"above the enemy the text starts.")]
|
||||
[SerializeField] private float verticalOffset = 2.0f;
|
||||
|
||||
[Tooltip("Maximum random horizontal jitter applied to the spawn position so " +
|
||||
"consecutive pop-ups don't stack visually.")]
|
||||
[SerializeField] private float positionJitter = 0.4f;
|
||||
|
||||
[Tooltip("Maximum random vertical jitter applied on top of verticalOffset.")]
|
||||
[SerializeField] private float verticalJitter = 0.2f;
|
||||
|
||||
// ----- Lifecycle --------------------------------------------------
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Debug.LogWarning("[FloatingTextSpawner] Duplicate instance detected. " +
|
||||
"Only one should exist per scene.");
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (Instance == this) Instance = null;
|
||||
}
|
||||
|
||||
// ----- Public API -------------------------------------------------
|
||||
|
||||
/// <summary>Spawns a gold-reward popup (e.g. "+10") at the given world position.</summary>
|
||||
public void SpawnGoldReward(Vector3 worldPos, int amount)
|
||||
=> SpawnInternal(worldPos, $"+{amount}", goldColor);
|
||||
|
||||
/// <summary>Spawns a life-loss popup (e.g. "-1") at the given world position.</summary>
|
||||
public void SpawnLifeLoss(Vector3 worldPos, int amount)
|
||||
=> SpawnInternal(worldPos, $"-{amount}", livesColor);
|
||||
|
||||
/// <summary>Lower-level overload: arbitrary content and color.</summary>
|
||||
public void SpawnCustom(Vector3 worldPos, string text, Color color)
|
||||
=> SpawnInternal(worldPos, text, color);
|
||||
|
||||
// ----- Internal ---------------------------------------------------
|
||||
|
||||
private void SpawnInternal(Vector3 worldPos, string text, Color color)
|
||||
{
|
||||
if (prefab == null)
|
||||
{
|
||||
Debug.LogWarning("[FloatingTextSpawner] No prefab assigned. " +
|
||||
"Pop-up will not be shown.");
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 jitter = new Vector3(
|
||||
Random.Range(-positionJitter, positionJitter),
|
||||
Random.Range(0f, verticalJitter),
|
||||
Random.Range(-positionJitter, positionJitter));
|
||||
|
||||
Vector3 spawnPos = worldPos + Vector3.up * verticalOffset + jitter;
|
||||
|
||||
var instance = Instantiate(prefab, spawnPos, Quaternion.identity);
|
||||
instance.Init(text, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/_Project/Scripts/UI/FloatingTextSpawner.cs.meta
Normal file
2
Assets/_Project/Scripts/UI/FloatingTextSpawner.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a31401869def6d64c87e645f1da1aa2a
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
// Assets/_Project/Scripts/UI/HUDController.cs
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Netcode;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UIElements;
|
||||
using TD.Core;
|
||||
using TD.Gameplay;
|
||||
using TD.Towers;
|
||||
using TD.UI.Minimap;
|
||||
|
|
@ -38,6 +41,7 @@ namespace TD.UI
|
|||
|
||||
private Label goldLabel;
|
||||
private Label waveLabel;
|
||||
private Label livesLabel;
|
||||
private Label portraitName;
|
||||
private Label levelLabel;
|
||||
private VisualElement statLines;
|
||||
|
|
@ -51,6 +55,18 @@ namespace TD.UI
|
|||
private Label ttStats;
|
||||
private Label ttCost;
|
||||
private Label rejectionLabel;
|
||||
private VisualElement portraitFrame;
|
||||
|
||||
// Enemy-info sub-panel — built programmatically and inserted into stat-lines
|
||||
// whenever an Enemy is selected. Cached so we can update HP each frame
|
||||
// without rebuilding the elements.
|
||||
private VisualElement enemyHealthBar;
|
||||
private VisualElement enemyHealthFill;
|
||||
private Label enemyHealthText;
|
||||
|
||||
// Match-end overlay — built once on Start and toggled on Phase changes.
|
||||
private VisualElement matchEndOverlay;
|
||||
private Label matchEndTitle;
|
||||
|
||||
// ----- State ------------------------------------------------------
|
||||
|
||||
|
|
@ -58,6 +74,7 @@ namespace TD.UI
|
|||
private bool placementManagerReady; // true once TowerPlacementManager.Instance is non-null
|
||||
private bool uiInitialized;
|
||||
private bool selectionSubscribed; // true once we've successfully hooked SelectionState.OnSelectionChanged
|
||||
private bool matchStateSubscribed; // true once OnPhaseChanged is hooked
|
||||
private MinimapView minimapView;
|
||||
private IPanel myPanel; // tracked separately so OnDestroy only clears the static if it still points at us
|
||||
|
||||
|
|
@ -149,6 +166,16 @@ namespace TD.UI
|
|||
|
||||
// Seed portrait/grid in case the builder already auto-selected before Start.
|
||||
HandleSelectionChanged(SelectionState.Instance?.SelectedObject);
|
||||
|
||||
TrySubscribeMatchState();
|
||||
}
|
||||
|
||||
private void TrySubscribeMatchState()
|
||||
{
|
||||
if (matchStateSubscribed) return;
|
||||
if (MatchState.Instance == null) return;
|
||||
MatchState.Instance.OnPhaseChanged += HandlePhaseChanged;
|
||||
matchStateSubscribed = true;
|
||||
}
|
||||
|
||||
private void InitializeUI()
|
||||
|
|
@ -172,6 +199,7 @@ namespace TD.UI
|
|||
// so UXML/USS mismatches surface immediately.
|
||||
goldLabel = Require<Label>(root, "gold-label");
|
||||
waveLabel = Require<Label>(root, "wave-label");
|
||||
livesLabel = Require<Label>(root, "lives-label");
|
||||
portraitName = Require<Label>(root, "portrait-name");
|
||||
levelLabel = Require<Label>(root, "level-label");
|
||||
statLines = Require<VisualElement>(root, "stat-lines");
|
||||
|
|
@ -210,6 +238,15 @@ namespace TD.UI
|
|||
minimapView = new MinimapView(minimapContainer, cameraController);
|
||||
}
|
||||
|
||||
// Portrait click → center camera on current selection (WC3 convention).
|
||||
portraitFrame = root.Q<VisualElement>("portrait-frame");
|
||||
if (portraitFrame != null)
|
||||
portraitFrame.RegisterCallback<ClickEvent>(OnPortraitClicked);
|
||||
|
||||
// Build the match-end overlay (Victory / Defeat + Retry). Hidden until
|
||||
// MatchState.OnPhaseChanged fires Victory or Defeat.
|
||||
BuildMatchEndOverlay(root);
|
||||
|
||||
// Publish the panel so non-UI systems can query "is pointer over the HUD".
|
||||
// Stored on `myPanel` too so OnDestroy only clears the static if it still
|
||||
// points at this instance (defensive against re-creation overlap).
|
||||
|
|
@ -235,6 +272,11 @@ namespace TD.UI
|
|||
SelectionState.Instance.OnSelectionChanged -= HandleSelectionChanged;
|
||||
selectionSubscribed = false;
|
||||
}
|
||||
if (matchStateSubscribed && MatchState.Instance != null)
|
||||
{
|
||||
MatchState.Instance.OnPhaseChanged -= HandlePhaseChanged;
|
||||
matchStateSubscribed = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void TrySubscribeSelection()
|
||||
|
|
@ -252,8 +294,13 @@ namespace TD.UI
|
|||
if (!placementManagerReady)
|
||||
TryReadyPlacementManager();
|
||||
|
||||
if (!matchStateSubscribed)
|
||||
TrySubscribeMatchState();
|
||||
|
||||
RefreshGoldDisplay();
|
||||
RefreshMatchStateDisplays();
|
||||
UpdateBuildProgressIfShown();
|
||||
UpdateEnemyInfoIfShown();
|
||||
HandleHotkeys();
|
||||
minimapView?.Tick();
|
||||
}
|
||||
|
|
@ -330,6 +377,29 @@ namespace TD.UI
|
|||
goldLabel.text = gm != null ? $"{gm.CurrentGold:N0} g" : "-- g";
|
||||
}
|
||||
|
||||
// ----- Match-state display ----------------------------------------
|
||||
|
||||
// Polled each frame from Update. MatchState exposes Lives and CurrentWave
|
||||
// as plain int properties backed by NetworkVariables; polling avoids
|
||||
// having to add OnLivesChanged / OnCurrentWaveChanged events to MatchState
|
||||
// for every consumer that wants to display them. The cost is one int read
|
||||
// and a string allocation per frame — negligible at HUD scale.
|
||||
private void RefreshMatchStateDisplays()
|
||||
{
|
||||
var ms = MatchState.Instance;
|
||||
|
||||
if (livesLabel != null)
|
||||
livesLabel.text = ms != null ? $"lives: {ms.Lives}" : "lives: --";
|
||||
|
||||
if (waveLabel != null)
|
||||
{
|
||||
int total = WaveManager.Instance?.TotalWaves ?? 0;
|
||||
waveLabel.text = ms != null && ms.CurrentWave > 0 && total > 0
|
||||
? $"Wave {ms.CurrentWave} / {total}"
|
||||
: "Wave --";
|
||||
}
|
||||
}
|
||||
|
||||
// ----- Command grid -----------------------------------------------
|
||||
|
||||
private const int GRID_COLS = 5;
|
||||
|
|
@ -579,6 +649,12 @@ namespace TD.UI
|
|||
isBuildSite ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
|
||||
// Stat lines — clear and rebuild based on selection kind.
|
||||
// The enemy-info cached references (health bar + label) are invalidated
|
||||
// by Clear() and re-cached if a new Enemy gets selected below.
|
||||
enemyHealthBar = null;
|
||||
enemyHealthFill = null;
|
||||
enemyHealthText = null;
|
||||
|
||||
if (statLines != null)
|
||||
{
|
||||
statLines.Clear();
|
||||
|
|
@ -598,10 +674,113 @@ namespace TD.UI
|
|||
AddStatLine($"Slow: {(1f - def.SlowFactor) * 100f:0}%");
|
||||
}
|
||||
}
|
||||
else if (selection is EnemyHealth enemy)
|
||||
{
|
||||
BuildEnemyInfo(enemy);
|
||||
}
|
||||
// BuildSiteVisual: no stat lines — progress bar conveys the state.
|
||||
}
|
||||
}
|
||||
|
||||
// ----- Enemy info -------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Builds the enemy info stat block (HP bar + speed + bounty) inside the
|
||||
/// stat-lines container. The bar and label references are cached so
|
||||
/// <see cref="UpdateEnemyInfoIfShown"/> can drive them every frame as the
|
||||
/// enemy takes damage.
|
||||
/// </summary>
|
||||
private void BuildEnemyInfo(EnemyHealth enemy)
|
||||
{
|
||||
var def = enemy.Definition;
|
||||
|
||||
// ----- Health bar (X / Y) -----
|
||||
// A thin horizontal bar with a green fill and a centered "X / Y" label
|
||||
// on top. Styled with inline-style so we don't need to add USS classes
|
||||
// — keeps this self-contained.
|
||||
var hpRow = new VisualElement();
|
||||
hpRow.style.flexDirection = FlexDirection.Row;
|
||||
hpRow.style.alignItems = Align.Center;
|
||||
hpRow.style.marginTop = 4;
|
||||
hpRow.style.marginBottom = 4;
|
||||
|
||||
var hpLabel = new Label("HP");
|
||||
hpLabel.style.minWidth = 28;
|
||||
hpLabel.style.color = new Color(0.85f, 0.85f, 0.85f);
|
||||
hpRow.Add(hpLabel);
|
||||
|
||||
// Background + fill share a parent so the fill can be styled as a
|
||||
// percentage width inside the background.
|
||||
var hpBackground = new VisualElement();
|
||||
hpBackground.style.flexGrow = 1;
|
||||
hpBackground.style.height = 14;
|
||||
hpBackground.style.backgroundColor = new Color(0.1f, 0.1f, 0.1f, 0.85f);
|
||||
hpBackground.style.borderTopWidth = hpBackground.style.borderBottomWidth =
|
||||
hpBackground.style.borderLeftWidth = hpBackground.style.borderRightWidth = 1;
|
||||
var borderColor = new Color(0.3f, 0.3f, 0.3f);
|
||||
hpBackground.style.borderTopColor = hpBackground.style.borderBottomColor =
|
||||
hpBackground.style.borderLeftColor = hpBackground.style.borderRightColor = borderColor;
|
||||
|
||||
var hpFill = new VisualElement();
|
||||
hpFill.style.height = Length.Percent(100);
|
||||
hpFill.style.width = Length.Percent(100);
|
||||
hpFill.style.backgroundColor = new Color(0.3f, 0.85f, 0.3f);
|
||||
hpFill.pickingMode = PickingMode.Ignore;
|
||||
hpBackground.Add(hpFill);
|
||||
|
||||
// Overlay "X / Y" label, centered above the bar.
|
||||
var hpText = new Label();
|
||||
hpText.pickingMode = PickingMode.Ignore;
|
||||
hpText.style.position = Position.Absolute;
|
||||
hpText.style.left = 0;
|
||||
hpText.style.right = 0;
|
||||
hpText.style.top = 0;
|
||||
hpText.style.bottom = 0;
|
||||
hpText.style.unityTextAlign = TextAnchor.MiddleCenter;
|
||||
hpText.style.color = Color.white;
|
||||
hpText.style.fontSize = 11;
|
||||
hpBackground.Add(hpText);
|
||||
|
||||
hpRow.Add(hpBackground);
|
||||
statLines.Add(hpRow);
|
||||
|
||||
// Cache references for per-frame updates.
|
||||
enemyHealthBar = hpBackground;
|
||||
enemyHealthFill = hpFill;
|
||||
enemyHealthText = hpText;
|
||||
|
||||
// Initial value (will be refreshed every frame in UpdateEnemyInfoIfShown).
|
||||
UpdateEnemyHpDisplay(enemy);
|
||||
|
||||
// ----- Speed + Bounty stat lines -----
|
||||
if (def != null)
|
||||
{
|
||||
AddStatLine($"Speed: {def.MoveSpeed:0.0}");
|
||||
AddStatLine($"Bounty: {def.GoldReward} g");
|
||||
// (Weaknesses/resistances will go here once the resistance system lands.)
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateEnemyInfoIfShown()
|
||||
{
|
||||
if (enemyHealthFill == null) return; // no Enemy selected
|
||||
var sel = SelectionState.Instance?.SelectedObject;
|
||||
if (sel is EnemyHealth enemy && (UnityEngine.Object)enemy != null)
|
||||
UpdateEnemyHpDisplay(enemy);
|
||||
}
|
||||
|
||||
private void UpdateEnemyHpDisplay(EnemyHealth enemy)
|
||||
{
|
||||
float cur = Mathf.Max(0f, enemy.CurrentHp);
|
||||
float max = Mathf.Max(1f, enemy.MaxHp);
|
||||
float pct = Mathf.Clamp01(cur / max);
|
||||
|
||||
if (enemyHealthFill != null)
|
||||
enemyHealthFill.style.width = Length.Percent(pct * 100f);
|
||||
if (enemyHealthText != null)
|
||||
enemyHealthText.text = $"{Mathf.CeilToInt(cur)} / {Mathf.CeilToInt(max)}";
|
||||
}
|
||||
|
||||
private void AddStatLine(string text)
|
||||
{
|
||||
var label = new Label(text);
|
||||
|
|
@ -667,6 +846,145 @@ namespace TD.UI
|
|||
rejectionFadeCoroutine = null;
|
||||
}
|
||||
|
||||
// ----- Portrait click: center camera on selection -----------------
|
||||
|
||||
// WC3 / SC2 convention: clicking the portrait recenters the camera on
|
||||
// whoever is selected. Zoom is preserved (CameraController.JumpTo only
|
||||
// moves the pivot). No-op when nothing is selected or the camera isn't wired.
|
||||
private void OnPortraitClicked(ClickEvent evt)
|
||||
{
|
||||
var sel = SelectionState.Instance?.SelectedObject;
|
||||
if (sel == null) return;
|
||||
if (cameraController == null) return;
|
||||
|
||||
var t = sel.SelectionTransform;
|
||||
if (t == null) return;
|
||||
|
||||
cameraController.JumpTo(t.position);
|
||||
}
|
||||
|
||||
// ----- Match-end overlay (Victory / Defeat + Retry) ---------------
|
||||
|
||||
private void BuildMatchEndOverlay(VisualElement root)
|
||||
{
|
||||
matchEndOverlay = new VisualElement();
|
||||
matchEndOverlay.style.position = Position.Absolute;
|
||||
matchEndOverlay.style.left = 0;
|
||||
matchEndOverlay.style.right = 0;
|
||||
matchEndOverlay.style.top = 0;
|
||||
matchEndOverlay.style.bottom = 0;
|
||||
matchEndOverlay.style.alignItems = Align.Center;
|
||||
matchEndOverlay.style.justifyContent = Justify.Center;
|
||||
matchEndOverlay.style.backgroundColor = new Color(0f, 0f, 0f, 0.6f);
|
||||
matchEndOverlay.style.display = DisplayStyle.None;
|
||||
// The overlay swallows pointer events so the player can't click towers
|
||||
// or builders through it while it's visible.
|
||||
matchEndOverlay.pickingMode = PickingMode.Position;
|
||||
|
||||
var panel = new VisualElement();
|
||||
panel.style.minWidth = 320;
|
||||
panel.style.paddingTop = 24;
|
||||
panel.style.paddingBottom = 24;
|
||||
panel.style.paddingLeft = 32;
|
||||
panel.style.paddingRight = 32;
|
||||
panel.style.backgroundColor = new Color(0.08f, 0.08f, 0.10f, 0.95f);
|
||||
panel.style.borderTopWidth = panel.style.borderBottomWidth =
|
||||
panel.style.borderLeftWidth = panel.style.borderRightWidth = 2;
|
||||
var border = new Color(0.4f, 0.4f, 0.45f);
|
||||
panel.style.borderTopColor = panel.style.borderBottomColor =
|
||||
panel.style.borderLeftColor = panel.style.borderRightColor = border;
|
||||
panel.style.alignItems = Align.Center;
|
||||
|
||||
matchEndTitle = new Label("Victory");
|
||||
matchEndTitle.style.fontSize = 32;
|
||||
matchEndTitle.style.color = Color.white;
|
||||
matchEndTitle.style.marginBottom = 16;
|
||||
matchEndTitle.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
panel.Add(matchEndTitle);
|
||||
|
||||
var retryBtn = new Button(OnRetryClicked) { text = "Retry" };
|
||||
retryBtn.style.minWidth = 120;
|
||||
retryBtn.style.height = 36;
|
||||
retryBtn.style.fontSize = 16;
|
||||
retryBtn.style.marginTop = 8;
|
||||
panel.Add(retryBtn);
|
||||
|
||||
matchEndOverlay.Add(panel);
|
||||
root.Add(matchEndOverlay);
|
||||
}
|
||||
|
||||
private void HandlePhaseChanged(MatchPhase previous, MatchPhase next)
|
||||
{
|
||||
if (matchEndOverlay == null) return;
|
||||
|
||||
switch (next)
|
||||
{
|
||||
case MatchPhase.Victory:
|
||||
if (matchEndTitle != null)
|
||||
{
|
||||
matchEndTitle.text = "Victory";
|
||||
matchEndTitle.style.color = new Color(1f, 0.84f, 0.2f);
|
||||
}
|
||||
matchEndOverlay.style.display = DisplayStyle.Flex;
|
||||
break;
|
||||
|
||||
case MatchPhase.Defeat:
|
||||
if (matchEndTitle != null)
|
||||
{
|
||||
matchEndTitle.text = "Defeat";
|
||||
matchEndTitle.style.color = new Color(0.95f, 0.25f, 0.25f);
|
||||
}
|
||||
matchEndOverlay.style.display = DisplayStyle.Flex;
|
||||
break;
|
||||
|
||||
default:
|
||||
matchEndOverlay.style.display = DisplayStyle.None;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Reloads the active scene and restarts the host. Host-only — testing
|
||||
// convenience until a real lobby/restart flow exists. The static
|
||||
// sceneLoaded callback survives the scene reload (HUDController dies),
|
||||
// re-arms StartHost once the fresh scene has finished loading, and
|
||||
// unsubscribes itself.
|
||||
private void OnRetryClicked()
|
||||
{
|
||||
var nm = NetworkManager.Singleton;
|
||||
if (nm == null)
|
||||
{
|
||||
Debug.LogWarning("[HUDController] Retry clicked but NetworkManager is null.");
|
||||
return;
|
||||
}
|
||||
if (!nm.IsServer)
|
||||
{
|
||||
Debug.LogWarning("[HUDController] Retry only works on the host. " +
|
||||
"Clients should ask the host to retry.");
|
||||
return;
|
||||
}
|
||||
|
||||
Scene active = SceneManager.GetActiveScene();
|
||||
s_pendingHostRestartBuildIndex = active.buildIndex;
|
||||
SceneManager.sceneLoaded += OnSceneLoadedForRetry;
|
||||
|
||||
nm.Shutdown();
|
||||
SceneManager.LoadScene(active.buildIndex);
|
||||
}
|
||||
|
||||
private static int s_pendingHostRestartBuildIndex = -1;
|
||||
|
||||
private static void OnSceneLoadedForRetry(Scene loaded, LoadSceneMode mode)
|
||||
{
|
||||
if (loaded.buildIndex != s_pendingHostRestartBuildIndex) return;
|
||||
|
||||
SceneManager.sceneLoaded -= OnSceneLoadedForRetry;
|
||||
s_pendingHostRestartBuildIndex = -1;
|
||||
|
||||
var nm = NetworkManager.Singleton;
|
||||
if (nm != null) nm.StartHost();
|
||||
else Debug.LogWarning("[HUDController] Retry: no NetworkManager in reloaded scene.");
|
||||
}
|
||||
|
||||
// ----- Helpers ----------------------------------------------------
|
||||
|
||||
private static T Require<T>(VisualElement root, string name) where T : VisualElement
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue