法線マップ×パズル:その1
白い玉を白いエリア(左)へ
黒い玉を黒いエリア(右)へ
マウスで線を描いて導く。
/**
* 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/tXS7
*/
/*
白い玉を白いエリア(左)へ
黒い玉を黒いエリア(右)へ
マウスで線を描いて導く。
*/
package {
import flash.display.Sprite;
import flash.events.*;
public class FlashTest extends Sprite {
public function FlashTest() {
// write as3 code here..
addChild(new GameMain());
}
}
}
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.net.*;
import flash.text.*;
import flash.filters.*;
internal class GameMain extends Sprite{
//==Const==
//Constもどき(Stageの幅から再計算する)
static public var GOAL_W:int = 100;
//==Var==
//法線マップ保持用(そしてそのまま描画)
public var m_BitmapData:BitmapData;
//==Func==
public function GameMain(){
//Init Later (for Using "stage" etc.)
addEventListener(Event.ADDED_TO_STAGE, Init);
}
public function Init(e:Event = null):void{
//Init Once Only
{
removeEventListener(Event.ADDED_TO_STAGE, Init);
}
var W:int = stage.stageWidth;
var H:int = stage.stageHeight;
//Init Param
{
GOAL_W = W * 1/5;
}
//Create Bitmap
{
m_BitmapData = new BitmapData(W, H, false, Vector_to_Color(new Vector3D(0,0,1)));
addChild(new Bitmap(m_BitmapData));
}
//Create Goal
{
var bmp:Bitmap;
//White : Left
{
bmp = new Bitmap(new BitmapData(GOAL_W, H, false, 0xFFFFFF));
bmp.x = 0;
addChild(bmp);
}
//Black : Right
{
bmp = new Bitmap(new BitmapData(GOAL_W, H, false, 0x000000));
bmp.x = W - GOAL_W;
addChild(bmp);
}
}
//Draw Nrm By Mouse
{
var draw_flag:Boolean = false;
var mouseX_Old:int = 0;
var mouseY_Old:int = 0;
var shape:Shape = new Shape();
var g:Graphics = shape.graphics;
{
shape.filters = [
new BlurFilter()
];
}
//Draw
var draw:Function = function(in_X:int, in_Y:int, in_OldX:int, in_OldY:int):void{
//Nrm
var vec:Vector3D;
{
const BASE_Z:Number = 10.0;
vec = new Vector3D(
in_X - in_OldX,
-(in_Y - in_OldY),
BASE_Z
);
vec.normalize();
}
//Nrm => Color
var nrm_color:uint;
{
nrm_color = Vector_to_Color(vec);
}
//draw circle
{
const RAD:uint = 20;
g.clear();
g.lineStyle(RAD, nrm_color, 1.0);
g.moveTo(in_OldX, in_OldY);
g.lineTo(in_X, in_Y);
m_BitmapData.draw(shape);
}
};
//Down
addEventListener(
MouseEvent.MOUSE_DOWN,
function(e:MouseEvent):void{
//Flag On
{
draw_flag = true;
}
//Mouse Pos
{
mouseX_Old = mouseX;
mouseY_Old = mouseY;
}
//Draw Nrm
{
draw(mouseX, mouseY, mouseX_Old, mouseY_Old);
}
}
);
//Move
stage.addEventListener(
MouseEvent.MOUSE_MOVE,
function(e:MouseEvent):void{
//Check
{
if(! draw_flag){
return;
}
}
//Draw Nrm
{
draw(mouseX, mouseY, mouseX_Old, mouseY_Old);
}
//Mouse Pos
{
mouseX_Old = mouseX;
mouseY_Old = mouseY;
}
}
);
//Up
stage.addEventListener(
MouseEvent.MOUSE_UP,
function(e:MouseEvent):void{
//Flag Off
{
draw_flag = false;
}
}
);
}
//Create Obj
{
/*
const Num:int = 100;
for(var i:int = 0; i < Num; i++){
addChild(new PointObject(PointObject.TYPE_WHITE, W*Math.random(), H*Math.random(), m_BitmapData));
}
//*/
//*
const Num:int = 10;
const line_w:int = W*1/5;
var vec:Vector3D = new Vector3D(0,0.5,1);
vec.normalize();
var rect:Rectangle = new Rectangle(0,0, W/2, H);
var i:int;
var line_x:int;
//Black
{
line_x = W * 2/5;
//Side
rect.x = 0;
m_BitmapData.fillRect(rect, Vector_to_Color(vec));
//Obj
for(i = 0; i < Num; i++){
addChild(new PointObject(PointObject.TYPE_BLACK, line_x, H * i/Num, m_BitmapData));
}
}
//White
{
line_x = W * 3/5;
//Line
rect.x = W/2;
vec.y = -vec.y;//方向反転
m_BitmapData.fillRect(rect, Vector_to_Color(vec));
//Obj
for(i = 0; i < Num; i++){
addChild(new PointObject(PointObject.TYPE_WHITE, line_x, H * i/Num, m_BitmapData));
}
}
//*/
}
//Call "Update"
{
addEventListener(Event.ENTER_FRAME, Update);
}
}
public function Update(e:Event):void{
}
//Utility
public function Vector_to_Color(in_Nrm:Vector3D):uint{
var color:uint;
{//初期状態で静止可能にするため、0xFE/2が速度0の時の値になるように変更
var r:uint = 0xFE * (0.5 + 0.5*in_Nrm.x);
var g:uint = 0xFE * (0.5 + 0.5*in_Nrm.y);
var b:uint = 0xFE * (0.5 + 0.5*in_Nrm.z);
color = (r << 16) | (g << 8) | (b << 0);
}
return color;
}
}
class PointObject extends Sprite
{
//static var
//未ゴールのObj数
static public var m_ObjCount:int = 0;
//const
static public const RAD:int = 5;
static public const VEL:int = 10;
static public var TypeIter:int = 0;
static public const TYPE_WHITE:int = TypeIter++;
static public const TYPE_BLACK:int = TypeIter++;
static public const COLOR:Array = [
0xFFFFFF,//TYPE_WHITE
0x000000 //TYPE_BLACK
];
//var
public var m_BitmapData:BitmapData;
public var m_Vel:Vector3D = new Vector3D(0, 0);
public var m_Type:int = TYPE_WHITE;
//Init
public function PointObject(in_Type:int, in_X:int, in_Y:int, in_BitmapData:BitmapData){
//Count++
{
m_ObjCount++;
}
//Type
{
m_Type = in_Type;
}
//Pos
{
this.x = in_X;
this.y = in_Y;
}
//Nrm
{
m_BitmapData = in_BitmapData;
}
//Graphic
{
var shape:Shape = new Shape();
{//Draw Circle
var g:Graphics = shape.graphics;
g.beginFill(COLOR[m_Type], 1.0);
g.drawCircle(0, 0, RAD);
}
{//Add Filter
shape.filters = [
new BlurFilter(),
new GlowFilter(COLOR[m_Type])
];
}
addChild(shape);
}
//Call "Update"
{
addEventListener(Event.ENTER_FRAME, Update);
}
}
public function Update(e:Event=null):void{
//法線マップから得られる速度
var NrmVel:Vector3D;
{
NrmVel = Color_to_Vector(m_BitmapData.getPixel(this.x, this.y));
NrmVel.scaleBy(VEL);
}
//現在の速度とマージ
{
// var ratio:Number = 0.1;
var ratio:Number = 1 - NrmVel.z/VEL;//速度指定がないようなら今の速度を維持する
m_Vel.x = lerp(m_Vel.x, NrmVel.x, ratio);
m_Vel.y = lerp(m_Vel.y, NrmVel.y, ratio);
}
//Move
{
this.x += m_Vel.x;
this.y += m_Vel.y;
if(this.x < 0){this.x += m_BitmapData.width;}
if(this.x >= m_BitmapData.width){this.x -= m_BitmapData.width;}
if(this.y < 0){this.y += m_BitmapData.height;}
if(this.y >= m_BitmapData.height){this.y -= m_BitmapData.height;}
}
//Check Goal
{
var GoodEndFlag:Boolean = false;
var BadEndFlag:Boolean = false;
{
//判定はGameMain側でやるべき気がするが
if(this.x < GameMain.GOAL_W){
switch(m_Type){
case TYPE_WHITE:
//White : Left
GoodEndFlag = true;
break;
case TYPE_BLACK:
//Black : Right
BadEndFlag = true;//逆サイドに入ってしまった
break;
}
}
if(this.x > stage.stageWidth - GameMain.GOAL_W){
switch(m_Type){
case TYPE_WHITE:
//White : Left
BadEndFlag = true;//逆サイドに入ってしまった
break;
case TYPE_BLACK:
//Black : Right
GoodEndFlag = true;
break;
}
}
}
if(GoodEndFlag){//ゴールに入った
//Kill(相当)
{
parent.removeChild(this);
removeEventListener(Event.ENTER_FRAME, Update);
}
//Count--
{
m_ObjCount--;
if(m_ObjCount == 0){
//全てOBJがゴールしたらクリア処理
//めんどうだからもらったBitmapDataにらくがきしてしらせちゃえー
var shape:Shape = new Shape();
var g:Graphics = shape.graphics;
g.lineStyle(10, 0xFFFFFF, 1.0);
g.drawCircle(m_BitmapData.width/2, m_BitmapData.height/2, 100);
m_BitmapData.draw(shape);
}
}
}else{
if(BadEndFlag){//逆サイドに入ってしまった
//めんどうなのでUpdateしないだけにする
removeEventListener(Event.ENTER_FRAME, Update);
}
}
}
}
//Utility
public function Color_to_Vector(in_Color:uint):Vector3D{
var dir:Vector3D;
{
dir = new Vector3D(
2 * ((in_Color >> 16) & 0xFF) / 254.0 - 1,
-(2 * ((in_Color >> 8) & 0xFF) / 254.0 - 1),
2 * ((in_Color >> 0) & 0xFF) / 254.0 - 1
);
}
return dir;
}
public function lerp(in_Src:Number, in_Dst:Number, in_Ratio:Number):Number{
return (in_Src * (1 - in_Ratio)) + (in_Dst * in_Ratio);
}
}