Flash Game Development with Flex and Actionscript(No.7)

In part 6 we added collision detection. In part 7 we will add animations to allow us to include some nice explosions.

 

在第六部分我们已经添加了碰撞探测,在第七部分里我们将添加一个爆炸的动画在里边。

 

In part 6 we introduced collision detection, which allowed us to destroy and crash into the enemies on the screen. But the enemies just disappeared, which was a little unsatasifying. In this article we will add animations, which in turn will allow us to include some nice explosions.

 

在第六章里我们已经介绍了碰撞探测,在消灭或撞到敌人时会在屏幕上显示结果,碰撞探测延伸一下就是在什么情况下出现这个结果。

 

If there is one thing Flash is famous for, it's animation. Flex does allow you to use the same vector based animations that have been so popular with Flash, however for our game we will be using good old frame based animations. There are two reasons for this. The first is that frame based animation is easier to create, and more applicable to the style of game we are making. The second is that I am not an artist and have to make do with the free artwork that I can find out on the web, which in this case is frame based :).

 

The image above shows what I mean by frame based animation. It is a series of frames that are displayed in sequence to produce an animation. Have you ever drawn a little animation in the corners of your textbook at school? It's the same concept.

To implement animaions we first need to make some changes to the GraphicsResource class. Lets take a loot at that now.

 

上面展示的这张图就是我们做动画时需的帖图。

GraphicsResource.as

package

{

import flash.display.*;

public class GraphicsResource

{

public var bitmap:BitmapData = null;

public var bitmapAlpha:BitmapData = null;

public var frames:int = 1;

public var fps:Number = 0;

public function GraphicsResource(image:DisplayObject, frames:int = 1, fps:Number = 0)

{

bitmap = createBitmapData(image);

bitmapAlpha = createAlphaBitmapData(image);

this.frames = frames;

this.fps = fps;

}

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):BitmapData

{

var bitmap:BitmapData = new BitmapData(image.width, image.height);

bitmap.draw(image, null, null, flash.display.BlendMode.ALPHA);

return bitmap;

}

}

}

 

The changes here are quite simple. We add two properties: frames and fps. The frames property is a count of how many frames of animation are included in the image held by the GraphicsResource. Using the explosion image above as an example, the frames would be set to 7. The fps property defines the frames per second that the animation will play.

 

这里的改动是相当简单的。我们只添加了两个属性:帖和帖频。帖属性就是动画里需要多少张图片。就拿上边的这个爆炸图片来说吧,它的帖为7.帧频的定义就是在每秒里要显示多少帖。

 

The GameObject class does not know about animations. If you initialized a GameObject with the image above, the entire image would be displayed on the screen rather than an animated sequence. To enable animations we need to create a new class: AnimatedGameObject. Lets look at that code now.


AnimatedGameObject.as

 

package

{

import flash.display.*;

import flash.geom.*;

import mx.collections.*;

public class AnimatedGameObject extends GameObject

{

static public var pool:ResourcePool = new ResourcePool(NewAnimatedGameObject);

protected var frameTime:Number = 0;

protected var currentFrame:int = 0;

protected var frameWidth:int = 0;

protected var playOnce:Boolean = false;

static public function NewAnimatedGameObject():AnimatedGameObject

{

return new AnimatedGameObject();

}

public function AnimatedGameObject()

{

}

public function startupAnimatedGameObject(graphics:GraphicsResource, position:Point, z:int = 0, playOnce:Boolean = false):void

{

this.playOnce = playOnce;

this.frameWidth = graphics.bitmap.width / graphics.frames;

startupGameObject(graphics, position, z);

}

override public function enterFrame(dt:Number):void

{

if (inuse)

{

frameTime += dt;

if (graphics.fps != -1)

{

while (frameTime > 1/graphics.fps)

{

frameTime -= 1/graphics.fps;

currentFrame = (currentFrame + 1) % graphics.frames;

if (currentFrame == 0 && playOnce)

{

shutdown();

break;

}

}

}

}

}

override public function copyToBackBuffer(db:BitmapData):void

{

if (inuse)

{

var drawRect:Rectangle = new Rectangle(currentFrame * frameWidth, 0, frameWidth, graphics.bitmap.height);

db.copyPixels(graphics.bitmap, drawRect, position, graphics.bitmapAlpha, new Point(drawRect.x, 0), true);

}

}

override protected function setupCollision():void

{

collisionArea = new Rectangle(0, 0, frameWidth, graphics.bitmap.height);

}

}

}

Like any other game resource, the AnimatedGameObject class extends GameObject. To play an animation we override 3 of GameObjects functions: enterFrame, copyToBackBuffer and setupCollision.

During enterFrame an AnimatedGameObject keeps a track of how long it has been since the last frame was played. Once this reaches the value defined by the fps property of the GraphicsResource the AnimatedGameObject moves to the next frame. There is also a playOnce property, which if set to true triggers the AnimatedGameObject to remove itself from the game once one complete animation has been played. This will be useful for creating effects (like an explosion) that play once and should then dissappear. It allows you as a coder to create a kind of "fire and forget" object in the game that will clean itself up.

The copyToBackBuffer has been modified slightly from the same code in the GameObject to allow it to only copy a section of the image referenced by the grahipcs property. This section relates to the current frame, and as the section that is moves from left to right we appear to get an animation on the screen.

