Space Game源码+教程

Space Game源码+教程


源文件更新了,修正了几个bug。

给 代码加注释的时候又发现了几处冗余,所以可能源文件和贴出来的 代码不太一样,不过也不影响。
我OOP还不是很熟,所以可能很多地方还不完善。不足之处请一定提出来。

这个 游戏是个飞行 游戏,模仿老外的一个 游戏做的。因为这个 游戏很适合用oop来完成,所以练练手。

Q: 不规则碰撞。
A: 飞机上有3个红点,我只检测了红点的碰撞,使用hitTestPoint,注意前两个 参数为全局坐标,要把本地坐标转化为全局坐标,最后一个 参数设置为true。
可以根据需要增加到10个点,这样就更好了。


Q:键盘监听在什么上面好?
A:以前由于键盘是控制飞机的,所以我把键盘有关的代码放在飞机这个类里。
但是现在想想,代码放在 gameStage这个类里比较好,监听是当然是放在放在stage上的。

Q:游戏如何实现那个有惯性的飞机呢?
A:这个很容易还是x=x+dx,y=y+dy来 缓动控制x,y的坐标。(我叫他 缓动控制,意思是值不是跳跃的、是连续的、 缓动变化的)
在加上使用dx=dx+fx,dy=dy+fy 来缓动控制一下dx,dy就能实现这种惯性效果了。

Q:如何使用继承?
A:MovieClip <--MoveObject <--Plane
                                            <--Bullet
                                             <--Stone<--stone_small

Q:当延时调用方法的时候需要注意什么
A:要使用标志变量来保证同时只有一个计时器(或者说只有一个方法将被延时调用)

Q:如何检测按键是否按下?
A:Tools类提供了这个方法。请看 源码



======================= 注释讲解================================

