SendMessage

I have a script that changes a gameObjects material. I’m attempting to have that change of material trigger a “laser shot” that’s controlled on another script. But for the life of me, I can’t figure out why the two scripts aren’t talking to each other. Below are my two script, can anyone help?

// Preview
var myMaterials : Material[];
var delay : float; // seconds between color changes

  function Start () {

    InvokeRepeating ("ChangeColor", delay, delay);
	
}

 function ChangeColor () {


    renderer.material = myMaterials[Random.Range (0, myMaterials.Length)];
    SendMessage("laserBeam");

	
}
//Auto Fire based on preview 

SendMessageOptions.RequireReceiver("laserBeam");


var laserBeamPrefab : Transform;


function Update (){

		
        var laserBeam = Instantiate(laserBeamPrefab, gameObject.Find("spawnPoint").transform.position,Quaternion.identity);
    
    	laserBeam.rigidbody.AddForce(Vector3.forward * 100);

        lastFireTime = Time.time;
 
    }

In my mind, “laserBeam” should just be a function in your second script. There is no need for the SendMessageOptions. Also, you are instantiating a laserBeam prefab every frame. That can’t be good.

SendMessage only works on the object the script is attached to. If you need to send a message to another object, you need to get a reference to that object first. SendMessageOptions is something that can only be used inside SendMessage; if you try to write code the way you have it, it will generate an error and the script won’t compile.

–Eric

lol your right, a laserBeam is being instantiated every frame- it one of the issues I’m trying to fix. I’m trying to set it up so the “preview” determines the speed rate of fire. What do you mean that the “laserBeam” should be a function of the second script?

Script A:

    // Preview
    var laserShooter : GameObject;//Make sure to assign this in the inspector, with the object that has Script B on it (can be the same object or not)
    var myMaterials : Material[];
    var delay : float; // seconds between color changes
     
      function Start () {
     
        InvokeRepeating ("ChangeColor", delay, delay);
       
    }
     
     function ChangeColor () {
     
     
        renderer.material = myMaterials[Random.Range (0, myMaterials.Length)];
        laserShooter.SendMessage("ShootLaserBeam", SendMessageOptions.RequireReceiver);
     
       
    }

Script B:

    //Auto Fire based on preview
     
    var laserBeamPrefab : Transform;
     
     
    function ShootLaserBeam (){
     
           
            var laserBeam = Instantiate(laserBeamPrefab, GameObject.Find("spawnPoint").transform.position,Quaternion.identity);
       
            laserBeam.rigidbody.AddForce(Vector3.forward * 100);
     
            lastFireTime = Time.time;
     
        }

I haven’t tested this, but I think it should work fine.

^^^^
That’s what I meant.

Edit.
I’d also recommend that you use GetComponent() over SendMessage(). SendMessage has to check all scripts attached to this object, then run thru each script to see if it has said function. getComponent() stores the script in question saving some processing time.

Thanks for the tip! The only problem I’m having with the script idea from deram_scholzara is that it won’t let me assign my object for “Laser Shooter” into the inspector. The object is a the “laser” itself. It’s a prefab that instantiates if that helps out at all. Is there another way of assigning it that I may not be aware of?

Looks like a jumped the gun on that one. I got the object assigned in the inpsector ( was a brain fart moment). Now I’m getting the error:

SendMessage ShootLaserBeam has no receiver!
UnityEngine.GameObject:SendMessage(String, SendMessageOptions)
laserPreview:ChangeColor() (at Assets/Scripts/laserPreview.js:23)

Any ideas? I’m really close to this! Help is much much much appreciated!

So you simply want object, or component A to tell component B to do that?

If so, just use

///this is scriptB on objectB
var objectA: GameObject;
var objectAData : scriptA;
function Awake()
{
objectAData = objectA.GetComponent(scriptA);
}

function Start()
{
///objectB has instructed objectA to perform its doSomething function
objectAData.doSomething();
}

I just realised I coded that incorrectly. I adjusted it above.

really cool! I’m messing with it now. I’m not 100% clear on your line 12, the “doSomething” part. What part of ScriptA do I put there?

Line 12 is whatever you want. In this case, I have told objectB’s script to instruct, objectA’s script to perform the function doSomething(). With the pointer, objectAData, you can call any function in objectA, set any public value as well. Lets say for instance that you want to set onjectA’s var, score, or adjust it. You would do something like this.

///lets just say, object b is an enemy who was just killed.
/// since he was killed, we must adjust the score, held in objectA
function thisEnemyKilled()
{
objectAData.score += 100;
}

What happens here is that, we have added 100 to the value of objectA’s score variable.

My Brain is leaking is starting to turn into jello. I have no idea what I’m doing wrong. I’m getting these too errors:

ArgumentException: The prefab you want to instantiate is null.
UnityEngine.Object.CheckNullArgument (System.Object arg, System.String message) (at C:/BuildAgent/work/7535de4ca26c26ac/Runtime/ExportGenerated/Editor/UnityEngineObject.cs:103)
UnityEngine.Object.Instantiate (UnityEngine.Object original, Vector3 position, Quaternion rotation) (at C:/BuildAgent/work/7535de4ca26c26ac/Runtime/ExportGenerated/Editor/UnityEngineObject.cs:81)
LaserFire.Start () (at Assets/Scripts/LaserFire.js:71)

