废话就不多说了,直接进入今天的主题-事件在我们所接触到的事件一般分两种:
一种是自定义的,自定义的事件需要自己对其进行赋值。
一种是控件提供方定义的,如:ngui,控件事件只需要查找控件定义的事件列表,选择所需要的进行操作即可。
当然,我们的话题是上面第一种啦。
实例模拟场景为:
游戏战斗中,猪脚在指定的一片区域中,存在4只怪物,他的目的就是一只一只找到并消灭该区域的怪物。
简易流程:查询目标->行走->攻击,依次循环
ok,在此,我用代码快速模拟这样一个情景,建立一个Hero类,如下:
注:仅仅为了指导一个思想,真正战斗逻辑代码肯定不是这样的,好多东西我都直接文字描述代过了,毕竟今天主题不是这个。
好了,接下来绑定代码到任何对象,设置怪物个数
运行如下:
行了,上面代码虽然完成了所描述的功能,可是这样代码质量很差的,如果策划那天来些奇葩需求,如:我要人物可以飞着移动,我要攻击的时候打个降龙十八掌等等
那么,说不定第二天又有新闻某某公司程序通宵加班,猝死。。。
为了防止善变的策划,那我们在做东西的时候就得聪明一点了,那又应该如何来写呢?
先埋个伏笔,先来说说今天的主题事件
事件是什么?对代码 有什么用?又该如何使用?
让我们一起带着疑问往下走,
首先,我还是得先谈谈委托,委托事件委托事件,从字面意思就可看出委托是事件的基础,也有一种说法事件是特殊化的委托。
委托 :使用委托可以将方法应用(不是方法)封装在委托对象内,然后将委托对象传递给调用方法的代码,这样编译的时候代码就没有必要知道调用哪个方法。
通过使用委托程序能够在运行时动态的调用不同的方法。 具体实现见《【unity 代码升华篇】委托、事件全解析(一)》。
事件 :在此要分2个部分来说,暂叫它们为 事件发行者 、 事件接收者。 事件发行者 : 指对象自身状态信息发送变动时,就触发一个事件,并通知事件接收者发生了一个操作。
就如生活中我们常常面对的策划,某天突然找到你说 需求发生了改变 ,呵呵...苦逼的程序也只有呵呵面对了。(趁机黑下策划)
事件接收者 : 指接收到事件发行者的消息后,通常需要提供一个事件处理的方法,在事件发行者触发一个事件后,会自动执行这个方法。
这就是生活中程序要干的事情了..
以下为事件处理机制模型:
简单来讲:
就是说当一个结果发生时,有可能引起另外的一些反应,就好比佛家常说的因果关系,而事件,就是这个因果关系的内部联系。
在此还有个东西有必要提下,
Observer 设计模式,主要包括如下两类对象
1.Subject:监视对象,它往往包含着其他对象所感兴趣的内容。 在本范例中,角色的目标就是一个监视对象,它包含的其他对象所感兴趣的内容,就是Targetid字段,当这个字段的值变为0时,会把数据发给监视它的对象。
2. Observer:监视者,它监视Subject,当Subject 中的某件事发生的时候,会告知Observer,而Observer 则会采取相应的行动。
在本范例中,Observer 有查询和行走,它们采取的行动分别是查询目标和向目标移动。
好了,事件基本含义了解了,下面通过5个步骤用代码实例进行一次深入探讨:
1.声明事件(定义事件).
2.注册事件 .
3.实现事件.
4.触发事件.
5.为事件增加“添加/删除”方法.
一、声明事件(定义事件)
首先,要建立委托,格式为:
public delegate void 委托名(object sender, EventArgs e);
1.对象:sender
2.参数:
object sender: 指触发对象(如:Button).
EventArgs e :则为引发这个事件的原因,包含了Observer 所感兴趣的数据,在本例中是Targetid.
委托名一般格式是:名字+EnvenHandle。这样取名比较规范。
如下:
然后,建立一个事件字段:
public event 委托类型 事件名;
注意:event关键字代表事件,返回类型为委托
如:
//===================
//用event关键字声明事件对象
public event TestEnvenHandle testEvent;
//===================
再定义一个方法,处理事件,再本例中为OnTargetChange (EventArgs e),
使用virtual 的方法供内部的代码调用,接收一个testEventArgs 对象,这个对象包含要传递给消息接收方的一些信息
最后还要创建触发事件的方法。例子中为selectTarget(),在其方法中,当条件满足则调用OnTargetChange 来达到触发事件的目的。
再使用事件时,通常要定义两个方法,一个是和事件定义的委托签名一致的方法,
在本例中分为,朝目标行走
攻击目标
绑定事件的方法很简单,用+=表示添加事件,-=表示删除事件。
运行修改后的代码:
ok,完全没问题,修改后的代码我就不贴出来了,我放百度云需要的大家自己去下载哈
后面总结得有些乱,附上源码 大家可以对照看,都有详细注释,方便大家更容易理解。
通过使用事件方式,代码真变得整洁很多,方便管理 而且可扩展性超强哟,希望大家看后也能在代码方面有更好的提升,
欢迎吐槽,欢迎点赞...谢谢大家
好了,今天就先讲到这里啦,累死了
下面是完整代码下载地址:http://pan.baidu.com/s/1i3FZHMt
一种是自定义的,自定义的事件需要自己对其进行赋值。
一种是控件提供方定义的,如:ngui,控件事件只需要查找控件定义的事件列表,选择所需要的进行操作即可。
当然,我们的话题是上面第一种啦。
实例模拟场景为:
游戏战斗中,猪脚在指定的一片区域中,存在4只怪物,他的目的就是一只一只找到并消灭该区域的怪物。
简易流程:查询目标->行走->攻击,依次循环
ok,在此,我用代码快速模拟这样一个情景,建立一个Hero类,如下:
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
using
UnityEngine;
using
System.Collections;
using
System.Collections.Generic;
using
System;
// 英雄角色
public
class
Hero : MonoBehaviour
{
//当前目标id
public
int
TargetID=0;
public
List<
int
> ListMonster;
void
Start()
{
InvokeRepeating(
"selectTarget"
, 0.3f, 0.3f);
}
// 查询目标
private
void
selectTarget()
{
if
(TargetID==0)
{
if
(ListMonster.Count > 0)
{
for
(
int
i = 0; i <= ListMonster.Count; i++)
{
TargetID = ListMonster[i];[/i]
WalkToTarget(TargetID);
Atk(TargetID,i);
break
;
}
}
else
{
Debug.Log(
"恭喜随风去旅行为名除害成功,获得荣誉称号“为民除害”"
);
CancelInvoke(
"selectTarget"
);
}
}
}
private
void
WalkToTarget(
int
id)
{
Debug.Log(String.Format(
"朝目标{0} 移动,幸运触发了缩地成寸,到达攻击区域内..:"
, id));
}
private
void
Atk(
int
id,
int
itemNum)
{
Debug.Log(String.Format(
"向目标{0}发动猛烈的攻击,幸运触发一击必杀,成功杀死了目标{1}:"
, id,id));
ListMonster.RemoveAt(itemNum);
TargetID = 0;
}
}
|
注:仅仅为了指导一个思想,真正战斗逻辑代码肯定不是这样的,好多东西我都直接文字描述代过了,毕竟今天主题不是这个。
好了,接下来绑定代码到任何对象,设置怪物个数
运行如下:
行了,上面代码虽然完成了所描述的功能,可是这样代码质量很差的,如果策划那天来些奇葩需求,如:我要人物可以飞着移动,我要攻击的时候打个降龙十八掌等等
那么,说不定第二天又有新闻某某公司程序通宵加班,猝死。。。
为了防止善变的策划,那我们在做东西的时候就得聪明一点了,那又应该如何来写呢?
先埋个伏笔,先来说说今天的主题事件
事件是什么?对代码 有什么用?又该如何使用?
让我们一起带着疑问往下走,
首先,我还是得先谈谈委托,委托事件委托事件,从字面意思就可看出委托是事件的基础,也有一种说法事件是特殊化的委托。
委托 :使用委托可以将方法应用(不是方法)封装在委托对象内,然后将委托对象传递给调用方法的代码,这样编译的时候代码就没有必要知道调用哪个方法。
通过使用委托程序能够在运行时动态的调用不同的方法。 具体实现见《【unity 代码升华篇】委托、事件全解析(一)》。
事件 :在此要分2个部分来说,暂叫它们为 事件发行者 、 事件接收者。 事件发行者 : 指对象自身状态信息发送变动时,就触发一个事件,并通知事件接收者发生了一个操作。
就如生活中我们常常面对的策划,某天突然找到你说 需求发生了改变 ,呵呵...苦逼的程序也只有呵呵面对了。(趁机黑下策划)
事件接收者 : 指接收到事件发行者的消息后,通常需要提供一个事件处理的方法,在事件发行者触发一个事件后,会自动执行这个方法。
这就是生活中程序要干的事情了..
以下为事件处理机制模型:
简单来讲:
就是说当一个结果发生时,有可能引起另外的一些反应,就好比佛家常说的因果关系,而事件,就是这个因果关系的内部联系。
在此还有个东西有必要提下,
Observer 设计模式,主要包括如下两类对象
1.Subject:监视对象,它往往包含着其他对象所感兴趣的内容。 在本范例中,角色的目标就是一个监视对象,它包含的其他对象所感兴趣的内容,就是Targetid字段,当这个字段的值变为0时,会把数据发给监视它的对象。
2. Observer:监视者,它监视Subject,当Subject 中的某件事发生的时候,会告知Observer,而Observer 则会采取相应的行动。
在本范例中,Observer 有查询和行走,它们采取的行动分别是查询目标和向目标移动。
好了,事件基本含义了解了,下面通过5个步骤用代码实例进行一次深入探讨:
1.声明事件(定义事件).
2.注册事件 .
3.实现事件.
4.触发事件.
5.为事件增加“添加/删除”方法.
一、声明事件(定义事件)
首先,要建立委托,格式为:
public delegate void 委托名(object sender, EventArgs e);
1.对象:sender
2.参数:
object sender: 指触发对象(如:Button).
EventArgs e :则为引发这个事件的原因,包含了Observer 所感兴趣的数据,在本例中是Targetid.
委托名一般格式是:名字+EnvenHandle。这样取名比较规范。
如下:
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
|
//定义委托,它定义了可以代表的方法的类型
public
delegate
void
TestEnvenHandle(
object
sender, testEventArgs e);
/// <summary>
/// 定义testEventArgs 类,传递给Observer 所感兴趣的信息
/// </summary>
public
class
testEventArgs : EventArgs
{
public
readonly
int
TargetID;
public
testEventArgs(
int
_TargetID)
{
this
.TargetID = _TargetID;
}
}
|
然后,建立一个事件字段:
public event 委托类型 事件名;
注意:event关键字代表事件,返回类型为委托
如:
//===================
//用event关键字声明事件对象
public event TestEnvenHandle testEvent;
//===================
再定义一个方法,处理事件,再本例中为OnTargetChange (EventArgs e),
使用virtual 的方法供内部的代码调用,接收一个testEventArgs 对象,这个对象包含要传递给消息接收方的一些信息
[C#]
纯文本查看
复制代码
1
2
3
4
5
6
7
8
9
|
// 可以供继承自 Hero 的类重写,以便继承类拒绝其他对象对它的监视
protected
virtual
void
OnTargetChange(testEventArgs e)
{
//任何注册到事件的方法,通知它们
if
(testEvent !=
null
)
{
testEvent(
this
, e);
// 调用所有注册对象的方法
}
}
|
最后还要创建触发事件的方法。例子中为selectTarget(),在其方法中,当条件满足则调用OnTargetChange 来达到触发事件的目的。
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
|
// 查询目标
public
void
selectTarget()
{
for
(
int
i = 0; i <= Caching.ListMonster.Count; i++)
{
Caching.itemNum = i;
//建立testEventArgs 对象。
testEventArgs e =
new
testEventArgs(Caching.ListMonster);
// 调用 OnTargetChange 方法
OnTargetChange(e);
break
;
}
}
|
再使用事件时,通常要定义两个方法,一个是和事件定义的委托签名一致的方法,
在本例中分为,朝目标行走
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
|
// <summary>
/// 普通行走
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public
static
void
WalkToTarget(System.Object sender, Select.testEventArgs e)
{
//访问 sender 中的公共字段
Debug.Log(System.String.Format(
"朝目标{0} 移动,幸运触发了缩地成寸,到达攻击区域内..:"
, e.TargetID));
}
|
攻击目标
[C#]
纯文本查看
复制代码
1
2
3
4
5
6
|
//一击必杀
public
void
AtkToTarget(System.Object sender, Select.testEventArgs e)
{
Debug.Log(System.String.Format(
"向目标{0}发动猛烈的攻击,幸运触发一击必杀,成功杀死了目标{1}:"
,e.TargetID, e.TargetID));
Caching.ListMonster.RemoveAt(Caching.itemNum);
}
|
绑定事件的方法很简单,用+=表示添加事件,-=表示删除事件。
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
|
private
Select _hero =
new
Select();
private
Atk _atk =
new
Atk();
void
Awake()
{
//注册静态方法
_hero.testEvent += Walk.WalkToTarget;
//注册方法
// _hero.testEvent += _atk.AtkToTarget;
//_hero.testEvent -= (new Atk()).AtkToTarget; //删除事件
_hero.testEvent +=
new
Select.TestEnvenHandle(_atk.AtkToTarget);
//也可以这么注册
}
|
运行修改后的代码:
ok,完全没问题,修改后的代码我就不贴出来了,我放百度云需要的大家自己去下载哈
后面总结得有些乱,附上源码 大家可以对照看,都有详细注释,方便大家更容易理解。
通过使用事件方式,代码真变得整洁很多,方便管理 而且可扩展性超强哟,希望大家看后也能在代码方面有更好的提升,
欢迎吐槽,欢迎点赞...谢谢大家
好了,今天就先讲到这里啦,累死了
下面是完整代码下载地址:http://pan.baidu.com/s/1i3FZHMt
明天,委托进阶
文章转载自【unity 代码升华篇】委托、事件全解析(二),感谢ζއ随风去旅行提供好文章