アミダ崩し(AMIDA Breakout)
操作方法
・クリック(Click)
・アミダの追加(Add Line)
/**
* Copyright o_healer ( http://wonderfl.net/user/o_healer )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/qR2gA
*/
/*
「アミダ崩し」
・
操作方法
・クリック(Click)
・アミダの追加(Add Line)
*/
/*
Memo
アミダは1ドット単位でラインんを管理
・実際の表示はラインの大きさでスケーリングをかけるだけ
*/
package {
import flash.display.*;
import flash.events.*;
import flash.filters.*;
import flash.geom.*;
import flash.net.*;
import flash.system.*;
import flash.text.*;
import net.wonderfl.utils.WonderflAPI;
[SWF(width="465", height="465", frameRate="30", backgroundColor="0x000000")]
public class GameMain extends Sprite {
//==Const==
//画面の大きさ
static public const VIEW_W:int = 465;
static public const VIEW_H:int = 465;
//バーの初期位置
static public const BAR_INIT_X:int = VIEW_W/4;
static public const BAR_INIT_Y:int = VIEW_H*7/8;
//アミダの線の太さ
static public const LINE_W:int = 4;
//アミダの線の数
static public const LINE_NUM_X:int = 5;
static public const LINE_NUM_Y:int = (BAR_INIT_Y - 2*LINE_W)/LINE_W;
//アミダの線の色
static public const LINE_COLOR:uint = 0xFF000000;
//球の色
static public const BALL_COLOR:uint = 0xFFFFFFFF;
//ボールの移動パターン
static public var BallModeIter:int = 0;
static public const BALL_MODE_U:int = BallModeIter++;
static public const BALL_MODE_D:int = BallModeIter++;
static public const BALL_MODE_L:int = BallModeIter++;
static public const BALL_MODE_R:int = BallModeIter++;
//ブロックの大きさ
static public const BLOCK_W:int = (int)(VIEW_W/LINE_NUM_X/LINE_W) * LINE_W;
static public const BLOCK_H:int = VIEW_H/32;
//ブロックの数
static public const BLOCK_NUM_X:int = LINE_NUM_X;
static public const BLOCK_NUM_Y:int = 8;
//作業用
static public const BMP_INIT_OFFSET_X:int = VIEW_W/LINE_NUM_X/LINE_W/2;
static public const BMP_GAP_X:int = VIEW_W/LINE_NUM_X/LINE_W;
// static public const AMIDA_INIT_OFFSET_X:int = VIEW_W/LINE_NUM_X/2;
// static public const AMIDA_GAP_X:int = (int)(VIEW_W/LINE_NUM_X/LINE_W) * LINE_W;
static public const AMIDA_INIT_OFFSET_X:int = BMP_INIT_OFFSET_X * LINE_W;
static public const AMIDA_GAP_X:int = BMP_GAP_X * LINE_W;
//==Var==
//Pseudo Singleton
static public var Instance:GameMain;
//レイヤー
public var m_Layer_Root:Sprite = new Sprite();
public var m_Layer_BG:Sprite = new Sprite();
public var m_Layer_MoveObj:Sprite = new Sprite();
public var m_Layer_LineCand:Sprite = new Sprite();
//画像
public var m_BitmapData_BG:BitmapData = new BitmapData(VIEW_W, VIEW_H, false, 0x666666);
public var m_BitmapData_Amida:BitmapData = new BitmapData(VIEW_W/LINE_W + 1, VIEW_H/LINE_W + 1, true, 0x00000000);
//横線候補
public var m_Bitmap_LineCand:Bitmap;
//球
public var m_BallX:int;
public var m_BallY:int;
public var m_BallMove:Number = 0;
public var m_BallMode:int = BALL_MODE_U;
public var m_BallAttackFlag:Boolean = true;//左右移動後に上昇するか否か
//バー
public var m_Bar:Bar;
//ブロック
public var m_Blocks:Vector.<Vector.<Block> >;
//球の移動軌跡用エフェクト
public var m_Rect_Amida:Rectangle;
public var m_CT_Amida:ColorTransform;
//テキスト
public var m_Text:TextField = new TextField();
public var m_Text_Score:TextField = new TextField();
//スコア
public var m_Score:int = 0;
//
public var m_EndFlag:Boolean = false;
//==Function==
//Init
public function GameMain():void {
var i:int;
var x:int;
var y:int;
//Pseudo Singleton
{
Instance = this;
}
//Static Init
{
// ImageManager.Init();
ScoreWindowLoader.init(this, new WonderflAPI(loaderInfo.parameters));
}
//Layer
{
//Root
addChild(m_Layer_Root);
{
//背景
m_Layer_Root.addChild(m_Layer_BG);
//動くOBJ系
m_Layer_Root.addChild(m_Layer_MoveObj);
//横線候補の表示レイヤー
m_Layer_Root.addChild(m_Layer_LineCand);
}
}
//背景
{
m_Layer_BG.addChild(new Bitmap(m_BitmapData_BG));
}
//アミダ
{
var bmp:Bitmap;
//基本ライン(縦線)
var rect:Rectangle = new Rectangle(0,0, 1, VIEW_H);
for(i = 0; i < LINE_NUM_X; i++){
rect.x = BMP_INIT_OFFSET_X + i*BMP_GAP_X;
m_BitmapData_Amida.fillRect(rect, LINE_COLOR);
}
bmp = new Bitmap(m_BitmapData_Amida);
bmp.scaleX = LINE_W;
bmp.scaleY = LINE_W;
m_Layer_BG.addChild(bmp);
}
//横線候補
//- m_Bitmap_LineCand;
{
var bmd:BitmapData;
const a:uint = 0x30;
bmd = new BitmapData(VIEW_W/LINE_NUM_X/LINE_W, 1, true, (0x00FFFFFF & LINE_COLOR) | (a << 24));
m_Bitmap_LineCand = new Bitmap(bmd);
//最初は範囲外にして擬似非表示
m_Bitmap_LineCand.x = -100;
m_Bitmap_LineCand.y = -100;
m_Bitmap_LineCand.scaleX = LINE_W;
m_Bitmap_LineCand.scaleY = LINE_W;
m_Layer_LineCand.addChild(m_Bitmap_LineCand);
}
//球
{
m_BallX = BMP_INIT_OFFSET_X + (int)((LINE_NUM_X-1)/2)*BMP_GAP_X;
m_BallY = BAR_INIT_Y/LINE_W;
}
//バー
{
m_Bar = new Bar();
m_Bar.x = BAR_INIT_X;
m_Bar.y = BAR_INIT_Y;
m_Layer_MoveObj.addChild(m_Bar);
}
//ブロック
{
m_Blocks = new Vector.<Vector.<Block> >(BLOCK_NUM_Y);
for(y = 0; y < BLOCK_NUM_Y; y++){
m_Blocks[y] = new Vector.<Block>(BLOCK_NUM_X);
for(x = 0; x < BLOCK_NUM_X; x++){
var hue:Number = 1.0 * x / BLOCK_NUM_X;
var saturation:Number = 0.8;
var value:Number = 1 - 0.5 * y/BLOCK_NUM_Y;
var block:Block = new Block(HSVtoRGB(hue, saturation, value));
block.x = x * BLOCK_W;
block.y = y * BLOCK_H;
m_Blocks[y][x] = block;
m_Layer_MoveObj.addChild(block);
}
}
}
//エフェクト
{
m_Rect_Amida = m_BitmapData_Amida.rect;
m_CT_Amida = new ColorTransform(0.9, 0.95, 0.98);
}
//Text
{
m_Text_Score.selectable = false;
m_Text_Score.autoSize = TextFieldAutoSize.RIGHT;
m_Text_Score.defaultTextFormat = new TextFormat('Verdana', 16, 0xFFFFFF, true);
m_Text_Score.text = '0';
m_Text_Score.filters = [new GlowFilter(0x00FFFF,1.0, 4,4)];
m_Text_Score.x = VIEW_W - 32;
m_Text_Score.y = 0;
addChild(m_Text_Score);
}
{
m_Text.selectable = false;
m_Text.autoSize = TextFieldAutoSize.LEFT;
m_Text.defaultTextFormat = new TextFormat('Verdana', 60, 0xFFFFFF, true);
m_Text.text = '';
m_Text.filters = [new GlowFilter(0x00FFFF,1.0, 8,8)];
addChild(m_Text);
}
//Mouse
{
stage.addEventListener(MouseEvent.MOUSE_MOVE, OnMouseMove);
stage.addEventListener(MouseEvent.MOUSE_DOWN, OnMouseDown);
}
//Update
{
addEventListener(Event.ENTER_FRAME, Update);
}
//Debug : For Wonderfl Screenshot
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, function(event:KeyboardEvent):void{
if(event.ctrlKey && event.shiftKey && event.altKey && event.keyCode == 65){
m_Layer_Root.y = VIEW_H/4;
}else{
m_Layer_Root.y = 0;
}
});
}
}
//Update
public function Update(e:Event=null):void{
var DeltaTime:Number = 1.0 / stage.frameRate;
if(m_EndFlag){return;}
//Bar
m_Bar.Update(DeltaTime);
//Ball
Update_Ball(DeltaTime);
//Block
Update_Block(DeltaTime);
}
//Update : Block
public function Update_Block(DeltaTime:Number):void{
var AllClearFlag:Boolean = true;
m_Score = 0;
for(var y:int = 0; y < BLOCK_NUM_Y; y++){
for(var x:int = 0; x < BLOCK_NUM_X; x++){
var block:Block = m_Blocks[y][x];
block.Update(DeltaTime);
if(block.IsExist()){
AllClearFlag = false;
}else{
++m_Score;
}
}
}
//Score
{
m_Text_Score.text = m_Score.toString();
}
if(AllClearFlag){
OnGoal();
}
}
public function OnFail():void{
m_EndFlag = true;
//Text
{
//Text
m_Text.text = 'Fail';
//Centering
m_Text.x = (stage.stageWidth - m_Text.width) / 2;
m_Text.y = (stage.stageHeight - m_Text.height) / 2;
}
//スコア表示に移る
ScoreWindowLoader.show(m_Score);
}
public function OnGoal():void{
m_EndFlag = true;
//Text
{
//Text
m_Text.text = 'Clear';
//Centering
m_Text.x = (stage.stageWidth - m_Text.width) / 2;
m_Text.y = (stage.stageHeight - m_Text.height) / 2;
}
//スコア表示に移る
ScoreWindowLoader.show(m_Score);
}
//Update : Ball
public function Update_Ball(DeltaTime:Number):void{
var Vel:Number = 30;
m_BallMove += Vel * DeltaTime;
while(1 <= m_BallMove){
m_BallMove -= 1;
switch(m_BallMode){
case BALL_MODE_U:
//1ドット上に進む
--m_BallY;
//移動先にブロックがあれば反転
if(HitCheckBlock()){
m_BallMode = BALL_MODE_D;
m_BallAttackFlag = false;
break;
}
//左右にラインがあれば次の移動はそちらに進む
if(IsLine(m_BallX-1, m_BallY)){
m_BallMode = BALL_MODE_L;
break;
}
if(IsLine(m_BallX+1, m_BallY)){
m_BallMode = BALL_MODE_R;
break;
}
//移動先にラインがなければ反射
if(! IsLine(m_BallX, m_BallY-1)){
m_BallMode = BALL_MODE_D;
m_BallAttackFlag = false;
}
break;
case BALL_MODE_D:
//1ドット下に進む
++m_BallY;
//移動先にブロックがあれば壊すだけ
if(HitCheckBlock()){
//上の関数内だけで完結
}
//左右にラインがあれば次の移動はそちらに進む
if(IsLine(m_BallX-1, m_BallY)){
m_BallMode = BALL_MODE_L;
break;
}
if(IsLine(m_BallX+1, m_BallY)){
m_BallMode = BALL_MODE_R;
break;
}
//移動先にバーがあれば反射
if(m_Bar.IsRange(m_BallX * LINE_W, m_BallY * LINE_W)){
m_BallMode = BALL_MODE_U;
m_BallAttackFlag = true;
}
//移動先にラインがなければ終了
if(! IsLine(m_BallX, m_BallY+1)){
OnFail();
}
break;
case BALL_MODE_L:
//1ドット左に進む
--m_BallX;
//移動先にブロックがあれば反転
if(HitCheckBlock()){
m_BallMode = BALL_MODE_R;
m_BallAttackFlag = false;
break;
}
//上下にラインがあれば次の移動はそちらに進む
if(m_BallAttackFlag){//上に移動すべき場合
if(IsLine(m_BallX, m_BallY-1)){
m_BallMode = BALL_MODE_U;
}
}else{//下に移動すべき場合
if(IsLine(m_BallX, m_BallY+1)){
m_BallMode = BALL_MODE_D;
}
}
//ただし連続横移動の方を優先する
if(IsLine(m_BallX-1, m_BallY)){
m_BallMode = BALL_MODE_L;
}
break;
case BALL_MODE_R:
//1ドット右に進む
++m_BallX;
//移動先にブロックがあれば反転
if(HitCheckBlock()){
m_BallMode = BALL_MODE_L;
m_BallAttackFlag = false;
break;
}
//上下にラインがあれば次の移動はそちらに進む
if(m_BallAttackFlag){//上に移動すべき場合
if(IsLine(m_BallX, m_BallY-1)){
m_BallMode = BALL_MODE_U;
}
}else{//下に移動すべき場合
if(IsLine(m_BallX, m_BallY+1)){
m_BallMode = BALL_MODE_D;
}
}
//ただし連続横移動の方を優先する
if(IsLine(m_BallX+1, m_BallY)){
m_BallMode = BALL_MODE_R;
}
break;
}
ApplyFilter();
}
}
//Effect
public function ApplyFilter():void{
m_BitmapData_Amida.colorTransform(m_Rect_Amida, m_CT_Amida);
m_BitmapData_Amida.setPixel32(m_BallX, m_BallY, BALL_COLOR);
}
//Mouse : Move
public function OnMouseMove(event:MouseEvent):void{
var IndexX:int = (mouseX - AMIDA_INIT_OFFSET_X) / AMIDA_GAP_X;
var IndexY:int = mouseY / LINE_W;
//Range
if(IndexX < 0){IndexX = 0;}
if(LINE_NUM_X-1 <= IndexX){IndexX = LINE_NUM_X-2;}
if(IndexY < 0){IndexY = 0;}
if(LINE_NUM_Y <= IndexY){IndexY = LINE_NUM_Y-1;}
//Pos
m_Bitmap_LineCand.x = AMIDA_INIT_OFFSET_X + IndexX * AMIDA_GAP_X;
m_Bitmap_LineCand.y = IndexY * LINE_W;
}
//Mouse : Down
public function OnMouseDown(event:MouseEvent):void{
//ラインの(Bitmap上での)位置
var src_x:int;
var dst_x:int;
var y:int;
{
var IndexX:int = (mouseX - AMIDA_INIT_OFFSET_X) / AMIDA_GAP_X;
var IndexY:int = mouseY / LINE_W;
//Range
if(IndexX < 0){IndexX = 0;}
if(LINE_NUM_X-1 <= IndexX){IndexX = LINE_NUM_X-2;}
if(IndexY < 0){IndexY = 0;}
if(LINE_NUM_Y <= IndexY){IndexY = LINE_NUM_Y-1;}
src_x = BMP_INIT_OFFSET_X + IndexX*BMP_GAP_X;
dst_x = src_x + BMP_GAP_X;
src_x += 1;
dst_x -= 1;
y = IndexY;
}
//ラインカラー(オン・オフ)
var color:uint;
{
color = LINE_COLOR;
// if(IsLine((src_x+dst_x)/2, y)){
// color = 0x00000000;
// }
//→オフはなくしてみた
}
//反映
for(var x:int = src_x; x <= dst_x; x++){
m_BitmapData_Amida.setPixel32(x, y, color);
}
}
//
public function IsLine(in_X:int, in_Y:int):Boolean{
return (m_BitmapData_Amida.getPixel32(in_X, in_Y) & 0xFF000000) != 0x00000000;
}
//
public function HitCheckBlock():Boolean{
var BallX:int = m_BallX * LINE_W;
var BallY:int = m_BallY * LINE_W;
for(var y:int = 0; y < BLOCK_NUM_Y; y++){
for(var x:int = 0; x < BLOCK_NUM_X; x++){
var block:Block = m_Blocks[y][x];
if(! block.IsExist()){continue;}
if(block.IsRange(BallX, BallY)){
block.Vanish();
return true;
}
}
}
//それっぽいブロックがなかったのでノーヒット
return false;
}
//Utility
static public function Lerp(in_Src:Number, in_Dst:Number, in_Ratio:Number):Number{
return (in_Src * (1 - in_Ratio)) + (in_Dst * in_Ratio);
}
static public function HSVtoRGB(in_Hue:Number, in_Saturation:Number, in_Value:Number):uint{
var r:uint;
var g:uint;
var b:uint;
//色
{
//赤~黄、黄~緑、緑~青緑、青緑~青、青~紫、紫~赤の6フェイズ
const calcVal:Function = function(in_Ratio:Number):uint{
if(in_Ratio > 1.0){in_Ratio -= 1.0;}
if(in_Ratio < 1.0/6.0){return 0xFF;}
if(in_Ratio < 2.0/6.0){return 0xFF * (2.0 - in_Ratio*6.0);}
if(in_Ratio < 3.0/6.0){return 0x00;}
if(in_Ratio < 4.0/6.0){return 0x00;}
if(in_Ratio < 5.0/6.0){return 0xFF * (in_Ratio*6.0 - 4.0);}
if(in_Ratio < 6.0/6.0){return 0xFF;}
return 0xFF;//err
}
r = calcVal(in_Hue + 0.0/3.0);
g = calcVal(in_Hue + 2.0/3.0);
b = calcVal(in_Hue + 1.0/3.0);
}
//彩度計算
{
r = Lerp(0xFF, r, in_Saturation);
g = Lerp(0xFF, g, in_Saturation);
b = Lerp(0xFF, b, in_Saturation);
}
//明度計算
{
r *= in_Value;
g *= in_Value;
b *= in_Value;
}
return (0xFF << 24) | (r << 16) | (g << 8) | (b << 0);
}
}
}
import flash.display.*;
import flash.events.*;
import flash.filters.*;
import flash.geom.*;
import flash.net.*;
import flash.system.*;
import flash.ui.*;
import net.wonderfl.utils.WonderflAPI;
class MoveObj extends Sprite
{
//==Var==
protected var m_Bitmap:Bitmap;
protected var m_BitmapData:BitmapData;
protected var m_W:int;
protected var m_H:int;
//==Function==
//Init
public function MoveObj(in_W:int, in_H:int){
//Param
{
m_W = in_W;
m_H = in_H;
}
//m_BitmapData
{
m_BitmapData = new BitmapData(in_W, in_H, true, 0x00000000);
m_Bitmap = new Bitmap(m_BitmapData);
addChild(m_Bitmap);
}
}
//Util
public function IsRange(in_X:int, in_Y:int):Boolean{
var RelX:int = in_X - this.x - m_Bitmap.x;
var RelY:int = in_Y - this.y - m_Bitmap.y;
return (0 <= RelX) && (RelX <= m_W) && (0 <= RelY) && (RelY <= m_H);
}
}
class Bar extends MoveObj
{
//==Const==
static public const W:int = GameMain.VIEW_W/GameMain.LINE_NUM_X * 5/4;
static public const H:int = GameMain.VIEW_H/32;
static public const RANGE_X_MIN:int = W/2;
static public const RANGE_X_MAX:int = GameMain.VIEW_W - W/2;
static public const VEL:Number = 15;
//==Var==
//移動速度
public var m_VX:Number = VEL;
//==Function==
//Init
public function Bar(){
//Super
{
super(W, H);
}
//Centering
{
m_Bitmap.x = -W/2;
m_Bitmap.y = -H/2;
}
//Graphic
{
m_BitmapData.fillRect(m_BitmapData.rect, 0xFFFFFFFF);
}
}
//Update
public function Update(DeltaTime:Number):void{
this.x += m_VX * DeltaTime;
if(this.x < RANGE_X_MIN){
this.x = RANGE_X_MIN + (RANGE_X_MIN - this.x);
m_VX = -m_VX;
}
if(RANGE_X_MAX < this.x){
this.x = RANGE_X_MAX - (this.x - RANGE_X_MAX);
m_VX = -m_VX;
}
}
}
class Block extends MoveObj
{
//==Const==
static public const W:int = GameMain.BLOCK_W;
static public const H:int = GameMain.BLOCK_H;
//==Var==
public var m_Color:uint;
public var m_VanishFlag:Boolean = false;
//==Function==
//Init
public function Block(in_Color:uint){
//Super
{
super(W, H);
}
//Param
{
m_Color = in_Color;
}
//Graphic
{
m_BitmapData.fillRect(m_BitmapData.rect, in_Color);
}
}
//Update
public function Update(DeltaTime:Number):void{
if(m_VanishFlag){
this.alpha *= 0.9;
}
}
//
public function Vanish():void{
m_VanishFlag = true;
}
//
public function IsExist():Boolean{
return !m_VanishFlag;
}
}
//*
//bkzenさんのコードを利用
//@see http://wonderfl.net/c/cuY4
//@see http://wonderfl.net/c/kYyY
class ScoreWindowLoader
{
private static var _top: DisplayObjectContainer;
private static var _api: WonderflAPI;
private static var _content: Object;
//private static const URL: String = "wonderflScore.swf";
private static const URL: String = "http://swf.wonderfl.net/swf/usercode/5/57/579a/579a46e1306b5770d429a3738349291f05fec4f3.swf";
private static const TWEET: String = "Playing Amida Breakout [score: %SCORE%] #wonderfl";
public static function init(top: DisplayObjectContainer, api: WonderflAPI): void
{
_top = top, _api = api;
var loader: Loader = new Loader();
var comp: Function = function(e: Event): void
{
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, comp);
_content = loader.content;
// handler();
}
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, comp);
loader.load(new URLRequest(URL), new LoaderContext(true));
}
public static function show( score: int): void
{
var window: DisplayObject = _content.makeScoreWindow(_api, score, "Amida Breakout", 1, TWEET);
// var close: Function = function(e: Event): void
// {
// window.removeEventListener(Event.CLOSE, close);
// closeHandler();
// }
// window.addEventListener(Event.CLOSE, close);
_top.addChild(window);
}
}
//*/