В Unity, какой тип метода Update()? А как сделать свой?

Откуда игровые объекты узнают, что void Update означает каждый кадр, а OnCollisionEnter — когда они сталкиваются. Могу ли я сделать свой собственный? вроде этого

void OnPositionChange () {
 //code goes here
}

И тогда любой скрипт, у которого есть это OnPositionChange, распознает его и что-то с ним сделает, когда позиция изменится.


person messedupsongguy    schedule 05.12.2015    source источник


Ответы (3)


Встроенный компонент SendMessage: http://docs.unity3d.com/ScriptReference/Component.SendMessage.html

Думаю, это может вам кое-что помочь: http://answers.unity3d.com/questions/676625/creating-my-own-custom-unity-messages.html

Здесь предлагается создать базовый класс, из которого будут расширяться все объекты, которым потребуется метод. В примере он использовал источник урона и повреждаемые объекты и пример того, как они будут взаимодействовать:

В DamageSource.cs (класс, который вы бы использовали для нанесения урона)

using UnityEngine;
 using System.Collections;

 public class DamageSource : MonoBehaviour {
     protected float damageAmount = 10f;

     //not 100% necessary, but handy for an example of how to 
     //handle damage based on the attacker (which is 
     //relevant for info sent in the OnTakeDamage() method
     protected ElementType elementType = ElementType.Normal;

     //we use a function for getting the damage this 
     //DamageSource can do because it lets us overwrite it.
     //Eg, if the enemy is weakened, you can factor that 
     //in and return a lesser amount of damage.
     public float GetDamageAmount() {
         return damageAmount;
     }

     public ElementType GetElementType() {
         return elementType;
     }
 }

 //kinds of elements available for damage / resistance calculations
 public enum ElementType {
     Normal,
     Fire,
     Ice,
     Lightning
 }

В DamageableObject.cs (базовый класс, от которого наследуются все повреждаемые объекты):

using UnityEngine;
 using System.Collections;

 public class DamageableObject : MonoBehaviour {
     protected bool wasRecentlyHit;
     protected float health;
     protected float maxHealth;

     public void Awake() {
         health = maxHealth;
     }

     //Creating a virtual void method lets you choose whether 
     //or not you want to set it in a derived class.
     //Here, we track the amount of damage and the source 
     //the damage came from. This can sometimes be handy for 
     //context-sensitive reactions to being damaged. Eg, play 
     //a particular sound in damaging the player, when 
     //successfully damaged by a particular attack.
     //Note that this base implementation does nothing - you 
     //override it in an inheriting class, very similar to using Update() etc.
     protected virtual void OnTakeDamage(float damageAmount, DamageSource damageSource) {}
     //An example of how you'd check whether damage is incoming. 
     //You can alternatively just call 
     //someDamageableObject.TryDoDamage() from another script.
     public void OnTriggerEnter(Collider other) {
         DamageSource damageGiver = other.GetComponent<DamageSource>();
         if (damageGiver) {
             TryDoDamage(damageGiver.GetDamageAmount(),damageGiver.gameObject);
         }
     }
     public void TryDoDamage(float damageAmount, GameObject damageGiver) {
         //early out, this DamageableObject was damaged a very 
         //short time ago and shouldn't be damaged again so soon
         if (wasRecentlyHit) return;

         //optionally perform any damage calculations here based
         //on the damageGiver, eg more damage from the player 
         //being weakened somehow, or less damage from type 
         //resistances... etc.
         damageAmount = CalculateDamage(damageAmount,damageGiver);

         //if after our damage calculations we still have an 
         //amount of damage greater than 0, we do the damage and 
         //send the OnTakeDamage() message.
         if (damageAmount>0f) {
             health -= damageAmount;

             //optional handling of dying (uncomment this and the OnDeath() function to enable)
             //if (health<0f) {
             //    OnDeath(damageAmount,damageGiver);
             //}
             //else {
             OnTakeDamage(damageAmount,damageGiver);
             //}
         }
     }

     //Uncomment this and the (healtn<0f) if statement above 
     //if you want to handle dying as well as being damaged
     //protected virtual void OnDeath(float damageAmount, DamageSource damageSource);

     //Default implementation for calculating damage, 
     //given some amount of damage, and some source of damage.
     //Override this in an inheriting class if you want to do 
     //different damage, eg based on the damage source (2x 
     //damage from fire attacks, 0.5x damage from ice 
     //attacks... etc) or based on the DamageableObject's 
     //current state (eg, player is weakened, so takes 1.5x damage)
     protected float CalculateDamage(float damageAmount, DamageSource damageSource) {
         return damageAmount;
     }
 }

В PlayerDamageReceiver.cs:

using UnityEngine;
 using System.Collections;

 public class PlayerDamageReceiver : DamageableObject {

     //override the OnTakeDamage() method to make a 
     //different implementation of it for this class
     protected override void OnTakeDamage(float damageAmount, DamageSource damageSource) {
         Debug.Log("Ouch, the player was damaged!");
     }

     //Uncomment this to override the OnDeath() function 
     //in DamageableObject (if you've uncommented that, that is)
     //protected override void OnDeath(float damageAmount, DamageSource damageSource) {
     //    Debug.Log("Uhoh... The player died. :(");
     //}

     //override the CalculateDamage() function to 
     //determine how damage applies to the player
     protected override float CalculateDamage(float damageAmount, DamageSource damageSource) {
         //Example: give the player a 2x weakness to fire damage, and immunity to ice damage
         switch (damageSource.GetElementType()) {
             case (ElementType.Fire):
                 damageAmount *= 2f;
                 break;
             case (ElementType.Ice):
                 damageAmount = 0f;
                 break;
         }
         return damageAmount;
     }
 }

(Я скопировал и вставил код от пользователя "nesis" сюда, как попросил товарищ в комментариях)

person ゴスエン ヘンリ    schedule 05.12.2015
comment
Для потомков, не могли бы вы включить в свой ответ соответствующие части ссылки, которые, по вашему мнению, полезны? Таким образом, если ссылка не работает, изменяется и т. д., ваш ответ не станет бесполезным. Большое спасибо. - person Wai Ha Lee; 05.12.2015

На самом деле вы можете это сделать. Просто вы можете создать свой собственный класс Behavior.

public class MyBehavior : MonoBehaviour {

    Vector3 lastPosition = new Vector3();

    void Update () {
        Vector3 position = new Vector3();
        if (position != lastPosition)
        {
            OnPositionChange();
            lastPosition = position;
        }
        else
        {
            lastPosition = position;
        }
    }

    public virtual void OnPositionChange(){}
}

Теперь вы определяете свой скрипт, который напрямую наследует MyBehavior вместо MonoBehavior.

public class test : MyBehavior {

    public override void OnPositionChange()
    {
        Debug.Log("override");
    }

}

Это самое близкое к тому, что вы просили, я верю.

person ali.turan    schedule 05.12.2015

Update(), Start() и другие методы с подобными специальными функциями относятся к overloads из класса MonoBehaviour. Вы можете видеть, что все ваши скрипты являются производными от класса MonoBehaviour.

Вам нужно использовать Events. Вы можете создать event и delegate, а в особой ситуации raise их, чтобы все ваши сценарии, зарегистрированные в этом событии, могли вызывать свой собственный метод для этого события.

person Hossein Rashno    schedule 06.12.2015