Finally we have overridden the setupCollision function to define a collisionArea that is the size of one animated frame as opposed to the size of the whole image.

The rest of the code here (like the resource pooling and startup/shutdown functions) have been discussed in previous articles, and their application here follows the same mentality.

We also need to make some changes to the ResourceManager to accomodate the extra information required by an animation. Lets take a look at that now.

 

ResourceManager.as

 

package

{

import flash.display.*;

public final class ResourceManager

{

[Embed(source="../media/brownplane.png")]

public static var BrownPlane:Class;

public static var BrownPlaneGraphics:GraphicsResource = new GraphicsResource(new BrownPlane(), 3, 20);

[Embed(source="../media/smallgreenplane.png")]

public static var SmallGreenPlane:Class;

public static var SmallGreenPlaneGraphics:GraphicsResource = new GraphicsResource(new SmallGreenPlane(), 3, 20);

[Embed(source="../media/smallblueplane.png")]

public static var SmallBluePlane:Class;

public static var SmallBluePlaneGraphics:GraphicsResource = new GraphicsResource(new SmallBluePlane(), 3, 20);

[Embed(source="../media/smallwhiteplane.png")]

public static var SmallWhitePlane:Class;

public static var SmallWhitePlaneGraphics:GraphicsResource = new GraphicsResource(new SmallWhitePlane(), 3, 20);

[Embed(source="../media/bigexplosion.png")]

public static var BigExplosion:Class;

public static var BigExplosionGraphics:GraphicsResource = new GraphicsResource(new BigExplosion(), 7, 20);

[Embed(source="../media/smallisland.png")]

public static var SmallIsland:Class;

public static var SmallIslandGraphics:GraphicsResource = new GraphicsResource(new SmallIsland());

[Embed(source="../media/bigisland.png")]

public static var BigIsland:Class;

public static var BigIslandGraphics:GraphicsResource = new GraphicsResource(new BigIsland());

[Embed(source="../media/volcanoisland.png")]

public static var VolcanoIsland:Class;

public static var VolcanoIslandGraphics:GraphicsResource = new GraphicsResource(new VolcanoIsland());

[Embed(source="../media/twobullets.png")]

public static var TwoBullets:Class;

public static var TwoBulletsGraphics:GraphicsResource = new GraphicsResource(new TwoBullets());

[Embed(source="../media/cloud.png")]

public static var Cloud:Class;

public static var CloudGraphics:GraphicsResource = new GraphicsResource(new Cloud());

}

}

 

As you can see all we have done is to add values for frames and fps in the GraphicsResource constructor for those images that will now be animations.

The final step is to modify the game elements that should now be animated to extend the AnimatedGameObject class instead of GameObject, and to create some explosions when we destroy a plane.

Both the Player and Enemy classes will be animated, and both will create an explosion when they are destroyed. The code changes are the same for both classes, so I will show only the new Enemy class. You can download the source code at the end of the article to see the changes made to the Player class.

Enemy.as

package

{

import flash.geom.Point;

import mx.core.*;

public class Enemy extends AnimatedGameObject

{

static public var pool:ResourcePool = new ResourcePool(NewEnemy);

protected var logic:Function = null;

protected var speed:Number = 0;

static public function NewEnemy():Enemy

{

return new Enemy();

}

public function Enemy()

{

super();

}

public function startupBasicEnemy(graphics:GraphicsResource, position:Point, speed:Number):void

{

super.startupAnimatedGameObject(graphics, position, ZOrders.PlayerZOrder);

logic = basicEnemyLogic;

this.speed = speed;

this.collisionName = CollisionIdentifiers.ENEMY;

}

override public function shutdown():void

{

super.shutdown();

logic = null;

}

override public function enterFrame(dt:Number):void

{

super.enterFrame(dt);

if (logic != null)

logic(dt);

}

 

protected function basicEnemyLogic(dt:Number):void

{

if (position.y > Application.application.height + graphics.bitmap.height )

this.shutdown();

position.y += speed * dt;

}

override public function collision(other:GameObject):void

{

var animatedGameObject:AnimatedGameObject = AnimatedGameObject.pool.ItemFromPool as AnimatedGameObject;

animatedGameObject.startupAnimatedGameObject(

ResourceManager.BigExplosionGraphics,

new Point(

position.x + graphics.bitmap.width / graphics.frames / 2 - ResourceManager.BigExplosionGraphics .bitmap.width / ResourceManager.BigExplosionGraphics.frames / 2,

position.y + graphics.bitmap.height / 2 - ResourceManager.BigExplosionGraphics .bitmap.height / 2),

ZOrders.PlayerZOrder,

true);

this.shutdown();

}

}

}

 

By extending AnimatedGameObject instead of GameObject we allow the Enemy class to be animated. This also requires calling super.startupAnimatedGameObject instead of super.startupGameObject in our startup function.

The only other change is in the collision function, where we create an AnimatedGameObject to represent the explosion. Notice that we set playOnce to true in the constructor. This means that the explosion will be created, then play through once before removing itself from the game.

Animations add a whole new level of detail to a game. By creating the AnimatedGameObject class we now have the ability to quickly and easily add animated object to the game. The only thing missing now are some sound effects, which we will add in part 8.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值