1
\$\begingroup\$

I am trying to place a button onto a canvas background using C# script. I want the button specific to the canvas (i.e., if I move the camera to look at another canvas, I do not want the button visible).

My C# script is below. I have attached it to an empty game object. When I run the game, the Heirarchy panel of Unity shows that the canvas and button are created OK, and that
the button is a child of the canvas. The canvas appears in game view at the right size (200 x 200).

But in game view, there is no button!

The button is definitely present ; clicking on its name the Heirarchy panel shows me a location and size in the scene view that are exactly as specified in my C# script. But nothing happens when I click the region in game view where the button is supposedly present.

Unity's Inspector panel shows that a "Button (Script)" has been attached to my button object, with Rect Transform parameters as specified in my C# code. I tried messing with the colors, but still no button. The "On Click()" window contains nothing except the message "List is Empty".

How do I make the button appear in game view?

How do I make the button work (i.e., generate the Console message "button pressed")?

using UnityEngine;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class TestScript : MonoBehaviour {

private GameObject myGO;
private Vector2 buttonSize;
private Vector3 buttonPosition;

void Start () {
// setup a canvas
    myGO = new GameObject ();
    Canvas myCanvas = myGO.GetComponent<Canvas> ();
    myCanvas.renderMode = RenderMode.WorldSpace;
    RectTransform parentRectTransform = myGO.GetComponent<RectTransform> ();
    parentRectTransform.sizeDelta = new Vector2 (200, 200); // set size of parent rectangle

// create and place the button
    Vector2 buttonSize = new Vector2 (10, 10);
    Vector3 buttonPosition = new Vector3 (150, -70, 1);

    CreateButton (myGO.transform, buttonPosition, buttonSize);
}  // end Start()

public void CreateButton(Transform panel ,Vector3 position, Vector2 size)
{
    GameObject button = new GameObject();
    button.name = "Button";
    button.transform.parent = panel;
    button.AddComponent<RectTransform>();
    button.AddComponent<Button>().onClick.AddListener (handleButton);
    button.transform.position = position;
}

void handleButton() {
    Debug.Log("Button pressed!");
}


} //  end class TestScript
\$\endgroup\$
  • \$\begingroup\$ You should create a canvas inside the editor and start using the rect transform elements in the inspector. this way you might understand better how elements are positioned with its anchor points. \$\endgroup\$ – XandruCea Sep 4 '15 at 6:22
0
\$\begingroup\$

As you have already fixed the positioning problem, I'll only address the second question about the button, which appears to not function at all.

First of all, I really recommend to set this up via the inspector, it's a pain to set it up manually in a script, but here we go:

In CreateButton(...), you add another Canvas component to your game object. Delete the following line as you already have a canvas.

button.AddComponent<Canvas>();

