用新浪微博登录

只需一步,快速搞定

 找回密码
 立即注册

用新浪微博登录

只需一步,快速搞定

查看: 2138|回复: 1
打印 上一主题 下一主题

一个完全使用AS2编制的飞机游戏之制作详解

[复制链接]

该用户从未签到

667

主题

2111

帖子

5570

积分

LV 11.会员

MS爱好者!!!!

积分
5570

社区居民偶尔光临工蜂最爱沙发在线达人社区平民做个有钱人略有小成常驻会员忠实会员

跳转到指定楼层
楼主
发表于 2012-3-15 11:51:23 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式 |          
作者自己的水平应该是很高的了,但从游戏的模式上而言,这个游戏并没有太多的创新,仍旧是无限循制,
不过想法上已经相当完整了,有这样一个很好的开发习惯,想做大的东东,就不会无从下手了。
作者写此文章的主要目的是在于介绍给大家如何真正用面向对象的AS2来写游戏,
所以,从这个角度而言,这篇文章还是相当优秀的,尤其是在国内这方面资料比较馈乏的时候,
这种文章可谓雪中送碳的佳举,我翻译一下,一方面是自己有提高,另一个方面,也算是给闪吧增点辉,给广大的FLASHER做点贡献吧~~~~
(第一次翻国外的东东,所以有什么不地道的地方,敬请高手斧正,英文原文附在第三帖中了.
对了,要是作者本人给你发邮件说想找EmilMatthew收中文版的版权费时,你们就说不认识我啊,呵呵~~~:)
)
这篇文档是我第一个用OOP(面向对象的编程)方法写的AS2游戏。
这个一个标准的空间打击敌人的游戏,有三架敌机和一架游戏者的喷火镭射机。
起初只会有一关,但是设计上可以使得增加关数的可能性变得非常方便。
游戏中会有基本的分数以及生命值。
和别的正在挣扎着实行在FLASH MX2004中的新的ACTIONSCRIPT2.0语法的人一样,
这篇文档也是为了我个人学习的好处。
我会遵照一个合理的传统的OOP设计的结构。
非常感谢并尊重来自http://www.1coinplay.com的Squize让我使用他的小精灵纸(?)来做为这个例子。
1要求文档。
2使用事件。
3类的表格。
4交互的表格。
5试验最初的代码。
6迭代(Iteration)
7测试。
8发布。
*************************************************************************************
要求:
Spaceship:
上下左右移动。
通过空格键来发射镭射。
Enemy:
在一个随机的高度从右移到左。
有三个实例。
当它从左移出屏幕时,重新回到右侧。
BackGround:
从左移到右。
前景要比背景移动的快(视差(PARALLAX))
Laser:
当空格键按下时火焰从飞船中喷出。
Game:
如果射到敌人,游戏者得到分数。
如果飞船撞到敌机,则会损失生命值。
如果游戏者得到了胜利的分数,那个他(她)就赢了,游戏重新开始。
如果损失生命数超过三,游戏结束,游戏者失败。
2使用的事件:
使用的事件是用图表来代表(设计的)要求。它们展示了在游戏中会发生的不同的事件,或者是所有会发生的不同的动作。
这就是你所有所要做的。仅仅是把它们在一张纸上完整的实现(NUT ?),
这张表格能很好的给最终将使用的类及方法一个好的提示。
当你做完这些以后,该是你搞定你会要使用什么类以及这些类需要什么什么属性及方法.
类的表格:
类的表格展示了类之间的关系。
在我们下面的这张表格里:飞船,敌人,镭射及背景类都包含在进了游戏类.
这意味着那些类的实体被在游戏类中声明了。
这被叫做取合或者是“有一层”关系而区别于被描述为“是一种”关系的继承。?
游戏类被取聚合进了我的Flash文件里。
类的描述:
宇宙飞船类
属性或方法 类型 描述
speed Number x变量的增量
moveShip() method 用按键来移动飞船
setShipX(x) setter _x变量获取值的方法
getShipX() getter 返回_x值
setShipY(y) setter _y变量获取值的方法
getShipY() getter 返回_y值
敌机类
属性或方法 类型 描述
enSpeed Number x变量的增量
moveEn() method 随机的移动敌机
setEnX(x) setter _x变量获取值的方法
getEnX() getter 返回_x值
setEnY(y) setter _y变量获取值的方法
getEnY() getter 返回_y值
镭射子弹类
属性或方法 类型 描述
fire() method start 当空格键按下时移动
setLaserX(x) setter _x变量获取值的方法
getLaserX() getter 返回_x值
setLaserY(y) setter _y变量获取值的方法
getLaserY() getter 返回_y值
背景类
属性或方法 类型 描述
scroll() method 从右移到左
setBackX(x) setter _x变量获取值的方法
getBackX() getter 返回_x值
setBackY(y) setter _y变量获取值的方法
getBackY() getter 返回_y值
游戏类
属性或方法 类型 描述
score Number 游戏者的得分
lives Number 游戏者的生命数
checkCollisions() method 碰撞检测
CheckLives(lives) method 如果生命值为0就停止游戏。
checkScore() method 检测并展示分数
交互的表格
交互表格述了通过方法传递的信息来符合我们一开始所提出的要求。
我现在对这项计划是否有效没有任何概念,因为我不知道Flash是否能处理组合。
游戏类包含着其它类并且是游戏的管理者。
但是我并不清楚是否能在一个类中控制一个继承于MovieClip类的子类(的实例).
那好,这里就是这计划,让我们看一下它是否能起作用。
计划不是被放在混凝土里的。如果它们无效,你可以把它们扔掉,或者是修改,甚至从草稿重新开始。
最重要的事情是过程。
通过过程来明确问题并呈现给我们处理问题的方法。这就像给电影的情节串连图版.
你草拟出它,呈现出脚本的想法同时也瞄准了观众的需求。
一旦你把这个都搞定了,你就把它扔在了一边并用本能进行着导演。
你知道故事的背景因为你浏览了情节串连图版的过程。这里也是如此:
上面是我画的一个份交互的表格。
我甚至做了一些改变并意识到一些在类表格中里所遗漏的内容。
就像那个moveship方法需要一个方向(左,右,上,下)并且我能过一个变量dir来传递按了哪个键。
dir可以是string类(“left”)或者是一个字母(1,2,3,4).这并不重要。
测试优先:
我新建了一个新的Flash 文件并创建了一个spaceship_mc(mc),把它连接到库里的ship_mc并把“Spaceship”放进连接(link)AS2 CLASS选项中。
然后在交互面板中我写下了下面的代码:
//连接spaceship_mc
attachMovie("ship_mc", "myShip", getNextHighestDepth());
//声明变量
var enArray:Array; // 现在是空的
var bulletArray:Array; // 空的
var myGame = new Game(myShip , enArray , bulletArray);
//游戏循环
_root.onEnterFrame = function(){
myGame.moveShip("right");
}
Then I wrote minimal code so that the classes would just compile
然后我写下最少量的代码以致能让它刚好编译
class Game{
//游戏类,控制整个游戏并包含其它类的实例。
// 声明变量
var ship:Spaceship;
var enemyArray:Array;
var laserArray:Array;
(译者注:上面最好用Private加以标明,否则就没有封装的意义了)
// 构造函数
function Game(_ship:Spaceship, _enArray:Array, _bullArray:Array){
ship = _ship;
enemyArray = _enArray;
laserArray = _bullArray;
}
(译者注:这个函数最好在头前加Public在尾部加:void,这样子就比较正规了。)
}
然后在Spaceship.as文件里我这样写:
class Spaceship extends MovieClip{
}
然后编译,但是没有错误。
但是那里应该有些错误因为moveShip方法还没有出现?嗯??(译者注:我倒)
在调试中什么也没有出现。
相当讨厌的出错检查。。。噢,好吧。。。
现在我必须写Game.moveShip方法了。。。我会写下它并测试。。。
我写下了moveShip方法并意识到我必须再写一个可以检测哪个键被按下了并传回一个Sring类的dir变量的
chekcKey 方法用以检测按键。
// Game类
// 检测按键的方法:
function checkKey():String{
if(Key.isDown(Key.RIGHT)){
dir = "right";
}
if(Key.isDown(Key.LEFT)){
dir = "left";
}
if(Key.isDown(Key.UP)){
dir = "up";
}
if(Key.isDown(Key.DOWN)){
dir = "down";
}
return dir;
}
// moveship方法
// 1. 检查按键
// 2. 分配变量dir就是在每按下键一次,把dir传给spaceship.move方法
function moveShip(dir:String){
ship.move(dir);
}
编译后并得到了错误。。。
" 行 38: 没有'move'方法."
太棒了,开始得到错误了,(译者注,我再倒),那正是所期待着的要发生的事。
现在写下ship.move方法来清除错误。。。
那就是“测试优先”的想法(作者这样写:主要是这里做的是个小东东,而且主要目的
在于尝试AS2编程,至于诸位自己做项目的时候,用什么模式,还请自己拿捏准哟.)
把方法在一系列的测试中实施直到它们出了问题,然后编写方法直到它符合要求接着移向下一个方法。
我使得飞船移动,这里就是我如何做的。。。
class Game{
//声明变量
var ship:Spaceship;
var enemyArray:Array;
var laserArray:Array;
var dir:String;
// ==== 构造函数 ==============
function Game(_ship:Spaceship, _enArray:Array,
_bullArray:Array){
ship = _ship;
enemyArray = _enArray;
laserArray = _bullArray;
}
// ==== 检查按键的方法 =======
function checkKey():String{
if(Key.isDown(Key.RIGHT)){
dir = "right";
}
else if(Key.isDown(Key.LEFT)){
dir = "left";
}
else if(Key.isDown(Key.UP)){
dir = "up";
}
else if(Key.isDown(Key.DOWN)){
dir = "down";
}
else dir="stop";
//下面这个起作用了
//trace(dir + " - in game.checkey");
return dir;
}
// === 移动飞船的方法 =====
// 1.检查按键
// 2.分配给变量dir相应的方向
// 3 把变量dir的值传进spaceship.move方法中
function moveShip(dir:String){
ship.move(checkKey());
}
} //game类结束
在宇宙飞船类中:
class Spaceship extends MovieClip{
var dir:String;
function move(_dir:String){
dir = _dir;
if(dir=="left") _x -= 20;
if(dir=="right")_x += 20;
if(dir=="up") _y -= 20;
if(dir=="down") _y += 20;
if(dir=="stop"){
_x +=0;
_y +=0;
}
}
} //Spaceship类结束
我在把变量dir传进ship.move方法时没有遇到任何麻烦,然后我尝试试着直接使用checkKey方法,因为它总是返回dir,当然,这个起效了。
然后我不得不加一个stop在其中...无论何时当键按起的时候,飞船的运动有一些可笑,这样的状态一直持继着,直到我在后来能把运动变得平缓为止...
但是我知道我的设计起效了。
我仅仅要作是只是把宇宙飞船(SPACESHIP)的实例传给游戏类的构造函数中。
然后,哈哈,presto(类例于芝麻开门之类的话)...接下来是什么呢?嗯,或许是发射镭射子弹吧。。。好的,让我们走。
发射雷射子弹
这个花了我两天的时间,我几乎不能相信。我持续着错误的子弹发射。。。这里是我发射镭射子弹方法的第一次尝试。
// 在game类中:
// ====== 发射镭射子弹 ========
function fireLaser_old(){
if(Key.isDown(Key.SPACE)){
// set start pt of laser
laserArray[bulletNum]._y = ship.getY();
laserArray[bulletNum]._x = ship.getX();
// if space bar pressed set flag
hasFired = true;
bulletNum++;
if(bulletNum >=5){
bulletNum = 0;
}
}
}
上面的代码已相当接近我最后结束时的状态,最实际的问题是在于movelaser方法。
噢哈哈,我把镭射子弹发射放在了我的FLA中的EnterFrame循环中了...大大的错误...
这必须放在FLA文件的onKeyDown事件中。这就是目前为止的状况
://在fla文件的actions面板中
attachMovie("ship_mc", "myShip", getNextHighestDepth());
var enArray = new Array(3);
var bulletArray = new Array(5);
//连接bullet数组
for(var i =0;i < 5;i++){
attachMovie("laser_mc", "laser"+i, 100 + i);
bulletArray = _root["laser"+i];
}
// 声明并初始化游戏类的实体
// 把飞船, 敌机数组和子弹数组传进去
var myGame = new Game(myShip , enArray , bulletArray);
// ======= 获取键值============ //
someListener = new Object();
someListener.onKeyDown = function () {
myGame.fireLaser();
};
Key.addListener(someListener);
// 游戏循环
_root.onEnterFrame = function(){
myGame.checkKey();
myGame.moveShip(dir);
myGame.moveLaser();
}
这样好了一些,但是仍旧没有得到正确的子弹发射。。。它要比空格键延迟两个键后才发射。
嗯,好吧,这是我这次使用的moveLaser方法:
// ========= move laser ==========//
function moveLaser_old(){
if(hasFired==true){
laserArray[bulletNum]._x += 30;
}
if(laserArray[bulletNum]._x > Stage.width)
{
laserArray[bulletNum]._x = -10;
hasFired = false;
}
} // ============== //
下面是最终(也就是现在)使用的镭射子弹发射方法。
它的运作很简单,得到飞机的位置并传递给子弹。
然后子弹数目开始增加,当数字大于5的时候,它被重新初始化到0。
// ========= FIRE LASER ====== //
function fireLaser(){
if(Key.isDown(Key.SPACE)){
// set start point
laserArray[bulletNum]._y = ship.getY();
laserArray[bulletNum]._x = ship.getX();
// increment the bullet number
++bulletNum;
// if more than 5 bullets , start again at 0
if (bulletNum>5) {
bulletNum = 0;
}
}
}
下面是最终移动子弹的方法,同样是非常的单简。
这个过程遍历所有的子弹,如果有子弹可以提供,就移动它。它仍旧不是很完美,但现在还能凑和着用。
// ======= MOVE LASER ======= //
function moveLaser(){
var bulleti = 0;
while (bulleti<6) {
laserArray[bulleti]._x += 30;
bulleti++;
}
} // ============= //
下面是到目前为止所创建的游戏类:
class Game{
// ========= 声明变量
var ship:Spaceship;
var enemyArray:Array;
var laserArray:Array;
var dir:String;
var bulletNum:Number = 0;
// ==== 构造函数==============
function Game(_ship:Spaceship, _enArray:Array,
_bullArray:Array){
ship = _ship;
enemyArray = _enArray;
laserArray = _bullArray;
}
// ==== 检测键被按下的方法 =======
function checkKey():String{
if(Key.isDown(Key.RIGHT)){
dir = "right";
}
else if(Key.isDown(Key.LEFT)){
dir = "left";
}
else if(Key.isDown(Key.UP)){
dir = "up";
}
else if(Key.isDown(Key.DOWN)){
dir = "down";
}
else dir="stop";
return dir;
}
// === 移动飞船的方法 =====
// 1.检查按键
// 2.分配给变量dir相应的方向
// 3 把变量dir的值传进spaceship.move方法中
function moveShip(dir:String){
ship.move(checkKey());
}
// ========= 发射子弹 ====== //
function fireLaser(){
if(Key.isDown(Key.SPACE)){
// 设置起始位置
laserArray[bulletNum]._y = ship.getY();
laserArray[bulletNum]._x = ship.getX();
// 增加子弹数目
++bulletNum;
// 如果大于5,重新将数目开始于 0
if (bulletNum>5) {
bulletNum = 0;
}
}
}
// ======= 移动子弹 ======= //
function moveLaser(){
var bulleti = 0;
while (bulleti<6) {
laserArray[bulleti]._x += 30;
bulleti++;
}
} // ============= //
} // ------ 游戏类结束 ------- //
下面是Spaceship类和它所使用的 getX 和getY方法:
class Spaceship extends MovieClip{
var dir:String;
// ===== 移动 =========
function move(_dir:String){
dir = _dir;
if(dir=="left") _x -= 20;
if(dir=="right")_x += 20;
if(dir=="up") _y -= 20;
if(dir=="down") _y += 20;
if(dir=="stop"){
_x +=0;
_y +=0;
}
}
// ====== 得到X值 ====
function getX():Number{
return _x;
}
// ======= 得到Y值 =====
function getY():Number{
return _y;
}
} // ====Spaceship类结束
这里是Laser类:
class Laser extends MovieClip{
// ======= 构造函数 ========= //
function Laser(x:Number, y:Number){
_x = x;
_y = y;
}
}
在FLASH MX2004中做好你的敌人MC,然后在链接对话框中,在标识文本框内写下“baddie”,在AS2类文本框中写下“Enemy”。
现在在你的FLA的交互面板中写下下面的脚本,把敌人MC连接到场景中,并把它们放进enemyArray数组中:
(译者注:看来,AS2的ARRAY还是和AS1一样(还有JAVASCRIPT),什么东东都能放啊,这里用的相当的妙。)
// ------ 连接到ENEMY数组 --------- //
for(var j=0;j<3;j++){
attachMovie("baddie", "baddie"+j, 200+j);
enArray[j] = _root["baddie"+j];
enArray[j]._x = 50*j;
enArray[j]._y = 100;
}
这就是到目前为止在我们的 Enemy 类中写的东西:
class Enemy extends MovieClip{
// 把实现的代码写在这里
} // ------- enemy类结束
移动Enemy类
没有,所以我们需要些什么呢 ? 来些变量如何.
让我们回到先前的类表中去看一下我们在文档里能设计些什么.
好的,我们需要速度,所以我把它放进去,并且我们需要一个移动的方法
噢,还有一些我在设计里忘记的东西,一个reset()方法,使敌机从场景的左边移出时或者它们被刺击中时重新回到场景的右边.
我们可以在构造函数里设定初始的速度,这就是我到目前为止所完成的内容:
class Enemy extends MovieClip{
// 声明属性
private var speed:Number;
// ======= 构造函数
function Enemy(){
speed = 20;
}
// ===== 移动
function moveEnemy(){
if(_x<=-30){// 当移出场景左边时
reset();
}
else{
_x -= speed;
}
}
// ====== 重设
function reset()
{
_x = Stage.width+50;
_y = Math.random()*380 + 10;
speed = Math.random()* 10 + 10;
}
} // ----- enemy类结束
通过编译测试它.
啊哈! 凑效了.敌机以在X方向上以10-20像素/帧的速度开始始动.
噢,然后我们会把我们的机子放进game类中,所以把下面的代码放进Game类中.
// 在 Game类中
// 移动敌人
function moveBaddies(){
for(var i=0;i<3;i++){
enemyArray.moveEnemy();
}
}
并且再度确认你有movebaddies方法在你的flash文件中的Enterframe循环中,这使得你的ACTION面板里的代码十分的整齐和干净.
// 循环
_root.onEnterFrame = function(){
myGame.checkKey();
myGame.moveShip(dir);
myGame.moveLaser();
myGame.moveBaddies();
}
碰撞检测
我不是很清楚我将要如何实现它,或许是在游戏类中。
并且要做一些循环...
//在game类中
// 碰撞检测
function collision(){
for(var j = 0; j<6;j++){
for(var k=0;k<3;k++){
if(laserArray[j].hitTest(enemyArray[k])){
trace("enemy hit, no. " + k );
}
}
}
}
并把这里的方法放进我们的FLA文件中的ENTERFRAME事件中去 :
// 循环:
_root.onEnterFrame = function(){
myGame.checkKey();
myGame.moveShip(dir);
myGame.moveLaser();
myGame.moveBaddies();
myGame.collision();
}
制造爆炸效果,当子弹击中敌机的时候,我们想看到爆炸(那是当然的)。
在你的FLASH MX 2004的文件里做一个爆炸的MC。
我只是聚 集了一些烟和雾的图像放在每一帧里,并在最后加一个空白帧,还有一个stop()。
我把这个MC取名叫做“Splode_mc”并且在链接对话框中把它的链接名子叫做"Splode".
所以在磁碰撞的方法里,我应该连接上splode这个MC,重设敌机,然后我们把分数给加上。
// 在 game类中
// 碰撞检测
function collision(){
for(var j = 0; j<6;j++){
for(var k=0;k<3;k++){
if(laserArray[j].hitTest(enemyArray[k])){
// 爆炸效果
_root.attachMovie("splode", "splode", 301);
// 使爆炸作用于敌机的位置
_root.splode._x = enemyArray[k]._x;
_root.splode._y = enemyArray[k]._y;
// 把敌机重设在场景的右边
enemyArray[k].reset();
break;
}
}
}
}
碰撞检测之敌机碰飞船.
现在让我们审视一下敌机我和我们的宇宙飞船之间的碰撞。
我重复利用了sploe_mc,改变了它的颜色及x,y方向的拉伸值,
我们也能够把一个声音的效果加在每一次击中的判定中。
但是我还是把那件是交给你们吧
。// 碰撞检测
function collision(){
for(var j = 0; j<6;j++){
for(var k=0;k<3;k++){
//检查子弹击中敌机
if(laserArray[j].hitTest(enemyArray[k])){
// // 爆炸效果
_root.attachMovie("splode", "splode", 301);
// 使爆炸作用于敌机的位置
_root.splode._x = enemyArray[k]._x;
_root.splode._y = enemyArray[k]._y;
// 把敌机重设在场景的右边
enemyArray[k].reset();
}// end if
// 检查敌机击中飞船
if(enemyArray[k].hitTest(ship)){
_root.attachMovie("splode", "splode", 301);
// 使得爆炸符合飞机的坐标
_root.splode._x = ship._x;
_root.splode._y = ship._y;
// 改变颜色
var my_color:Color = new Color(_root.splode);
my_color.setRGB(0xff0000);
// 改变大小
_root.splode._xscale = _root.splode._yscale = 400;
}
}
}
}
分数以及身命值:
剩下的是什么呢?
分数以生命值.我或许应该做一些文本框,在改变发生的时候去改变它们的TEXT属性。
所以在我们的FLASH MX 2004文件中制做两个文本框,把它们分别取名叫做score_txt和lives_txt.
然后给游戏类增加两个变量,score和lives 并在在我们的构造函数中初始化它们。
// 在 Game 类中
//声明变量
var score:Number;
var lives:Number;
// ==== 构造函数 ==============
function Game(_ship:Spaceship, _enArray:Array,
_bullArray:Array){
ship = _ship;
enemyArray = _enArray;
laserArray = _bullArray;
//初始化子弹及生命值
score = 0;
lives = 10;
}
现在让我们把score及lives变量设置给textfields
// 在 Game 类中
// 碰撞检测
function collision(){
for(var j = 0; j<6;j++){
for(var k=0;k<3;k++){
//检查子弹击中敌机
if(laserArray[j].hitTest(enemyArray[k])){
// 增加分数值并呈现它
score += 10;
_root.score_txt.text = " Score: " + score;
// 爆炸效果
_root.attachMovie("splode", "splode", 301);
// 使爆炸作用于敌机的位置
_root.splode._x = enemyArray[k]._x;
_root.splode._y = enemyArray[k]._y;
// 把敌机重设在场景的右边
enemyArray[k].reset();
}// end if
// 检查敌机击中飞船
if(enemyArray[k].hitTest(ship)){
// 重设敌机,减小生命值
// 显示生命值
enemyArray[k].reset();
lives -= 1 ;
_root.lives_txt.text = " Lives : " + lives;
_root.attachMovie("splode", "splode", 301);
// 使得爆炸符合飞机的坐标
_root.splode._x = ship._x;
_root.splode._y = ship._y;
// 改变颜色
var my_color:Color = new Color(_root.splode);
my_color.setRGB(0xff0000);
// 改变大小
_root.splode._xscale = _root.splode._yscale = 400;
}
}
}
}
在上面的代码中在敌机击中飞船的时候我不得不重设敌机,由于碰撞会持续几帧,所以生命数会持续的减少。
把enemyArray[k].reset() 一行注释掉你会看到生命数持续的减少。
上面所做的是一个相当简单的过程:
1碰撞检测。
2变量值的增加或减少。
3呈现变化的变量值.
这在技术方面对我们而言语是一个有些份量的跳跃,我想,我会把它放在那里一会儿让我们消化消化。
下一步我们将会做一个检查分数的方法用以来检查分数及生命数是否出界,如果是,就结束游戏。
但在呢,让我们体息。下面的注意事项和第一部分一样...
接下来要进入第三部分,在那里,我们将会整理出一个呈现分数的方法并制作一个水平方面移动的背景.
现在我们必须来检查我们的生命数并且当然相应的做出处理。
检查生命数:
在你的FLA文档中
创建两个新帧,并把第一帧的代码放进第二帧f去。
In your fla, make 2 new frames and put the code that was on frame 1 onto frame 2.
添加一个stop();写在代码的开头部分,分别添加在第一帧和第三帧。
在第一帧中,加一个标题,一些说明及一个按纽。
在按纽上写下如下的代码:
on(release){
_root.gotoAndStop(2);
}
在第三帧中加一个动态的文本框来呈现游戏中的结果,并把实例名命名为"result_txt"
添加一个重新开始的按纽,并给按纽写上如下的代码,好让它返回第二帧。
on(release){
_root.gotoAndStop(2);
}
重新回到我们的游戏类中的代码并添加这个方法用以检查剩下多少生命以及处理结果:
// 在Game类中
// ============检查生命值=============== //
function checkLives() {
if (lives<=0) {
// 擦屏
// 重新移动mc对象
ship.removeMovieClip();
for(var i=0;i<enemyArray.length;i++){
enemyArray.removeMovieClip();
}
// 设定文本框的文字量示位置
_root.result_txt.autoSize = "left";
// 展示分数(Good)
_root.result_txt.text =
"You have scored "+score+" . Congratulations.";
// 跳转至结果的图像面.
_root.gotoAndStop(3);
}
}
移动背景
我们此刻有两个选择。
我们可以只在我们的FLASH里做一个移动的背景动画或者是
做一个Background类并把移动的方式写在其中.
好吧,我决定做一个Background类并把移动的方式写在其中.
首先我做了4个mc,大小上两倍于舞台的宽度,高度与舞台一致。
我的做成了1400*400大小,我准备在我的背景中使用视差.
最近的背景会比较远的被放置在后面的背移动的快.
我把这些MC命名分别为sky,far,mid,和fore.
这里就是BackGround类了。
class Background {
// ----- 初始化背景 --- //
function initBack() {
_root.attachMovie("sky", "sky", 1);
_root.attachMovie("far", "far", 2);
_root.attachMovie("mid", "mid", 3);
_root.attachMovie("fore", "fore", 4);
}
// ========== 移动背景 ==== //
function moveBack(){
// sky移动
if(_root.sky._x <= -Stage.width){
_root.sky._x = 0;
}
_root.sky._x -= 2;
// far前景移动
if(_root.far._x <= -Stage.width){
_root.far._x = 0;
}
_root.far._x -= 4;
// mid移动
if(_root.mid._x <= -Stage.width){
_root.mid._x = 0;
}
_root.mid._x -= 6;
// fore 移动
if(_root.fore._x <= -Stage.width){
_root.fore._x = 0;
}
_root.fore._x -= 8;
}
//
// ===擦除背景 === //
function cleanBack(){
_root.sky.removeMovieClip();
_root.far.removeMovieClip();
_root.mid.removeMovieClip();
_root.fore.removeMovieClip();
}
}
注意到我有三个方法:
initBack() - 在这里我把背景剪辑加载到了时间轴上
moveBack() -用不同的速度来移动背景对象
cleanBack() - 当生命数为0时,移除所有的背景对象。
在Game类中增加back变量,并改变构造函数把背景对象实体给传进去
.// 在Game中
// 声明变量
var back:Background;
//...构造函数
function Game(_ship:Spaceship, _enArray:Array,
_bullArray:Array,_back:Background) {
ship = _ship;
enemyArray = _enArray;
laserArray = _bullArray;
back = _back;
score = 0;
lives = 10;
}
现在我们需要来初始化我们的背景。
在game类中,在initGame方法中,初始化背景:
// 在Game中
// --- 初始化 ----------- //
function initGame(){
back.initBack();
}
然后移动它:
//在Game中
// == 移动背景 ===== //
function moveBackground(){
back.moveBack();
}
//在我们的fla中
// 游戏循时
_root.onEnterFrame = function(){
myGame.checkKey();
myGame.moveShip(dir);
myGame.moveLaser();
myGame.moveBaddies();
myGame.collision();
myGame.checkLives();
myGame.moveBackground();
}
固定我们的分数并呈现.
现在所有都做的很好,但是我们看不现展示出的分数及生命脉数。
那是因为我们的文本框是在root层(level),而背景则是在1-4层,所以root层被覆盖了。
所以我们现在要做是增加一个动态检测,并把它们放在一个更高的层次上。
把这一等增加在游戏类中我们声明变量的地方:
var myformat:TextFormat;
这将会使得我们在后面去风格化我们的文本框,并且在initGame(初始化游戏)的方法中添加动态文本框:
// 在Game类中
// --- 初始化----------- //
function initGame(){
back.initBack();
// 创建一个文本框并设置好格式
_root.createTextField("score_txt",501,20,10,100,50);
myformat = new TextFormat();
myformat.color = 0xff0000;
myformat.size =20;
_root.score_txt.text = "Score : " + score;
_root.score_txt.setTextFormat(myformat);
//初始化显示生命值的文本框
_root.createTextField("lives_txt", 502, 600,10, 100, 30);
_root.lives_txt.text = "Lives : " + lives;
_root.lives_txt.setTextFormat(myformat);
}
删除我们放在场景中的广西文本框并进行子弹和敌机以及敌机和主机间的碰撞检测。
// 在Game类中
// 碰撞检测 ...
// 子弹击中敌机
score += 10;
_root.score_txt.text = " Score: " + score;
_root.score_txt.setTextFormat(myformat);
// ...
// 敌机击中宇宙飞船
lives -= 1;
_root.lives_txt.text = " Lives : "+lives;
_root.lives_txt.setTextFormat(myformat);
// ...
擦除
当游戏结束的时候,我们仍旧需要把场景从游戏场景中移出。
所以我做了一个新的方法来做这项工作:
// 在 Background 类中
// ===擦除背景=== //
function cleanBack(){
_root.sky.removeMovieClip();
_root.far.removeMovieClip();
_root.mid.removeMovieClip();
_root.fore.removeMovieClip();
}
现在把这一行checkLives()方法添加进Game类中:
// 在Game 类中
// 在 CheckLives 的方法里
if(lives<=0){
// ...
back.cleanBack();
// ...
}
还剩下要做:
这个游戏还远没有完成。
对于我来说这是编程的一次练习并且我忽略了很多游戏性方面的因素,视觉上审还将美角度的效果以及别的一些东西。
这就是能被添加的东西:
声间---子弹射击,碰撞。
更多的关数,更大和更坏的敌人(译著注:作者在这里"更坏"用的是badder~~~~)
一张最高成绩表单
把按纽的代码写进游戏类中
难道没有一些别的什么东西吗?就凭你的想象了.
回复

使用道具 举报

该用户从未签到

667

主题

2111

帖子

5570

积分

LV 11.会员

MS爱好者!!!!

积分
5570

社区居民偶尔光临工蜂最爱沙发在线达人社区平民做个有钱人略有小成常驻会员忠实会员

沙发
 楼主| 发表于 2012-3-15 11:52:11 | 只看该作者
常见的飞机发射子弹的控制
只随便画了方块表示飞机,小矩形条表示子弹
space(空格键)发射子弹.
主要代码:
var i = 0;//初始变量
fly.time = getTimer();//获取时间
fly.onEnterFrame = function() {
if (Key.isDown(Key.SPACE) and getTimer()-this.time>200) {
//按下空格或者两次按键的时间差>200
this.time = getTimer();
bullet();
}
};
function bullet() {
B = this.attachMovie("bullet", "bullet"+i, i++);//调库中的子弹
B._x = fly._x;
B._y = fly._y+20;//设置子弹的初始位置
B.onEnterFrame = function() {
this._y -= 10;//子弹逐桢移动距离10
if (this._y<0) {
this.removeMovieClip();//如果子弹超出屏幕,就删除
}
};
}
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

     
    Archiver|手机版|小黑屋|( 沪ICP备12034951号 )

GMT+8, 2024-4-28 00:00 , Processed in 0.122025 second(s), 28 queries .

© 2001-2011 Powered by Discuz! X3.1

快速回复 返回顶部 返回列表