Main.as(文档类):
复制内容到剪贴板
代码:
package{
import flash.display.*;
import flash.ui.Keyboard;
import flash.events.*;
public class Main extends Sprite
{
var gameStage:GameStage=null;
var uiMenu:UiMenu=null;
function Main()
{
Tools.init(stage);//Tools类有静态方法用来检测键盘是否按下,初始化Tools使其可用
uiMenu=new UiMenu(1)//创建游戏封面(为了简化游戏封面与游戏结束画面合并),所以游戏封面可以显示lastLevel(死亡时关数)

addChild(uiMenu);//加入舞台


}


}
}
UiMenu类:被库中的uiMenu这个MC绑定
因为这个类被文档类实例化所以先说这个类
复制内容到剪贴板
代码:
package{
import flash.display.*;
import flash.events.*;
import flash.text.*;

public class UiMenu extends MovieClip
{
var angle=0;

function UiMenu(level)
{
bestlevel_txt.text=String(level);//将传来的参数显示到文本框
button.addEventListener(MouseEvent.CLICK,clickHandle)//为按钮增加监听
}
function clickHandle(e:MouseEvent)//监听句柄
{
Main(root).gameStage=new GameStage();//创建游戏舞台画面
Main(root).addChild(Main(root).gameStage);
Main(root).removeChild(this)//最后remove掉自己,否则root为空了,上边两句不能执行
}

}
}
GameStage类(重要容器):用来接收用户键盘操作,检测游戏结束,并为游戏中的石头、飞机、子弹提供显示容器
复制内容到剪贴板
代码:
package{
import flash.display.*;
import flash.text.*;
import flash.events.*;
import flash.ui.Keyboard;
import flash.media.*;
import flash.utils.*;
public class GameStage extends MovieClip
{
public static const STAGEWIDTH=550;//影片宽度
public static const STAGEHEIGHT=400;//同上

private const angle_step=5;//每次转动的角度
public var plane:Plane;//用来持有飞机
public var stone_arr:Array=new Array();//大石头和小石头都放在这个数组里,数组为0的时候,说明过关了
public var timerKicking=false;//同时只能有一个计时器计时,否则可能导致异步问题(飞机坠毁后和最后的“小”石头爆炸会使用计时器)
private var life_num=4;//生命数
private var level=1;//当前关数

function GameStage()
{

level_txt.text=String(level);//当前关数显示
addEventListener(Event.ADDED_TO_STAGE,addedToStageHandle)
addEventListener(Event.REMOVED_FROM_STAGE,removeStageHandle)

}


function addedToStageHandle(e:Event)
{
stage.focus=stage;//焦点放在stage上,键盘可以被响应
plane=new Plane(200,200,0.2,0.02);//在坐标(200,200)生成0.2推动力和0.02摩擦力的飞机
plane.alpha=0;//
addChild(plane);
//add stones
makeStone(level)//增加关数个石头
stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownHandle);
addEventListener(Event.ENTER_FRAME,enterFrameHandle)
}

function removeStageHandle(e:Event)
{
//bg_sc.stop();
}



function makeStone(level)
{
for(var i=0;i<level;i++)
{
var stone=new Stone( Math.random()*stage.stageWidth,Math.random()*stage.stageHeight, 1+Math.random()*3, Math.random()*360);//产生石头(随机坐标,随机方向,随机速度)
stone_arr.push(stone);//放入数组
stone.alpha=0;//石头透明
addChild(stone);

}
}
function enterFrameHandle(e:Event)//每帧检测键盘
{
if(root==null)//enterframe事件只对显示在舞台上的对象有效,remove以后该事件变为空事件
return;
//key
if(plane.isDead)//飞机死了 就不检测键盘了
return;

if(Tools.isDown(Keyboard.LEFT))//左键按下?
{
plane.rotation=plane.rotation-angle_step;//转
}
if(Tools.isDown(Keyboard.RIGHT))
{
plane.rotation=plane.rotation+angle_step;
}
if(Tools.isDown(Keyboard.DOWN))//下键按下就急停
{
plane.fx=0;
plane.fy=0;
plane.dx=0;
plane.dy=0;
}
//power
if(Tools.isDown(Keyboard.UP))//上键按下?喷火
{
if(plane.fire.currentLabel!="onfire")
plane.fire.gotoAndStop("onfire")
plane.angle_to_fxfy(plane.rotation-90);//并使飞机产生fx,fy两个轴上的推动力
}else
{
plane.fire.gotoAndStop("nothine")
plane.fx=0;//熄火后无力的作用
plane.fy=0;
}
}

//shoot
function keyDownHandle(e:KeyboardEvent)
{
if(e.keyCode==Keyboard.SPACE&&!plane.isDead)//活着的飞机在按下空格键时射击
{
addChild(new Bullet(plane.x,plane.y,10,plane.rotation-90));
}

}

function checkOver()//检测是否全部消灭石头
{
if(stone_arr.length==0&&timerKicking==false)
{
timerKicking=true;
setTimeout(over,3000,"pass");//延时调用over函数,参数pass表明是因为过关而over
}
}

function over(str)
{
timerKicking=false;
if(str=="dead")//因为死亡而over
{
restart();

}else if(str=="pass")//因为过关而over,就增加新的关数和新的石头
{
level++;
level_txt.text=String(level);
makeStone(level)
}
checkOver();
}
function restart()//用来把死的飞机变成活得
{
if(--life_num!=0)//还有命没有
{
life_show.gotoAndStop(6-(life_num));
plane.isDead=false;
plane.gotoAndStop(1);
plane.dx=0;
plane.dy=0;
plane.fx=0
plane.fy=0
plane.alpha=0;
plane.invincibility_time=100;
}
else//没命了回到游戏封面
{
stage.removeEventListener(KeyboardEvent.KEY_DOWN,keyDownHandle);
removeEventListener(Event.ENTER_FRAME,enterFrameHandle)

Main(root).uiMenu=new UiMenu(level)
Main(root).addChild(Main(root).uiMenu);
Main(root).removeChild(this)
}
}
}
}
MoveObject类:一个父类,不要实例化,提供了速度,大小,角度属性和移动方法。飞机、子弹和石头都直接或间接继承这个类
复制内容到剪贴板
代码:
package{
import flash.display.*;
import flash.events.*;

public class MoveObject extends MovieClip
{
var speed=1;
var angle=0;
var dx=0,dy=0;
var size=50;

function MoveObject($x:int,$y:int,$speed:Number,$angle:int,$size:int)
{
x=$x;
y=$y;
speed=$speed;
angle=$angle;
size=$size;
}
function moveme()//移动,溢出屏幕就从另一边回来
{
var halfsize=(size/2)
if(x>GameStage.STAGEWIDTH + halfsize)
x=-halfsize
else if(x<=-halfsize)
x=GameStage.STAGEWIDTH + halfsize

if(y>GameStage.STAGEHEIGHT+halfsize)
y=-halfsize
else if(y<=-halfsize)
y=GameStage.STAGEHEIGHT+halfsize

x=x+dx;
y=y+dy;
}
}
}
Plane类:飞机,被库中plane这个mc绑定
复制内容到剪贴板
代码:
package{
import flash.display.*;
import flash.events.*;
import flash.utils.*;
import flash.geom.*;
public class Plane extends MoveObject//注意继承
{
var fx=0;
var fy=0;
var power=1;
var friction=0.05;
var isDead=false;
var invincibility_time=100;//无敌时间,每帧递减,大于0时无敌,小于0时可以被击毁
function Plane($x:int,$y:int,$power,$friction)
{
super($x,$y,0,0,20)
x=$x;
y=$y;
power=$power;//动力
friction=$friction//摩擦力
addEventListener(Event.ADDED_TO_STAGE,addedToStageHandle);
addEventListener(Event.REMOVED_FROM_STAGE,removeFromStageHandle);
}
function addedToStageHandle(e:Event)
{
addEventListener(Event.ENTER_FRAME,enterFrameHandle)
}

function removeFromStageHandle(e:Event)
{
removeEventListener(Event.ENTER_FRAME,enterFrameHandle)
}

function enterFrameHandle(e:Event)
{
if(root==null)//对象不显示就返回
return;

invincibility_time--;//无敌时间递减
if(invincibility_time<0)
alpha=1-invincibility_time/100//根据无敌时间调整alpha

if(!isDead)//没死
{
changedxdy() //根据fx、fy,得到dx、dy
moveme();//根据dx、dy,得到x、y
hitMe();//检测碰撞
}
}

function hitMe()
{
for(var i=0;i<(root as Main).gameStage.stone_arr.length;i++)
{
if(hitTestPlane(i))//自定义碰撞函数
{
if(!isDead &&(root as Main).gameStage.timerKicking==false&& invincibility_time<0&&(root as Main).gameStage.stone_arr[i].invincibility_time<0)
{
(root as Main).gameStage.timerKicking=true;
isDead=true;
play();
setTimeout((root as Main).gameStage.over,3000,"dead");//延时结束游戏,因为dead结束游戏
return;
}
}
}
}
function hitTestPlane($i):Boolean//自定义碰撞函数,
{
for(var i=1;i<=3;i++)//之检测hitbit1、hitbit2、hitbit3三个子mc的坐标是否与石头碰撞
{
var p=this.localToGlobal( new Point(this["hitbit"+i].x,this["hitbit"+i].y) )//局部坐标转全局坐标
if((root as Main).gameStage.stone_arr[$i].hitTestPoint(p.x,p.y,true))
{
return true;//检测到碰撞返回true
}
}
return false;//没检测到碰撞返回false

}

function angle_to_fxfy($angle:Number)
{
fx = Math.cos($angle/180*Math.PI)*power;
fy = Math.sin($angle/180*Math.PI)*power;
}

function changedxdy()
{
//friction 摩擦力
if(dx>0)
dx-=friction;
else
dx+=friction;

if(dy>0)
dy-=friction;
else
dy+=friction;

//power
dx=dx+fx;
dy=dy+fy;
}


}
}
Stone类:大石头这个类,小石头继承这个类覆盖一些方法
复制内容到剪贴板
代码:
package{
import flash.display.*;
import flash.events.*;
public class Stone extends MoveObject
{
static const INVTIME=100;//无敌时间
var invincibility_time=INVTIME;//当前无敌时间
function Stone($x,$y,$speed,$angle,$size=50)
{
super($x,$y,$speed,$angle,$size)
addEventListener(Event.ADDED_TO_STAGE,addedToStageHandle)
addEventListener(Event.REMOVED_FROM_STAGE,removeFromStageHandle);

}
function addedToStageHandle(e:Event)
{
angle_to_dxdy(angle);//角度得dxdy,只需要一次,因为石头不会改变方向的
addEventListener(Event.ENTER_FRAME,enterFrameHandle);
addEventListener(Event.REMOVED_FROM_STAGE,removeFromStageHandle);
}
function removeFromStageHandle(e:Event)
{
removeEventListener(Event.ENTER_FRAME,enterFrameHandle)
}
function enterFrameHandle(e:Event)
{
if(root==null)//不显示就返回
return;
invincibility_time_deal();
moveme();
rotateme();
}

function invincibility_time_deal()//每帧处理无敌时间
{
invincibility_time--
if(invincibility_time>0)
alpha=1-invincibility_time/INVTIME
}
function removeFromStoneArr(me)//从array中删去指定石头的方法
{
for(var i=0;i&lt;(root as Main).gameStage.stone_arr.length;i++)
{
if((root as Main).gameStage.stone_arr[i]==me)
{
(root as Main).gameStage.stone_arr[i]=(root as Main).gameStage.stone_arr[(root as Main).gameStage.stone_arr.length-1];
(root as Main).gameStage.stone_arr.pop();
}
}
}

function rotateme()//转
{
rotation++
}
function burst()//爆炸
{
(root as Main).gameStage.addChild(new Bit(x,y, Math.random()*360,true));

removeFromStoneArr(this);

//add 2 new small stone

var stone1_1=new Stone_small( x,y, 1+Math.random()*2, Math.random()*360);
var stone1_2=new Stone_small(x,y, 1+Math.random()*2, Math.random()*360);
(root as Main).gameStage.stone_arr.push(stone1_1);
(root as Main).gameStage.stone_arr.push(stone1_2);
//trace(root)
(root as Main).gameStage.addChild(stone1_1);
(root as Main).gameStage.addChild(stone1_2)
removeEventListener(Event.ENTER_FRAME,enterFrameHandle);
(root as Main).gameStage.removeChild(this);//最后让remove自己,使root在之前有效

}

function angle_to_dxdy($angle:Number)
{

dx = Math.cos($angle/180*Math.PI)*speed;
dy = Math.sin($angle/180*Math.PI)*speed;
}

}
}
Bullet类:子弹类,被库中bullet这个mc绑定
复制内容到剪贴板
代码:
package{
import flash.display.*;
import flash.events.*;
public class Bullet extends MoveObject
{

var toolong=0;//显示的时间,这个数会每帧递增,大于一个数的时候子弹会自己把自己remove掉
function Bullet($x,$y,$speed,$angle)
{
super($x,$y,$speed,$angle,1)
addEventListener(Event.ADDED_TO_STAGE,addedToStageHandle);
addEventListener(Event.REMOVED_FROM_STAGE,removeFromStageHandle);
}
function addedToStageHandle(e:Event)
{
angle_to_dxdy(angle);
addEventListener(Event.ENTER_FRAME,enterFrameHandle)
}
function removeFromStageHandle(e:Event)
{
removeEventListener(Event.ENTER_FRAME,enterFrameHandle)
}

function enterFrameHandle(e:Event)
{
if(root==null)
return;
moveme();
hitTestStrone();
testIsTooLong();
}

function testIsTooLong()//这个子弹存活了40帧,remove掉自己
{
if(toolong++>40)
{
(root as Main).gameStage.removeChild(this);
removeEventListener(Event.ENTER_FRAME,enterFrameHandle)
}
}
function hitTestStrone()
{
for(var i=0;i<(root as Main).gameStage.stone_arr.length;i++)
{
if( (root as Main).gameStage.stone_arr[i].hitTestPoint(x,y,true) )
{
if((root as Main).gameStage.stone_arr[i].invincibility_time<0)
{
Stone( Main(root).gameStage.stone_arr[i]).burst();
removeEventListener(Event.ENTER_FRAME,enterFrameHandle)
Main(root).gameStage.removeChild(this);
return;
}
}
}
}

function angle_to_dxdy($angle:Number)
{

dx = Math.cos($angle/180*Math.PI)*speed;
dy = Math.sin($angle/180*Math.PI)*speed;
}

}
}
还剩下几个简单的类,省略了,自己看下吧


[ 本帖最后由 wizim 于 2008-4-12 16:06 编辑 ]
附件
space game.rar (335.55 KB)

2008-4-12 15:27, 下载次数: 35

转自:http://bbs.actionscript3.cn/thread-5578-1-1.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

游鱼_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值