Question on Singleton usage and couch coop games

Hi! I hope you can help me!

I followed an instruction video on how to make a 2d platformer. In the code of the instructional video is a singleton. Unlike the video tutorial, I would like to my game multiplayer (3 people share 1 keyboard) and unfortunately, this singleton causes the jump, and crouch controls for player 2 and 3 to be applied to player 3 (named Kayla).The crouchbehavior and jumpbehavior are in other classes (also shown below. How can I replace this singleton with something that allows for multiple instances and not just for “Kayla”? Thank you very much! I am very new to coding hehe. Have a nice day!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public delegate void DeadEventHandler();
public class Control : Character1
{
    

    

    public event DeadEventHandler Dead;

    ***private static Control instance;

    public static Control Instance
    {
        get
        {
            if (instance == null)
            {
                instance = GameObject.FindObjectOfType<Kayla>();
            }
        return instance;
        }
    }***

   
   
    

    public Transform[] groundPoints; //points on the characters shoes for him to know if he is standing on solid ground
    public float groundRadius;
  
    public LayerMask whatIsGround;

    
    public bool airControl;
   
    public float jumpForce;

    private bool immortal = false;

    private SpriteRenderer spriteRenderer;


    [SerializeField]
    private float immortalTime;

    public Rigidbody2D MyRigidbody { get; set; }
    
    public bool Slide { get; set; }
    public bool Jump { get; set; }
    public bool OnGround { get; set; }
    public bool Crouch { get; set; }

    public override bool IsDead
    {
        get
        {
            if (healthStat.CurrentValue<= 0)
            {
                OnDead();

            }
            return healthStat.CurrentValue <= 0;
        }
    }

    private Vector2 startPos;


    // Use this for initialization
    public override void Start()
    {
        base.Start();   
        startPos = transform.position;
        spriteRenderer = GetComponent<SpriteRenderer>();
        MyRigidbody = GetComponent<Rigidbody2D>();
        
        
    }
    private void Update()
    {
        if (!TakingDamage && !IsDead)
        {

            if (transform.position.y <= -14f)
            {
                Death();
            }
        }
        HandleInput();
    }
    // Update is called once per frame
    public virtual void FixedUpdate()
    {
        if (!TakingDamage&&!IsDead)
        {
            float horizontal = Input.GetAxis("Horizontal_P1"); // "HORIZONTAL" is the name of a unity feature for movement control. You can see it in Edit>Project Settings>Input.
            OnGround = IsGrounded();
            HandleMovement(horizontal);
            Flip(horizontal);
        }
    }

    public void OnDead()
    {
        if(Dead!= null)
        {
            
            Dead();
        }
    }
    //METHODS:

    public void HandleMovement(float horizontal) // The horizontal in the parenthesis gets its value from the float Horizontal = blah blah in the fixed update
    {
       
        if(!Attack && (OnGround||airControl))
        {
            MyRigidbody.velocity = new Vector2(horizontal * movementSpeed, MyRigidbody.velocity.y);
        }

        if (Jump && MyRigidbody.velocity.y==0)
        {
            MyRigidbody.AddForce(new Vector2(horizontal * movementSpeed, jumpForce));
        }
        MyAnimator.SetFloat("Speed", Mathf.Abs(horizontal));

        if (Crouch)
        {
            MyRigidbody.velocity = new Vector2(0, MyRigidbody.velocity.y);
        }

    }

    
    public virtual void HandleInput() // where we put in controls (we can use this to make 2-3 player games
    {
        if (Input.GetKeyDown(KeyCode.W))
        {
            MyAnimator.SetTrigger("jump");
        }

        if (Input.GetKeyDown(KeyCode.Z))
        {
            MyAnimator.SetTrigger("attack");
        }

        if (Input.GetKeyDown(KeyCode.C))
        {
            MyAnimator.SetTrigger("slide");
        }
        if (Input.GetKey(KeyCode.S))
        {
            MyAnimator.SetBool("crouch", true);
        }
        if (Input.GetKeyDown(KeyCode.X))
        {
            MyAnimator.SetTrigger("throw");
        }

    }
    public void Flip(float horizontal)
    {
        if (horizontal > 0 && !facingRight || horizontal < 0 && facingRight)
        {
            ChangeDirection();
        }
    }
    
    public bool IsGrounded()
    {
        if (MyRigidbody.velocity.y <= 0)
        {
            foreach (Transform point in groundPoints)
            {
                Collider2D[] colliders = Physics2D.OverlapCircleAll(point.position, groundRadius, whatIsGround);
                
                for (int i=0;i<colliders.Length;i++)
                {
                    if (colliders*.gameObject !=gameObject)*

{
return true;
}

}
}
}
return false;
}
public override void ThrowKnife (int value)
{
base.ThrowKnife(value);
}

private IEnumerator IndicateImmortal()
{
while (immortal)
{
foreach (Renderer r in GetComponentsInChildren())
r.enabled = false;
yield return new WaitForSeconds(.1f);

foreach (Renderer r in GetComponentsInChildren())
r.enabled = true;
yield return new WaitForSeconds(.1f);

}
}

public override IEnumerator TakeDamage()
{
if (!immortal)
{
healthStat.CurrentValue -= 10;
if (!IsDead)
{
MyAnimator.SetTrigger(“damage”);
immortal = true;
StartCoroutine(IndicateImmortal());
yield return new WaitForSeconds(immortalTime);
immortal = false;

}

else
{
MyAnimator.SetLayerWeight(1, 0);
MyAnimator.SetTrigger(“die”);

}
}
}

public override void Death()
{
MyRigidbody.velocity = Vector2.zero;
MyAnimator.SetTrigger(“idle”);
healthStat.CurrentValue = healthStat.MaxVal;
transform.position = startPos;
}
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CrouchBehavior : StateMachineBehaviour {
// OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
Control.Instance.Crouch = true;

}
// OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{

animator.ResetTrigger(“crouch”);
}

// OnStateExit is called when a transition ends and the state machine finishes evaluating this state
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
Control.Instance.Crouch = false;
}

// OnStateMove is called right after Animator.OnAnimatorMove(). Code that processes and affects root motion should be implemented here
//override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
//
//}

// OnStateIK is called right after Animator.OnAnimatorIK(). Code that sets up animation IK (inverse kinematics) should be implemented here.
//override public void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
//
//}
}

None of the functionality of the character controller is static, so just remove the whole Instance property and then reference the object directly, like any other component.

Keep in mind that StateMachineBehaviours are a part of an animator instance, and animators are normal components attached to GameObjects in the scene. You can access the current GameObject inside of the StateMachineBehaviour by using animator.gameObject, so you can access other components too. Maybe one of those components is the controller, so you can set “crouched”, or maybe one of the components has a reference to the controller- either way, it’s accessible that way pretty easily.