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);
}
}
}