2006/08/24 | flash 贪吃蛇游戏的制作
类别(Flash游戏教程) | 评论(9) | 阅读(2719) | 发表于 10:17



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 内附原代码下载。
0

评论Comments