試作:ショットで壁を撃ち抜くAct
試作:ショットで壁を撃ち抜くAct:2D
・DisplacementMapFilterで地形に干渉するアクションゲームの試作
・ねじ曲げ方については「DisplacementMapFilterで四分の一円 ( http://wonderfl.net/c/bzmh )」を参考にした
操作方法(画面を2回ほどクリックしないとキーボード操作できないかもしれません)
・十字キー
・移動&ジャンプ
・SPACE(半角で)
・ショット(地形に当たると地形をねじ曲げる)
/**
* 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/lmjM
*/
/*
試作:ショットで壁を撃ち抜くAct:2D
・DisplacementMapFilterで地形に干渉するアクションゲームの試作
・ねじ曲げ方については「DisplacementMapFilterで四分の一円 ( http://wonderfl.net/c/bzmh )」を参考にした
操作方法(画面を2回ほどクリックしないとキーボード操作できないかもしれません)
・十字キー
・移動&ジャンプ
・SPACE(半角で)
・ショット(地形に当たると地形をねじ曲げる)
*/
package
{
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.net.*;
import flash.text.*;
import flash.filters.*;
import flash.ui.*;
public class GameMain extends Sprite
{
//==Const==
//干渉半径
static public const DIS_RAD:int = 0x20;
//プレイヤーの初期位置
static public const PLAYER_INIT_X:int = 70;
static public const PLAYER_INIT_Y:int = 70;
//Utility
static public const POS_ZERO:Point = new Point(0,0);
//==Var==
//背景
public var m_BitmapData_View:BitmapData;
//破壊部分(背景を一度これにコピーして、Filterで破壊してから背景に書き戻す)
public var m_Bitmap_Destroy:Bitmap;
//コリジョン(背景を太く書き出して、プレイヤーのためのコリジョンとして扱う)
public var m_BitmapData_Collision:BitmapData;
//プレイヤー
public var m_Player:Player;
//==Function==
//Static Global Access
static private var m_Instance:GameMain;
static public function Instance():GameMain{return m_Instance;}
//Init
public function GameMain()
{
m_Instance = this;
addEventListener(Event.ADDED_TO_STAGE, Init);
}
public function Init(e:Event=null):void
{
var g:Graphics;
//Init Once
{
removeEventListener(Event.ADDED_TO_STAGE, init);
}
//コリジョン
{
m_BitmapData_Collision = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0xFFFFFFFF);
//debug
// addChild(new Bitmap(m_BitmapData_Collision));
}
//背景
{
//Create & Regist
{
m_BitmapData_View = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0xFFFFFF);
addChild(new Bitmap(m_BitmapData_View));
}
//Draw
{
var shape_bg:Shape = new Shape();
g = shape_bg.graphics;
g.clear();
g.lineStyle(3, 0x000000);
g.drawRect(50, 50, 200, 100);
g.drawRect(150, 250, 200, 100);
g.beginFill(0x000000, 1.0);
g.drawRect(50, 100, 50, 50);
g.drawRect(350, 100, 200, 100);
g.drawRect(0, 300, 50, 50);
g.drawRect(50, 400, 50, 50);
g.drawRect(250, 400, 250, 150);
g.endFill();
m_BitmapData_View.draw(shape_bg);
}
}
//破壊部分
{
//Create & Regist
{
m_Bitmap_Destroy = new Bitmap(new BitmapData(2*DIS_RAD, 2*DIS_RAD, true, 0x00000000));
}
//フィルター
{
//オフセットから色を計算
const calc_color:Function = function(in_GapX:int, in_GapY:int):uint{
if(in_GapX > 0){return 0x008080;}
var LenX:Number = DIS_RAD - Math.abs(in_GapX);
var LenY:Number = DIS_RAD - Math.abs(in_GapY);
LenY *= 1.5;
var Distance:Number = Math.sqrt(LenX*LenX + LenY*LenY);
var r:uint = 0x00;
var g:uint = 0x80 + LenX - Distance;
if(Distance > DIS_RAD){g = 0x80 + LenX - DIS_RAD;}
var b:uint = 0x80;// + in_GapY;
return (r << 16) | (g << 8) | (b << 0);
};
//オフセット値を格納したBitmap
var bmd_sampling:BitmapData = new BitmapData(2*DIS_RAD, 2*DIS_RAD, false, calc_color(0,0));
//歪めるための計算
for(var y:int = 0; y < 2*DIS_RAD; y++){
var GapY:int = DIS_RAD - y;
for(var x:int = 0; x < 2*DIS_RAD; x++){
var GapX:int = DIS_RAD - x;
bmd_sampling.setPixel(x, y, calc_color(GapX, GapY));
}
}
//実際にフィルターとして生成&セット
m_Bitmap_Destroy.filters = [
new DisplacementMapFilter(
bmd_sampling,//Sampling : Bitmap
null,//Sampling : Point
BitmapDataChannel.GREEN,//X
BitmapDataChannel.BLUE,//Y
0x100,//ScaleX
0x100,//ScaleY
DisplacementMapFilterMode.COLOR,//Mode
0x000000,//color
0//alpha
)
];
}
/*
//Debug
{
addChild(m_Bitmap_Destroy);
//初期化
Update_Destroy();
//マウスの移動のたびに更新
stage.addEventListener(MouseEvent.MOUSE_MOVE, Update_Destroy);
}
/*/
Update_Collision();
//*/
}
//プレイヤー
{
//Create & Regist
{
m_Player = new Player(PLAYER_INIT_X, PLAYER_INIT_Y);
addChild(m_Player);
}
}
}
/*
//破壊部分の更新:デバッグ表示確認用
static public var copy_rect:Rectangle = new Rectangle(0,0, 2*DIS_RAD,2*DIS_RAD);
public function Update_Destroy(e:Event=null):void{
var lx:int = mouseX-DIS_RAD;
var uy:int = mouseY-DIS_RAD;
//背景の該当部分をBitmapにコピー
copy_rect.x = lx;
copy_rect.y = uy;
m_Bitmap_Destroy.bitmapData.copyPixels(m_BitmapData_View, copy_rect, POS_ZERO);
m_Bitmap_Destroy.x = lx;
m_Bitmap_Destroy.y = uy;
//さらにコリジョンも更新
Update_Collision();
}
//*/
//コリジョンの更新
static public var mtx:Matrix = new Matrix();
public function Update_Collision(e:Event=null):void{
//背景を描画
m_BitmapData_Collision.copyPixels(m_BitmapData_View, m_BitmapData_View.rect, POS_ZERO);
//白い部分を透明にする
m_BitmapData_Collision.threshold(m_BitmapData_Collision, m_BitmapData_Collision.rect, POS_ZERO, ">", 0xFF/2, 0x00000000, 0x000000FF);
//さらにプレイヤーの厚みに合わせて相対的にコリジョン側の厚みを増やす(プレイヤーは1ドット分の大きさで済むように)
const glow_filter_x:GlowFilter = new GlowFilter(0x000000,1.0, 2*Player.RAD,0, 255);
const glow_filter_y:GlowFilter = new GlowFilter(0x000000,1.0, 0,2*Player.RAD, 255);
m_BitmapData_Collision.applyFilter(m_BitmapData_Collision, m_BitmapData_Collision.rect, POS_ZERO, glow_filter_x);
m_BitmapData_Collision.applyFilter(m_BitmapData_Collision, m_BitmapData_Collision.rect, POS_ZERO, glow_filter_y);
}
//コリジョンがあるか
public function IsCollision(in_X:int, in_Y:int):Boolean{
//範囲外チェック:ぶつかるようにする
{
if(in_X < 0){return true;}
if(in_X >= m_BitmapData_Collision.width){return true;}
if(in_Y < 0){return true;}
if(in_Y >= m_BitmapData_Collision.height){return true;}
}
//あとは普通にコリジョンを見る
var color:uint = m_BitmapData_Collision.getPixel32(in_X, in_Y);
var a:uint = (color >> 24) & 0xFF;
return a > 0xFF/2;//一定以上不透明だったらコリジョンとみなす
}
}
}
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.net.*;
import flash.text.*;
import flash.filters.*;
import flash.ui.*;
//プレイヤー
internal class Player extends Sprite{
//==Cost==
//#Size
static public const RAD:int = 8;
//#Input
static public var button_enum:int = 0;
static public const BUTTON_L:int = button_enum++;
static public const BUTTON_R:int = button_enum++;
static public const BUTTON_U:int = button_enum++;
static public const BUTTON_NUM:int = button_enum;
//#Move
static public const VEL_X:Number = 100.0;
static public const VEL_Y:Number = 300.0;
static public const ACC_Y:Number = 500.0;
//==Var==
//#Input
public var m_Input:Array = new Array(BUTTON_NUM);
//#Move
public var m_VY:Number = 0.0;
public var m_OnGround:Boolean = false;
//==Function==
//#Init
public function Player(in_X:int, in_Y:int){
//Pos
{
this.x = in_X;
this.y = in_Y;
}
//Init Later (for Using "stage" etc.)
addEventListener(Event.ADDED_TO_STAGE, Init );
}
public function Init(e:Event = null):void{
var i:int;
//Init Once Only
{
removeEventListener(Event.ADDED_TO_STAGE, Init );
}
//Create Graphic
{
var shape:Shape = new Shape();
var g:Graphics = shape.graphics;
g.lineStyle(2, 0xFF0000, 1.0);
g.beginFill(0xFFFFFF, 1.0);
g.drawCircle(0,0, RAD);
g.endFill();
addChild(shape);
}
//Input
{
//Init
for(i = 0; i < BUTTON_NUM; i++){
m_Input[i] = false;
}
//Listener
stage.addEventListener(KeyboardEvent.KEY_DOWN, KeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, KeyUp);
}
//Call Update
{
addEventListener(Event.ENTER_FRAME, Update);
}
}
//#Input
public function KeyDown(e:KeyboardEvent):void{
switch(e.keyCode){
case Keyboard.LEFT: m_Input[BUTTON_L] = true; this.scaleX = -1; break;
case Keyboard.RIGHT: m_Input[BUTTON_R] = true; this.scaleX = 1; break;
case Keyboard.UP: m_Input[BUTTON_U] = true; break;
case Keyboard.SPACE:
// GameMain.Instance().addChild(new Shot(this.x, this.y, 100 * this.scaleX));
GameMain.Instance().addChild(new Shot(this.x, this.y, 100));//左に発射した時の地形干渉を用意してないので右にだけショット
break;
}
}
public function KeyUp(e:KeyboardEvent):void{
switch(e.keyCode){
case Keyboard.LEFT: m_Input[BUTTON_L] = false; break;
case Keyboard.RIGHT: m_Input[BUTTON_R] = false; break;
case Keyboard.UP: m_Input[BUTTON_U] = false; break;
}
}
//#Update
public function Update(e:Event):void{
var DeltaTime:Number = 1.0 / 24.0;
//Move
{
//Calc MoveVal
var MoveX:int;
var MoveY:int;
{
//X
{
MoveX = 0;
if(m_Input[BUTTON_L]){MoveX -= VEL_X * DeltaTime;}
if(m_Input[BUTTON_R]){MoveX += VEL_X * DeltaTime;}
}
//Y
{
//ジャンプ
if(m_OnGround && m_Input[BUTTON_U]){
m_VY = -VEL_Y;
}
m_OnGround = false;//毎回着地判定を行うので、着地しなかった時のためにリセット
//重力
m_VY += ACC_Y * DeltaTime;
MoveY = m_VY * DeltaTime;
}
}
//移動アルゴリズム実行
const BaseOffset:int = 1;//浮く量
var Offset:int;
var TrgX:int;
var TrgY:int;
var i:int;
//Move : Up
{
TrgX = this.x;
Offset = (MoveY < 0)? BaseOffset-MoveY: BaseOffset;
for(i = 0; i < Offset; i++){
TrgY = this.y - 1;
if(GameMain.Instance().IsCollision(TrgX, TrgY)){
//天井にぶつかったので速度は0にする
m_VY = 0;
break;
}
this.y = TrgY;
}
}
//Move : Horz
{
TrgX = this.x;
TrgY = this.y;
for(i = 0; i != MoveX; ){
if(i < MoveX){
i++;
TrgX++;
}else{
i--;
TrgX--;
}
if(GameMain.Instance().IsCollision(TrgX, TrgY)){break;}
this.x = TrgX;
}
}
//Move : Down
{
TrgX = this.x;
Offset = (MoveY > 0)? BaseOffset+MoveY: BaseOffset;
for(i = 0; i < Offset; i++){
TrgY = this.y + 1;
if(GameMain.Instance().IsCollision(TrgX, TrgY)){
//接地したとみなす
m_OnGround = true;//ジャンプできるようにフラグオン
m_VY = 0;//速度リセット
break;
}
this.y = TrgY;
}
}
}
}
}
//ショット
internal class Shot extends Sprite{
//==Const==
static public const RAD:int = 4;
//==Var==
public var m_PosX:Number;
public var m_PosY:Number;
public var m_VX:Number;
//==Function==
public function Shot(in_X:int, in_Y:int, in_VX:Number){
//Param
{
this.x = m_PosX = in_X;
this.y = m_PosY = in_Y;
m_VX = in_VX;
}
//Graphic
{
var shape:Shape = new Shape();
var g:Graphics = shape.graphics;
g.lineStyle(1, 0x444444, 1.0);
g.beginFill(0x888888, 1.0);
g.drawCircle(0,0, RAD);
g.endFill();
addChild(shape);
}
//Update
{
addEventListener(Event.ENTER_FRAME, Update);
}
}
public function Update(e:Event=null):void{
const DeltaTime:Number = 1/24.0;
var TrgX:Number = m_PosX + m_VX * DeltaTime;
var MoveX:int = TrgX - this.x;
var LastX:int = this.x;
for(var i:int = 0; i != MoveX; ){
if(i < MoveX){
i++;
}else{
i--;
}
if(GameMain.Instance().IsCollision(this.x + i, this.y)){
//壁にぶつかった
//→まわりをねじ曲げて消滅
//まずは背景をコピー
var rect:Rectangle = new Rectangle(LastX - GameMain.DIS_RAD, this.y - GameMain.DIS_RAD, 2*GameMain.DIS_RAD, 2*GameMain.DIS_RAD);
const POS_ZERO:Point = new Point(0,0);
GameMain.Instance().m_Bitmap_Destroy.bitmapData.copyPixels(GameMain.Instance().m_BitmapData_View, rect, POS_ZERO);
//フィルターをかけたもので背景を上書き
var mtx:Matrix = new Matrix();
mtx.tx = rect.x;
mtx.ty = rect.y;
GameMain.Instance().m_BitmapData_View.draw(GameMain.Instance().m_Bitmap_Destroy, mtx);
//さらに白円で塗りつぶしてみる
var shape:Shape = new Shape();
var g:Graphics = shape.graphics;
g.lineStyle(0, 0x000000, 0.0);
g.beginFill(0xFFFFFF, 1.0);
g.drawCircle(LastX+32, this.y, 16);
g.endFill();
GameMain.Instance().m_BitmapData_View.draw(shape);
//背景に基づきコリジョンを再計算
GameMain.Instance().Update_Collision();
//Kill
parent.removeChild(this);
removeEventListener(Event.ENTER_FRAME, Update);
return;
}
LastX = this.x+i;
}
//壁にぶつからなかった
//→普通に移動
m_PosX = TrgX;
this.x = m_PosX;
//範囲外になったら死んでおく
if(this.x > stage.stageWidth){
parent.removeChild(this);
removeEventListener(Event.ENTER_FRAME, Update);
}
}
}