Ignore Raycasts on layers other than layer 2

I’m making an RTS and everything’s coming along really well. I can place/upgrade buildings, mine/spend resources and send tanks/soldiers/choppers of to battle.

BUT, I want to get rid of this ugly piece of code…

		GameObject newUnit = Instantiate(unit, this.transform.position, Quaternion.identity)as GameObject;
		newUnit.tag = this.tag;
		newUnit.transform.gameObject.layer = this.transform.gameObject.layer;
		if(this.transform.gameObject.layer == 10)
		{
			newUnit.transform.gameObject.layer = 16;
		}
		if(this.transform.gameObject.layer == 11)
		{
			newUnit.transform.gameObject.layer = 17;
		}

Every time a structure instantiates a unit, it sets that unit’s layer as Player_1_Unit if the structure’s layer is Player_1_Building. The script sets the unit’s layer to Player_2_Unit if the structure’s on the Player_2_Building layer. The reason the unit’s currently can’t share the same layer as the structures that instantiate them is that the units have a sphere collider to detect enemies to shoot at. This sphere ends up catching any Raycasts before they reach the building, which means the player can’t upgrade the buildings or re-aim where the buildings are sending their tanks/soldiers/choppers etc.

This works fine, but it seems cumbersome and I’m wondering if there’s a better way to do it.

I have tried creating a LayerMask and assigning that to the unit but of course Unity complains that an object can only be on one layer, which makes sense.

Is there a way to simply assign both the building and unit to layer Player_1, Player_2, Player_3 (and so on…), but have units on that layer ignore Raycasts?

I’m pretty sure the answer’s ‘no’ and the code I currently have works fine, I just want to make sure there isn’t a more elegant way of doing this before I move on to the next phase of this project.

Any help greatly appreciated. =)

I think putting objects on separate layers as you’ve described is as good as it gets.

You could clean up this code, perhaps making things easier as you move forward, by creating a system which handles this for you. It looks like you’ve got a decentralized way of handling layer assignment on a case by case basis, whereas it can and probably should be a static method or something you can call from anywhere in your project; then all such logic can be edited in one place.

You appear to be basing the layer assignment decisions on the object’s current layer - there’s not anything inherently wrong about that, but it looks like a potential headache. I’d suggest an alternative way of determining which layer to assign; perhaps by some meta information you have access to when you’re calling your shiny new static method, like the unit or structure’s class or team.

// layers
// 10 = friendly structures
// 11 = friendly ground units...
// 20 = enemy structures
// 21 = enemy ground units...

// in a Statics.cs file...
public static class Statics {
  public static int GetLayerFor( BaseClass source ) {
    int result = 10;
    if (source.team == 2) result += 10;  // team 2's layers start @ 20
    switch (source.classification) {
    case Classification.Structure : return result + 0;
    case Classification.GroundUnit : return result + 1;
    }
    return result;
  }

  public static void SetBestLayer (this BaseClass source) {
    source.gameObject.layer = GetLayerFor( source );
  }
}

// when instantiating an object derived from BaseClass
GameObject go = Instantiate(prefab) as GameObject;
go.GetComponent<SomeDerivativeOfBaseClass>().SetBestLayer();

//and if you ever need the layer without changing the object
int layer = Statics.GetLayerFor( myObject );

I think you are approaching this from the wrong direction - don’t ask ‘how do I make my object ignore a raycast’, instead you should ask ‘how do I make (a particular) raycast ignore this object?’

Then, on wherever you are shooting your raycast from, you can use a layermask to ignore a layer.

Actually, in your case, it might actually be easier to simply put your structures and units on the default layer, and put the sphere collider that you use for enemy detection on the Ignore Raycast layer, so that it won’t catch any raycasts (because you don’t want it to, is what I understand from your comment?).

But if you want to use custom layers you can put those sphere colliders that detect enemies on some ‘RadarLayer’ or something, and when you raycast to select a building or unit you use a layermaks to tell it to ignore RadarLayer.