More elegant way to reuse code with slight changes?

Wasn’t really sure how to word the title for this.

I’m a bit of a newbie when it comes to Unity and C#. I’m currently working on a four player game that consists of multiple minigames. Every player has their own set of game objects and variables. Right now, I have this code for player 1 in one of my scripts:

if (Input.GetButtonDown ("P1") && p1Enabled) {
            p1Banana.SetBool ("GameStarted", false);
            p1Banana.SetFloat ("Speed", 0f);
            if (p1Target.onTarget) {
                p1ScoreToAdd += p1Target.score;
            }
            if (p1PerfectTarget.onTarget) {
                p1ScoreToAdd += p1PerfectTarget.score;
                Debug.Log ("Perfect!");
            }
            gameManager.SendMessage ("UpdateP1Score", p1ScoreToAdd);
            p1Enabled = false;
        }

It works perfectly in the context of the whole script. But I’ll need to rewrite the same code three more times, only switching out every “p1” for a “p2”, “p3”, or “p4” for the remaining players. I was just wondering if there was a more elegant way to do that, given that the code will only be changed so slightly. Is there a way to put the code in a function but dynamically change all the variable names when it’s called?

Any help you guys have would be much appreciated. Thanks!

(Here’s the whole script, if it helps. Obviously when adding the above code for the other players, I’d also give them all their own versions of the necessary variables and such):

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

public class LevelManager_MG00 : MonoBehaviour {

[Header ("Player01 Variables")]
    public Animator p1Banana;
    public bool p1Enabled;
    public TriggerChecker p1Target;
    public TriggerChecker p1PerfectTarget;
    public float p1ScoreToAdd;

private GameManager gameManager;

void Awake () {
        //Get reference to Game Manager
        gameManager = GameObject.Find ("GameManager").GetComponent<GameManager> ();

        //Enable player controls
        p1Enabled = true;
    }

void Start () {
        p1Banana.SetBool ("GameStarted", true);
    }

void Update () {
        if (Input.GetButtonDown ("P1") && p1Enabled) {
            p1Banana.SetBool ("GameStarted", false);
            p1Banana.SetFloat ("Speed", 0f);
            if (p1Target.onTarget) {
                p1ScoreToAdd += p1Target.score;
            }
            if (p1PerfectTarget.onTarget) {
                p1ScoreToAdd += p1PerfectTarget.score;
                Debug.Log ("Perfect!");
            }
            gameManager.SendMessage ("UpdateP1Score", p1ScoreToAdd);
            p1Enabled = false;
        }
    }
}

Programmers have been having that same problem for 70 years. Code for multiple players in Unity isn’t much different than code for bank deposits for different customers. Read about standard programming stuff - functions, parameters, and arrays, and the stuff in-between while you’re there. Any Intro to Programming book will cover it (I obviously like mine, at taxesorcatses.)

Don’t put all your player stuff in the LevelManager. Make a PlayerManager script, change stuff like p1Banana to just Banana and add a string to the Inspector for which button to check. Then make a player prefab and instantiate 4 of them, one for each player.

A simple solution building on what you already have is to create a Player Component (below), then simply add 4 of these (changing the PlayerButton and GameManagerMethod variables)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour {
[Header ("Player Variables")]
public Animator Banana;
public bool Enabled;
public TriggerChecker Target;
public TriggerChecker PerfectTarget;
public float ScoreToAdd;
public string PlayerButton = "PX";
public string GameManagerMethod = "UpdatePXScore";
private GameManager gameManager;

void Awake () {
        //Get reference to Game Manager
        gameManager = GameObject.Find ("GameManager").GetComponent<GameManager> ();
        //Enable player controls
        Enabled = true;
    }

void Start () {
        Banana.SetBool ("GameStarted", true);
    }

void Update () {
        if (Input.GetButtonDown (PlayerButton) && Enabled) {
            Banana.SetBool ("GameStarted", false);
            Banana.SetFloat ("Speed", 0f);
            if (Target.onTarget) {
                ScoreToAdd += Target.score;
            }
            if (PerfectTarget.onTarget) {
                ScoreToAdd += PerfectTarget.score;
                Debug.Log ("Perfect!");
            }
            gameManager.SendMessage (GameManagerMethod, ScoreToAdd);
            Enabled = false;
        }
    }
}

Maybe create an prefab for this that is an empty with this script on it, and then you can set the Banana property to what you want (guessing its the same for all players)