Your script does not create an EventSystem and also no InputModule (such as the ones shipped with Unity, StandaloneInputModule and TouchInputModule. Adding a Behaviour that inherits from BaseInputModule will automatically add an EventSystem component, if it doesn't exist yet. Add the following, it's probably the best if you do so before you start to build up the canvas.

GameObject eventSystem = new GameObject("EventSystem");
eventSystem.AddComponent<StandaloneInputModule>();

Last but not least, you also need a GraphicRaycaster component. Add this line when you added your canvas component.

myGO.AddComponent<GraphicRaycaster>();

Now you're be ready to go - so far. But i still really, really recommend to set this up via the inspector.

A small but useful tip: AddComponent<...> also returns the component. Use the returned reference to avoid unnecessary GetComponent<...> calls. Instead of

myGO.AddComponent<Canvas>();
Canvas myCanvas = myGO.GetComponent<Canvas>();

you can simply write

Canvas myCanvas = myGO.AddComponent<Canvas>();

You avoid searching for the component then as the method does not need to look it up.

\$\endgroup\$
  • \$\begingroup\$ Suddoha thank you so much. It works perfectly now. I am doing it with script because of future plans I have for the project. But you know, in a wierd way, scripting also helps me to understand what the Inspector does. \$\endgroup\$ – Pat Ward Sep 4 '15 at 11:34
  • \$\begingroup\$ @Pat Ward Why accepted and then unaccepted? I thought it helped. \$\endgroup\$ – Suddoha Sep 7 '15 at 16:52
  • \$\begingroup\$ Sorry ; I accepted it, and then it unaccepted itself, so I re-accepted it back again! It did help enormously ; thanks again. \$\endgroup\$ – Pat Ward Sep 16 '15 at 6:21
1
\$\begingroup\$

The Canvas co-ordinate system is a bit different. The origin is at the centre of the canvas. And the size of the canvas gets divided evenly with respect to the origin.

So in your case the canvas width is 200 , so the left extreme co-ordinate becomes 100. Your button position is 150 which exceeds 100 hence it doesn't lie inside the canvas.

enter image description here

\$\endgroup\$
  • \$\begingroup\$ Thanks for replying. I changed the button location to "Vector3 buttonPosition = new Vector3 (0, 0, 0);" That positioned the button in the centre of the canvas but it still does not function. I have since updated the CreateButton method to add Canvas and Image components to the button. This solved the problem of making the button visible in game view. But it still does not function ; it does not respond at all to the mouse click. \$\endgroup\$ – Pat Ward Sep 4 '15 at 7:12
  • \$\begingroup\$ Are you using the exact code which you shared?? Because that gave me null reference error for canvas component , I had to write extra line to attach the canvas. Please share the updated code which you are currently using. \$\endgroup\$ – Hash Buoy Sep 4 '15 at 7:19
0
\$\begingroup\$

OK, here is the exact code I am using, including stuff that might not be relevant to the problem. I tested it first and then just pasted it all straight in. For me, it creates a canvas with text, and a button right in the middle. But the button does not function.

using UnityEngine;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class TestScript : MonoBehaviour {

private GameObject myGO, childGO;
private Vector2 buttonSize;
private Vector3 buttonPosition;

void Start () {
    // set up the camera
    Camera.main.orthographicSize = 200f;
    Camera.main.transform.position = new  Vector3 (100f, 0f, -10f);

    // create game object and name it child object
    myGO = new GameObject ("Page 1"); // create game object and name it 
    myGO.AddComponent<Canvas> (); // add a canvas to the parent
    RectTransform parentRectTransform = myGO.GetComponent<RectTransform> ();
    parentRectTransform.sizeDelta = new Vector2 (200, 200); // set size of parent rectangle

    // set up a parent canvas 
    Canvas myCanvas = myGO.GetComponent<Canvas> ();
    myCanvas.renderMode = RenderMode.WorldSpace;
    Sprite mySprite = Resources.Load<Sprite> ("images/parchment 2"); //Get a sprite
    myGO.AddComponent<Image> ().sprite = mySprite; //Assign The Sprite

    // set up child object
    // set child anchors for resizing behaviour
    // make a reference to the child rect transform and set its values
    childGO = new GameObject ("Text"); // create child object and name it 
    childGO.transform.parent = myGO.transform; // set the child object as a child of the parent
    childGO.AddComponent<RectTransform> (); // add a recttransform to the child
    RectTransform childRectTransform = childGO.GetComponent<RectTransform> ();
    childRectTransform.anchoredPosition3D = new Vector3 (0f, 0f, 0f);
    childRectTransform.sizeDelta = new Vector2 (0f, 0f);
    childRectTransform.anchorMin = new Vector2 (0f, 0f);
    childRectTransform.anchorMax = new Vector2 (1f, 1f);

    // set text font type and material at runtime from font stored in Resources folder
    childGO.AddComponent<Text> ();
    Text textComponent = childGO.GetComponent<Text> ();
    textComponent.text = "Hello \n World"; // set the font text
    Font myFont = Resources.Load<Font> ("fonts/Open_Sans/OpenSans-Bold");
    textComponent.font = myFont;
    textComponent.fontSize = 50;

    // Add button
    Vector2 buttonSize = new Vector2 (50, 50);
    Vector3 buttonPosition = new Vector3 (0, 0, 0);
    CreateButton (myCanvas.transform, buttonPosition, buttonSize);

}  // end Start()

public  void  CreateButton(Transform panel ,Vector3 position, Vector2 size)
{
    GameObject button = new GameObject("Button");
    button.transform.SetParent(panel, false);
    button.transform.position = position;
    button.AddComponent<Canvas> ();
    button.AddComponent<Image> ();
    button.AddComponent<Button>();
    button.GetComponent<Button>().onClick.RemoveAllListeners();
    button.GetComponent<Button>().onClick.AddListener (handleButton);

}
void handleButton() {
    Debug.Log("Button pressed!");
}

} //  end class TestScript

The "images/parchment 2" is a jpeg image in a "images" subfolder of the "Resources" folder.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.