How to damage different types of objects with least code vs least overhead.

How guys,

I’m trying to set up a simple explosion that not only stuns and throws the player about (have simple 3D animation as my head has no arms - so can’t ragdoll, lol). However I want the same explosion to be able to blow out lights, blow doors in and the like.

FYI it’s a simple 2.5D game, so for placeholder stuff I’m just removed doors/windows renderers and playing a particle system to simulate debris.

My question is this…

I haven’t used SendMessage yet, but from what I’m read on these forums it seems to be rather overhead intensive. My other option is to check each object, then check it’s tag, type and find the relevant script for the right types of object. This will be quite code intensive (the amount of code that is, imagine it’s just a lot of the same with different references in if’s).

Which would be better to use? I will using a raycast to make sure that nothing it comes into contact with isn’t on another floor (don’t want that, lol).

Also would I have to have an receiving Function in each objects script? For Example

// this object does not actually respond to 'Boom'
public void Boom()
{
return;
}

you use enum and statemachine to avoid overhead

then you use GetComponent on interaction to access that object… or SendMsg if you dont have well structured code.

1 Like

Hi @Ironmax ,
Thanks for the reply. I haven’t gotten round to using enum or statemachine - will look into those in a few mins.

As for getcomponent, that’s what I was meaning by “check each object, then check it’s tag, type and find the relevant script” (wasn’t clear, I know… :frowning: ).

Would it be better to have a ‘boom’ script on all objects and then have the relevant ‘what object am I attached to’ code in that to find the right componenet/script, or have all that in the explosives code? I’m still learning about well structured code - keep coming back to bits I wrote 2 days ago and thinking “now that’s just a mess” lol.

No problem. You use tags on target/objects type, but you use enum on “damage different types”.

Example:

    public enum DamageType
    {      
        Fire,
        Ice,
        Magical,
        Melee
    }

DamageType damageType; // make an instance of that in this code..
damageType = DamageType.Fire; // just example

if (damageType == DamageType.Fire)
{
     // on trigger event
if (hit.gameObject.tag == "Monster")
{
// Do fire damage
}


}

There is also another way of doing it if you dont want to use tags. Tags uses string and string will allocate in memory…

1 Like

Okay, that makes sense - but how do I communicate this to the other object in question? (sorry I’m being dense today, lol)

Again, thank you for the help! XD

one way is to use this:

void  OnTriggerEnter(Collider  hit)
{

    // Interaction
// Example1:
hit.gameobject.GetComponent<GameLogic>().GetHit(damagetype);
// Example2:
// Other is to use SendMessege to access a object with different script name..

}
1 Like

Cool, that’s what I was thinking.

Essentially I’m looking for different scripts components depending on what the object is tagged as, right?

So I could have a light bulb with a tag as “ExplodableBulb” and a door as “ExplodableDoor” and then after checking the tag just use something like GetComponent().Boom();

Thank you for helping me to clear this up! Nice to know I’m on the right path still, lol.

I recommend using your enums in a global singletone script seperated. you can do statement check on enum when ever you want. its cheap and fast code…

1 Like

Only your mind is the limit :wink: but that is correct

you also can use the enum to access something else if damagetype == DamageType.Ice (example freezing)

1 Like

AWESOME!

Still not sure on the use of Enum (or singleton, for that matter)… but you’ve got me on a path now - I’ll go do some research on using using them both… after lunch, lol.

Again, many thanks for the Help @Ironmax - it’s been really helpful to bounce this off of someone! XD

P.S. you can probably tell that I’m teaching myself all this as I go, lol.

1 Like

Just happy i could help :slight_smile: and that i put you on the right track

// also hint… if you make the enum public, there be a rollup menu in the inspector so that you can set things up without touching any code.

1 Like

OK, here’s the key bit I think you’re missing: MonoBehaviours can implement an interface, and you can use that interface with GetComponent to get and invoke a method on all components that implement it.

So for example, you could define your interface as:

interface IExplodable {
    void Explode(Vector3 sourcePosition);
}

Now, any object that should react to an explosion should implement IExplodable, and do whatever it wants to do in response to that.

public class Bulb : MonoBehaviour, IExplodable {
    void Explode(Vector3 sourcePosition) {
        // here's what bulbs do when an explosion goes off nearby...
    }
    void Update() {
        // here's what bulbs do every frame...
    }
}

Now when you set off an explosion, you just find all objects within the blast radius (or on the same floor or whatever), and for each of those, do:

foreach (IExplodable exp in obj.GetComponentsInChildren<IExplodable>()) {
    exp.Explode(transform.position);
}

and presto, you now have things responding to explosions in their own way. Adding a new explosion response only requires defining a new MonoBehaviour that implements IExplodable; you won’t have to touch the invoking code at all.

Any time you find yourself checking a type and doing a switch or a big pile of if’s based on that type, this is a bad smell, and you should look for a better way (as you have done here!). So, good job recognizing that and asking for help!

Oh, and one more thing: you shouldn’t be worrying too much about efficiency at this stage. You should be focused on writing code that is clear and correct, and gets your game finished as quickly as possible. Bonus points if it’s also easy to maintain. Efficiency is the last thing you need to worry about, and only then after you’ve found an actual problem, and used a profiler to track it down to some inefficient thing you’re doing. We avoid SendMessage not because it has “overhead,” but because it is unsafe and fragile (using a string literal to look up a method is another bad smell).

