原文地址
在经历了5篇大段代码的"重"教程后,我们终于到了塔防游戏最核心的组件:塔楼!塔楼在你的塔防游戏里至关重要.现在,我使用塔楼这个词并不一定意味这是一些一柱擎天的鸡巴,石头结构那样的东西并且给附近的敌人浇一阵死亡之雨( Now, by “towers” I don’t necessarily mean some phallic, stone structure jutting into the sky that rains death upon enemies nearby.).这里的"塔"可以是任何装置,对象,动物等等玩家可以放置在地图上的阻碍敌人到达他们目的地的.一些游戏可能会有实际的塔楼结构,一些游戏可能会有带有火箭炮的军队,一些游戏可能会有一个你可以放置在附近的房子或者产生装置,并且玩家的装置从其中产出以阻挡敌人.塔是一个主要的技工给玩家提供了一种方式来体验策略,手段,成就以及乐趣(更详尽的咱就不说了).
即便如此,不幸的是我在这个demo中对塔不太公平.如果你之前玩过demo,你就会看见我的两个塔只是简单地蓝色和红色框.敌人是动态的并且比塔漂亮得多.该死,即使子弹也有些跟随他们的粒子也比塔楼漂亮得多.不管怎么说,这就是关键.我上次像你展示了我是如何创建敌人动画的.你可以为塔楼做同样的事情自己做些有漂亮动画的塔楼他们有着不同的状态"装载弹药","射击"等等.
更新8/1/13-抽象出Tower的敌人寻找策略为ITowerStrategy.as以及TowerStrategyNearest.as.另外也加了些注释在设计模式上.
Ok,像我们之前有关敌人的文章一样,我们从我们如何定义塔楼的JSON数据开始
{ "towers": [ { "id": "tower1", "index": 0, "name": "Blue Tower", "imageName": "towers/tower1_001", "bulletImageName": "bullets/sparkle_blue_001", "bulletSpeed": 12, "bulletWidth": 32, "bulletHeight": 32, "towerWidth": 20, "towerHeight": 20, "maxLevel": 3, "sounds": [ { "state": "onFire", "soundId": "shot1" } ], "levelData": [ { "level": 1, "range": 75, "damage": 5, "speed": 1500, "dps": 3.33, "cost": 10 }, { "level": 2, "range": 150, "damage": 10, "speed": 1250, "dps": 8, "cost": 30 }, { "level": 3, "range": 200, "damage": 20, "speed": 900, "dps": 22.22, "cost": 50 } ] } ] }
这个是在src/assets/json/towers/towerData.json文件中列出的第一个塔,这个文件定义了两种类型的塔.我们逐行看下.
TowerManager.as
package com.zf.managers { import com.zf.core.Config; import com.zf.objects.enemy.Enemy; import com.zf.objects.tower.Tower; import com.zf.states.Play; import flash.geom.Point; import org.osflash.signals.Signal; import starling.display.Sprite; import starling.events.Touch; import starling.events.TouchEvent; import starling.events.TouchPhase; public class TowerManager implements IZFManager { public var play:Play; public var onTowerRemoved:Signal; public var onTowerAdded:Signal; public var onTowerManagerRemovingEnemy:Signal; private var _towers:Array; private var _towerData:Object; private var _currentTower:Tower; private var _p:Point = new Point(); private var _isDragging:Boolean = false; private var _canvas:Sprite; public function TowerManager(playState:Play, towerData:Object) { play = playState; _canvas = play.towerLayer; _towers = []; _setTowerData(towerData); onTowerAdded = new Signal(Tower); onTowerRemoved = new Signal(Tower); onTowerManagerRemovingEnemy = new Signal(Enemy); } public function update():void { if(_towers.length > 0) { var t:Tower, len:int = _towers.length; for(var i:int = len - 1; i >= 0; i--) { t = _towers[i]; t.update(); } } } public function destroy():void {} public function destroyTower(t:Tower):void { var len:int = _towers.length; for(var i:int = 0; i < len; i++) { if(t == _towers[i]) { _towers.splice(i, 1); t.destroy(); t.removeFromParent(true); } } onTowerRemoved.dispatch(t); } public function createNewTower(towerID:String, pos:Point):void { if(_currentTower) { _currentTower.deactivate(); } var tower:Tower = new Tower(_towerData[towerID], this); tower.setSoundData(_towerData[towerID].sounds); tower.x = pos.x - tower.halfWidth; tower.y = pos.y - tower.halfHeight; tower.activated = true; _currentTower = tower; play.addChild(tower); play.addEventListener(TouchEvent.TOUCH, towerFollowMouse); } public function towerFollowMouse(evt:TouchEvent):void { var touch:Touch = evt.getTouch(play); if(touch) { switch(touch.phase) { case TouchPhase.BEGAN: var checkObject:Object = play.map.checkCanPlaceTower(_p); if(checkObject.canPlace) { play.removeEventListener(TouchEvent.TOUCH, towerFollowMouse); evt.stopImmediatePropagation(); placeTower(checkObject.point); } break; case TouchPhase.ENDED: break; case TouchPhase.MOVED: break; case TouchPhase.HOVER: var tPos:Point = touch.getLocation(play); _currentTower.x = _p.x = tPos.x - _currentTower.halfWidth; _currentTower.y = _p.y = tPos.y - _currentTower.halfHeight; // Check if we can place, then update the tower image accordingly _currentTower.enterFrameTowerPlaceCheck(play.map.checkCanPlaceTower(_p).canPlace); break; } } }todo