General Scripting Best Practices ?

As already "sort of " described in this question http://answers.unity3d.com/questions/489039/exposing-reference-or-resourcesloads-best-practice.html (not answered) I am unsure about how to properly script for unity (using c# here).

My Problem is that I cannot combine proper inheritance with the need of extending the MonoBehaviourclass.
When for example having a unit in my game, I have the superclass unit and now want to make subclasses for the specific units.
This won’t work because the specific units derive from my Unit class and not from the MonoBehaviour class, therefore I can’t attach them to the GameObject neither in the editor nor by AddComponent.

The only way I found to work around that is to make the Unit class very very big and add all possible configuration for the specific units into that class and let it derive from MonoBehaviour. But this seems very messy and swollen to me. I want to have own classes for different units and derive from my own superclass.
Having similar data/structure-types would also make this approach very redundant as I would have to copy most of the functions/members into seperate classes instead of deriving from the same superclass.
This kinda destroys the sense of OOP for me.

I hope you guys can hint me into the right direction?
I really want to get started scripting, but I don’t know what approach to use.

Can your base class not derive from MonoBehaviour? All child classes can then be added as you would want.

@Frotty,
I am 4 years into scripting, and last month I hit my first conundrum of realizing the benefits of superclass, subclass etc. I was racking my brain how to get the correct scripts to call each other. GetComponent was too cumbersome and given the amount of times I would need to get a component at start or awake, I felt I would be choking the engine, delaying the games ability to start smoothly.

I then was reminded of SendMessage(). I had been using get component over this before since it most likely is easier on the engine to call a coached components function. However, wieghing the alternatives I am using send message very frequently on mobile with no hitches.

For instance, I have an object entrance manager which must call in various objects into scene. Each object has a different script, but they all have a common function, runMember(). This allows my manager to just gather an object from its array, then it tells the object to runMember, via sendMessage. Ultimately this saves me gathering the component of the object, when the compent could be one of many.

This method I find is very clean and handles the issues I was having with creating a superclass, subclass etc. on top of that, it is flexible, as I can have other menagers calling an object that, if had built the superclass, but not have access to it as easily.

I hope this helps.

@Frottyz

Seems like youre heading down a path thats not really inline with how Unity wants to be used. Have your classes etc, but dont make them extend monobehaviour. Use OO for aspects like behaviour (AI, movement ability, weapons, player states, etc).

@renman

If you are only using SendMessage during initialization, thats fine…

if you are using the same pattern for all of your component communication, you are following an extremely inefficient and poorly designed path, especially for device.

This doesn’t work. The class has directly derive from MonoBehaviour, at least in the editor. Is this different with AddComponent?

I only read that SendMessage shouldn’t be used alot in the docks, but other than that, it sounds good.
Can you maybe provide a code example of how exactly you are using it? Does it work with subclasses of which a superclass extends MonoBehavior? Do you only call methods or do you retrieve the object that way?

Exactly that’s why I am asking how to approach this.
If I don’t extend MonoBehaviour, how do I attach my class-instances to the GameObjects?
I am making an RTS-style game where almost all unity are greated ingame and not placed on the editor.
If I can’t add the scripts to my e.g. prefabs, how can I communicate with my instances between objects without totally leaving out unity’s stuff?

I could save my instances in an array, using the .getInstanceId()-id as index, but this seems very “far away” from intended because I am basically doing what unity should/does provide in a bad way.

@James
How do you mean?

My method is this…
objectEntranceManager… Calls in onject via object*.SendMessage(runMember);*
Once object is completed its run, it tells the mng. This is my loop.
I am testing on an old iPod 4th gen, ad it runs fine. Like a dream. Since the objects in object[ ] have various behaviors, each with the common denominator runMember() this method works very well for me.

You would initialise your classes like a standard c# class within your monobehaviour classes.

eg.

public class TurretController : MonoBehaviour
{

  TurretBehaviour turretBehaviour;

  void Start()
  {
    turretBehaviour = new TurretBehaviour();
  }

