Nebula2探秘13-输入管理器nInputServer

2007-04-28     推荐:4104004    收藏:2655528    评论:0     来源:e800开发者频道

Nebula2探秘13-输入管理器nInputServer

happykevins文

本节将介绍如何创建和使用nInputServer来检测输入设备的状态及事件。
在创建InputServer之前首先要创建一个Windows窗口,这项工作我们已经在第11节中完成。您可能会注意到本节的代码结构与第11节非常相似,只是多出了创建nInputServer的代码和一个DumpInput函数(用来检测用户输入,并将结果输出到控制台)。

与创建其他Server一样,只需要在KernelServer中将它new出来然后Open一下即可;但是目前的Nebula2版本并没有提供对应的Close函数,所以用户并不需要为销毁InputServer做什么,下面是创建inputserver及建立事件映射的代码:

/// 创建nInputServer
nInputServer* input = (nInputServer*)ks->New(ndi8server, /sys/servers/input);
input
->Open();

///----------------------------------------------------------------------------
/// +添加按键映射
/// @ 1. 可以在脚本中配置
/// @ 2. 可以通过设备的映射名来索取设备并检测设备状态
/// @ 3. 可以将脚本函数与设备直接帮定,这样在设备产生事件时会自动调用相关函数
input->BeginMap();
input
->Map(keyb0:space.down, reset);
input
->Map(relmouse0:btn0.pressed, look);
input
->Map(relmouse0:+x, right);
input
->EndMap();
/// -添加按键映射
///----------------------------------------------------------------------------

nInputServer提供了一下3种处理设备事件的方式:
1.传统的遍历消息列表并转发或处理的模式。
2.由用户逻辑轮训事件。
3.由InputServer主动出发用户感兴趣的事件。
其中第2、3种的使用方式基本一样,只不过2是用户为事件起一个别名,而3是用户直接把脚本函数注册到事件上而已。
下面的函数DumpInput展示了如何使用第1种方式遍历并处理事件列表:

///----------------------------------------------------------------------------
/// +输入测试
///
void DumpInput()
{
/// 遍历事件列表,并将事件详细信息分类输出到控制台
for(nInputEvent* inputEvent = nInputServer::Instance()->FirstEvent();
inputEvent
!= NULL;
inputEvent
= nInputServer::Instance()->NextEvent(inputEvent))
{
/// 根据事件的DeviceID区分设备
switch(inputEvent->GetDeviceId())
{
case N_INPUT_MOUSE(0):
printf(
MouseEvent Detected! [BTN:%i] , inputEvent->GetButton());
switch(inputEvent->GetType())
{
case N_INPUT_MOUSE_MOVE:
printf(
[MouseMove]);
break;

case N_INPUT_BUTTON_DOWN:
printf(
[ButtonDown]);
break;

case N_INPUT_BUTTON_UP:
printf(
[ButtonUp]);
break;
}
break;
case N_INPUT_KEYBOARD(0):
printf(
KeyEvent Detected! [KEY:%i] , inputEvent->GetKey());
switch(inputEvent->GetType())
{
case N_INPUT_KEY_DOWN:
printf(
[KeyDown]);
break;

case N_INPUT_KEY_UP:
printf(
[KeyUp]);
break;

case N_INPUT_KEY_CHAR:
printf(
[CharEvent]);
break;
}
break;
}
printf(
);
}
}
///
/// -输入测试
///----------------------------------------------------------------------------

另外在游戏主循环每一帧结束的位置都要调用nInputServer::FlushEvents()方法以确保事件列表被清除,否则即使已经被处理过的事件也会一直保留在列表中。

下面是完整的程序代码:

/****************************************************************************/
/* Nebula2 - Tutorial 13 */
/* Input Server */
/* author: happykevins */
/****************************************************************************/

