Platformer level management

This commit is contained in:
ThomasCharester committed 2026-03-23 12:01:33 +03:00
1 parent 72070901ec
commit 1aceea1b79
94 files changed
+3656 -197

No files matched your search

@@ -1,4 +1,8 @@
using System;
using Code.Infrastructure.Audio;
using Code.Infrastructure.Configs;
using Cysharp.Threading.Tasks;
using Reflex.Attributes;
using UnityEngine;
namespace Code.Example.Platformer.Entity.Enemies
@@ -11,11 +15,42 @@ namespace Code.Example.Platformer.Entity.Enemies
private float _acceleration = 3f;
[SerializeField] private EntityHealth health;
[Inject] private IAudioService _audioService;
private void Start()
{
health.OnEntityDamage = OnEntityDamage;
health.OnEntityDeath = OnEntityDeath;
}
private void OnEntityDeath()
{
animator.SetBool(Died, true);
animator.SetTrigger(OnDeath);
Die().Forget();
}
private async UniTaskVoid Die()
{
await UniTask.WaitForSeconds(1);
_audioService.PlayOneShot(AudioNames.Platformer, 3 );
Destroy(gameObject);
}
private void OnEntityDamage(int obj)
{
_audioService.PlayOneShot(AudioNames.Platformer, 2);
UnityEngine.Debug.Log(gameObject.name + " damaged");
animator.SetTrigger(OnHit);
}
protected override void Move()
{
if (health.IsDead) return;
if (_target)
{
_directionRight = ((_target.position - transform.position)).x > float.Epsilon;
TryAttack();
_directionRight = (_target.position - transform.position).x > float.Epsilon;
UnityEngine.Debug.DrawLine(transform.position, (transform.position + (_target.position - transform.position)), Color.salmon);
CheckupDirection();
@@ -30,7 +65,7 @@ namespace Code.Example.Platformer.Entity.Enemies
rigidbody2D.linearVelocityX = _directionRight ? 0.5f : -0.5f;
}
}
protected override void HandleFlipX() => spriteRenderer.flipX = rigidbody2D.linearVelocity.x > -0.01f;
private void CheckupDirection()
@@ -45,9 +80,15 @@ namespace Code.Example.Platformer.Entity.Enemies
LayerMasks.Masks[LayerMaskType.PlatformerGround]))
_directionRight = true;
}
private void TryAttack()
{
if ((transform.position - _target.position).magnitude < attackThreshold) _target.GetComponent<EntityHealth>().GiveDamage(1);
}
private Transform _target;
private float attackThreshold = 0.5f;
public void GotTarget(Transform target)
{
_target = target;
@@ -5,26 +5,42 @@ namespace Code.Example.Platformer.Entity
{
public abstract class Entity : MonoBehaviour
{
private static readonly int VelocityY = Animator.StringToHash("VelocityY");
private static readonly int VelocityX = Animator.StringToHash("VelocityX");
private static readonly int OnGround = Animator.StringToHash("OnGround");
protected static readonly int VelocityY = Animator.StringToHash("VelocityY");
protected static readonly int VelocityX = Animator.StringToHash("VelocityX");
protected static readonly int OnGround = Animator.StringToHash("OnGround");
protected static readonly int OnHit = Animator.StringToHash("OnHit");
protected static readonly int OnDeath = Animator.StringToHash("OnDeath");
protected static readonly int Died = Animator.StringToHash("Died");
[SerializeField] protected Rigidbody2D rigidbody2D;
[SerializeField] protected Animator animator;
[SerializeField] protected SpriteRenderer spriteRenderer;
[SerializeField] private Vector2 groundPoint;
private PlatformerEntityData _data;
private PlatformerEntityData _data; // TODO
protected bool isFreezed;
protected bool onGround;
public void SetData(PlatformerEntityData data)
{
_data = data;
}
protected bool onGround;
public void Freeze()
{
rigidbody2D.bodyType = RigidbodyType2D.Kinematic;
isFreezed = true;
}
public void UnFreeze()
{
rigidbody2D.bodyType = RigidbodyType2D.Dynamic;
isFreezed = false;
}
protected virtual void Update()
{
if(isFreezed) return;
animator.SetFloat(VelocityX, rigidbody2D.linearVelocityX);
animator.SetFloat(VelocityY, rigidbody2D.linearVelocityY);
}
@@ -33,6 +49,8 @@ namespace Code.Example.Platformer.Entity
protected virtual void FixedUpdate()
{
if(isFreezed) return;
onGround = CheckGround();
animator.SetBool(OnGround, onGround);
@@ -48,8 +66,5 @@ namespace Code.Example.Platformer.Entity
}
protected abstract void Move();
public virtual void OnGetDamage(){}
public virtual void OnDeath(){}
}
}
@@ -1,4 +1,6 @@
using System;
using Code.Infrastructure.EventBus;
using Cysharp.Threading.Tasks;
using Reflex.Attributes;
using UnityEngine;
@@ -8,19 +10,47 @@ namespace Code.Example.Platformer.Entity
{
private int _health;
private int _maxHealth;
public void SetMaxHealth(int maxHealth) => _maxHealth = maxHealth;
private float _damageThreshold;
public void Setup(int maxHealth, float damageThreshold)
{
_maxHealth = maxHealth;
_health = maxHealth;
_damageThreshold = damageThreshold;
}
public bool IsDead { get; private set; }
private bool _isDamageable = true;
[Inject] private EventBus _eventBus;
[SerializeField] private Entity entity;
[Inject] private EventBus _eventBus;
public Action<int> OnEntityHeal;
public Action<int> OnEntityDamage;
public Action OnEntityDeath;
private async UniTaskVoid WaitThreshold()
{
await UniTask.WaitForSeconds(_damageThreshold);
_isDamageable = true;
}
public void GiveDamage(int damage)
{
if (!_isDamageable) return;
_health -= damage;
if(_health <= 0) IsDead = true;
_isDamageable = false;
OnEntityDamage?.Invoke(_health);
if(_health <= 0)
{
IsDead = true;
OnEntityDeath?.Invoke();
}
_eventBus.RaiseEvent<IEntityDamagedHandler>(x=> x.EntityDamaged(gameObject, damage, IsDead));
WaitThreshold().Forget();
}
public void Heal(int heal)
@@ -29,6 +59,8 @@ namespace Code.Example.Platformer.Entity
if (_health + heal > _maxHealth) _health = _maxHealth;
else _health += heal;
OnEntityHeal?.Invoke(_health);
_eventBus.RaiseEvent<IEntityHealedHandler>(x=> x.EntityHealed(gameObject, heal));
}
}
@@ -4,9 +4,12 @@ using System.Linq;
using Code.Infrastructure.Configs;
using Code.Infrastructure.EventBus;
using Cysharp.Threading.Tasks;
using Reflex.Core;
using Reflex.Injectors;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using Object = UnityEngine.Object;
namespace Code.Example.Platformer.Entity
{
@@ -15,7 +18,7 @@ namespace Code.Example.Platformer.Entity
UniTaskVoid WarmEnemy(PlatformerEntityType enemyType);
void ReleaseEnemy(PlatformerEntityType racerType);
UniTaskVoid SpawnEnemy(
void SpawnEnemy(
PlatformerEntityType enemyType,
Vector3 position);
}
@@ -67,10 +70,6 @@ namespace Code.Example.Platformer.Entity
await _enemyPrefabsHandle[enemyType].ToUniTask();
var entity = _enemyPrefabsHandle[enemyType].Result.GetComponent<Entity>();
entity.SetData(_enemyConfigs[enemyType].EntityData);
var health = _enemyPrefabsHandle[enemyType].Result.GetComponent<EntityHealth>();
health.SetMaxHealth(_enemyConfigs[enemyType].EntityData.maxHealth);
_eventBus.RaiseEvent<IPlatformerEnemyLoadedHandle>(x => x.PlatformerEnemyLoaded(enemyType, entity));
}
@@ -81,13 +80,21 @@ namespace Code.Example.Platformer.Entity
_enemyPrefabsHandle.Remove(racerType);
}
public async UniTaskVoid SpawnEnemy(
public void SpawnEnemy(
PlatformerEntityType enemyType,
Vector3 position)
{
if (enemyType == PlatformerEntityType.Player) return;
await Addressables.InstantiateAsync(_enemyConfigs[enemyType].prefabReference, position, Quaternion.identity);
var gameObject = Object.Instantiate(_enemyPrefabsHandle[enemyType].Result, position, Quaternion.identity);
var entity = gameObject.GetComponent<Entity>();
entity.SetData(_enemyConfigs[enemyType].EntityData);
var health = gameObject.GetComponent<EntityHealth>();
health.Setup(_enemyConfigs[enemyType].EntityData.maxHealth, _enemyConfigs[enemyType].EntityData.damageRecieveThreshold);
GameObjectInjector.InjectObject(gameObject, Container.RootContainer);
}
public void Dispose()
@@ -1,6 +1,7 @@
using System;
using Code.Infrastructure.Generators;
using UnityEngine.AddressableAssets;
using UnityEngine.Serialization;
namespace Code.Example.Platformer.Entity
{
@@ -14,6 +15,7 @@ namespace Code.Example.Platformer.Entity
public int damage;
public PlatformerEntityType type;
public int maxHealth;
public float damageRecieveThreshold;
}
public enum PlatformerEntityType
@@ -10,15 +10,16 @@ using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.SceneManagement;
using Object = UnityEngine.Object;
namespace Code.Example.Platformer.Entity
{
public interface IPlatformerPlayerFactory
{
UniTaskVoid LoadPlayer();
UniTaskVoid WarmPlayer();
void ReleasePlayer();
UniTaskVoid SpawnPlayer(Vector3 position);
void SpawnPlayer(Vector3 position);
}
public class PlatformerPlayerFactory : IPlatformerPlayerFactory, IDisposable
@@ -50,7 +51,7 @@ namespace Code.Example.Platformer.Entity
_eventBus.RaiseEvent<IPlatformerPlayerFactoryInitializedHandle>(x => x.PlatformerPlayerFactoryInitialized());
}
public async UniTaskVoid LoadPlayer()
public async UniTaskVoid WarmPlayer()
{
if (_playerPrefabHandle.IsValid())
{
@@ -63,8 +64,6 @@ namespace Code.Example.Platformer.Entity
_playerPrefabHandle = Addressables.LoadAssetAsync<GameObject>(_playerConfig.prefabReference);
await _playerPrefabHandle.ToUniTask();
var racer = _playerPrefabHandle.Result.GetComponent<Entity>();
racer.SetData(_playerConfig.EntityData);
_eventBus.RaiseEvent<IPlatformerPlayerLoadedHandle>(x => x.PlatformerPlayerLoaded());
}
@@ -74,11 +73,20 @@ namespace Code.Example.Platformer.Entity
_playerPrefabHandle.Release();
}
public async UniTaskVoid SpawnPlayer(Vector3 position)
public void SpawnPlayer(Vector3 position)
{
var player = await Addressables.InstantiateAsync(_playerConfig.prefabReference, position, Quaternion.identity).ToUniTask();
var player = Object.Instantiate(_playerPrefabHandle.Result, position, Quaternion.identity);
var racer = player.GetComponent<Entity>();
racer.SetData(_playerConfig.EntityData);
var health = player.GetComponent<EntityHealth>();
health.Setup(_playerConfig.EntityData.maxHealth, _playerConfig.EntityData.damageRecieveThreshold);
GameObjectInjector.InjectObject(player, Container.RootContainer); // TODO САМОЕ НЕСТАБИЛЬНОЕ ДЕРЬМО ВО ВСЕЛЕННОЙ КОНТЕЙНЕР ДОЛЖЕН БЫТЬ КОНТЕКСТНЫМ
_eventBus.RaiseEvent<IPlatformerPlayerSpawnedHandle>(x => x.PlatformerPlayerSpawned(player.GetComponent<Entity>()));
_eventBus.RaiseEvent<IPlatformerPlayerSpawnedHandle>(
x => x.PlatformerPlayerSpawned(player.GetComponent<Entity>()));
}
public void Dispose()
@@ -1,3 +1,4 @@
using System;
using Code.Infrastructure.Audio;
using Code.Infrastructure.Camera;
using Code.Infrastructure.Configs;
@@ -32,6 +33,11 @@ namespace Code.Example.Platformer.Entity
}
private void OnDestroy()
{
if(!health.IsDead) UnbindControls();
}
private void UnbindControls()
{
_inputService.UnbindActionPerformed((int)ActionMappings.Platformer, (int)PlatformerActions.Move,
MovementPerformed);
@@ -65,6 +71,8 @@ namespace Code.Example.Platformer.Entity
rigidbody2D.AddForceY(100f);
_acceleration = 1f;
_audioService.PlayOneShot(AudioNames.Platformer, 6);
}
[SerializeField] private Vector2 attackOffset;
@@ -75,7 +83,7 @@ namespace Code.Example.Platformer.Entity
//
//
_audioService.PlayOneShot(AudioNames.UISounds, 1);
_audioService.PlayOneShot(AudioNames.Platformer, 1);
animator.SetBool(OnAttack, true);
}
@@ -89,7 +97,6 @@ namespace Code.Example.Platformer.Entity
foreach (var damaged in damagedOnes)
{
damaged.gameObject.GetComponent<EntityHealth>().GiveDamage(1);
_audioService.PlayOneShot(AudioNames.UISounds, 2);
}
}
@@ -105,5 +112,28 @@ namespace Code.Example.Platformer.Entity
}
public void AttackEnd() => animator.SetBool(OnAttack, false);
[SerializeField] private EntityHealth health;
private void Start()
{
health.OnEntityDeath = OnEntityDeath;
health.OnEntityDamage = OnEntityDamage;
}
private void OnEntityDamage(int obj)
{
UnityEngine.Debug.Log("Player damaged");
}
private void OnEntityDeath()
{
_moveDirection = Vector2.zero;
animator.SetBool(Died, true);
UnbindControls();
// Destroy(gameObject, 1f);
}
}
}
@@ -0,0 +1,14 @@
using Code.Infrastructure.EventBus;
using Reflex.Attributes;
using UnityEngine;
namespace Code.Example.Platformer.Level
{
public class LevelEndTrigger : MonoBehaviour
{
[Inject] private EventBus _eventBus;
private void OnTriggerEnter2D(Collider2D other) =>
_eventBus.RaiseEvent<IPlayerReachedFinishHandle>(x=> x.PlayerReachedFinish());
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8241eab603dc4d86bb4bac79c0cb9740
timeCreated: 1774254263
@@ -0,0 +1,28 @@
using Code.Example.Platformer.Level;
using Code.Infrastructure.EventBus;
using Code.Infrastructure.SceneLoader;
using Reflex.Core;
using UnityEngine;
namespace Code.Example.Platformer
{
public class Platformer2SceneInstaller :
MonoBehaviour,
IInstaller
{
// [SerializeField] private PlatformerCanvas gameplayPlatformerCanvas;
[SerializeField] private PlatformerFirstLevelData firstLevelData;
public void InstallBindings(ContainerBuilder containerBuilder)
{
containerBuilder.RegisterValue(firstLevelData);
containerBuilder.OnContainerBuilt += OnContainerBuild;
}
private void OnContainerBuild(Container container)
{
container.Resolve<EventBus>()
.RaiseEvent<IOnPlatformer2SceneLoadedHandler>(x => x.OnPlatformer2SceneInitialized(container));
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9f7e699014b54f2ca9338e1168db97e3
timeCreated: 1774253993
@@ -0,0 +1,28 @@
using Code.Example.Platformer.Level;
using Code.Infrastructure.EventBus;
using Code.Infrastructure.SceneLoader;
using Reflex.Core;
using UnityEngine;
namespace Code.Example.Platformer
{
public class Platformer3SceneInstaller:
MonoBehaviour,
IInstaller
{
// [SerializeField] private PlatformerCanvas gameplayPlatformerCanvas;
[SerializeField] private PlatformerFirstLevelData firstLevelData;
public void InstallBindings(ContainerBuilder containerBuilder)
{
containerBuilder.RegisterValue(firstLevelData);
containerBuilder.OnContainerBuilt += OnContainerBuild;
}
private void OnContainerBuild(Container container)
{
container.Resolve<EventBus>()
.RaiseEvent<IOnPlatformer3SceneLoadedHandler>(x => x.OnPlatformer3SceneInitialized(container));
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f8ad38e6ff54474d8df1d26cb18c2d09
timeCreated: 1774254152
@@ -18,10 +18,9 @@ namespace Code.Example.Platformer
IPlatformerPlayerFactoryInitializedHandle,
IDisposable
{
// [SerializeField] private PlatformerCanvas gameplayPlatformerCanvas;
[SerializeField] private PlatformerFirstLevelData firstLevelData;
private Loading _sceneInit;
private Container _container;
private void LoadingComplete()
{
@@ -36,33 +35,21 @@ namespace Code.Example.Platformer
// Container
_sceneInit = new(3, LoadingComplete);
// containerBuilder.RegisterValue(gameplayPlatformerCanvas);
containerBuilder.Parent.Resolve<EventBus>().Subscribe(this);
containerBuilder.RegisterValue(firstLevelData);
containerBuilder.RegisterType(typeof(PlatformerEnemyFactory), new []{typeof(IPlatformerEnemyFactory)}, Lifetime.Scoped, Resolution.Eager);
containerBuilder.RegisterType(typeof(PlatformerPlayerFactory), new []{typeof(IPlatformerPlayerFactory)}, Lifetime.Scoped, Resolution.Eager);
containerBuilder.OnContainerBuilt += OnContainerBuild;
}
private Container _container;
private void OnContainerBuild(Container container)
{
// gameplayPlatformerCanvas.GameplayPlatformerCanvas.worldCamera =
// container.Resolve<CameraStateMachineContext>().cameraLoadedData.Camera;
_container = container;
_sceneInit.DoProgress();
}
public void PlatformerEnemyFactoryInitialized()
{
_sceneInit.DoProgress();
}
public void PlatformerEnemyFactoryInitialized() => _sceneInit.DoProgress();
public void PlatformerPlayerFactoryInitialized()
{
_sceneInit.DoProgress();
}
public void PlatformerPlayerFactoryInitialized() => _sceneInit.DoProgress();
public void Dispose()
{
+110 -39
View File
@@ -19,43 +19,58 @@ namespace Code.Example.Platformer
[StateRaisingEvent]
public partial class PlatformerState :
IOnPlatformerSceneLoadedHandler,
IOnPlatformer2SceneLoadedHandler,
IOnPlatformer3SceneLoadedHandler,
ICinematicMachineHandle,
IPlatformerEnemyLoadedHandle,
IPlatformerPlayerLoadedHandle,
IPlatformerPlayerSpawnedHandle
{
IPlatformerPlayerSpawnedHandle,
IReadyToPlayHandle,
IPlayerReachedFinishHandle
{
private IPlatformerEnemyFactory _enemyFactory;
private IPlatformerPlayerFactory _playerFactory;
private PlatformerFirstLevelData _currentLevelData;
private Entity.Entity _playerEntity;
private IAudioFactory _audioFactory;
private Container _fixdamncontainer;
private Loading _loading;
public PlatformerState(AppStateMachineContext context, EventBus eventBus) : base(context, eventBus)
{
}
public override AppStates myState => AppStates.Platformer;
protected override void OnEnterState()
{
EventBus.Subscribe(this);
// Scene
// Dependency scene
// Level scene
// Camera
// Enemy snail
// Enemy bee
// Enemy boar
// Player
_loading = new(6, LoadingCompleted);
// Music
_loading = new(8, InitialLoadingCompleted);
Context.UIService.OpenPanel(UIPanelType.Loading);
Context.SceneLoader.LoadSceneAsync(SceneId.Platformer, LoadSceneMode.Single).Forget();
Context.InputService.EnableMap(ActionMappings.Platformer);
Context.CameraFactory.LoadCinemachineCamera(CameraMode.Platformer).Forget();
}
private Loading _loading;
private void LoadingCompleted()
private void InitialLoadingCompleted()
{
Context.AudioService.CancelMusic(AudioNames.UISounds,0);
Context.UIService.ClosePanel(UIPanelType.Loading);
_enemyFactory.SpawnEnemy(PlatformerEntityType.Snail, _firstLevelData.enemySpawnPoints[0].position);
_enemyFactory.SpawnEnemy(PlatformerEntityType.Boar, _currentLevelData.enemySpawnPoints[0].position);
_playerFactory.SpawnPlayer(_firstLevelData.playerCheckPoints[0].position);
_playerFactory.SpawnPlayer(_currentLevelData.playerCheckPoints[0].position);
}
@@ -70,37 +85,10 @@ namespace Code.Example.Platformer
Context.CameraFactory.ReleaseCinemachineCamera(CameraMode.Platformer);
EventBus.Unsubscribe(this);
Context.InputService.DisableMap(ActionMappings.Platformer);
_audioFactory.ReleaseAudios(AudioNames.Platformer);
}
public void OnPlatformerSceneLoaded()
{
}
private IPlatformerEnemyFactory _enemyFactory;
private IPlatformerPlayerFactory _playerFactory;
private PlatformerFirstLevelData _firstLevelData;
private Container _fixdamncontainer;
public void OnPlatformerSceneInitialized(Container container)
{
_fixdamncontainer = container;
_firstLevelData = container.Resolve<PlatformerFirstLevelData>();
_enemyFactory = container.Resolve<IPlatformerEnemyFactory>();
_enemyFactory.WarmEnemy(PlatformerEntityType.Bee);
_enemyFactory.WarmEnemy(PlatformerEntityType.Boar);
_enemyFactory.WarmEnemy(PlatformerEntityType.Snail);
_playerFactory = container.Resolve<IPlatformerPlayerFactory>();
_playerFactory.LoadPlayer();
_loading.DoProgress();
}
public void CinemachineLoaded(CinemachineCamera cinemachineCamera)
{
@@ -119,7 +107,90 @@ namespace Code.Example.Platformer
public void PlatformerPlayerSpawned(Entity.Entity entity)
{
_playerEntity = entity;
Context.CameraFactory.GetCinematicCamera(CameraMode.Platformer).Follow = entity.transform;
}
public void OnReadyToPlay(AudioNames groupName)
{
if(groupName == AudioNames.Platformer) _loading.DoProgress();
}
public void PlayerReachedFinish()
{
_loading = new(1, Level2LoadingCompleted);
Context.UIService.OpenPanel(UIPanelType.Loading);
_playerEntity.Freeze();
SceneManager.MoveGameObjectToScene(_playerEntity.gameObject, Context.SceneLoader.GetScene(SceneId.Platformer));
Context.SceneLoader.UnloadSceneAsync(SceneId.Platformer2).Forget();
Context.SceneLoader.LoadSceneAsync(SceneId.Platformer3, LoadSceneMode.Additive).Forget();
}
private void Level2LoadingCompleted()
{
Context.UIService.ClosePanel(UIPanelType.Loading);
_enemyFactory.SpawnEnemy(PlatformerEntityType.Boar, _currentLevelData.enemySpawnPoints[0].position);
_playerEntity.transform.position = _currentLevelData.playerCheckPoints[0].position;
_playerEntity.UnFreeze();
}
public void OnPlatformerSceneLoaded()
{
Context.SceneLoader.LoadSceneAsync(SceneId.Platformer2, LoadSceneMode.Additive).Forget();
}
public void OnPlatformerSceneInitialized(Container container)
{
_fixdamncontainer = container;
_audioFactory = container.Resolve<IAudioFactory>();
_audioFactory.LoadAudioClips(AudioNames.Platformer);
_enemyFactory = container.Resolve<IPlatformerEnemyFactory>();
_enemyFactory.WarmEnemy(PlatformerEntityType.Bee);
_enemyFactory.WarmEnemy(PlatformerEntityType.Boar);
_enemyFactory.WarmEnemy(PlatformerEntityType.Snail);
_playerFactory = container.Resolve<IPlatformerPlayerFactory>();
_playerFactory.WarmPlayer();
_loading.DoProgress();
}
public void OnPlatformer2SceneLoaded()
{
SceneManager.SetActiveScene(Context.SceneLoader.GetScene(SceneId.Platformer2));
}
public void OnPlatformer2SceneInitialized(Container container)
{
_currentLevelData = container.Resolve<PlatformerFirstLevelData>();
_loading.DoProgress();
}
public void OnPlatformer3SceneLoaded()
{
}
public void OnPlatformer3SceneInitialized(Container container)
{
_currentLevelData = container.Resolve<PlatformerFirstLevelData>();
_loading.DoProgress();
}
}
public interface IPlayerReachedFinishHandle : IGlobalSubscriber
{
void PlayerReachedFinish();
}
}