做一个像植物大战僵尸的Flash游戏5
现在,我们来到了这个教程的第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变成了一个二维数组,一个元素代表一行: http://www.emanueleferonato.com/wp-content/uploads/2011/03/pvz.swf (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |