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…

Why not have an isDead bool? Encapsulate the attack and OnMove in a if(!isDead), on the Die() method set it to true.

Don’t use FindObjectsOfType. It makes code like GameObject.FindObjectOfType<Movement>().enabled = false; affect one of the players only.

Overall I think you should rethink your code architecture here. I say that because your code right now breaks [Single responsibility principle][1] 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 ();
    }
    [1]: Single-responsibility principle - Wikipedia