Flash 动画:
贪吃蛇游戏,因为制作简单,逻辑性较强,通常是学做游戏的必练的项目。很久以前,我曾经
在DOS系统下用TC作过一个,当时费了很大的劲,先是以文本串形式实现运动,再改到图形界面中用
绘图的方法来做。代码写了一大堆,现在想起来,还是有些头大。
flash 中进行游戏设计时,界面的可视操作,是其最大的优点,利用它自身的优点,可以将精
力集中到核心代码的设计上,界面中的元件直接在屏幕中画出来既可,真是太方便了。于是这次制
作贪吃蛇,没有花太多的时间,代码也更易于阅读。
在flash中设计时需要考虑的问题主要是键盘控制,mc的加载与御载,一些变量的初始化,以及
界面结构的配合。
在本次设计中,规划了三个主页面的结构,第一个界面用于显示封面,第二个是游戏界面,第
三个是结束界面,也就是说只要三帧即可。
为了实现参数化的效果,这里使用了一个boundary_mc 用来表示可运动的范围,系统中一切的
位置信息都是与它有关,并且用它来表示。初始变量包括:蛇身体部分的初始长度、运动方向以及
运动速度。// ============== initial Vars
var init_length = 2;
var dir = 1;
var speed = 15;
在游戏设计中,数据结构是一个需要首先考虑的问题,flash中已经可以摆脱类似链表的复杂结
构,直接使用数组就可以对一系列的mc进行控制。在这里用了一个mov_array 来保存蛇的头(head)
、身体(body)、尾巴(tail)。代码如下:
// ============== create snake ===========
var mov_array:Array = new Array();
mov_array.push(head);
head._x = boundary_mc._x + head._width / 2;
head._y = boundary_mc._y + boundary_mc._height - head._height / 2;
mov_array.push(body);
body._x = head._x;
body._y = head._y;
body._visible = false;
for (var i = 0; i < init_length; i++) {
duplicateMovieClip(body, "body" + i, i);
mov_array.push(_root["body" + i]);
_root["body" + i]._x = head._x;
_root["body" + i]._y = head._y;
//trace(mov_array[i]._x);
}
mov_array.push(tail);
tail._x = head._x;
tail._y = head._y;
运动效果是通过对数组依次从最后向前刷新位置来实现的。用函数来表示:
function s_move() {
for (var i = mov_array.length - 1; i > 0; i--) {
mov_array[i]._x = mov_array[i - 1]._x;
mov_array[i]._y = mov_array[i - 1]._y;
}
}
贪吃蛇当然不能少了食物,这里的食物只有一个,并且设置了一个定时器,当蛇吃到食物时或者到
达一定时间长度时,就将食物重新放置,这样,食物会在自己的时间周期到时自动移动,(如果构造
一个复杂的食物系统,可以在这里加代码,比如随机出现不同的食物。)
// ============ create food ===========
function create_food() {
food_mc._x = Math.floor(Math.random() * 19) * head._width + boundary_mc._x + 8;
food_mc._y = Math.floor(Math.random() * 15) * head._height + boundary_mc._y + 8;
}
food_interval = setInterval(create_food, 5000);
吃到食物时如何进行控制,下面的函数里记录了这些内容。
function eat_food() {
if (food_mc.hitTest(head)) {
var i = mov_array.length - 2;
duplicateMovieClip(body, "body" + i, i);
mov_array.pop();
mov_array.push(_root["body" + i]);
mov_array.push(tail);
create_food();
clearInterval(food_interval);
food_interval = setInterval(create_food, 5000);
}
}
凡是游戏必有一定的规则,这里建立了两套规则,第一套是传统风格,碰墙既死,第二套规则可以
穿墙,但当身体超过20个单位长度时,游戏结束。编译时使用了第二套规则。
function check_rulesI() {
var left_x = boundary_mc._x;
var right_x = boundary_mc._x + boundary_mc._width;
var top_y = boundary_mc._y;
var button_y = boundary_mc._y + boundary_mc._height;
if (head._x < left_x || head._x > right_x || head._y < top_y || head._y > button_y) {
return true;
} else {
return false;
}
}
function check_rulesII() {
var left_x = boundary_mc._x;
var right_x = boundary_mc._x + boundary_mc._width;
var top_y = boundary_mc._y;
var button_y = boundary_mc._y + boundary_mc._height;
if (head._x < left_x) {
head._x = right_x - head._width / 2;
}
if (head._x > right_x) {
head._x = left_x + head._width / 2;
}
if (head._y < top_y) {
head._y = button_y - head._height / 2;
}
if (head._y > button_y) {
head._y = top_y + head._height / 2;
}
if (mov_array.length > 22) {
return true;
} else {
return false;
}
}
游戏结束时,应该先做一些清理工作,设计窗口场景中的元件越过关键帧后,自动就不存在了,但
是复制出来的mc 就必须用代码来清理一下,同时还要清除的有按键的侦听器,以及产生食物的定时
器,因为重新进行游戏时,这些东西还会再生成,这里一定要清干净,否则会出现效果叠加的情况
,比如时间未到食物就跑开了,因为多个定时器同时起作用了。在设定定时器时使用的名称
food_interval,只是对定时器的引用,直接再给它设一个定时器,则前面设定的定时器仍存在,所
以必须明确的清除一下,用clearInterval(food_interval);我的清除函数是这么写的:
function end_game() {
clearInterval(food_interval);
//弹出尾部
mov_array.pop();
while (mov_array.length > 1) {
//逐个弹出并删除身体。
removeMovieClip(mov_array[mov_array.length - 1]);
mov_array.pop();
}
Key.removeListener(keyListener);
gotoAndStop("game over");
}
常言到兵马未动,粮草先行,设计时需要用到的函数就是这个"粮草",多数时候没办法直接确定
需要用那些函数,这也不要紧,边设计边总结,把局部的功能都用函数来实现,再将函数放到上层
的单独层中,最下面的AS层放入核心代码,这样,核心代码的长度将会得到有效的控制,并且有利
于实现模块化设计。下面核心的代码出场了。
onEnterFrame = function () {
switch (dir) {
case 1 :
head._x += speed;
break;
case 2 :
head._y += speed;
break;
case 3 :
head._x -= speed;
break;
case 4 :
head._y -= speed;
break;
}
if (check_rulesII()) {
delete this.onEnterFrame;
end_game();
}
s_move();
eat_food();
};
var keyListener:Object = new Object();
keyListener.onKeyDown = function() {
if (Key.getCode() == Key.RIGHT) {
dir = 1;
} else if (Key.getCode() == Key.DOWN) {
dir = 2;
} else if (Key.getCode() == Key.LEFT) {
dir = 3;
} else if (Key.getCode() == Key.UP) {
dir = 4;
}
};
Key.addListener(keyListener);
呵呵,是不是很短啊,这就是贪吃蛇啊?没错,就是这几行代码了,除去侦听器用了十几行外,核
心的onEnterFrame 其实就没有多少内容,只是按照预订好的方向进行移动,并且先判断是否结束游
戏,再移动,再进食,就是这些内容。
仅看核心代码是不全面的,所以回到函数设计的阶段,看看函数是怎么设置的,我也并不是一下子
就定好了全部的函数。而且界面只是简单的制作了一下,体现的是设计思想,真正的修饰的空间还
很大。希望你玩得开心~~
(提示:蛇的头、身、尾是和代码不相关的,所以可以设计一个更炫的图形来表示一下,留给你自己
做吧。)
////作者与2007年6月26日补充:
《贪吃蛇的制做》已经写成完整的教程并发表在博客中,详情请参阅下面这篇文章:
blog.5d.cn/user12/dzxz/200611/330066.html 内附原代码下载。
回复Comments
作者:
{commentrecontent}