feat(platforms): add new platform types and implement lever functionality

This commit is contained in:
Данил Ярош 2025-11-24 16:57:20 +03:00
parent a4ebcd4d6f
commit 05a1469725
45 changed files with 43643 additions and 4726 deletions

View File

@ -128,7 +128,7 @@ AnimatorStateMachine:
m_Position: {x: 520, y: -280, z: 0}
- serializedVersion: 1
m_State: {fileID: -7985827421827872045}
m_Position: {x: 520, y: -160, z: 0}
m_Position: {x: 520, y: -170, z: 0}
- serializedVersion: 1
m_State: {fileID: -234086058997577863}
m_Position: {x: 520, y: -60, z: 0}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,311 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &609356841017142299
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2021945858374592067}
- component: {fileID: 995760246805472318}
m_Layer: 0
m_Name: Lever_Base
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &2021945858374592067
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 609356841017142299}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0.5, y: 0.18, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 3607988290522455547}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!212 &995760246805472318
SpriteRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 609356841017142299}
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: 0
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: a97c105638bdf8b4a8650670310a4cd3, 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: 0
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: 1
m_Sprite: {fileID: 742792760, guid: f8c847d5cac325b47a5a48506f30eff7, type: 3}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_FlipX: 0
m_FlipY: 0
m_DrawMode: 0
m_Size: {x: 0.73, y: 0.36}
m_AdaptiveModeThreshold: 0.5
m_SpriteTileMode: 0
m_WasSpriteAssigned: 1
m_MaskInteraction: 0
m_SpriteSortPoint: 0
--- !u!1 &1436029135993153407
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1067377230144882428}
m_Layer: 0
m_Name: Stick
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1067377230144882428
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1436029135993153407}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0.38268343, w: 0.92387956}
m_LocalPosition: {x: 0.5, y: 0.18, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 8317511111288633183}
m_Father: {fileID: 3607988290522455547}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 45}
--- !u!1 &2513619836281733522
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3607988290522455547}
- component: {fileID: 914741219563962730}
- component: {fileID: 6770219739503201904}
m_Layer: 0
m_Name: Lever
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &3607988290522455547
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2513619836281733522}
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: 1067377230144882428}
- {fileID: 2021945858374592067}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!61 &914741219563962730
BoxCollider2D:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2513619836281733522}
m_Enabled: 1
serializedVersion: 3
m_Density: 1
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_ForceSendLayers:
serializedVersion: 2
m_Bits: 4294967295
m_ForceReceiveLayers:
serializedVersion: 2
m_Bits: 4294967295
m_ContactCaptureLayers:
serializedVersion: 2
m_Bits: 4294967295
m_CallbackLayers:
serializedVersion: 2
m_Bits: 4294967295
m_IsTrigger: 1
m_UsedByEffector: 0
m_CompositeOperation: 0
m_CompositeOrder: 0
m_Offset: {x: 0.5, y: 1}
m_SpriteTilingProperty:
border: {x: 0, y: 0, z: 0, w: 0}
pivot: {x: 0, y: 0}
oldSize: {x: 0, y: 0}
newSize: {x: 0, y: 0}
adaptiveTilingThreshold: 0
drawMode: 0
adaptiveTiling: 0
m_AutoTiling: 0
m_Size: {x: 3, y: 2}
m_EdgeRadius: 0
--- !u!114 &6770219739503201904
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2513619836281733522}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ce80a76f2d1833941876252f2475b965, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Lever
stick: {fileID: 1067377230144882428}
leverBase: {fileID: 2021945858374592067}
rotationAngle: 90
rotationSpeed: 5
--- !u!1 &4494697277844752984
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8317511111288633183}
- component: {fileID: 2278547409547904938}
m_Layer: 0
m_Name: Lever_Stick
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8317511111288633183
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4494697277844752984}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0.001, y: 0.475, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1067377230144882428}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!212 &2278547409547904938
SpriteRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4494697277844752984}
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: 0
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: a97c105638bdf8b4a8650670310a4cd3, 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: 0
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_Sprite: {fileID: 1927729786, guid: f8c847d5cac325b47a5a48506f30eff7, type: 3}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_FlipX: 0
m_FlipY: 0
m_DrawMode: 0
m_Size: {x: 0.24, y: 0.59}
m_AdaptiveModeThreshold: 0.5
m_SpriteTileMode: 0
m_WasSpriteAssigned: 1
m_MaskInteraction: 0
m_SpriteSortPoint: 0

View File

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

View File

@ -100,7 +100,7 @@ CompositeCollider2D:
m_CompositeOperation: 0
m_CompositeOrder: 0
m_Offset: {x: 0, y: 0}
m_GeometryType: 0
m_GeometryType: 1
m_GenerationType: 0
m_EdgeRadius: 0
m_ColliderPaths:

View File

