5
\$\begingroup\$

I was wondering how should I design this relation in terms of "better OOP"?

Should I have a Singleton EnemyManager which contains a list of enemies (EnemyList); then Bullets can access the EnemyList to check for collision?

Or should I just pass EnemyManager as a reference to each Bullet so Bullets can still access the EnemyList but not in a Singleton way?

Or is there any other better ways of doing?

Please advise.

\$\endgroup\$
  • 1
    \$\begingroup\$ Have you considered just checking for the collision events of the bullet using OnCollisionEnter and checking whether it hit an enemy by comparing for its tag or layer? \$\endgroup\$ – brain56 Nov 1 '15 at 2:44
  • \$\begingroup\$ yea I did... but I'm not using unity's collider to check for collision. so I couldn't really use OnCollisionEnter \$\endgroup\$ – Cadrick Loh Nov 1 '15 at 3:28
  • 2
    \$\begingroup\$ Why aren't you using it? \$\endgroup\$ – brain56 Nov 1 '15 at 7:21
  • 1
    \$\begingroup\$ @nickson104 that's a long answer. Short version is that unity was not designed for OOP. It uses a component system. \$\endgroup\$ – Evorlor Nov 2 '15 at 15:12
  • 1
    \$\begingroup\$ @nickson104 in my experience, no. If you use straight C# objects sure, but then it's separate from the unity engine. Anything that inherits from mono behavior should be treated as a component and not an object. Someone could prove me wrong, but trying to OOP in Unity sounds like you want a different game engine. (Personally, I love the unity design pattern...don't tell anyone) \$\endgroup\$ – Evorlor Nov 2 '15 at 15:34
2
\$\begingroup\$

or is there any other better ways of doing?

What is your metric for "better"? Setting aside the comments on the question that "it isn't the Unity way", both of your approaches are just fine.

Another option is to pass in IEnemyManager (an interface or superclass of EnemyManager) to each Bullet, which exposes some but not all features of EnemyManager. The usual reasons for this approach are:

  • For testing, you might pass in a test-only implementation of IEnemyManager.
  • For safety, to prevent whoever's working on Bullet code from inadvertently or sneakily using methods on EnemyManger that you didn't intend for a Bullet to use, like creating new enemies or what not. (Less of an issue on a solo or small team effort.)

But probably a singleton is just fine for now if it lets you move forward on your project. (Or switching over to a more Unity-conventional way.)

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

In my experience, the structure you use should always be the least abstract (most understandable) that you can come up with, in a way that is also efficient. Think hard about the physics behind what you're trying to achieve. What should the bullet know about it's environment? What does the enemy need to know? How does the interaction take place?

Now there is probably a penultimate way of doing things, but it's so complex, and considers so many different things.. like motion prediction optimizing, event listeners, grid-based object-pointers, bounding-box trees. The question is whether you need any of that.

When you don't know what method to use, just go with whatever inspires you. You're probably not going to find entirely the right answer whatever you do, but it's the only way you're going to find out what that right answer is. If you get stuck, consider re-writing whatever it is that lead you to that dead end. In a sense, I'm saying it all depends on your game.

That said, I agree with the other posters that if you can, follow Unity's guidelines. Unity was built assuming that you use it to its full potential. You will always encounter brick walls if you don't (however climbable those walls might be :P).

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

Don't keep a list of enemies. Make your health script generic. So when bullet hits a gameobject tagged "enemy", you can call like:

if(hittedCollider.gameObject.tag == "enemy")
{
    hittedCollider.gameObject.GetComponent<HealthManager>().AddDamage(damageAmount);
}

(this is an example of course, names are up to your decision)

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

Put safe that in Unity the suggested/best way of managing collision is using Unity colliders.

Let's follow your aproach. As the max numbers of enemies and bullets you may have at the same time and the dimension of your map grows, you may consider managing your enemies and bullets not in single list but in a Geometric hashing structure. Here you find a didactic Spatial hashing implementation for fast 2D collisions and this also helped me for collision detection in love2d.

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

An interface contains definitions for a group of related functionalities that a class or a struct can implement.

By using interfaces, you can, for example, include behavior from multiple sources in a class. That capability is important in C# because the language doesn't support multiple inheritance of classes. In addition, you must use an interface if you want to simulate inheritance for structs, because they can't actually inherit from another struct or class.

For example these classes have Color Interface:

enter image description here

https://msdn.microsoft.com/en-us/library/ms173156.aspx

https://unity3d.com/learn/tutorials/topics/scripting/interfaces


First you should define interface.

using UnityEngine;
using System.Collections;

    public interface ITakeDamage<T>
    {
        void Damage(T damageTaken);
    }

this is Bullet script:

using UnityEngine;
    using System.Collections;
    
    public class Bullet : MonoBehaviour
    {
        public int amount = 10;
    
        void OnCollisionEnter(Collision other)
        {
            if (other.gameObject.tag == "Enemy")
            {
                other.gameObject.GetComponent<ITakeDamage<float>>().Damage(amount);
            }
        }
    }

by using interfaces you can have many object that they have ITakeDamage like car , player , etc.so you can have condition if object have ITakeDamage then decrease health value.

void OnCollisionEnter(Collision other)
{
    var TakeDamage = other.gameObject.GetComponent<ITakeDamage<float>>();
    if (TakeDamage != null)
    {
        TakeDamage.Damage(amount);
    }
}

implementing ITakeDamage interface in Enemy script

using UnityEngine;
using System.Collections;

public class Enemy : MonoBehaviour,ITakeDamage<float>
{
    public float health;
    public float Health { get { return health; }
    set {
        if (health > 0) {
            health = value;
        }else
        {
            Destroy(gameObject);
        }
     }
  }

    public void Damage(float damageTaken)
    {
        Health -= damageTaken;
    }
}
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I was under the impression methods needed to be declared as abstract, in an interface \$\endgroup\$ – Gnemlock Dec 4 '16 at 4:40
  • \$\begingroup\$ Also, I can see how this answers the question, because I am already familiar with how interfaces work. If you are not familiar, this answer seems a bit confusing. You've gone to good effort to show us how to use the interface; you should probably add a paragraph, at the top, noting how the asker could use interfaces in context of their problem. \$\endgroup\$ – Gnemlock Dec 4 '16 at 4:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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