Adobe Flash Builder 4 简体中文正式版 Windows版点击下载:http://g.csdn.net/5134151
Adobe Flash Builder 4 简体中文正式版 Mac版点击下载 :http://g.csdn.net/5134152
Adobe 在线课堂:http://adobev.csdn.net/zx/index.html
Adobe平台技术峰会课程视频:http://adobev.csdn.net/
http://blog.flashgen.com/gaming/pushbutton-engine/pushbutton-engine-handling-user-input/
在前几篇文章中,我已经介绍了如何创建你的工作区 (Flash Professional 或 Flash Builder) 以及如何创建场景,并添加 玩家 实体 – 一般称为 主角 实体。在本文中,我将向你介绍如何关联基本的键盘输入,以控制玩家在场景中实际移动。
在了解代码前,最好对你添加输入控制时打开的不同选项有一定了解。你可以直接关联 PBE 主类的 InputManager 实例,也可使用输入映射。直接关联很简单,但是需要保证你的实体和 InputManager 之间有紧密的关系。
例如,如果你想要使使用者自定义游戏控制按键 ( 这是非常对我胃口的一项设计,因为我是左撇子,我的右手操作键盘不如左手那么灵活 ) 。这同样也使得用 PBE 对基于 XML 的描述符文件的支持变得难于实施,因为他们期望一种替代机制 – 一种输入映射来配置输入。 该输入映射是直接与进行关联的一种替代 ( 更准确地说是一种扩展 ) 方案。
使用一种输入映射的优点在于其可从 InputManager 提取键位关联。这使得你可更方便地在任何一点改变键位。另外,输入映射还使得从基于 XML 的 .pbelevel 文件中进行配置变得更为简单 ( 这会在以后的文章中详述)。现在,让我们看看如何通过两种机制来进行键盘输入映射。
使用 InputManager 进行键盘控制
将键盘控制添加至你的游戏的最简单的方法是 InputManager 类中的 isKeyDown() 方法。但是,如你将看到的,这可能导致过多复杂而难以控制的映射信息。让我们就从这个入门,以便你在今后加以提高。和其他情况一样,你需要创建一个类来管理输入操作。这将从 TickedComponent 来继承,这样在每个游戏时间( game-tick ),都可以对其加以调用。基本架构是采用你的控制权,而不管 onTick() 方法。
要对你的实体进行各方面的关联,你需要导入相关属性引用。你可以发布所需 ( 类型 PropertyReference) 的变量,然后通过所有人引用来在需要时进行访问。因此,你可以从如下范例代码中看出,有一个变量名为 positionReference( 属于类型 PropertyReference ),要访问它,只需调用 owner.getProperty() 方法,并导入你想要访问的引用,作为方法签名。
1 2 3 4 5 6 7 8 9 10 | public var positionReference:PropertyReference;
override public function onTick ( deltaTime: Number ) : void { super . onTick ( deltaTime ) ;
var _position:Point = owner. getProperty ( positionReference ) ;
owner. setProperty ( positionReference, _position ) ; } |
要对一条属性进行任何更改, 只需调用计数方法 getProperty() ,即 setProperty() 。 这种方法涉及两种参数 – 引用的属性和你想要为其所设的值(如上述代码底部所示)。 .
对键盘输入进行映射是很简单的,因为 PBE 开发者已经提供了你关联所想使用的几乎每个按键的常数 ( 可点击此处查看列表 here )。
完整的键盘控制类( KeyboardController class )如下
1 2 3 4 5 6 7 8 9 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 49 50 51 52 | package com. flashgen . gaming . controllers { import com. pblabs . engine . PBE ; import com. pblabs . engine . components . TickedComponent ; import com. pblabs . engine . core . InputKey ; import com. pblabs . engine . entity . PropertyReference ;
import flash. geom . Point ;
publicclass KeyboardController extends TickedComponent { publicvar positionReference:PropertyReference;
publicfunction KeyboardController () { super () ; }
overridepublicfunction onTick ( deltaTime: Number ) : void { super . onTick ( deltaTime ) ;
var _position:Point = owner. getProperty ( positionReference ) ;
if ( PBE. isKeyDown ( InputKey. UP )) _position. y -= 5 ;
if ( PBE. isKeyDown ( InputKey. DOWN )) _position. y += 5 ;
if ( PBE. isKeyDown ( InputKey. LEFT )) _position. x -= 5 ;
if ( PBE. isKeyDown ( InputKey. RIGHT )) _position. x += 5 ;
if ( _position. x > 190 ) _position. x = 190 ;
if ( _position. x < - 190 ) _position. x = - 190 ;
if ( _position. y > 105 ) _position. y = 105 ;
if ( _position. y < - 105 ) _position. y = - 105 ;
owner. setProperty ( positionReference, _position ) ; } } } |
将控制器添加至你的实际实体是很简单的。只需发布元素即可 – 这里指你的 KeyboardController ,并为其分配所需属性。最后,确保其添加至实体本身;如下列代码所示:
1 2 3 | var _input:SimpleKeyboardController = new SimpleKeyboardController () ; _input. positionProperty = new PropertyReference ( "@Spatial.position" ) ; _hero. addComponent ( _input, "Input" ) ; |
这都是基于上一篇文章《开始使用 Pushbutton引擎 》中介绍的玩家(主角)来设置的。但该代码是整洁而简要的 – 假设我只映射了4 个按键,它不能将输入控制指令和实际控制类中定义的指令进行紧密关联。一种更好的方法是将该信息进行提取,以便其可有用户或外部配置来进行定义。可采用 InputMap 类来实现这一目的。
通过 InputMap 进行灵活得键盘映射
使用 InputMap 类需要一点逆向思维,这主要是因为最好是从控制器开始,再回到将使用它的实体。现在 InputMap 类既有一些你肯定不会陌生的方便方法:
· mapActionToHandler()
· mapKeyToAction()
· mapKeyToHandler()
列表中最后一个是不言自明的,通过它,你可以输入 InputKey 任务、每个处理器( handler ) 的名称,且当按键按下时,处理器被调用。关于这些方法,有一点你必须了解,即它们不会将一个事件对象传给处理器。它们只是早按键按下时传递值 1( 一),在按键弹起时传递值 0( 零)。
下列范例显示了如何使用前两个方法: mapActionToHandler() 和 mapKeyToAction() 。将这两者想象为一个物体的两半。你把它们中的一个用于控制器内,而另一个在实体内(或你想映射的任何地方)。看看完整的键盘控制器 ( 我之前称之为 InputMapKeyboardController) ,对其进行分解,即可有更深的认识。
1 2 3 4 5 6 7 8 9 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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | package com. flashgen . gaming . controllers { import com. pblabs . engine . PBE ; import com. pblabs . engine . components . TickedComponent ; import com. pblabs . engine . core . InputKey ; import com. pblabs . engine . core . InputMap ; import com. pblabs . engine . entity . PropertyReference ;
import flash. geom . Point ;
public class InputMapKeyboardController extends TickedComponent { private var _inputMap:InputMap;
public var positionProperty:PropertyReference; private var _right: Number ; private var _left: Number ; private var _down: Number ; private var _up: Number ;
public function InputMapKeyboardController () { super () ; }
protected function onRight ( value: Number ) : void { _right = value; }
protected function onLeft ( value: Number ) : void { _left = value; }
protected function onDown ( value: Number ) : void { _down = value; }
protected function onUp ( value: Number ) : void { _up = value }
public override function onTick ( deltaTime: Number ) : void { super . onTick ( deltaTime ) ;
var _position:Point = owner. getProperty ( positionProperty ) ;
if ( Boolean ( _up )) _position. y -= 5 ;
if ( Boolean ( _down )) _position. y += 5 ;
if ( Boolean ( _left )) _position. x -= 5 ;
if ( Boolean ( _right )) _position. x += 5 ;
if ( _position. x > 190 ) _position. x = 190 ;
if ( _position. x < - 190 ) _position. x = - 190 ;
if ( _position. y > 105 ) _position. y = 105 ;
if ( _position. y < - 105 ) _position. y = - 105 ;
owner. setProperty ( positionProperty, _position ) ; }
public function get inputMap () :InputMap { return _inputMap; }
public function set inputMap ( value:InputMap ) : void { _inputMap = value;
if ( _inputMap ! = null ) { _inputMap. mapActionToHandler ( "Up" , onUp ) ; _inputMap. mapActionToHandler ( "Down" ,onDown ) ; _inputMap. mapActionToHandler ( "Left" , onLeft ) ; _inputMap. mapActionToHandler ( "Right" ,onRight ) ; } } } } |
如你所见,这与第一个控制器类并非差之千里。但是,最大的不同是与最后的 getter / setter 方法有关。我在 setter 中查看是否有一个有效的 InputMap 对象,如果有,则使用 mapActionToHandler() 在控制器中创建一个映射。如你所见,其取一个串值并将其与一个事先确定的处理器向关联。
1 2 3 4 5 6 7 8 9 10 11 12 | public function set inputMap ( value:InputMap ) : void { _inputMap = value;
if ( _inputMap ! = null ) { _inputMap. mapActionToHandler ( "Up" , onUp ) ; _inputMap. mapActionToHandler ( "Down" ,onDown ) ; _inputMap. mapActionToHandler ( "Left" , onLeft ) ; _inputMap. mapActionToHandler ( "Right" ,onRight ) ; } } |
在这些相关处理器中,只有一个变量,该变量设为传递给它的当前数值 – 具体取决于该键是上还是下 (0 或 1 )。最后的不同是在 onTick() 方法中。与之前的控制器范例(明确检视每个键来确定是否按下)不同,该范例采用的是处理器变量值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public override function onTick ( deltaTime: Number ) : void { super . onTick ( deltaTime ) ;
var _position:Point = owner. getProperty ( positionProperty ) ;
if ( Boolean ( _up )) _position. y -= 5 ;
if ( Boolean ( _down )) _position. y += 5 ;
if ( Boolean ( _left )) _position. x -= 5 ;
if ( Boolean ( _right )) _position. x += 5 ; ... } |
再观察完整代码,你可能会发现,我没有在代码中任何地方发布实际输入按键; 而是提供了一种抽象的方法来帮助你进行键盘映射。但是,对于控制器类来说,这就够了。不过你将如何进行实际的映射工作?在本例中,你是在实体本身内进行映射。与你过去用来将添加基本键盘控制器添加至实体所用的三行代码不同,你需要添加更多的参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 | var _input:InputMapKeyboardController = new InputMapKeyboardController () ;
_input. inputMap = new InputMap () ; _input. inputMap . mapKeyToAction ( InputKey. UP , "Up" ) ; _input. inputMap . mapKeyToAction ( InputKey. DOWN , "Down" ) ; _input. inputMap . mapKeyToAction ( InputKey. LEFT , "Left" ) ; _input. inputMap . mapKeyToAction ( InputKey. RIGHT , "Right" ) ;
_input. inputMap .
_input. positionProperty = new PropertyReference ( "@Spatial.position" ) ;
_hero. addComponent ( _input, "Input" ) ; |
这并没有那么难,但是你可以看出,你是通过我们的控制器的 InputMap 范例中的 mapKeyToAction() 方法来对输入按键进行映射的。简言之,要确保你记得例示 InputMap ,否则就会失败 – 我当然知道,但还是要说明下,因为我们常常因忽略简单的事情而失败。
小结
在本文中,你学到了如何通过 InputManage 实施简单的键盘控制,首先通过你的控制器类里明确定义输入键,然后通过 InputMap 类(作为 InputManager 的 一种外观 )进行提取。你还学到了如何使用 InputMap 类来轻松地解除实际输入键和游戏之间的关联 – 使得使用者可自定义键盘配置。
相关文件
PBE002_HandlingUserInput.zip