/**
简介:
本节将介绍如何创建和使用nInputServer来检测输入设备的状态及事件。
在创建InputServer之前首先要创建一个Windows窗口,这项工作我们已经在第11节中完成。
您可能会注意到本节的代码结构与第11节非常相似,只是多出了创建nInputServer的代码
和一个DumpInput函数(用来检测用户输入,并将结果输出到控制台)。

创建:
与创建其他Server一样,只需要在KernelServer中将它new出来然后Open一下即可;但是
目前的Nebula2版本并没有提供对应的Close函数,所以用户并不需要为销毁InputServer做什么。

使用:
InputServer提供了一下3种处理设备事件的方式:
1.传统的遍历消息列表并转发或处理的模式。
2.由用户逻辑轮训事件。
3.由InputServer主动出发用户感兴趣的事件。
其中第2、3种的使用方式基本一样,只不过2是用户为事件起一个别名,而3是用户直接把脚本
函数注册到事件上而已。
*/

///----------------------------------------------------------------------------
/// +必要头文件

// nebula2 includes
#include kernel/nkernelserver.h
#include
kernel/nfileserver2.h
#include
input/ninputserver.h
#include
gfx2/nd3d9server.h

// Tutorial工具库:一些通用的宏定义
#include ../NebulaUtils/nutildefs.h

/// -必要头文件
///----------------------------------------------------------------------------

///----------------------------------------------------------------------------
/// +链接库

#pragma comment(lib, ”wsock32.lib”)

#pragma comment(lib, ”dxguid.lib”)
#pragma comment(lib, ”dxerr9.lib”)
#pragma comment(lib, ”d3d9.lib”)
#pragma comment(lib, ”d3dx9d.lib”)
#pragma comment(lib, ”dinput8.lib”)

#pragma comment(lib, ”d_nkernel.lib”)
#pragma comment(lib, ”d_nnebula.lib”)
#pragma comment(lib, ”d_ndirect3d9.lib”)
#pragma comment(lib, ”d_ndinput8.lib”)

/// -链接库
///----------------------------------------------------------------------------

///----------------------------------------------------------------------------
/// +声明使用的Nebula2 Package&Module
nNebulaUseModule(nresource);
nNebulaUseModule(nresourceserver);
nNebulaUseModule(nfont2);
nNebulaUseModule(nmesh2);
nNebulaUseModule(nmesharray);
nNebulaUseModule(nshader2);
nNebulaUseModule(ntexture2);
nNebulaUseModule(ngfxserver2);
nNebulaUseModule(ninputserver);
nNebulaUsePackage(ndirect3d9);
nNebulaUsePackage(ndinput8);
/// -声明使用的Nebula2 Package&Module
///----------------------------------------------------------------------------

nKernelServer
* ks = NULL;
nGfxServer2
* gfx2 = NULL;

///----------------------------------------------------------------------------
/// +初始化环境,创建需要的Server
///
bool InitApp()
{
/// 创建KernelServer
ks = n_new(nKernelServer);

///----------------------------------------------------------------------------
/// +向KernelServer中添加Package&Module
nNebulaAddModule(nresource);
nNebulaAddModule(nresourceserver);
nNebulaAddModule(nfont2);
nNebulaAddModule(nmesh2);
nNebulaAddModule(nmesharray);
nNebulaAddModule(nshader2);
nNebulaAddModule(ntexture2);
nNebulaAddModule(ngfxserver2);
nNebulaAddModule(ninputserver);
ks
->AddPackage(ndirect3d9);
ks
->AddPackage(ndinput8);
/// +向KernelServer中添加Package&Module
///----------------------------------------------------------------------------

/// 创建D3D9Server
gfx2 = (nGfxServer2*)ks->New(nd3d9server, /sys/servers/gfx);
/// 创建ResourceServer
nResourceServer* res = (nResourceServer*)ks->New(nresourceserver, /sys/servers/resource);

/// 获得FileServer设置shaders的路径
nFileServer2* file = (nFileServer2*)ks->Lookup(sys/servers/file2);
/// @note:这是启动d3d9server必须的
/// 因为d3d9server在初始化时会访问”shaders:shape.fx”,用它来控制绘制调试图形的渲染状态
file->SetAssign(shaders, bin:../../datafiles/shaders/fixed);

/// 初始化显示模式
nDisplayMode2 mode;
mode.SetXPos(
0);
mode.SetYPos(
0);
mode.SetWidth(
320);
mode.SetHeight(
200);
/// 将显示模式应用到d3d9server
gfx2->SetDisplayMode(mode);

/// 启动d3d9server
gfx2->OpenDisplay();


/// 创建nInputServer
nInputServer* input = (nInputServer*)ks->New(ndi8server, /sys/servers/input);
input
->Open();

///----------------------------------------------------------------------------
/// +添加按键映射
/// @ 1. 可以在脚本中配置
/// @ 2. 可以通过设备的映射名来索取设备并检测设备状态
/// @ 3. 可以将脚本函数与设备直接帮定,这样在设备产生事件时会自动调用相关函数
input->BeginMap();
input
->Map(keyb0:space.down, reset);
input
->Map(relmouse0:btn0.pressed, look);
input
->Map(relmouse0:+x, right);
input
->EndMap();
/// -添加按键映射
///----------------------------------------------------------------------------

return true;
}
///
/// +初始化环境,创建需要的Server
///----------------------------------------------------------------------------

