http://www.9ria.com/news/2011/0505/13143.html
下载:http://www.emanueleferonato.com/wp-content/uploads/2011/01/pvz4.zip
欢迎来到第四步。在这个步骤里,我们会使得植物能够开火,并且最终杀死僵尸。让我们先来明确一下什么时候植能开火:*当至少有一个僵尸与植物处于同一行*植物一次只能射出一颗子弹*距离上一次射击必须过去一定的时间现在让我们来定义一下子弹的活动:*子弹从左往右飞*当子弹击中一个僵尸时被移除*当子弹飞到舞台之外时被移除这6个概念给我们的脚本带来了一些大的改动。意识到把所有的代码写到一个类里使得脚本变得很混乱,我尽力以最清晰的方式来组织它。我尽我最大所能来使得它保持可读性。我创建了一个叫做bulletMc的对象,它代表了子弹。准备好去看一个接近300行的代码吗?
[code="flex"]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;// 布尔型变量,标志玩家是否在移动一个植物
public function Main():void {
setupField();// 初始化游戏区块
drawField();// 画出游戏区块
fallingSuns();// 初始化下落的阳光
addPlants();// 初始化植物
addZombies();// 初始化僵尸
addEventListener(Event.ENTER_FRAME,onEnterFrm);
}
//
// 游戏区域设置,创建用来存储植物和僵尸信息的数组
//
private function setupField():void {
plantsArray=new Array();
for (var i:uint=0; i=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);
// 检查该区块是否位于游戏区域内,并且该区块没有其它植物存在
if (plantRow>=0&&plantCol>=0&&plantRow0&&currentPlant.recharge==currentPlant.fireRate&&! currentPlant.isFiring) {
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;// 植物正在开火
}
if (currentPlant.recharge650) {
firingPlant.isFiring=false;// 植物不再处于正在开火的状态
bulletContainer.removeChild(movingBullet);// 移除子弹
} else {
for (j=0; j=0&&plantCol>=0&&plantRow
如果你一路跟随着我之前的几个教程做了下来的说话,你就会注意到我改变了很多的代码,但是原来的概念保持不变。我会把注意力放到新的东西上。首先,创建了一个新的数组,名为zombiesArray(第18行),它会存储每一行上的僵尸。这是非常有用的当我们想要知道一株植物是否能开火时。此刻,只要有一个僵尸与植物处于同一行时植物就能射击,我并不关心僵尸是在植物的左边还是右边,但是这个地方我将会再下一个步骤来改变它,使得只有僵尸在植物的右边时,植物才能开火,因为我可不想把植物放在僵尸的右边,然后看着它往右没有目标地开火。当一个新的僵尸被加到舞台,看一下newZombie函数的这两行:zombie.zombieRow=Math.floor(Math.random()*5);zombiesArray[zombie.zombieRow]++;给僵尸声明一个zombieRow属性,然后增加zombiesArray的第zombieRow个元素的值。多亏了这个数组,使得我总是可以轻易地知道有每一行分别有多少僵尸。再看下placePlant函数(第170行),这个函数我用来放置一株植物,我将给植物增加一些属性:placedPlant.fireRate=75;placedPlant.recharge=0;placedPlant.isFiring=false;placedPlant.plantRow=plantRow;我定义了植物开发的速率,单位是帧。它意味着植物至少要每隔fireRate帧开火一次。我选择用帧而不是用毫秒来作为植物开火的速率是因为如果有太多的对象在舞台上,游戏循环速率就会变慢,而不是保持不变。recharge属性每秒都帧都会增加,当它等于fireRate时,植物就准备好射击了。isFiring属性告诉我们植物是否正在射击。plantRow属性存储自己所在的行数。当检查有多少僵尸处于这一行时这个属性是很有用的。来看一下是否一株植物可以开火,我们用这个语句来描述:if (zombiesArray[currentPlant.plantRow]>0&&currentPlant.recharge==currentPlant.fireRate&&! currentPlant.isFiring) { 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;} 这个if语句检查与植物是否至少有一个僵尸与植物同一行,并且植物是否正在开火,是否准备好开火了。如果满足这些条件了,一个新的子弹就被创造出来了,并且植物的一些状态就被改变了,来告诉脚本植物正在开火,并且需要重新准备。但是所有上面的这些功能的实现,我们需要给子弹一个sonOf属性来存储它是哪一株植物射出来的。这是非常有用的一旦子弹要被移出舞台,我们就要更新射出该子弹的植物的isFiring状态。最后看一下杀死僵尸部分的核心代码,它是一个for循环:for (j=0; 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); if (movingZombie.alpha zombiesArray[movingZombie.zombieRow]--; zombieContainer.removeChild(movingZombie); } break; }} 我遍历所有的僵尸,进行碰撞检测。如果一个僵尸被子弹击中,我们移除子弹,并设置射出该子弹的植物的isFiring为false,并且减少僵尸的能量。此刻通过降低僵尸的透明度。如果透明度降至0,我们移除该僵尸,并且减少zombiesArray相应位置元素的值来更新在该行上僵尸的数量。现在你可以测试一下游戏了:[flash]http://www.emanueleferonato.com/wp-content/uploads/2011/01/pvz4.swf[/flash]收集硬币,购买植物然后杀死僵尸吧。下载源代码。下一次,我们将会使得僵尸也能攻击。