  void Update()
  {
    Vector3 result = turretBehaviour.CalculateSomeStuff(transform);
    
    transform.Rotate(turretBehaviour.BaseRotationSpeed, 0, turretBehavour.HeadRotationSpeed);
  }

}


public class TurretBehaviour
{
  public float BaseRotationSpeed = 30;
  public float HeadRotationSpeed = 45;

  public Vector3 CalculateTargetRotation(Transform target)
  {
    //do something
  }
}

This is probably not really answering your question on the best OO approaches to use with Unity, but I dont see a huge amount of benefit in trying to implement heavy OO into Unity games, because as I said, Unity doesnt feel like it wants to be used that way.

To put it another way, Ive found very little need/benefit to follow a regimented OO design in my game. Sure some behaviours will be standard, and there will be places where some nice inheritance might make life easier. I prefer to write scripts that serve a purpose, and serve that purpose without being locked down to a single unit.

ie, The first thing my code does when it creates a vehicle, is add a vehicle system
That file will load an xml data file with all the details on vehicle behaviour, including engines, weapons, health, armour, etc.
Then the required scripts for each of those components will be added to the GameObject, each script adding the required scripts it needs.

ie, EngineController adds an axle controller, the AxleController will either add TrackControllers or WheelControllers depending on the vehicle type, and so on.

In my project, a typical scene has a camera with one script on it. From there the entire game can be built up without using a single prefab. This isnt really relevant to OO though. Thats more of a design decision. I dont like prefabs, and I dont like scenes, so I build my games without relying on either being pre-made. Sometimes this is a bit counter productive (ie, adding various effect scripts and setting properties on the main camera), but it also means I can get new scenes up and running very quickly.

@renman

Ive seen your game videos, come back and tell me its smooth when you’re working on something of significant size, when performance and optimization are very important.

Getting into bad habbits is never going to be beneficial.

My game videos tend to stall because I am building on an iMac, and running Unity and Screenium, to,record, causes chokes. On the device it works fine thank you very much. In fact I have overloaded my scene with enemies, all running various maneuvers, and it only begins to choke when there are way too many, and more than I would have in game in scene, running at once.

Again, you have have not pointed out why this is a bad habit. Just made a snappy remark.

Not very helpful.

Thanks alot for your detailed answer, JamesLeeNZ.
I have been working with Java OpenGL frameworks and not complete game engines, this is why I am thrown off a bit.

This is something I also thought about. Having a Container-Class that contains the actual class that I want.
My problem here is that I would either have to make a container for every class that will be attached or a general container which “type” of created class gets set in unity and then used via reflection.
Both ways seem kinda bad/redundant.

Well I’m used to it and in my opinion it’s very great. Kinda sad that unity doesn’t “work” that well in that aspect I guess, it was the best of the “average” engines that I found.

This is somewhat the way I want it to be, too! I don’t want to make too much in the editor and rely on scripting most of the time.
I am using the scene-editor tho, because I only will have 1 scene.
How do you avoid using prefabs? I read everywhere that making Prefabs and instantiating them is the better choice than creating the complete Object in Script yourself. How do you generalize the process ?

Also, more importantly, how do you attach/retrieve your scripts then, if you don’t use prefabs?
Do you use Add/GetComponent or what?

Please don’t throw me off by saying I could try and find this out myself - I sure could - but I would much rather have a solid approach which I can use without reinventing the wheel badly for every step I do in Unity.

Again, thanks for the fast help!

Well what exactly is a prefab…

Its a gameobject with a handful of stuff added.

There are things that I do use the prefab system for, but these are generally things I dont feel like building up in code, like particle systems. Those are easier to get working in scenes and then save out.

Usually I retain the reference to the components as I add them.

elaborate…?

public class EngineController
{

  AxleController axleController;
  
  void Start()
  {
     axleController = gameObject.AddComponent<AxleController>();
  }

}