///----------------------------------------------------------------------------
/// +退出程序,清理资源
///
bool CloseApp()
{
/// 关闭d3d9server
gfx2->CloseDisplay();

/// 销毁KernelServer
n_delete(ks);

return true;
}
///
/// -退出程序,清理资源
///----------------------------------------------------------------------------

///----------------------------------------------------------------------------
/// +输入测试
///
void DumpInput()
{
/// 遍历事件列表,并将事件详细信息分类输出到控制台
for(nInputEvent* inputEvent = nInputServer::Instance()->FirstEvent();
inputEvent
!= NULL;
inputEvent
= nInputServer::Instance()->NextEvent(inputEvent))
{
/// 根据事件的DeviceID区分设备
switch(inputEvent->GetDeviceId())
{
case N_INPUT_MOUSE(0):
printf(
MouseEvent Detected! [BTN:%i] , inputEvent->GetButton());
switch(inputEvent->GetType())
{
case N_INPUT_MOUSE_MOVE:
printf(
[MouseMove]);
break;

case N_INPUT_BUTTON_DOWN:
printf(
[ButtonDown]);
break;

case N_INPUT_BUTTON_UP:
printf(
[ButtonUp]);
break;
}
break;
case N_INPUT_KEYBOARD(0):
printf(
KeyEvent Detected! [KEY:%i] , inputEvent->GetKey());
switch(inputEvent->GetType())
{
case N_INPUT_KEY_DOWN:
printf(
[KeyDown]);
break;

case N_INPUT_KEY_UP:
printf(
[KeyUp]);
break;

case N_INPUT_KEY_CHAR:
printf(
[CharEvent]);
break;
}
break;
}
printf(
);
}
}
///
/// -输入测试
///----------------------------------------------------------------------------

///----------------------------------------------------------------------------
/// +Application
int main(int argc, const char** argv)
{
/// 初始化Application
if ( !InitApp() )
{
n_error(
程序初始化失败! );
return 0;
}

/// 这里相当于游戏循环,gfx2->Trigger()将触发win32的消息泵
while ( gfx2->Trigger() )
{
/// 一帧开始
gfx2->BeginFrame();
/// 绘制场景开始
if ( gfx2->BeginScene() )
{
/// 设置渲染缓冲区
gfx2->Clear(nGfxServer2::AllBuffers, 0.2f, 0.2f, 0.8f, 1.0f, 0, 0);
/// 绘制场景结束
gfx2->EndScene();
/// 显示场景
gfx2->PresentScene();
}
/// 一帧结束
gfx2->EndFrame();

/// 检测输入事件,并输出到控制台
DumpInput();

/// 清空输入事件列表
nInputServer::Instance()->FlushEvents();

n_sleep(
0.01f);
}

/// 释放资源
if ( !CloseApp() )
{
n_error(
释放资源失败! );
return 0;
}

return 0;
}
/// -Application
///----------------------------------------------------------------------------

您可以针对本文进行:[评论]  [收藏]  [推荐]   [查看原文链接]  
  • 共有0条评论  点击查看更多评论
  • 网友评论仅供网友表达个人看法,并不表明e800同意其观点或证实其描述
我想发表评论:
用户名密码
  • 匿名发表
    验证码: