Wonderfl Tower Defense (Mockup Test)
-----------------------------------------------------
* まだ全然出来てないんですが、とりあえずテストで投稿。
* 今後更新を重ねてちゃんと完成まで持っていく予定です。
*
* 4月から本気出す
*
* -----------------------------------------------------
/**
* Copyright o8que ( http://wonderfl.net/user/o8que )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/q7nD
*/
/* -----------------------------------------------------
* まだ全然出来てないんですが、とりあえずテストで投稿。
* 今後更新を重ねてちゃんと完成まで持っていく予定です。
*
* 4月から本気出す
*
* -----------------------------------------------------
*/
package {
import com.bit101.components.ProgressBar;
import flash.display.*;
import flash.events.Event;
public class Main extends Sprite {
public static var nodes:Array;
public static var towers:Array;
public static var enemies:Array;
public static var bullets:Array;
public static var goals:Array;
private var _fieldMap:FieldMap;
private var _frontend:Frontend;
public function Main() {
var preloader:Preloader = ImageFactory.preload(this);
preloader.addEventListener(Event.COMPLETE, initialize);
}
private function initialize(e:Event):void {
e.target.removeEventListener(Event.COMPLETE, initialize);
graphics.beginFill(0x000000);
graphics.drawRect(0, 0, 465, 465);
graphics.endFill();
initializeNodes();
towers = [];
enemies = [];
bullets = [];
goals = Parameter.getGoals();
addChild(_fieldMap = new FieldMap( -9, 12));
addChild(_frontend = new Frontend());
}
private function initializeNodes():void {
nodes = [];
for (var row:int = 0; row < Parameter.NODE_ROWS; row++) {
nodes[row] = [];
for (var col:int = 0; col < Parameter.NODE_COLS; col++) {
nodes[row][col] = new Node(col, row, Parameter.MAP_DATA[row][col]);
}
}
}
}
}
//package {
import flash.geom.Point;
//public
class Parameter {
public static const FRAMERATE:int = 30; // fps
public static const NODE_SIZE:Number = 16; // ノードの大きさ
public static const NODE_COLS:int = 24; // ノードの行数(横に並ぶ数)
public static const NODE_ROWS:int = 26; // ノードの列数(縦に並ぶ数)
public static const TOWER_SIZE:Number = NODE_SIZE * 2; // タワーの大きさ
public static const TOWER_IMAGE_SIZE:int = TOWER_SIZE + 8; // タワーの画像の大きさ
public static const TOWER_SELL_RATE:Number = 0.8; // タワー売却値の率
public static const SLOWING_TIME:Number = 4.0; // スロー状態の持続時間
public static const INITIAL_LIVES:int = 20; // ライフの初期値
public static const INITIAL_GOLD:int = 10000; // ゴールドの初期値
// マップを構成する各ノードの属性の情報
public static const MAP_DATA:Array = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1],
[1,0,0,0,0,0,0,0,0,0,2,1,1,2,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,1,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,1,1],
[1,1,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,1,1]
];
// 読み込むべき外部画像のリスト
public static const EXTERNAL_IMAGES:Object = {
Fieldmap : "http://assets.wonderfl.net/images/related_images/5/5f/5ff7/5ff7c989b7a1068c50a7008713931f651804468c",
Arrow : "http://assets.wonderfl.net/images/related_images/6/63/6343/63436a18a4aea50e9219db1a18fed0c3feddfd45",
Gatling : "http://assets.wonderfl.net/images/related_images/4/40/4008/4008e51eb77440a7421dfc0363f55fc4784f069c",
Bomb : "http://assets.wonderfl.net/images/related_images/b/b5/b5d2/b5d2a5c08373d1bd07375d9ad74bf502f9fcccc8",
Misslie : "http://assets.wonderfl.net/images/related_images/6/69/6950/6950fb7ed305b34a23392d7b1371a13b49a7ccbc",
Frost : "http://assets.wonderfl.net/images/related_images/6/69/6931/6931d44cd4bbf0feb60b4c2d24ffa6f29098479b",
Vortex : "http://assets.wonderfl.net/images/related_images/d/df/df45/df45671017d8385c582396d44f98e8e2fd705ee2",
Laser : "http://assets.wonderfl.net/images/related_images/9/92/9245/9245550bd2d49a69cec242205454199d1e4f6b87"
};
private static const data:XML =
<root>
<towers>
<tower name="Arrow" ground="1" air="1" slow="0" splash="0">
<stats rank="E" cost="10" damage="30" range="60" firerate="1.5" />
<stats rank="D" cost="20" damage="60" range="65" firerate="1.5" />
<stats rank="C" cost="40" damage="90" range="70" firerate="1.5" />
<stats rank="B" cost="80" damage="120" range="75" firerate="1.5" />
<stats rank="A" cost="280" damage="150" range="150" firerate="1.5" />
</tower>
<tower name="Gatling" ground="1" air="1" slow="0" splash="0">
<stats rank="E" cost="20" damage="15" range="50" firerate="3" />
<stats rank="D" cost="40" damage="30" range="55" firerate="4" />
<stats rank="C" cost="80" damage="45" range="60" firerate="5" />
<stats rank="B" cost="160" damage="60" range="65" firerate="6" />
<stats rank="A" cost="400" damage="90" range="70" firerate="8" />
</tower>
<tower name="Bomb" ground="1" air="0" slow="0" splash="1">
<stats rank="E" cost="25" damage="10" range="90" firerate="1" />
<stats rank="D" cost="50" damage="20" range="95" firerate="1" />
<stats rank="C" cost="75" damage="40" range="100" firerate="1" />
<stats rank="B" cost="100" damage="80" range="105" firerate="1" />
<stats rank="A" cost="300" damage="160" range="120" firerate="1" />
</tower>
<tower name="Misslie" ground="0" air="1" slow="0" splash="0">
<stats rank="E" cost="30" damage="25" range="65" firerate="4" />
<stats rank="D" cost="60" damage="50" range="65" firerate="4" />
<stats rank="C" cost="120" damage="100" range="65" firerate="4" />
<stats rank="B" cost="180" damage="200" range="65" firerate="4" />
<stats rank="A" cost="240" damage="300" range="65" firerate="4" />
</tower>
<tower name="Frost" ground="1" air="1" slow="1" splash="1">
<stats rank="E" cost="50" damage="10" range="50" firerate="0.5" />
<stats rank="D" cost="100" damage="15" range="50" firerate="0.7" />
<stats rank="C" cost="150" damage="20" range="55" firerate="0.7" />
<stats rank="B" cost="200" damage="25" range="55" firerate="0.9" />
<stats rank="A" cost="150" damage="30" range="60" firerate="1.0" />
</tower>
<tower name="Vortex" ground="1" air="0" slow="0" splash="1">
<stats rank="E" cost="100" damage="150" range="40" firerate="0.3" />
<stats rank="D" cost="200" damage="300" range="40" firerate="0.3" />
<stats rank="C" cost="400" damage="600" range="40" firerate="0.3" />
<stats rank="B" cost="600" damage="1000" range="40" firerate="0.3" />
<stats rank="A" cost="1000" damage="2000" range="40" firerate="0.3" />
</tower>
<tower name="Laser" ground="1" air="1" slow="0" splash="1">
<stats rank="E" cost="150" damage="80" range="80" firerate="0.3" />
<stats rank="D" cost="300" damage="160" range="80" firerate="0.3" />
<stats rank="C" cost="450" damage="320" range="80" firerate="0.4" />
<stats rank="B" cost="900" damage="640" range="80" firerate="0.4" />
<stats rank="A" cost="2000" damage="960" range="80" firerate="0.5" />
</tower>
</towers>
<enemies>
<enemy type="Normal" hpbase="2" hpgrow="7" bounty="1" speed="1.0" />
<enemy type="Immune" hpbase="2" hpgrow="6" bounty="1" speed="1.0" />
<enemy tyep="Flying" hpbase="2" hpgrow="5" bounty="2" speed="1.0" />
</enemies>
<levels>
<level type="normal" time="20"><spawn num="10" /><spawn num="0" /><spawn num="10" /></level>
</levels>
<starts>
<start x="35" y="400" width="75" height="12"/>
<start x="275" y="400" width="75" height="12"/>
<start x="160" y="400" width="64" height="12"/>
</starts>
<goals>
<goal x="10" y="3" /><goal x="10" y="4" />
<goal x="11" y="4" /><goal x="12" y="4" />
<goal x="13" y="3" /><goal x="13" y="4" />
</goals>
</root>;
// タワーの属性情報を返す
public static function getTowerAttlibutes(towerName:String):Object {
var tower:XMLList = Parameter.data.towers.*.(@name == towerName);
if (tower.length() == 0) { return null; } // 指定した名前のタワーが存在しないならnullを返す
return {
ground : Boolean(int(tower.@ground)),
air : Boolean(int(tower.@air)),
slow : Boolean(int(tower.@slow)),
splash : Boolean(int(tower.@splash))
};
}
// タワーのステータス情報を返す
public static function getTowerStats(towerName:String, rankNum:int):Object {
var stats:XML = Parameter.data.towers.*.(@name == towerName).stats[rankNum];
if (stats == null) { return null; } // ステータス情報が無いならnullを返す
return {
rank : stats.@rank,
cost : stats.@cost,
damage : stats.@damage,
range : stats.@range,
firerate : stats.@firerate
};
}
// ゴールの配列を返す
public static function getGoals():Array {
var goals:Array = [];
for each(var g:XML in Parameter.data.goals.*) {
goals.push(new Goal(new Point(int(g.@x), int(g.@y))));
}
return goals;
}
}
//}
//package {
import flash.display.*;
import flash.filters.*;
import flash.geom.Matrix;
import flash.text.*;
//public
class ImageFactory {
private static var _externalImages:Object; // 外部画像の連想配列
private static var _enemyImages:Object; // 敵画像の連想配列
private static var _towerBase:BitmapData = null; // タワーの土台
private static var _cancelMark:BitmapData = null; // (タワー選択)キャンセルのマーク
// プリローダーを作成、読み込みを開始する
public static function preload(parentOfProgressBar:DisplayObjectContainer):Preloader {
initializeEnemyImages();
_externalImages = { };
return new Preloader(parentOfProgressBar, _externalImages);
}
// 敵画像の連想配列を初期化する
private static function initializeEnemyImages():void {
_enemyImages = { };
var enemyTypes:Array = ["Normal", "Immune", "Flying"];
for (var i:int = 0; i < enemyTypes.length; i++) {
_enemyImages[enemyTypes[i]] = ImageFactory.createEnemy(enemyTypes[i]);
}
}
// 外部画像を取得する
public static function getImage(name:String):BitmapData {
return _externalImages[name];
}
// 敵画像を取得する
public static function getEnemy(name:String):BitmapData {
return _enemyImages[name];
}
// キャンセルのマークの画像を取得する
public static function getCancelMark():BitmapData {
if (_cancelMark == null) {
_cancelMark = new BitmapData(Parameter.TOWER_IMAGE_SIZE, Parameter.TOWER_IMAGE_SIZE, true, 0x00ffffff);
var shape:Shape = new Shape();
var center:Number = Parameter.TOWER_IMAGE_SIZE / 2;
var radius:Number = center - 8;
shape.graphics.lineStyle(4, 0xff0000);
shape.graphics.drawCircle(center, center, radius);
shape.graphics.moveTo(center + (radius * Math.cos(9 * Math.PI / 8)), center + (radius * Math.sin(9 * Math.PI / 8)));
shape.graphics.lineTo(center + (radius * Math.cos(Math.PI / 8)), center + (radius * Math.sin(Math.PI / 8)));
_cancelMark.draw(shape);
}
return _cancelMark;
}
// タワーの土台の画像を取得する
public static function getTowerBase():BitmapData {
if (_towerBase == null) {
_towerBase = new BitmapData(Parameter.TOWER_SIZE, Parameter.TOWER_SIZE);
var shape:Shape = new Shape();
shape.graphics.beginFill(0xc0c0c0);
shape.graphics.drawRect(0, 0, Parameter.TOWER_SIZE, Parameter.TOWER_SIZE);
shape.graphics.endFill();
shape.filters = [new BevelFilter(1, 45, 0xffffff, 1, 0x606060, 1, Parameter.TOWER_SIZE / 4, Parameter.TOWER_SIZE / 4, 255)];
_towerBase.draw(shape);
}
return _towerBase;
}
// 敵の画像を作成する
private static function createEnemy(type:String):BitmapData {
var bitmapData:BitmapData = new BitmapData(Parameter.NODE_SIZE, Parameter.NODE_SIZE, true, 0x00ffffff);
var shape:Shape;
switch(type) {
case "Normal": shape = ImageFactory.createNormalEnemy(); break;
case "Immune": shape = ImageFactory.createImmuneEnemy(); break;
case "Flying": shape = ImageFactory.createFlyingEnemy(); break;
default: shape = new Shape();
}
bitmapData.draw(shape);
return bitmapData;
}
private static function createNormalEnemy():Shape {
var shape:Shape = new Shape();
shape.graphics.beginFill(0xff0000);
shape.graphics.drawRect(4, 2, 4, 12);
shape.graphics.drawRect(8, 6, 4, 4);
shape.graphics.endFill();
shape.filters = [new GlowFilter(0x880000, 1, 2, 2, 255)];
return shape;
}
private static function createImmuneEnemy():Shape {
var shape:Shape = new Shape();
shape.graphics.beginFill(0xff0000);
shape.graphics.drawCircle(8, 8, 6);
shape.graphics.endFill();
shape.filters = [new GlowFilter(0x880000, 1, 2, 2, 255)];
return shape;
}
private static function createFlyingEnemy():Shape {
var shape:Shape = new Shape();
shape.graphics.lineStyle(1, 0x880000);
shape.graphics.beginFill(0xff0000);
shape.graphics.moveTo(2, 4);
shape.graphics.lineTo(10, 4);
shape.graphics.lineTo(14, 8);
shape.graphics.lineTo(2, 4);
shape.graphics.endFill();
return shape;
}
// 普通のテキストを作成する
public static function createSimpleText(posx:int, posy:int, width:int, height:int, text:String, fontSize:int, textColor:uint):TextField {
return ImageFactory.createText(posx, posy, width, height, text, fontSize, textColor, TextFieldAutoSize.CENTER);
}
// 縁取り付きのテキストを作成する
public static function createBorderedText(posx:int, posy:int, width:int, height:int, text:String, fontSize:int, textColor:uint, borderColor:uint):TextField {
return ImageFactory.createText(posx, posy, width, height, text, fontSize, textColor, TextFieldAutoSize.CENTER, false, true, borderColor);
}
// スコア表示用のテキストを作成する
public static function createScoreText(posx:int, posy:int, width:int, height:int, text:String, fontSize:int, textColor:uint):TextField {
return ImageFactory.createText(posx, posy, width, height, text, fontSize, textColor, TextFieldAutoSize.RIGHT, true);
}
// タワーのステータス表示用テキストを作成する
public static function createStatsText(posx:int, posy:int, width:int, height:int, text:String, fontSize:int, textColor:uint):TextField {
return ImageFactory.createText(posx, posy, width, height, text, fontSize, textColor, TextFieldAutoSize.CENTER, true);
}
private static function createText(posx:int, posy:int, width:int, height:int, text:String, fontSize:int, textColor:uint, autoSize:String, bold:Boolean = false, border:Boolean = false, borderColor:uint = 0x000000):TextField {
var textField:TextField = new TextField();
var textFormat:TextFormat = new TextFormat("Arial", fontSize, null, bold);
textField.defaultTextFormat = textFormat;
textField.text = text;
textField.x = posx;
textField.y = posy + Math.ceil((height - (textField.textHeight + 4)) / 2);
textField.width = Math.max(width, textField.textWidth);
textField.height = textField.textHeight + 4;
textField.textColor = textColor;
if (border) { textField.filters = [new GlowFilter(borderColor, 1, 4, 4)]; }
textField.autoSize = autoSize;
textField.mouseEnabled = textField.selectable = false;
return textField;
}
// ウインドウを作成する(FF6っぽいヤツ)
public static function createWindow(posx:int, posy:int, width:int, height:int):Sprite {
var sprite:Sprite = new Sprite();
sprite.x = posx;
sprite.y = posy;
var matrix:Matrix = new Matrix();
matrix.createGradientBox(width, height, Math.PI / 2);
sprite.graphics.lineStyle(2);
sprite.graphics.lineGradientStyle(GradientType.LINEAR, [0xf0f0f0, 0x808080], [1, 1], [0, 255], matrix);
sprite.graphics.beginGradientFill(GradientType.LINEAR, [0x303090, 0x000030], [1, 1], [0, 255], matrix);
sprite.graphics.drawRoundRect(1, 1, width - 2, height - 2, 10);
sprite.graphics.endFill();
return sprite;
}
// カーソルを描画する
public static function drawCursor(g:Graphics):void {
g.lineStyle(1, 0xffffff);
g.drawRect(0.5, 0.5, Parameter.TOWER_SIZE - 1, Parameter.TOWER_SIZE - 1);
g.endFill();
}
// 射程範囲の円を描画する
public static function drawRangeCircle(g:Graphics, radius:int = 16, color:uint = 0xffffff):void {
g.beginFill(color, 0.3);
g.drawCircle(Parameter.TOWER_SIZE / 2, Parameter.TOWER_SIZE / 2, radius);
g.endFill();
}
}
//}
//package {
import com.bit101.components.ProgressBar;
import flash.display.DisplayObjectContainer;
import flash.events.*;
//public
class Preloader extends EventDispatcher {
private var _imageNum:int; // 読み込むべき外部画像の数
private var _loadedNum:int; // 読み込み完了した外部画像の数
private var _loaders:Object; // 外部画像ローダの連想配列
private var _imagesReference:Object; // 外部画像の連想配列の参照
private var _progressBar:ProgressBar; // プログレスバー
public function Preloader(parentOfProgressBar:DisplayObjectContainer, images:Object) {
_imageNum = 0;
_loadedNum = 0;
_loaders = { };
_imagesReference = images;
_progressBar = new ProgressBar(parentOfProgressBar, 182, 227);
// 各外部画像の読み込みを開始する
for (var imageName:* in Parameter.EXTERNAL_IMAGES) {
_imageNum++;
var loader:ExternalImageLoader = new ExternalImageLoader();
_loaders[imageName] = loader;
loader.addEventListener(Event.COMPLETE, imageLoaded);
loader.load(Parameter.EXTERNAL_IMAGES[imageName]);
}
_progressBar.maximum = _imageNum;
}
// 一つの画像の読み込みが完了した際に呼ばれるメソッド
private function imageLoaded(e:Event):void {
e.target.removeEventListener(Event.COMPLETE, imageLoaded);
_loadedNum++;
_progressBar.value = _loadedNum;
if (_loadedNum == _imageNum) { loadComplete(); }
}
// 全ての画像の読み込みが完了した際に呼ばれるメソッド
private function loadComplete():void {
for (var imageName:* in _loaders) {
_imagesReference[imageName] = _loaders[imageName].content;
}
DisplayObjectContainer(_progressBar.parent).removeChild(_progressBar);
dispatchEvent(new Event(Event.COMPLETE));
}
}
//}
//package {
import flash.display.*;
import flash.events.*;
import flash.net.URLRequest;
import flash.system.LoaderContext;
//public
class ExternalImageLoader extends EventDispatcher {
private var _content:BitmapData;
private var _tmpA:Loader;
private var _tmpB:Loader;
public function get content():BitmapData { return _content; }
public function ExternalImageLoader() {
_content = null;
_tmpA = new Loader();
_tmpB = new Loader();
}
public function load(url:String):void {
_tmpA.contentLoaderInfo.addEventListener(Event.INIT, tmpALoaded);
_tmpA.load(new URLRequest(url), new LoaderContext(true));
}
private function tmpALoaded(e:Event):void {
_tmpA.contentLoaderInfo.removeEventListener(Event.INIT, tmpALoaded);
_content = new BitmapData(int(_tmpA.width), int(_tmpA.height), true, 0x00ffffff);
_tmpB.contentLoaderInfo.addEventListener(Event.INIT, tmpBLoaded);
_tmpB.loadBytes(_tmpA.contentLoaderInfo.bytes);
}
private function tmpBLoaded(e:Event):void {
_tmpB.contentLoaderInfo.removeEventListener(Event.INIT, tmpBLoaded);
_content.draw(_tmpB);
_tmpA.unload();
_tmpB.unload();
dispatchEvent(new Event(Event.COMPLETE));
}
}
//}
//package {
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
//public
class FieldMap extends Sprite {
private var _groundEnemyLayer:Sprite;
private var _towerLayer:Sprite;
private var _airEnemyLayer:Sprite;
private var _bulletLayer:Sprite;
private var _cursor:Sprite;
public function FieldMap(posx:int, posy:int) {
x = posx;
y = posy;
addChild(new Bitmap(ImageFactory.getImage("Fieldmap")));
addChild(_groundEnemyLayer = new Sprite());
addChild(_towerLayer = new Sprite());
addChild(_airEnemyLayer = new Sprite());
addChild(_bulletLayer = new Sprite());
addChild(_cursor = new Sprite());
_bulletLayer.mouseEnabled = _cursor.mouseEnabled = false;
_cursor.visible = false;
addEventListener(MouseEvent.CLICK, clickFieldMap);
addEventListener(MouseEvent.ROLL_OVER, showCursor);
addEventListener(MouseEvent.ROLL_OUT, hideCursor);
//test
var e:Enemy = new Enemy(new Point(40, 390), { hp:1, bounty:1, speed:1 } );
Main.enemies.push(e);
_groundEnemyLayer.addChild(e);
addEventListener(Event.ENTER_FRAME, test);
}
private function test(e:Event):void {
for (var i:int = 0; i < Main.towers.length; i++) {
Main.towers[i].update();
}
for (var j:int = 0; j < Main.enemies.length; j++) {
Main.enemies[j].update();
}
}
private function clickFieldMap(e:MouseEvent):void {
var data:GameData = GameData.instance;
var selectedTower:Tower = data.selectedTower;
if (selectedTower != null && !selectedTower.active) {
if (Node.buildable(_cursor.x, _cursor.y) && data.buyable(selectedTower.cost) && Goal.reSearch(Node.tileFromPosition(new Point(_cursor.x,_cursor.y)))) {
var tower:Tower = new Tower(_cursor.x, _cursor.y, data.selectedTower.towerName, true);
data.spendGold(selectedTower.cost);
Main.towers.push(tower);
_towerLayer.addChild(tower);
}
}
}
private function showCursor(e:MouseEvent):void {
_cursor.visible = true;
addEventListener(Event.ENTER_FRAME, updateCursor);
}
private function hideCursor(e:MouseEvent):void {
removeEventListener(Event.ENTER_FRAME, updateCursor);
_cursor.visible = false;
}
private function updateCursor(e:Event):void {
var selectedTower:Tower = GameData.instance.selectedTower;
if(!(selectedTower != null && selectedTower.active)){
_cursor.x = mouseX - (mouseX % Parameter.NODE_SIZE);
_cursor.y = mouseY - (mouseY % Parameter.NODE_SIZE);
}else {
_cursor.x = selectedTower.x;
_cursor.y = selectedTower.y;
}
_cursor.graphics.clear();
if (selectedTower != null) {
ImageFactory.drawRangeCircle(_cursor.graphics, selectedTower.range, 0xffffff);
ImageFactory.drawCursor(_cursor.graphics);
}
}
}
//}
//package {
import com.bit101.components.*;
import flash.display.*;
import flash.events.*;
import flash.text.*;
//public
class Frontend extends Sprite {
private var _level:TextField;
private var _score:TextField;
private var _lives:TextField;
private var _gold:TextField;
private var _towerStatsWindow:Sprite;
private var _towerMenuWindow:Sprite;
private var _name:TextField;
private var _attlibuteGround:TextField;
private var _attlibuteAir:TextField;
private var _attlibuteSlow:TextField;
private var _attlibuteSplash:TextField;
private var _rank:TextField;
private var _cost:TextField;
private var _damage:TextField;
private var _range:TextField;
private var _fireRate:TextField;
public function Frontend() {
setupMainStatsWindow();
setupTowerSelectWindow();
setupTowerStatsWindow();
setupLevelBarWindow();
setupMenuWindow();
GameData.instance.addEventListener(Event.CHANGE, update);
}
// メインステータスを表示するウインドウを配置する
private function setupMainStatsWindow():void {
var mainStatsWindow:Sprite = ImageFactory.createWindow(0, 0, 365, 25);
mainStatsWindow.addChild(ImageFactory.createBorderedText(14, 0, 40, 25, "Level :", 12, 0xffffff, 0x808080));
mainStatsWindow.addChild(_level = ImageFactory.createScoreText(54, 0, 25, 25, "0", 14, 0xffffff));
mainStatsWindow.addChild(ImageFactory.createBorderedText(93, 0, 40, 25, "Score :", 12, 0xffffff, 0x808080));
mainStatsWindow.addChild(_score = ImageFactory.createScoreText(133, 0, 50, 25, "0", 14, 0xffffff));
mainStatsWindow.addChild(ImageFactory.createBorderedText(197, 0, 40, 25, "Lives :", 12, 0xffffff, 0xf00000));
mainStatsWindow.addChild(_lives = ImageFactory.createScoreText(237, 0, 20, 25, Parameter.INITIAL_LIVES.toString(), 14, 0xff0000));
mainStatsWindow.addChild(ImageFactory.createBorderedText(271, 0, 35, 25, "Gold :", 12, 0xffffff, 0xb0b000));
mainStatsWindow.addChild(_gold = ImageFactory.createScoreText(306, 0, 45, 25, Parameter.INITIAL_GOLD.toString(), 14, 0xffff00));
addChild(mainStatsWindow);
}
// タワーを選択するウインドウを配置する
private function setupTowerSelectWindow():void {
var towerSelectWindow:Sprite = ImageFactory.createWindow(365, 0, 100, 415);
var towerNames:Array = ["Arrow", "Gatling", "Bomb", "Misslie", "Frost", "Vortex", "Laser", "Cancel"];
for (var i:int = 0; i < 8; i++) {
var tower:Tower = new Tower(((i < 4) ? 15 : 53), (7 + 38 * (i % 4)), towerNames[i], false);
towerSelectWindow.addChild(tower);
if (i < 7) { towerSelectWindow.addChild(ImageFactory.createSimpleText(((i < 4) ? 1 : 85), tower.y, 14, 32, String(i + 1), 10, 0xffffff)); }
}
addChild(towerSelectWindow);
}
// タワーのステータスを表示するウインドウを作成する
private function setupTowerStatsWindow():void {
_towerStatsWindow = ImageFactory.createWindow(370, 160, 90, 250);
_towerStatsWindow.addChild(ImageFactory.createWindow(0, 0, 90, 20));
_towerStatsWindow.addChild(_name = ImageFactory.createSimpleText(0, 0, 90, 20, "Tower", 12, 0xffffff));
_towerStatsWindow.addChild(_attlibuteGround = ImageFactory.createSimpleText(5, 25, 40, 10, "Ground", 10, 0xffffff));
_towerStatsWindow.addChild(_attlibuteAir = ImageFactory.createSimpleText(5, 35, 40, 10, "Air", 10, 0xffffff));
_towerStatsWindow.addChild(_attlibuteSlow = ImageFactory.createSimpleText(45, 25, 40, 10, "Slow", 10, 0x606060));
_towerStatsWindow.addChild(_attlibuteSplash = ImageFactory.createSimpleText(45, 35, 40, 10, "Splash", 10, 0x606060));
_towerStatsWindow.addChild(ImageFactory.createBorderedText(0, 50, 90, 10, "Rank", 10, 0xffffff, 0x00b000));
_towerStatsWindow.addChild(_rank = ImageFactory.createStatsText(0, 62, 90, 15, "E", 14, 0x00ff00));
_towerStatsWindow.addChild(ImageFactory.createBorderedText(0, 80, 90, 10, "Cost", 10, 0xffffff, 0xb0b000));
_towerStatsWindow.addChild(_cost = ImageFactory.createStatsText(0, 92, 90, 15, "0", 14, 0xffff00));
_towerStatsWindow.addChild(ImageFactory.createBorderedText(0, 110, 90, 10, "Damage", 10, 0xffffff, 0xf00000));
_towerStatsWindow.addChild(_damage = ImageFactory.createStatsText(0, 122, 90, 15, "0", 14, 0xff0000));
_towerStatsWindow.addChild(ImageFactory.createBorderedText(0, 140, 90, 10, "Range", 10, 0xffffff, 0x00b0b0));
_towerStatsWindow.addChild(_range = ImageFactory.createStatsText(0, 152, 90, 15, "0", 14, 0x00ffff));
_towerStatsWindow.addChild(ImageFactory.createBorderedText(0, 170, 90, 10, "FireRate", 10, 0xffffff, 0xb000b0));
_towerStatsWindow.addChild(_fireRate = ImageFactory.createStatsText(0, 182, 90, 15, "0", 14, 0xff00ff));
_towerStatsWindow.addChild(_towerMenuWindow = ImageFactory.createWindow(0, 200, 90, 50));
var upgradeButton:PushButton = new PushButton(_towerMenuWindow, 5, 5, "Upgrade", clickUpdateButton);
var sellButton:PushButton = new PushButton(_towerMenuWindow, 5, 25, "Sell", clickSellButton);
upgradeButton.width = sellButton.width = 80;
addChild(_towerStatsWindow);
_towerStatsWindow.visible = false;
}
private function clickUpdateButton(e:MouseEvent):void {
GameData.instance.selectedTower.upgrade();
GameData.instance.setSelectedTower(GameData.instance.selectedTower);
}
// 売却ボタンを押した時の処理
private function clickSellButton(e:MouseEvent):void {
GameData.instance.selectedTower.sell();
GameData.instance.setSelectedTower(null);
}
// レベルバーを表示するウインドウを配置する
private function setupLevelBarWindow():void {
var levelBarWindow:Sprite = ImageFactory.createWindow( -10, 415, 475, 50);
/*
var backgroundBar:Shape = new Shape();
backgroundBar.graphics.beginFill(0x000000);
backgroundBar.graphics.drawRect(0, 10, 475, 30);
backgroundBar.graphics.endFill();
levelBarWindow.addChild(backgroundBar);
var hand:Shape = new Shape();
hand.graphics.lineStyle(1, 0xffff00);
hand.graphics.moveTo(45, 2);
hand.graphics.lineTo(45, 48);
levelBarWindow.addChild(hand);
*/
addChild(levelBarWindow);
}
// メニューウインドウを配置する
private function setupMenuWindow():void {
var menuWindow:Sprite = ImageFactory.createWindow(365, 415, 100, 50);
//var pauseButton:PushButton = new PushButton(menuWindow, 5, 4, "Pause", null);
//var nextLevelButton:PushButton = new PushButton(menuWindow, 5, 26, "Next Level", null);
//pauseButton.width = nextLevelButton.width = 90;
addChild(menuWindow);
}
// ゲーム情報の更新を反映する
public function update(e:Event):void {
updateMainStatsWindow();
updateTowerStatsWindow();
}
// メインステータス表示を更新する
private function updateMainStatsWindow():void {
var data:GameData = GameData.instance;
_level.text = data.level.toString();
_score.text = data.score.toString();
_lives.text = data.lives.toString();
_gold.text = data.gold.toString();
}
// タワーのステータス表示を更新する
private function updateTowerStatsWindow():void {
_towerStatsWindow.visible = (GameData.instance.selectedTower != null);
if (_towerStatsWindow.visible) {
var selectedTower:Tower = GameData.instance.selectedTower;
_towerMenuWindow.visible = selectedTower.active;
_name.text = selectedTower.towerName + " Tower";
var onColor:uint = 0xffffff;
var offColor:uint = 0x606060;
_attlibuteGround.textColor = (selectedTower.ground ? onColor : offColor);
_attlibuteAir.textColor = (selectedTower.air ? onColor : offColor);
_attlibuteSlow.textColor = (selectedTower.slow ? onColor : offColor);
_attlibuteSplash.textColor = (selectedTower.splash ? onColor : offColor);
_rank.text = selectedTower.rank + ((selectedTower.active && selectedTower.hasNextRank()) ? (" → " + selectedTower.nextRank) : "");
_cost.text = selectedTower.cost + ((selectedTower.active && selectedTower.hasNextRank()) ? (" + " + (selectedTower.nextCost - selectedTower.cost)) : "");
_damage.text = selectedTower.damage + ((selectedTower.active && selectedTower.hasNextRank()) ? (" + " + (selectedTower.nextDamage - selectedTower.damage)) : "");
_range.text = selectedTower.range + ((selectedTower.active && selectedTower.hasNextRank()) ? (" + " + (selectedTower.nextRange - selectedTower.range)) : "");
_fireRate.text = selectedTower.fireRate.toFixed(1) + ((selectedTower.active && selectedTower.hasNextRank()) ? (" + " + (selectedTower.nextFireRate - selectedTower.fireRate).toFixed(1)) : "");
}
}
}
//}
//package {
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.geom.Point;
//public
class GameData extends EventDispatcher {
private static var _instance:GameData;
private var _selectedTower:Tower;
private var _level:int;
private var _score:int;
private var _lives:int;
private var _gold:int;
public function get selectedTower():Tower { return _selectedTower; }
public function get level():int { return _level; }
public function get score():int { return _score; }
public function get lives():int { return _lives; }
public function get gold():int { return _gold; }
public function GameData(enforcer:SingletonEnforcer) {
initialize();
}
public function initialize():void {
_level = 0;
_score = 0;
_lives = Parameter.INITIAL_LIVES;
_gold = Parameter.INITIAL_GOLD;
dispatchEvent(new Event(Event.CHANGE));
}
// 選択中のタワーを設定する
public function setSelectedTower(tower:Tower):void {
_selectedTower = tower;
dispatchEvent(new Event(Event.CHANGE));
}
public function damageLives():void {
_lives--;
dispatchEvent(new Event(Event.CHANGE));
}
// 購入できるかどうか
public function buyable(price:int):Boolean {
return price <= _gold;
}
// ゴールドを得る
public function earnGold(amount:int):void {
_gold += amount;
dispatchEvent(new Event(Event.CHANGE));
}
// ゴールドを消費する
public function spendGold(amount:int):void {
_gold -= amount;
dispatchEvent(new Event(Event.CHANGE));
}
public static function get instance():GameData {
if (GameData._instance == null) {
_instance = new GameData(new SingletonEnforcer());
}
return _instance;
}
}
//}
class SingletonEnforcer { }
//package {
import flash.geom.Point;
//public
class Node {
private var _tile:Point;
private var _center:Point;
private var _passable:Boolean; // 敵が通れるかどうか
private var _buildable:Boolean; // タワーが建てられるかどうか
private var _enemyNum:int; // このノード上にいる敵の数
public function get tileX():int { return _tile.x; }
public function get tileY():int { return _tile.y; }
public function get centerX():Number { return _center.x; }
public function get centerY():Number { return _center.y; }
public function get passable():Boolean { return _passable; }
public function set passable(value:Boolean):void { _passable = value; }
public function get buildable():Boolean { return _buildable && (_enemyNum == 0); }
public function set buildable(value:Boolean):void { _buildable = value; };
public function get enemyNum():int { return _enemyNum; }
public function set enemyNum(value:int):void { _enemyNum = value; }
public function Node(tilex:int, tiley:int, type:int) {
_tile = new Point(tilex, tiley);
var pos:Point = Node.positionFromTile(_tile);
_center = new Point(pos.x + (Parameter.NODE_SIZE / 2), pos.y +(Parameter.NODE_SIZE / 2));
switch(type) {
case 0: _passable = true; _buildable = true; break;
case 1: _passable = false; _buildable = false; break;
case 2: _passable = true; _buildable = false; break;
}
_enemyNum = 0;
}
// タイル縦横値から、XY座標値を求める
public static function positionFromTile(tile:Point):Point {
var pos:Point = new Point();
pos.x = tile.x * Parameter.NODE_SIZE;
pos.x = Math.max(0, Math.min(pos.x, (Parameter.NODE_COLS - 1) * Parameter.NODE_SIZE));
pos.y = tile.y * Parameter.NODE_SIZE;
pos.y = Math.max(0, Math.min(pos.y, (Parameter.NODE_ROWS - 1) * Parameter.NODE_SIZE));
return pos;
}
// XY座標値から、タイル縦横値を求める
public static function tileFromPosition(pos:Point):Point {
var tile:Point = new Point();
tile.x = int(pos.x / Parameter.NODE_SIZE);
tile.x = Math.max(0, Math.min(tile.x, Parameter.NODE_COLS - 1));
tile.y = int(pos.y / Parameter.NODE_SIZE);
tile.y = Math.max(0, Math.min(tile.y, Parameter.NODE_ROWS - 1));
return tile;
}
// タワーが設置できるかどうか
public static function buildable(posx:int, posy:int):Boolean {
var tile:Point = Node.tileFromPosition(new Point(posx, posy));
return (Main.nodes[tile.y][tile.x].buildable &&
Main.nodes[tile.y + 1][tile.x].buildable &&
Main.nodes[tile.y][tile.x + 1].buildable &&
Main.nodes[tile.y + 1][tile.x + 1].buildable);
}
public static function changeBulidablity(towerTile:Point, buildable:Boolean):void {
Main.nodes[towerTile.y][towerTile.x].buildable = buildable;
Main.nodes[towerTile.y + 1][towerTile.x].buildable = buildable;
Main.nodes[towerTile.y][towerTile.x + 1].buildable = buildable;
Main.nodes[towerTile.y + 1][towerTile.x + 1].buildable = buildable;
}
public static function changePassablity(towerTile:Point, passable:Boolean):void {
Main.nodes[towerTile.y][towerTile.x].passable = passable;
Main.nodes[towerTile.y + 1][towerTile.x].passable = passable;
Main.nodes[towerTile.y][towerTile.x + 1].passable = passable;
Main.nodes[towerTile.y + 1][towerTile.x + 1].passable = passable;
}
}
//}
//package {
import flash.geom.Point;
//public
class Goal {
private static const DX:Array = [0, -1, 1, 0, -1, 1, -1, 1];
private static const DY:Array = [ -1, 0, 0, 1, -1, -1, 1, 1];
private static const DCOST:Array = [1, 1, 1, 1, Math.SQRT2, Math.SQRT2, Math.SQRT2, Math.SQRT2];
private var _node:Node;
private var _openNodes:Array; // 保留ノードリスト
private var _nodeCost:Array; // 各ノードの移動コスト
private var _nodeNext:Array; // 各ノードの次の経路となるノード
private var _previousNodeCost:Array; // 以前のnodeCost
private var _previousNodeNext:Array; // 以前のnodeNext
public function get node():Node { return _node; }
public function getCost(tile:Point):Number { return _nodeCost[tile.y][tile.x]; }
public function getNext(tile:Point):Node { return _nodeNext[tile.y][tile.x]; }
public function Goal(tile:Point) {
_node = Main.nodes[tile.y][tile.x];
_openNodes = [];
_nodeCost = _nodeNext = null;
search();
}
// ダイクストラ法による経路探索
public function search():void {
initialize();
while (_openNodes.length > 0) {
var subject:Node = _openNodes.pop() as Node;
// 周囲8方向のノードを訪問する
for (var i:int = 0; i < 8; i++) {
// 画面外の存在しないノードを指すなら次の周囲ノードへ進む
if (!isValid(subject.tileX + Goal.DX[i], subject.tileY + Goal.DY[i])) { continue; }
// 通れないノード、計算済み(確定)ノード、直進することができないノードなら次の周囲ノードへ進む
var test:Node = Main.nodes[subject.tileY + Goal.DY[i]][subject.tileX + Goal.DX[i]];
if (isImpassable(test) || isCalculatedNode(test) || !canGoStraightTo(subject, test)) { continue; }
// 移動コストを計算する
_nodeCost[test.tileY][test.tileX] = _nodeCost[subject.tileY][subject.tileX] + Goal.DCOST[i];
// 次の経路ノードをsubjectノードに設定する
_nodeNext[test.tileY][test.tileX] = subject;
// 保留ノードリストに追加する
insertToOpenNodes(test);
}
}
}
private function initialize():void {
_previousNodeCost = _nodeCost;
_previousNodeNext = _nodeNext;
_nodeCost = [];
_nodeNext = [];
for (var row:int = 0; row < Parameter.NODE_ROWS; row++) {
_nodeCost[row] = [];
_nodeNext[row] = [];
for (var col:int = 0; col < Parameter.NODE_COLS; col++) {
_nodeCost[row][col] = Number.MAX_VALUE;
_nodeNext[row][col] = Main.nodes[row][col];
}
}
// Goalのノードを経路探索のスタートノードとする
_nodeCost[_node.tileY][_node.tileX] = 0;
_openNodes.push(_node);
}
// indexの値が有効な値かどうか
private function isValid(col:int, row:int):Boolean {
return ((col >= 0) && (col < Parameter.NODE_COLS) && (row >= 0) && (row < Parameter.NODE_ROWS));
}
// 既にコストを計算済みのノードかどうか
private function isCalculatedNode(node:Node):Boolean {
return _nodeCost[node.tileY][node.tileX] != Number.MAX_VALUE;
}
// 通れないノードかどうか
private function isImpassable(node:Node):Boolean {
return !node.passable;
}
// subjectノードからtestノードへ直進できるかどうか
private function canGoStraightTo(subject:Node, test:Node):Boolean {
return (Main.nodes[subject.tileY][test.tileX].passable && Main.nodes[test.tileY][subject.tileX].passable);
}
// nodeを保留ノードリストの適切な場所に挿入する
private function insertToOpenNodes(node:Node):void {
var insertIndex:int;
var len:int = _openNodes.length;
var nodeCost:Number = _nodeCost[node.tileY][node.tileX];
for (insertIndex = 0; insertIndex < len; insertIndex++) {
var openNode:Node = _openNodes[insertIndex];
if (nodeCost > _nodeCost[openNode.tileY][openNode.tileX]) { break; }
}
_openNodes.splice(insertIndex, 0, node);
}
// 一つ前の状態を復元する
public function revertToPrevious():void {
_nodeCost = _previousNodeCost;
_nodeNext = _previousNodeNext;
}
// 指定した位置から最も近いゴールを取得する
public static function getNearestGoalFrom(tile:Point):Goal {
var goals:Array = Main.goals;
var nearest:Goal = goals[0];
var len:int = goals.length;
for (var i:int = 1; i < len; i++) {
if (goals[i].getCost(tile) < nearest.getCost(tile)) {
nearest = goals[i];
}
}
return nearest;
}
// 最探索し、成功したかどうかを返す
public static function reSearch(towerTile:Point):Boolean {
Node.changePassablity(towerTile, false);
var i:int;
for (i = 0; i < Main.goals.length; i++) {
Main.goals[i].search();
}
var hasPathAllEnemy:Boolean = true;
for (i = 0; i < Main.enemies.length; i++) {
Main.enemies[i].updateNearestGoal();
if (!Main.enemies[i].hasPathToGoal()) {
hasPathAllEnemy = false;
break;
}
}
Node.changePassablity(towerTile, true);
if (hasPathAllEnemy) {
return true;
// ブロッキングしていたら全部元に戻す
}else {
for (i = 0; i < Main.goals.length; i++) {
Main.goals[i].revertToPrevious();
}
for (i = 0; i < Main.enemies.length; i++) {
Main.enemies[i].updateNearestGoal();
}
return false;
}
}
}
//}
//package {
import flash.display.*;
import flash.events.MouseEvent;
import flash.geom.Point;
//public
class Tower extends Sprite {
private var _center:Point;
private var _name:String;
private var _rank:int;
private var _attlibutes:Object;
private var _currentStats:Object;
private var _nextStats:Object;
private var _active:Boolean;
private var _target:Enemy;
private var _reloadSpeed:Number; // 毎フレームのカウントの上昇値
private var _reloadCount:Number; // この値が100を超えたら発射可能
private var _image:Sprite;
public function get towerName():String { return _name; }
public function get ground():Boolean { return _attlibutes.ground; }
public function get air():Boolean { return _attlibutes.air; }
public function get slow():Boolean { return _attlibutes.slow; }
public function get splash():Boolean { return _attlibutes.splash; }
public function get rank():String { return _currentStats.rank; }
public function get cost():int { return _currentStats.cost; }
public function get damage():int { return _currentStats.damage; }
public function get range():int { return _currentStats.range; }
public function get fireRate():Number { return _currentStats.firerate; }
public function get nextRank():String { return _nextStats.rank; }
public function get nextCost():int { return _nextStats.cost; }
public function get nextDamage():int { return _nextStats.damage; }
public function get nextRange():int { return _nextStats.range; }
public function get nextFireRate():Number { return _nextStats.firerate; }
public function get active():Boolean { return _active; }
public function Tower(posx:int, posy:int, name:String, active:Boolean) {
x = posx;
y = posy;
_center = new Point(posx + Parameter.TOWER_SIZE / 2, posy + Parameter.TOWER_SIZE / 2);
_name = name;
_rank = 0;
_attlibutes = Parameter.getTowerAttlibutes(_name);
_currentStats = Parameter.getTowerStats(_name, _rank);
_nextStats = Parameter.getTowerStats(_name, _rank + 1);
_active = active;
if (active) {
_target = null;
_reloadSpeed = _currentStats.firerate * 100 / Parameter.FRAMERATE;
_reloadCount = 0;
var tile:Point = Node.tileFromPosition(new Point(x, y));
Node.changePassablity(tile, false);
Node.changeBulidablity(tile, false);
}
draw();
buttonMode = true;
addEventListener(MouseEvent.CLICK, selected);
}
// タワーの画像を描画する
private function draw():void {
addChild(new Bitmap(ImageFactory.getTowerBase()));
_image = new Sprite();
var bitmap:Bitmap = new Bitmap((_name != "Cancel") ? ImageFactory.getImage(_name) : ImageFactory.getCancelMark(), "auto", true);
bitmap.x = bitmap.y = int( -Parameter.TOWER_IMAGE_SIZE / 2);
_image.x = _image.y = int(Parameter.TOWER_SIZE / 2);
_image.addChild(bitmap);
addChild(_image);
if (active) { _image.rotation = int(350 * Math.random() - 175); }
}
public function update():void {
// ターゲット無しかターゲットがやられていたら、新しいターゲットを探す
if (_target == null || _target.hp <= 0) {
for (var i:int = 0; i < Main.enemies.length; i++) {
var diffX:Number = _center.x - Main.enemies[i].posX;
var diffY:Number = _center.y - Main.enemies[i].posY;
if (Math.sqrt(diffX * diffX + diffY * diffY) < _currentStats.range) {
_target = Main.enemies[i];
break;
}
}
}
// ターゲットがいるなら、
// 射程内ならターゲットの方を向き、射程外ならターゲットからはずす
if (_target != null) {
diffX = _target.posX - _center.x;
diffY = _target.posY - _center.y;
if (Math.sqrt(diffX * diffX + diffY * diffY) < _currentStats.range) {
var degree:Number = Math.atan2(diffY, diffX) * 180 / Math.PI;
_image.rotation = degree;
}else {
_target = null;
}
}
// 弾を発射できるなら発射する
_reloadCount += _reloadSpeed;
}
// タワーアップグレード時の処理
public function upgrade():void {
if (hasNextRank() && GameData.instance.buyable(_nextStats.cost - _currentStats.cost)) {
GameData.instance.spendGold(_nextStats.cost - _currentStats.cost);
_rank++;
_currentStats = _nextStats;
_nextStats = Parameter.getTowerStats(_name, _rank + 1);
_reloadSpeed = _currentStats.firerate * 100 / Parameter.FRAMERATE;
}
}
// 次のランクがあるかどうか
public function hasNextRank():Boolean {
return _nextStats != null;
}
// タワー売却時の処理
public function sell():void {
parent.removeChild(this);
var tile:Point = Node.tileFromPosition(new Point(x, y));
Node.changePassablity(tile, true);
Node.changeBulidablity(tile, true);
Main.towers.splice(Main.towers.indexOf(this), 1);
GameData.instance.earnGold(int(_currentStats.cost * Parameter.TOWER_SELL_RATE));
}
private function selected(e:MouseEvent):void {
GameData.instance.setSelectedTower((_name != "Cancel") ? this : null);
}
}
//}
//package {
import flash.display.*;
import flash.geom.Point;
//public
class Enemy extends Sprite {
private var _position:Point;
private var _velocity:Point;
private var _hp:int; // ヒットポイント
private var _bounty:int; // 倒して得る金
private var _speed:Number; // 速さ(スカラー)
private var _immunity:Boolean; // 免疫が有るか
private var _slowing:int; // スロー状態かどうか
private var _isFlying:Boolean; // 飛行しているか
private var _currentNode:Node; // 現在のノード
private var _nearestGoal:Goal; // 最短で到達できるゴールノード
private var _nextNode:Node; // 次に進むべきノード
private var _image:Sprite;
public function get posX():Number { return _position.x; }
public function get posY():Number { return _position.y; }
public function get hp():int { return _hp; }
public function Enemy(pos:Point, stats:Object) {
_position = pos;
_hp = stats.hp;
_bounty = stats.bounty;
_speed = stats.speed;
_immunity = false;
_slowing = 0;
_isFlying = false;
initializeVelocity();
var tile:Point = Node.tileFromPosition(_position);
initializeCurrentNode(tile);
initializeNearestGoal(tile);
initializeNextNode(tile);
draw();
}
private function initializeVelocity():void {
if (_isFlying) {
_velocity = new Point(0, -_speed);
}else {
_velocity = new Point();
}
}
private function initializeCurrentNode(tile:Point):void {
_currentNode = Main.nodes[tile.y][tile.x];
if (!_isFlying) { _currentNode.enemyNum++; }
}
private function initializeNearestGoal(tile:Point):void {
if (_isFlying) {
_nearestGoal = Main.nodes[4][tile.x];
}else {
_nearestGoal = Goal.getNearestGoalFrom(tile);
}
}
private function initializeNextNode(tile:Point):void {
if (_isFlying) {
_nextNode = _nearestGoal.node;
}else {
_nextNode = _nearestGoal.getNext(tile);
}
}
private function draw():void {
_image = new Sprite();
var bitmap:Bitmap = new Bitmap(ImageFactory.getEnemy("Normal"));
bitmap.x = bitmap.y = int( -Parameter.NODE_SIZE / 2);
_image.rotation = -90;
_image.addChild(bitmap);
addChild(_image);
}
public function update():void {
if (_hp <= 0) {
GameData.instance.earnGold(_bounty);
vanish();
return;
}
var tile:Point = Node.tileFromPosition(_position);
// ゴールに着いたら、ライフが減って敵消滅
if (arrivedGoal(tile)) {
GameData.instance.damageLives();
vanish();
return;
}
move(tile);
veer(tile);
}
// 消滅する
private function vanish():void {
if (!_isFlying) { _currentNode.enemyNum--; }
parent.removeChild(this);
Main.enemies.splice(Main.enemies.indexOf(this), 1);
}
// 移動する
private function move(tile:Point):void {
var slowed:Boolean = (_slowing > 0);
if (slowed) { _slowing--; }
x = (_position.x += (slowed ? _velocity.x / 2 : _velocity.x));
y = (_position.y += (slowed ? _velocity.y / 2 : _velocity.y));
}
// 進行方向の修正
private function veer(tile:Point):void {
if (!_isFlying) {
//次に進むべきノードへ到着していたら、次に進むべきノードを更新する
if (arrivedNextNode(tile)) {
_currentNode.enemyNum--;
_nextNode.enemyNum++;
_currentNode = _nextNode;
updateNextNode(tile);
}
var radian:Number = Math.atan2(_nextNode.centerY - _position.y, _nextNode.centerX - _position.x);
_velocity.x = (_velocity.x + _speed * Math.cos(radian)) * 0.5;
_velocity.y = (_velocity.y + _speed * Math.sin(radian)) * 0.5;
var degree:Number = radian * 180 / Math.PI;
_image.rotation = degree;
}
}
// 最短で到達できるゴールノードを更新する
public function updateNearestGoal():void {
var tile:Point = Node.tileFromPosition(_position);
_nearestGoal = Goal.getNearestGoalFrom(tile);
updateNextNode(tile);
}
// 次に進むべきノードを更新する
private function updateNextNode(tile:Point):void {
_nextNode = _nearestGoal.getNext(tile);
}
// ゴールへ向かう経路が存在しているかどうか
public function hasPathToGoal():Boolean {
return _currentNode != _nextNode;
}
// ゴールノードへ到着しているかどうか
private function arrivedGoal(tile:Point):Boolean {
return (tile.x == _nearestGoal.node.tileX) && (tile.y == _nearestGoal.node.tileY);
}
// 次に進むべきノードへ到着しているかどうか
private function arrivedNextNode(tile:Point):Boolean {
return (tile.x == _nextNode.tileX) && (tile.y == _nextNode.tileY);
}
// ダメージを受ける
public function damaged(amount:int, slow:Boolean):void {
_hp -= amount;
if (slow) { slowed(); }
}
// 移動が遅くなる(免疫が無ければ)
private function slowed():void {
if (!_immunity) { _slowing = Parameter.SLOWING_TIME; }
}
}
//}