3 Likes

COOL! Thanks guys.

@JoeStrout Me? Write easy to maintain and easily understandable. Steady on bud, one thing at a time! lol.

Yeah currently I’m using lot’s of If’s and, you’re right, it reeks to high heaven (even with my limited knowledge!).

Cool, well at least I have a few new skill sets to add to my trip bag. Will have to play around with them in my test project first to get to grips with them. Again, thanks guys!

P.S. When I’m ready to release a ‘Demo’ level of my game would you be interested in a link to it? Gonna be a while as I’m adding core features (okay… and exposions, lol) and bug squashing at mo with placeholder models… but it’s coming along, lol.

GetComponent does also allocate memory + i don’t really recommend interface at all (its a design/structure pattern). Let me clear up something. Overhead is not the same as allocation. You really cant avoid allocation like when you do collision or doing a raycast or even working with strings. Overheads happens when to much allocation happens at ones and the Garbage Collections kicks inn and draw your CPU resource to handle that.

“The key is to make sure things happen only, ones…”. Example OnCollisionTrigger is a much better practice then “OnCollisionEnter”.

I would really avoid doing things like this:

    foreach (IExplodable exp in obj.GetComponentsInChildren<IExplodable>()) {
        exp.Explode(transform.position);
    }

The reference to a game Compented should be allocated before using for loops, also read about pool-managing,
how C# works with mermory, stack/Heap boxing/unboxing etc before going in to interface pattern.

Singleton is also a design pattern just like interface, and is much easier to understand for a beginner. Even what Joe here says is correct, i think interface is something you go learn “next” or when your game project is huge and you need good structure. Interface takes some time to implement but, makes things easy to change in a huge project.

Here is a very good documentation about it:
http://wiki.unity3d.com/index.php/Toolbox

1 Like

I was fully with you until you got to the last part:

foreach (IExplodable exp in obj.GetComponentsInChildren<IExplodable>()) {
    exp.Explode(transform.position);
}

Where would this go? You’ve got an interface that declares an Explode function, making that a requirement for any class inheriting IExplodable. Then you’ve got member classes defining Explode. I’m that far.

It’s been a while since I saw foreach (thing in array) - so that’s saying “for each (type IExplodable Component) in list of all children gameObjects inheriting IExplodable.”

So you’re suggesting all the IExplodable objects are children of some manager class in this example, correct? - I’m sure there are many other possible arrangements as well.

1 Like

I am sure Joe was just using it as an example in good fate :slight_smile: I really like Joyes stuff on the forum. Interface is like the mafia, ones your a member, your with the “gang” all the time even if you like it or not :stuck_out_tongue: Your right there are many possible arrangements… Have a nice weekend every one.

1 Like

Interfaces are definitely the key to this. Interfaces are basically a contract saying what methods a type exposes. Tons of different types can implement the same interface. That way everything can respond to the explosion, without the explosion knowing about any other types.

Here is another code example to consider, working on top of what @JoeStrout has given you.

void DoExplosion (){
    Collider[] hits = Physics.OverlapSphere (transform.position, 1);
    foreach (Collider hit in hits){
        IExplodable explodable = hit.GetComponent<IExplodable>();
        if(explodable){
            explodable.Explode(transform.position);
        }
    }
}
2 Likes

I can understand that example and I’m pretty sure I’m going to use it in my game of life simulator I’m building. I’m making a 3D critter box. So far I’ve just been working on movement and orientation (five iterations, three different approaches- all saved, much learned) but soon I’ll want to implement more complex conditional behavior. I already use an interface to control my game’s states and switch scenes.

I disagree, interface is a design method not a key-feature, there is no one type fits all situation. Secondly he didn’t ask for vector3 explosion simulation,a simple partial effect would do it (and much better performance) and add some addforce physics or scaling physical objects. Arrays are also heavy on allocation. (the OP worried about overhead)…

Recommending interface in the starter forum section is maybe not the best. :stuck_out_tongue:

Use enums, they are smart cheap and fast…ofc every one is free to explode there own memory…

1 Like

This would go in the code for whatever’s exploding. That has the job of finding all the game objects within range (and if you need help with that, start another thread about it — there are lots of ways to go about it), and then just run the above code for each one.

Not at all. You run the above code on ALL objects within range (on that floor of your level or whatever). If the object has no IExplodable components on it, then the above code does nothing. No harm, no foul.

And note that I strongly disagree with @Ironmax about the relative difficulty of interfaces vs. enums-and-ifs. Interfaces are not hard; I posted above everything you need to know about them. Doing a bunch of if-tests may seem easier until you’ve tried the other approach, but try it once in a real game and you’ll see why it’s so awesome.

And yes, if you finish your game and notice performance problems and run the profiler and find that explosions are causing a glitch due to this GetComponentsInChildren call, then you can refactor it to improve performance in a variety of ways. But framerate glitches are not the greatest risk by far; the greatest risk is that you will never finish the project at all, due to drowning in complexity, or it taking so long that you lose interest. Thousands of games die such an ignoble death for every one that ever gets finished. So, be ruthless about using whatever code seems simplest, clearest, and easiest to maintain to you, and ignore any grim mutterings you may hear about allocations and garbage collection.[/code][/QUOTE]

3 Likes