Nebula2探秘10-Signal System
happykevins文
使用Nebula2信号系统的目的:
Nebula2的信号系统主要功能是对象间的消息传递。
由于消息的发出者和接收者是在运行时动态邦定的,所以用这种方式传递消息并不会增加程序的耦合度。
另外Nebula2还提供了一个SignalServer用于实现延时消息。
Nebula2信号系统主要包含以下几个类:
nSignal:
继承自nCmdProto类,用于标识一个信号,并描述信号回调函数的原形
nSignalRegistry:
包含多个nSignal的集合;nClass继承自此类;因此可以推测出信号是与类
邦定的,要使Nebula类型支持产生信号,我们首先要向该类注册信号
nSignalBinding:
封装了信号接收者及其回调函数,用于向信号发出者注册
nSignalBindingSet:
包含多个nSignalBinding的集合
nSignalEmitter:
信号发生器,nObject继承自此类;因此所有的Nebula对象都支持发出信号
的功能,前提是你注册了信号
nSignalServer:
这其实是独立于信号系统的一个附加功能,主要是实现了相应延时信号
Nebula2信号系统的使用方法:
Nebula2的信号系统支持Native代码和脚本两种途径的传递,下面简单介绍通过脚本途径的使用。
首先需要实现一个用于产生信号的Emtter类,Emitter就是一个普通的继承自nObject的Nebula2类型,只是在初始化命令的函数中添加了信号(nSignal)。
然后我们需要实现一个Receiver类,Receiver类也是一个继承自nObject的普通Nebula2脚本类,可以将Receiver的脚本指令向Emitter中感兴趣的信号注册,这样在Emitter产生信号时就会向注册的Receiver广播消息了;需要注意的是在Receiver向Emitter注册时需要保证Receiver的回调函数与Emitter的信号的函数原形保持一致。
Nebula2引擎的Bug:
需要改正一个Nebula2的Bug,在nargs.h的第276行加上代码:
this->type = Type::String;
原来的代码由于缺少这句话,在nArgs从va_list复制String类型参数时会丢失类型信息,所以在信号传递过程中如果使用String类型参数的话Nebula2就会出错。
下面是Emitter的代码:
/*Nebula2-Tutorial10*/
/*Nebula2SignalSystem*/
/*author:happykevins*/
/****************************************************************************/
///Emitter.h
#pragmaonce
#include"kernel/nroot.h"
#include"signals/nsignal.h"
classEmitter:publicnRoot
{
///@note
///为了支持信号系统,在类的实现中不需要添加任何代码
///只需在Emitter对应的nClass中注册信号即可
///注册信号的工作一般在初始化脚本指令的函数(n_initcmds)中完成
};
///Emitter.cpp
#include"Emitter.h"
#include"kernel/nkernelserver.h"
#include"../NebulaUtils/nutildefs.h"
nNebulaScriptModule(Emitter,emitter,"nroot");
voidnNebulaScriptInitCmds(emitter)(nClass*cls)
{
///在这里添加信号
///注册信号始需要指出信号对应回调函数的原形以及信号的ID
cls->BeginSignals(1);
cls->AddSignal("v_sig1_s",'SIG1');
cls->EndSignals();
}
下面是Receiver的代码:
/*Nebula2-Tutorial10*/
/*Nebula2SignalSystem*/
/*author:happykevins*/
/****************************************************************************/
///Receiver.h
#pragmaonce
#include"kernel/nroot.h"
classReceiver:publicnRoot
{
public:
voidPrint(constchar*str)
{
n_printf("%s ",str);
}
};
///Receiver.cpp
#include"Receiver.h"
#include"kernel/nkernelserver.h"
#include"../NebulaUtils/nutildefs.h"
nNebulaScriptModule(Receiver,receiver,"nroot");
staticvoidn_print(void*o,nCmd*cmd);
voidnNebulaScriptInitCmds(receiver)(nClass*cl)
{
///为Emitter的回调添加脚本函数
///信号系统也是通过脚本函数来传递消息
///脚本函数的需要与Emitter对应的信号保持一致
cl->BeginCmds();
cl->AddCmd("v_print_s",'PRNT',n_print);
cl->EndCmds();
}
staticvoidn_print(void*o,nCmd*cmd)
{
Receiver*slf=(Receiver*)o;
slf->Print(cmd->In()->GetS());
}
下面是使用信号系统的范例代码:
/*Nebula2-Tutorial10*/
/*Nebula2SignalSystem*/
/*author:happykevins*/
/****************************************************************************/
///----------------------------------------------------------------------------
///+必要头文件
//nebula2includes
#include"kernel/nkernelserver.h"
#include"kernel/ntimeserver.h"
#include"signals/nsignalserver.h"
#include"../NebulaUtils/nutildefs.h"
#include"Emitter.h"
#include"Receiver.h"
///-必要头文件
///----------------------------------------------------------------------------
///----------------------------------------------------------------------------
///+声明使用的Nebula2Package&Module
nNebulaUseModule(emitter);
nNebulaUseModule(receiver);
///-声明使用的Nebula2Package&Module
///----------------------------------------------------------------------------
///----------------------------------------------------------------------------
///+Application
intmain(intargc,constchar**argv)
{
///创建KernelServer
nKernelServer*ks=n_new(nKernelServer);
nNebulaAddModule(emitter);
nNebulaAddModule(receiver);
///创建SignalServer
nSignalServer*signals=(nSignalServer*)ks->New("nsignalserver","/sys/servers/signals");
///创建信号发生器
Emitter*emit=(Emitter*)ks->New("emitter","/usr/signals/emitter");
///创建信号接收器
Receiver*rec=(Receiver*)ks->New("receiver","/usr/signals/receiver");
///将信号接收器邦定到信号发生器指定的信号
emit->BindSignal('SIG1',rec,'PRNT',0,true);
///发出立即信号
emit->EmitSignal('SIG1',"EmitSignalSynchronized!");
///发出延迟信号(5秒后执行)
emit->PostSignal(5.0f,'SIG1',"EmitSignalAsynchronized!");
n_printf("*****WaitAsynchronizedSignal***** ");
///等待延迟信号
doubletime=0;
while(time<=8.0f)
{
signals->Trigger(nTimeServer::Instance()->GetFrameTime());
n_sleep(0.2f);
time+=0.2f;
}
n_printf("*****PressAnyKey!***** ");
///销毁KernelServer
n_delete(ks);
getchar();
return0;
}
///-Application
///----------------------------------------------------------------------------
<The End>