SAVE THE EARTHをズルしてみた
インベーダーの侵略から地球を守りましょう。
*
* 自機はマウスで操作可能です。
* 敵は自機で体当たりすると倒せます。
* 敵を倒すごとにENEMY LIFEゲージが減ります。
* ENEMY LIFEゲージが0にすればクリアです。
*
* 敵が自機の後ろの地球にぶつかるとPLAYER LIFEゲージが減っていきます。
* PLAYER LIFEゲージが0になるとゲームオーバーです。
*
* change Viewボタンで視点を変えれます。
* (難しくなるだけです。。)
*
* インベーダーの描画のソースはnutsuさんのcheckmate作品より拝借しました。
* http://wonderfl.net/c/3OcH
*
*
/**
* Copyright uwi ( http://wonderfl.net/user/uwi )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/anmw
*/
// forked from sakusan393's SAVE THE EARTH
/*
*
* インベーダーの侵略から地球を守りましょう。
*
* 自機はマウスで操作可能です。
* 敵は自機で体当たりすると倒せます。
* 敵を倒すごとにENEMY LIFEゲージが減ります。
* ENEMY LIFEゲージが0にすればクリアです。
*
* 敵が自機の後ろの地球にぶつかるとPLAYER LIFEゲージが減っていきます。
* PLAYER LIFEゲージが0になるとゲームオーバーです。
*
* change Viewボタンで視点を変えれます。
* (難しくなるだけです。。)
*
* インベーダーの描画のソースはnutsuさんのcheckmate作品より拝借しました。
* http://wonderfl.net/c/3OcH
*
* */
package
{
import flash.display.BitmapData;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.net.navigateToURL;
import flash.net.URLRequest;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.ui.Keyboard;
import flash.utils.escapeMultiByte;
import flash.utils.Timer;
import net.hires.debug.Stats;
import org.libspark.betweenas3.BetweenAS3;
import org.libspark.betweenas3.easing.Expo;
import org.papervision3d.core.geom.renderables.Particle;
import org.papervision3d.materials.BitmapMaterial;
import org.papervision3d.materials.ColorMaterial;
import org.papervision3d.materials.special.ParticleMaterial;
import org.papervision3d.materials.WireframeMaterial;
import org.papervision3d.objects.primitives.PaperPlane;
import org.papervision3d.objects.primitives.Plane;
import org.papervision3d.objects.primitives.Sphere;
import org.papervision3d.objects.special.ParticleField;
import org.papervision3d.view.BasicView;
[SWF(backgroundColor="0x000000", frameRate="30", width="465", height="465")]
/**
* ...
* @author 393
*/
public class Main extends BasicView
{
private var _count:int;
private var _paperPlane:PaperPlane;
private var _enemyArray:Array = new Array();
private var _enemyGraArray:Array = new Array();
private var _timer:Timer;
private var _maxLength:int = 20;
private var _isKeyLeft:Boolean;
private var _isKeyRight:Boolean;
private var _cMat:ColorMaterial;
private var _wMat:WireframeMaterial;
private var _particleField:ParticleField;
private var _scoreTf:TextField;
private var _hitCount:int;
private var _earth:Sphere;
private var _damageCount:int;
private var _viewAngleArray:Array = [0, 200, 800,-400];
private var _viewAngleCount:int;
private var _damageBm:Bitmap;
private var _damageTimer:Timer;
private var _scoreLabelTf:TextField;
private var _playerLifeLabelTf:TextField;
private var _playerLifeBar:Sprite;
private var _restartBtnContainer:Sprite;
private var _changeViewBtnContainer:Sprite;
private var _tweetBtn:Sprite;
private var _w:int;
private var _h:int;
private var _enemyLifeBar:Sprite;
private var _enemyLifeLabelTf:TextField;
private var _enemyPhisyc:int = 50;
private var _playerPhisyc:int = 20;
private var _messageLabelTf:TextField;
private var _endTimer:Timer;
private var _isCleared:Boolean = false;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
_w = stage.stageWidth;
_h = stage.stageHeight;
addChild(new Stats);
//自機
_cMat = new ColorMaterial(0xFFFF00);
_cMat.doubleSided = true;
_paperPlane = new PaperPlane(_cMat);
scene.addChild(_paperPlane);
_paperPlane.z = -100;
_paperPlane.rotationZ = 180;
camera.x = 0;
camera.y = 0;
camera.z = -1000;
//母星
var wireMat:WireframeMaterial = new WireframeMaterial();
wireMat.doubleSided = true;
_earth = new Sphere(wireMat, 200, 8, 6);
scene.addChild(_earth);
_earth.z = -800;
_earth.y = 0;
//敵の生成
for (var i:int = 0; i < _maxLength; i++)
{
//敵の色
var color:int = Math.random() * 0xFFFFFF;
color = color + 0xFF000000;
//敵のグラフィック
var bmd1:BitmapData = fig1(color);
var bmdMat1:BitmapMaterial = new BitmapMaterial(bmd1);
var bmd2:BitmapData = fig2(color);
var bmdMat2:BitmapMaterial = new BitmapMaterial(bmd2);
var bmd3:BitmapData = fig3(color);
var bmdMat3:BitmapMaterial = new BitmapMaterial(bmd3);
_enemyGraArray.push({gra1:bmdMat1,gra2:bmdMat2,gra3:bmdMat3});
//敵を保持
var enemy:Plane = new Plane(bmdMat1,180,180,0,0);
_enemyArray.push(enemy);
scene.addChild(_enemyArray[i]);
}
//敵の位置情報のセット
initEnemy();
//背景パーティクル
var particle:ParticleMaterial = new ParticleMaterial(0xFFFFFF, 1, 1, 2);
_particleField = new ParticleField(particle, 3000, 1, 1000, 5000, 5000)
scene.addChild(_particleField);
_particleField.y = -2000;
//敵グラフィックのコマアニメ用
var _timer:Timer = new Timer(250);
_timer.addEventListener(TimerEvent.TIMER, changeEnemyGraphic);
_timer.start();
//クリア後のディレイ用タイマー
_endTimer = new Timer(200,1);
_endTimer.addEventListener(TimerEvent.TIMER, endTimerHandler);
//score
_scoreTf = createTf("0",20, "right", true);
addChild(_scoreTf);
_scoreTf.x = _w / 2 - _scoreTf.width / 2;
_scoreTf.y = 10;
//scoreLabel
_scoreLabelTf = createTf("SCORE:",18, "right", false);
addChild(_scoreLabelTf);
_scoreLabelTf.x = _w / 2 - _scoreLabelTf.width;
_scoreLabelTf.y = 13;
//プレイヤーdamageLabel
_playerLifeLabelTf = createTf("PLAYER LIFE:",18, "right", false);
addChild(_playerLifeLabelTf);
_playerLifeLabelTf.x = _w / 2 - _playerLifeLabelTf.width -100;
_playerLifeLabelTf.y = 53;
//プレイヤーライフバー
_playerLifeBar = createLifeBar(0x00FF00);
addChild(_playerLifeBar);
_playerLifeBar.x = _w / 2 - _playerLifeBar.width / 2;
_playerLifeBar.y = 56;
//エネミーdamageLabel
_enemyLifeLabelTf = createTf("ENEMY LIFE:",18, "right", false);
addChild(_enemyLifeLabelTf);
_enemyLifeLabelTf.x = _w / 2 - _enemyLifeLabelTf.width -100;
_enemyLifeLabelTf.y = 83;
//エネミーライフバー
_enemyLifeBar= createLifeBar(0xFF9933);
addChild(_enemyLifeBar);
_enemyLifeBar.x = _w / 2 - _enemyLifeBar.width / 2;
_enemyLifeBar.y = 86;
//ダメージ演出
var bmd:BitmapData = new BitmapData(_w, _h, false, 0xFFFF0000);
_damageBm = new Bitmap(bmd);
addChild(_damageBm);
_damageBm.visible = false;
_damageTimer = new Timer(50, 1);
_damageTimer.addEventListener(TimerEvent.TIMER, damageTimerHandler);
//リスタートボタン
_restartBtnContainer = createBtn("restart");
this.addChild(_restartBtnContainer);
_restartBtnContainer.x = _w / 2 - _restartBtnContainer.width / 2;
_restartBtnContainer.y = _h / 2 + 50;
_restartBtnContainer.visible = false;
_restartBtnContainer.addEventListener(MouseEvent.CLICK, restartHandler);
//changeViewボタン
_changeViewBtnContainer = createBtn("chage view");
this.addChild(_changeViewBtnContainer);
_changeViewBtnContainer.x = _w / 2 - _changeViewBtnContainer.width / 2;
_changeViewBtnContainer.y = _h - _changeViewBtnContainer.height -10;
_changeViewBtnContainer.addEventListener(MouseEvent.CLICK, changeViewHandler);
//Tweetボタン
_tweetBtn = createBtn("post twitter");
this.addChild(_tweetBtn);
_tweetBtn.x = _w / 2 - _restartBtnContainer.width / 2;
_tweetBtn.y = _h / 2;
_tweetBtn.visible = false;
_tweetBtn.addEventListener(MouseEvent.CLICK, tweetHandler);
//メッセージ
_messageLabelTf = createTf("YOU LOSE!", 40, "center", false);
_messageLabelTf.textColor = 0xFFFFFF;
_messageLabelTf.width = 450;
_messageLabelTf.visible = false;
addChild(_messageLabelTf);
_messageLabelTf.x = _w / 2 - _messageLabelTf.width / 2;
_messageLabelTf.y = _h/2 - 80;
//リサイズ判定
stage.addEventListener(Event.RESIZE, resizeHandler);
resizeHandler(null);
}
private function endTimerHandler(e:TimerEvent):void
{
_restartBtnContainer.visible = true;
_tweetBtn.visible = true;
_messageLabelTf.text = "YOU WIN!";
_messageLabelTf.visible = true;
_enemyLifeBar.scaleX = 0;
stopRendering();
}
//ライフバーの生成
private function createLifeBar(color:int = 0xFFFFFF ):Sprite
{
var sp:Sprite = new Sprite();
sp.graphics.beginFill(0xFF0000);
var cover:Shape = new Shape();
cover.graphics.beginFill(color);
cover.graphics.drawRect(0, 0, 200, 20);
cover.graphics.endFill();
sp.addChild(cover);
sp.graphics.drawRect(0, 0, 200, 20);
sp.graphics.endFill();
return sp;
}
private function tweetHandler(e:MouseEvent):void {
var comment:String = "あなたは" + _hitCount + "匹のインベーダーを退治しました。あなたのおかげで";
var comment1:String;
if (!_isCleared)
{
comment1= "地球は滅亡しました [save the earth] ";
}
else
{
comment1= "地球は救われました [save the earth] ";
}
var post:String = comment + comment1 + " " + "http://bit.ly/bZmfqp" + " " + "#wonderfl";
navigateToURL(new URLRequest("http://twitter.com/home?status=" + escapeMultiByte(post)), "_blank");
}
//ボタンの生成
private function createBtn(str:String):Sprite
{
var sp:Sprite = new Sprite();
sp.buttonMode = true;
var tf:TextField = createTf(str, 20, "center", true);
tf.mouseEnabled = false;
tf.background = true;
tf.textColor = 0;
tf.backgroundColor = 0xFFFFFF;
sp.addChild(tf);
return sp
}
//リサイズ処理
private function resizeHandler(e:Event):void
{
_w = stage.stageWidth;
_h = stage.stageHeight;
//ダメージ演出
_damageBm.width = _w;
_damageBm.height = _h;
//各種座標
_scoreTf.x = _w / 2 - _scoreTf.width / 2;
_scoreLabelTf.x = _w / 2 - _scoreLabelTf.width-100;
_playerLifeBar.x = _w / 2 - 200 / 2;
_playerLifeLabelTf.x = _w / 2 - _playerLifeLabelTf.width -100;
_enemyLifeBar.x = _w / 2 - 200 / 2;
_enemyLifeLabelTf.x = _w / 2 - _playerLifeLabelTf.width -100;
_restartBtnContainer.x = _w / 2 - _restartBtnContainer.width / 2;
_restartBtnContainer.y = _h / 2 + 50;
_changeViewBtnContainer.x = _w / 2 - _changeViewBtnContainer.width / 2;
_changeViewBtnContainer.y = _h - _changeViewBtnContainer.height -10;
_tweetBtn.x = _w / 2 - _restartBtnContainer.width / 2;
_tweetBtn.y = _h / 2;
_messageLabelTf.x = _w / 2 - _messageLabelTf.width / 2;
_messageLabelTf.y = _h/2 - 80;
}
//リスタート処理
private function restartHandler(e:MouseEvent):void
{
_restartBtnContainer.visible = false;
_messageLabelTf.visible = false;
_tweetBtn.visible = false;
initEnemy();
_playerLifeBar.scaleX = 1;
_enemyLifeBar.scaleX = 1;
_damageCount = 0;
_playerLifeBar.getChildAt(0).alpha = 1;
_enemyLifeBar.getChildAt(0).alpha = 1;
_scoreTf.text = "0";
_count = 0;
_hitCount = 0;
}
//初期化処理
private function initEnemy():void
{
//敵の位置セット
for (var i:int = 0; i < _maxLength; i++)
{
_enemyArray[i].z = 10000 + 1000 * i;
_enemyArray[i].x = Math.random() * 100-200;
_enemyArray[i].y = Math.random() * 100-200;
_enemyArray[i].extra = { vx:Math.random() * 30 - 15,vy:Math.random() * 10 - 5, vz:Math.random() * 300 + 50,isBreak:false}
}
//PV3Dレンダリングスタート
startRendering();
//エンターフレーム処理
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
//ダメージ演出用タイマー処理
private function damageTimerHandler(e:TimerEvent):void
{
_damageBm.visible = false;
}
private function createTf(str:String,size:int,tfmAlign:String,isBorder:Boolean):TextField
{
var tf:TextField = new TextField();
var tfm:TextFormat = new TextFormat();
tfm.font = "Verdana";
tfm.size = size;
tfm.align = tfmAlign;
tfm.color = 0xFFFFFF;
tf.wordWrap = false;
tf.border = isBorder;
tf.borderColor = 0xFFFFFF;
tf.defaultTextFormat = tfm;
tf.text = str;
tf.width = 200;
tf.height = tf.textHeight + 3;
return tf;
}
//カメラ視点の変化
private function changeViewHandler(e:MouseEvent):void
{
_viewAngleCount++;
if (_viewAngleCount >= _viewAngleArray.length) _viewAngleCount = 0;
var angle:int = _viewAngleArray[_viewAngleCount];
trace("angle : " + angle);
camera.y = angle;
}
//敵のグラフィックの変化
private function changeEnemyGraphic(e:TimerEvent):void
{
_count++;
for (var i:int = 0; i < _maxLength; i++)
{
var bMat:BitmapMaterial;
if (_count % 2 == 0) bMat = _enemyGraArray[i].gra1;
else bMat = _enemyGraArray[i].gra2;
if (!_enemyArray[i].extra.isBreak)
{
_enemyArray[i].material = bMat;
}
}
}
//エンターフレーム処理
private function enterFrameHandler(e:Event):void
{
for (var i:int = 0; i < _maxLength; i++)
{
_enemyArray[i].z -= _enemyArray[i].extra.vz;
_enemyArray[i].x += _enemyArray[i].extra.vx;
_enemyArray[i].y += _enemyArray[i].extra.vy;
//自機への当たり判定
if (_paperPlane.hitTestObject(_enemyArray[i]))
{
_enemyArray[i].material = _enemyGraArray[i].gra3;
_enemyArray[i].extra.isBreak = true;
_hitCount++;
_scoreTf.text = String(_hitCount);
trace("_scoreTf.text : " + _scoreTf.text);
var ePercent:Number = (_enemyPhisyc - _hitCount) / _enemyPhisyc;
_enemyLifeBar.scaleX = ePercent;
_enemyLifeBar.getChildAt(0).alpha = ePercent;
if (_enemyLifeBar.scaleX <= 0)
{
_isCleared = true;
removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
_endTimer.start();
}
}
//母星への当たり判定
if (_earth.hitTestObject(_enemyArray[i]))
{
trace("_damaged!! ");
if (!_enemyArray[i].extra.isBreak)
{
_damageCount++;
var pPercent:Number = (_playerPhisyc - _damageCount) / _playerPhisyc;
_playerLifeBar.scaleX = pPercent;
_playerLifeBar.getChildAt(0).alpha = pPercent;
trace("_damageCount : " + _damageCount);
_damageBm.visible = true;
_damageTimer.start();
//ダメージ0で終了
if (_playerLifeBar.scaleX <= 0)
{
_isCleared = false;
stopRendering();
removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
_restartBtnContainer.visible = true;
_tweetBtn.visible = true;
_messageLabelTf.text = "YOU LOSE..";
_messageLabelTf.visible = true;
_playerLifeBar.scaleX = 0;
}
}
}
//敵が画面外に消えた時の処理
if (_enemyArray[i].z < -1000)
{
_enemyArray[i].extra.isBreak = false;
_enemyArray[i].material = _enemyGraArray[i].gra1;
_enemyArray[i].z = 10000;
_enemyArray[i].x = Math.random() * 100 - 200;
_enemyArray[i].y = Math.random() * 100 - 200;
_enemyArray[i].extra = { vx:Math.random() * 30 - 15,vy:Math.random() * 20 - 10, vz:Math.random() * 300 + 50 }
}
}
//自機のマウス操作
// var vx:Number = ((mouseX - _w / 2) * 2 - _paperPlane.x) * 0.1;
// var vy:Number = ((mouseY - _h/2)*2 - _paperPlane.y)*0.1;
var v:Array = algo();
var vx:Number = (v[0] - _paperPlane.x) * 0.1;
var vy:Number = (v[1] - _paperPlane.y)*0.1;
_paperPlane.x += vx;
_paperPlane.y += vy;
if (vx > 40) BetweenAS3.tween(_paperPlane, { rotationZ: 900 }, { rotationZ:900+720 } , 0.5, Expo.easeOut).play();
else _paperPlane.rotationZ += (vx - _paperPlane.rotationZ) * 0.1+ 90;
if (vx < -40) BetweenAS3.tween(_paperPlane, { rotationZ:900 }, { rotationZ:900-720 }, 0.5, Expo.easeOut).play();
else _paperPlane.rotationZ += (vx - _paperPlane.rotationZ) * 0.1 + 90;
//背景パーティクルの動き
_particleField.rotationX -= 1;
//母星の自転
_earth.rotationY ++;
}
private function algo() : Array
{
// 敵機のうち、母星にぶつかる予定でかつ自機のz座標到達するまでの時間が最短のものを選ぶ
var R : Number = 200 + 90 * Math.SQRT2;
var mint : Number = 9999;
var mini : int = -1;
for (var i:int = 0; i < _maxLength; i++)
{
// 自機より後方は無視
if(_enemyArray[i].z < -100)continue;
var rx : Array = [_enemyArray[i].x, _enemyArray[i].y, _enemyArray[i].z + 800];
var rv : Array = [_enemyArray[i].extra.vx, _enemyArray[i].extra.vy, -_enemyArray[i].extra.vz];
// (x+vt)・v=0
var rxv : Number = rx[0]*rv[0] + rx[1]*rv[1] + rx[2]*rv[2];
var rvv : Number = rv[0]*rv[0] + rv[1]*rv[1] + rv[2]*rv[2];
var t : Number = Math.max(-rxv / rvv, 0);
var dClosest : Number =
(rx[0] + rv[0] * t) * (rx[0] + rv[0] * t) +
(rx[1] + rv[1] * t) * (rx[1] + rv[1] * t) +
(rx[2] + rv[2] * t) * (rx[2] + rv[2] * t);
if(dClosest > R * R)continue;
var ct : Number = (_enemyArray[i].z + 100) / _enemyArray[i].extra.vz;
if(ct < mint){
mint = ct;
mini = i;
}
}
if(mini == -1)return [0, 0];
return [
_enemyArray[mini].x + mint * _enemyArray[mini].extra.vx,
_enemyArray[mini].y + mint * _enemyArray[mini].extra.vy
];
}
public function fig1(color:int):BitmapData
{
var highLignt:int = color;
return BitmapPatternBuilder.build(
[[0,0,1,0,0,0,0,0,1,0,0],
[0,0,0,1,0,0,0,1,0,0,0],
[0,0,1,1,1,1,1,1,1,0,0],
[0,1,1,0,1,1,1,0,1,1,0],
[1,1,1,1,1,1,1,1,1,1,1],
[1,0,1,1,1,1,1,1,1,0,1],
[1,0,1,0,0,0,0,0,1,0,1],
[0,0,0,1,1,0,1,1,0,0,0]],
[0x00000000, highLignt]);
}
public function fig2(color:int):BitmapData
{
var highLignt:int = color;
return BitmapPatternBuilder.build(
[[0,0,1,0,0,0,0,0,1,0,0],
[1,0,0,1,0,0,0,1,0,0,1],
[1,0,1,1,1,1,1,1,1,0,1],
[1,1,1,0,1,1,1,0,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1],
[0,1,1,1,1,1,1,1,1,1,0],
[0,0,1,0,0,0,0,0,1,0,0],
[0,1,0,0,0,0,0,0,0,1,0]],
[0x00000000, highLignt])
}
public function fig3(color:int):BitmapData
{
var highLignt:int = color;
return BitmapPatternBuilder.build(
[[0,0,0,1,0,0,0,1,0,0,0],
[0,1,0,0,1,0,1,0,0,1,0],
[0,0,0,1,0,0,0,1,0,0,0],
[1,0,1,0,1,0,1,0,1,0,1],
[0,0,0,1,1,1,1,1,0,0,0],
[0,1,0,0,1,0,1,0,0,1,0],
[0,0,0,1,0,0,0,1,0,0,0],
[1,0,1,0,1,0,1,0,1,0,1]],
[0x00000000,highLignt])
}
}
}
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Graphics;
class BitmapPatternBuilder{
/**
* creates BitmapData filled with dot pattern.
* First parameter is 2d array that contains color index for each pixels;
* Second parameter contains color reference table.
*
* @parameter pattern:Array 2d array that contains color index for each pixel.
* @parameter colors:Array 1d array that contains color table.
* @returns BitmapData
*/
public static function build(pattern:Array, colors:Array):BitmapData{
var bitmapW:int = pattern[0].length;
var bitmapH:int = pattern.length;
var bmd:BitmapData = new BitmapData(bitmapW,bitmapH,true,0x000000);
for(var yy:int=0; yy<bitmapH; yy++){
for(var xx:int=0; xx<bitmapW; xx++){
var color:int = colors[pattern[yy][xx]];
bmd.setPixel32(xx, yy, color);
}
}
return bmd;
}
/**
* short cut function for Graphics.beginBitmapFill with pattern.
*/
public static function beginBitmapFill(pattern:Array, colors:Array, graphics:Graphics):void{
var bmd:BitmapData = build(pattern, colors);
graphics.beginBitmapFill(bmd);
bmd.dispose();
}
}