0
\$\begingroup\$

I have a game that has many UI buttons. How do I detect which UI button is pressed? I am using Unity5 so there are no GUI elements. I am not able to use the onClick standard functions because all of my game objects are spawned.
My player has to shoot, jump and reload their weapons. I am able to move the spawned player with a joystick. But for the shoot and reload I get a null reference if I use the onClick functions (but they work fine with get axis implementation for shoot).

using UnityEngine;
using System.Collections;
using UnityStandardAssets;
using UnityEngine.UI;
using UnityStandardAssets.CrossPlatformInput;
public class wepScript : MonoBehaviour {

public Camera fpsCam;
public GameObject hitPar;
public int damage = 30;
public int maxDamage = 60;
public int range = 10000;
public int ammo = 10;
public int clipSize = 10;
public int clipCount = 5;
public float recoilPower = 30;
public Animation am;
public AnimationClip shoot;
public AnimationClip reloadA;

public Texture hitMarker;
public int hitCD = 0;

public AudioClip shootSound;
public AudioClip reloadSound;

public animManager amM;

public string  weaponName = "";
public bool done = false;
public GameObject[] objectsToDisable;
public bool canAim = false;
public float aimFOV = 20;
public float regFOV = 60;
public float regOffset = 0;
public float aimOffset = -75;
public PhotonView pv;

public Texture scope;
public bool isAimed = false;

void Awake(){

}


void Update(){

    //Vector3 targetVelocity = new Vector3(CrossPlatformInputManager.GetAxis("Horizontal2"), 0, CrossPlatformInputManager.GetAxis("Vertical"));
    //Debug.Log (targetVelocity.x);
    //if (targetVelocity.x > 0 ) {
    //  fireShot ();
    //
//  }
    if () // 
    {
        fireShot();//UI BUTTON PRESS
    }

    if (Input.GetMouseButtonDown (1)) {
        aim (true);
    }

    if (Input.GetMouseButtonUp (1)) {
        aim (false);
    }
    targetVelocity = new Vector3(CrossPlatformInputManager.GetAxis("Horizontal3"), CrossPlatformInputManager.GetAxis("Vertical3"));
    if (targetVelocity.x > 0) {
        reload();
    }

    hitCD += -1;
}

public void fireShot(){
    if (!am.IsPlaying (reloadA.name) && ammo >= 1) {
        if(!am.IsPlaying (shoot.name)){
            am.CrossFade (shoot.name);

            ammo = ammo - 1;

            pv.transform.GetComponent<RigidbodyFPSWalker>().getClip(shootSound);
            Debug.Log ("playing Sound!");
            pv.RPC ("playSound", PhotonTargets.AllBuffered, null);

            fpsCam.transform.Rotate (Vector3.right, -recoilPower * Time.deltaTime);

            RaycastHit hit;
            Ray ray = fpsCam.ScreenPointToRay (new Vector3 (Screen.width / 2, Screen.height / 2 + regOffset, 0));

            if (Physics.Raycast (ray, out hit, range)) {
                if (hit.transform.tag == "Player") {
                    hit.transform.GetComponent<PhotonView> ().RPC ("applyDamage", PhotonTargets.AllBuffered, Random.Range (damage, maxDamage), PhotonNetwork.playerName, weaponName);
                    PhotonNetwork.player.AddScore(1);
                    Debug.Log (PhotonNetwork.player.GetScore());
                    hitCD = 20;
                }

                if (hit.transform.tag == "Ai") {
                    hit.transform.GetComponent<PhotonView> ().RPC ("AiDamage", PhotonTargets.AllBuffered, Random.Range (damage, maxDamage), PhotonNetwork.playerName, weaponName);
                    PhotonNetwork.player.AddScore(1);
                    Debug.Log (PhotonNetwork.player.GetScore());
                    hitCD = 20;
                }


                GameObject particleClone;
                particleClone = PhotonNetwork.Instantiate (hitPar.name, hit.point, Quaternion.LookRotation (hit.normal), 0) as GameObject;
                Destroy (particleClone, 2);
                Debug.Log (hit.transform.name);

            }
        }

    }
}

public void reload(){
    if (clipCount >= 1) {
        am.CrossFade (reloadA.name);
        GetComponent<AudioSource>().PlayOneShot(reloadSound);
        ammo = clipSize;
        clipCount = clipCount - 1;
        //amM.reload ();
    }

}

public void aim(bool isIn){
    if (canAim) {
        if (isIn) {
            fpsCam.fieldOfView = aimFOV;
            disable ();
            regOffset = aimOffset;
            isAimed = true;
        } else {
            fpsCam.fieldOfView = regFOV;
            enable ();
            regOffset = 0;
            isAimed = false;
        }
    }
}

public void disable(){
    foreach (GameObject part in objectsToDisable) {
        part.SetActive (false);
    }
}
public void enable(){
    foreach (GameObject part in objectsToDisable) {
        part.SetActive (true);
    }
}


void OnGUI(){
    GUI.Box (new Rect(110,10,150,30), "Ammo: " + ammo + "/" + clipSize + "/" + clipCount);
    GUI.Box (new Rect (10, 45, 100, 30), "Score: " + PhotonNetwork.player.GetScore());

    if (hitCD >= 0) {
        GUI.DrawTexture (new Rect(Screen.width/2 - 25, Screen.height / 2 -25, 50,50), hitMarker, ScaleMode.StretchToFill);
    }


    if (isAimed) {
        GUI.DrawTexture (new Rect(0,0,Screen.width, Screen.height), scope,      ScaleMode.StretchToFill);
    }
}
}

