Help Me Understand Inheritance

Okay, I’m hopelessly lost with figuring out how inheritance works in Unity JS.

Here’s the setup: I’m making an RTS engine where the player can control different units. I have an abstract class called “Unit” and two inheriting classes called “Tank” and “Ship”. In Unit.js I define a function like so:

virtual function moveTo() {
...
}

Now, when I’m Raycasting to see which unit the player clicked on, “Tank” or “Ship”, I get a reference to an instance of the Tank object or Ship object. Once I get that reference, I want to be able to call the moveTo() function on it, but how? I know it’s supposed be in this form:

reference.scriptName.moveTo()

But if I say

reference.Unit.moveTo()

I get an error. And I can’t say

reference.TankScript.moveTo()

because the reference might be a ship, and that would throw an error.

I’m an ActionScript 3.0 guy and the fact that Unity objects can have multiple scripts is totally throwing me off. No matter how I try, I can’t seem to access functions dynamically across various objects. It’s like a catch-22: to access moveTo() I need to know the object’s script name. But I can’t know the script name because depending on the object selected, it changes.

How do you guys deal with this problem? It’s impossible to code anything without resolving it.

Also, when you guys speak of “classes”, are you talking about the script or the object? And for the above example, is it necessary to have the abstract Unit object actually in the Hierarchy (in the game world), or is it simply enough to have a script called Unit?

You need to use GetComponent to get a specific component. ScriptName will not work

I don’t see how GetComponent helps. What would I be getting the component of? Doing as you say would look like this:

var scriptName:TankScript = GetComponent(TankScript);

But that’s just begging the question. What if the component I need is the ShipScript? I can’t hard-code every component; they need to be dynamic.

the game object on which the component is.

And yes you will have to know the type of component you are looking for or can’t look for it.

Look up SendMessage. Also, instead of doing the raycasting yourself and referencing scripts, look up OnMouseDown.

–Eric

That helps somewhat, but I’m still baffled how Unit doesn’t allow me to work dynamically with large batches of objects. I’m hesitant to even consider how I’ll solve more complex interaction if something this basic is proving impossible.

Just consider this example: I have 500 different types of objects that can be out in the world. Some of these objects the player can select with his mouse, some he cannot. Of those he can select, some are stationary, some are mobile. Ideally I want to be able to give every object in the game a variable like: isSelectable and isMobile. Then, I want to be able to check those variables across all 500 object types.

In this case, tags do not suffice, because an object can only have 1 tag. I need to be able to say:

if (reference.isSelectable == true) {
...
}
else {
...
}

But Unity doesn’t allow it. Am I supposed to create a 500-part switch statement to match up every possible reference and GetComponent(ScriptName)? Here’s what it would look like, but it’s absurd:

if (GameObject.name == "Tank") {
  var xxx = GetComponent(TankScript);
}
else if (GameObject.name == "Ship") {
  var xxx = GetComponent(ShipScript);
}
...
...
... 498 more times!

if (reference.xxx.isSelectable == true) {
...add reference to array of selected objects
}

What am I missing? If Unity can’t handle this operation elegantly, I might as well stop evaluating.

No. :wink: If you want to tell an object to execute a MoveTo function when clicking it by using raycasting, and if it doesn’t have a MoveTo function then don’t do anything, you’d write:

if (Physics.Raycast(ray, hit)) {
	hit.collider.SendMessage("MoveTo", SendMessageOptions.DontRequireReceiver);
}

I get the impression you may be trying to write a single “controls everything” script, but it’s a lot simpler to have each object in Unity have its own scripts attached which do different things depending on the objects’ functions.

–Eric

Agreed. Unity’s object/component architecture can take a bit of adjustment for someone coming from a different programming background, but basically it’s something like this:

Each GameObject is a thing in your scene, and has an arbitrary number of components attached to it.

Components are classes, and each class defines a specific behaviour for the object.

So instead of having your units differentiated by properties in one hierarchy of master scripts, Unity expects you to have each behaviour as its own class in its own script, and a GameObject’s behaviours are defined by which of those scripts are attached to it.

So your Tank would be a GameObject with the Selectable behaviour, the Driving behaviour and the GunTurret behaviour attached as their own scripts, whereas the FighterJet would be a GameObject with Selectable, Flying and MissileRack behaviours. You can inherit behaviours too, so for the above example have a Movement parent behaviour and a Weapon parent, and inherit from those. You already know that part, though. :wink:

The only other key piece that you’re missing is that GetComponent can find classes by type. For example, if you want to get the renderer on 10 objects and half of them are MeshRenderers but half are SkinnedMeshRenderers, using GetComponents(Renderer) (i.e. the parent class) will return all of them.

Going back to the inheritance-based thing we were discussing elsewhere, instead of:

if (GameObject.name == "Tank") {
  var xxx = GetComponent(TankScript);
}
else if (GameObject.name == "Ship") {
  var xxx = GetComponent(ShipScript);
}
...
...
... 498 more times!

if (reference.xxx.isSelectable == true) {
...add reference to array of selected objects
}

…Tank and Ship can derive from a common base class (Unit, for example, as we discussed in the other thread), then you can do this:

var unit : Unit = GetComponent(Unit);
if(unit.isSelectable)
{...}

If the GameObject has a Tank component on it, GetComponent(Unit) will still find it, and you’ll be able to access it through any of the properties and (ideally) virtual functions defined by Unit without any further type checks. You don’t need to concern yourself with the actual type of the unit if you do it this way.

This can be used alongside Eric’s suggestion of using SendMessage and dawvee’s collection of components. I use a mixture of all of these techniques in my own projects.