- Home /
new input system 2020 - character still can be moved after death
Hi, I am creating a local multiplayer fight game with the new input system from 2020. Everything works fine, but when the character dies you can still move him and attack. Only the first player can't move but still can attack. I don't know why their still moving, the fact that the first player can' move anymore makes me think I am on the right direction, but can't figure out what is missing.
I saw a lot of methods how to fix this problem when i researched it, but honestly i really don't understand how to adapt them to my script/s, so that it functions as it should.
i have three scripts: MovementInputHandler, Movement and the Damage_Script.
Here you can see them:
First the MovementInputHandler Script: using System.Linq; using UnityEngine; using UnityEngine.InputSystem;
public class MovementInputHandler : MonoBehaviour
{
private PlayerInput playerInput;
private Movement movementScript;
void Awake()
{
playerInput = gameObject.GetComponent<PlayerInput>();
var movementScripts = FindObjectsOfType<Movement>();
var newIndex = playerInput.playerIndex;
movementScript = movementScripts.FirstOrDefault(move => move.playerIndex == newIndex);
}
public void OnMove(InputAction.CallbackContext ctx)
{
if (movementScript != null)
{
movementScript.move = ctx.ReadValue<Vector2>();
}
}
public void OnAttack(InputAction.CallbackContext ctx)
{
if (ctx.ReadValue<float>() != 0 && movementScript != null)
{
movementScript.Attack();
}
}
}
This is the Movement Script: using UnityEngine;
public class Movement : MonoBehaviour
{
public int playerIndex = 0;
[HideInInspector]public Vector2 move;
float moveSpeed = 25f;
private bool facingLeft = false;
private Animator anim;
private Rigidbody2D rb;
private BoxCollider2D boxCollider2d;
[SerializeField] private Transform attackPoint;
public LayerMask enemyLayers;
public float attackRange = 0.5f;
public int attackDamage = 10;
void Awake()
{
boxCollider2d = transform.GetComponent<BoxCollider2D>();
}
void Start()
{
anim = GetComponent<Animator>();
rb = GetComponent<Rigidbody2D>();
}
public void Attack()
{
anim.SetTrigger("Attack");
Collider2D[] hitEnemies = Physics2D.OverlapCircleAll(attackPoint.position, attackRange, enemyLayers);
foreach (Collider2D enemy in hitEnemies)
{
enemy.GetComponent<Damage_Script>().TakeDamage(attackDamage);
}
}
void OnDrawGizmosSelected()
{
if (attackPoint == null)
return;
Gizmos.DrawWireSphere(attackPoint.position, attackRange);
}
void FixedUpdate()
{
rb.velocity = new Vector2(move.x * moveSpeed, rb.velocity.y);
anim.SetFloat("speed", Mathf.Abs(rb.velocity.x));
if (move.x < 0 && !facingLeft)
reverseImage();
else if (move.x > 0 && facingLeft)
reverseImage();
}
void reverseImage()
{
facingLeft = !facingLeft;
Vector2 theScale = rb.transform.localScale;
theScale.x *= -1;
rb.transform.localScale = theScale;
}
}
And finally the Damage Script:
using UnityEngine;
public class Damage_Script : MonoBehaviour
{
public Animator anim;
private int currentHealth;
public HealthBar healthBar;
public int maxHealth = 100;
void Start()
{
currentHealth = maxHealth;
healthBar.SetMaxHealth(maxHealth);
}
public void TakeDamage(int damage)
{
currentHealth -= damage;
anim.SetTrigger("Hurt");
healthBar.SetHealth(currentHealth);
if (currentHealth <= 0)
{
Die();
}
}
void Die()
{
GameObject.FindObjectOfType<Movement>().enabled = false;
}
}
Hope you can help..
Answer by Mashimaro7 · Aug 10, 2020 at 11:28 AM
Why not have an isDead bool? Encapsulate the attack and OnMove in a if(!isDead), on the Die() method set it to true.
hi @$$anonymous$$ashimaro7 , that sounds like a good idea, but since I am using the new Input System from 2020 I am very confused where I have to inplement the IsDead bool in the Script.
Declare the damage script in the other two scripts like,
Damage_Script damage;
And put a public bool isDead on top of the damage script, then check for it like this
public void Attack()
{
if(!damage.isDead)
{
anim.SetTrigger("Attack");
Collider2D[] hitEnemies = Physics2D.OverlapCircleAll(attackPoint.position, attackRange, enemyLayers);
foreach (Collider2D enemy in hitEnemies)
{
enemy.GetComponent<Damage_Script>().TakeDamage(attackDamage);
}
}
public void On$$anonymous$$ove(InputAction.CallbackContext ctx)
{
if (movementScript != null && !damage.isDead)
{
movementScript.move = ctx.ReadValue<Vector2>();
}
}
Also, lastly,
void Die()
{
isDead = true;
GameObject.FindObjectOfType<$$anonymous$$ovement>().enabled = false;
}
Sorry it's sloppy, it wasn't letting me preview where the code was until I sent it haha
Hello @$$anonymous$$ashimaro7 , thank you for your help! Before you started helping me andrew-lukasik helped me and now it works fine! Later I will also test your version!
Answer by andrew-lukasik · Aug 10, 2020 at 10:13 AM
Don't use FindObjectsOfType
. It makes code like GameObject.FindObjectOfType<Movement>().enabled = false;
affect one of the players only.
Hi @andrew-lukasik , thanks for the answer. When I don't use "FindObjectOfType" the Script will not find my $$anonymous$$ovement Script anymore. I get the information " Cannot resolve symbol '$$anonymous$$ovement' ". Could you explain what I need to use instead?
Add [SerializeField] $$anonymous$$ovement _movement = null
field in Damage_Script
class, fill this field in inspector and then replace GameObject.FindObjectOfType<$$anonymous$$ovement>().enabled = false;
with _movement.enabled = false;
. This way FindObjectOfType
will not be needed at all and execute in correct context.
Thank you, they now stop moving if they die, that's great! But they still can attack after their death, do you have a solution for this? The attacking script is within the movement script, I don't get why it still works after disabling it.
Answer by andrew-lukasik · Aug 10, 2020 at 12:14 PM
Overall I think you should rethink your code architecture here. I say that because your code right now breaks **Single responsibility principle** and that makes it harder to reason about it even for you.
Here is an example:
///
/// RESPONSIBILITY: centralize information about given player instance
/// and provide references to other important components
///
public class PlayerInfoComponent : MonoBehaviour
{
public int playerIndex = 0;
public HealthComponent health;
public MovementComponent movement;
public LayerMask enemyLayers;
public float attackRange = 0.5f;
public int attackDamage = 10;
public Transform attackPoint;
public bool isAlive => health.isAlive;
public bool isDead => health.isDead;
#if UNITY_EDITOR
void OnDrawGizmosSelected ()
{
if( attackPoint!=null ) Gizmos.DrawWireSphere( attackPoint.position , attackRange );
}
#endif
}
///
/// RESPONSIBILITY: forwards human-player inputs to corresponding components for given player
///
public class PlayerInputHandler : MonoBehaviour
{
[SerializeField] PlayerInfoComponent _player;
[SerializeField] PlayerInput _input;
#if UNITY_EDITOR
void OnValidate ()
{
if( _player==null ) _player = GetComponent<PlayerInfoComponent>();
if( _input==null ) _input = GetComponent<PlayerInput>();
}
#endif
public void OnMove ( UnityEngine.InputSystem.InputAction.CallbackContext ctx )
{
if( _player.isDead ) return;
_player.movement.move = ctx.ReadValue<Vector2>();
}
public void OnAttack ( UnityEngine.InputSystem.InputAction.CallbackContext ctx )
{
if( _player.isDead ) return;
if( ctx.ReadValue<float>()!=0 )
{
Collider2D[] hitEnemies = Physics2D.OverlapCircleAll( _player.attackPoint.position , _player.attackRange , _player.enemyLayers );
foreach( Collider2D collider in hitEnemies )
{
var damagable = collider.GetComponent<IDamageable>();
if( damagable!=null && damagable.isAlive && damagable!=(IDamageable)_player.health )
{
damagable.TakeDamage( _player.attackDamage );
}
}
_player.movement.ActAttack();
}
}
}
///
/// RESPONSIBILITY: sole control over movement on screen and Animator
///
public class MovementComponent : MonoBehaviour
{
[HideInInspector] public Vector2 move;
float moveSpeed = 25f;
bool facingLeft = false;
[SerializeField] PlayerInfoComponent _player;
[SerializeField] Animator _animator;
[SerializeField] Rigidbody2D _rigidbody;
[SerializeField] Collider2D _collider;
#if UNITY_EDITOR
void OnValidate ()
{
if( _player==null ) _player = GetComponent<PlayerInfoComponent>();
if( _collider==null ) _collider = GetComponent<Collider2D>();
if( _animator==null ) _animator = GetComponent<Animator>();
if( _rigidbody==null ) _rigidbody = GetComponent<Rigidbody2D>();
}
#endif
void FixedUpdate ()
{
_rigidbody.velocity = new Vector2(move.x * moveSpeed, _rigidbody.velocity.y);
_animator.SetFloat("speed", Mathf.Abs(_rigidbody.velocity.x));
if (move.x < 0 && !facingLeft)
ReverseImage();
else if (move.x > 0 && facingLeft)
ReverseImage();
}
public void ActAttack ()
{
_animator.SetTrigger("Attack");
}
public void ActHurt ()
{
_animator.SetTrigger("Hurt");
}
public void ActKilled ()
{
enabled = false;
_animator.SetTrigger("Killed");
}
public void ActRevived ()
{
enabled = true;
_animator.SetTrigger("Revived");
}
void ReverseImage ()
{
facingLeft = !facingLeft;
Vector2 scale = transform.localScale;
scale.x *= -1;
transform.localScale = scale;
}
}
Damage_Script
///
/// RESPONSIBILITY: keep track of health, notify other components when it changes
///
public class HealthComponent : MonoBehaviour, IDamageable, IHealable
{
int _currentHealth = 0;
[SerializeField] int _maxHealth = 100;
[SerializeField] MovementComponent _movement;
[SerializeField] HealthBar _healthBar;
public bool isAlive => _currentHealth > 0;
public bool isDead => !isAlive;
void Start ()
{
_currentHealth = _maxHealth;
_healthBar.SetMaxHealth( _maxHealth );
}
public void TakeDamage ( int damage )
{
_currentHealth -= damage;
_healthBar.SetHealth( _currentHealth );
if( _currentHealth>0 )
{
_movement.ActHurt();
}
else
{
_movement.ActKilled();
}
}
public void Heal ( int healing )
{
_currentHealth += healing;
_healthBar.SetHealth( _currentHealth );
}
public void Heal ()
{
_currentHealth = _maxHealth;
_healthBar.SetHealth( _currentHealth );
}
}
public interface IHealth
{
bool isAlive { get; }
bool isDead { get; }
}
public interface IDamageable : IHealth
{
void TakeDamage ( int damage );
}
public interface IHealable : IHealth
{
void Heal ( int healing );
void Heal ();
}
Hello @andrew-lukasik , this looks very interesting! Thank you so much for your advice! :-)
Your answer

Follow this Question
Related Questions
How to consume input when automatically switching control schemes through a Player Input Component 0 Answers
How to mimic Unity's Components based System 1 Answer
Help In Making a SphereCast for 3D Tire! Working RayCast Script included! 0 Answers
New Input System 0 Answers
how do i do 3d jump w/ 2021.1.1f1 and newest input system. 0 Answers