概述
做一个FLASH游戏你需要掌握的东西
作者:jianzhong
一直想着什么时间好好做一个像样点的游戏,于是刻意的开始去了解FLASHGAME的相关资料,在这里把自己在整个制作和收集过程中的一些感觉使用的东西和自己的经验贴一下,方便爱好FLASH GAME的朋友找资料,同时以此共勉.(我会坚持每天至少贴出一个相关内容争取尽快完成)
正题:
首先要解决的一个最常用的东西就是"碰撞的检测"
回忆一下你所接触个各类游戏.....
是吧,不管飞行还是格斗还是RPG...都回很频繁的与"碰撞"这个词打交道
比如现在我们做一个飞机游戏吧:
一般做法:将hitTest方法加到子弹MC上.接合FOR...IN...循环检测所有的敌机是否与子弹发生碰撞.
试想一下,如果屏幕上有50发子弹.敌机2架.那么,为第一个子弹上加上这样的代码
bullet.onEnterFrame=function(){
for(enemy in enemyarea){
if(this.hitTest(执行("enemyarea."+enemy)))
{removeMovieClip(this);removeMovieClip(执行("enemyarea."+enemy))}}
}
先不说可能出现的碰撞误差了.就刚刚这个假设,50发子弹,2架敌机,也就是每一桢,就有50个onEnterFrame中进行2次判断.处理复杂度也就是50*2=100
现在我们换一下思路,把碰撞检测写在敌机上呢?毕竟大多数情况下,飞机要比子弹少.
当然,如果我们还用和上边类似的FOR...IN...循环,那处理复制度还是一样的.不过是变成2*50=100罢了.
所以,要想一种更有靠和高效点的办法.
可以从传统做法上看出.大过数的子弹都在做无效检测.也就是说,他本身并没有碰到任何东西,但检测碰撞这一操作仍然是在进行.只不过hitTest不会返回TRUE值罢了.所以,资源就浪费在了那些没有结果的检测上了.所以我们下边在用敌机做检测者的时候,要用到另一种检测手段了.
注意上边那段代码里的那个"enemyarea",这个MC是包含了所有敌机的MC.我把相同类型的对象封装在一个大的MC中.这样便于FOR...IN...查询,而不用在FOR...IN...里再嵌套多的对象名判定.同理,下面我将所有的子弹MC也封装在一个大的MC中.我为它取个实例名叫"bulletarea".
而子弹的设计上又要有一点技巧了.
子弹由两部分组成,一个是看得见的子弹形状,一个是看不见的感应域.后者比前者大.用来感应碰撞.
看得见的子弹形状也是一个MC,实例名就设为"inbullet".整个子弹的实例名为"bullet"
好,MC设计好了.假设还是开始的那种情况,即,屏幕上有50发子弹,2架敌机.
现在我们在敌机上写上代码.
this.onEnterFrame=function()
{
if(bulletarea.hitTest(this._x,this._y,true))
{checkcol(this)}
}
function checkcol(who)
{ for(each in bulletarea){
if(执行("bulletarea."+each).inbullet.hitTest(执行(who))){
removeMovieClip(执行("area."+each));removeMovieClip(执行(who))
}}
}
看出区别来了么?
因为这句"if(bulletarea.hitTest(this._x,this._y,true))"的判定,让飞机直接去检测整个子弹域--bulletarea,查看是否有碰撞的情况发生.这里检测的是整个大的MC,而不是去盲目地检测是否和每一颗子弹发生碰撞.毕竟,要同时和所有子弹发生碰撞也不容易.所以,先确定一下到底有没有碰撞的情况发生再说吧.
当真的有碰撞发生了,再执行checkcol(who)函数,用for...in...接合子弹内核inbullet碰撞检测,从而从子弹域里找到和自己发生碰撞的那个子弹.并删除它,然后再删除自己,当然,你也可以不急着删除自己.因为你还可以考虑血量嘛.这样一来,一般情况下影片每运行一桢只做了2次判断.如果有一个飞机出现碰撞情况了,那个飞机执行checkcol函数,那么就会有2+50=52次.如果不幸两个飞机都中弹了.那也无非比传统的检测方式多两次判断而已.总体来说,资源大大节约啊.
所以说,这种方式的碰撞检测,从一定程度上避免了"无用功检测"的情况.且运用了反馈式检测,即,先由敌机上的轴心点与子弹进行点检测,再由子弹内核进行边沿检测.这样,检测的效率也就更高,更可靠了.
【楼主】(1)我们再来了解一下"追踪效果实现方法"
作者:drmingdrmer 来源:闪吧
Chaser 类:
Chaser类实现了简单的追踪效果,使用这个类,用户可以大大简化各种追踪效果的实现。
Chaser的实例具有追踪其他mc的功能,可以追踪的属性如下:
_x
_y
_xscale
_yscale
_width
_height
_rotation
_alpha
使用方法:将一个mc连接到xp.gameLib.chase.Chaser类或其子类,并设置onChase事件处理函数,用户在onChase函数中实现追踪的具体实现。
此方法不同于Target类,它将功能实现写在chaser上面,使他可以追踪任何一个mc(也可以是其他对象,但主要是针对mc作的这个dd^^)。
Target类则是将功能实现在‘目标’上,使它可以被任何1个对象所追踪。
Top Features:
l 速度比较快,如果要更快,可以删除一些不必要得追踪属性
l 易扩展,继承Chaser类后可以在calculateChase方法中添加需要的追踪属性。
l 通用性。
l 性价比高。。功能要求中等的场合。譬如追踪导弹,有趣的拖动条等。
disAdv:
l 追踪者必须是Chaser类或其子类,制约了其他的功能实现。
l 只能追踪特定的属性,不能对不同的对象选择不同的追踪属性,追踪的功能难以细分(下个dd解决这个问题,恩)
l 其他的还在想。。。
类实现:
/**
* @author xp@drmingdrmer
* Chaser implements chasing.
* By making an MC to be a Chaser instance.
* Chaser的实例具有追踪其他mc的功能,可以追踪的属性如下:
*
* _x
* _y
* _xscale
* _yscale
* _width
* _height
* _rotation
* _alpha
*
* 使用方法:将一个mc连接到xp.gameLib.chase.Chaser类或其子类,并设置onChase事件处理函数,用户在onChase函数中实现追踪的具体实现。
* Chaser类仅提供了简单的即时追踪效果.
* 不支持指定步长的追踪,或几何速率的追踪。用户可以在子类中扩展并实现这些功能。
*/
class xp.gameLib.chase.Chaser extends xp.system.MovieClipAdv{
/**
* 触发器
*/
static var impulser:Object;
/**
* default properties list in which the property will be chase.
* 默认的属性列表。
*/
static var defaultPropList:Object={
_x:1,
_y:1,
_xscale:1,
_yscale:1,
_width:1,
_height:1,
_rotation:1,
_alpha:1
};
/**
* properties list,use ’addProperty’,’delProperty’ to add or remove properties from chasing。
* @see addProperty
* @see delProperty
* 属性列表,设置那些属性可以被追踪到。当Chaser实例被实例化后,就具有了默认的属性列表。
*/
var propList:Object;
/**
* mc list to which this Chaser chases.
* mc列表,记录那些mc被这个Chaser实例追踪了
*/
private var mlist:Array;
/**
* total weight value.
* 总的权重。
*/
var totalWeight:Number;
/**
* constructor
* 监听impulser的callChase事件,初始化成员变量。
*/
public function Chaser() {
//for sub class create a ’constructor’ property.
//function implemented in MovieClipAdv.
this["createConstructor"](arguments);
if (impulser==undefined){
impulser=createImpulser();
}
impulser.addListener(this);
propList=new Object();
for (var i in defaultPropList){
propList[i]=defaultPropList[i];
}
mlist=new Array();
totalWeight=0;
}
/**
* overWritten
* create a impulser.
* @return impulser implemented ’xp.events.Broadcaster’ interface.
* 生成一个触发器,定时调用callChase函数,默认生成的impulser每帧调用1次callChase,子类可以覆盖此函数。
*/
function createImpulser():Object{
return xp.system.Broadcaster.createAutoBroadcaster("callChase",2);
}
/**
* add a property to chase
* @param n String property name
* 添加一个被追踪的属性
*/
function addProp(n:String){
propList[n]=1;
}
/**
* 删除 a property to chase
* @param n String property name
* 删除一个被追踪的属性
*/
function delProp(n:String){
删除 propList[n];
}
/**
* add another target to chase,optionally specifying a weight value for calculating chasing result.
* @param m MovieClip instance to chase.
* @param w weight.
* 添加一个被追踪的目标。
*/
function addTarget(m:MovieClip,w:Number){
if (!m) return;
if (w==undefined || isNaN(w)) w=1;
//push instance to queue,& remember its position.
m.__chaser__id__=mlist.push({w:w,ins:m})-1;
totalWeight+=w;
}
/**
* 删除 a target.
* @param p could be MC reference or id.
* @return Boolean
* 删除一个被追踪的目标
*/
function delTarget(p):Boolean{
var id:Number=undefined;
if (!isNaN(p)) id=Number(p);
else id=p["__chaser__id__"];
if (id==undefined) return false;
mlist.split(id);
for (var i : Number = id; i < mlist.length; i++) {
mlist[i]["__chaser__id__"]=i;
}
return true;
}
/**
* invoked by impulser
* broadcast ’onChase’ event
* 由impulser定时触发,计算追踪数值并调用用户定义的onChase函数。
*/
function callChase(){
var eo=calculateChase();
//subclass implement onChase by get/set function !!
this.onChase(eo);
}
/**
* abstract function
* overWritten by user defined function.
* 由用户覆盖此函数。
* @param eo 属性集合,包含所有propList中列出的属性。
*/
function onChase(eo){
}
/**
* overWritten
*
* 计算追踪的数据,子类应该覆盖此函数以实现更多的追踪效果(例如colorTransfrom,或瞄准目标的角度和距离等)
* 计算追踪目标的加权平均值,保存到eo对象中并返回此对象。
* @return Object containing infomation of targets.this object will be used as ’eo’ parameter for ’onChase’ function.
*
*/
function calculateChase():Object{
var eo:Object=new Object();
var tx=0;
var ty=0;
for (var i : String in propList) {
eo[i]=0;
}
for (var j : Number = 0; j < mlist.length; j++) {
for (var i : String in propList) {
eo[i]+=mlist[j].ins[i]*mlist[j].w;
}
}
for (var i : String in propList) {
eo[i]/=totalWeight;
}
//for compatibility to Target
eo.ins=eo;
eo.geo=eo;
eo.stp=eo;
return eo;
}
}
--- jianzhong
【楼主】(2)这句话很实际:
创造把!制作自己的游戏!
Flash游戏实际上可以很简单的。光使用按钮命令,就可以做出打靶的游戏了;只是用按钮和gotoAndPlay,就可以做出文字AVG,你相信么?
世界上没有教出来的高手,高手都是自学的。他们都是那种特别性急的人,只学到一点点东西就试图做出游戏来;但是却又充满学习的欲望。
慢慢的,在不断的学习和制作中,你会发现你对as越来越了解。
--- jianzhong
【楼主】(3)用enterframe控制MC动作
在主场景下,选中一个 MC-主角 的实例,打开属性面板(Ctrl + F3) 设置实例名( InstanceName) 为 主角。
下面我们用 enterframe 控制主角的移动。
在主事件轴上加一个图层叫as。选中这个图层,打开as面板( F9 )输入如下as:
--------------------------------------------------------------------------------
//主角的enterframe函数
主角.onEnterFrame = function (){
_x += 5; //每帧x增加5
_y += 3; //y增加3
}
--------------------------------------------------------------------------------
注意大小写和下划线。执行看看,主角自动向右下移动了。注意,主场景的注册点是左上角,坐标为(0,0);y轴正方向向下,x轴正方向向右。 所以,_y增大主角会往下移动。
每个mc都可以有自己的enterframe函数。系统每帧都会依次调用所有mc的enterframe,然后才刷新画面。
enterframe 是控制游戏的基本手段之一,本教程就是使用它来控制整个游戏的。
--------------------------------------------------------------------------------
为了更直观的理解坐标,我们把当前主角的坐标输出出来。 在主角的 enterframe 代码中加上一句 trace( this._x + " " + this._y )
this表示函数的主人,也就是主角拉。
这样as层的代码就变成这样:
--------------------------------------------------------------------------------
//主角的enterframe函数
主角.onEnterFrame = function (){
_x += 5; //每帧x增加5
_y += 3; //y增加3
trace( this._x + "," + this._y );
}
--------------------------------------------------------------------------------
执行看看,会跳出一个小窗口,不停的报出主角的当前坐标。
trace是 Flash 最常用的调试工具。
--------------------------------------------------------------------------------
点击主场景空白处,打开属性窗口(Ctrl + F3)即可编辑主场景的属性。我们可以编辑场景的大小、fps(Frame per Second 秒间帧数)以及背景颜色。 双击这个位置也会跳出如图的面板:
fps表示一个swf播放时一秒钟绘制多少帧画面。上图为Flash 默认设置,12 fps,即一秒钟播放12帧。
每帧,mc自己的时间轴会前进一格,同时系统会让所有设置了 enterframe 的mc调用自己的 enterframe 函数。
所以 fps 越高,动作越是连贯流畅。譬如上面的例子中,角色每帧水平移动5像素,一秒移动 12 x 5 = 60 像素。若是提高到30 fps而速度不变,把代码改为每帧2像素,画面就更为流畅了。 当然,若是只加大fps而代码不变,就只是快进效果。
Flash 游戏一般采用30 fps;PC上的商业游戏则要求 60 fps。当游戏由于运算量过大跑不动的时候,流畅的底线要求是24 fps。
--- jianzhong
【楼主】(4)RPG里的地图随人物移动
onClipEvent (enterFrame) {
if (Key.isDown(Key.LEFT)) {
if (_x>100) {
this._x -= 2;
} else {
_root.map._x += 2;
}
}
if (Key.isDown(Key.RIGHT)) {
if (_x<400) {
this._x += 2;
} else {
_root.map._x -= 2;
}
}
if (Key.isDown(Key.UP)) {
if (_y>100) {
this._y -= 2;
} else {
_root.map._y += 2;
}
}
if (Key.isDown(Key.DOWN)) {
if (_y<400) {
this._y += 2;
} else {
_root.map._y -= 2;
}
}
}
如果要在地图里面加入障碍物的方法也简单,我看了原文件,只是可惜这里没绿色通道来上传.
this._visible = false;
--- jianzhong
【楼主】(5)找了半天,终于让我找到了这个游戏的中的鼻祖原代码, 把下面这段代码直接写在第一帧上发布看看, 不错! 然后在仔细看看这段代码,你会学到很多的东西,收益非浅啊!!!推荐
//Invaders - by Enrique Jaimes version 1.0 723 bytes
// rupenztynzy@yahoo.com
//fps: 35
function G(){ // Main game function
var sc = 0; // score var
var w = 300; // width of scene
var h = 400; // height of escene
var t=0; // time variable
var i=0; // bullet counter
Mouse.hide(); // first hide the cursor
lineStyle(1); // draw the background
beginFill(0xeeeeee,100);lineTo(w-1,0);lineTo(w-1,h);lineTo(0,h);lineTo(0,0);endFill();
//createTextField("st",10,5,0,50,16);
createEmptyMovieClip("b",2); // create the bullet called b
b.lineStyle(3); // draw the bullet
b.lineTo(0,-6);
createEmptyMovieClip("s",1); //create the space ship!
with(s){
lineStyle(1); // draw the space ship
lineTo(10,25);lineTo(-10,25);lineTo(0,0);
startDrag(this,true,375,290); // now drag the ship with the mouse
} // end with
//this functi on create a bullet at the mouse down event
s.onmousedown = function(){
duplicateMovieClip("_root.b","b"+i,100+i); // duplicate the clip b
执行("_root.b"+i)._x = this._x; // set the coords
执行("_root.b"+i)._y = this._y; // at the ship's coords
// 执行("_root.b"+i)._alpha = 100;
执行("_root.b"+i).onEnterFrame = function(){ // set the bullet actions
this._y -= 10; // the bullet just grow up
--- jianzhong
【楼主】(6)今天看来不睡了,整理一点 就贴一点,希望天亮能贴完
接下来就是控制"主角"移动的问题了 :KEY对象在游戏中的应用
创建四个空白关键贞,分别把小人按左下右上四个不同的方向
放到每一个空白关键贞里,并且在贞标签添入关键字眼:"left""front""right""back"
其他操作相同~
选中MC的第一贞,添加代码;
stop();
注意:四个小人在舞台的位置是重合的
我们回到主场景
在图层一:CTRL+L打开库面板,,把刚才导入的背景图片拖入到舞台,并且对齐,接着,新建一个图层,把刚才做的MC拖入到场景中,并且在属性面板里命名:cuiyysw
选中这个MC,我们进行脚本编辑:
onClipEvent(load){//影片加载时
_root.cuiyysw._x=200;
_root.cuiyysw._y=300;//规定了MC的初始位置
}
onClipEvent(enterFrame){//进入贞
if(Key.isDown(Key.RIGHT)){如果响应键盘事件“右键”
_root.cuiyysw._x+=5;//MC在X轴的位置就加5个单位长度
this.gotoAndStop("right")//这个时候的MC停留在"right"这一贞标签位置,从而实现转身的目的
}
if(Key.isDown(Key.LEFT)){
_root.cuiyysw._x-=5;
this.gotoAndStop("left")
}
if(Key.isDown(Key.UP)){
_root.cuiyysw._y-=5;
this.gotoAndStop("back")
}
if(Key.isDown(Key.DOWN)){
_root.cuiyysw._y+=5;
this.gotoAndStop("front")
}//注解同上,
//规定了MC的范围,以至于不出场景外
if(_root.cuiyysw._x>535){
_root.cuiyysw._x=535;
}
else if(_root.cuiyysw._x<15){
_root.cuiyysw._x=15;
}
else if(_root.cuiyysw._y>400){
_root.cuiyysw._y=400;
}
else if(_root.cuiyysw._y<15){
_root.cuiyysw._y=15;
}
}
--- jianzhong
【楼主】(7)飞机游戏中的跟踪子弹 (简单AI)
首先敌人是定时创建的,创建时push入一个数组objectInScene内储存,并给每个敌人一个属性exist=true
当每个子弹发射时,先随机从objectInScene数组中引用一个目标
在每个子弹移动的过程中,循环检测
目标是否存在
#存在
跟踪目标,遍历objectInScene,检测是否有打到敌人
#打到
清除敌机,清除objectInScene相对应元素,清除子弹
次序不能颠倒,如果交换前两项,数组一变动,索引也就变动了,被打敌机的元素索引可能就不对了.而子弹如果一清除,后面的程序都不执行了.
#不存在
根据自定义路线飞行,并查找objectInScene是否为空
#不为空
随机再找一个元素为目标跟踪
代码如下
//- ATTACH AIM INTO THE CONTAINER -//
var scene:MovieClip = this.createEmptyMovieClip ("scene", 1);
scene.depth = 1;
var objectsInScene:Array = new Array ();
function addEnemy ()
{
for (var i = 0; i < 5; i++)
{
var aim:MovieClip = scene.attachMovie ("aim", "aim" + i, scene.depth++);
aim._x = random (500);
aim._y = random (400);
aim.exist = true;
objectsInScene.push (aim);
}
}
setInterval (addEnemy, 2500);
//- ATTACH BULLET -//
onmousedown = function ()
{
var b:MovieClip = scene.attachMovie ("bullet", "bullet" + scene.depth, scene.depth++);
b._x = _root._xmouse;
b._y = _root._ymouse;
b.radian = 0;
b.dir = (random (2) ? 1 : -1);
b.oldy = b._y;
b.oldx = b._x;
b.aim = objectsInScene[random(objectsInScene.length)];
b.onEnterFrame = shoot;
};
//- BULLET SHOOT -//
function shoot ()
{
if(this._x > 500) this.removeMovieClip();
else if(this._x < 0) this.removeMovieClip();
if(this._y > 400) this.removeMovieClip();
else if(this._y < 0) this.removeMovieClip();
var x, y;
var ōa = objectsInScene;
if (!this.aim.exist)
{
if(oa.length)
this.aim = oa[random(oa.length)];
if (this.radian < 2)
{
this.radian += 0.1;
}
x = Math.cos (this.radian) * 15 * this.dir;
y = -Math.sin (this.radian) * 15;
}
else
{
var i = oa.length;
while(--i > -1)
{
if(this.hitTest(oa[i]))
{
oa[i].removeMovieClip();
oa.splice(i, 1);
this.removeMovieClip();
}
}
var r = Math.atan2 (this.aim._y - this._y, this.aim._x - this._x);
x = Math.cos (r) * 15;
y = Math.sin (r) * 15;
}
this._x += x;
this._y += y;
this._rotation = Math.atan2 (this._y - this.oldy, this._x - this.oldx) * 57.3;
this.oldy = this._y;
this.oldx = this._x;
}
--- jianzhong
【楼主】(8)一段五子棋的代码,目前只有人人对战还没有做AI,这段代码个人觉得很实用,在做一些小游戏的时候能给主角另一种思路
格子是做成MC的:1帧空白(值为0),2帧白子(值为1),3帧黑子(值为-1)
判断是否连续时用的是加法。。(5个格子的值相加,取绝对值,如果等于5,表示有连续)
我想这样效率高些,代码也可简洁些
var sm=20;//棋盘格子的行列数
var width=400;//棋盘长宽
var width2=width/sm;//格子长宽
var depth=10;
var kk=true;//上白子还是黑子。。
var mydata=[];//棋盘整体状况记录:0表示空,1表示白子,-1表示黑子
bbb._visible=false;//bbb就是那个“replay”按钮,最后临时加上的
bbb.onRelease=function(){
cls_dot();
win="";//“win”就是文本框显示的信息
this._visible=false;
}
for (var i=0;imydata[i]=[];
for (var j=0;jmydata[i][j]=0;
var a=this.attachMovie("dot","dot"+i+"_"+j,depth++);
a.gotoAndStop(1);
a.i=i;
a.j=j;
a._width=a._height=width2;
a._x=j*width2;
a._y=i*width2;
a.onPress=function(){
if (this._currentframe==1 and !bbb._visible){//格子停留在第一帧,表示没有棋子
if (kk){
this.gotoAndStop(2);//停到2帧(白子)
mydata[this.i][this.j]=1;
//检测
var jc=is_ok(this.i,this.j);
if (jc!="") {
win=jc+"/n白子胜";
bbb._visible=true;
}
}else{
this.gotoAndStop(3);//停到3帧(黑子)
mydata[this.i][this.j]=-1;
//检测
var jc=is_ok(this.i,this.j);
if (jc!="") {
win=jc+"/n黑子胜";
bbb._visible=true;
}
}
//
trace("-----------目前局势------------------");
for (var bb=0;bbtrace("-------------END---------------------");
kk=!kk;
} }
}
}
//-------------------------下面这段写得比较繁琐---------------------------------------------------
//判断有无连续五子。。
function is_ok(this_i,this_j){
var is_ok="";
//行检测范围
var sta_i=this_i-4;
if (sta_i<0) sta_i=0;
var end_i=this_i+4;
if (end_i>sm-1) end_i=sm-1;
//列检测范围
var sta_j=this_j-4;
if (sta_j<0) sta_j=0;
var end_j=this_j+4;
if (end_j>sm-1) end_j=sm-1;
//检测行连续
for (var j=sta_j;j<=this_j;j++){
if(Math.abs(mydata[this_i][j]+mydata[this_i][j+1]+mydata[this_i][j+2]+mydata[this_i][j+3]+mydata[this_i][j+4])==5){
is_ok="行连续";
break;
}
}
//检测列连续
for (var i=sta_i;i<=this_i;i++){
if(Math.abs(mydata[i][this_j]+mydata[i+1][this_j]+mydata[i+2][this_j]+mydata[i+3][this_j]+mydata[i+4][this_j])==5){
is_ok="列连续";
break;
}
}
//检测斜"/"连续
for (var i=sta_i,j=sta_j;i<=this_i;i++){
if(Math.abs(mydata[i][j]+mydata[i+1][j+1]+mydata[i+2][j+2]+mydata[i+3][j+3]+mydata[i+4][j+4])==5){
is_ok="斜“//”连续";
break;
}
j++;
}
//检测斜"/"连续
for (var i=sta_i,j=0;i<=this_i;i++){
if(Math.abs(mydata[i][end_j-j]+mydata[i+1][end_j-j-1]+mydata[i+2][end_j-j-2]+mydata[i+3][end_j-j-3]+mydata[i+4][end_j-j-4])==5){
is_ok="斜“/”连续";
break;
}
j++;
}
//得出结果
return is_ok;
}
//——————————————————
//清除所有棋子
function cls_dot(){
for(var i=0;ifor(var j=0;jthis["dot"+i+"_"+j].gotoAndStop(1);
mydata[i][j]=0;
}
}
}
--- jianzhong
【楼主】(9)再来看一篇来至"灵翼"写的枪战游戏基础制作 !
枪战游戏主要应用的代码
1.鼠标跟随 startDrag(this, true);用来做标准器
2.层级别的控制 swapDepths();
3.碰撞检测 hitTest(_root.gun.hit)
4.动态加载敌人: _root.attachMovie();
5.动态文本框制作 显示分数
制作流程:
1.准备一个瞄准器MC,内含开火的动画
2.敌人MC一个,内含敌人中弹动画,在库中将敌人MC连接ID命名为“man"
3.动态文本框 编写代码: 首先主时间轴第一帧AS:
// ------主时间轴代码----------------
// 将鼠标隐藏
Mouse.hide();
// 初始设置分数为0
scores = 0; 此变量必须和分数文本框的变量名对应
// 封装代码,建立新的函数"copyman"
function copyman() {
// 复制库中ID为“man"的MC到主场景,命名为“man”+_root.i,层级别为_root.i
// 注意:_root.i没有设置初始值,所以默认为无。
// _root.i++,就是_root.i+1
_root.attachMovie("man", "man"+_root.i, _root.i++);
// 设置新MC的位置
// 将复制出来的新MC放到x轴为0-550之间,y轴为0-400的随机坐标上
_root["man"+_root.i]._x = random(550);
_root["man"+_root.i]._y = random(400);
}
// 执行新函数
copyman();
然后将瞄准器MC拖到舞台实例名为“gun”在其MC上写AS:
// ----------准星MC的代码--------------
onClipEvent (enterFrame) {
// 实现鼠标跟随,并且所定鼠标到此MC的注册点
startDrag(this, true);
}
onClipEvent (mouseDown) {
// 当鼠标按下的时候运行到此MC第3帧(开火动画)执行
gotoAndPlay(3);
}
onClipEvent (load) {
// 设置次准星层级别为9999,数字越大层级越高,以免准星被敌人覆盖
this.swapDepths(9999);
}
此MC内部有个开火的动画在开火动画这一段加上一隐形MC,实例名为“hit”
制作敌人MC内部
敌人MC内部,第一帧为没有中弹时候的画面,在这帧再加入一隐形MC,加AS:
// 碰撞检测
onClipEvent (enterFrame) {
// 如果如果检测到于准星MC里的hit发生接触就在上一级跳转到第5帧(被毖了)执行.
if (hitTest(_root.gun.hit)) {
_parent.gotoAndPlay(5);
}
}
5帧以后为中弹后死亡的动画,在最后一帧加AS:
// 分数加100
_root.scores += 100;
//运行copyman的函数 复制敌人
_root.copyman();
// 删除此MC
removeMovieClip(this);
游戏测试地址:
http://www.flash8.net/bbs/UploadFile/2004-7/200478212237216.swf
--- jianzhong
【楼主】(10)明天晚上接着贴后面的部分 应该不是很多了
--- jianzhong
【楼主】(11)惯性移动的制作方法
代码写入MC
// 侦听键盘
onClipEvent (load) {
myListener = new Object();
myListener.onKeyDown = function() {
kpress = 1;
};
myListener.onKeyUp = function() {
kpress = 0;
};
Key.addListener(myListener);
}
// 设置初始值
onClipEvent (load) {
// 移动x初速度
var speed = 0;
// 移动y初速度
var yspeed = 0;
// 是否按键
var kpress = 0;
// 最大速度
var maxs =15;
}
// 设置最大速度
onClipEvent (enterFrame) {
if (speed>maxs) var speed = maxs;
if (speed<-maxs)var speed = -maxs;
if (yspeed>maxs) var yspeed = maxs;
if (yspeed<-maxs) var yspeed = -maxs;
}
// 设置移动
onClipEvent (enterFrame) {
_x += speed;
_y += yspeed;
if ( kpress == 0) {
if (speed>0) speed--;
if (speed<0) speed++;
if (yspeed>0) yspeed--;
if (yspeed<0) yspeed++;
if (_x>530||_x<20) var speed=0;
if (_y>380||_y<20) var yspeed=0;
}
// 设置按键
if (Key.isDown(Key.LEFT)) {
speed--;
if (_x<=20) var speed=0;
}
if (Key.isDown(Key.RIGHT)) {
speed++;
if (_x>=530) var speed=0;
}
if (Key.isDown(Key.UP)) {
yspeed--;
if (_y<=20) var yspeed=0;
}
if (Key.isDown(Key.DOWN)) {
yspeed++;
if (_y>=380) var yspeed=0;
}
}
--- jianzhong
扑(12)太长了就心情看 先留个名有时间再来看
--- 孤傲一世
猫(13)LIU MING...
--- 我的星座是插座
【楼主】(14)我想上面的东西大家如果都能理解一些了,到现在做一个简单的FLASHGAME应该不是多困难的事了,本人是个AS的大菜鸟,也不能给大家具体的详细讲到多深的问题,只是在一边学习的过程中一边感慨别人的AS写得太漂亮了,于是拿来共享一下,接着是最后一讲:
我想用这个很就以前放一个高人做的例子来结尾,当然就不详讲了,例一段主要的代码先,留给大家分析一下:
这是写在主角MC "PLAYER"上的一段代码,供初学者参考一下:
onClipEvent (load)
{
function zd()
{
if (_root.f < 10)
{
_root.attachMovie("paodan", "paodan" + _root.f);
_root.f++;
} // end if
} // End of the function
var speed = new Array(0, 6, 9, 8);
_root.go = "";
_root.fire = "";
playerx = this._x;
playery = this._y;
_root.yx = 1;
_root.b = true;
_root.l = 65;
_root.u = 87;
_root.r = 68;
_root.d = 83;
_root.a = 78;
_root.j = 77;
_root.x = 1;
_root.z = 1;
scale = 1;
_root.f = 1;
_root.zd_x = 0;
_root.zd_y = 1;
}
onClipEvent (enterFrame)
{
if (_root.b == true)
{
with (_root.player)
{
if (Key.isDown(_root.l) && !Key.isDown(_root.d))
{
scale = 0;
_x = _x - speed[1];
gotoAndStop(2);
} // end if
if (Key.isDown(_root.r) && !Key.isDown(_root.d))
{
scale = 1;
_x = _x + speed[1];
gotoAndStop(2);
} // end if
if (Key.isDown(_root.u) && !Key.isDown(_root.r) || Key.isDown(_root.u) && !Key.isDown(_root.l))
{
_x = _x + speed[0];
gotoAndStop(4);
} // end if
if (Key.isDown(_root.d))
{
_root.fire = 2;
_x = _x + speed[0];
gotoAndStop(5);
} // end if
if (Key.isDown(_root.a) && !Key.isDown(_root.l) && !Key.isDown(_root.r) && !Key.isDown(_root.d) && !Key.isDown(_root.u) && !Key.isDown(_root.j))
{
if (_root.z == 1)
{
_root.go = 9;
zd();
} // end if
}
else if (Key.isDown(_root.a) && Key.isDown(_root.l) || Key.isDown(_root.a) && Key.isDown(_root.r))
{
if (_root.z == 1)
{
_root.go = 9;
_root.b = false;
} // end if
}
else if (Key.isDown(_root.a) && Key.isDown(_root.d) && !Key.isDown(_root.r) && !Key.isDown(_root.l))
{
if (_root.z == 1)
{
_root.go = 12;
_root.b = false;
} // end if
}
else if (Key.isDown(_root.a) && Key.isDown(_root.d) && Key.isDown(_root.l))
{
gotoAndStop(5);
}
else if (Key.isDown(_root.a) && Key.isDown(_root.u) && !Key.isDown(_root.r) && !Key.isDown(_root.l))
{
if (_root.z == 1)
{
_root.go = 8;
_root.b = false;
} // end if
}
else if (Key.isDown(_root.a) && Key.isDown(_root.u) && Key.isDown(_root.l))
{
gotoAndStop(8);
}
else
{
_root.go = "";
_root.b = true;
_root.z = 1;
} // end if
if (Key.isDown(_root.j) && !Key.isDown(_root.u) && !Key.isDown(_root.l) && !Key.isDown(_root.r) && !Key.isDown(_root.d) && !Key.isDown(_root.a))
{
if (_root.z == 1)
{
_root.go = 7;
_root.b = false;
} // end if
}
else if (Key.isDown(_root.j) && Key.isDown(_root.l))
{
if (_root.z == 1)
{
_root.go = 7;
_root.b = false;
} // end if
}
else if (Key.isDown(_root.j) && Key.isDown(_root.r))
{
if (_root.z == 1)
{
_root.go = 7;
_root.b = false;
} // end if
}
else if (Key.isDown(_root.j) && Key.isDown(_root.u))
{
if (_root.z == 1)
{
_root.go = 10;
_root.b = false;
} // end if
}
else if (Key.isDown(_root.j) && Key.isDown(_root.d))
{
if (_root.z == 1)
{
_root.go = 6;
_root.b = false;
} // end if
} // end if
if (Key.isDown(_root.d) && Key.isDown(_root.u) || Key.isDown(_root.l) && Key.isDown(_root.r))
{
gotoAndStop(1);
} // end if
if (Key.isDown(_root.l) && Key.isDown(_root.d) && Key.getCode() == _root.d)
{
_root.fire = 2;
speed[1] = 0;
gotoAndStop(5);
}
else if (Key.isDown(_root.l) && Key.isDown(_root.u) && Key.getCode() == _root.u)
{
speed[1] = 0;
gotoAndStop(4);
}
else if (Key.isDown(_root.r) && Key.isDown(_root.d) && Key.getCode() == _root.d)
{
_root.fire = 2;
speed[1] = 0;
gotoAndStop(5);
}
else if (Key.isDown(_root.r) && Key.isDown(_root.u) && Key.getCode() == _root.u)
{
speed[1] = 0;
gotoAndStop(4);
}
else if (Key.isDown(_root.d) && Key.isDown(_root.l) && Key.getCode() == _root.l)
{
scale = 0;
speed[1] = 0;
gotoAndStop(5);
}
else if (Key.isDown(_root.d) && Key.isDown(_root.r) && Key.getCode() == _root.r)
{
scale = 1;
speed[1] = 0;
gotoAndStop(5);
}
else if (Key.isDown(_root.u) && Key.isDown(_root.l) && Key.getCode() == _root.l)
{
speed[1] = 0;
scale = 0;
gotoAndStop(4);
}
else if (Key.isDown(_root.u) && Key.isDown(_root.r) && Key.getCode() == _root.r)
{
speed[1] = 0;
gotoAndStop(4);
scale = 1;
}
else
{
_root.fire = 1;
speed[1] = 6;
} // end if
} // End of with
} // end if
}
onClipEvent (enterFrame)
{
if (scale == 1)
{
_xscale = 100;
}
else
{
_xscale = -100;
} // end if
}
onClipEvent (keyUp)
{
if (_root.go == "")
{
_root.player.gotoAndStop(1);
}
else
{
_root.player.gotoAndStop(_root.go);
} // end if
}
最后
以上就是懵懂汉堡为你收集整理的做一个FLASH游戏你需要掌握的东西【实用】的全部内容,希望文章能够帮你解决做一个FLASH游戏你需要掌握的东西【实用】所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复