球体交換 -Ball Swap-
ボールの位置を交換してゴールを目指すゲーム
操作方法(How to Play)
・別のボールをタッチ(Touch another ball)
・位置交換(Swap)
Android版
・試作品として以下に追加
・https://play.google.com/store/apps/details?id=air.showohealer.game.airprototype
注意事項
・Box2Dのバージョンは2.0.2
・wonderfl対応も一因だが、単純に2.1への対応コストが高いので2.0.2のままにしてる
/**
* 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/bVKw
*/
/*
「球体交換 -Ball Swap-」
・ボールの位置を交換してゴールを目指すゲーム
操作方法(How to Play)
・別のボールをタッチ(Touch another ball)
・位置交換(Swap)
Android版
・試作品として以下に追加
・https://play.google.com/store/apps/details?id=air.showohealer.game.airprototype
注意事項
・Box2Dのバージョンは2.0.2
・wonderfl対応も一因だが、単純に2.1への対応コストが高いので2.0.2のままにしてる
メモ
・スマホではタッチが難しかったのでステージの量産を断念
・移動している球のタッチが難しい
・マウスでもわりと難しい
・球の種類を増やしたり、それとは別にブロックの種類を増やすことでバリエーションは出せそうだったんだけど
・磁石ボール&ブロックとか、特定のボールだけが通過できるブロックとか、ダッシュパネルやトランポリン的なブロックとか
・斜めに設定できる固定ブロックはすでにあり、坂道として使ったりすることとかが可能
・普通に登ったり天井に逆登り坂として配置したり跳ねさせて方向変換したり坂の昇り降りで左右移動の方向変更とかができる
*/
/*
ToDo
・PlayerとGoal以外はグレアでタッチ可能状態を可視化
・Animの方には含めない
・ワープ時は非表示にしたい
→対応を忘れてしまったが、微妙に対応コストがかかるので対応はやめておく
*/
/*
反重力
・b2Islandにて「b.m_linearVelocity.x += step.dt * (gravity.x + b.m_invMass * b.m_force.x);」とある
・なのでgravityは0にしてinvMass * forceがそれと同じになるようにすればOK
→force = gravity * mass
・ただし、forceはその処理内でSetZeroによるリセットを受けるため、それでリセットされないようなb2Vec2を用意して置き換えた
ワープアニメ
・基本的にはパラパラ漫画の原理を利用する
・事前に拡散→収束するパーティクルアニメを用意しておき、それを移動しつつ順次表示することで実現する
*/
package {
import flash.display.*;
import flash.events.*;
import flash.filters.*;
import flash.geom.*;
import flash.net.*;
import flash.system.*;
import flash.text.*;
//Box2D
import Box2D.Dynamics.*;
import Box2D.Collision.*;
import Box2D.Collision.Shapes.*;
import Box2D.Common.*;
import Box2D.Common.Math.*;
import Box2D.Dynamics.Joints.*;
[SWF(width="465", height="465", frameRate="30", backgroundColor="0x004400")]
public class BallSwap extends Sprite {
//==Const==
//画像ファイル名
//*
static public const URL_IMAGE:String = "http://assets.wonderfl.net/images/related_images/8/84/848f/848f9b44d9dac57756643368e83b1cc3ca0caa3a";
/*/
[Embed(source='ballswap.png')]
private static var Bitmap_Image: Class;
//*/
//画面サイズ
static public const VIEW_W:int = 465;
static public const VIEW_H:int = 465;
//重力
static public const GRAVITY:Number = 5;//10;
//1マスの大きさ
static public const PANEL_LEN:int = 32;
//画像サイズ
static public const PANEL_W:int = 24;
static public const PANEL_H:int = 32;
static public const PANEL_NUM_X:int = 3;
static public const PANEL_NUM_Y:int = 4;
//マップ要素
static public var MapIndexIter:int = 0;
static public const O:int = MapIndexIter++;
static public const W:int = MapIndexIter++;
static public const X:int = MapIndexIter++;
static public const P:int = MapIndexIter++;
static public const G:int = MapIndexIter++;
static public const F:int = MapIndexIter++;
static public const U:int = MapIndexIter++;
static public const L:int = MapIndexIter++;
static public const R:int = MapIndexIter++;
static public const N:int = MapIndexIter++;
//マップ
static public const MAP:Array = [
/*
{
map:[
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
[W,O,O,O,O,F,O,O,O,F,O,O,O,F,O,O,O,F,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
[W,O,P,O,O,O,O,O,O,O,O,O,O,O,O,O,O,G,O,O,O,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
],
append:[
]
},
//*/
/*
{
map:[
[W,W,W,W,W,W,W,W,W,W,W],
[W,O,O,O,O,W,O,O,O,O,W],
[W,O,O,O,O,W,O,O,O,O,W],
[W,O,L,O,O,W,O,O,R,O,W],
[W,W,W,W,W,W,W,W,W,W,W],
[W,O,P,O,O,O,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,W],
[W,W,W,W,W,W,W,W,W,W,W],
],
append:[
]
},
//*/
/*
{//慣性で坂の先へ
map:[
[W,W,W,W,W,W,W,W,W,W,W,W,W,W],
[W,O,U,O,O,O,O,O,O,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,W],
[W,P,O,O,O,O,O,O,O,O,O,O,O,W],
[W,W,O,O,O,O,O,O,O,O,O,O,O,W],
[W,W,O,O,O,O,O,O,O,O,O,O,O,W],
[W,W,O,O,O,O,O,O,O,O,O,O,O,W],
[W,W,O,O,O,O,O,O,O,O,O,O,O,W],
[W,W,W,W,W,O,O,O,O,W,W,W,W,W],
[W,W,W,W,W,O,O,O,O,W,W,W,W,W],
[W,W,W,W,W,O,O,O,O,W,W,W,W,W],
[W,W,W,W,W,O,O,O,O,W,W,W,W,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W],
],
append:[
{x:3.5, y:7.0, w:5, h:0.5, ang:45},
]
},
//*/
/*
{//easy:逆上り坂
map:[
[W,W,W,W,W,W,W,W,W,W,W],
[W,W,O,O,O,O,O,O,O,O,W],
[W,W,O,O,O,O,O,O,O,O,W],
[W,W,O,O,O,O,O,O,O,O,W],
[W,W,O,O,O,O,O,O,O,O,W],
[W,W,O,O,O,O,O,O,O,O,W],
[W,W,O,O,O,O,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,W],
[W,U,P,O,O,O,O,O,O,O,W],
[W,W,W,W,W,W,W,W,W,W,W],
],
append:[
{x:3.5, y:3.0, w:5, h:0.5, ang:-45},
]
},
//*/
/*
{//easy:上り坂
map:[
[W,W,W,W,W,W,W,W,W,W,W],
[W,O,O,O,O,O,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,W],
[W,O,O,P,O,O,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,W],
[W,R,O,O,O,O,O,O,O,O,W],
[W,W,W,W,W,W,W,W,W,W,W],
],
append:[
{x:5.5, y:5.0, w:13, h:0.5, ang:-45},
]
},
//*/
/*
{//easy:エレベーター
map:[
[W,W,W,W,W,W,W,W,W,W,W,W,W],
[W,W,W,O,O,O,O,O,O,W,W,W,W],
[W,W,W,O,O,O,O,O,O,W,W,W,W],
[W,W,W,W,W,W,W,O,O,W,W,W,W],
[W,W,W,W,W,W,W,O,O,W,W,W,W],
[W,W,W,W,W,W,W,O,O,W,W,W,W],
[W,W,W,W,W,W,W,O,O,W,W,W,W],
[W,W,W,O,O,O,O,O,O,W,W,W,W],
[W,W,W,L,O,U,O,P,O,W,W,W,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W],
],
append:[
]
},
//*/
/*
{//mid:多重エレベーター
map:[
[W,W,W,W,W,W,W,W,W,W,W,W,W],
[W,W,W,O,O,O,O,O,O,W,W,W,W],
[W,W,W,O,O,O,O,O,O,W,W,W,W],
[W,W,W,O,O,W,W,W,W,W,W,W,W],
[W,W,W,O,O,W,W,W,W,W,W,W,W],
[W,W,W,O,O,W,W,W,W,W,W,W,W],
[W,W,W,O,O,W,W,W,W,W,W,W,W],
[W,W,W,O,O,O,O,O,O,W,W,W,W],
[W,W,W,O,O,O,O,O,O,W,W,W,W],
[W,W,W,W,W,W,W,O,O,W,W,W,W],
[W,W,W,W,W,W,W,O,O,W,W,W,W],
[W,W,W,W,W,W,W,O,O,W,W,W,W],
[W,W,W,W,W,W,W,O,O,W,W,W,W],
[W,W,W,O,O,O,O,O,O,W,W,W,W],
[W,W,W,L,O,U,O,P,R,W,W,W,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W],
],
append:[
]
},
//*/
/*
{//??:シリンダー(全体を上に持ち上げる実験)(タッチの近さを考えないと誤検出される)
map:[
[W,W,W,W,W,W,W,W,W,W,W,W,W],
[W,W,W,W,W,W,O,W,W,W,W,W,W],
[W,W,W,W,W,W,O,W,W,W,W,W,W],
[W,W,W,W,W,W,O,W,W,W,W,W,W],
[W,W,W,W,W,W,O,W,W,W,W,W,W],
[W,W,W,W,W,W,O,W,W,W,W,W,W],
[W,W,W,W,W,W,O,W,W,W,W,W,W],
[W,W,W,W,W,W,U,W,W,W,W,W,W],
[W,W,W,W,W,W,U,W,W,W,W,W,W],
[W,W,W,W,W,W,U,W,W,W,W,W,W],
[W,W,W,W,W,W,U,W,W,W,W,W,W],
[W,W,W,W,W,W,N,W,W,W,W,W,W],
[W,W,W,W,W,W,N,W,W,W,W,W,W],
[W,W,W,W,W,W,P,W,W,W,W,W,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W],
],
append:[
]
},
//*/
/*
{//目詰り解消
map:[
[W,W,W,W,W,W,W,W,W,W],
[W,W,W,O,O,O,O,O,O,W],
[W,W,W,O,O,O,O,O,O,W],
[W,W,W,O,O,O,O,O,O,W],
[W,W,W,O,W,W,W,W,O,W],
[W,W,O,O,O,W,W,W,O,W],
[W,W,O,O,O,W,W,W,O,W],
[W,W,O,O,O,W,W,W,O,W],
[W,W,O,O,O,W,W,W,O,W],
[W,W,O,O,O,W,W,W,O,W],
[W,W,O,O,O,W,W,W,O,W],
[W,W,O,O,O,W,W,W,O,W],
[W,W,O,O,O,W,W,W,O,W],
[W,W,O,O,O,W,W,W,O,W],
[W,W,U,P,U,W,W,W,O,W],
[W,W,W,W,W,W,W,W,W,W],
],
append:[
{x:2.0, y:6.0, w:2.4, h:0.5, ang:-45},
{x:5.0, y:6.0, w:2.4, h:0.5, ang: 45},
{x:4.2, y:2.0, w:4.4, h:0.5, ang:-45},
]
},
//*/
//*
{//UP用
map:[
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,F,O,O,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,O,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,O,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,O,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,W,W,O,W,O,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,W,O,W,O,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,O,O,O,O,W,G,W,O,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,W,W,W,O,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,W,W,W,W,O,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W],
[W,W,W,W,W,W,W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W],
[W,W,W,W,W,W,W,W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,F,W],
[W,W,W,W,W,O,O,O,O,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,U,W],
[W,W,W,W,W,W,W,W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,U,W],
[W,W,W,W,W,W,W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W],
[W,L,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
[W,O,R,L,O,O,O,O,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
[W,O,O,O,O,O,O,O,O,O,W,W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
[W,O,O,O,O,O,O,O,O,O,W,O,O,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
[W,O,W,W,W,W,W,W,W,W,O,W,O,W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
[W,O,W,W,W,W,W,W,W,W,W,W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
[W,O,W,W,W,W,W,W,W,W,W,W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
[W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
[W,O,W,W,W,R,W,U,W,L,W,W,W,W,W,O,O,O,O,O,W,W,U,W,L,W,W,W,W,W,W],
[W,O,W,W,W,O,W,O,W,O,W,W,W,W,W,O,O,O,O,O,W,W,O,W,O,W,W,W,W,W,W],
[W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,W,W,O,W,W,W,W,W,W,W,W,W,W,W],
[W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,W,W,O,W,W,W,W,W,W,W,W,W,W,W],
[W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,W,W,O,W,W,W,W,W,W,W,W,W,W,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,W,W,O,O,O,O,O,F,O,O,O,O,O,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,W,W,W,W,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,O,W,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,W,O,W,W,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,W,W,O,W,W,W,O,O,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,O,W,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,O,W,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,O,W,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,F,O,O,O,O,O,O,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,F,O,O,O,O,O,O,O,O,O,O,F,O,O,O,O,U,W],
[W,O,P,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
[W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
[W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
],
append:[
]
},
//*/
];
//マップのパネル数
static public const MAP_NUM_X:int = MAP[0].map[0].length;
static public const MAP_NUM_Y:int = MAP[0].map.length;
//マップの大きさ
static public const MAP_W:int = MAP_NUM_X * PANEL_LEN;
static public const MAP_H:int = MAP_NUM_Y * PANEL_LEN;
//Box2Dと実際の表示の比率(Box2Dに大きすぎる値を入れると上手く動かなかったりする)
static public const PHYS_SCALE:Number = 10;
static public function PHYS_to_IMAGE(in_Val:Number):Number{return in_Val * PHYS_SCALE;}
static public function IMAGE_to_PHYS(in_Val:Number):Number{return in_Val / PHYS_SCALE;}
//Box2Dの画面外の余白
static public const BOX2D_RANGE_OFFSET:int = 100;
//モード
static public var ModeIter:int = 0;
static public const MODE_MAIN:int = ModeIter++;
static public const MODE_GOAL:int = ModeIter++;
static public const MODE_GAME_OVER:int = ModeIter++;
//==Var==
//Pseudo Singleton
static public var Instance:BallSwap;
//マップ(プレイヤーなどを地面に置き換えたりしたもの)
public var m_Map:Vector.<Vector.<int> >;
//プレイヤーの初期位置
public var m_PlayerX:int = 2.5*PANEL_LEN;//一応それっぽい位置に初期化
public var m_PlayerY:int = 2.5*PANEL_LEN;
//ゴールの初期位置
public var m_GoalX:int = 0.5*PANEL_LEN;//一応それっぽい位置に初期化
public var m_GoalY:int = 0.5*PANEL_LEN;
//レイヤー
public var m_Layer_Root:Sprite = new Sprite();//Root
public var m_Layer_Ground:Sprite = new Sprite();//地面用レイヤー
public var m_Layer_Obj:Sprite = new Sprite();//通常表示用レイヤー
public var m_Layer_Debug:Sprite = new Sprite();//デバッグ描画用
public var m_Layer_HUD:Sprite = new Sprite();//情報表示用レイヤー
//地形画像
public var m_BitmapData_Floor:BitmapData = new BitmapData(MAP_W, MAP_H, true, 0x00000000);
//トゲ判定のためのダミーSprite
public var m_NeedleSprite:Sprite = new Sprite();
//GameObjectのリスト
public var m_GameObjectList:Vector.<GameObject> = new Vector.<GameObject>();
//タッチ中のGameObject(リリース時に反応するためUpdateでタッチのチェックを行う)
public var m_TouchObj:GameObject = null;
//Swapまわり
public var m_SwapFlag:Boolean = false;
public var m_SwapAnimCount:int = 0;
public var m_SrcX:int;
public var m_SrcY:int;
public var m_DstX:int;
public var m_DstY:int;
//プレイヤー
public var m_Player:Player;
//ゴール
public var m_Goal:Goal;
public var m_GoalAnimIndex:int = 0;
//テキスト
public var m_Text:TextField = new TextField();
//モード
public var m_Mode:int = MODE_MAIN;
//Box2D
public var m_Box2D_World:b2World;
//==Function==
//Init
public function BallSwap(){
if(stage != null){
Init(null);
}else{
addEventListener(
Event.ADDED_TO_STAGE,//ステージに追加されたら
Init
);
}
}
public function Init(e:Event):void
{
var x:int;
var y:int;
//Pseudo Singleton
{
Instance = this;
}
//Common
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
}
//Static Init
{
ImageManager.Init();
//Player.Initialize();
}
//MAP => m_Map
{
m_Map = new Vector.<Vector.<int> >(MAP_NUM_Y);
for(y = 0; y < MAP_NUM_Y; y++){
m_Map[y] = new Vector.<int>(MAP_NUM_X);
var PosY:int = (y+0.5) * PANEL_LEN;
for(x = 0; x < MAP_NUM_X; x++){
var PosX:int = (x+0.5) * PANEL_LEN;
var index:int = MAP[0].map[y][x];
switch(index){
case P:
index = O;//プレイヤーの居た位置は地面扱いする
m_PlayerX = PosX;
m_PlayerY = PosY;
break;
case G:
index = O;//ゴールのある位置は地面扱いする
m_GoalX = PosX;
m_GoalY = PosY;
break;
}
m_Map[y][x] = index;
}
}
}
//Box2D
{
//考慮する領域
var worldAABB:b2AABB = new b2AABB();
worldAABB.lowerBound.Set(IMAGE_to_PHYS(-BOX2D_RANGE_OFFSET), IMAGE_to_PHYS(-BOX2D_RANGE_OFFSET));
worldAABB.upperBound.Set(IMAGE_to_PHYS(MAP_W+BOX2D_RANGE_OFFSET), IMAGE_to_PHYS(MAP_H+BOX2D_RANGE_OFFSET));
//重力ベクトル
//var gravity:b2Vec2 = new b2Vec2(0, GRAVITY);
var gravity:b2Vec2 = new b2Vec2(0, 0);//重力は個々で設定することにして、上方向の重力などを実現
//Sleep
var useSleep:Boolean = false;//位置交換するし動く物体の数は少ないはずなのでスリープはさせない
//物理world
m_Box2D_World = new b2World(worldAABB, gravity, useSleep);
//ContactListener
m_Box2D_World.SetContactListener(new ContactListener());
}
//Layer
{
addChild(m_Layer_Root);
{
m_Layer_Root.addChild(m_Layer_Ground);
m_Layer_Root.addChild(m_Layer_Obj);
m_Layer_Root.addChild(m_Layer_Debug);
}
addChild(m_Layer_HUD);
}
//地形
{
ImageManager.Map_to_Bitmap(
m_Map,
m_BitmapData_Floor
);
var bmp:Bitmap;
//Floor
{
bmp = new Bitmap(m_BitmapData_Floor);
m_Layer_Ground.addChild(bmp);
}
}
//Text
{
m_Text.selectable = false;
m_Text.autoSize = TextFieldAutoSize.LEFT;
m_Text.defaultTextFormat = new TextFormat('Verdana', 60, 0xFFFF00, true);
m_Text.text = '';
m_Text.filters = [new GlowFilter(0xFF0000,1.0, 8,8)];
addChild(m_Text);
}
//Touch
{
stage.addEventListener(MouseEvent.MOUSE_DOWN, OnMouseDown);
stage.addEventListener(MouseEvent.MOUSE_MOVE, OnMouseMove);
stage.addEventListener(MouseEvent.MOUSE_UP, OnMouseUp);
}
//画像ロード開始
{
//*
const LoadFunc:Function = function(in_URL:String, in_OnLoad:Function):void{
var loader:Loader = new Loader();
loader.load(new URLRequest(in_URL), new LoaderContext(true));//画像のロードを開始して
loader.contentLoaderInfo.addEventListener(
Event.COMPLETE,//ロードが完了したら
function(e:Event):void{
in_OnLoad(loader.content);//初期化に入る
}
);
}
LoadFunc(URL_IMAGE, OnLoadEnd);
/*/
OnLoadEnd(new Bitmap_Image());
//*/
}
/*
//Debug
{
var debugDraw:b2DebugDraw = new b2DebugDraw();
debugDraw.m_sprite = m_Layer_Debug;//this;
debugDraw.m_drawScale = PHYS_SCALE;
debugDraw.m_fillAlpha = 0.6;
debugDraw.m_lineThickness = 1;
debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit;
m_Box2D_World.SetDebugDraw(debugDraw);
}
//*/
}
//Reset
public function Reset():void{
var x:int;
var y:int;
var i:int;
//Param
{
m_SwapFlag = false;
}
//GameObject
{
//Remove Old
ClearGameObjectList();
//Playerを追加
//Goalを追加
//Ballを生成のたびに追加
m_Map = new Vector.<Vector.<int> >(MAP_NUM_Y);
for(y = 0; y < MAP_NUM_Y; y++){
m_Map[y] = new Vector.<int>(MAP_NUM_X);
var pos_y:int = (y+0.5) * PANEL_LEN;
for(x = 0; x < MAP_NUM_X; x++){
var pos_x:int = (x+0.5) * PANEL_LEN;
var index:int = MAP[0].map[y][x];
switch(index){
case P:
m_Player = new Player();
RegisterGameObject(m_Player, pos_x, pos_y);
index = O;//プレイヤーの居た位置は地面扱いする
m_PlayerX = pos_x;
m_PlayerY = pos_y;
break;
case G:
m_Goal = new Goal();
RegisterGameObject(m_Goal, pos_x, pos_y);
m_GoalAnimIndex = 0;
index = O;//ゴールのある位置は地面扱いする
m_GoalX = pos_x;
m_GoalY = pos_y;
break;
case F:
RegisterGameObject(new GameObject_Ball_Fix(), pos_x, pos_y);
break;
case U:
RegisterGameObject(new GameObject_Ball_Move(0, -1), pos_x, pos_y);
break;
case L:
RegisterGameObject(new GameObject_Ball_Move(-1, 0), pos_x, pos_y);
break;
case R:
RegisterGameObject(new GameObject_Ball_Move(+1, 0), pos_x, pos_y);
break;
case N:
RegisterGameObject(new GameObject_Ball(), pos_x, pos_y);
break;
}
m_Map[y][x] = index;
}
}
//一応リセット
m_TouchObj = null;
}
//
{
var param_arr:Array = MAP[0].append;
var param_num:int = param_arr.length;
for(i = 0; i < param_num; ++i){
var param:* = param_arr[i];
RegisterGameObject(new GameObject_Box(param.w * PANEL_LEN, param.h * PANEL_LEN, param.ang), param.x * PANEL_LEN, param.y * PANEL_LEN);
}
}
//地形コリジョン
{
Init_Terrain_Collision();
}
//Camera
{
Update_Camera(1.0);
}
}
//GameObjectの登録を全部解除
public function ClearGameObjectList():void{
var num:int = m_GameObjectList.length;
for(var i:int = 0; i < num; ++i){
var obj:GameObject = m_GameObjectList[i];
if(obj.parent != null){
obj.parent.removeChild(obj);
}
}
m_GameObjectList = new Vector.<GameObject>();
}
//GameObjectを登録
public function RegisterGameObject(in_GameObj:GameObject, in_X:Number, in_Y:Number):void{
in_GameObj.SetPosition(in_X, in_Y);
m_Layer_Obj.addChild(in_GameObj);
m_GameObjectList.push(in_GameObj);
}
//Init : Terrain Collision
public function Init_Terrain_Collision():void{
var x:int;
var y:int;
var r:Rectangle;
//準備:トゲ判定
const NEEDLE_W:Number = 0.5*PANEL_LEN * 1.1;
var body_needle:b2Body;
var shapeDef_needle:b2PolygonDef;
{
//まずはトゲ用のBodyを一つだけ作成
//var body_needle:b2Body;
{
body_needle = m_Box2D_World.CreateBody(new b2BodyDef());
body_needle.SetUserData(m_NeedleSprite);
}
//作成するShapeのベースを作成
//var shapeDef_needle:b2PolygonDef;
{
shapeDef_needle = new b2PolygonDef();
shapeDef_needle.density = 0;//Fix
shapeDef_needle.isSensor = true;
}
}
//コリジョンリスト
var RectList:Vector.<Rectangle> = new Vector.<Rectangle>();
{
//現在の行のコリジョン
var RectList_Now:Vector.<Rectangle> = new Vector.<Rectangle>(MAP_NUM_X);
//結合するため、一時的に溜めておく
var RectList_Pre:Vector.<Rectangle> = new Vector.<Rectangle>(MAP_NUM_X);
for(y = 0; y < MAP_NUM_Y; y++){
var PosY:int = (y+0.5) * PANEL_LEN;
r = null;
//まずはこの行のまとめられるところをまとめる
for(x = 0; x < MAP_NUM_X; x++){
var PosX:int = (x+0.5) * PANEL_LEN;
var index:int = m_Map[y][x];
switch(index){
case X:
index = W;//壁として一体化する
//トゲ判定を追加する
shapeDef_needle.SetAsOrientedBox(IMAGE_to_PHYS(NEEDLE_W), IMAGE_to_PHYS(NEEDLE_W), new b2Vec2(IMAGE_to_PHYS(PosX), IMAGE_to_PHYS(PosY)));
body_needle.CreateShape(shapeDef_needle);
break;
}
if(index == W){
if(r == null){
r = new Rectangle(x*PANEL_LEN, y*PANEL_LEN, PANEL_LEN, PANEL_LEN);
RectList_Now[x] = r;
}else{
r.width += PANEL_LEN;
}
}else{
r = null;
}
}
//前回の結果と統合できるなら統合する
for(x = 0; x < MAP_NUM_X; x++){
if(RectList_Pre[x] != null){//前回の結果と
if(RectList_Now[x] != null){//今回の結果で同じ始点のものがあり
if(RectList_Pre[x].width == RectList_Now[x].width){//幅が同じなら
//統合する
RectList_Pre[x].height += PANEL_LEN;
RectList_Now[x] = null;
continue;
}
}
//前回の結果が統合できない場合、もう統合することもないのでResultに入れてしまう
RectList.push(RectList_Pre[x]);
}
//今回の結果を前回の結果の方に移す
RectList_Pre[x] = RectList_Now[x];
RectList_Now[x] = null;
}
}
//残っているやつをResultに移す
for(x = 0; x < MAP_NUM_X; x++){
if(RectList_Pre[x] != null){
RectList.push(RectList_Pre[x]);
}
}
}
//実際に作成
{
//まずは地形用のBodyを一つだけ作成
var body:b2Body;
{
body = m_Box2D_World.CreateBody(new b2BodyDef());
}
//作成するShapeのベースを作成
var shapeDef:b2PolygonDef;
{
shapeDef = new b2PolygonDef();
shapeDef.density = 0;//Fix
shapeDef.friction = 0;
shapeDef.restitution = 0.5;
}
//あとはリストの形状を追加していく
var w:Number;
var h:Number;
var center:b2Vec2 = new b2Vec2();
var ColNum:int = RectList.length;
for(var i:int = 0; i < ColNum; i++){
r = RectList[i];
w = IMAGE_to_PHYS(r.width/2);
h = IMAGE_to_PHYS(r.height/2);
center.x = IMAGE_to_PHYS(r.x) + w;
center.y = IMAGE_to_PHYS(r.y) + h;
shapeDef.SetAsOrientedBox(w, h, center);
body.CreateShape(shapeDef);
}
//一応、追加したShapeに合わせてMassを計算(Fixなので不要かもしれない)
body.SetMassFromShapes();
}
/*
//Debug
var sprite:Sprite = new Sprite();
m_Layer_Debug.addChild(sprite);
var g:Graphics = sprite.graphics;
g.lineStyle(3,0x00FFFF,1.0);
for(i = 0; i < ColNum; i++){
r = RectList[i];
g.drawRect(r.x, r.y, r.width, r.height);
}
//*/
}
//OnLoad
public function OnLoadEnd(in_Graphic:DisplayObject):void{
//Init ImageManager
{
ImageManager.SetImage(in_Graphic);//それを保持した後
}
//今の表示のスクリーンショットを撮っておいて、α減衰させつつ画像表示に移行させてみる
{
var bmd:BitmapData = new BitmapData(VIEW_W, VIEW_H, false, 0x000000);
bmd.draw(m_Layer_Root, new Matrix(1,0,0,1, m_Layer_Root.x,m_Layer_Root.y));
var bmp:Bitmap = new Bitmap(bmd);
addChild(bmp);
addEventListener(Event.ENTER_FRAME, function f(e:Event):void{
var DeltaAlpha:Number = 5 * 1.0/30.0;
bmp.alpha -= DeltaAlpha;
if(bmp.alpha <= 0){
removeChild(bmp);
removeEventListener(Event.ENTER_FRAME, f);
}
});
}
//ブロック描画
{
ImageManager.Map_to_Bitmap(
m_Map,
m_BitmapData_Floor
);
}
var mtx:Matrix = new Matrix();
//各ボールの画像
{//Player
mtx.tx = -0*32;
mtx.ty = -2*32;
Player.s_BitmapData.draw(in_Graphic, mtx);
}
{//GameObject_Ball_Fix
mtx.tx = -1*32;
mtx.ty = -2*32;
GameObject_Ball_Fix.s_BitmapData.draw(in_Graphic, mtx);
}
{//GameObject_Ball_Move
mtx.tx = -2*32;
mtx.ty = -2*32;
GameObject_Ball_Move.s_BitmapData.draw(in_Graphic, mtx);
mtx.tx = -0*32;
mtx.ty = -3*32;
GameObject_Ball_Move.s_BitmapData_Arrow.draw(in_Graphic, mtx);
}
{//Goal
mtx.tx = -3*32;
mtx.ty = -2*32;
Goal.s_BitmapData.draw(in_Graphic, mtx);
}
//Update
{
addEventListener(Event.ENTER_FRAME, Update);
}
//残りはResetと同じ処理
{
Reset();
}
}
//Touch : Down
private function OnMouseDown(e:MouseEvent):void{
if(m_SwapFlag){
return;
}
m_TouchObj = null;
var min_ratio:Number = 1.0;
var num:int = m_GameObjectList.length;
for(var i:int = 0; i < num; ++i){
var obj:GameObject = m_GameObjectList[i];
var touch_ratio:Number = obj.GetTouchRangeRatio();
if(touch_ratio < min_ratio){
m_TouchObj = obj;
min_ratio = touch_ratio;
}
}
}
//Touch : Move
private function OnMouseMove(e:MouseEvent):void{
//ここでやるよりはUpdateでチェックしたほうがコリジョン自身の移動にも対応できて良い
}
//Touch : Up
private function OnMouseUp(e:MouseEvent):void{
if(m_SwapFlag){
return;
}
/*
if(m_TouchObj != null){
//Swap
var another_x:Number = m_TouchObj.x;
var another_y:Number = m_TouchObj.y;
m_TouchObj.SetPosition(m_Player.x, m_Player.y);
m_Player.SetPosition(another_x, another_y);
}
m_TouchObj = null;
/*/
if(m_TouchObj != null){
//Swap
Begin_Swap();
}
//*/
}
//Swap : Begin
public function Begin_Swap():void{
m_SwapFlag = true;
m_SwapAnimCount = 0;
m_SrcX = m_Player.x;
m_SrcY = m_Player.y;
m_DstX = m_TouchObj.x;
m_DstY = m_TouchObj.y;
}
//Swap : End
public function End_Swap():void{
m_Player.SetPosition(m_DstX, m_DstY);
m_TouchObj.SetPosition(m_SrcX, m_SrcY);
m_Player.SetAnimIndex(0);
m_TouchObj.SetAnimIndex(0);
m_SwapFlag = false;
m_TouchObj = null;
}
//Update
public function Update(e:Event=null):void{
//Check
if(IsEnd()){
if(m_GoalAnimIndex < GameObject.ANIM_NUM-1){
++m_GoalAnimIndex;
}
m_Goal.SetAnimIndex(m_GoalAnimIndex);
return;
}
//今回進める時間
var DeltaTime:Number = 1.0/30.0;
//Swap処理
if(m_SwapFlag){
Update_Swap();
return;
}
//タッチを開始した相手をタッチし続けてるかチェック
//- 途中で外れたら離した時に反応しないようにする
if(m_TouchObj != null){
if(1.0 < m_TouchObj.GetTouchRangeRatio()){
m_TouchObj = null;
}
}
//物理まわりの更新
Update_Phys(DeltaTime);
//GameObjectの更新
Update_GameObj(DeltaTime);
//Player
//m_Player.Update(DeltaTime);
//Goal
//m_Goal.Update();
//Camera
Update_Camera();
}
//Swapの移動処理
public function Update_Swap():void{
//Ratio
var lerp_ratio:Number = 1.0 * m_SwapAnimCount / GameObject.ANIM_NUM;
lerp_ratio = 0.5 - 0.5*Math.cos(Math.PI * lerp_ratio);
//lerp_ratio = 0.5 - 0.5*Math.cos(Math.PI * lerp_ratio);
//m_Player : Src => Dst
m_Player.x = Util.Lerp(m_SrcX, m_DstX, lerp_ratio);
m_Player.y = Util.Lerp(m_SrcY, m_DstY, lerp_ratio);
m_Player.SetAnimIndex(m_SwapAnimCount);
//m_TouchObj: Dst => Src
m_TouchObj.x = Util.Lerp(m_DstX, m_SrcX, lerp_ratio);
m_TouchObj.y = Util.Lerp(m_DstY, m_SrcY, lerp_ratio);
m_TouchObj.SetAnimIndex(m_SwapAnimCount);
//Count
++m_SwapAnimCount;
if(GameObject.ANIM_NUM <= m_SwapAnimCount){
End_Swap();
}
}
//物理まわりの更新
public function Update_Phys(in_DeltaTime:Number):void{
var b:b2Body;
//物理エンジンをDeltaTimeだけ進める
m_Box2D_World.Step(in_DeltaTime, 10);
//Sync
for(b = m_Box2D_World.m_bodyList; b; b = b.m_next){
//画像との同期
if(b.m_userData != null){
var sprite:Sprite = b.m_userData as Sprite;
sprite.x = PHYS_to_IMAGE(b.GetPosition().x);
sprite.y = PHYS_to_IMAGE(b.GetPosition().y);
//b.m_userData.m_VX = PHYS_to_IMAGE(b.m_linearVelocity.x);
//b.m_userData.m_VY = PHYS_to_IMAGE(b.m_linearVelocity.y);
sprite.rotation = b.GetAngle() * 180/Math.PI;
}
/*
//擬似摩擦
{
const Ratio:Number = 0.99;//本当はDeltaTime依存の値にした方が良い
b.GetLinearVelocity().x *= Ratio;
b.GetLinearVelocity().y *= Ratio;
b.SetAngularVelocity(b.GetAngularVelocity() * Ratio);
}
//*/
}
}
//GameObjectの更新
public function Update_GameObj(in_DeltaTime:Number):void{
var num:int = m_GameObjectList.length;
for(var i:int = 0; i < num; ++i){
var obj:GameObject = m_GameObjectList[i];
obj.Update(in_DeltaTime);
}
}
//Update : Camera
public function Update_Camera(in_LerpRatio:Number = 0.2):void{
var PlayerX:int = m_Player.x;
var PlayerY:int = m_Player.y;
//移動量
var CameraMoveX:int = 0;
var CameraMoveY:int = 0;
{
//現在のカメラでのプレイヤー相対位置
var RelPlayerX:Number = PlayerX + m_Layer_Root.x;
var RelPlayerY:Number = PlayerY + m_Layer_Root.y;
//中央からの差がそのまま移動量
CameraMoveX = VIEW_W/2 - RelPlayerX;
CameraMoveY = VIEW_H/2 - RelPlayerY;
}
//目標値
var RootX:int = m_Layer_Root.x + CameraMoveX;
var RootY:int = m_Layer_Root.y + CameraMoveY;
{
//端制限
if(RootX < -MAP_W + VIEW_W){
RootX = -MAP_W + VIEW_W;
}
if(RootX > 0){
RootX = 0;
}
if(RootY < -MAP_H + VIEW_H){
RootY = -MAP_H + VIEW_H;
}
if(RootY > 0){
RootY = 0;
}
}
/*
m_Layer_Root.x = RootX;
m_Layer_Root.y = RootY;
/*/
//補間(ワープ時にカメラはゆっくり追いかけるようにするため)
m_Layer_Root.x = Util.Lerp(m_Layer_Root.x, RootX, in_LerpRatio);
m_Layer_Root.y = Util.Lerp(m_Layer_Root.y, RootY, in_LerpRatio);
//*/
}
//Goal
public function OnGoal():void{
//Mode
{
m_Mode = MODE_GOAL;
}
//Text
{
//Text
m_Text.text = 'Clear';
//Centering
m_Text.x = (stage.stageWidth - m_Text.width) / 2;
m_Text.y = (stage.stageHeight - m_Text.height) * 4/9;
}
}
//Game Over : Damage
public function OnDead_Damage():void{
//Mode
{
m_Mode = MODE_GAME_OVER;
}
//Text
{
//Text
m_Text.text = 'Game Over';
//Centering
m_Text.x = (stage.stageWidth - m_Text.width) / 2;
m_Text.y = (stage.stageHeight - m_Text.height) / 2;
}
}
//Game Over : Fall
public function OnDead_Fall():void{
//Mode
{
m_Mode = MODE_GAME_OVER;
}
//Text
{
//Text
m_Text.text = 'Game Over';
//Centering
m_Text.x = (stage.stageWidth - m_Text.width) / 2;
m_Text.y = (stage.stageHeight - m_Text.height) / 2;
}
}
//#IsGameOver
public function IsEnd():Boolean{
return (m_Mode != MODE_MAIN);
}
}
}
import flash.display.*;
import flash.events.*;
import flash.filters.*;
import flash.geom.*;
import flash.net.*;
import flash.system.*;
import flash.text.*;
import flash.sensors.*;
//Box2D
import Box2D.Dynamics.*;
import Box2D.Collision.*;
import Box2D.Collision.Shapes.*;
import Box2D.Common.*;
import Box2D.Common.Math.*;
import Box2D.Dynamics.Joints.*;
class ContactListener extends b2ContactListener
{
//衝突が発生した
override public function Add(in_ContactPoint:b2ContactPoint):void{
var body1:b2Body = in_ContactPoint.shape1.GetBody();
var body2:b2Body = in_ContactPoint.shape2.GetBody();
//ダメージ処理
{
//*
var body_needle:b2Body;
var body_object:b2Body;
{
if(body1.GetUserData() == BallSwap.Instance.m_NeedleSprite){
body_needle = body1;
if(body2.IsDynamic()){
body_object = body2;
}
}
if(body2.GetUserData() == BallSwap.Instance.m_NeedleSprite){
body_needle = body2;
if(body1.IsDynamic()){
body_object = body1;
}
}
}
//if(body_needle && body_object)
if(body_needle)
{
//今は仮ですぐにゲームオーバーにしてしまう
BallSwap.Instance.OnDead_Damage();
}
//*/
}
//ゴール処理
{
var body_player:b2Body;
var body_goal:b2Body;
{
if(body1.GetUserData() == BallSwap.Instance.m_Player){
body_player = body1;
}
if(body2.GetUserData() == BallSwap.Instance.m_Player){
body_player = body2;
}
if(body1.GetUserData() == BallSwap.Instance.m_Goal){
body_goal = body1;
}
if(body2.GetUserData() == BallSwap.Instance.m_Goal){
body_goal = body2;
}
}
if(body_player != null && body_goal != null){
BallSwap.Instance.OnGoal();
}
}
}
}
class ImageManager
{
//==Const==
//#Graphic
static public var m_GraphicIndexIter:int = 0;
static public const GRAPHIC_INDEX_BG:int = m_GraphicIndexIter++;
static public const GRAPHIC_INDEX_WALL:int = m_GraphicIndexIter++;
static public const GRAPHIC_INDEX_WALL_X:int = m_GraphicIndexIter++;
static public const GRAPHIC_INDEX_WALL_Y:int = m_GraphicIndexIter++;
static public const GRAPHIC_INDEX_WALL_XorY:int = m_GraphicIndexIter++;
static public const GRAPHIC_INDEX_WALL_XandY:int = m_GraphicIndexIter++;
static public const GRAPHIC_INDEX_NEEDLE:int = m_GraphicIndexIter++;
static public const GRAPHIC_INDEX_NEEDLE_X:int = m_GraphicIndexIter++;
static public const GRAPHIC_INDEX_NEEDLE_Y:int = m_GraphicIndexIter++;
static public const GRAPHIC_INDEX_NEEDLE_XY:int = m_GraphicIndexIter++;
static public const GRAPHIC_INDEX_NUM:int = m_GraphicIndexIter;
//#enum:Quater
static public const LU:int = 0;
static public const RU:int = 1;
static public const LD:int = 2;
static public const RD:int = 3;
//#enum:Pos
static public const POS_X:int = 0;
static public const POS_Y:int = 1;
//#Graphic
static public var m_BitmapData_View:BitmapData;
//#Mapping
static public var GRAPHIC_INDEX_TO_POS:Array;
//#Palette
static public var m_Palette_ForView:Array;
//#Utility
static public const POS_ZERO:Point = new Point(0,0);
//==Function==
//#Init
static public function Init():void{
var x:int, y:int, i:int;
//m_BitmapData_View
{
m_BitmapData_View = new BitmapData(256, 256, false, 0x000000);
}
//GRAPHIC_INDEX_TO_POS
{//GRAPHIC_INDEX_~から画像の位置へのマッピング(さらにどの隅での処理かも含む)(そして左から何マス目、上から何マス目、という指定)
GRAPHIC_INDEX_TO_POS = new Array(GRAPHIC_INDEX_NUM);
//[LU][RU][LD][RD]
GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_BG] = [[3,2], [3,2], [3,2], [3,2]];
GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_WALL] = [[1,1], [1,1], [1,1], [1,1]];
GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_WALL_X] = [[0,1], [2,1], [0,1], [2,1]];
GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_WALL_Y] = [[1,0], [1,0], [1,2], [1,2]];
GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_WALL_XorY] = [[0,0], [2,0], [0,2], [2,2]];
GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_WALL_XandY] = [[3,0], [4,0], [3,1], [4,1]];
GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_NEEDLE] = [[3,3], [4,3], [3,4], [4,4]];
GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_NEEDLE_X] = [[0,4], [2,4], [0,4], [2,4]];
GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_NEEDLE_Y] = [[1,3], [1,3], [1,5], [1,5]];
GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_NEEDLE_XY] = [[0,3], [2,3], [0,5], [2,5]];
}
//m_Palette_ForView
{
m_Palette_ForView = new Array(256);
var index_graphic:int = GRAPHIC_INDEX_BG;
for(i = 0; i < 256; i++){
//区切りごとにindexを変更。次の区切りまではその値をセット
switch(i){
case 0:
case 6:
case 18:
case 24:
index_graphic = GRAPHIC_INDEX_BG; break;
case 3:
case 21:
index_graphic = GRAPHIC_INDEX_NEEDLE_Y; break;
case 9:
case 15:
index_graphic = GRAPHIC_INDEX_NEEDLE_X; break;
case 12:
index_graphic = GRAPHIC_INDEX_NEEDLE_XY; break;
case 27:
index_graphic = GRAPHIC_INDEX_NEEDLE; break;
case 54:
case 63:
index_graphic = GRAPHIC_INDEX_WALL_XorY; break;
case 60:
case 69:
index_graphic = GRAPHIC_INDEX_WALL_X; break;
case 72:
index_graphic = GRAPHIC_INDEX_WALL_Y; break;
case 78:
index_graphic = GRAPHIC_INDEX_WALL_XandY; break;
case 80:
index_graphic = GRAPHIC_INDEX_WALL; break;
}
m_Palette_ForView[i] = index_graphic;
}
}
}
//画像設定
static public function SetImage(in_Graphic:DisplayObject):void
{
m_BitmapData_View.draw(in_Graphic);
}
//#Draw : BG
static public function Map_to_Bitmap(in_Map:Vector.<Vector.<int> >, out_BitmapData_View:BitmapData):void
{
var x:int, y:int, i:int;
var mtx:Matrix = new Matrix();
var NumX:int = in_Map[0].length;
var NumY:int = in_Map.length;
//Map => Bitmap_Base
//Mapの要素を元に、「0:空白」「1:トゲ」「2:壁」というBitmapを生成
var BitmapData_Base:BitmapData;
{
BitmapData_Base = new BitmapData(NumX, NumY, false, 0x000000);
for(y = 0; y < NumY; y++){
for(x = 0; x < NumX; x++){
var index:int = 0;//default(O, P, G)
{
switch(in_Map[y][x]){
case BallSwap.W:
index = 2;
break;
case BallSwap.X:
index = 1;
break;
}
}
BitmapData_Base.setPixel(x, y, index);
}
}
}
//Bitmap_Base => Bitmap_LU,Bitmap_RU,Bitmap_LD,Bitmap_RD
//Bitmap_Baseを元に、四隅の隣接状況をそれぞれ求める(Uniqueな値になるようにする)
var BitmapData_Quater:Array = new Array(4);
{
//Create Filter
const filter:Array = [
new ConvolutionFilter(3,3,
[//LU
1, 3, 0,
9, 27, 0,
0, 0, 0,
]
),
new ConvolutionFilter(3,3,
[//RU
0, 3, 1,
0, 27, 9,
0, 0, 0,
]
),
new ConvolutionFilter(3,3,
[//LD
0, 0, 0,
9, 27, 0,
1, 3, 0,
]
),
new ConvolutionFilter(3,3,
[//RD
0, 0, 0,
0, 27, 9,
0, 3, 1,
]
),
];
for(i = 0; i < 4; i++){
//Init
BitmapData_Quater[i] = new BitmapData(NumX, NumY, false, 0x000000);
//Apply Filter
BitmapData_Quater[i].applyFilter(BitmapData_Base, BitmapData_Base.rect, POS_ZERO, filter[i]);
}
}
//Bitmap_LU,Bitmap_RU,Bitmap_LD,Bitmap_RD => ForView
//Uniqueな値から、対応するIndexへと変換する
var BitmapData_ForView:Array = new Array(4);
{
for(i = 0; i < 4; i++){
//Init
BitmapData_ForView[i] = new BitmapData(NumX, NumY, false, 0x000000);
//Apply Palette
BitmapData_ForView[i].paletteMap(BitmapData_Quater[i], BitmapData_Quater[i].rect, POS_ZERO, null, null, m_Palette_ForView);
}
}
//Draw
//上で求めたIndexに基づき描画
{
var rect:Rectangle = new Rectangle(0,0, 16,16);
for(y = 0; y < NumY; y++){
for(x = 0; x < NumX; x++){
for(i = 0; i < 4; i++){
rect.x = x * 32 + 16 * ((i&1)>>0);
rect.y = y * 32 + 16 * ((i&2)>>1);
//#view
mtx.tx = rect.x - 16 * GRAPHIC_INDEX_TO_POS[BitmapData_ForView[i].getPixel(x, y)][i][POS_X];
mtx.ty = rect.y - 16 * GRAPHIC_INDEX_TO_POS[BitmapData_ForView[i].getPixel(x, y)][i][POS_Y];
out_BitmapData_View.draw(m_BitmapData_View, mtx, null, null, rect);
}
}
}
}
}
}
//Game用のObject全般クラス
class GameObject extends Sprite
{//コリジョンまで含めたもの
//==Const==
static public const ANIM_NUM:int = 24;//16;//32;
static public const ANIM_EXPAND_RATIO:Number = 5.0;//5.0;//3.0;
//==Var==
//コリジョン本体
//- Swapの際に外部から位置を設定する場合などに使用
public var m_Body:b2Body;
//表示まわり
public var m_Bitmap:Bitmap = new Bitmap();
public var m_AnimList:Vector.<BitmapData> = new Vector.<BitmapData>(ANIM_NUM);
//==Function==
//Init
public function GameObject(){
addChild(m_Bitmap);
}
public function SetAnimIndex(in_Index:int):void{
m_Bitmap.bitmapData = m_AnimList[in_Index];
}
public function CreateAnimList(in_BitmapData_Ori:BitmapData):void{
var xx:int;
var yy:int;
var panel_len:int = BallSwap.PANEL_LEN;
var anim_w:int = panel_len * ANIM_EXPAND_RATIO;
var center_x:Number = panel_len / 2.0;
var center_y:Number = panel_len / 2.0;
var bmd_ori:BitmapData = in_BitmapData_Ori;
var append_ratio:Vector.<Vector.<Number> > = new Vector.<Vector.<Number> >(panel_len);
var timing_ratio:Vector.<Vector.<Number> > = new Vector.<Vector.<Number> >(panel_len);
var rot_sin_ratio:Vector.<Vector.<Number> > = new Vector.<Vector.<Number> >(panel_len);
var rot_cos_ratio:Vector.<Vector.<Number> > = new Vector.<Vector.<Number> >(panel_len);
for(yy = 0; yy < panel_len; ++yy){
append_ratio[yy] = new Vector.<Number>(panel_len);
timing_ratio[yy] = new Vector.<Number>(panel_len);
rot_sin_ratio[yy] = new Vector.<Number>(panel_len);
rot_cos_ratio[yy] = new Vector.<Number>(panel_len);
for(xx = 0; xx < panel_len; ++xx){
append_ratio[yy][xx] = 1;// + 0.5*Math.random();
timing_ratio[yy][xx] = 0.7 * (1 - 2*Math.random());
var theta:Number = 0.1 * Math.PI * (1 - 2*Math.random());
rot_sin_ratio[yy][xx] = Math.sin(theta);
rot_cos_ratio[yy][xx] = Math.cos(theta);
}
}
for(var i:int = 0; i < ANIM_NUM; ++i){
var bmd:BitmapData = new BitmapData(anim_w, anim_w, true, 0x00000000);
for(xx = 0; xx < panel_len; ++xx){
var gap_x:Number = xx - center_x;
for(yy = 0; yy < panel_len; ++yy){
var gap_y:Number = yy - center_y;
var color:uint = bmd_ori.getPixel32(xx, yy);
if((color & 0xFF000000) == 0x00000000){continue;}//透明部分はムシ
var gap:Number = Math.sqrt(gap_x*gap_x + gap_y*gap_y);
var expand_ratio:Number = 1.0 * i / ANIM_NUM;
if(0 < timing_ratio[yy][xx]){
expand_ratio = Util.Lerp(expand_ratio, Math.sin(0.5*Math.PI * expand_ratio), timing_ratio[yy][xx]);
}else{
expand_ratio = Util.Lerp(expand_ratio, 1-Math.cos(0.5*Math.PI * expand_ratio), -timing_ratio[yy][xx]);
}
expand_ratio = Util.Lerp(1, ANIM_EXPAND_RATIO * append_ratio[yy][xx], Math.sin(Math.PI * expand_ratio));
var expand_distance:Number = gap * expand_ratio;
if(gap <= 1){gap = 1;}//一応0を避ける
var base_expand_x:Number = gap_x * expand_distance / gap;
var base_expand_y:Number = gap_y * expand_distance / gap;
var cos:Number = Util.Lerp(1, rot_cos_ratio[yy][xx], Math.sin(Math.PI * i / ANIM_NUM));
var sin:Number = Util.Lerp(0, rot_sin_ratio[yy][xx], Math.sin(Math.PI * i / ANIM_NUM));
var expand_x:Number = base_expand_x * cos - base_expand_y * sin;
var expand_y:Number = base_expand_x * sin + base_expand_y * cos;
var trg_x:int = int(anim_w/2 + expand_x + 0.5);
var trg_y:int = int(anim_w/2 + expand_y + 0.5);
bmd.setPixel32(trg_x, trg_y, color);
}
}
m_AnimList[i] = bmd;
}
}
//Position
public function SetPosition(in_X:Number, in_Y:Number):void{
//Image
{
this.x = in_X;
this.y = in_Y;
}
//Phys
if(m_Body != null)
{
var pos:b2Vec2 = m_Body.GetPosition();
pos.x = BallSwap.IMAGE_to_PHYS(in_X);
pos.y = BallSwap.IMAGE_to_PHYS(in_Y);
var angle:Number = m_Body.GetAngle();
m_Body.SetXForm(pos, angle);
}
}
//Touch
public function GetTouchRangeRatio():Number{
//タッチの近さを返す:1未満ならタッチ扱い、低いほど近い
//Overrideして使う
return 1.0;
}
//Update
public function Update(in_DeltaTime:Number):void{
//Overrideして使う
}
//Gravity
public function SetGravity(in_GravityX:Number, in_GravityY:Number):void{
m_Body.m_force = new b2Vec2_ForGravity(m_Body.GetMass() * in_GravityX, m_Body.GetMass() * in_GravityY);
}
}
//
class GameObject_Ball extends GameObject
{
//==Var==
//タッチの範囲は実際の表示より少し大きくとる
public var m_Range:Number = BallSwap.PANEL_LEN * 0.8;//BallSwap.PANEL_LEN/2;
//==Function==
//Init
public function Init():void{
//グラフィック
{
//Anim
{
/*
var bmd_ori:BitmapData = new BitmapData(BallSwap.PANEL_LEN, BallSwap.PANEL_LEN, true, 0x00000000);
var shape:Shape = new Shape();
DrawGraphics(shape.graphics);
bmd_ori.draw(shape);
/*/
var bmd_ori:BitmapData = GetOriBitmapData();
//*/
CreateAnimList(bmd_ori);
}
//m_Bitmap
{
m_Bitmap.x = -m_AnimList[0].width/2;
m_Bitmap.y = -m_AnimList[0].height/2;
SetAnimIndex(0);
}
}
//コリジョン
{
//Shape Def
var shapeDef:b2ShapeDef = CreateShapeDef();
//Body Def
var bodyDef:b2BodyDef;
{
bodyDef = new b2BodyDef();
bodyDef.position.Set(BallSwap.IMAGE_to_PHYS(this.x), BallSwap.IMAGE_to_PHYS(this.y));
//bodyDef.fixedRotation = true;
}
//Body
var body:b2Body;
{
body = BallSwap.Instance.m_Box2D_World.CreateBody(bodyDef);
body.CreateShape(shapeDef);
body.SetMassFromShapes();
body.m_userData = this;
}
m_Body = body;
SetGravity(0, BallSwap.GRAVITY);
}
}
//Init : Graphic
/*
public function DrawGraphics(g:Graphics):void{
g.lineStyle(2, 0x000000, 0.9);
g.beginFill(0x888888, 1.0);
g.drawCircle(BallSwap.PANEL_LEN/2, BallSwap.PANEL_LEN/2, BallSwap.PANEL_LEN/2 * 0.9);
g.endFill();
}
/*/
public function GetOriBitmapData():BitmapData{
//Overrideして使う
var bmd_ori:BitmapData = new BitmapData(BallSwap.PANEL_LEN, BallSwap.PANEL_LEN, true, 0x00000000);
var shape:Shape = new Shape();
var g:Graphics = shape.graphics;
g.lineStyle(2, 0x000000, 0.9);
g.beginFill(0x888888, 1.0);
g.drawCircle(BallSwap.PANEL_LEN/2, BallSwap.PANEL_LEN/2, BallSwap.PANEL_LEN/2 * 0.9);
g.endFill();
bmd_ori.draw(shape);
return bmd_ori;
}
//*/
//Init : Collision Param
public function CreateShapeDef():b2ShapeDef{
return CreateCircleDef();
}
public function CreateCircleDef():b2CircleDef{
//Overrideして必要なものは変更する
var shapeDef:b2CircleDef;
{
shapeDef = new b2CircleDef();
shapeDef.radius = BallSwap.IMAGE_to_PHYS(BallSwap.PANEL_LEN/2 * 0.9);
shapeDef.density = 1;//tekitou
shapeDef.friction = 0;//5;
shapeDef.restitution = 0.01;
}
return shapeDef;
}
//Touch
override public function GetTouchRangeRatio():Number{
var distance:Number = Math.sqrt(mouseX*mouseX + mouseY*mouseY);
return (distance / m_Range);
}
}
//
class Player extends GameObject_Ball
{
//==Var==
static public var s_BitmapData:BitmapData = new BitmapData(BallSwap.PANEL_LEN, BallSwap.PANEL_LEN, true, 0x00000000);
//==Function==
//Init
public function Player(){
Init();
}
//Init : Graphic
override public function GetOriBitmapData():BitmapData{
return s_BitmapData;
}
//Init : Collision
override public function CreateCircleDef():b2CircleDef{
var shapeDef:b2CircleDef;
{
shapeDef = super.CreateCircleDef();
shapeDef.friction = 0;//0.01;
}
return shapeDef;
}
//Touch
override public function GetTouchRangeRatio():Number{
return 1.0;//プレイヤー自身は交換されない
}
}
//
class GameObject_Ball_Fix extends GameObject_Ball
{
//==Var==
static public var s_BitmapData:BitmapData = new BitmapData(BallSwap.PANEL_LEN, BallSwap.PANEL_LEN, true, 0x00000000);
//==Function==
//Init
public function GameObject_Ball_Fix(){
Init();
}
//Init : Graphic
override public function GetOriBitmapData():BitmapData{
return s_BitmapData;
}
//Init : Collision
override public function CreateCircleDef():b2CircleDef{
var shapeDef:b2CircleDef;
{
shapeDef = super.CreateCircleDef();
shapeDef.density = 0;//Fix
}
return shapeDef;
}
}
//
class GameObject_Ball_Move extends GameObject_Ball
{
//==Var==
static public var s_BitmapData:BitmapData = new BitmapData(BallSwap.PANEL_LEN, BallSwap.PANEL_LEN, true, 0x00000000);
static public var s_BitmapData_Arrow:BitmapData = new BitmapData(BallSwap.PANEL_LEN, BallSwap.PANEL_LEN, true, 0x00000000);
//==Var==
// public var m_IsRotRight:Boolean;
public var m_RatioX:Number;
public var m_RatioY:Number;
//==Function==
//Init
public function GameObject_Ball_Move(in_RatioX:Number, in_RatioY:Number){
m_RatioX = in_RatioX;
m_RatioY = in_RatioY;
Init();
// m_IsRotRight = in_IsRotRight;
SetGravity(in_RatioX * BallSwap.GRAVITY, in_RatioY * BallSwap.GRAVITY);
}
//Init : Graphic
override public function GetOriBitmapData():BitmapData{
var bmd:BitmapData = s_BitmapData.clone();
var mtx:Matrix = new Matrix();
// if(0 < m_RatioX){mtx.rotate( 0); mtx.translate( 0*32, 0*32);}
if(m_RatioX < 0){mtx.rotate(Math.PI); mtx.translate( 1*32, 1*32);}
if(m_RatioY < 0){mtx.rotate(-Math.PI/2);mtx.translate( 0*32, 1*32);}
var ct:ColorTransform = new ColorTransform(0.3, 0.3, 0.3);
bmd.draw(s_BitmapData_Arrow, mtx, ct, BlendMode.ADD);
return bmd;
}
//Init : Collision
override public function CreateCircleDef():b2CircleDef{
var shapeDef:b2CircleDef;
{
shapeDef = super.CreateCircleDef();
//shapeDef.density = 0;//Fix
shapeDef.friction = 0;
}
return shapeDef;
}
//Update
override public function Update(in_DeltaTime:Number):void{
/*
var rot_vel:Number = BallSwap.IMAGE_to_PHYS(100);
m_Body.SetAngularVelocity(m_IsRotRight? rot_vel: -rot_vel);
//*/
}
}
//
class GameObject_Box extends GameObject
{
//==Var==
public var m_W:Number;
public var m_H:Number;
//==Function==
//Init
public function GameObject_Box(in_W:Number, in_H:Number, in_Ang:Number){
//Param
{
m_W = in_W;
m_H = in_H;
}
//グラフィック
{
//Anim
{
var bmd_ori:BitmapData = new BitmapData(in_W, in_H, true, 0xFF888888);
m_AnimList[0] = bmd_ori;
}
//m_Bitmap
{
m_Bitmap.x = -in_W/2;
m_Bitmap.y = -in_H/2;
SetAnimIndex(0);
}
}
//コリジョン
{
//Shape Def
var shapeDef:b2ShapeDef = CreateShapeDef();
//Body Def
var bodyDef:b2BodyDef;
{
bodyDef = new b2BodyDef();
bodyDef.position.Set(BallSwap.IMAGE_to_PHYS(this.x), BallSwap.IMAGE_to_PHYS(this.y));
//bodyDef.fixedRotation = true;
bodyDef.angle = in_Ang * Math.PI/180;
}
//Body
var body:b2Body;
{
body = BallSwap.Instance.m_Box2D_World.CreateBody(bodyDef);
body.CreateShape(shapeDef);
body.SetMassFromShapes();
body.m_userData = this;
}
m_Body = body;
SetGravity(0, BallSwap.GRAVITY);
}
}
//Init : Collision Param
public function CreateShapeDef():b2ShapeDef{
return CreateBoxDef();
}
public function CreateBoxDef():b2PolygonDef{
//Overrideして必要なものは変更する
var shapeDef:b2PolygonDef;
{
shapeDef = new b2PolygonDef();
shapeDef.SetAsBox(BallSwap.IMAGE_to_PHYS(m_W/2), BallSwap.IMAGE_to_PHYS(m_H/2));
shapeDef.density = 0;//fix
shapeDef.friction = 0;
shapeDef.restitution = 0.5;
}
return shapeDef;
}
}
//#Goal
class Goal extends GameObject_Ball
{
//==Var==
static public var s_BitmapData:BitmapData = new BitmapData(BallSwap.PANEL_LEN, BallSwap.PANEL_LEN, true, 0x00000000);
//==Function==
//Init
public function Goal(){
Init();
//Vanish Anim
{
var ct:ColorTransform = new ColorTransform();
for(var i:int = 0; i < ANIM_NUM; ++i){
var bmd:BitmapData = m_AnimList[i];
var alpha:Number = Math.max(1 - 2*i/ANIM_NUM, 0);
ct.alphaMultiplier = alpha;
bmd.colorTransform(bmd.rect, ct);
}
}
}
//Init : Graphic
override public function GetOriBitmapData():BitmapData{
return s_BitmapData;
}
//Init : Collision
override public function CreateCircleDef():b2CircleDef{
var shapeDef:b2CircleDef;
{
shapeDef = super.CreateCircleDef();
shapeDef.density = 0;//Fix
}
return shapeDef;
}
}
class b2Vec2_ForGravity extends b2Vec2
{
public function b2Vec2_ForGravity(x_:Number=0, y_:Number=0) : void {super(x_, y_)};
//物理エンジン内でのリセットを無効化することで、forceを重力相当として扱う
override public function SetZero() : void {}
}
class Util
{
//Lerp
static public function Lerp(in_Src:Number, in_Dst:Number, in_Ratio:Number):Number{
return (in_Src * (1 - in_Ratio)) + (in_Dst * in_Ratio);
}
}