Wednesday, September 18, 2013

Unity3D: How to Call Code from a Different GameObject

Something that gets asked all the time is how to call code in a script attached to a GameObject from a different GameObject in Unity3D. In Javascript or C#, the answer is pretty simple, but not necessarily intuitive at first glance. This post will provide a nice template that you can use to do exactly that.

First, you'll need at least two GameObjects in your scene, with a different script attached to each: one with some code you'll want to execute, and one that will execute the code in the other script.

So let's say I have a GameObject called "controllerObject" with a script called "controllerScript", which will do the calling, and a GameObject called "workerObject" that has a script called "workerScript", which has the code I want to execute. The hierarchy would look something like this:


In "workerScript", let's put some code in that just prints to the console.

C#

public void DoStuff ()
{
     print ("Remote method successfully called.");
}

Notice we've made this method public so that other code can see it. If you've got a private method, your controller can find the script, but it won't be able to call the method due to its protection level.

In "controllerScript", we're going to place the heart of this code. We're going to find the GameObject containing our worker script, then we're going to find the script and communicate with it.

C#

private void CallRemoteMethod ()
{
    private GameObject workerObject;
    private workerScript workerObjectScript;
   
    void Start ()
    {
        workerObject = GameObject.Find ("workerObject");
        workerObjectScript = (workerScript)workerObject.GetComponent (typeof (workerScript));
      
        CallRemoteMethod ();
    }
   
    private void CallRemoteMethod ()
    {
        workerObjectScript.DoStuff ();
    }    

}

This is a little more involved, so I'll break down what we're doing.

First, we're creating a couple of variables to contain the objects that we need to interact with: "workerObject" is the object that contains our worker script, and "workerObjectScript" is the worker script itself. In Start (), which will be executed one time when the scene starts, we first find the worker object by name, and then assign the script we're looking for to the "workerObjectScript" variable. Finally, we call "CallRemoteMethod ()", which executes the "DoStuff ()" method in the worker script.

Make sure that the scripts are attached to the appropriate GameObjects and press "Play". You'll see your console output, verifying that the method has been called.



You can use this template to call methods or check variables on any script on any object in the scene, provided that those methods and variables have the proper protection level. This technique can also be modified to work in many different ways. For instance, instead of finding the GameObject "workerObject" using the GameObject.Find () method, we could have created a public GameObject and simply dragged the worker object on to that field in the Inspector. However, the beauty in doing it entirely in code is that even if the calling is instantiated at run time, it can find the proper object and call code from it.

Unity 3D error: "Compute mesh inertia tensor failed"

This is error is almost always caused when you have a Mesh Collider on a plane. To get rid of it, remove the Mesh Collider and use a thin Box Collider instead.

Please note that in Unity 4.x, it is not sufficient to disable the Mesh Collider; you must remove it entirely.

Monday, August 12, 2013

Unity 3D: How to Create a Simple Button with NGUI

I use NGUI on an almost daily basis for the majority of my GUI needs. Just like most tools, regardless of their user-friendliness, there is something of a learning curve. This post covers one of the simplest and most-used features of NGUI: making a standard 2D button.

NOTE: This blog post was originally written for NGUI 2.x. It has been updated for NGUI 3.x. If you are still using 2.x for some reason, please either upgrade or contact me and I'll send you the old post.

If you haven't already, hop on over to the Asset Store and download NGUI (full or free). Import the package into your project and we'll get started!

In the toolbar, go to NGUI > Create > 2D UI. This is where we'll create our base NGUI object.


You will now see the "UI Root" object in your hierarchy. This will be the parent of all of the NGUI objects, including the camera used to render the UI, which they've already created for you.

The simplest way to add a button is to add one of the prefabs NGUI provides and customize it to your liking. The button we're going to add is called "Control - Simple Button". You can find it by either searching for "Control" in the Project pane, and selecting it from the items that come up, or by navigating in your Project pane to Assets > NGUI > Examples > Atlases > Wooden. Either way, drag the prefab into the Hierarchy pane. It should come in as a child of "UI Root".


If you hit "Play" now, you'll find you have a nice-looking button that reacts to being hovered over and clicked. Pretty spiffy, but it doesn't really do anything, because we haven't told it to. Let's fix that.

Create a new C# script by clicking "Create > C# script" in the Project pane. Name it "buttonClick". Double-click it to open it in Mono, delete all of the contents of the file, and paste in the following:

using UnityEngine;

public class buttonClick : MonoBehaviour
{
    private int counter = 0;
   
    void OnClick ()
    {
        counter++;
        print ("Clicked " + counter.ToString () + " times.");
    }
}


Drag and drop this script on to the "Control - Simple Button" object in your hierarchy. Whenever an NGUI button is clicked, it calls the "OnClick ()" method, and the code you've placed in that method will execute. Here, we are simply incrementing a counter and displaying the output in the console. If you don't already know, your console output will be displayed at the very bottom of the editor window. You can also view the console in a separate window by going to "Window > Console" or pressing "Ctrl + Shift + C".


A couple of other useful tidbits:

The text on the button is located in a Label under the "Control - Simple Button" object. Select the label and edit the text field in the Inspector to change the text:


If you want to resize the button, don't do so under the "Transform" component in the Inspector! Doing so will lead to ugly, stretched text. Instead, click the "Control - Simple Button" GameObject, and under the UISprite component, change the "Dimensions" values. Make sure that "Box Collider - auto-adjust to match" is checked. This way, whatever you change the image dimensions to, the collider that detects button presses will match.

So now you have a basic button, and you can modify the code to perform any tasks that you may want (exiting the game, saving settings, selecting a level, etc.). You can create several buttons to make a menu as simple or as complex as you need, and move them all around right in the Scene window to create your layout.

Monday, April 15, 2013

Windows Server 2003 - OWA is broken

After some clients upgraded to Internet Explorer 10, OWA would not display properly from our poor old Win2k3 box. There was a "Loading ..." message where the emails should display, and a bunch of raw HTML in the top pane.



The solution was simple: use Microsoft's built-in Compatibility View. Direct your client to click the link to the right of the address bar that looks like a sheet of paper torn in half. After this, one of two things will happen: either the page will fix itself and show the client their messages, or you will get a "web page not found" error.



If you get the 404, direct your user to click the Back button and sign back in. They should then be able to access OWA without any further problems. Conversely, you can have them click "Basic" as opposed to "Premium" under the "Client" option on the log-in page. This should let them sign in using Compatibility View without the "web page not found" error.