酷勤网 – 程序员的那点事!

当前位置:首页 > 编程 > 游戏开发 > 正文

针对触屏设备制作游戏虚拟操纵杆的教程

浏览次数: 2012年05月25日 GamerBoom.com 游戏邦 字号:

在编译本篇教程所提供的源文件之前,你需要先下载GreenSock的TweenLite(AS3)库类到你的项目文件夹的“greensock”子文件夹中。(这点将在第18步骤中详细讨论到)。

以下便是我们将努力创造出的最终结果:

virtual joystick for touch devices(from active.tutsplus)

virtual joystick for touch devices(from active.tutsplus)

步骤1:创造一个新的AS3文件

让我们开始在Flash Professional CS5中创造一个新的AS3文件。

new_document(from active.tutsplus)

new_document(from active.tutsplus)

在属性面板中找到文件设置,并确保文件的规格为(550×400),背景颜色为 (#000000) ,如下图所示:

document_properties(from active.tutsplus)

document_properties(from active.tutsplus)

在属性面板上将文件的类名设置为“com.MyApp”。这是我们所创造并用来代表主要应用的类。我们也将在之后创造其它针对于操纵杆的类,从而使我们能够只使用几行代码便将操纵杆添加到任何其它应用中。

将文件另存为“JoystickApp.fla”。

步骤2:创造文件类

document_class(from active.tutsplus)

document_class(from active.tutsplus)

现在,点击类名旁边的铅笔图标从而触发出编辑类。因为本来并不存在类,所以我们必须去创造它们。

edit_document_class(from active.tutsplus)

edit_document_class(from active.tutsplus)

当我们需要选择软件去编辑类定义时,我们可以选择Flash Professional。这时候你将能够看到新的类定义预填充在新的ActionScript文件中:

package com { import flash.display.MovieClip; public class MyApp extends MovieClip { public function MyApp() { // constructor code } } }

将其保存在子文件夹“com”中与.fla 文件相同的文件夹中,并命名为“MyApp.as”。需要注意的是你可以自己设定文件夹的名称和结构。而文件夹结构的设置可以参考你的AS包的结构。

步骤3:绘制基本的操纵杆和把手

在这个步骤中我们将绘制出一套基本的圆圈以代表操纵杆。而在之后的步骤中我们将进一步优化我们的用户界面(UI)以让其更加具有吸引力。首先我们需要在.fla 文件中画出一个圆圈。并设置其属性为宽:160,高:160,颜色: #CCCCCC,其位置为横坐标:100,纵坐标:300。

将这个圆圈转变成一个MovieClip,并将其命名为“操纵杆”。在转变过程中选择一个定位点作为中心。

将MovieClip“操纵杆”放置在如下平台的左下方。(这只是用于参考)。我们将在之后的步骤中从“MyApp”类中动态地添加MovieClip到平台上。

circle_joystick_movieclip(from active.tutsplus)

circle_joystick_movieclip(from active.tutsplus)

在平台上绘制另外一个更小的圆圈,设置其宽为50px,高为50px。同样地将这个圆圈转变为新的MovieClip并命名为“操纵杆把手”。如下图将其放置于“操纵杆”MovieClip之上。

joystickKnob_movieclip(from active.tutsplus)

joystickKnob_movieclip(from active.tutsplus)

这便是我们完成所有阶段后能够看到的基本版操纵杆。我们将其安置在如上图的位置上。既然我们明确了操纵杆的外表,我们便可以开始为其撰写脚本了。现在你便可以在这个平台上删除这两个MovieClip了。

步骤4:将UI与定制类绑定

现在让我们将我们所创造的UI与它们的定制类维系在一起。打开程序库并右击“操纵杆”MovieClip。选择“属性”。

在“输出行动脚本”的复选框中打勾。将你的类名改为“com.controls.Joystick”。我们将在“com”文件夹中创建一个子文件夹,并在“com.controls”包中设置与控制相关的代码。

joystick_mc_class(from active.tutsplus)

joystick_mc_class(from active.tutsplus)

点击类名旁边的铅笔图标,如果需要打开编辑器就选择“Flash Professional”。这时候我们便创造出了一个名为.as的文件,其类名为“操纵杆”,并且是“MovieClip类的扩展。

在另外的“操纵杆把手”MovieClip中重复相同的过程。提供类名“com.controls.JoystickKnob”。

将两个类文件分别保存为“操纵杆.as”和“操纵杆把手.as”。

此时你的程序库将如下所示,即拥有两个MovieClip并附属于它们各自的定制类上:

library(from active.tutsplus)

library(from active.tutsplus)

步骤5:操纵杆把手类

我们根据操纵杆的位置去设置把手的起点。如此我们便能够在把手被拖曳到其它任何位置时更好地找到其最初的位置。

为此,我们将在“操纵杆把手”类中使用两个简单的属性。

package com.controls { import flash.display.MovieClip; public class JoystickKnob extends MovieClip { private var _origin_x:Number; private var _origin_y:Number; public function JoystickKnob() { // constructor code } } }

让我们先写下获取和设定方法,并以此读出或写下“ _origin_x”和“ _origin_y”属性。在“操纵杆把手”类中添加以下方法:

public function get origin_x():Number { return _origin_x; } public function set origin_x(o_x:Number):void { _origin_x = o_x; } public function get origin_y():Number { return _origin_x; } public function set origin_y(o_y:Number):void { _origin_y = o_y; }

明确一开始的函数名中不会包含“_”(下划线),因为我们希望外部类的名字为“origin_x”和“origin_y”。

步骤6:基本的操纵杆类

让我们开始添加参数到“操纵杆”类的构造函数中。我们将添加2种参数,分别是“left_margin:Number”和“bottom_margin:Number”。如此我们便能够在实例化MovieClip时将操纵杆设置在任何一个位置上。

随后,我们将在“操纵杆”类的私有变量中分配这两个参数。你所设置的代码需如下:

package com.controls { import flash.display.MovieClip; public class Joystick extends MovieClip { private var my_x:Number; private var my_y:Number; public function Joystick(margin_left:Number, margin_bottom:Number) { my_x = margin_left; my_y = margin_bottom; } } }

现在我们需要编写“初始化()”方法以设置屏幕上的操纵杆位置。我们将在这个方法上添加“操纵杆把手”MovieClip。这个方法中包含了一个“事件”类型的参数,而我们将在一分钟后才涉及到这一参数。

在你添加“操纵杆把手”MovieClip之前我们需要在这个类中输入“操纵杆把手”类。添加以下输入代码:

import com.controls.JoystickKnob;

既然我们已经输入了“操纵杆把手”类,我们便需要在你的类中申明一个代表把手的变量:

private var knob:JoystickKnob;

现在,将以下函数添加到你的类中:

private function init(e:Event=null):void { this.x = my_x + this.width / 2; this.y = stage.stageHeight – my_y – this.height / 2; knob = new JoystickKnob(); knob.x = 0; knob.y = 0; knob.origin_x = 0; knob.origin_y = 0; addChild(knob); // knob.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown); // stage.addEventListener(MouseEvent.MOUSE_UP, mouseReleased); knob.buttonMode = true; }

正如你所看到的,基于构造函数能够接受的边际范围我们已经在平台上添加了“把手”,并且将“操纵杆”MovieClip设置于平台上了。除此之外我们还在“把手”和“平台”上添加了一些事件监听器,分别是“MOUSE_DOWN”和“MOUSE_UP”。之后我们需要在类中写下“mouseDown()”和“mouseReleased()”方法,使我们能够拖放把手。现在我们监听器添加了注释;而与此同时也不要忘记取消在方法之后的两行内容的批注。

既然平板电脑/触屏设备中的MouseEvent.<EVENT_NAMES>转变成了碰触事件,我们便能够使用鼠标去取代碰触行动了。

现在我们需要从构造函数中调用这一方法。但是比起盲目地调用方法,通过实践去检查现有的“平台”并调用它会更加合适。如果此时“操纵杆”MovieClip的“平台”属性还未进行初始化,我们便需要在明确了“平台”属性后调用init()方法。因此我们需要基于下述方法调用init()(在你的构造函数中添加以下内容):

if (stage) { init(); } else { addEventListener(Event.ADDED_TO_STAGE,init); }

我们需要删除之前添加的事件监听器。所以让我们在(最初的)init()方法中添加以下内容:

if (hasEventListener(Event.ADDED_TO_STAGE)) { removeEventListener(Event.ADDED_TO_STAGE,init); }

步骤7:在平台上添加操纵杆

在我们执行这一代码并核查输出之前,我们需要从“MyApp”类中实例化“操纵杆”类。在你的“MyApp”类构造函数中添加以下代码。同时输入“操纵杆”类并申明一个能够代表“操纵杆”MovieClip的属性。所以此时你的“MyApp”类应该如下所示:

package com { import flash.display.MovieClip; import com.controls.Joystick; public class MyApp extends MovieClip { private var joystick:Joystick; public function MyApp() { joystick = new Joystick(30, 30); addChild(joystick); } } }

现在你便能够执行并测试应用。你需要在你的平台上动态地添加“操纵杆”MovieClip,并在左边和下部位置留出30px的空间以传递构造函数。以下是SWF的截图:

swf_joystick_placement(from active.tutsplus)

swf_joystick_placement(from active.tutsplus)

步骤8:在把手上添加互动作用

现在是时候在“操纵杆把手”MovieClip中添加互动作用了,使得我们能够在操纵杆周长内拖动把手。在“操纵杆”类中取消我们之前所添加的两个事件监听器批注。现在我们需要为“把手”编写“mouseDown()”和“mouseReleased()”方法。

我们需要在mouseDown()方法中添加startDrag() 方法。通过设置属性而明确“操纵杆”MovieClip的范围。同时也不要忘记输入类“flash.geom.Rectangle”和“flash.events.MouseEvent”。

private function mouseDown(event:MouseEvent):void { knob.startDrag(false,new Rectangle( - this.width / 2, - this.height / 2,this.width,this.height)); }

现在mouseReleased()便是一个简单的stopDrag()。随后我们需要添加更多代码以激活把手回到其“origin_x”和“origin_y”(游戏邦注:初始位置)。现在只要你释放鼠标,它便能够快速回到这一初始点上。

private function mouseReleased(event:MouseEvent):void { knob.stopDrag(); knob.x = knob.origin_x; knob.y = knob.origin_y; }

此时你便能够执行操纵杆的基本互动作用了。编译并运行!它将如下所示:

virtual joystick(from active.tutsplus)

virtual joystick(from active.tutsplus)

步骤9:检测把手的移动

让我们在操纵杆上尝试并检查“把手”的移动,并明确我们将如何基于自上而下的视图精灵去使用它。

当我们能够四处拖曳把手时,我们便需要基于操纵杆去明确把手的位置。修改精灵。我们将在之后创造一个精灵;而现在我们只需要设置把手位置的参数值即可。

在拖曳时明确把手的位置,我们还需要涵括一个ENTER_FRAME方法。在“操纵杆”类中添加以下代码:

private function knobMoved(event:Event):void { trace(knob.x + “, ” + knob.y); }

在mouseDown()方法中的startDrag()之前添加ENTER_FRAME事件监听器:

private function mouseDown(event:MouseEvent):void { this.addEventListener(Event.ENTER_FRAME, knobMoved); knob.startDrag(false,new Rectangle( - this.width / 2, - this.height / 2,this.width,this.height)); }

我们并不想一直运行着ENTER_FRAME方法,因为这么做非常耗成本。因此我们打算只在拖曳动作开始时添加监听器,并在调用stopDrag()方法时立刻删除监听器。在运行stopDrag()之后添加removeEventListener:

if (this.hasEventListener(Event.ENTER_FRAME)) { this.removeEventListener(Event.ENTER_FRAME, knobMoved); }

编译并运行SWF以进行测试。在输出窗口中读取参数值。

步骤10:对齐把手

因为我们面向的是触屏设备,所以用户在此体验不到控制的物理感触。所以有可能用户只是碰触到把手的外部,并尝试着去拖动操纵杆。所以我们根本不可能期待用户能精确地碰触并拖动把手。为了克服这一问题,我们必须想办法将把手对齐到用户碰触于操纵杆的点上。

也就是我们将在这个步骤中将“把手”的MovieClip与“操纵杆”所发生的碰触点对齐在一起。

在“操纵杆”类中添加以下私有方法:

private function snapKnob(event:MouseEvent):void { knob.x = this.mouseX; knob.y = this.mouseY; mouseDown(null); }

在上述代码中,我们将“把手”的MovieClip纵坐标和横坐标等同于“操纵杆”的MovieClip的鼠标相对横坐标和纵坐标。我们同时也将调用mouseDown(null)方法开始拖曳过程。

我们将通过添加事件监听器而调用这一方法。让我们在init()方法中进行实践。围绕着事件监听器调用mouseDown()方法。在init()方法中添加以下代码:

this.addEventListener(MouseEvent.MOUSE_DOWN, snapKnob); knob.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown); stage.addEventListener(MouseEvent.MOUSE_UP, mouseReleased);

根据上述代码,当“操纵杆”MovieClip获得MOUSE_DOWN事件后,它便能够调用snapKnob()方法。转而,这一方法能够把“把手”的MovieClip对齐到用户所碰触的位置上。随后调用mouseDown(null)方法,我们将推动startDrag()过程以让玩家感觉自己好像真的在碰触把手。

步骤11:创造一个主角MovieClip

既然我们的基本操纵杆已经能够有效运行了,我们便需要根据“把手”的位置参数值创造一个“主角”MovieClip以开始移动操纵杆。

现在打开.fla文件并绘制一个圆圈,如下所示。将其转变为MovieClip并再次使用定位点。将MovieClip命名为“主角”。然后设置其属性:宽为30px,高为30px,颜色为#0099CC。

在将圆圈转变为MovieClip的同时将其导出到行动脚本中,并将其类名命为“com.Hero”。

export_hero_mc(from active.tutsplus)

export_hero_mc(from active.tutsplus)

下图便是将圆圈转变为MovieClip的样子。

hero_mc(from active.tutsplus)

hero_mc(from active.tutsplus)

现在我们便能够从平台上删除MovieClip,因为我们将从“MyApp”类中将“主角”MovieClip动态地添加到平台上。

在你导出带有定制类名“com.Hero”的MovieClip后,不要忘记创建一个新的类文件并将其保存在“com”文件夹中。

步骤12:在平台上添加主角

让我们打开“MyApp.as”并动态地添加“主角”MovieClip。因为我们已经从“JoystickApp.fla”程序库中导出了“主角”的MovieClip,所以我们现在只需要打开“MyApp.as”,导入“com.Hero”类并申明一个新的属性“主角”,然后在实例化“操纵杆”MovieClip之前添加以下代码。你的“MyApp”类应该如下:

package com { import flash.display.MovieClip; import com.controls.Joystick; import com.Hero; public class MyApp extends MovieClip { private var joystick:Joystick; private var hero:Hero; public function MyApp() { hero = new Hero(); hero.x = stage.stageWidth/2; hero.y = stage.stageHeight/2; addChild(hero); joystick = new Joystick(30, 30); addChild(joystick); } } }

你可以注意到我们已经将MovieClip对齐在平台中央了。此时如果你编译并运行SWF,你便能够看到平台中央的“主角”MovieClip。

步骤13:将“主角”MovieClip转移到操纵杆类中

现在,为了能够在“操纵杆”MovieClip中访问“主角”MovieClip,我们需要使用一个简单的方法将“主角”MovieClip连同“margin_left”和“margin_bottom”属性转移到“操纵杆”MovieClip的构造函数中。

打开“com.controls.Joystick”类。输入“com.Hero” 类并在构造函数中添加第三个参数,如下:

public function Joystick(margin_left:Number, margin_bottom:Number, hero_mc:Hero) {

现在,既然我们希望能够在这个类中访问这一参数,我们就需要在此创造一个名为“主角”的私有变量:

private var hero:Hero;

随后,将我们刚刚添加的第三个参数转移到构造函数中的变量中,如下:

hero = hero_mc;

最后一步便是从“MyApp”类中将“主角”MovieClip转移到“操纵杆”MovieClip中(游戏邦注:并同时进行实例化)。将第三个参数添加到“操纵杆”MovieClip的构造参数中。

joystick = new Joystick(30, 30, hero);

此时我们便能够在平台上通过“操纵杆”MovieClip访问“主角”的MovieClip了。

步骤14:主角类

让我们准备一个“主角”类以移动“操纵杆”MovieClip。我们应该创造如下的基本类:

package com { import flash.display.MovieClip; public class Hero extends MovieClip { public function Hero() { } } }

在类中添加以下属性。我们应该在移动过程中使用这些属性。

package com { import flash.display.MovieClip; public class Hero extends MovieClip { private var walk_speed = 2; public var move_left:Boolean = false; public var move_up:Boolean = false; public var move_right:Boolean = false; public var move_down:Boolean = false; public function Hero() { } } }

因为属性是不需要加以说明的,所以你必须理解它们的用途。让我们前进到下个步骤并开始创造“主角”MovieClip的动画。

我们所添加的四个布尔属性是用于明确主角的移动方向。我们将通过“操纵杆”的类明确这些属性是正确还是错误。但是在此之前,让我们先准备具有移动能力的“主角”类。

在“主角”类中添加一个名为“heroMove()”的空白方法。

private function heroMove(event:Event):void { }

我们将通过一个ENTER_FRAME事件监听器调用这一方法。在这一类的构造函数中添加事件监听器。

public function Hero() { this.addEventListener(Event.ENTER_FRAME, heroMove); }

再一次需要记住输入一般类,如“flash.events.Event”等。

步骤15:理解把手的移动

现在,我们需要在“主角”类中调用“heroMove()” 方法以处理ENTER_FRAME事件。我们将在此核查4个布尔变量并相对应地移动主角。不过在此之前,我们还需要在“操纵杆”类中添加一个特殊的代码。所以让我们打开“操纵杆.as”文件并调用“knobMoved()”。

我们在方法中设置了跟踪语句,以此追踪“把手”MovieClip的横坐标和纵坐标位置。使用如下代码替换你的跟踪语句,你的“knobMoved()”方法 应该是:

private function knobMoved(event:Event):void { // LEFT OR RIGHT if (knob.x > 20) { hero.move_right = true; hero.move_left = false; } else if (knob.x < -20) { hero.move_right = false; hero.move_left = true; } else { hero.move_right = false; hero.move_left = false; } // UP OR DOWN if (knob.y > 20) { hero.move_down = true; hero.move_up = false; } else if (knob.y < -20) { hero.move_down = false; hero.move_up = true; } else { hero.move_down = false; hero.move_up = false; } }

上述代码是用于分离“左或右”和“上或下”移动相关代码,因为这里不存在让主角向左和右或向上和下移动的情节。所以我们便基于“把手”的MovieClip的横坐标和纵坐标(并围绕着“操纵杆”MovieClip的中心位置)将“主角”MovieClip的4个方向变量设置为正确或错误。

根据下图我们便能够更容易明白这一逻辑:

joystick_area_overview(from active.tutsplus)

joystick_area_overview(from active.tutsplus)

上图的2条红色虚线交汇在(0,0)或“起始点”或“操纵杆”MovieClip的“定位点”上。

而4个红色虚线框则代表“主角”能够移动“把手”的纵坐标和横坐标范围。红色虚线框中的文本则代表着方向。

蓝色矩形代表的是简单的方向,在此碰触点/把手只能朝着一个方向移动。

图像中间那个40×40 px的方形(灰色)代表的是一个槽区,即如果在此移动“把手”MovieClip也不会发生任何变化。这个槽区提供给用户能够容纳得下小指的空间,并且当用户碰触这块区域时也不会影响游戏的发展。因为在触屏设备中用户不能感受到任何物理界面,所以这种槽区更是非常必要(至少对于某些基本的游戏来说)——除非游戏拥有一个超级敏感的操纵杆。

以下是分离“左或右”的情况:

joystick_area_leftright(from active.tutsplus)

joystick_area_leftright(from active.tutsplus)

以下是分离“上和下”的情况:

joystick_area_updown(from active.tutsplus)

joystick_area_updown(from active.tutsplus)

步骤16:创造主角动画

现在,我们需要在“主角”类中调用“heroMove()” 方法以处理ENTER_FRAME事件。我们将在此核查4个布尔变量并相对应地移动主角。

在“heroMove()”方法中包含以下代码让我们能够根据基本的把手移动去移动“主角”MovieClip。

private function heroMove(event:Event):void { if (move_left) { this.x -= walk_speed; } if (move_up) { this.y -= walk_speed; } if (move_right) { this.x += walk_speed; } if (move_down) { this.y += walk_speed; } }

最后,记得在“操纵杆”类的“mouseReleased()”方法中将4个布尔变量重置为“错误的”。如果忘记了这个步骤“,“主角”MovieClip将在停止拖曳把手时继续运动着(游戏邦注:这是通过ENTER_FRAME事件基于“主角”类中的“heroMove()”方法所触发的)。

此时你的SWF应该如下:

virtual joystick (from active.tutsplus)

virtual joystick (from active.tutsplus)

继续前进并向下移动操纵杆把手。

步骤17:主角循环和方向

我们一直在尝试着创造出一款拥有自上而下视图以及一个能够到处走动的角色的游戏。虽然没有华丽的图像和动画,但是我们仍希望根据主角的移动创造出主角的方向或循环。如此我们便需要在.fla文件中添加一个额外的内容到“主角”MovieClip中(即一个像鼻子一样的形状)。

打开程序库中的“主角”标记,并添加一个小圆圈以代表“鼻子”。下图便是这一“鼻子”的放大版本及其MovieClip的实际尺寸视图。

hero_nose(from active.tutsplus)

hero_nose(from active.tutsplus)

现在让我们改变“主角”类中的“主角”MovieClip的“循环”属性。打开“主角”类,在“heroMove()”方法的开端添加以下代码:

private function heroMove(event:Event):void { if (move_left && move_up) { this.rotation = -45; } else if (move_right && move_up) { this.rotation = 45; } else if (move_left && move_down) { this.rotation = 225; } else if (move_right && move_down) { this.rotation = 135; } else if (move_right) { this.rotation = 90; } else if (move_left) { this.rotation = -90; } else if (move_up) { this.rotation = 0; } else if (move_down) { this.rotation = 180; } if (move_left) { this.x -= walk_speed; } if (move_up) { this.y -= walk_speed; } if (move_right) { this.x += walk_speed; } if (move_down) { this.y += walk_speed; } }

在上述代码中我们已经核查了所有的8个方向,并相应地循环了“主角”MovieClip。现在编译并运行代码,你便能够看到如下场景:

virtual joystick (from active.tutsplus)

virtual joystick (from active.tutsplus)

这便是操纵杆和主角的基本行为。

步骤18:添加TweenLite支持

在这个步骤中我们将掌握TweenLite程序库是如何运行的,以及我们可以如何轻松地将其整合到我们的演示内容中以获得更棒的动画效果。

我们选择使用GreenSock所开发的TweenLite程序库。这是一种较为简单的动画引擎,开发者能够快速掌握它;并且它对于动画性能的影响也非常小。

打开网站http://www.greensock.com/tweenlite/并点击右边的“Download AS3”按钮。

阅读并接受相关条款,一旦完成了下载你便拥有了greensock-as3.zip。

将其解压到一个文件夹中。

在解压后的文件夹中找到“com”文件夹,导航到“com”文件夹中。

你需要找到一个名为“greensock”的子文件夹。这便是我们所需要的文件夹。

现在有两种方法能够帮助你在自己的项目中使用这一程序库。

将这一文件夹复制到你的项目文件夹中,或者将其动态链接至你的项目中。

动态链接具有一个优点,即你可以在不同项目的常见位置上使用相同的文件夹。而如果你选择将“greensock”文件夹复制到你的项目文件夹中,你便只能够在这一项目中使用它。如果你仍坚持将这一文件夹用于其它项目中,那么当引擎本身的漏洞得到了修改或者出现了新的功能时,你便需要面向不同的项目去更新你的本地文件夹。

不过不管怎样,在这一项目中我们最终选择了复制文件夹到我们的项目位置上。

将“greensock”文件夹复制到你的项目“com”文件夹中。以下图像将帮助你更好地理解“greensock”文件夹的最终位置:

greensock_folder(from active.tutsplus)

greensock_folder(from active.tutsplus)

现在,我们将输出创造把手动画所需要的类。打开“操纵杆.as”文件,并添加以下输入代码:

import com.greensock.*;

步骤19:创造把手动画

让我们为把手创造一个简单的动画,即更好地表现出它从触动到回到起始点的这一过程。我们需要在“操纵杆.as”文件中完成这一操作。

将以下方法添加到类中:

private function mover():void { TweenLite.to(knob, 0.5, {x: knob.origin_x, y:knob.origin_y}); }

在方法“mouseReleased()”的最后添加函数调用到“mover()”:

mover();

切记在“mouseReleased()”方法中删除以下两行内容:

knob.x = knob.origin_x knob.y = knob.origin_y;

现在,尝试着拖曳把手并离开中心处。你将会看到如下swf格式的动画:

virtual joystick (from active.tutsplus)

virtual joystick (from active.tutsplus)

步骤20:把手反弹效果

因为操纵杆能够将把手拉回起始点的位置,所以我们需要在此添加一个自然的反弹效果。幸运的是使用TweenLite引擎能够帮助我们节省许多不必要的工作。

我们只需要打开“操纵杆.as”文件并输入TweenLite类包以创造出释放效果:

import com.greensock.easing.*;

TweenLite所支持的一种性能将帮助我们定义动画的类型。从我们的例子来看,也就是我们所需要的反弹效果。所以我们需要在“TweenLite.to()”方法中包含“释放”属性,如下:

TweenLite.to(knob, 0.5, {x: knob.origin_x, y:knob.origin_y, ease:Bounce.easeOut});

漏洞

你将能够在上面的SWF中发现一个小故障或漏洞。基于动画的原因,如果你快速轻拍把手并放开它,它便不会有任何反应。而当你快速轻拍多次把手时,那么第一次轻拍所触发的动画便会持续下去。TweenLite将迫使“把手”回到起始点位置。

改善

为了解决这一问题,我们需要在用户轻拍于“操纵杆”MovieClip时强制停止动画的运行。而这就需要我们获得能够代表动画的标识符。

所以我们便开始创造“TweenLite”的标识符(变量)。即我们需要在“操纵杆”类中创造这一新变量:

private var knob_tween:TweenLite;

现在,我们使用“TweenLite.to()”所执行的动画将被定义为这一属性。我们还需要适当地调整动画的陈述。删除对于静态方法“to()”的调用,并将其改为:

knob_tween = new TweenLite(knob, 0.5, {x: knob.origin_x, y:knob.origin_y, ease:Bounce.easeOut

新属性。“knob_tween”是我们用于强制停止动画的一种方法。来到“mouseDown()”方法并在方法的前端添加以下陈述:

if (knob_tween) { knob_tween.kill(); }

测试并将下图的SWF与之前的进行比较。快速轻拍“操纵杆”MovieClip。并观察行为发生的改变。

这里包括了操纵杆的最终行为。

步骤21:重新设计操纵杆

直至现在,我们只使用了2种颜色的圆圈去表示操纵杆和把手。我并不打算在这一部分教程中过分讲究,因为这是一种主观设计,每个人都能够发挥自己的创造性。我将列举出一些能够适应这一逻辑并加强游戏体验与外观的例子。

例子1(截图)

example_1(from active.tutsplus)

example_1(from active.tutsplus)

例子2(截图)

example_2(from active.tutsplus)

example_2(from active.tutsplus)

例子3(截图)

example_3(from active.tutsplus)

example_3(from active.tutsplus)

步骤22:最终代码

我们将在此回顾每个.as文件的最终代码:

MyApp.as

package com { import flash.display.MovieClip; import com.controls.Joystick; import com.Hero; public class MyApp extends MovieClip { private var joystick:Joystick; private var hero:Hero; public function MyApp() { hero = new Hero(); hero.x = stage.stageWidth/2; hero.y = stage.stageHeight/2; addChild(hero); joystick = new Joystick(30, 30, hero); addChild(joystick); } } }

操纵杆把手.as

package com.controls { import flash.display.MovieClip; public class JoystickKnob extends MovieClip { private var _origin_x:Number; private var _origin_y:Number; public function JoystickKnob() { } public function get origin_x():Number { return _origin_x; } public function set origin_x(o_x:Number):void { _origin_x = o_x; } public function get origin_y():Number { return _origin_x; } public function set origin_y(o_y:Number):void { _origin_y = o_y; } } }

主角.as

package com { import flash.display.MovieClip; import flash.events.Event; public class Hero extends MovieClip { private var walk_speed = 2; public var move_left:Boolean = false; public var move_up:Boolean = false; public var move_right:Boolean = false; public var move_down:Boolean = false; public function Hero() { this.addEventListener(Event.ENTER_FRAME, heroMove); } private function heroMove(event:Event):void { if (move_left && move_up) { this.rotation = -45; } else if (move_right && move_up) { this.rotation = 45; } else if (move_left && move_down) { this.rotation = 225; } else if (move_right && move_down) { this.rotation = 135; } else if (move_right) { this.rotation = 90; } else if (move_left) { this.rotation = -90; } else if (move_up) { this.rotation = 0; } else if (move_down) { this.rotation = 180; } if (move_left) { this.x -= walk_speed; } if (move_up) { this.y -= walk_speed; } if (move_right) { this.x += walk_speed; } if (move_down) { this.y += walk_speed; } } } }

操纵杆.as

package com.controls { import flash.events.Event; import flash.display.MovieClip; import flash.events.MouseEvent; import flash.geom.Rectangle; import com.controls.JoystickKnob; import com.Hero; import com.greensock.*; import com.greensock.easing.*; public class Joystick extends MovieClip { private var my_x:Number; private var my_y:Number; private var knob:JoystickKnob; private var hero:Hero; private var knob_tween:TweenLite; public function Joystick(margin_left:Number, margin_bottom:Number, hero_mc:Hero) { my_x = margin_left; my_y = margin_bottom; hero = hero_mc; if (stage) { init(); } else { addEventListener(Event.ADDED_TO_STAGE,init); } } private function init(e:Event=null):void { if (hasEventListener(Event.ADDED_TO_STAGE)) { removeEventListener(Event.ADDED_TO_STAGE,init); } this.x = my_x + this.width / 2; this.y = stage.stageHeight – my_y – this.height / 2; knob = new JoystickKnob(); knob.x = 0; knob.y = 0; knob.origin_x = 0; knob.origin_y = 0; addChild(knob); this.addEventListener(MouseEvent.MOUSE_DOWN, snapKnob); knob.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown); stage.addEventListener(MouseEvent.MOUSE_UP, mouseReleased); knob.buttonMode = true; } private function snapKnob(event:MouseEvent):void { knob.x = this.mouseX; knob.y = this.mouseY; mouseDown(null); } private function mouseDown(event:MouseEvent):void { if (knob_tween) { knob_tween.kill(); } this.addEventListener(Event.ENTER_FRAME, knobMoved); knob.startDrag(false,new Rectangle( - this.width / 2, - this.height / 2,this.width,this.height)); } private function knobMoved(event:Event):void { // LEFT OR RIGHT if (knob.x > 20) { hero.move_right = true; hero.move_left = false; } else if (knob.x < -20) { hero.move_right = false; hero.move_left = true; } else { hero.move_right = false; hero.move_left = false; } // UP OR DOWN if (knob.y > 20) { hero.move_down = true; hero.move_up = false; } else if (knob.y < -20) { hero.move_down = false; hero.move_up = true; } else { hero.move_down = false; hero.move_up = false; } } private function mouseReleased(event:MouseEvent):void { knob.stopDrag(); hero.move_left = false; hero.move_up = false; hero.move_right = false; hero.move_down = false; if (this.hasEventListener(Event.ENTER_FRAME)) { this.removeEventListener(Event.ENTER_FRAME, knobMoved); } mo

ver(); } private function mover():void { knob_tween = new TweenLite(knob, 0.5, {x: knob.origin_x, y:knob.origin_y, ease:Bounce.easeOut}); } }

步骤27:总结

本篇教程是关于如何通过添加屏幕控制而创造出一款触屏游戏。

而不同游戏类型也将需要有所针对地改变主角的移动逻辑。例如自上而下视角的汽车控制(停车场类游戏),平台游戏/横向卷轴游戏,益智游戏以及其它休闲游戏。

游戏邦注:原文发表于2011年2月2日,所涉事件和数据均以当时为准。

本文来源:原文链接 英文链接

无觅相关文章插件,快速提升流量