SendMessage: trying (again) to figure out what's the problem

bad engrish incoming

Hi everyone. A few days ago i posted a question about a weird error that i encountered while experimenting new things. A kind user helped me for a point but his solution for the 2nd problem didn’t worked (as the other solutions expressed by the other users)
Basically my target is to renderize 2 or more letters at random. One of them have to be touched to continue. My approach is that: create a script to attach to the camera: it must renderize the shapes, wait for stuff (touch events) to happen and then destroy 'em and renderize other letters. The letters are just rotated plane prefabs with a texture.
Every prefab letter got an helper script that basically is just useful for the principal script to say what letter must be touched.
So: those are the 2 script:
The one to attach to the camera

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

public class StuffRenderer : MonoBehaviour {
    //a complete list of the figures that can be shown during the game.
    public List<Transform> objectList = new List<Transform>();
    //a list of the figures actually shown in the game
    public List<GameObject> inGame = new List<GameObject>();
    //the letter a
    public Transform a;
    //the letter b
    public Transform b;

    //i use this gameobject to renderize prefabs as gameobject
    public GameObject toRenderize;

    //difficulty. i'm not going to explain you why i need it but basically don't think to it as "difficulty". just a variable.
    int difficulty;

    //the first spawn is controlled. not the other ones.
    bool firstLoop;

    //max number of shapes that can be shown
    const int MAX_TO_RENDER = 10;

    //if spawning or waiting for other
    bool inSpawn;


	// Use this for initialization
	void Start () {
        firstLoop = true;
        difficulty = 2;
        objectList.Add(a);
        objectList.Add(b);
        inSpawn = true;
	}
	
	// Update is called once per frame
	void Update () {
        int toTouch = Random.Range(0, 1);
        if (inSpawn)
        {
            int xPos;
            int yPos;
            Vector3 position;

            if (firstLoop)
            {
                for (int i = 0; i < 2; i++)
                {
                    xPos = Random.Range(-55, 55);
                    yPos = Random.Range(-75, 60);
                    position = new Vector3(xPos, yPos, 5);
                    toRenderize = Instantiate(objectList[i], position, Quaternion.identity) as GameObject;
                    inGame.Add(toRenderize);
                    //NOW: look at here:
                    if (i == toTouch)
                    {
                        toRenderize.SendMessage("setTarget");
                    }
                }
                firstLoop = false;
            }
            else
            {
                xPos = Random.Range(-55, 55);
                yPos = Random.Range(-75, 60);
                position = new Vector3(xPos, yPos, 5);
                spawna(position);
            }

            inSpawn = false;
        }
        else
        {
            for (int i = 0; i < inGame.Count; i++)
            {
                if (i == toTouch)
                {
                    //other stuff here to do in order to return at the inSpawn state.
                }
            }
        }
	}

    void spawna(Vector3 position) //work in progress at that point
    {
        for (int i = 0; i < difficulty  i < MAX_TO_RENDER; i++)
        {
            toRenderize = Instantiate(objectList[i], position, Quaternion.identity) as GameObject;
            inGame.Add(toRenderize);
        }
    }
}

the one to attach to all of the prefabs:

using UnityEngine;
using System.Collections;

public class Letter : MonoBehaviour {

    bool isTarget;

    void Awake()
    {
        isTarget = false;
    }

    // Use this for initialization
    void Start()
    {
        transform.Rotate(new Vector3(90, 180, 0));
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.tag == "Letter")
        {
            transform.position = new Vector3(Random.Range(-55, 55), Random.Range(-75, 60), 5);
        }
    }

    void OnMouseDown()
    {
        if (isTarget)
        {
            print("ok");
        }
        else
        {
            print("no");
        }
    }

    void setTarget()
    {
        this.isTarget = true;
    }
}

I drag two prefabs (until now i got only 2 but of course at the end there will be more) and a game object “renderizzabile” to the inspector’s script session. i attach both where they have to be attached. I run the game and that’s the result.
1292530--59357--$CatturaBug.PNG