@ -52,6 +52,10 @@ PrefabInstance:
propertyPath: m_Name
value: MovingPlatform
objectReference: {fileID: 0}
- target: {fileID: 8025066920931157874, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_GeometryType
value: 1
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []

View File

@ -52,6 +52,10 @@ PrefabInstance:
propertyPath: m_Name
value: ShiftingPlatform
objectReference: {fileID: 0}
- target: {fileID: 8025066920931157874, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_GeometryType
value: 1
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []

View File

@ -0,0 +1,83 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &3659765315877780117
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7368601649257520958, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_Name
value: TrajectoryPlatform
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents:
- targetCorrespondingSourceObject: {fileID: 7368601649257520958, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
insertIndex: -1
addedObject: {fileID: -7142050134933705222}
m_SourcePrefab: {fileID: 100100000, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
--- !u!1 &6091277937240876459 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 7368601649257520958, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
m_PrefabInstance: {fileID: 3659765315877780117}
m_PrefabAsset: {fileID: 0}
--- !u!114 &-7142050134933705222
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6091277937240876459}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 89af0d17b8f24fa4ea9d4cbb01169c5f, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::TrajectoryPlatform
moveSpeed: 5
coordinates: []
loop: 1
attachPlayer: 1

View File

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

View File

@ -0,0 +1,83 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &5972793445274325198
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6864733315602298511, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7368601649257520958, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_Name
value: TriggeringPlatform
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents:
- targetCorrespondingSourceObject: {fileID: 7368601649257520958, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
insertIndex: -1
addedObject: {fileID: -5744794363907911638}
m_SourcePrefab: {fileID: 100100000, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
--- !u!1 &3792338571613016048 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 7368601649257520958, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
m_PrefabInstance: {fileID: 5972793445274325198}
m_PrefabAsset: {fileID: 0}
--- !u!114 &-5744794363907911638
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3792338571613016048}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ea9b4f424a362c5449f2c099e4f3082d, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::RR.Game2D.Entities.Platforms.TriggeringPlatform
moveSpeed: 1
pathLength: 5
moveDirection: 3
attachPlayer: 1

View File

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

View File

@ -52,6 +52,10 @@ PrefabInstance:
propertyPath: m_Name
value: VanishingPlatform
objectReference: {fileID: 0}
- target: {fileID: 8025066920931157874, guid: 745f8f5963b5fe048a51dd7d435a8865, type: 3}
propertyPath: m_GeometryType
value: 1
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
@ -80,3 +84,4 @@ MonoBehaviour:
vanishDuration: 0.5
reappearDelay: 2
reappearDuration: 0.5
vanishStartDelay: 0.2

View File

@ -34,7 +34,7 @@ TextureImporter:
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
filterMode: 0
aniso: 1
mipBias: 0
wrapU: 1
@ -43,7 +43,7 @@ TextureImporter:
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteMode: 2
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
@ -106,9 +106,66 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: WindowsStoreApps
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
sprites:
- serializedVersion: 2
name: Lever_Stick
rect:
serializedVersion: 2
x: 24
y: 37
width: 24
height: 59
alignment: 0
pivot: {x: 0, y: 0}
border: {x: 0, y: 0, z: 0, w: 0}
customData:
outline: []
physicsShape: []
tessellationDetail: 0
bones: []
spriteID: 6835a673e18a44345b14cb19b1c65209
internalID: 1927729786
vertices: []
indices:
edges: []
weights: []
- serializedVersion: 2
name: Lever_0
rect:
serializedVersion: 2
x: 0
y: 1
width: 73
height: 36
alignment: 0
pivot: {x: 0, y: 0}
border: {x: 0, y: 0, z: 0, w: 0}
customData:
outline: []
physicsShape: []
tessellationDetail: 0
bones: []
spriteID: 7d5354849e11acc4e9cc11b3c08bebf7
internalID: 742792760
vertices: []
indices:
edges: []
weights: []
outline: []
customData:
physicsShape: []
@ -122,7 +179,9 @@ TextureImporter:
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
nameFileIdTable:
Lever_0: 742792760
Lever_Stick: 1927729786
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:

View File

@ -1,5 +1,6 @@
fileFormatVersion: 2
guid: 31e4973578565bd448cb191ac2c707e5
guid: bf491ba62b5d50d48b41ca23347f82d1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:

View File

@ -0,0 +1,50 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Lever
m_Shader: {fileID: 4800000, guid: e260cfa7296ee7642b167f1eb5be5023, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _AlphaTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 2800000, guid: f8c847d5cac325b47a5a48506f30eff7, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MaskTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _NormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _EnableExternalAlpha: 0
- _ZWrite: 0
m_Colors:
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _RendererColor: {r: 1, g: 1, b: 1, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0cd3cbb27b17e294898e6b00b50f0948
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1658,6 +1658,7 @@ Transform:
m_Children:
- {fileID: 310989943}
- {fileID: 658885398}
- {fileID: 8762723050865976547}
m_Father: {fileID: 1747659608}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &332519789
@ -2672,6 +2673,7 @@ MonoBehaviour:
vanishDuration: 0.5
reappearDelay: 2
reappearDuration: 0.5
vanishStartDelay: 0.2
--- !u!1 &556549583
GameObject:
m_ObjectHideFlags: 0
@ -3298,7 +3300,7 @@ Transform:
m_GameObject: {fileID: 658885397}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -13, y: 63, z: 0}
m_LocalPosition: {x: 177, y: 63, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
@ -39803,6 +39805,68 @@ PrefabInstance:
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: ff70cd57edcbc3c439493cb8c61b9072, type: 3}
--- !u!1001 &8762723050865976546
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 325799050}
m_Modifications:
- target: {fileID: 3012080002866914914, guid: 7db3a0e7f73de1e4c8f5ad4b61d4097d, type: 3}
propertyPath: m_LocalPosition.x
value: -13
objectReference: {fileID: 0}
- target: {fileID: 3012080002866914914, guid: 7db3a0e7f73de1e4c8f5ad4b61d4097d, type: 3}
propertyPath: m_LocalPosition.y
value: -2
objectReference: {fileID: 0}
- target: {fileID: 3012080002866914914, guid: 7db3a0e7f73de1e4c8f5ad4b61d4097d, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3012080002866914914, guid: 7db3a0e7f73de1e4c8f5ad4b61d4097d, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3012080002866914914, guid: 7db3a0e7f73de1e4c8f5ad4b61d4097d, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3012080002866914914, guid: 7db3a0e7f73de1e4c8f5ad4b61d4097d, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3012080002866914914, guid: 7db3a0e7f73de1e4c8f5ad4b61d4097d, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3012080002866914914, guid: 7db3a0e7f73de1e4c8f5ad4b61d4097d, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3012080002866914914, guid: 7db3a0e7f73de1e4c8f5ad4b61d4097d, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3012080002866914914, guid: 7db3a0e7f73de1e4c8f5ad4b61d4097d, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6101297246587189107, guid: 7db3a0e7f73de1e4c8f5ad4b61d4097d, type: 3}
propertyPath: m_Name
value: TrajectoryPlatform_Common
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 7db3a0e7f73de1e4c8f5ad4b61d4097d, type: 3}
--- !u!4 &8762723050865976547 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 7894378856842464282, guid: 7db3a0e7f73de1e4c8f5ad4b61d4097d, type: 3}
m_PrefabInstance: {fileID: 8762723050865976546}
m_PrefabAsset: {fileID: 0}
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -958,11 +958,11 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 8213225719790051476, guid: c95e72e011a10ca43a3cb1bd524cdc19, type: 3}
propertyPath: m_LocalPosition.x
value: 133.8579
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8213225719790051476, guid: c95e72e011a10ca43a3cb1bd524cdc19, type: 3}
propertyPath: m_LocalPosition.y
value: -8.3745
value: -8
objectReference: {fileID: 0}
- target: {fileID: 8213225719790051476, guid: c95e72e011a10ca43a3cb1bd524cdc19, type: 3}
propertyPath: m_LocalPosition.z

View File

@ -6720,7 +6720,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.132, y: 0.5}
m_AnchorMax: {x: 0.846, y: 0.77500004}
m_AnchoredPosition: {x: -54.5, y: 5}
m_AnchoredPosition: {x: -54.499996, y: 5}
m_SizeDelta: {x: -107, y: -10}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1474919456
@ -10318,7 +10318,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.132, y: 0.21750003}
m_AnchorMax: {x: 0.846, y: 0.5}
m_AnchoredPosition: {x: -54.5, y: -79}
m_AnchoredPosition: {x: -54.499996, y: -79}
m_SizeDelta: {x: -107, y: -63}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1959311160

View File

