Implement enemy death animation

This commit is contained in:
Denis-Cosmin Nutiu 2019-08-21 19:23:28 +03:00
parent c972ce5514
commit 18e95b16b6
10 changed files with 152 additions and 130 deletions

View file

@ -29,7 +29,7 @@ AnimatorState:
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_Name: Dumber m_Name: Normal
m_Speed: 1 m_Speed: 1
m_CycleOffset: 0 m_CycleOffset: 0
m_Transitions: [] m_Transitions: []
@ -59,7 +59,7 @@ AnimatorStateMachine:
m_ChildStates: m_ChildStates:
- serializedVersion: 1 - serializedVersion: 1
m_State: {fileID: 1102746068587636566} m_State: {fileID: 1102746068587636566}
m_Position: {x: 200, y: 0, z: 0} m_Position: {x: 336, y: 24, z: 0}
m_ChildStateMachines: [] m_ChildStateMachines: []
m_AnyStateTransitions: [] m_AnyStateTransitions: []
m_EntryTransitions: [] m_EntryTransitions: []

View file

@ -56,7 +56,7 @@ namespace src.Ammo
{ {
Debug.Log("Hit something"); Debug.Log("Hit something");
var key = hit.collider.GetComponent<IExplosable>(); var key = hit.collider.GetComponent<IExplosable>();
key?.onExplosion(); key?.OnExplosion();
break; break;
} }
} }
@ -68,11 +68,11 @@ namespace src.Ammo
{ {
if (!_exploded && other.CompareTag("Explosion")) if (!_exploded && other.CompareTag("Explosion"))
{ {
onExplosion(); OnExplosion();
} }
} }
public void onExplosion() public void OnExplosion()
{ {
CancelInvoke(nameof(Explode)); CancelInvoke(nameof(Explode));
Explode(); Explode();

View file

@ -1,115 +1,136 @@
using src.Helpers; using System.Collections;
using src.Managers;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using src.Helpers;
using src.Managers;
using UnityEngine; using UnityEngine;
public abstract class EnemyBase : MonoBehaviour, IExplosable namespace src.Base
{ {
public abstract class EnemyBase : MonoBehaviour, IExplosable
protected Vector2[] _directions = { Vector3.up, Vector3.down, Vector3.left, Vector3.right };
protected readonly GameStateManager gameStateManager = GameStateManager.Instance;
protected Rigidbody2D Rigidbody2d { get; set; }
protected float Speed { get; set; }
protected Vector2 Direction { get; set; }
private List<Vector3> _allowedDirections = new List<Vector3>();
private bool _isStucked = false;
private System.Random _random = new System.Random();
// Start is called before the first frame update
protected void Start()
{ {
Direction = _directions.ChoseRandom(); private readonly Vector2[] _directions = {Vector3.up, Vector3.down, Vector3.left, Vector3.right};
Rigidbody2d = GetComponent<Rigidbody2D>(); private readonly GameStateManager _gameStateManager = GameStateManager.Instance;
}
// Update is called once per frame protected Rigidbody2D Rigidbody2d { get; set; }
protected void FixedUpdate() private Collider2D Collider2D { get; set; }
{ private Animator Animator { get; set; }
if (gameStateManager.IsGamePaused || gameStateManager.IsPlayerMovementForbidden) {return;} protected float Speed { get; set; }
if(_isStucked) protected Vector2 Direction { get; set; }
private readonly List<Vector3> _allowedDirections = new List<Vector3>();
private bool _isStuck;
private bool _isDead;
private static readonly int AnimExplode = Animator.StringToHash("animExplode");
// Start is called before the first frame update
protected void Start()
{ {
Direction = _directions.ChoseRandom();
Rigidbody2d = GetComponent<Rigidbody2D>();
Collider2D = GetComponent<Collider2D>();
Animator = GetComponentInChildren<Animator>();
}
// Update is called once per frame
protected void FixedUpdate()
{
if (_gameStateManager.IsGamePaused || _gameStateManager.IsPlayerMovementForbidden || _isDead)
{
return;
}
if (_isStuck)
{
Unstuck();
}
HandleMovement();
}
/// <summary>
/// This function is implemented by subclasses and should provided personalized movement logic.
/// </summary>
protected abstract void HandleMovement();
public void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Explosion"))
{
OnExplosion();
}
}
public void OnExplosion()
{
Collider2D.enabled = false;
_isDead = true;
Animator.SetTrigger(AnimExplode);
Destroy(gameObject, 1);
}
public void OnCollisionEnter2D(Collision2D col)
{
MoveToCenterOfTheCell();
Unstuck(); Unstuck();
} }
Rigidbody2d.MovePosition(Rigidbody2d.position + Speed * Time.deltaTime * Direction);
}
public void OnTriggerEnter2D(Collider2D other) public void OnCollisionStay2D(Collision2D col)
{
if (other.CompareTag("Explosion"))
{ {
onExplosion(); MoveToCenterOfTheCell();
Unstuck();
}
protected void MoveToCenterOfTheCell()
{
var position = transform.position;
var absX = Mathf.RoundToInt(position.x);
var absY = Mathf.RoundToInt(position.y);
var newPosition = new Vector2(absX, absY);
transform.SetPositionAndRotation(newPosition, Quaternion.identity);
}
protected Vector2 ChooseRandomDirection()
{
return _directions.ChoseRandom();
}
protected Vector2 ChooseRandomExceptCertainDirection(Vector2 direction)
{
return _directions.ChoseRandomExcept(direction);
}
private void Unstuck()
{
_allowedDirections.Clear();
StartCoroutine(CheckForObstacle(Vector3.down));
StartCoroutine(CheckForObstacle(Vector3.left));
StartCoroutine(CheckForObstacle(Vector3.up));
StartCoroutine(CheckForObstacle(Vector3.right));
if (_allowedDirections.Count == 0)
{
_isStuck = true;
}
else
{
Direction = _allowedDirections.PeekRandom();
_isStuck = false;
}
}
private IEnumerator CheckForObstacle(Vector3 direction)
{
const int layerMask = 1 << 8; // Block layer
var currentPosition = transform.position;
var hit = Physics2D.Raycast(new Vector2(currentPosition.x + 0.5f, currentPosition.y + 0.5f),
direction, 1, layerMask);
if (!hit.collider)
{
_allowedDirections.Add(direction);
}
yield return new WaitForSeconds(0.05f);
} }
} }
}
public void onExplosion()
{
Destroy(gameObject);
}
public void OnCollisionEnter2D(Collision2D col)
{
MoveToCenterOfTheCell();
Unstuck();
}
public void OnCollisionStay2D(Collision2D col)
{
MoveToCenterOfTheCell();
Unstuck();
}
protected void MoveToCenterOfTheCell()
{
var absX = Mathf.RoundToInt(transform.position.x);
var absY = Mathf.RoundToInt(transform.position.y);
Vector2 position = new Vector2(absX, absY);
transform.SetPositionAndRotation(position, Quaternion.identity);
}
protected Vector2 ChooseRandomDirection()
{
return _directions.ChoseRandom();
}
protected Vector2 ChooseRandomExceptCertainDirection(Vector2 direction)
{
return _directions.ChoseRandomExcept(direction);
}
private void Unstuck()
{
_allowedDirections.Clear();
StartCoroutine(CheckForObstacle(Vector3.down));
StartCoroutine(CheckForObstacle(Vector3.left));
StartCoroutine(CheckForObstacle(Vector3.up));
StartCoroutine(CheckForObstacle(Vector3.right));
if(_allowedDirections.Count == 0)
{
_isStucked = true;
}
else
{
var index = _random.Next(_allowedDirections.Count);
Direction = _allowedDirections[index];
_isStucked = false;
}
}
private IEnumerator CheckForObstacle(Vector3 direction)
{
var layerMask = (1 << 8) | (1 << 9);
var currentPosition = transform.position;
var hit = Physics2D.Raycast(new Vector2(currentPosition.x + 0.5f, currentPosition.y + 0.5f), direction, 1, layerMask);
if (!hit.collider)
{
_allowedDirections.Add(direction);
}
yield return new WaitForSeconds(0.05f);
}
}

View file

@ -20,7 +20,7 @@ namespace src.Base
{ {
if (other.CompareTag("Explosion")) if (other.CompareTag("Explosion"))
{ {
onExplosion(); OnExplosion();
} }
if (other.CompareTag("Enemy")) if (other.CompareTag("Enemy"))
{ {
@ -28,7 +28,7 @@ namespace src.Base
} }
} }
public void onExplosion() public void OnExplosion()
{ {
DebugHelper.LogInfo("Player hit by explosion"); DebugHelper.LogInfo("Player hit by explosion");
} }

View file

@ -1,4 +1,7 @@
namespace src.Enemy using src.Base;
using UnityEngine;
namespace src.Enemy
{ {
public class CollisionMovementEnemy : EnemyBase public class CollisionMovementEnemy : EnemyBase
/* Enemy that will change direction only on collision. */ /* Enemy that will change direction only on collision. */
@ -9,10 +12,9 @@
base.Start(); base.Start();
} }
protected new void FixedUpdate() protected override void HandleMovement()
{ {
base.FixedUpdate(); Rigidbody2d.MovePosition(Rigidbody2d.position + Speed * Time.deltaTime * Direction);
} }
} }
} }

