使用FLEX和 Actionscript 开发FLASH游戏(三)-2


使用FLEX和 Actionscript 开发FLASH游戏(三)-2
2010年07月10日
  for each(var gameObject:GameObject in gameObjects)
  {
  //this is a bad idea…
  gameObjects.addItemAt(1,new GameObject());
  gameObjects.addItemAt(2,new GameObject());
  }
  这不仅仅是限于ActionScript或者FLEX,许多编程语言特别地防止在某个集合上循环时改变它的元素的值。即使可能在某个循环时改变集合的值,这仍然是一个错误的做法,因为如果某个地方错了的话代码会变得非常难以调试。我们通过下面方式避免这个错误:把所有刚刚生成的游戏对象添加到newGameObjects集合(使用addGameObject函数)以及把所有被终止的游戏对象添加到removedGameObjects集合(使用removeGameObject函数)。这两个集合在我们进入循环之前通过insertNewGameObjects和DeleteRemovedGameObjects这两个函数与主要的gameObjects集合同步了。
  我们给startup函数增加了一段代码来生成和初始化一个bounce对象。这个对象不是最终游戏的一部分,但是将作为一个示范来说明怎样来继承一个GameObject类来生成一个游戏的元素。Bounce类的代码将在下面详细说明。
  我们的shutdown函数原来是一个空语句函数,现在调用了一个shutdownAll函数。shutdownAll函数在所有生成的游戏对象上依次调用shutdown函数。通过这种方法我们在离开游戏状态时(在我们的应用程序类里通过exitGame函数)通过能够只调用一次GameObjectManager的shutdown函数就可以清理整个GameObjects。
  enterFrame函数升级后包含了调用insertNewGameObjects函数和removeDeletedGameObjects函数,这两个函数我们在前面已经提到,它们使得gameObjects集合反映了任何被开始或者被终结的GameObjects.我们也在gameObjects集合上循环,在所有的GameObjects上调用enterFrame函数。GameObject类(包括它被继承的类)在enterFrame函数这里升级它自身。例如一个敌人对象在调用enterFrame函数时将改变它在屏幕上的位置。最终我们调用drawObjects函数,它将在每个GameObject矩形化backBuffer然后调用copyToBackBuffer函数。正是通过copyToBackBuffer函数一个GameObject对象将自己绘制在屏幕上。现在我们已经知道GameObjectManager怎么管理一个GameObject的集合,现在让我们看看GameObject类。
  GameObject.as
  package
  {
  import flash.display.*;
  import flash.events.*;
  import flash.geom.*;
  /* The base class for all objects in the game */
  public class GameObject
  {
  //object position
  public var position:Point=new Point(0,0);
  //higher zOrder objects are rendered on top of lower ones
  public var zOrder:int=0;
  //the bitmap data to display
  public var graphics:GraphicsResource=null;
  //true if the object is active in the game
  public var inuse:Boolean=false;
  public function GameObject()
  {
  }
  public function startupGameObject(graphics:GraphicsResource,positi on:Point,z:int=0):void
  {
  if(!insue)
  {
  this.graphics=graphics;
  this.zOrder=z;
  this.position=position.clone();
  this.inuse=true;
  GameObjectManager.Instance.addGameObject(this);
  }
  }
  public function shutdown():void
  {
  if(!inuse)
  {
  graphics=null;
  inuse=false;
  GameObjectManager.Instance.removeGameObject(this);
  }
  }
  public function copyToBackBuffer(db:BitmapData):void
  {
  db.copyPixels(graphics.bitmap,graphics.bitmap.rect ,position,graphics.bitmapAlpha,new Point(0,0),true);
  }
  public function enterFrame(dt:Number):void
  {
  }
  }
  }
  这个类的目的是被继承以生成更多特定的游戏元素,例如:子弹、游戏者、敌人等等。它有4个属性。位置属性仅仅定义了GameObject在屏幕上的位置。坐标(0,0)代表一个屏幕左上角的位置,坐标(1,1)代表右下角的位置。zOrder属性定义了屏幕上物体的高度。一个有着低的zOrder的游戏对象(例如地面上的建筑物)将被画在一个有着高的zOrder的游戏对象(比如游戏者)下面。图形属性是图形资源的引用,后面再进行阐述。图形资源是要画到后台缓冲器上面的图片。最后inuse属性仅仅是对象在游戏中活跃的标志。我们将使用这个属性来允许后面的资源池的使用。
  startupGameObject和shutdown两个函数起初应该看起来差不多。shutdown和startup 函数对在我们增加更多的类时将是一个共同主题。在GameObject里面他们仅仅是初始化变量,以及从GameObjectManager维护的集合里面添加或者删除游戏对象。copyToBackBuffer函数取出存储在图形属性里的图片,并把他们复制到后台缓冲器。enterFrame函数在这里是空的,这是因为游戏对象的目的是被更多特定的类继承,而且正是这些特定的类将在enterFrame函数里面增加逻辑语句。Bounce类是一个如何这样做的例子。
  使用FLEX和Actionscript开发FLASH 游戏-嵌入资源和增加游戏元素(第四页,共四页)
  Bounce.as
  package
  {
  import flash.geom.*;
  import mx.core.*;
  public class Bounce extends GameObject
  {
  //movement speed of the bouncing object
  protected static const speed:Number=100;
  //direction that the bouncing object should move(1 for right/down,-1 for left/up)
  protected var direction:Point=new Point(1,1);
  public function Bounce()
  {
  super();
  }
  public function startupBounce():void
  {
  super.startupGameObject(ResourceManager.BrownPlane Graphics,new Point(0,0));
  }
  override public function shutdown():void
  {
  super.shutdown();
  }
  override public function enterFrame(dt:Number):void
  {
  super.enterFrame(dt);
  position.x+=direction.x*speed*dt;
  position.y+=direction.y*speed*dt;
  if(position.x>=Application.application.width-graphi cs.bitmap.width)
  direction.x=-1;
  else if(position.x=Application.application.height-graph ics.bitmap.height)
  direction.y=-1;
  else if(position.y游戏元素增加了一些专门的逻辑语言。在这里逻辑语言只是仅仅用来使得游戏元素在屏幕里面到处移动。
  Bounce有两个属性。速度定义了游戏对象将在屏幕里面四处多快地移动,方向定义了游戏对象当前在x和y坐标轴移动的方向。
  我们在这个对象里面再一次用到了startup和shutdown函数对。我曾告诉过你他们将是一个共同主题。在这里我们仅仅是继承了GameObject的startup和shutdown函数。
  enterFrame函数用来在绘制循环中更新对象本身。Bounce对象在它撞到屏幕边缘之前只是仅仅做直线运动,然后当撞到后作反方向运动。这不是太灵巧,但是Bounce类在最终游戏不会出现;它唯一的目的是作为一个简单的示范来显示GameObject时如何被继承的。
  最后的两个类用来让我们开始在屏幕上绘制,它们是ResourceManager和GraphicsResource。
  资源管理是游戏的一个重要的方面。你将如何包装你游戏中的图形和声音效果?你怎样载入它们?它们存储在哪里?这些是简单的问题,但是包含着巨大的影响。粗略地说Flex给你三个选项来访问图形和声音资源。第一个:从本地磁盘载入它们。虽然这是载入资源的传统方式,对于一个在网络上玩的游戏这不是一个可行的方法。基于此Flex也允许你载入存储在网络服务器上的资源。但是虽然这使得最终用户不必在本地磁盘上保存任何东西,但是它也意味着游戏SWF文件和其他的游戏资源必须作为单独分开的文件来存储。谢天谢地Flex提供了第三种选项:直接把资源嵌入到最终的SWF文件。
  嵌入一个资源你可以使用嵌入(Embed)标签。只要你嵌入的文件被Flex识别(包括海量的图形格式,还有声音的MP3格式)Flex将把文件直接编译进最终的SWF文件里,而且通过一个类来列出文件的内容。
  ResourceManager被用来作为嵌入和访问游戏资源的地方。它根本没有任何函数:它唯一的目的是列出描述嵌入资源的属性。这里我们定义了1个图形资源:brownplane.png图形。
  ResourceManager.as
  package
  {
  import flash.diaplay.*;
  public final class ResourceManager
  {
  [Embed(source="../media/brownplane.png")]
  public static var BrownPlane:Class;
  public static var BrownPlaneGraphics:GraphicsResource=new GraphicsResource(new BrownPlane        ());
  }
  }
  为了使用嵌入的图形我们需要从原始图片中分离出alpha(或者即透明的)层。如果你回顾下在GameObject类中的coptToBackBuffer函数你将知道copyPixels函数即使用了GraphicsResource对象的bitmap属性也使用了它的alphaBitmap属性。从一个嵌入的图片上提取和展示这些元素是GraphicsResource类的唯一目的。现在让我们看下GraphicsResource类。
  GraphicsResource.as
  package
  {
  import flash.display.*;
  public class GraphicsResource
  {
  public var bitmap:BitmapData=null;
  public var bitmapAlpha:BitmapData=null;
  public function GraphicsResource(image:DisplayObject)
  {
  bitmap=createBitmapData(image);
  bitmapAlpha=createAlphaBitmapData(image);
  }
  protected function createBitmapData(image:DisplayObject):BitmapData
  {
  var bitmap:BitmapData=new BitmapData(image.width,image.height);
  bitmap.draw(image);
  return bitmap;
  }
  protected function createAlphaBitmapData(image:DisplayObject):BitmapD ata
  {
  var bitmap:BitmapData=new BitmapData(image.width,image.height);
  bitmap.draw(image,null,null,flash.display.BlendMod e.ALPHA);
  return bitmap;
  }
  }
  }
  在上面提到GraphicsResource有两个属性:bitmap和bitmapAlpha。这些属性通过createBitmapData和createAlphaBitmapData函数从嵌入的图形中提取出来传给构造器。一旦它们被提取出来它们就有了一个方便使用的形式,在GameObject的copyToBackBuffer函数中调用的copyPixels函数使用。
  那么我们干成了什么?我们在本系列的第一部分和第二部分的基础性工作上嵌入了资源(ResourceManager和GraphicsResource),生成了更多特定游戏对象的基本类(GameObject),最后把它们全部整合起来给屏幕增加了一个移动的对象(Bounce)。
  在本系列的第四部分我们将增加一个游戏者能控制的对象,除此之外还生成一个可供游戏者在其上飞行的滚动的背景。
  在http://flexfighters.sourceforge.net/flexfighters3. html可查看最终结果,从https://sourceforge.net/project/showfiles.php?grou p_id=241490&package_id=293860&release_id=631869可下载资源。
  
  

猜你喜欢

转载自djjrq21t.iteye.com/blog/1571652
今日推荐