@ -2,6 +2,10 @@
namespace RR.Common.Interfaces
{
/// <summary>
/// Интерфейс для объектов, которые могут быть возвращены к владельцу.
/// Используется для реализации механики возврата брошенных объектов.
/// </summary>
public interface IRecallable
{
/// <summary>
@ -12,6 +16,10 @@ namespace RR.Common.Interfaces
public void Recall();
}
/// <summary>
/// Интерфейс для объектов, которые могут быть подняты игроком.
/// Реализуется объектами, которые можно подбирать и/или держать.
/// </summary>
public interface IPickable
{
/// <summary>
@ -24,18 +32,52 @@ namespace RR.Common.Interfaces
public bool TryPickup(GameObject newOwner, Transform optionalAttachPoint = null);
}
/// <summary>
/// Интерфейс для объектов, которые могут получать и наносить урон.
/// Реализуется всеми сущностями, имеющими систему здоровья.
/// </summary>
public interface IDamageable
{
/// <summary>
/// Метод для получения урона объектом.
/// </summary>
/// <param name="amount">Количество урона</param>
void TakeDamage(float amount);
/// <summary>
/// Метод для восстановления здоровья объекта.
/// </summary>
/// <param name="amount">Количество восстанавливаемого здоровья</param>
void Heal(float amount);
/// <summary>
/// Метод для обработки смерти объекта.
/// Вызывается когда здоровье достигает нуля или меньше.
/// </summary>
void Die();
}
/// <summary>
/// Интерфейс для объектов, которые могут выполнять действие.
/// Используется для интерактивных объектов в игре.
/// </summary>
public interface IActionable
{
/// <summary>
/// Выполняет действие, связанное с объектом.
/// Например, активация механизма, открытие двери и т.д.
/// </summary>
void PerformAction();
}
}
namespace RR.Game2D.Core.Managers.Interfaces
{
public interface ILauchable
/// <summary>
/// Интерфейс для объектов, которые могут быть запущены как снаряд.
/// Реализуется объектами, которые можно бросать в определенном направлении.
/// </summary>
public interface ILaunchable
{
/// <summary>
/// Метод для запуска объекта как снаряд
@ -46,6 +88,10 @@ namespace RR.Game2D.Core.Managers.Interfaces
public void Launch(Vector2 direction, float speed, GameObject thrower);
}
/// <summary>
/// Интерфейс для объектов, которые могут отскакивать от поверхностей.
/// Реализуется объектами с физикой отскока при столкновении.
/// </summary>
public interface IBouncy
{

View File

@ -17,7 +17,11 @@ namespace RR.Common.Audio
private void OnEnable() => GameManager.Instance.PlayerSpawned += OnPlayerSpawned;
private void OnDisable() => GameManager.Instance.PlayerSpawned -= OnPlayerSpawned;
private void OnDisable()
{
if (GameManager.Instance) GameManager.Instance.PlayerSpawned -= OnPlayerSpawned;
}
private void Awake()
{

View File

@ -6,7 +6,7 @@ using RR.Game2D.Core.Managers.Interfaces;
namespace RR.Game2D.Entities.Projectiles
{
[RequireComponent(typeof(Rigidbody2D), typeof(Collider2D))]
public abstract class Projectile2D : MonoBehaviour, ILauchable
public abstract class Projectile2D : MonoBehaviour, ILaunchable
{
[Header("Базовые настройки")]
[SerializeField] protected float initialSpeed = 15f;

View File

@ -0,0 +1,99 @@
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using RR.Common.Interfaces;
namespace RR.Game2D.Entities
{
[RequireComponent(typeof(Collider2D))]
public class Lever : MonoBehaviour, IActionable
{
[Header("Управление")]
[SerializeField] private InputActionReference activateKey;
[Header("Настройки частей рычага")]
[SerializeField] private Transform stick;
[SerializeField] private Transform leverBase;
[Header("Настройки поворота рычага")]
[SerializeField] private float rotationAngle = 90f;
[SerializeField] private float rotationSpeed = 5f;
[Header("События после активации")]
[SerializeField] private UnityEvent onActivate;
private Quaternion _initialRotation;
private Collider2D _collider;
private bool _isActivated;
private bool _canBeActivated = false;
private void Start()
{
_isActivated = false;
// onActivate = new UnityEvent();
if (_collider == null) _collider = GetComponent<Collider2D>();
if (_collider == null) _collider = gameObject.AddComponent<Collider2D>();
if (!_collider.isTrigger) _collider.isTrigger = true;
if (stick == null)
{
Debug.LogError("Lever: Stick transform is not assigned!", this);
}
else
{
_initialRotation = stick.rotation;
}
// activateKey.action.performed += OnActivateKey;
activateKey.action.started += OnActivateKey;
activateKey.action.Enable();
}
private void OnTriggerEnter2D(Collider2D other)
{
if (!other.CompareTag("Player")) return;
_canBeActivated = true;
}
private void OnTriggerExit2D(Collider2D other)
{
if (!other.CompareTag("Player")) return;
_canBeActivated = false;
}
public void PerformAction()
{
StopAllCoroutines();
StartCoroutine(RotateLever());
onActivate?.Invoke();
}
private IEnumerator RotateLever()
{
// initialRotation = stick.rotation;
Quaternion targetRotation = _initialRotation * Quaternion.Euler(0f, 0f, rotationAngle);
float elapsedTime = 0f;
while (elapsedTime < rotationSpeed)
{
stick.rotation = Quaternion.Slerp(_initialRotation, targetRotation, elapsedTime / rotationSpeed);
elapsedTime += Time.deltaTime;
yield return null;
}
stick.rotation = targetRotation;
_isActivated = true;
}
private void OnActivateKey(InputAction.CallbackContext obj)
{
if (!_canBeActivated) return;
PerformAction();
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ce80a76f2d1833941876252f2475b965

View File

@ -1,5 +1,6 @@
fileFormatVersion: 2
guid: 530cb6df09ac2d74587e3db0e51f6f91
guid: cc36b3c628aba664788d72de8fd885a7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,8 +1,8 @@
using System;
using RR.Game2D.Core;
using UnityEngine;
namespace RR.Game2D.Entities
using RR.Game2D.Core;
namespace RR.Game2D.Entities.Platforms
{
public class MovingPlatform : MonoBehaviour
{

View File

@ -0,0 +1,79 @@
using System;
using System.Collections;
using RR.Game2D.Core;
using UnityEngine;
namespace RR.Game2D.Entities.Platforms
{
public class ShiftingPlatform : MonoBehaviour
{
[Header("Настройки смещения платформы")]
[SerializeField] private Vector3 shiftAmount = new Vector3(0f, 2f, 0f);
[SerializeField] private float shiftDuration = 1f;
[SerializeField] private Direction2D shiftDirection = Direction2D.Down;
[Header("Прикрепление игрока")]
[SerializeField] private bool attachPlayer = true;
private Vector3 _startPosition;
private void Awake()
{
_startPosition = transform.position;
}
private void OnCollisionEnter2D(Collision2D other)
{
if (!other.gameObject.CompareTag("Player")) return;
if (attachPlayer) other.transform.SetParent(transform);
Vector3 shiftVector = shiftDirection switch
{
Direction2D.Down => Vector3.down * shiftAmount.y,
Direction2D.Left => Vector3.left * shiftAmount.x,
Direction2D.Right => Vector3.right * shiftAmount.x,
Direction2D.Up => Vector3.up * shiftAmount.y,
_ => Vector3.zero
};
StopAllCoroutines();
StartCoroutine(ShiftPlatform(shiftVector));
}
private void OnCollisionExit2D(Collision2D other)
{
if (!other.gameObject.CompareTag("Player")) return;
if (attachPlayer) other.transform.SetParent(null);
Vector3 shiftVector = shiftDirection switch
{
Direction2D.Down => Vector3.up * shiftAmount.y,
Direction2D.Left => Vector3.right * shiftAmount.x,
Direction2D.Right => Vector3.left * shiftAmount.x,
Direction2D.Up => Vector3.down * shiftAmount.y,
_ => Vector3.zero
};
StopAllCoroutines();
StartCoroutine(ShiftPlatform(shiftVector));
}
private IEnumerator ShiftPlatform(Vector3 shiftVector)
{
Vector3 initialPosition = transform.position;
Vector3 finalPosition = initialPosition + shiftVector;
float elapsedTime = 0f;
while (elapsedTime < shiftDuration)
{
transform.position = Vector3.Lerp(initialPosition, finalPosition, (elapsedTime / shiftDuration));
elapsedTime += Time.deltaTime;
yield return null;
}
transform.position = finalPosition;
}
}
}

View File

@ -0,0 +1,62 @@
using UnityEngine;
namespace RR.Game2D.Entities.Platforms
{
public class TrajectoryPlatform : MonoBehaviour
{
[Header("Настройки движения платформы")]
[SerializeField] private float moveSpeed = 1f;
[SerializeField] private Vector3[] coordinates;
[SerializeField] private bool loop = true;
[Header("Прикрепление игрока")]
[SerializeField] private bool attachPlayer = true;
private int _currentTargetIndex;
private void FixedUpdate()
{
if (coordinates == null || coordinates.Length == 0) return;
// Определяем целевую точку
Vector3 targetPoint = coordinates[_currentTargetIndex];
// Двигаем платформу к целевой точке
transform.position = Vector3.MoveTowards(transform.position, targetPoint, moveSpeed * Time.fixedDeltaTime);
// Проверяем, достигли ли целевой точки
if (!(Vector3.Distance(transform.position, targetPoint) < 0.01f)) return;
if (loop)
{
// Режим зацикливания: переходим к следующей точке по кругу
_currentTargetIndex = (_currentTargetIndex + 1) % (coordinates.Length + 1);
// Если вернулись к началу, корректируем индекс
if (_currentTargetIndex == coordinates.Length)
{
_currentTargetIndex = 0;
}
}
else
{
_currentTargetIndex++;
if (_currentTargetIndex < coordinates.Length) return;
transform.position = coordinates[0];
_currentTargetIndex = 0;
}
}
private void OnCollisionEnter2D(Collision2D other)
{
if (!attachPlayer) return;
if (!other.gameObject.CompareTag("Player")) return;
other.transform.SetParent(transform);
}
private void OnCollisionExit2D(Collision2D other)
{
if (!attachPlayer) return;
if (!other.gameObject.CompareTag("Player")) return;
other.transform.SetParent(null);
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 89af0d17b8f24fa4ea9d4cbb01169c5f

View File

@ -0,0 +1,61 @@
using System.Collections;
using UnityEngine;
using RR.Game2D.Core;
namespace RR.Game2D.Entities.Platforms
{
public class TriggeringPlatform : MonoBehaviour
{
[Header("Настройки движения платформы")]
[SerializeField] private float moveSpeed = 3f;
[SerializeField] private float pathLength = 5f;
[SerializeField] private Direction2D moveDirection = Direction2D.Right;
[Header("Прикрепление игрока")]
[SerializeField] private bool attachPlayer = true;
private Vector3 _startPosition;
private Vector3 _endPosition;
private void Awake()
{
_startPosition = transform.position;
_endPosition = moveDirection switch
{
Direction2D.Down => _startPosition + Vector3.down * pathLength,
Direction2D.Left => _startPosition + Vector3.left * pathLength,
Direction2D.Right => _startPosition + Vector3.right * pathLength,
Direction2D.Up => _startPosition + Vector3.up * pathLength,
_ => _startPosition
};
}
public void Move()
{
StopAllCoroutines();
StartCoroutine(MovePlatform(_endPosition));
}
public void MoveBack()
{
StopAllCoroutines();
StartCoroutine(MovePlatform(_startPosition));
}
private IEnumerator MovePlatform(Vector3 targetPosition)
{
while (transform.position != targetPosition)
{
transform.position = Vector3.MoveTowards(
transform.position,
targetPosition,
Time.deltaTime * moveSpeed);
yield return null;
}
transform.position = targetPosition;
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ea9b4f424a362c5449f2c099e4f3082d

View File

@ -0,0 +1,259 @@
using System.Collections;
using UnityEngine;
namespace RR.Game2D.Entities.Platforms
{
public class VanishingPlatform : MonoBehaviour
{
[Header("Настройки исчезновения платформы")]
[SerializeField] private float vanishDuration = 0.5f;
[SerializeField] private float reappearDelay = 2f;
[SerializeField] private float reappearDuration = 0.5f;
[SerializeField, Min(0f)] private float vanishStartDelay = 0.2f;
private CompositeCollider2D _compositeCollider;
private Rigidbody2D _rigidbody;
private SpriteRenderer[] _spriteRenderers;
private Coroutine _vanishCoroutine;
private Coroutine _reappearCoroutine;
private Coroutine _delayedVanishCoroutine;
private Color[] _initialColors;
/// <summary>
/// Кэширует необходимые компоненты и предупреждает, если чего-то не хватает.
/// </summary>
private void Awake()
{
_compositeCollider = GetComponent<CompositeCollider2D>();
_rigidbody = GetComponent<Rigidbody2D>();
_spriteRenderers = GetComponentsInChildren<SpriteRenderer>();
if (_compositeCollider == null)
Debug.LogWarning($"[{nameof(VanishingPlatform)}] CompositeCollider2D не найден на {gameObject.name}.");
if (_rigidbody == null)
Debug.LogWarning($"[{nameof(VanishingPlatform)}] Rigidbody2D не найден на {gameObject.name}. CompositeCollider2D требует Rigidbody2D.");
if (_spriteRenderers == null || _spriteRenderers.Length == 0)
Debug.LogWarning($"[{nameof(VanishingPlatform)}] SpriteRenderer'ы не найдены на {gameObject.name} и его дочерних объектах.");
}
/// <summary>
/// Запускает отсрочку исчезновения при входе игрока на платформу.
/// </summary>
/// <param name="other">Коллизия, по которой определяем игрока.</param>
private void OnCollisionEnter2D(Collision2D other)
{
if (!other.gameObject.CompareTag("Player")) return;
if (_delayedVanishCoroutine != null)
{
StopCoroutine(_delayedVanishCoroutine);
_delayedVanishCoroutine = null;
}
// Если в процессе была корутина Reappear — её отменяем
if (_reappearCoroutine != null)
{
StopCoroutine(_reappearCoroutine);
_reappearCoroutine = null;
}
if (_vanishCoroutine != null)
StopCoroutine(_vanishCoroutine);
// _vanishCoroutine = StartCoroutine(Vanish());
_delayedVanishCoroutine = StartCoroutine(StartVanishWithDelay());
}
/// <summary>
/// Останавливает исчезновение и инициирует процесс появления, когда игрок уходит.
/// </summary>
/// <param name="other">Коллизия выхода игрока.</param>
private void OnCollisionExit2D(Collision2D other)
{
if (!other.gameObject.CompareTag("Player")) return;
if (_delayedVanishCoroutine != null)
{
StopCoroutine(_delayedVanishCoroutine);
_delayedVanishCoroutine = null;
}
// Если в процессе была корутина Vanish — её отменяем
if (_vanishCoroutine != null)
{
StopCoroutine(_vanishCoroutine);
_vanishCoroutine = null;
}
if (_reappearCoroutine != null)
StopCoroutine(_reappearCoroutine);
_reappearCoroutine = StartCoroutine(Reappear());
}
/// <summary>
/// Плавно уменьшает альфу спрайтов до нуля и отключает физику платформы.
/// </summary>
private IEnumerator Vanish()
{
if (_spriteRenderers == null || _spriteRenderers.Length == 0)
yield break; // нечего анимировать
// Сохраняем начальные цвета для всех рендереров (если ещё не сохранены)
if (_initialColors == null || _initialColors.Length != _spriteRenderers.Length)
{
_initialColors = new Color[_spriteRenderers.Length];
for (int i = 0; i < _spriteRenderers.Length; i++)
_initialColors[i] = _spriteRenderers[i].color;
}
// Запоминаем текущую альфу для каждого рендерера
float[] startAlphas = new float[_spriteRenderers.Length];
for (int i = 0; i < _spriteRenderers.Length; i++)
startAlphas[i] = _spriteRenderers[i].color.a;
float elapsed = 0f;
while (elapsed < vanishDuration)
{
elapsed += Time.deltaTime;
float t = vanishDuration > 0f ? Mathf.Clamp01(elapsed / vanishDuration) : 1f;
for (int i = 0; i < _spriteRenderers.Length; i++)
{
Color c = _initialColors[i];
float alpha = Mathf.Lerp(startAlphas[i], 0f, t);
_spriteRenderers[i].color = new Color(c.r, c.g, c.b, alpha);
}
yield return null;
}
// Принудительно установить 0 альфу
for (int i = 0; i < _spriteRenderers.Length; i++)
{
Color c = _initialColors[i];
_spriteRenderers[i].color = new Color(c.r, c.g, c.b, 0f);
}
if (_rigidbody)
_rigidbody.simulated = false; // отключаем Collider через Rigidbody2D
_vanishCoroutine = null;
}
/// <summary>
/// Плавно возвращает платформу и повторно включает физику после задержки.
/// </summary>
private IEnumerator Reappear()
{
if (_spriteRenderers == null || _spriteRenderers.Length == 0)
yield break; // нечего анимировать
// Убедимся, что у нас есть базовые цвета — если нет, прочитаем текущие
if (_initialColors == null || _initialColors.Length != _spriteRenderers.Length)
{
_initialColors = new Color[_spriteRenderers.Length];
for (int i = 0; i < _spriteRenderers.Length; i++)
_initialColors[i] = _spriteRenderers[i].color;
}
// Задержка перед появлением (как в предыдущей логике)
yield return new WaitForSeconds(reappearDelay);
// Запоминаем текущую альфу для каждого рендерера
float[] startAlphas = new float[_spriteRenderers.Length];
for (int i = 0; i < _spriteRenderers.Length; i++)
startAlphas[i] = _spriteRenderers[i].color.a;
float elapsed = 0f;
while (elapsed < reappearDuration)
{
elapsed += Time.deltaTime;
float t = reappearDuration > 0f ? Mathf.Clamp01(elapsed / reappearDuration) : 1f;
for (int i = 0; i < _spriteRenderers.Length; i++)
{
Color c = _initialColors[i];
float alpha = Mathf.Lerp(startAlphas[i], 1f, t);
_spriteRenderers[i].color = new Color(c.r, c.g, c.b, alpha);
}
yield return null;
}
// Принудительно установить полную непрозрачность
for (int i = 0; i < _spriteRenderers.Length; i++)
{
Color c = _initialColors[i];
_spriteRenderers[i].color = new Color(c.r, c.g, c.b, 1f);
}
if (_rigidbody)
_rigidbody.simulated = true; // возвращаем физику
_reappearCoroutine = null;
}
/// <summary>
/// Позволяет внешним системам сразу запустить исчезновение (без ожидания).
/// </summary>
public void TriggerVanish()
{
if (_delayedVanishCoroutine != null)
{
StopCoroutine(_delayedVanishCoroutine);
_delayedVanishCoroutine = null;
}
if (_reappearCoroutine != null)
{
StopCoroutine(_reappearCoroutine);
_reappearCoroutine = null;
}
if (_vanishCoroutine != null)
StopCoroutine(_vanishCoroutine);
_vanishCoroutine = StartCoroutine(Vanish());
}
/// <summary>
/// Позволяет внешним системам сразу запустить появление.
/// </summary>
public void TriggerReappear()
{
if (_delayedVanishCoroutine != null)
{
StopCoroutine(_delayedVanishCoroutine);
_delayedVanishCoroutine = null;
}
if (_vanishCoroutine != null)
{
StopCoroutine(_vanishCoroutine);
_vanishCoroutine = null;
}
if (_reappearCoroutine != null)
StopCoroutine(_reappearCoroutine);
_reappearCoroutine = StartCoroutine(Reappear());
}
/// <summary>
/// Ожидает заданную задержку перед фактическим запуском корутины Vanish.
/// </summary>
private IEnumerator StartVanishWithDelay()
{
if (vanishStartDelay > 0f)
yield return new WaitForSeconds(vanishStartDelay); // выдерживаем таймер ожидания
_vanishCoroutine = StartCoroutine(Vanish());
_delayedVanishCoroutine = null;
}
}
}

View File

@ -1,76 +0,0 @@
using System;
using System.Collections;
using RR.Game2D.Core;
using UnityEngine;
public class ShiftingPlatform : MonoBehaviour
{
[Header("Настройки смещения платформы")]
[SerializeField] private Vector3 shiftAmount = new Vector3(0f, 2f, 0f);
[SerializeField] private float shiftDuration = 1f;
[SerializeField] private Direction2D shiftDirection = Direction2D.Down;
[Header("Прикрепление игрока")]
[SerializeField] private bool attachPlayer = true;
private Vector3 _startPosition;
private void Awake()
{
_startPosition = transform.position;
}
private void OnCollisionEnter2D(Collision2D other)
{
if (!other.gameObject.CompareTag("Player")) return;
if (attachPlayer) other.transform.SetParent(transform);
Vector3 shiftVector = shiftDirection switch
{
Direction2D.Down => Vector3.down * shiftAmount.y,
Direction2D.Left => Vector3.left * shiftAmount.x,
Direction2D.Right => Vector3.right * shiftAmount.x,
Direction2D.Up => Vector3.up * shiftAmount.y,
_ => Vector3.zero
};
StopAllCoroutines();
StartCoroutine(ShiftPlatform(shiftVector));
}
private void OnCollisionExit2D(Collision2D other)
{
if (!other.gameObject.CompareTag("Player")) return;
if (attachPlayer) other.transform.SetParent(null);
Vector3 shiftVector = shiftDirection switch
{
Direction2D.Down => Vector3.up * shiftAmount.y,
Direction2D.Left => Vector3.right * shiftAmount.x,
Direction2D.Right => Vector3.left * shiftAmount.x,
Direction2D.Up => Vector3.down * shiftAmount.y,
_ => Vector3.zero
};
StopAllCoroutines();
StartCoroutine(ShiftPlatform(shiftVector));
}
private IEnumerator ShiftPlatform(Vector3 shiftVector)
{
Vector3 initialPosition = transform.position;
Vector3 finalPosition = initialPosition + shiftVector;
float elapsedTime = 0f;
while (elapsedTime < shiftDuration)
{
transform.position = Vector3.Lerp(initialPosition, finalPosition, (elapsedTime / shiftDuration));
elapsedTime += Time.deltaTime;
yield return null;
}
transform.position = finalPosition;
}
}

View File

@ -1,256 +0,0 @@
using System.Collections;
using UnityEngine;
public class VanishingPlatform : MonoBehaviour
{
[Header("Настройки исчезновения платформы")]
[SerializeField] private float vanishDuration = 0.5f;
[SerializeField] private float reappearDelay = 2f;
[SerializeField] private float reappearDuration = 0.5f;
[SerializeField, Min(0f)] private float vanishStartDelay = 0.2f;
private CompositeCollider2D _compositeCollider;
private Rigidbody2D _rigidbody;
private SpriteRenderer[] _spriteRenderers;
private Coroutine _vanishCoroutine;
private Coroutine _reappearCoroutine;
private Coroutine _delayedVanishCoroutine;
private Color[] _initialColors;
/// <summary>
/// Кэширует необходимые компоненты и предупреждает, если чего-то не хватает.
/// </summary>
private void Awake()
{
_compositeCollider = GetComponent<CompositeCollider2D>();
_rigidbody = GetComponent<Rigidbody2D>();
_spriteRenderers = GetComponentsInChildren<SpriteRenderer>();
if (_compositeCollider == null)
Debug.LogWarning($"[{nameof(VanishingPlatform)}] CompositeCollider2D не найден на {gameObject.name}.");
if (_rigidbody == null)
Debug.LogWarning($"[{nameof(VanishingPlatform)}] Rigidbody2D не найден на {gameObject.name}. CompositeCollider2D требует Rigidbody2D.");
if (_spriteRenderers == null || _spriteRenderers.Length == 0)
Debug.LogWarning($"[{nameof(VanishingPlatform)}] SpriteRenderer'ы не найдены на {gameObject.name} и его дочерних объектах.");
}
/// <summary>
/// Запускает отсрочку исчезновения при входе игрока на платформу.
/// </summary>
/// <param name="other">Коллизия, по которой определяем игрока.</param>
private void OnCollisionEnter2D(Collision2D other)
{
if (!other.gameObject.CompareTag("Player")) return;
if (_delayedVanishCoroutine != null)
{
StopCoroutine(_delayedVanishCoroutine);
_delayedVanishCoroutine = null;
}
// Если в процессе была корутина Reappear — её отменяем
if (_reappearCoroutine != null)
{
StopCoroutine(_reappearCoroutine);
_reappearCoroutine = null;
}
if (_vanishCoroutine != null)
StopCoroutine(_vanishCoroutine);
// _vanishCoroutine = StartCoroutine(Vanish());
_delayedVanishCoroutine = StartCoroutine(StartVanishWithDelay());
}
/// <summary>
/// Останавливает исчезновение и инициирует процесс появления, когда игрок уходит.
/// </summary>
/// <param name="other">Коллизия выхода игрока.</param>
private void OnCollisionExit2D(Collision2D other)
{
if (!other.gameObject.CompareTag("Player")) return;
if (_delayedVanishCoroutine != null)
{
StopCoroutine(_delayedVanishCoroutine);
_delayedVanishCoroutine = null;
}
// Если в процессе была корутина Vanish — её отменяем
if (_vanishCoroutine != null)
{
StopCoroutine(_vanishCoroutine);
_vanishCoroutine = null;
}
if (_reappearCoroutine != null)
StopCoroutine(_reappearCoroutine);
_reappearCoroutine = StartCoroutine(Reappear());
}
/// <summary>
/// Плавно уменьшает альфу спрайтов до нуля и отключает физику платформы.
/// </summary>
private IEnumerator Vanish()
{
if (_spriteRenderers == null || _spriteRenderers.Length == 0)
yield break; // нечего анимировать
// Сохраняем начальные цвета для всех рендереров (если ещё не сохранены)
if (_initialColors == null || _initialColors.Length != _spriteRenderers.Length)
{
_initialColors = new Color[_spriteRenderers.Length];
for (int i = 0; i < _spriteRenderers.Length; i++)
_initialColors[i] = _spriteRenderers[i].color;
}
// Запоминаем текущую альфу для каждого рендерера
float[] startAlphas = new float[_spriteRenderers.Length];
for (int i = 0; i < _spriteRenderers.Length; i++)
startAlphas[i] = _spriteRenderers[i].color.a;
float elapsed = 0f;
while (elapsed < vanishDuration)
{
elapsed += Time.deltaTime;
float t = vanishDuration > 0f ? Mathf.Clamp01(elapsed / vanishDuration) : 1f;
for (int i = 0; i < _spriteRenderers.Length; i++)
{
Color c = _initialColors[i];
float alpha = Mathf.Lerp(startAlphas[i], 0f, t);
_spriteRenderers[i].color = new Color(c.r, c.g, c.b, alpha);
}
yield return null;
}
// Принудительно установить 0 альфу
for (int i = 0; i < _spriteRenderers.Length; i++)
{
Color c = _initialColors[i];
_spriteRenderers[i].color = new Color(c.r, c.g, c.b, 0f);
}
if (_rigidbody)
_rigidbody.simulated = false; // отключаем Collider через Rigidbody2D
_vanishCoroutine = null;
}
/// <summary>
/// Плавно возвращает платформу и повторно включает физику после задержки.
/// </summary>
private IEnumerator Reappear()
{
if (_spriteRenderers == null || _spriteRenderers.Length == 0)
yield break; // нечего анимировать
// Убедимся, что у нас есть базовые цвета — если нет, прочитаем текущие
if (_initialColors == null || _initialColors.Length != _spriteRenderers.Length)
{
_initialColors = new Color[_spriteRenderers.Length];
for (int i = 0; i < _spriteRenderers.Length; i++)
_initialColors[i] = _spriteRenderers[i].color;
}
// Задержка перед появлением (как в предыдущей логике)
yield return new WaitForSeconds(reappearDelay);
// Запоминаем текущую альфу для каждого рендерера
float[] startAlphas = new float[_spriteRenderers.Length];
for (int i = 0; i < _spriteRenderers.Length; i++)
startAlphas[i] = _spriteRenderers[i].color.a;
float elapsed = 0f;
while (elapsed < reappearDuration)
{
elapsed += Time.deltaTime;
float t = reappearDuration > 0f ? Mathf.Clamp01(elapsed / reappearDuration) : 1f;
for (int i = 0; i < _spriteRenderers.Length; i++)
{
Color c = _initialColors[i];
float alpha = Mathf.Lerp(startAlphas[i], 1f, t);
_spriteRenderers[i].color = new Color(c.r, c.g, c.b, alpha);
}
yield return null;
}
// Принудительно установить полную непрозрачность
for (int i = 0; i < _spriteRenderers.Length; i++)
{
Color c = _initialColors[i];
_spriteRenderers[i].color = new Color(c.r, c.g, c.b, 1f);
}
if (_rigidbody)
_rigidbody.simulated = true; // возвращаем физику
_reappearCoroutine = null;
}
/// <summary>
/// Позволяет внешним системам сразу запустить исчезновение (без ожидания).
/// </summary>
public void TriggerVanish()
{
if (_delayedVanishCoroutine != null)
{
StopCoroutine(_delayedVanishCoroutine);
_delayedVanishCoroutine = null;
}
if (_reappearCoroutine != null)
{
StopCoroutine(_reappearCoroutine);
_reappearCoroutine = null;
}
if (_vanishCoroutine != null)
StopCoroutine(_vanishCoroutine);
_vanishCoroutine = StartCoroutine(Vanish());
}
/// <summary>
/// Позволяет внешним системам сразу запустить появление.
/// </summary>
public void TriggerReappear()
{
if (_delayedVanishCoroutine != null)
{
StopCoroutine(_delayedVanishCoroutine);
_delayedVanishCoroutine = null;
}
if (_vanishCoroutine != null)
{
StopCoroutine(_vanishCoroutine);
_vanishCoroutine = null;
}
if (_reappearCoroutine != null)
StopCoroutine(_reappearCoroutine);
_reappearCoroutine = StartCoroutine(Reappear());
}
/// <summary>
/// Ожидает заданную задержку перед фактическим запуском корутины Vanish.
/// </summary>
private IEnumerator StartVanishWithDelay()
{
if (vanishStartDelay > 0f)
yield return new WaitForSeconds(vanishStartDelay); // выдерживаем таймер ожидания
_vanishCoroutine = StartCoroutine(Vanish());
_delayedVanishCoroutine = null;
}
}

View File

@ -1,143 +1,146 @@
using UnityEngine;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using System.Collections;
public class ScrollSelectionFollower : MonoBehaviour
namespace RR.Common.UI
{
[SerializeField] private ScrollRect scrollRect;
[SerializeField] private float padding = 8f; // отступы сверху/снизу/слева/справа
[SerializeField] private float duration = 0.15f; // длительность анимации
[SerializeField] private bool onlyWhenNotVisible = true; // если false — центрируем всегда
private GameObject _lastSelected;
private Coroutine _anim;
private void Reset()
public class ScrollSelectionFollower : MonoBehaviour
{
scrollRect = GetComponentInChildren<ScrollRect>();
}
[SerializeField] private ScrollRect scrollRect;
[SerializeField] private float padding = 8f; // отступы сверху/снизу/слева/справа
[SerializeField] private float duration = 0.15f; // длительность анимации
[SerializeField] private bool onlyWhenNotVisible = true; // если false — центрируем всегда
private void LateUpdate()
{
GameObject sel = EventSystem.current ? EventSystem.current.currentSelectedGameObject : null;
if (!sel || sel == _lastSelected) return;
private GameObject _lastSelected;
private Coroutine _anim;
// Только если элемент внутри нашего Content
if (!scrollRect || sel.transform is not RectTransform tr || !tr.IsChildOf(scrollRect.content)) return;
ScrollTo(tr);
_lastSelected = sel;
}
public void ScrollTo(RectTransform target)
{
if (!scrollRect || !target) return;
// Сначала убедимся, что лейауты посчитались
Canvas.ForceUpdateCanvases();
RectTransform content = scrollRect.content;
RectTransform viewport = scrollRect.viewport != null ? scrollRect.viewport : (RectTransform)scrollRect.transform;
// Получаем мировые углы и преобразуем в локальное пространство viewport
Vector3[] itemCorners = new Vector3[4];
target.GetWorldCorners(itemCorners);
Vector3[] viewportCorners = new Vector3[4];
viewport.GetWorldCorners(viewportCorners);
// Преобразуем в локальное пространство content
for (int i = 0; i < 4; i++)
private void Reset()
{
itemCorners[i] = content.InverseTransformPoint(itemCorners[i]);
viewportCorners[i] = content.InverseTransformPoint(viewportCorners[i]);
scrollRect = GetComponentInChildren<ScrollRect>();
}
// Вычисляем границы
float itemTop = itemCorners[1].y;
float itemBottom = itemCorners[0].y;
float itemLeft = itemCorners[0].x;
float itemRight = itemCorners[2].x;
float viewTop = viewportCorners[1].y;
float viewBottom = viewportCorners[0].y;
float viewLeft = viewportCorners[0].x;
float viewRight = viewportCorners[2].x;
Vector2 offset = Vector2.zero;
// Вертикальная прокрутка
if (scrollRect.vertical)
private void LateUpdate()
{
float delta = 0f;
bool above = itemTop > viewTop - padding;
bool below = itemBottom < viewBottom + padding;
GameObject sel = EventSystem.current ? EventSystem.current.currentSelectedGameObject : null;
if (!sel || sel == _lastSelected) return;
if (!onlyWhenNotVisible || above || below)
// Только если элемент внутри нашего Content
if (!scrollRect || sel.transform is not RectTransform tr || !tr.IsChildOf(scrollRect.content)) return;
ScrollTo(tr);
_lastSelected = sel;
}
private void ScrollTo(RectTransform target)
{
if (!scrollRect || !target) return;
// Сначала убедимся, что лейауты посчитались
Canvas.ForceUpdateCanvases();
RectTransform content = scrollRect.content;
RectTransform viewport = scrollRect.viewport != null ? scrollRect.viewport : (RectTransform)scrollRect.transform;
// Получаем мировые углы и преобразуем в локальное пространство viewport
Vector3[] itemCorners = new Vector3[4];
target.GetWorldCorners(itemCorners);
Vector3[] viewportCorners = new Vector3[4];
viewport.GetWorldCorners(viewportCorners);
// Преобразуем в локальное пространство content
for (int i = 0; i < 4; i++)
{
if (above && below)
{
// Элемент больше viewport - выравниваем по верхнему краю
delta = itemTop - (viewTop - padding);
}
else if (above)
{
delta = itemTop - (viewTop - padding);
}
else if (below)
{
delta = itemBottom - (viewBottom + padding);
}
offset.y = delta;
itemCorners[i] = content.InverseTransformPoint(itemCorners[i]);
viewportCorners[i] = content.InverseTransformPoint(viewportCorners[i]);
}
}
// Горизонтальная прокрутка
if (scrollRect.horizontal)
{
float delta = 0f;
bool left = itemLeft < viewLeft + padding;
bool right = itemRight > viewRight - padding;
// Вычисляем границы
float itemTop = itemCorners[1].y;
float itemBottom = itemCorners[0].y;
float itemLeft = itemCorners[0].x;
float itemRight = itemCorners[2].x;
if (!onlyWhenNotVisible || left || right)
float viewTop = viewportCorners[1].y;
float viewBottom = viewportCorners[0].y;
float viewLeft = viewportCorners[0].x;
float viewRight = viewportCorners[2].x;
Vector2 offset = Vector2.zero;
// Вертикальная прокрутка
if (scrollRect.vertical)
{
if (left && right)
float delta = 0f;
bool above = itemTop > viewTop - padding;
bool below = itemBottom < viewBottom + padding;
if (!onlyWhenNotVisible || above || below)
{
// Элемент больше viewport - выравниваем по левому краю
delta = itemLeft - (viewLeft + padding);
if (above && below)
{
// Элемент больше viewport - выравниваем по верхнему краю
delta = itemTop - (viewTop - padding);
}
else if (above)
{
delta = itemTop - (viewTop - padding);
}
else if (below)
{
delta = itemBottom - (viewBottom + padding);
}
offset.y = delta;
}
else if (left)
{
delta = itemLeft - (viewLeft + padding);
}
else if (right)
{
delta = itemRight - (viewRight - padding);
}
offset.x = delta;
}
// Горизонтальная прокрутка
if (scrollRect.horizontal)
{
float delta = 0f;
bool left = itemLeft < viewLeft + padding;
bool right = itemRight > viewRight - padding;
if (!onlyWhenNotVisible || left || right)
{
if (left && right)
{
// Элемент больше viewport - выравниваем по левому краю
delta = itemLeft - (viewLeft + padding);
}
else if (left)
{
delta = itemLeft - (viewLeft + padding);
}
else if (right)
{
delta = itemRight - (viewRight - padding);
}
offset.x = delta;
}
}
if (offset == Vector2.zero) return;
Vector2 targetPos = content.anchoredPosition - offset;
if (_anim != null) StopCoroutine(_anim);
_anim = StartCoroutine(AnimateTo(content, targetPos, duration));
}
if (offset == Vector2.zero) return;
Vector2 targetPos = content.anchoredPosition - offset;
if (_anim != null) StopCoroutine(_anim);
_anim = StartCoroutine(AnimateTo(content, targetPos, duration));
}
private static IEnumerator AnimateTo(RectTransform content, Vector2 target, float time)
{
Vector2 start = content.anchoredPosition;
float t = 0f;
while (t < 1f)
private static IEnumerator AnimateTo(RectTransform content, Vector2 target, float time)
{
t += Time.unscaledDeltaTime / Mathf.Max(0.0001f, time);
// лёгкая ease-in-out
float s = t * t * (3f - 2f * t);
content.anchoredPosition = Vector2.LerpUnclamped(start, target, s);
yield return null;
Vector2 start = content.anchoredPosition;
float t = 0f;
while (t < 1f)
{
t += Time.unscaledDeltaTime / Mathf.Max(0.0001f, time);
// лёгкая ease-in-out
float s = t * t * (3f - 2f * t);
content.anchoredPosition = Vector2.LerpUnclamped(start, target, s);
yield return null;
}
content.anchoredPosition = target;
}
content.anchoredPosition = target;
}
}
}

View File

@ -7,7 +7,7 @@ using RR.Game2D.Core.Managers;
namespace RR.Common.UI
{
[RequireComponent(typeof(CanvasGroup), typeof(SettingsUIList))]
[RequireComponent(typeof(CanvasGroup))]
public class SettingsUI : MonoBehaviour
{
[Header("Управление")]

View File

@ -1,54 +1,57 @@
using System;
using System;
using RR.Common.Managers;
using RR.Game2D.Core.Managers;
using TMPro;
using UnityEngine;
public class UICreditsTextController : MonoBehaviour
namespace RR.Common.UI
{
// UI elements
[SerializeField] private TextMeshProUGUI livesIncreaseText;
[SerializeField] private TextMeshProUGUI livesText;
// Strings to display
[SerializeField] private string livesIncreaseString = "{0}";
[SerializeField] private string livesString = "У вас будет {0}";
private GameManager _gameManager;
private SettingsManager _settingsManager;
private void Start()
public class UICreditsTextController : MonoBehaviour
{
_gameManager = GameManager.Instance;
// UI elements
[SerializeField] private TextMeshProUGUI livesIncreaseText;
[SerializeField] private TextMeshProUGUI livesText;
if (_gameManager == null) return;
// Strings to display
[SerializeField] private string livesIncreaseString = "{0}";
[SerializeField] private string livesString = "У вас будет {0}";
_settingsManager = _gameManager.Settings;
if (_settingsManager == null) _settingsManager = SettingsManager.Instance;
UpdateLivesText(_gameManager.MaxLives);
UpdateLivesIncreaseText();
_gameManager.MaxLivesChanged += (UpdateLivesText);
_gameManager.Settings.OnSettingsLoaded += UpdateLivesIncreaseText;
_gameManager.Settings.OnSettingsSaved += UpdateLivesIncreaseText;
}
private GameManager _gameManager;
private SettingsManager _settingsManager;
private void OnDestroy()
{
if (_gameManager == null) _gameManager = GameManager.Instance;
if (_gameManager != null) _gameManager.MaxLivesChanged -= UpdateLivesText;
}
private void Start()
{
_gameManager = GameManager.Instance;
private void UpdateLivesIncreaseText()
{
livesIncreaseText.text = string.Format(livesIncreaseString, _settingsManager.GetCurrentGameSettings().livesIncreasedByCredits);
if (_gameManager == null) return;
_settingsManager = _gameManager.Settings;
if (_settingsManager == null) _settingsManager = SettingsManager.Instance;
UpdateLivesText(_gameManager.MaxLives);
UpdateLivesIncreaseText();
_gameManager.MaxLivesChanged += (UpdateLivesText);
_gameManager.Settings.OnSettingsLoaded += UpdateLivesIncreaseText;
_gameManager.Settings.OnSettingsSaved += UpdateLivesIncreaseText;
}
private void OnDestroy()
{
if (_gameManager == null) _gameManager = GameManager.Instance;
if (_gameManager != null) _gameManager.MaxLivesChanged -= UpdateLivesText;
}
private void UpdateLivesIncreaseText()
{
livesIncreaseText.text = string.Format(livesIncreaseString, _settingsManager.GetCurrentGameSettings().livesIncreasedByCredits);
}
private void UpdateLivesText(int newLives)
{
livesText.text = string.Format(livesString, newLives);
}
}
private void UpdateLivesText(int newLives)
{
livesText.text = string.Format(livesString, newLives);
}
}
}

View File

@ -1,126 +1,129 @@
using UnityEngine;
using UnityEngine;
using UnityEngine.EventSystems;
public class UIPointer : MonoBehaviour
namespace RR.Common.UI
{
[Header("Настройки")]
[SerializeField] private GameObject pointer;
[SerializeField] private RectTransform content; // Content ScrollView, где находятся элементы
[SerializeField] private float smoothSpeed = 10f; // Скорость перемещения указателя
[SerializeField] private Vector2 offset = Vector2.zero; // Смещение указателя относительно элемента
private RectTransform pointerRect;
private void Start()
public class UIPointer : MonoBehaviour
{
if (pointer != null)
[Header("Настройки")]
[SerializeField] private GameObject pointer;
[SerializeField] private RectTransform content; // Content ScrollView, где находятся элементы
[SerializeField] private float smoothSpeed = 10f; // Скорость перемещения указателя
[SerializeField] private Vector2 offset = Vector2.zero; // Смещение указателя относительно элемента
private RectTransform pointerRect;
private void Start()
{
pointerRect = pointer.GetComponent<RectTransform>();
if (pointerRect == null)
if (pointer != null)
{
Debug.LogError("UIPointer: pointer не имеет RectTransform!");
pointerRect = pointer.GetComponent<RectTransform>();
if (pointerRect == null)
{
Debug.LogError("UIPointer: pointer не имеет RectTransform!");
}
}
else
{
Debug.LogError("UIPointer: pointer не назначен!");
}
// Если content не задан, пытаемся найти его автоматически
if (content == null)
{
content = GetComponent<RectTransform>();
}
}
else
private void LateUpdate()
{
Debug.LogError("UIPointer: pointer не назначен!");
if (!pointerRect || !content) return;
// Получаем текущий выбранный элемент из EventSystem
GameObject selected = EventSystem.current?.currentSelectedGameObject;
// Если ничего не выбрано, скрываем указатель
if (selected == null)
{
if (pointer.activeSelf)
pointer.SetActive(false);
return;
}
// Проверяем, что выбранный элемент находится внутри нашего content
RectTransform selectedRect = selected.GetComponent<RectTransform>();
if (!selectedRect || !selectedRect.IsChildOf(content))
{
if (pointer.activeSelf)
pointer.SetActive(false);
return;
}
// Показываем указатель, если он был скрыт
if (!pointer.activeSelf)
pointer.SetActive(true);
// Вычисляем целевую позицию
Vector2 targetPos = GetTargetPosition(selectedRect);
// Плавно перемещаем указатель
if (smoothSpeed > 0)
{
pointerRect.anchoredPosition = Vector2.Lerp(
pointerRect.anchoredPosition,
targetPos,
Time.unscaledDeltaTime * smoothSpeed
);
}
else
{
pointerRect.anchoredPosition = targetPos;
}
}
// Если content не задан, пытаемся найти его автоматически
if (content == null)
private Vector2 GetTargetPosition(RectTransform target)
{
content = GetComponent<RectTransform>();
}
}
// Получаем позицию целевого элемента относительно content
Vector2 targetAnchoredPos = target.anchoredPosition;
private void LateUpdate()
{
if (!pointerRect || !content) return;
// Если элементы не прямые дети content, нужно пересчитать позицию
if (target.parent == content)
return new Vector2(
pointerRect.anchoredPosition.x + offset.x, // X оставляем как есть (или применяем offset)
targetAnchoredPos.y + offset.y // Y берем от целевого элемента
);
// Конвертируем мировую позицию в локальную позицию content
Vector3[] corners = new Vector3[4];
target.GetWorldCorners(corners);
Vector3 center = (corners[0] + corners[2]) * 0.5f;
// Получаем текущий выбранный элемент из EventSystem
GameObject selected = EventSystem.current?.currentSelectedGameObject;
// Если ничего не выбрано, скрываем указатель
if (selected == null)
{
if (pointer.activeSelf)
pointer.SetActive(false);
return;
}
// Проверяем, что выбранный элемент находится внутри нашего content
RectTransform selectedRect = selected.GetComponent<RectTransform>();
if (!selectedRect || !selectedRect.IsChildOf(content))
{
if (pointer.activeSelf)
pointer.SetActive(false);
return;
}
// Показываем указатель, если он был скрыт
if (!pointer.activeSelf)
pointer.SetActive(true);
// Вычисляем целевую позицию
Vector2 targetPos = GetTargetPosition(selectedRect);
// Плавно перемещаем указатель
if (smoothSpeed > 0)
{
pointerRect.anchoredPosition = Vector2.Lerp(
pointerRect.anchoredPosition,
targetPos,
Time.unscaledDeltaTime * smoothSpeed
RectTransformUtility.ScreenPointToLocalPointInRectangle(
content,
RectTransformUtility.WorldToScreenPoint(null, center),
null,
out Vector2 localPos
);
}
else
{
pointerRect.anchoredPosition = targetPos;
}
}
targetAnchoredPos = localPos;
private Vector2 GetTargetPosition(RectTransform target)
{
// Получаем позицию целевого элемента относительно content
Vector2 targetAnchoredPos = target.anchoredPosition;
// Если элементы не прямые дети content, нужно пересчитать позицию
if (target.parent == content)
// Применяем смещение
return new Vector2(
pointerRect.anchoredPosition.x + offset.x, // X оставляем как есть (или применяем offset)
targetAnchoredPos.y + offset.y // Y берем от целевого элемента
);
// Конвертируем мировую позицию в локальную позицию content
Vector3[] corners = new Vector3[4];
target.GetWorldCorners(corners);
Vector3 center = (corners[0] + corners[2]) * 0.5f;
}
RectTransformUtility.ScreenPointToLocalPointInRectangle(
content,
RectTransformUtility.WorldToScreenPoint(null, center),
null,
out Vector2 localPos
);
targetAnchoredPos = localPos;
// Метод для ручного обновления позиции указателя (если нужно)
public void UpdatePointerPosition()
{
if (pointerRect == null || content == null) return;
// Применяем смещение
return new Vector2(
pointerRect.anchoredPosition.x + offset.x, // X оставляем как есть (или применяем offset)
targetAnchoredPos.y + offset.y // Y берем от целевого элемента
);
GameObject selected = EventSystem.current?.currentSelectedGameObject;
if (selected == null) return;
RectTransform selectedRect = selected.GetComponent<RectTransform>();
if (selectedRect == null || !selectedRect.IsChildOf(content)) return;
pointerRect.anchoredPosition = GetTargetPosition(selectedRect);
}
}
// Метод для ручного обновления позиции указателя (если нужно)
public void UpdatePointerPosition()
{
if (pointerRect == null || content == null) return;
GameObject selected = EventSystem.current?.currentSelectedGameObject;
if (selected == null) return;
RectTransform selectedRect = selected.GetComponent<RectTransform>();
if (selectedRect == null || !selectedRect.IsChildOf(content)) return;
pointerRect.anchoredPosition = GetTargetPosition(selectedRect);
}
}
}

View File

@ -697,7 +697,7 @@ PlayerSettings:
framebufferDepthMemorylessMode: 0
qualitySettingsNames: []
projectName: Mario-like platformer
organizationId: dis_bro
organizationId:
cloudEnabled: 0
legacyClampBlendShapeWeights: 0
hmiLoadingImage: {fileID: 0}