Created
February 15, 2021 09:41
-
-
Save tomaszczerminski/130e49310a6cae86504453e11758f634 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Diagnostics.CodeAnalysis; | |
using Sirenix.OdinInspector; | |
using Sirenix.Serialization; | |
namespace SDK.Gameplay.States | |
{ | |
// We need it in order to enable/disable states | |
[SuppressMessage("ReSharper", "Unity.RedundantEventFunction")] | |
public abstract class AbstractState : SerializedMonoBehaviour | |
{ | |
private void OnEnable() | |
{ | |
} | |
private void OnDisable() | |
{ | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using SDK.Gameplay.States; | |
using Sirenix.OdinInspector; | |
using UnityEngine; | |
using Random = UnityEngine.Random; | |
namespace SDK.Gameplay.Unit.States | |
{ | |
public sealed class Dead : AbstractState | |
{ | |
private static readonly int DieAnimation = Animator.StringToHash("die"); | |
[ShowInInspector] private AudioSource AudioSource { get; set; } | |
[ShowInInspector] private Animator Animator { get; set; } | |
public void Enter() | |
{ | |
enabled = true; | |
AudioSource.volume = Random.Range(0.5f, 0.7f); | |
AudioSource.pitch = Random.Range(0.7f, 1f); | |
Animator.SetTrigger(DieAnimation); | |
} | |
private void Awake() | |
{ | |
AudioSource = GetComponent<AudioSource>(); | |
Animator = GetComponent<Animator>(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using SDK.Gameplay.Commands; | |
using SDK.Gameplay.States; | |
using Sirenix.OdinInspector; | |
using UniRx; | |
using UnityEngine; | |
namespace SDK.Gameplay.Unit.States | |
{ | |
public sealed class Idle : AbstractState | |
{ | |
private static readonly int IdleAnimation = Animator.StringToHash("idle_1"); | |
private static readonly IMessageBroker Broker = MessageBroker.Default; | |
[ShowInInspector] private Animator Animator { get; set; } | |
[ShowInInspector] private UsingSkill UsingSkill { get; set; } | |
[ShowInInspector] private TakingDamage TakingDamage { get; set; } | |
[ShowInInspector] private TakingHeal TakingHeal { get; set; } | |
[ShowInInspector] private Moving Moving { get; set; } | |
[ShowInInspector] private Entity Entity { get; set; } | |
public void Enter() | |
{ | |
enabled = true; | |
Animator.SetTrigger(IdleAnimation); | |
} | |
private void Exit() | |
{ | |
enabled = false; | |
} | |
private void Awake() | |
{ | |
Entity = GetComponent<Entity>(); | |
Animator = GetComponent<Animator>(); | |
UsingSkill = GetComponent<UsingSkill>(); | |
TakingDamage = GetComponent<TakingDamage>(); | |
Moving = GetComponent<Moving>(); | |
Broker.Receive<AttackCommand>() | |
.Where(_ => isActiveAndEnabled) | |
.Where(command => int.Parse(command.UnitId) == Entity.Id) | |
.Do(_ => Exit()) | |
.Subscribe(command => UsingSkill.Enter(command.Target, command.Skill)) | |
.AddTo(this); | |
Broker.Receive<TakeDamageCommand>() | |
.Where(_ => isActiveAndEnabled) | |
.Where(command => command.Target.Id == Entity.Id) | |
.Do(_ => Exit()) | |
.Subscribe(command => TakingDamage.Enter(command.Damage)) | |
.AddTo(this); | |
Broker.Receive<MoveCommand>() | |
.Where(_ => isActiveAndEnabled) | |
.Where(command => command.Entity.Id == Entity.Id) | |
.Subscribe(command => Moving.Enter(null)) | |
.AddTo(this); | |
Broker.Receive<TakeHealCommand>() | |
.Where(_ => isActiveAndEnabled) | |
.Where(command => command.Target.Id == Entity.Id) | |
.Subscribe(command => TakingHeal.Enter(command.Heal)) | |
.AddTo(this); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using SDK.Gameplay.States; | |
using Sirenix.OdinInspector; | |
using UniRx; | |
using UnityEngine; | |
namespace SDK.Gameplay.Unit.States | |
{ | |
public class Invisible : AbstractState | |
{ | |
[ShowInInspector] private Visible Visible { get; set; } | |
[ShowInInspector] private SpriteRenderer[] Renderers { get; set; } | |
private const float Speed = 0.5f; | |
public void Enter() | |
{ | |
enabled = true; | |
MainThreadDispatcher.StartFixedUpdateMicroCoroutine(HideRenderers()); | |
} | |
private IEnumerator HideRenderers() | |
{ | |
var visible = true; | |
while (visible) | |
{ | |
// ReSharper disable once LocalVariableHidesMember | |
foreach (var renderer in Renderers) | |
{ | |
var color = renderer.color; | |
color = new Color | |
{ | |
r = color.r, | |
g = color.g, | |
b = color.b, | |
a = color.a - Speed * Time.fixedDeltaTime | |
}; | |
renderer.color = color; | |
visible = visible && color.a != 0; | |
} | |
yield return false; | |
} | |
} | |
private void Exit() | |
{ | |
enabled = false; | |
Visible.Enter(); | |
} | |
private void Awake() | |
{ | |
Renderers = GetComponentsInChildren<SpriteRenderer>(); | |
Visible = GetComponent<Visible>(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using JetBrains.Annotations; | |
using SDK.Gameplay.States; | |
using SDK.Gameplay.Values; | |
using Sirenix.OdinInspector; | |
using UniRx; | |
using UnityEngine; | |
using UnityEngine.Rendering; | |
namespace SDK.Gameplay.Unit.States | |
{ | |
public sealed class Moving : AbstractState | |
{ | |
private static readonly int MoveAnimation = Animator.StringToHash("move"); | |
[ShowInInspector] public SortingGroup SortingGroup { get; private set; } | |
[ShowInInspector] private AudioSource AudioSource { get; set; } | |
[ShowInInspector] private HealthBar HealthBar { get; set; } | |
[ShowInInspector] private Animator Animator { get; set; } | |
[ShowInInspector] private Idle Idle { get; set; } | |
[ShowInInspector] private Entity Entity { get; set; } | |
[UsedImplicitly] | |
public void OnStep() | |
{ | |
} | |
[UsedImplicitly] | |
public void OnMoveStarted() | |
{ | |
} | |
[UsedImplicitly] | |
public void OnMoveFinished() | |
{ | |
Exit(); | |
Idle.Enter(); | |
} | |
public void Enter(Tile tile) | |
{ | |
enabled = true; | |
Animator.SetTrigger(MoveAnimation); | |
MainThreadDispatcher.StartUpdateMicroCoroutine(Move(tile)); | |
} | |
private void Exit() | |
{ | |
enabled = false; | |
Idle.Enter(); | |
} | |
private IEnumerator Move(Tile tile) | |
{ | |
var current = Entity.CurrentTile; | |
SortingGroup.sortingOrder = current.Row > tile.Row | |
? tile.SortingOrder | |
: current.SortingOrder; | |
// Entity.CurrentTile = tile; | |
var position = tile.transform.position; | |
TurnTowards(position); | |
var target = new Vector2 | |
{ | |
x = position.x, | |
y = position.y + 1 | |
}; | |
var time = Time.time; | |
var start = transform.position; | |
var distance = Vector3.Distance(start, target); | |
while (new Vector2(transform.position.x - target.x, transform.position.y - target.y) != Vector2.zero) | |
{ | |
var covered = (Time.time - time) * 65; | |
var fraction = covered / distance; | |
transform.position = Vector3.Lerp(start, target, fraction * Time.fixedDeltaTime); | |
yield return false; | |
} | |
SortingGroup.sortingOrder = tile.SortingOrder; | |
} | |
private void TurnTowards(Vector3 target) | |
{ | |
var position = transform.position; | |
// ReSharper disable once Unity.InefficientPropertyAccess | |
var isFacingLeft = (int) transform.rotation.y != 0; | |
// ReSharper disable once InvertIf | |
if (isFacingLeft && position.x < target.x || !isFacingLeft && position.x > target.x) | |
{ | |
transform.Rotate(0, isFacingLeft ? -180 : 180, 0, Space.Self); | |
HealthBar.transform.Rotate(0, isFacingLeft ? -180 : 180, 0, Space.Self); | |
} | |
} | |
private void Awake() | |
{ | |
Entity = GetComponent<Entity>(); | |
SortingGroup = GetComponent<SortingGroup>(); | |
AudioSource = GetComponent<AudioSource>(); | |
Animator = GetComponent<Animator>(); | |
Idle = GetComponent<Idle>(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using JetBrains.Annotations; | |
using SDK.Extensions; | |
using SDK.Gameplay.Events.Infrastructure; | |
using SDK.Gameplay.States; | |
using SDK.Gameplay.Values; | |
using SDK.Tools; | |
using Sirenix.OdinInspector; | |
using Sirenix.Serialization; | |
using UniRx; | |
using UnityEngine; | |
using Logger = SDK.Tools.Logger; | |
namespace SDK.Gameplay.Unit.States | |
{ | |
public sealed class TakingDamage : AbstractState | |
{ | |
private static readonly int[] TakeDamageAnimations = | |
{ | |
Animator.StringToHash("take-damage_1"), | |
Animator.StringToHash("take-damage_2") | |
}; | |
private static readonly IMessageBroker Broker = MessageBroker.Default; | |
[OdinSerialize] [Required] private Popup Popup { get; set; } | |
[OdinSerialize] [Required] private Vector3 PopupOffset { get; set; } | |
[ShowInInspector] private HealthBar HealthBar { get; set; } | |
[ShowInInspector] private Animator Animator { get; set; } | |
[ShowInInspector] private Idle Idle { get; set; } | |
[ShowInInspector] private Dead Dead { get; set; } | |
[ShowInInspector] private Entity Entity { get; set; } | |
private Logger _logger; | |
[UsedImplicitly] | |
public void TakeDamage() | |
{ | |
} | |
[UsedImplicitly] | |
public void OnTakeDamageFinished() | |
{ | |
Exit(); | |
if (Entity.CurrentHealth >= 0) | |
{ | |
Idle.Enter(); | |
return; | |
} | |
Dead.Enter(); | |
} | |
public void Enter(int damage) | |
{ | |
enabled = true; | |
Animator.SetTrigger(TakeDamageAnimations.Random()); | |
// some effects - like heal or stun - may deal no damage | |
if (damage == 0) return; | |
var current = Entity.CurrentHealth; | |
damage = Math.Min(current, Math.Abs(damage)); | |
Entity.CurrentHealth -= damage; | |
CreatePopup(damage); | |
} | |
private void CreatePopup(int damage) | |
{ | |
var popup = Instantiate(Popup); | |
popup.Value = damage; | |
popup.transform.position = transform.position + PopupOffset; | |
} | |
private void Exit() | |
{ | |
enabled = false; | |
Idle.Enter(); | |
} | |
private void Awake() | |
{ | |
HealthBar = GetComponentInChildren<HealthBar>(); | |
Animator = GetComponent<Animator>(); | |
Idle = GetComponent<Idle>(); | |
Dead = GetComponent<Dead>(); | |
_logger = LogManager.GetLogger(name, typeof(TakingDamage)); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using SDK.Gameplay.States; | |
using SDK.Gameplay.Values; | |
using Sirenix.OdinInspector; | |
using Sirenix.Serialization; | |
using UniRx; | |
using UnityEngine; | |
namespace SDK.Gameplay.Unit.States | |
{ | |
public class TakingHeal : AbstractState | |
{ | |
[OdinSerialize] [Required] private Popup Popup { get; set; } | |
[OdinSerialize] [Required] private Vector3 PopupOffset { get; set; } | |
[ShowInInspector] private ReactiveProperty<int> MaximumHealth { get; set; } | |
[ShowInInspector] private ReactiveProperty<int> CurrentHealth { get; set; } | |
[ShowInInspector] private Idle Idle { get; set; } | |
public void Enter(int heal) | |
{ | |
enabled = true; | |
CreatePopup(heal); | |
Exit(); | |
} | |
private void CreatePopup(int heal) | |
{ | |
var popup = Instantiate(Popup); | |
popup.Value = heal; | |
popup.transform.position = transform.position + PopupOffset; | |
} | |
private void Exit() | |
{ | |
enabled = false; | |
Idle.Enter(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using JetBrains.Annotations; | |
using SDK.Gameplay.States; | |
using SDK.Gameplay.Values; | |
using Sirenix.OdinInspector; | |
using Sirenix.Serialization; | |
using UniRx; | |
using UnityEngine; | |
namespace SDK.Gameplay.Unit.States | |
{ | |
public sealed class UsingSkill : AbstractState | |
{ | |
private static readonly IMessageBroker Broker = MessageBroker.Default; | |
[OdinSerialize] [Required] private IList<Skill> Skills { get; set; } | |
[ShowInInspector] private HealthBar HealthBar { get; set; } | |
[ShowInInspector] private AudioSource AudioSource { get; set; } | |
[ShowInInspector] private Animator Animator { get; set; } | |
[ShowInInspector] private Idle Idle { get; set; } | |
private Skill _skill; | |
private Entity _target; | |
[UsedImplicitly] | |
public void UseSkill() | |
{ | |
_skill.Activate(); | |
} | |
[UsedImplicitly] | |
public void OnAnimationFinished() | |
{ | |
Exit(); | |
Idle.Enter(); | |
} | |
public void Enter(Entity target, string skillId) | |
{ | |
var skill = Skills.FirstOrDefault(_ => _.Id == skillId) ?? | |
throw new ArgumentOutOfRangeException( | |
$"GAME OBJECT: {name}, METHOD: {nameof(Enter)}, PARAMETER: {nameof(skillId)}, VALUE: {skillId}"); | |
_skill = skill; | |
_target = target; | |
_skill.Target = _target; | |
enabled = true; | |
Animator.SetTrigger(skill.Id); | |
} | |
private void Exit() | |
{ | |
enabled = false; | |
Idle.Enter(); | |
} | |
private void Awake() | |
{ | |
HealthBar = GetComponentInChildren<HealthBar>(); | |
AudioSource = GetComponent<AudioSource>(); | |
Animator = GetComponent<Animator>(); | |
Idle = GetComponent<Idle>(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using SDK.Gameplay.Unit.States; | |
using Sirenix.OdinInspector; | |
using UniRx; | |
using UnityEngine; | |
namespace SDK.Gameplay.States | |
{ | |
public class Visible : AbstractState | |
{ | |
[ShowInInspector] private Invisible Invisible { get; set; } | |
[ShowInInspector] private SpriteRenderer[] Renderers { get; set; } | |
private const float Speed = 0.5f; | |
public void Enter() | |
{ | |
enabled = true; | |
MainThreadDispatcher.StartFixedUpdateMicroCoroutine(ShowRenderers()); | |
} | |
private IEnumerator ShowRenderers() | |
{ | |
var invisible = true; | |
while (invisible) | |
{ | |
// ReSharper disable once LocalVariableHidesMember | |
foreach (var renderer in Renderers) | |
{ | |
var color = renderer.color; | |
color = new Color | |
{ | |
r = color.r, | |
g = color.g, | |
b = color.b, | |
a = color.a + Speed * Time.fixedDeltaTime | |
}; | |
renderer.color = color; | |
invisible = invisible && Math.Abs(color.a - 255) > float.Epsilon; | |
} | |
yield return false; | |
} | |
} | |
private void Exit() | |
{ | |
enabled = false; | |
Invisible.Enter(); | |
} | |
private void Awake() | |
{ | |
Renderers = GetComponentsInChildren<SpriteRenderer>(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
In order to copy-paste this FSM you need UniRx and Odin plugins for Unity3d