SendMessage ShootLaserBeam has no receiver!
UnityEngine.GameObject:SendMessage(String, SendMessageOptions)
laserPreview:ChangeColor() (at Assets/Scripts/laserPreview.js:23)

scriptA (aka "laserPreview, and is placed on gamObject “preview”)

// Preview
var laserShooter : GameObject;//Make sure to assign this in the inspector, with the object that has Script B on it (can be the same object or not)

    var myMaterials : Material[];

    var delay : float; // seconds between color changes

     
      function Start () {


        InvokeRepeating ("ChangeColor", delay, delay);

       
    }

     
     function ChangeColor () {

     
        renderer.material = myMaterials[Random.Range (0, myMaterials.Length)];

        laserShooter.SendMessage("ShootLaserBeam", SendMessageOptions.RequireReceiver);
     

    }

ScriptB (aka “LaserFire” and placed on gameObject “gun”)

//Auto Fire based on preview 

var objectA: GameObject;

var objectAData : laserPreview;

function Awake()

{

objectAData = objectA.GetComponent(laserPreview);

}

function Start()

{

///objectB has instructed objectA to perform its doSomething function

//objectAData.doSomething();

var laserBeamPrefab : Transform;

var laserBeam = Instantiate(laserBeamPrefab, gameObject.Find("spawnPoint").transform.position,Quaternion.identity);
    
    	laserBeam.rigidbody.AddForce(Vector3.forward * 100);

        
        lastFireTime = Time.time;

}

Wait. What are trying to do?

GetComponent, is a replacement for SendMessage. You are not even using the component you got. Can you please describe the scripts names and what each does, and what script you want to access from another script and for what reason.

Script A is called “laserPreview.” Its attached to a game object (called “preview”). Its acts as a preview to display the next color laser that shoots out. Example: Game starts, the preview is Blue. When the preview changes to the next color (lets say red), the color change triggers a blue laser to shoot. When the preview changes from red to the next color, the change triggers a red laser to shoot. And so on. Notice in this “Shoot Bubble” video, how you can see the what the next color bubble is going to be.

Script B is called “LaserFire.” Its attached to a game object called “gun” that contains a “spawnpoint.” It instantiates the laser prefab from that spawnPoint.

Thanks again for your continued help on this. You are a saint!

So you want to have a preview object and the shoot object.
I would consider putting them into one script.
If I may…

////shooting manager
/// handles preview and shot.


var previewCrystal :GameObject;
var loadedCrystal : GameObject;

function Start()
{
SetUpPreviewCrystal();
}

function setUpPreviewCrystal()
{
	previewCrystal = someRandomColorCrystal;
	//you will have to figure out how tocreate the random crystal
	//you must then know how to translate that crystsl and its color to the above function, setUpLaser()
        setUpLaser();
}
function setUpLaser()
{
	loadedCrystal = previewCrystal.color;
}
function shootLaser()
{
	//here you must propell the loadedCrstal somehow on input
	loadedCrystal.move();

///then start the cycle again
	setUpPrevieCrystal();
}

This code is not really code, but hopefully it gives you an idea of how one object can manage multiple things.

Thanks for all your help boss. It will take me some time, but I’m sure I can figure it out.

Does it make sense for what I am saying?

For what you need to do, SendMessage, even get component are unnecessary. But, if you want to use SendMessage, the other script you are sending a message to, has to be on the same object. Get component, it can be on any object.

Hope that helps chief. Back to hockey! LoL

It makes sense. But I’m still having trouble with it. 3D software for modeling, texturing, animation all come very natural to me. But Scripting is forcing me to use parts of my brain that have previously have only been used for vodka, beer, and other recreation lol. I’ve been trying the idea putting everything in one script.

So I’ve got my “gun,” “spawnPoint,” and “preview,” all parented under “gun.” Then I have my one script as a component of gun. I’m not getting any errors, however the gun changes colors randomly - and not the preview. The “lasers” shoot but there just not the defualt material :confused: Here’s my script (in progress) if you have any input.

var preview : GameObject; 
var myMaterials : Material[];
var delay : float; // seconds between color changes


  function Start () {

	gameObject.Find("preview");
    InvokeRepeating ("ChangeColor", delay, delay);


}


 function ChangeColor () {

 	gameObject.Find("preview");
    renderer.material = myMaterials[Random.Range (0, myMaterials.Length)];


}


//Fire 

var lastFireTime : float;
var fireDelay : float = 3.0f;
var laserBeamPrefab : Transform;
function Update()

{
	if(Time.time > lastFireTime + fireDelay)

    {

        var laserBeam = Instantiate(laserBeamPrefab, gameObject.Find("spawnPoint").transform.position,Quaternion.identity);
    
    	laserBeam.rigidbody.AddForce(Vector3.forward * 100);

        
        lastFireTime = Time.time;
        

    }


}