very weird. Endless list of A letters (but no Bs). Also that’s the inspector:

Very weird too. Since i say in the code to add to inGame the newly created toRenderize prefab, i can’t see where is the error.

Also, for every letter shown the console shows me this error:

NullReferenceException: Object reference not set to an instance of an object
StuffRenderer.Update () (at Assets/script/ingame/StuffRenderer.cs:61)
.

So i look at line61 of stuffrenderer and the incriminated line is that:

toRenderize.SendMessage("setTarget");

the strange thing is that if i delete the line (and the if statement of course) that’s the result:

1292530--59359--$Cattura.PNG

Just what i wanted. But since i need to set one of the 2 letters as the one to touch, i need that sendmessage function.

So i ended up with 3 options:

  • I’m a complete noob
  • I’m not a noob because the error is hard to encounter and not a common thing
  • i found a bug. YEEEEE bad unity3d

So can anyone help me? I really need a soultion. Many thanks in advance;

Regards, asduffo.

not sure about your scripts but

        int toTouch = Random.Range(0, 1);

will always be 0 (zero) as the second parameter is exclusive. when you want a 0 or 1 use Random.Range(0,2). see the documentation for this issue.

This worked. That changed a little the scene and now i have an endless list of As and Bs.
BUT NOW: funny (or maybe pathetic) update: until yesterday me and 2 friends of mine were planning to go today to the swimming pool; but this morning, AT 00:50 (just while i was about to go to the programmer’s dream world), one of the 2 friends called me (also i forgot to turn off the phone’s volume before to go to bed, and also to do a joke to a friend of us i had the internationale conducted by toscanini as ringtone; so i wake up everyone at house (true story, trust me)) to say that the other stood us up, AT 00:50.
So i spent something like an hour inside my mind trying to figure out what could be the problem in my script and i realized that effectively i didn’t completely initialize the gameobject; so i modified a little the core loop and now is like that:

for (int i = 0; i < 2; i++)
                {
                    xPos = Random.Range(-55, 55);
                    yPos = Random.Range(-75, 60);
                    position = new Vector3(xPos, yPos, 5);
                    toRenderize = Instantiate(objectList[i], position, Quaternion.identity) as GameObject;
                    //NOW:
                    toRenderize = new GameObject();
                    inGame.Add(toRenderize);
                    if (i == toTouch)
                    {
                        toRenderize.SendMessage("setTarget");
                    }
                }
                firstLoop = false;

this (finally) renderize just 2 figures as expected; but now the console gives me this error (just one time):
“SendMessage setTarget has no receiver!
UnityEngine.GameObject:SendMessage(String)
StuffRenderer:Update() (at Assets/script/ingame/StuffRenderer.cs:62)”

the incriminated line is still:

toRenderize.SendMessage("setTarget");

PS: also the list in the inspector is now like that:
1293267--59461--$Cattura2.PNG

And the hierarchy tells me that i created 2 empty gameobject (i expected that but since they’re pointless i have to find a way to delete 'em immediately).

So now where is the problem?

i don’t really know what you want to achieve so i cannot really tell you where your problem is. however, the error you get is from sending a message (ie calling a function) on an empty gameobject which has no script with this function attached.

toRenderize = Instantiate(objectList[i], position, Quaternion.identity) as GameObject;
//NOW:
toRenderize = new GameObject();
inGame.Add(toRenderize);
if (i == toTouch)
{
	toRenderize.SendMessage("setTarget");
}

toRenderize (btw the verb is “to render”) us filled with an instance of your prefab. right after this you fill it (a reference) with an empty gameobject and thus loose the reference to your prefab. then you add the empty gameobject in your list and send a message to it. if i where you i would delete the line toRenderize = new GameObject();. or maybe i just don’t get what you want to achieve with this.