Okay thanks, I guess you created the gameObject in code earlier?
Doesn’t EngineController have to extend MonoBehaviour?
How does Start() get called if you didn’t apply it to a GameObject? You mentioned before that you only have a BehaviourScript on an CameraObject, are you doing the other initialization object-updating yourself?
How do you keep track of the EngineController if you only add the AxleController to the GameObject?

That probably wasnt the best example because it wasnt code complete

  1. gameObject is the reference to the GameObject on which the enginecontroller is attached.
  2. Yes it should have been a monobehaviour
  3. I dont have any Behaviour scripts, I was suggesting if you wanted to follow some OO approach, that is how you might like to do it. All of the classes in my game that are attached to say a vehicle are MonoBehaviours. I have a handful of Data related classes that are not MonoBehaviours, but they arnt relative to OO.
  4. EngineController is already attached to the object (by another script previously).

I dont really need to keep track of the engine controller, they all self manage. The only input they take is forward/back/left/right, the rest is done internally. Its not really an OO approach, but this is my point… There isnt a huge gain in making an inherited OO system. Is any code in my solution re-usuable in a different game… not really… does it matter? I dont think so.

I’ve seen highly optimised (non OO) software that performed extremely well, turned into sluggish trash because someone wanted to follow OO best practices.

Okay, I think I got it now, thanks alot.
A followup question that comes to my mind now because of you not using prefabs is similar to the one I posted in the first post. How do you create your game objects if not using Prefabs? are you using resources.load or what? mentioned in the question i Linked in the first post this method seems deprecated which is why I’m wondering ,since you seem performance-oriented, if you are using it anyways.

Okay, here is how a typical vehicle would get built…

  1. Call CreateVehicle function (usually this is done via GUI)

  2. Load mesh for vehicle from resources - Instantiates Transform using Mesh as source

  3. Attach VehicleSystem script

  4. VehicleSystem script loads the xml data file that contains all my vehicle characteristics - this is based on the mesh name - ie. apc-01 (apc-01.xml)

  5. VehicleSystem Start calls a handful of Init functions (Physics, Weapons, Engines), based on the xml data, this includes adding a handful of scripts to the instantiated vehicle

  6. Each script self initialises via Start… this is based mainly on the sub-meshes (child transforms) of the vehicle mesh… so the EngineController script loops through all the meshes, if it finds meshes named track, it attaches a TrackController to that mesh, if it finds a Wheel mesh, it adds a WheelController, and so on. From there it knows its dealing with a tank type of vehicle. If no track meshes are found, it knows its dealing with a car/truck type vehicle. If its a non track vehicle, it adds WheelColliders to each wheel, the WheelController figures out the location of itself on the parent model… if its at the front, it knows its a turning wheel, if its at the back, it knows its a driving wheel, if its on the left, or right, etc.

So you use Resources.Load here ?

Also, you said you don’t use any BehaviourScripts ( I mean Scripts that extend MonoBehavior ! ), yet you say they self-initialize via Start and self-manage - how does that comply?

Short summary if I got it:
-Create Meshes/prefabs etc. with Resources.Load
-Add A “general” controller-script
-Add various ScriptFiles through controller that extend MonoBehaviour(?) and self-initialze/manage

Can I create the class and modify values before adding it or can I do it after adding?
If I am not using the unity inspector to modify values I would need a different script for e.g. every button, is that correct?

e: Also, “Call Create Vehicle Function” - is that a static function or how do you call it?

Just to clarify a previous point - this isn’t true. An “indirect” derivative class works just fine. And actually - the only requirement is that the class derive from Component - of which MonoBehaviour does. So you’ve actually already got several layers of inheritance going. :slight_smile:

does the indirect one work with AddComponent or what? It does not when dragging the script onto an object inside the editor.

It works with AddComponent. It also works if you click on the big Add Component button in the Inspector. I don’t do much drag-and-drop so I can’t speak to that but it sounds like something is wrong with your setup or code.

I have this inheritance chain working just fine in Fractured State:
ToolManager → ManagerWithMenu → Manager → MonoBehaviour

ToolManager is the only thing that ever gets added directly to a GameObject and Manager is abstract.