UE3输入输出开发笔记

发表于2017-03-23
评论0 2.1k浏览

很多游戏引擎因为只专注于图形渲染,所以很少为开发者提供输入事件处理方案。但UE3还是自带了一整套输入事件绑定系统,非常的自由灵活,可满足开发者各种开发需求。在UE3的官方文档中虽然有对UE3输入系统做一些基础介绍,但在一些细节上并未介绍清楚,初学者容易走弯路,而本篇文章是在官方文档基础上更为详细的整理了一些UE3输入系统的使用介绍,一起来看看吧。

 

1,一个简单的按键绑定例子。

A*Input.ini中为按键添加绑定事件。

打开$UDKRoot$UDKGameConfigUDKInput.ini,在   [Engine.PlayerInput]模块下  输入一条映射条目如下:

 

Bindings=(Name="E", Command="TestE")

 

注意,该条目应该放在最靠后位置,如果前面已经存在Name="E"的条目,该条目 将被后面的冲掉。如下:

Bindings=(Name="E", Command="TestE1")

Bindings=(Name="E", Command="TestE2")

当按下"E"键时,"TestE1"将不会响应,"TestE2"对其进行响应。

 

另外,必须放置在[Engine.PlayerInput]模块下,它是游戏中响应输入的模  块,其他       模块如[GameFramework.DebugCameraInput]等有其他用途。

 

B,在UE3脚本中添加事件函数。

UDK中可以添加事件函数的类很多,一般会在PlayerInput   类下添加,如下:

Exec function TestE()