Thanks

\$\endgroup\$
2
  • \$\begingroup\$ Its not clear what exactly you are trying to do. Are you trying to add specific method calls to the buttons that are instantiated at runtime or are you trying to create a generic listener for all the buttons that will handle the logic? Please explain what do you expect the buttons to do when they are clicked. \$\endgroup\$
    – Uri Popov
    Aug 3, 2016 at 11:05
  • \$\begingroup\$ Yes, im trying to add specific methods to buttons. The functions enable only during run time \$\endgroup\$ Aug 3, 2016 at 12:13

2 Answers 2

1
\$\begingroup\$

Besides the fact, that this screams for another way of separating your UI and logic code (the fact that your game objects are spawned at runtime does not mean, that you cannot have your UI listener functions in a script on a invisible dummy game object that always exists, right? Or are you spawning your buttons at runtime? Then see the last section of this answer), you can do the following:

You can add button listeners programmatically with Button.onClick.AddListener() where AddListener takes an Action (parameterless void function).

An example given a transform that has your button as a component using Linq would be:

transform.GetComponent<Button>().onClick.AddListener(() =>
{
    // put your action code here
});

I haven't tried that, but you should also be able to assign any void function without parameters as delegate to be listener.

If I got you wrong and you are spawning your UI buttons at runtime and these should have different but repetitive behavior, then just create a bunch of prefabs with listeners defined beforehand.

Hope that helps.

\$\endgroup\$
1
  • \$\begingroup\$ If i use the on click functions for the spawned player, i get a null reference exception.Even after adding the listner i get a null reference exception.What i did was to attach the "axis touch button" script.But then the behaviour is repeated.I want it to fire once when i press fire.Any suggestions ? \$\endgroup\$ Aug 3, 2016 at 9:27
0
\$\begingroup\$

Make a static GameManager class and attach it to the camera or an empty GameObject. Give it a variable

public GameObject player;

On the Player object, have a script saying:

void Start()
{
    GameManager.player = gameObject;
}

Then on your buttons, you can use a function:

void Click()
{
    if(GameManagaer.player != null)
    {
        // Do the thing
    }
}

And use that as the OnClick.

If you don't want to use a static GameManager class (though I recommend it, because they're awesome), you can do a find, so your click function would be:

void Click()
{
    GameObject player = GameObject.Find("Player");

    if(player != null)
    {
        // Do the thing
    }
}

Either way you're performing a null check so that a null reference doesn't break everything. With the two methods I've given, what will happen from a gameplay perspective is that nothing will happen if you click the button before the player has spawned. After the player has spawned, clicking the button will run the code.

\$\endgroup\$
1
  • \$\begingroup\$ hi thanks :).the set up i have right now works perfectly if the input is from a joystick.But shows a null reference only if the input is from a button.Any idea why that is? \$\endgroup\$ Aug 4, 2016 at 3:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .