http://bbs.9ria.com/thread-83537-1-3.html
现在,我们来到了这个教程的第5个阶段。
在这个阶段,我们会修改一个漏洞,这个漏洞允许植物开火只要有僵尸与植物处于同一行,不论僵尸是在植物的左边还是右边。同时我们也会增加僵尸攻击植物的功能。
首先,让我来解释一下一些改变:
在前面的步骤里,zombiesArray数组只存储每一行上的僵尸的数量。这个信息对我们想知道僵尸是在植物的左边还是右边是不够的,所以从现在开始zombiesArray改为一个二维数组,用来存储每一行上僵尸的名字。
你将会明白这一特性当我们讨论源代码的时候。
要使僵尸攻击植物,我们必须使他们停下来一旦他们与植物处于同一区块。
让我们来看源代码:
- package {
- import flash.display.Sprite;
- import flash.utils.Timer;
- import flash.events.TimerEvent;
- import flash.events.MouseEvent;
- import flash.events.Event;
- import flash.text.TextField;
- public class Main extends Sprite {
- //
- // 一个2维数组用来存储游戏区块
- //
- private var plantsArray:Array;// 种植在游戏区域里的植物
- private var zombiesArray:Array;//在游戏区域里的僵尸
- //
- // 计时器
- //
- private var flowersTimer:Timer=new Timer(5000);//计时器,使得阳光落下
- private var zombieTimer:Timer=new Timer(5000);// 计时器,让僵尸出场
- //
- // 容器
- //
- private var sunContainer:Sprite=new Sprite();// 所有阳光的容器
- private var plantContainer:Sprite=new Sprite();// 所有植物的容器
- public var bulletContainer:Sprite=new Sprite();// 所有子弹的容器
- private var zombieContainer:Sprite=new Sprite();// 所有僵尸的容器
- private var overlayContainer:Sprite=new Sprite();// 所有覆盖物的容器
- //
- // 我们的演员
- //
- private var movingPlant:plantMc;// 玩家在游戏区域能够拖动的植物
- private var selector:selectorMc;// 选择器(一个高亮的区块),告诉玩家他将把植物种在哪
- //
- // 其它变量
- //
- private var money:uint=0;// 玩家所拥有的金钱数量
- private var moneyText:TextField=new TextField ;// 动态文本框,用来显示玩家的金钱
- private var playerMoving:Boolean=false;// 布尔型变量,标志玩家是否在移动一个植物
- private var totalZombies:uint=0;//僵尸的总数
- public function Main():void {
- setupField();//初始化游戏区块
- drawField();//画出游戏区块
- fallingSuns();// 初始化下落的阳光
- addPlants();// 初始化植物
- addZombies();//初始化僵尸
- addEventListener(Event.ENTER_FRAME,onEnterFrm);
- }
- //
- // 游戏区域设置,创建用来存储植物和僵尸信息的数组
- //
- private function setupField():void {
- plantsArray=new Array();
- zombiesArray=new Array();
- for (var i:uint=0; i<5; i++) {
- plantsArray[i]=new Array();
- zombiesArray[i]=new Array();
- for (var j:uint=0; j<9; j++) {
- plantsArray[i][j]=0;
- }
- }
- }
- //
- // 显示玩家的金钱
- //
- private function updateMoney():void {
- moneyText.text="Money: "+money.toString();
- }
- //
- // 画出游戏区域
- //
- private function drawField():void {
- var fieldSprite:Sprite=new Sprite();
- var randomGreen:Number;
- addChild(fieldSprite);
- fieldSprite.graphics.lineStyle(1,0xFFFFFF);
- for (var i:uint=0; i<5; i++) {
- for (var j:uint=0; j<9; j++) {
- randomGreen=(125+Math.floor(Math.random()*50))*256;
- fieldSprite.graphics.beginFill(randomGreen);
- fieldSprite.graphics.drawRect(25+65*j,80+75*i,65,75);
- }
- }
- addChild(sunContainer);
- addChild(plantContainer);
- addChild(bulletContainer);
- addChild(zombieContainer);
- addChild(overlayContainer);
- overlayContainer.addChild(moneyText);
- updateMoney();
- moneyText.textColor=0xFFFFFF;
- moneyText.height=20;
- }
- //
- // 初始化僵尸
- //
- private function addZombies():void {
- zombieTimer.start();
- zombieTimer.addEventListener(TimerEvent.TIMER,newZombie);
- }
- //
- // 增加一个新的僵尸
- //
- private function newZombie(e:TimerEvent):void {
- var zombie:zombieMc=new zombieMc();// 构造僵尸
- totalZombies++;
- zombieContainer.addChild(zombie);// 增加僵尸
- zombie.zombieRow=Math.floor(Math.random()*5);//生成随机行数,用于放置僵尸
- zombie.name="zombie_"+totalZombies;//给僵尸一个名字
- zombiesArray[zombie.zombieRow].push(zombie.name);// 增加第row行的僵尸
- zombie.x=660;// 把僵尸放在屏幕的右边
- zombie.y=zombie.zombieRow*75+115;
- }
- //
- // 初始化阳光
- //
- private function fallingSuns():void {
- flowersTimer.start();
- flowersTimer.addEventListener(TimerEvent.TIMER, newSun);
- }
- //
- // 增加一束新的阳光
- //
- private function newSun(e:TimerEvent):void {
- var sunRow:uint=Math.floor(Math.random()*5);// 随机行
- var sunCol:uint=Math.floor(Math.random()*9);// 随机列
- var sun:sunMc = new sunMc();// 构造阳光
- sun.buttonMode=true;// 当鼠标滑过阳光时,改变鼠标的形状
- sunContainer.addChild(sun);// 加入显示列表
- sun.x=52+sunCol*65;// 把阳光放在合适的位置
- sun.destinationY=130+sunRow*75;// 定义阳光destinationY属性
- sun.y=-20;// 把阳光放在舞台顶部的上方
- sun.addEventListener(MouseEvent.CLICK,sunClicked);// 给阳光注册鼠标点击事件
- }
- //
- // 阳光的鼠标点击事件句柄
- //
- private function sunClicked(e:MouseEvent):void {
- e.currentTarget.removeEventListener(MouseEvent.CLICK,sunClicked);// 移除鼠标事件侦听
- money+=5;//让玩家赚到5个金币
- updateMoney();// 更新动态文本
- var sunToRemove:sunMc=e.currentTarget as sunMc;// 获得我们必须移除的阳光
- sunContainer.removeChild(sunToRemove);// 移除该阳光
- }
- // 创建一个植物栏,现在只有一种植物
- //
- private function addPlants():void {
- var plant:plantMc=new plantMc();// 构造一株新的植物
- overlayContainer.addChild(plant);// 增加植物
- plant.buttonMode=true;// 使鼠标改变形状,当它滑过新植物时
- plant.x=90;
- plant.y=40;
- plant.addEventListener(MouseEvent.CLICK,onPlantClicked);// 给新植物注册鼠标点击事件
- }
- //
- // 植物的鼠标点击事件句柄
- //
- private function onPlantClicked(e:MouseEvent):void {
- // 检查玩家是否有足够的钱(当前是10)来购买植物,并且是否正在拖动一个植物
- if (money>=10&&! playerMoving) {
- money-=10;// 付款
- updateMoney();// 更新动态文本
- selector=new selectorMc();// 创建一个新的选择器
- selector.visible=false;// 使选择器不可见
- overlayContainer.addChild(selector);// 把选择器加入到显示列表
- movingPlant=new plantMc();// 构建一个新的供玩家拖动的植物
- movingPlant.addEventListener(MouseEvent.CLICK,placePlant);// 给该植物注册一个鼠标点击事件
- overlayContainer.addChild(movingPlant);// 把该植物加入到显示列表
- playerMoving=true;// 告诉脚本正在移动一株植物
- }
- }
- //
- // 把植物放置在游戏区域中
- //
- private function placePlant(e:MouseEvent):void {
- var plantRow:int=Math.floor((mouseY-80)/75);
- var plantCol:int=Math.floor((mouseX-25)/65);
- // let's see if the tile is inside the game field and it's free
- if (plantRow>=0&&plantCol>=0&&plantRow<5&&plantCol<9&&plantsArray[plantRow][plantCol]==0) {
- var placedPlant:plantMc=new plantMc();// 构建一株植物,用来种植
- placedPlant.name="plant_"+plantRow+"_"+plantCol;// 给植物一个名字
- placedPlant.fireRate=75;// 植物的开火速率,单位帧
- placedPlant.recharge=0;// 当recharge 等于 fireRate时,植物已经准备好开火了
- placedPlant.isFiring=false;// 一个布尔变量来存储植物是否正在开火
- placedPlant.plantRow=plantRow;// 植物所在的行
- plantContainer.addChild(placedPlant);// 把该植物加入到显示列表
- placedPlant.x=plantCol*65+57;
- placedPlant.y=plantRow*75+115;
- playerMoving=false;// 告诉脚本玩家不在移动植物了
- movingPlant.removeEventListener(MouseEvent.CLICK,placePlant);// 移除事件侦听
- overlayContainer.removeChild(selector);// 移除选择器
- overlayContainer.removeChild(movingPlant);// 移除供拖动的植物
- plantsArray[plantRow][plantCol]=1;// 更新游戏区块信息
- }
- }
- //
- // 游戏循环,游戏的核心函数
- //
- private function onEnterFrm(e:Event):void {
- var i:int;
- var j:int;
- //
- // 植物管理
- //
- for (i=0; i<plantContainer.numChildren; i++) {
- var currentPlant:plantMc=plantContainer.getChildAt(i) as plantMc;
- // 让我们看看植物是否能开火
- if (currentPlant.recharge==currentPlant.fireRate&&! currentPlant.isFiring) {
- // 检查是否有僵尸与植物处于同一行
- if (zombiesArray[currentPlant.plantRow].length>0) {
- // 遍历僵尸
- for (j=0; j<zombiesArray[currentPlant.plantRow].length>0; j++) {
- var targetZombie:zombieMc=zombieContainer.getChildByName(zombiesArray[currentPlant.plantRow]
- [j]) as zombieMc;// 获得第j个僵尸
- // 如果僵尸在植物的右边
- if (targetZombie.x>currentPlant.x) {
- var bullet:bulletMc=new bulletMc();// 创建一个新子弹
- bulletContainer.addChild(bullet);// 加入到显示列表
- bullet.x=currentPlant.x;
- bullet.y=currentPlant.y;
- bullet.sonOf=currentPlant;// 存储该子弹是由哪一株植物射出的
- currentPlant.recharge=0;// 重新准备开火
- currentPlant.isFiring=true;// 植物正在开火
- break;// 终止for循环
- }
- }
- }
- }
- if (currentPlant.recharge<currentPlant.fireRate) {
- currentPlant.recharge++;
- }
- }
- //
- // 子弹管理
- //
- for (i=0; i<bulletContainer.numChildren; i++) {
- var movingBullet:bulletMc=bulletContainer.getChildAt(i) as bulletMc;
- movingBullet.x+=3;//把每个子弹向右移动3个像素
- var firingPlant:plantMc=movingBullet.sonOf as plantMc;// 获得这个子弹是哪个植物射击的
- // 让我们看看子弹是否飞出了舞台
- if (movingBullet.x>650) {
- firingPlant.isFiring=false;// 植物不再处于正在开火的状态
- bulletContainer.removeChild(movingBullet);// 移除子弹
- } else {
- for (j=0; j<zombieContainer.numChildren; j++) {
- var movingZombie:zombieMc=zombieContainer.getChildAt(j) as zombieMc;
- // 让我们看看植物是否被子弹击中
- if (movingZombie.hitTestPoint(movingBullet.x,movingBullet.y,true)) {
- movingZombie.alpha-=0.3;//减少僵尸的能量(透明度)
- firingPlant.isFiring=false;// 植物不再处于正在开火的状态
- bulletContainer.removeChild(movingBullet);// 移除子弹
- // 让我们看看僵尸的能量(透明度)是否降至为0了
- if (movingZombie.alpha<0) {
- zombiesArray[movingZombie.zombieRow].splice(zombiesArray
- [movingZombie.zombieRow].indexOf(movingZombie.name),1);// 减少该行的僵尸
- zombieContainer.removeChild(movingZombie);// 移除显示列表
- }
- break;
- }
- }
- }
- }
- //
- // 僵尸管理
- //
- var zombieColumn:int;
- for (i=0; i<zombieContainer.numChildren; i++) {
- movingZombie=zombieContainer.getChildAt(i) as zombieMc;
- zombieColumn = Math.floor((movingZombie.x-25)/65);// 得到僵尸所在的列
- // 检查是否有植物与之处于同一个区块
- if (zombieColumn<0||zombieColumn>8||plantsArray[movingZombie.zombieRow][zombieColumn]==0) {
- movingZombie.x-=0.5;// 每一个僵尸往左移动0.5个像素
- } else {
- // 僵尸开始攻击!!
- var attackedPlant:plantMc=plantContainer.getChildByName("plant_"+movingZombie.zombieRow+"_"+zombieColumn) as
- plantMc;
- attackedPlant.alpha-=0.01;// drains plant energy
- //检查植物是否死了
- if (attackedPlant.alpha<0) {
- plantsArray[movingZombie.zombieRow][zombieColumn]=0;//把植物移出数组
- plantContainer.removeChild(attackedPlant);//移出显示列表
- }
- }
- }
- //
- // 阳光管理
- //
- for (i=0; i<sunContainer.numChildren; i++) {
- var fallingSun:sunMc=sunContainer.getChildAt(i) as sunMc;
- // 让我们看看阳光是否还在下落
- if (fallingSun.y<fallingSun.destinationY) {
- fallingSun.y++;// 把阳光往下移动一个像素
- } else {
- fallingSun.alpha-=0.01;// 使阳光淡出
- // 检查阳光是否消失了
- if (fallingSun.alpha<0) {
- fallingSun.removeEventListener(MouseEvent.CLICK,sunClicked);// 移除事件侦听
- from the
- sun
- sunContainer.removeChild(fallingSun);// 移出显示列表
- }
- }
- }
- //
- // 安置植物
- //
- if (playerMoving) {
- movingPlant.x=mouseX;
- movingPlant.y=mouseY;
- var plantRow:int=Math.floor((mouseY-80)/75);
- var plantCol:int=Math.floor((mouseX-25)/65);
- // 检查是否在游戏区域内
- if (plantRow>=0&&plantCol>=0&&plantRow<5&&plantCol<9) {
- selector.visible=true;// 显示选择器
- selector.x=25+plantCol*65;
- selector.y=80+plantRow*75;
- } else {
- selector.visible=false;// 隐藏选择器
- }
- }
- }
- }
- }
在setupField函数中,zombiesArray变成了一个二维数组,一个元素代表一行:
private function setupField():void {
plantsArray=new Array();
zombiesArray=new Array();
for (var i:uint=0; i<5; i++) {
plantsArray=new Array();
zombiesArray=new Array();
for (var j:uint=0; j<9; j++) {
plantsArray[j]=0;
}
}
}
在newZombie函数中,我们根据僵尸所在的行,把僵尸的名字加入到zombiesArray的合适的位置:
private function newZombie(e:TimerEvent):void {
var zombie:zombieMc=new zombieMc();// 构造僵尸
totalZombies++;
zombieContainer.addChild(zombie);// 加入到显示列表
zombie.zombieRow=Math.floor(Math.random()*5);// 选择一个随机行来安置僵尸
zombie.name="zombie_"+totalZombies;//给僵尸一个名字
zombiesArray[zombie.zombieRow].push(zombie.name);// 增加第row行的僵尸
zombie.x=660;// 把僵尸放在舞台右边
zombie.y=zombie.zombieRow*75+115;
}
现在,整个判断一株植物是否能开火就被改成了这样:
if (currentPlant.recharge==currentPlant.fireRate&&! currentPlant.isFiring) {
if (zombiesArray[currentPlant.plantRow].length>0) {
for (j=0; j<zombiesArray[currentPlant.plantRow].length>0; j++) {
var targetZombie:zombieMc=zombieContainer.getChildByName(zombiesArray[currentPlant.plantRow][j]) as zombieMc;
zombie
if (targetZombie.x>currentPlant.x) {
var bullet:bulletMc=new bulletMc();
bulletContainer.addChild(bullet);
bullet.x=currentPlant.x;
bullet.y=currentPlant.y;
bullet.sonOf=currentPlant;
currentPlant.recharge=0;
currentPlant.isFiring=true;
break;
}
}
}
}
我们遍历了所有与植物处于同一行上的僵尸,然后检查僵尸是在植物的左边还是在植物的右边(第214行)。
下面几行简单的代码使得僵尸攻击植物:
var zombieColumn:int;
for (i=0; i<zombieContainer.numChildren; i++) {
movingZombie=zombieContainer.getChildAt(i) as zombieMc;
zombieColumn = Math.floor((movingZombie.x-25)/65);
if (zombieColumn<0||zombieColumn>8||plantsArray[movingZombie.zombieRow][zombieColumn]==0) {
movingZombie.x-=0.5;
} else {
var attackedPlant:plantMc=plantContainer.getChildByName("plant_"+movingZombie.zombieRow+"_"+zombieColumn) as plantMc;
attackedPlant.alpha-=0.01;
if (attackedPlant.alpha<0) {
plantsArray[movingZombie.zombieRow][zombieColumn]=0;
plantContainer.removeChild(attackedPlant);
}
}
}
我们先检查了是否有植物被安置在僵尸当前所在的区块上,如果有,僵尸就停下脚步然后开始攻击植物,减少植物的生命值(当前是透明度)。
下面是结果:
你应该知道该怎么玩。尽量让你的植物被僵尸杀死吧。
下载源代码。