Game Development Stack Exchange is a question and answer site for professional and independent game developers. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I am trying to use component based design in Unity3d v5. If I have 2 separate C# scripts attached to enemy ships like below:

  1. Script1.shipDead() - Remove game object and show explosion animation
  2. Script2.showPoints() - Destroyed ship shows points ex: +100 (later this will fade away)

How can I perform showPoints() function after shipDead() function has been performed, as a callback?

I can't put both actions in the same function, as some enemies will not have points. Some enemies will leave power ups/ small enemies/ bombs after being destroyed.

And I don't want to duplicated the same code in 4 functions.

Like :

  1. function 1: destroy ship (nothing more)
  2. function 2: destroy ship + show points
  3. function 3: destroy ship + spawn small enemies
  4. function 4: destroy ship + show points + spawn bomb

(As you can see above, there are many different possibilities / combinations I can come up with)

I need to separate functions and isolate them to do individual tasks. As shipDead() will not do anything related to showPoints() or showPowerUp() functions.

My question is how can I perform functions sequentially? One after another, like a callback function?

Like this:

  1. run Script1.DestroyShip() first;
  2. after that run Script2.ShowPoints();
  3. and finally run Script3.SpawnBomb();

Please provide a solution that will not violate the following:

  1. Components needs to be reusable (I can drag and drop the scrip in to other enemies/ships)
  2. Code shouldn't be duplicated
  3. Loosely coupled (Lesser dependancies)

Please help me on this, Thanks in advance!

share|improve this question
    
Why not use a virtual method? Override it to add extensions. Although, I guess that violates the dependency thing. I think your components are too small. I know splitting a game object up into little reusable functionality like this sounds appealing, but in practice I've found it's much more trouble than it's worth, especially when game objects with multiple states and animations are involved. The fact that all these things need to be executed in a sequence upon a specific event is enough to tell you they have some sort of dependency on something. – Ben Mar 27 '15 at 12:05
    
Thanks for the quick reply ben, with your experience do you encourage to use standard OOP, inheritance and etc over this "component based design". Do you find OOP more easier to implement in practice? – NeverBeenToSchool Mar 27 '15 at 14:22
    
I think it certainly is a great way to go about things, just not in this way. Trying to completely decouple tiny functionality like this is very difficult and probably not worth the time. For the approach I'd recommend, look at Unity's example components( there's a heap in the Unity 5 demos ) or at the examples in Unreal 4( there's a heap here too ). Really, components in this sense should provide one complete package, that's more than a single method. Think of transform, RigidBody, Renderer, etc. They can be huge pieces of code, but are still very reusable. – Ben Mar 27 '15 at 15:02

I see two solutions to your questions.

1) Use the SendMessage(string methodName) function. It will call the given method on every components of the gameObject. (More info here: http://docs.unity3d.com/ScriptReference/Component.SendMessage.html).

Here is an example:

public class Script1 : MonoBehavior
{
    public void DestroyShip()
    {
        /* Destroy the ship here. */
        SendMessage("OnShipDestroyed");
    }
}

public class Script2 : MonoBehavior
{
    public void OnShipDestroyed()
    {
        this.ShowPoints();
    }

    public void ShowPoint()
    {
        /* Show points here. */
    }
}

2) Use .Net events. Receiver registers to an event triggered when the ship is destroyed. Here is an example as well:

public class Script1 : MonoBehavior
{
    public event System.EventHandler OnShipDestroyed;

    public void DestroyShip()
    {
        if (this.OnShipDestroyed != null)
        {
            this.OnShipDestroyed.Invoke(this, new System.EventArgs());
        }
    }
}

public class Script2 : MonoBehavior
{
    void Awake()
    {
        this.GetComponent<Script1>().OnShipDestroyed += OnShipDestroyed;
    }

    private void OnShipDestroyed
    {
        this.ShowPoint();
    }

    public void ShowPoint()
    {
        /* Show points here. */
    }
}

Note that this solution creates a dependency of Script2 to Script1.

Hope it helps.

share|improve this answer
1  
Not much point using events in Unity for the purpose of decoupling components if you're going to keep the dependency. You should definitely mitigate as much dependency as possible by instead just even using a single EventManager Singleton class etc. You'll quickly run into spagetti code adding listeners to individual scripts etc. – DanoThom Mar 27 '15 at 13:12
    
Thanks! It seems "component based design" is not the best approach ever. Do u think for big projects this "component based design" is not a good idea? As it seems to be creating more problems for me. – NeverBeenToSchool Mar 27 '15 at 14:27
    
I totally agree with DanoThom that the second solution leads to dependencies and puzzle-programming. The first solution is more suitable for the component design you are trying to achieve as the SendMessage function does not require a recipient, and do not require to know the type of the script that invoke it. – Hef Mar 27 '15 at 16:58
    
@Hef You just have to know the EXACT name of the message in order to respond to it. Sounds like a dependency to me. Just a very poorly expressed one. – Ben Mar 27 '15 at 17:22

I'm going to try and write some example code using delegates since I think they might do what you want. Code is mostly taken from the delegate section of MSDN

using UnityEngine;
using System.Collections;

namespace MyNamespace
{
    public class ShowPoints : MonoBehaviour
    {

        public void showPoitsn()
        {
            Debug.Log("ShowingPoints");
        }
    }
}

using UnityEngine;
using System.Collections;


namespace MyNamespace
{
    public class DestroyShip : MonoBehaviour
    {


        public void Destroy()
        {
            Debug.Log("ShipDestroyed");
        }
    }
}
using UnityEngine;
using System.Collections;

namespace MyNamespace
{
   public enum BehaviourType
    {
        JustDestroy,
        DestroyAndShowPoints,
        ShowPoints
    }
    public class DelegateHandler : MonoBehaviour
    {
        private DestroyShip dShip;
        private ShowPoints sPoints;
        public  BehaviourType type;
        delegate void MyDelegate();
        MyDelegate destroy, showPoints,c;
        void Start()
        {
            dShip = GetComponent<DestroyShip>();
            sPoints = GetComponent<ShowPoints>();

            destroy = new MyDelegate(dShip.Destroy);
            showPoints = new MyDelegate(sPoints.showPoitsn);

            ComposeDelegates();
        }
        //Now we need some logic to handle the composing of a new delegate that can invoke the functions depending on our cases

        void ComposeDelegates()
        {
           switch(type)
            {
                case BehaviourType.JustDestroy:
                    c = new MyDelegate(destroy);
                    break;
                case BehaviourType.DestroyAndShowPoints:
                    c = new MyDelegate(destroy + showPoints);
                    break;
                case BehaviourType.ShowPoints:
                    c = new MyDelegate(showPoints);
                    break;
            }

            c();

        }

    }
}

How this works is that you attach all the components to the gameObject and the select what type of behaviour you want from the DelegateHandler. In my opinion this covers your criteria and its easy to extend. Not sure about the dependancy criteria you have.

share|improve this answer
    
Interesting approach. But this would create lots of boilerplate code I imagine. – S. Tarık Çetin Nov 25 at 16:40

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.