欢迎来到unity学习、unity培训、unity企业培训教育专区,这里有很多U3D资源、U3D培训视频、U3D教程、U3D常见问题、U3D项目源码,【狗刨学习网】unity极致学院,致力于打造业内unity3d培训、学习第一品牌。 我们了解了2D中的Sprite,Animation,RigidBody和Collider,在继续开发游戏的过程中,我们会遇到这样的问题,如何处理GameObject之间的相互调用,比如说在FlappyBird中我们在小鸟撞倒管子的时候,要把这个消息通知给许多GameObject,管子接到这个消息之后需要停止运动,UI接到这个消息要弹出GameOver的字样。接下来,我来讲一下如何合理地解决这个问题。相关源码参考:Flappy Bird的源码。 为什么要进行GameObject之间的通讯? 在游戏开发中我们经常遇到这样的问题,在游戏中发生了一个事件(event),我们如何把这个时间通知给其他GameObject:比如游戏中发生了爆炸,我们需要在一定范围内的GameObject都感知到这一事件。有的时候,我们希望摄像机以外的物体不要接到我们这一事件的通知。游戏中丰富多彩的世界正是由通信机制构成的。 有一种方法是在发生事件的GameObject的Start方法里面把对该事件感兴趣的所有GameObject当作成员变量保存在脚本组件里,那么我们把发生事件的object当作Subject,把对该事件感兴趣的object当作Observer。 将Observer作为成员变量存储在Subject中有一下缺点: 难以变更,一旦要新增一个Observer就需要更改Subject中的代码 如果Observer被销毁了,无法从Subject中移除掉这个成员变量,会发生NullReferernceException。 在发生事件时,一个个去invoke不同Observer中的相应handle方法的代码变得冗长繁杂。 还好的是,我们可以通过引入观察者模式来解决这个问题,更好的是,C#内置有一个非常棒的事件/委托机制,能让我们非常方便地进行观察者模式的构建。 如果你还不了解观察者模式和事件/委托机制,可以参考以下几篇文章: C# 中的委托和事件 -- 委托/事件入门 C#综合揭秘深入分析委托与事件 -- 委托/事件深入 你可能不知道的陷阱:C#委托和事件的困惑 -- 委托/事件陷阱 C#中标准的委托类型 我们在构建事件/委托机制的时候,首先要定义委托类型,参考在Cocos2d-x中的CCCallback,我先定义了以下三种类型的委托: // 该委托不传任何参数 public delegate void CallFunc(); // 该委托会传入发生事件的GameObject,即sender public delegate void CallFuncO(GameObject sender); // 该委托会传入发生事件的GameObject,即sender。和一个变长参数列表 public delegate void CallFuncOP(GameObject sender, EventArgs args); 但是我发现C#本身已经提供了一种比较好的委托类型:EventHandler,所以我就把游戏中的委托都替换成了这种委托。 public delegate void EventHandler(object sender, EventArgs e); 另一种更好的委托方式是使用泛型参数的委托类型:EventHandlerTEventArgs,其签名如下: public delegate void EventHandlerTEventArgs( Object sender, TEventArgs e ) 采用 EventHandler 模式发布事件 如果这个事件不产生任何额外参数(即除了事件的发送者之外),则在在调用时,向EventHandler的第二个参数传一个EventArgs.Empty即可。 如果产生额外参数,第二个参数是从 EventArgs 派生的类型并提供所有字段或属性需要保存事件数据。使用 EventHandlerTEventArgs 的优点在于,如果事件生成事件数据,则无需编写自己的自定义委托代码。 下面我们举一个例子来证实EventHandler的用法: using System; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Counter c = new Counter(new Random().Next()); //向该事件添加了一个委托函数 c.ThresholdReached = c_ThresholdReached; Console.WriteLine("press 'a' key to increase total"); while (Console.ReadKey(true).KeyChar == 'a') { Console.WriteLine("adding one"); c.Add(1); } } static void c_ThresholdReached(object sender, ThresholdReachedEventArgs e) { Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold, e.TimeReached); Environment.Exit(0); } } class Counter { private int threshold; private int total; public Counter(int passedThreshold) { threshold = passedThreshold; } public void Add(int x) { total = x; if (total = threshold) { ThresholdReachedEventArgs args = new ThresholdReachedEventArgs(); args.Threshold = threshold; args.TimeReached = DateTime.Now; OnThresholdReached(args); } } protected virtual void OnThresholdReached(ThresholdReachedEventArgs e) { EventHandlerThresholdReachedEventArgs handler = ThresholdReached; if (handler != null) { handler(this, e); } } //添加了一个带泛型参数的事件 public event EventHandlerThresholdReachedEventArgs ThresholdReached; } public class ThresholdReachedEventArgs : EventArgs { public int Threshold { get; set; } public DateTime TimeReached { get; set; } } } 在游戏中的应用 我们通过一个小鸟撞倒管子来作为事例说明如何进行通信: 在这个情景下,我们首先为小鸟设定两个事件(event),分别是分数加一(ScoreAdd)和小鸟碰到管子游戏结束(GameOver) 如下: using UnityEngine; using System.Collections; using System; public class BirdController : MonoBehaviour { public event EventHandler GameOver; public event EventHandler ScoreAdd; //当离开Empty Trigger的时候,分发ScoreAdd事件 void OnTriggerExit2D(Collider2D col) { if (col.gameObject.name.Equals("empty")) { if (ScoreAdd != null) ScoreAdd(this, EventArgs.Empty); } } //当开始碰撞的时候,分发GameOver事件 void OnCollisionEnter2D(Collision2D col) { rigidbody2D.velocity = new Vector2(0, 0); if (GameOver != null) GameOver(this, EventArgs.Empty); this.enabled = false; } } 然后在对这个事件感兴趣的GameObject会通过相应的Handler对该事件进行监听,这样就可以进行一对多的GameObject间的通信了。 using UnityEngine; using System.Collections; using System; public class TubeController : MonoBehaviour { // Use this for initialization void Start () { GameObject.Find("bird").GetComponentBirdController().GameOver = OnGameOver; } void OnDestroy() { if ( GameObject.Find("bird") ) GameObject.Find("bird").GetComponentBirdController().GameOver -= OnGameOver; } void OnGameOver(object sender, EventArgs e) { rigidbody2D.velocity = new Vector2(0, 0); } }更多内容,请访问【狗刨学习网】unity极致学院 声明:此篇文档时来自于【狗刨学习网】社区-unity极致学院,是网友自行发布的Unity3D学习文章,如果有什么内容侵犯了你的相关权益,请与官方沟通,我们会即时处理。
推荐整理分享事件委托机制实现GameObject之间的通信(事件委托实现),希望有所帮助,仅作参考,欢迎阅读内容。
文章相关热门搜索词:事件委托的原理以及优缺点,事件委托的实现思路,事件委托实现,事件委托jq,事件委托jq,事件委托机制将事件绑定到哪,事件委托机制的原理,事件委托机制实例,内容如对您有帮助,希望把文章链接给更多的朋友!
Unity AssetBundle爬坑手记 欢迎来到unity学习、unity培训、unity企业培训教育专区,这里有很多U3D资源、U3D培训视频、U3D教程、U3D常见问题、U3D项目源码,【狗刨学习网】unity极致学
Unity3D 事件 欢迎来到unity学习、unity培训、unity企业培训教育专区,这里有很多U3D资源、U3D培训视频、U3D教程、U3D常见问题、U3D项目源码,【狗刨学习网】unity极致学
unity动态加载之AssetBundle原理 Assetbundle是UnityPro提供提供的功能,它可以把多个游戏对象或者资源二进制文件封装到Assetbundle中,提供了封装与解包的方法使用起来很便利。1.预设Assetb