{

`Log('TestE');

}

注意,该函数一定要有Exec修饰符,否则按键绑定将没有效果。

 

C,保存ini文件,编译脚本并重启游戏,按下按键"E"时,便能输出日志"TestE"

 

D,此例中只说明了一个按键"E"的绑定脚本方式,其他的输入事件绑定同理,文   档最后会把可绑定的所有输入事件列一个表。

 

2*Input.ini中绑定条目Bindings的语法。

上例中我们添加了一个条目:

Bindings=(Name="E", Command="TestE")

这是绑定事件最简单的情况,意思是按键E按下时触发TestE命令,其中:

Name- 按键的绑定名称,也可以是别名或者映射的按键,后面会解释

Command- Name对应的按键或者事件被触发时,要执行的命令,它一般是UE3                       本中的Exec修饰的可执行函数或者input类型变量。

 

再列一些后面要用到的修饰符定义:

Control- 激活这个按键时,需要按下Ctrl

Shift- 激活这个按键时,需要按下Shift

Alt - 激活这个按键时,需要按下Alt

bIgnoreCtrl- 如果按下了Ctrl键,则忽略这个按键绑定

bIgnoreShift - 如果按下了Shift键,则忽略这个按键绑定

bIgnoreAlt- 如果按下了Alt键,则忽略这个按键绑定

Onrelease- 按键在释放时激活对应命令

 

现在,我们来扩展这个条目的各个功能。

A,组合按键。

我们想响应"Ctrl + E"按键,可以用如下语法:

Bindings=(Name="E",Command="TestE",  Control=true)

同理,响应"Alt + E", "Shift +E"可以如下:

Bindings=(Name="E", Command="TestE",  Alt=true)

Bindings=(Name="E", Command="TestE",  Shift=true)

或者响应多组合键"Alt + Shift + Ctrl + E"

Bindings=(Name="E", Command="TestE",  Control=true,  Shift=true, Alt=true)

注意:默认情况下,ControlAltShift都是为false的。

另外还有一个忽略按键选项,比如当按下Ctrl时,我不想响应"E"键,可以如下:

Bindings=(Name="E", Command="TestE",  bIgnoreCtrl=true)

注意:在同时有Control=truebIgnoreCtrl=true的情况下,该按键将在任何情况下       都无法响应,一般不会这样应用。

同理于AltShift按键,有对应的bIgnoreAltbIgnoreShift,并且他们默认都为false

 

B,按键按下或者释放响应,以及多命令响应。

我们想让"E"按下时响应"PressE",释放时响应"ReleaseE",语法如下:

Bindings=(Name="E",Command="PressE | onrelease ReleaseE")

Onrelease修饰符是加在Command下的,Command右边值可以有多个命令用“|“分      隔符分开,再比如:

Bindings=(Name="E",Command="PressE1 | PressE2 | onrelease ReleaseE")

该条目使"E"按下时同时响应"PressE1""PressE2"命令,释放时响应"ReleaseE"   令。

 

C,按键的别名。

按键别名是什么,有什么好处。其实按键别名,就是游戏开发者为具体应用取的一       个虚拟的按键名,比如射击类游戏有开火动作,而键盘上又不存在专用的开火这个

按钮怎么办,那么我就在Bingdings下取一个Name="Fire"的条目,如下:

Bindings=(Name="Fire",Command="ExecFire")

这样做有什么好处呢?因为UE3是跨平台的引擎,它除了面向PC,还面向手机、XBOX等,这些不同平台的硬件输入是很不一样的,比如我想在PC中开火用"F"       按键,XBOX中用它的"Y"按钮,我们就可以用如下方式来绑定:

Bindings=(Name="F",Command="Fire")

Bindings=(Name="XboxTypeS_Y",Command="Fire")

这样无论PC中按下"F"按键或者XBOX中按下"Y"键,都能最终执行到ExecFire     命令。

 

D,按键绑定链。

按键绑定语法还可以动态修改按键绑定的命令,具体原理是通过UnrealScript    SetBind   函数,它在Bindings语法内,可以通过Command来执行,并设置参数,     它在UnrealScript中的声明如下:

exec function SetBind(const out name BindNamestring Command)

可以注意到它是一个exec修饰的函数,所以可以通过命令绑定,我们可以通过如      Bingdings语法来传参数并执行它:

Bindings=(Name="F",Command="SetBind F PressF")

第一次按下"F"时,它便将"F"绑定到"PressF"命令上,第二次按"F"则直接执行"PressF"  命令。

 

什么是按键绑定链,它有什么作用?按键绑定链是一种按键触发技巧,它的作用是       可以灵活的根据需要动态设置按键绑定的命令,它的实现方式用到了"SetBind"   命令和一些自定义别名。我们举个一个按键绑定开灯关灯的例子,我们可以这样做:

 

Bindings=(Name="L"Command="Light")

Bindings=(Name="Light",Command="Light | SetBind L LightOff")

Bindings=(Name="LightOff"",Command="ExecLightOff | SetBind L Light")

 

第一条Bindings:按键"L"绑定到别名"Light"

第二条Bindings:别名"Light"对应命令是执行"ExecLight"开灯,同时通过"SetBind" "L"      绑定到别名"LightOff"

第三条Bindings:别名"LightOff"对应命令是执行"ExecLightOff"关灯,同时通过    "SetBind"       "L"绑定回别名"Light"

 

这样,"L"按键将不断切换开灯关灯命令。

 

E,按键绑定变量。

官方文档中说道:“应该在 ControllerInput 或任何它们的子类(例如   PlayerController  PlayerInput)中定义这个变量”,也就是说按键绑定的变量应该

定义在上述两个类子类中,定义在其他类中将绑定不了。

 

先介绍一下按键绑定的语法:

1Axis修饰符(轴修饰符)。

ControllerInput 或任何它们的子类中声明一个自定义input类型变量如下:

var input             float  aMyAxis;

注意:Axis修饰符的变量必须是float类型,否则绑定将无效。

 

 

UDKInput.ini中添加一条鼠标横轴方向(X)的响应:

Bindings=(Name="MouseX",Command="Axis aMyAxis")     

      

这个时候,aMyAxis的值将会和鼠标横轴运动幅度相关,如鼠标往左会有一定的负 值,往右会有一定的正值,而在鼠标横轴方向不运动时则清零。

 

Axis类型变量也可以绑定到键盘按键上而非只有鼠标、操纵杆类型的模拟输入设   备。语法如下:

Bindings=(Name="E",Command="Axis aMyAxis")

这个时候如果按键E按下,则aMyAxis值将为1,释放状态则aMyAxis值为0

 

也可以这样:

Bindings=(Name="E",Command="Axis aMyAxis  Speed=-1.0")  

这个时候如果按键E按下,则aMyAxis值将为-1,释放状态则aMyAxis值为0

其中SpeedAxis的附加修饰符,另外几个Axis的附加修饰符,官方说明如下,  大家有兴趣可以一一在UDKInput.ini中去试试:

 

·         AbsoluteAxis它是通过使用这个乘法器在增量时间过程中缩放输入值的预处理器。将其定义为一个整数。

·         DeadZone如果这个值一点也没有改变输入数据上的绝对差,那么忽略输入数据。

·         Invert它是使用这个数量倒置输入值的预处理器。

·         Speed它是这个轴的变化的速度。

 

2Button修饰符(按钮修饰符)

同上,脚本内声明一个input类型变量如下:

var input             byte  bMyButton;

注意:Button修饰符的变量必须是Byte类型,否则绑定将无效。

 

由于Button修饰符变量检测的是输入按键按下状态,所以,对于鼠标、操纵杆等   模拟设备的输入绑定无效,只能绑定按键类型输入,语法如下:

Bindings=(Name="E",Command="Button bMyButton") 

当按键E按下时,bMyButton值为1,释放时,bMyButton值为0,可用于检       长按按键事件。

 

3Toggle修饰符(触发器修饰符)

同样地,脚本内声明一个input类型变量如下:

var input             byte  bMyToggle;

注意:Toggle修饰符的变量同Button修饰符变量一样,必须是Byte类型,否则绑  定将无效。

同样地,Toggle修饰符也是检测输入按键按下状态,所以对于鼠标、操纵杆等无效。

语法如下:

Bindings=(Name="E",Command="Toggle bMyToggle") 

当按键E按下第一次时,bMyToggle值为1即所谓开关打开,当按键E按下第二    次时,bMyToggle值为0即所谓开关关闭,如此往返。

 

4Count修饰符(计数器修饰符)

同上,声明一个input类型变量:

var input             byte  bMyCount;

ToggleButton修饰符一样,Count修饰变量也必须为Byte类型,否则绑定将    无效。

ToggleButton不一样的是,Count修饰符即检测按键按下时间,也检测鼠标、 操纵杆等模拟设备的激活时间,只要激活状态存在,如鼠标在滑动,则游戏中每个      TickCount都会增1

语法如下:

Bindings=(Name="MouseX",Command="Count bMyCount")

Bindings=(Name="E",Command="Count bMyCount")

则按键E在按下时或者鼠标沿X轴移动时,,游戏中每个Tick都会给bMyCount  1bMyCount的上限值是255,超过时则重新从0开始。

 

3,按键原理说明

A,输入来源及处理

Unreal底层有一个Input类,是游戏输入处理的基类,它有以下几个方法:

         virtual UBOOL InputKey(...);

         virtual UBOOL InputAxis(...);

virtual UBOOL InputTouch(...);

virtual UBOOL InputMotion(...);

它们分别是各游戏平台中输入消息的接收函数,例如PC中按下、释放或者按住按键E  会调用InputKey,将按键状(按下、释放或者重复)传入输入类进行处理,而鼠标滑          (或者操纵杆),则会调用InputAxis 将鼠标滑动的Delta值、Tick时间等传入    输入类    进行处理,总之,这几个函数就是对各个平台各种类型的输入进行各种处理,最终会将       输入数据统一包装,然后交给函数ExecInputCommands进行统一处理。

注意:处理UIScaleform另外也有一个输入处理基类以及一系列Input*()函数,只有Scaleform输入未捕获的输入,才能传入到UInput类中。另外Kismet中也可以捕获事  件,Kismet未捕获的输入才会传入到ExecInputCommands中,捕获优先级是             Scalefrom -> Kismet -> ExecInputCommands

 

BUDKInput.iniBindings条目与代码的联系

InputInput*()系列函数中,有如下代码片段(伪码):

StringCommands = GetBind( Key ) ;

If(Command.IsValid())

{

      ExecInputCommands( Commands, GlobalLog )

}

Else

{

Super.Handle(...);

}

 

而在Input类中有一个数组:

var config array<KeyBind>                               Bindings;

 

数组元素类型KeyBind 的声明如下:

struct native KeyBind

{

         var config name            Name;

         var config string          Command;

         var config bool             ControlShift,  Alt;

         var    config bool          bIgnoreCtrlbIgnoreShiftbIgnoreAlt;

};

 

可见,这个数组保存了UDKInput.ini中的每一条Bindings所指内容,每个Bindings   指内容都可以用KeyBind来保存。所以,每当有某个输入事件产生时,假设这个输入       事件名称为Key,则通过KeyBindings数组里查找有没有对应要处理的Command

如果有则执行ExecInputCommands(Commands, GlobalLog ) 

注意:Bindings数组元素不止来自.ini文件,还可能在UE3脚本中通过函数SetBings 态设置,或者在UE3编辑器中通过Kismet的方式添加,.ini文件只是比较普遍的一种

方式。

 

CExecInputCommands处理流程

在找到输入事件Key对应的Commands之后,则要在ExecInputCommands函数里执行

Commands里的内容,因为上文有说过,bindings里的Name可以绑定多个命令,所以,

这里的Commands字符串可能包含多个命令。ExecInputCommands的伪代码如下:

VoidExecInputCommands(string Commands)

{

While( ParseCommands(Commands,OneCommands) )

{

// 处理Kismet事件

If ( ProcessKismetEvents(OneCommand) ) continue;

 

// 处理脚本Exec函数

If(  ProcessExecScriptFun(Onecommand)) continue;

 

// 处理绑定变量,Axis,Button, Count, Toggle ...

If(ProcessBindVar_Axis(Onecommand))continue;      If( ProcessBindVar_Button(Onecommand) ) continue;

If(ProcessBindVar_Count,(Onecommand) ) continue;

If(ProcessBindVar_Toggle(Onecommand) ) continue;

...

 

// 处理按键绑定链

// 如果OneCommand本身是一个KeyBindName,则继续执行这个Name     // 对应的Commands

For (int i=0;i< span="">

{

If ( Bingds[i].Name == OneCommand)

{

ExecInputCommands(Bingds[i].Commands);

continue;

}

}

}

}

 

 

D,按键绑定变量的处理细节,即上述伪码中ProcessBindVar_* 的处理细节

可以注意到Input类有如下声明:

 

var native const Map{FName,void*}                NameToPtr;

var native const init array<pointerAxisArray{FLOAT};

 

其中NameToPtr是一张Input类型变量的映射表,每次有按键触发绑定变量,则会去    NameToPtr里查找按按键对应的变量地址,并对变量进行数值修改。而AxisArray里则     是一个保存了所有浮点型Input类变量的数组。为什么要多一个AxisArray,而NameToPrt

表里不是也保存了同样一份浮点型的Input类变量的映射吗?从官方源码里看,    AxisArray的主要作用是在每个Tick内,输入处理前,将每个float类型的input     量重置为0,而其 他类型的input类型变量(例如Byte类型的input类型变量)则           需要每个Tick都重置。

 

在处理Axis类型的变量绑定时,是去NameToPtr里查找其中的float类型的input变量   ,并对该变量进行对应的输入的数值修改。

而在处理Button,Count, Toggle类型变量的绑定,则是去NameToPtr里查找Byte类型的input变量进行对应处理。

 

 

 

4,其他需要注意事项

 

UE3底层在加载.ini文件的时候,有一定的时间遵循规则,以输入相关的配置文件举例。UDKInput.iniDefaultInput.ini的内容条目都会影响程序的按键绑定。首先,程序加载DefaultInput.ini文件,判断其文件时间戳数值是否比文件内记录的时间戳数值大,如果是,说明该文件改动过,则UDKInput.ini文件将被DefaultInput.ini文件内容覆盖。如果DefaultInput.ini文件未修改过,则程序先加载DefaultInput.iniBindings内容,再覆盖上UDKInput.iniBindings内容。

另外UDK*.ini系列文件,名称也不是非得要用“UDK”,你可以将它改成自己的游戏名称,但是本人论坛中得知,似乎只有官方授权的版本才允许这样做。源码中貌似是通过修改一个宏的名称即可。

由于UE3输入系统考虑了移动、平板、XBOXPC等各种硬件输入设备,又考虑了    UI、游戏、Kismet等输入事件,另外还支持.ini文件的命令绑定按键配置语法和Unreal     脚本动态修改绑定,所以非常灵活和强大,能够满足开发者各种输入处理的开发需求,但也容易被各种输入事件混淆迷惑。

 

5可映射按键

这是一个被映射到虚幻引擎 3 中的按键的列表。

键盘

功能键

·         F1功能 1

·         F2功能 2

·         F3功能 3

·         F4功能 4

·         F5功能 5

·         F6功能 6

·         F7功能 7

·         F8功能 8

·         F9功能 9

·         F10功能 10

·         F11功能 11

·         F12功能 12

字母按键

·         A字每 A

·         B字母 B

·         C字母 C

·         D字母 D

·         E字母 E

·         F字母 F

·         G字母 G

·         H字母 H

·         I字母 I

·         J字母 J

·         K字母 K

·         L字母 L

·         M字母 M

·         N字母 N

·         O字母 O

·         P字母 P

·         Q字母 Q

·         R字母 R

·         S字母 S

·         T字母 T

·         U字母 U

·         V字母 V

·         W字母 W

·         X字母 X

·         Y字母 Y

·         Z字母 Z

特殊键

·         Escape-Escape(退出)键。

·         Tab-Tab 键。

·         Tilde-~(波浪号)。

·         ScrollLock滚动锁。

·         Pause暂停键。

·         one-1

·         two-2

·         three-3

·         four-4

·         five-5

·         six-6

·         seven-7

·         eight-8

·         nine-9

·         zero-0

·         Underscore-_(下划线)。

·         Equals-=(等号)。

·         Backslash-(反斜线)。

·         LeftBracket-[(左括号)。

·         RightBracket-](右括号)。

·         Enter回车键或数字键盘中的回车键。

·         CapsLock大写锁定。

·         Semicolon-;(分号)。

·         Quote-'(引号)。

·         LeftShift左侧的 shift 键。

·         Comma-,(逗号)。

·         Period-.(句点)。

·         Slash-/(斜线)

·         RightShift右侧的 Shift 键。

·         LeftControl左侧的 control 键。

·         LeftAlt左侧的 alt 键。

·         SpaceBar退格条。

·         RightAlt右侧 alt 键。

·         RightControl右侧 control 键。

·         Left左方向键。

·         Up上方向键。

·         Down下方向键。

·         Right右方向键。

·         Home-Home 键。

·         End-End 键。

·         Insert-Insert(插入)键。

·         PageUp向上翻页。

·         Delete-Delete(删除)键。

·         PageDown向下翻页。

·         NumLock数字锁定。

·         Divide数字键盘 /

·         Multiply数字键盘 *

·         Subtract数字键盘 -

·         Add数字键盘 +

·         PageDown向下翻页。

·         NumPadOne数字键盘 1

·         NumPadTwo数字键盘 2

·         NumPadThree数字键盘 3

·         NumPadFour数字键盘 4

·         NumPadFive数字键盘 5

·         NumPadSix数字键盘 6

·         NumPadSeven数字键盘 7

·         NumPadEight数字键盘 8

·         NumPadNine数字键盘 9

·         NumPadZero数字键盘 0

·         Decimal数字键盘小数点。

鼠标

·         LeftMouseButton左鼠标按钮。

·         RightMouseButton右鼠标按钮。

·         ThumbMouseButton主要的鼠标上用拇指摸的按钮。

·         ThumbMouseButton2次要的鼠标上用拇指摸的按钮。

·         MouseScrollUp向上滚动的鼠标滑轮。

·         MouseScrollDown向下滚动的鼠标滑轮。

·         MouseX X 轴上的鼠标运动。

·         MouseY Y 轴上的鼠标运动。

XBox360 控制器

·         XboxTypeS_LeftThumbStick左拇指操纵杆作为按钮按。

·         XboxTypeS_RightThumbStick右拇指操纵杆作为按钮按。

·         XboxTypeS_DPad_Up控制台方向向上。

·         XboxTypeS_DPad_Left控制台方向向左。

·         XboxTypeS_DPad_Right控制台方向向右。

·         XboxTypeS_DPad_Down控制台方向向下。

·         XboxTypeS_Back返回按钮。

·         XboxTypeS_Start开始按钮。

·         XboxTypeS_Y-Y 按钮。

·         XboxTypeS_X-X 按钮。

·         XboxTypeS_B-B 按钮。

·         XboxTypeS_A-A 按钮。

·         XboxTypeS_LeftShoulder左肩按钮。

·         XboxTypeS_RightShoulder右肩按钮。

·         XboxTypeS_LeftTrigger作为按钮按下的左侧触发器。

·         XboxTypeS_RightTrigger作为按钮按下的右侧触发器。

·         XboxTypeS_LeftTriggerAxis按下一半的左侧触发器。

·         XboxTypeS_RightTriggerAxis按下一半的右侧触发器。

·         XboxTypeS_LeftX在作为模拟控件使用的时候左边大拇指摸的操纵杆水平位置。

·         XboxTypeS_LeftY在作为模拟控件使用的时候左边大拇指摸的操纵杆垂直位置。

·         XboxTypeS_RightX在作为模拟控件使用的时候右边大拇指操纵杆水平位置。

·         XboxTypeS_RightY在作为模拟控件使用的时候右边大拇指操纵杆垂直位置。

 

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

0个评论