View file

@ -1,27 +1,21 @@
using UnityEngine; using src.Base;
using UnityEngine;
namespace Assets.Scripts.src.Enemy.Dummy namespace src.Enemy.Dummy
{ {
//This kind of enemy is used just for testing purposes //This kind of enemy is used just for testing purposes
//This enemy will go just in one direction or stays in place //This enemy will go just in one direction or stays in place
//To make it stay in place, don't assign any direction in OneDirection slot or assign Vector2.zero //To make it stay in place, don't assign any direction in OneDirection slot or assign Vector2.zero
public class OneDirectionEnemy : EnemyBase public class OneDirectionEnemy : EnemyBase
{ {
public Vector2 OneDirection = Vector2.zero;
protected new void Start() protected new void Start()
{ {
Speed = 4.0f; Speed = 4.0f;
Rigidbody2d = GetComponent<Rigidbody2D>(); Rigidbody2d = GetComponent<Rigidbody2D>();
} }
protected new void FixedUpdate() protected override void HandleMovement()
{ {
if (OneDirection != Vector2.zero)
{
if (gameStateManager.IsGamePaused || gameStateManager.IsPlayerMovementForbidden) { return; }
Rigidbody2d.MovePosition(Rigidbody2d.position + OneDirection * Speed * Time.deltaTime);
}
} }
} }
} }

View file

@ -1,5 +1,5 @@
using System; using System;
using src.Helpers; using src.Base;
using UnityEngine; using UnityEngine;
namespace src.Enemy namespace src.Enemy
@ -13,12 +13,11 @@ namespace src.Enemy
base.Start(); base.Start();
} }
protected new void FixedUpdate() protected override void HandleMovement()
{ {
var pos = transform.position; var pos = transform.position;
var x = pos.x; var x = pos.x;
var y = pos.y; var y = pos.y;
if (gameStateManager.IsGamePaused || gameStateManager.IsPlayerMovementForbidden) { return; }
if (Math.Abs(x - Mathf.Floor(x)) < 0.1 && Math.Abs(y - Mathf.Floor(y)) < 0.1) if (Math.Abs(x - Mathf.Floor(x)) < 0.1 && Math.Abs(y - Mathf.Floor(y)) < 0.1)
{ {
if (RandomChange()) if (RandomChange())

View file

@ -12,7 +12,7 @@ namespace src.Helpers
var max = list.Count - 1; var max = list.Count - 1;
for (var i = min; i < max; i++) for (var i = min; i < max; i++)
{ {
var randomPos = Mathf.FloorToInt(Random.Range(min, max)); var randomPos = Random.Range(min, max);
/* Swap elements in list */ /* Swap elements in list */
var aux = list[randomPos]; var aux = list[randomPos];
@ -23,10 +23,16 @@ namespace src.Helpers
public static T PopRandom<T>(this IList<T> list) public static T PopRandom<T>(this IList<T> list)
{ {
var randomIndex = Mathf.FloorToInt(Random.Range(0, list.Count - 1)); var randomIndex = Random.Range(0, list.Count - 1);
var elem = list[randomIndex]; var elem = list[randomIndex];
list.RemoveAt(randomIndex); list.RemoveAt(randomIndex);
return elem; return elem;
} }
public static T PeekRandom<T>(this IList<T> list)
{
var randomIndex = Random.Range(0, list.Count - 1);
return list[randomIndex];
}
} }
} }

View file

@ -4,5 +4,5 @@ using UnityEngine;
public interface IExplosable public interface IExplosable
{ {
void onExplosion(); void OnExplosion();
} }

View file

@ -60,7 +60,7 @@ namespace src.Wall
// _animator.speed = 10; // _animator.speed = 10;
} }
public void onExplosion() public void OnExplosion()
{ {
DebugHelper.LogInfo($"Destructible wall hit by explosion {transform.position}"); DebugHelper.LogInfo($"Destructible wall hit by explosion {transform.position}");
PlayDestroyAnimation(); PlayDestroyAnimation();