ワンダフルクエスト【倉庫番】
=====================================================
*
* ワンダフルクエストを倉庫番に。
* RPGからパズルゲームへ。
* http://www.sokoban.jp/
*
* 0:ゴール
* 16:荷物
* 同じ数にしてね
*
* [遊び方]
* はじめに、マップをクリックして...
* ↑ , w : 上に移動
* ↓ , s : 下に移動
* ← , a : 左に移動
* → , d : 右に移動
* =====================================================
/**
* Copyright TNKHRYK ( http://wonderfl.net/user/TNKHRYK )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/9Dsm
*/
// forked from osamX's ワンダフルクエスト
// forked from nengafl's nengafl
/**=====================================================
*
* ワンダフルクエストを倉庫番に。
* RPGからパズルゲームへ。
* http://www.sokoban.jp/
*
* 0:ゴール
* 16:荷物
* 同じ数にしてね
*
* [遊び方]
* はじめに、マップをクリックして...
* ↑ , w : 上に移動
* ↓ , s : 下に移動
* ← , a : 左に移動
* → , d : 右に移動
* ===================================================== */
package
{
import flash.display.*;
import flash.events.*;
import flash.geom.Point;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
[SWF(width="465", height="465", frameRate="30", backgroundColor="0x000000")]
public class WonderflQuest extends Sprite
{
private const SIZE:Number = 465;//ステージの大きさ
private const SCALE:Number = 3; //勇者やフィールドの拡大率
private const SPEED:Number = 6; //勇者が歩くスピード FLDSIZEの約数にしてください
private const MAPSIZE:uint = 7;//マップの横・縦のマスの個数
private const FLDSIZE:uint = 48;//フィールド(マップ上の1マス)の横・縦のドット数
private var yuusha:Yuusha; //勇者
private var yuushaPos:Point; //勇者のマップ上の座標
private var map:Sprite; //マップ本体 これを動かして勇者が移動しているように見せる
private var bMapData:Array = [];//フィールドが障害物か否かを記憶
private var frameCount:Number = 0; //onEnterFrameで使用
private var keyFlags:Array = [false, false, false, false]; //下上左右のキーが押されているか
private var walkDirection:int = 4; //歩いていく方向 (0~3:下上左右 4:止)
private var loaded:int = 0; //読み込み完了した画像の個数
private var isInit:Boolean = false; //初期化されているか onEnterFrameで使用
private var prgSpr:Sprite; //ロード画面表示用
private var lMapData:Array = [];//フィールドが荷物か否かを記憶
private var gMapData:Array = [];//フィールドがゴールか否かを記憶
private var luggDirection:int = 4;//荷物が動く方向
private var luggageArray:Array = [];//荷物保存
private var targetLuggageNum:int = 0;//押している荷物
/**-----------------------------------------------------
* マップの1マス(フィールド)のリストです。
* ここをいじると好きな画像をマップ上に貼ることができます。
* 画像のサイズは、基本的に16*16ピクセルです。
* 形式はjpeg,gif,pngのどれかにしてください。
* Twitterのアイコン画像取得は、こちらのAPIを使わせてもらってます。
* http://usericons.relucks.org/
* ----------------------------------------------------- */
private const fieldList:Array = [
new Field("http://flash-scope.com/wonderfl/WonderflQuest/map/map0.png", false), //[ 0]: 芝生
new Field("http://flash-scope.com/wonderfl/WonderflQuest/map/map1.png", false), //[ 1]: 砂
new Field("http://flash-scope.com/wonderfl/WonderflQuest/map/map2.png", false), //[ 2]: 石畳
new Field("http://flash-scope.com/wonderfl/WonderflQuest/map/map3.png", false), //[ 3]: フローリング
new Field("http://flash-scope.com/wonderfl/WonderflQuest/map/map4.png", false), //[ 4]: 橋(縦)
new Field("http://flash-scope.com/wonderfl/WonderflQuest/map/map5.png", false), //[ 5]: 橋(横)
new Field("http://flash-scope.com/wonderfl/WonderflQuest/map/map6.png", true), //[ 6]: 木(小)
new Field("http://flash-scope.com/wonderfl/WonderflQuest/map/map7.png", true), //[ 7]: 木(大)
new Field("http://flash-scope.com/wonderfl/WonderflQuest/map/map8.png", true), //[ 8]: サボテン
new Field("http://flash-scope.com/wonderfl/WonderflQuest/map/map9.png", true), //[ 9]: 水
new Field("http://flash-scope.com/wonderfl/WonderflQuest/map/map10.png", true), //[10]: 壁(石)
new Field("http://flash-scope.com/wonderfl/WonderflQuest/map/map11.png", true), //[11]: 壁(木)
new Field("http://flash-scope.com/wonderfl/WonderflQuest/map/map12.png", true), //[12]: 壁(武器屋)
new Field("http://flash-scope.com/wonderfl/WonderflQuest/map/map13.png", true), //[13]: 壁(防具屋)
new Field("http://flash-scope.com/wonderfl/WonderflQuest/map/map14.png", true), //[14]: 壁(宿屋)
new Field("http://flash-scope.com/wonderfl/WonderflQuest/map/map15.png", true), //[15]: 壺
new Field("http://flash-scope.com/wonderfl/WonderflQuest/map/map3.png", false),//[16]: 荷物(荷物おく普通の床に)
new Field("http://flash-scope.com/wonderfl/WonderflQuest/map/map17.png", true), //[17]: 石像
new Field("http://flash-scope.com/wonderfl/WonderflQuest/map/map18.png", true), //[18]: 真っ暗
new Field("http://usericons.relucks.org/twitter/TNKHRYK", true) //[19]: Twitterアイコン
];
private var LuggageImage:String = "http://flash-scope.com/wonderfl/WonderflQuest/map/map16.png";//荷物
/**-----------------------------------------------------
* マップのデータ(ここが木で、あそこが芝生で...ってやつ)が入ってます。
* ここをいじると、マップが変わります。上のfieldListのコメント参照。
* ----------------------------------------------------- */
//16:荷物(タンス)
// 0:ゴール(芝生)
private const mapData:Array =
[[18,11,11,18,11,18,18],
[18, 3, 3,11, 0,11,18],
[18, 3,16,16,16, 0,18],
[18, 3, 3,16, 3, 3,18],
[18, 3, 3, 3, 3, 3,18],
[18, 3, 3,18, 0, 0,18],
[11,11,11,11,11,11,11]];
/**-----------------------------------------------------
* コンストラクタ。 ここが最初に処理されます。
* ----------------------------------------------------- */
public function WonderflQuest():void
{
prgSpr = new Sprite();//ロード画面
addChild(prgSpr);
addEventListener(Event.ENTER_FRAME, onEnterFrame);//イベントリスナーの登録
createMap(); //マップを作る
yuusha = new Yuusha(); //勇者を作る
yuusha.scaleX = yuusha.scaleY = SCALE; //勇者を拡大表示
yuusha.x = yuusha.y = (SIZE-FLDSIZE)/2; //中央に配置
//yuushaPos = new Point(8 * FLDSIZE, 8 * FLDSIZE);//勇者初期位置
yuushaPos = new Point(1 * FLDSIZE, 5 * FLDSIZE);//勇者初期位置
moveMap(yuushaPos); //マップ移動
}
/**-----------------------------------------------------
* 毎フレームの処理。
* ----------------------------------------------------- */
private function onEnterFrame(event:Event):void {
if (loaded < MAPSIZE * MAPSIZE) { //フィールドの画像読み込み未完了なら
drawPrg();
return; //これ以下を処理しない
}
//画像読み込み完了後 1回だけ処理
if (!isInit) {
removeChild(prgSpr);//ロード画面非表示
prgSpr = null;
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); //イベントリスナーの登録
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp); //イベントリスナーの登録
addChild(map); //マップ表示
addChild(yuusha); //勇者表示
//addChild(luggage); //荷物表示
isInit = true;
}
//15フレーム毎に処理する
if (frameCount++ > 10) {
frameCount = 0;
yuusha.walk();
}
//マップ&荷物(勇者)をどの方向に動かすか判定
if (yuushaPos.x % FLDSIZE == 0 && yuushaPos.y % FLDSIZE == 0) {
checkClear();
var mapPosX:int = int(yuushaPos.x / FLDSIZE), mapPosY:int = int(yuushaPos.y / FLDSIZE);
walkDirection = 4; //止まる
luggDirection = 4;
targetLuggageNum = 0;
switch(true) {
case keyFlags[0]: //下
if (yuushaPos.y < (MAPSIZE - 1) * FLDSIZE && !bMapData[mapPosY + 1][mapPosX]) walkDirection = 0;
if (lMapData[mapPosY + 1][mapPosX]) {
if(yuushaPos.y < (MAPSIZE - 2) * FLDSIZE && !bMapData[mapPosY+2][mapPosX] && !lMapData[mapPosY+2][mapPosX]){
luggDirection = 0;
targetLuggageNum = lMapData[mapPosY + 1][mapPosX];
lMapData[mapPosY + 1][mapPosX] = null;
lMapData[mapPosY + 2][mapPosX] = targetLuggageNum;
}else {
walkDirection = 4;
}
}
yuusha.changeDirection(0);
break;
case keyFlags[1]: //上
if (yuushaPos.y > 0 && !bMapData[mapPosY - 1][mapPosX]) walkDirection = 1;
if (lMapData[mapPosY - 1][mapPosX]) {
if(yuushaPos.y > 1 * FLDSIZE && !bMapData[mapPosY - 2][mapPosX] && !lMapData[mapPosY-2][mapPosX]){
luggDirection = 1;
targetLuggageNum = lMapData[mapPosY - 1][mapPosX];
lMapData[mapPosY - 1][mapPosX] = null;
lMapData[mapPosY - 2][mapPosX] = targetLuggageNum;
}else {
walkDirection = 4;
}
}
yuusha.changeDirection(1);
break;
case keyFlags[2]: //左
if (yuushaPos.x > 0 && !bMapData[mapPosY][mapPosX - 1]) walkDirection = 2;
if (lMapData[mapPosY][mapPosX - 1]) {
if(yuushaPos.x > 1 && !bMapData[mapPosY][mapPosX - 2] && !lMapData[mapPosY][mapPosX-2]){
luggDirection = 2;
targetLuggageNum = lMapData[mapPosY][mapPosX - 1];
lMapData[mapPosY][mapPosX - 1] = null;
lMapData[mapPosY][mapPosX - 2] = targetLuggageNum;
}else {
walkDirection = 4;
}
}
yuusha.changeDirection(2);
break;
case keyFlags[3]: //右
if (yuushaPos.x < (MAPSIZE - 1) * FLDSIZE && !bMapData[mapPosY][mapPosX + 1]) walkDirection = 3;
if (lMapData[mapPosY][mapPosX + 1]) {
if(yuushaPos.x < (MAPSIZE - 2) * FLDSIZE && !bMapData[mapPosY][mapPosX + 2] && !lMapData[mapPosY][mapPosX+2]){
luggDirection = 3;
targetLuggageNum = lMapData[mapPosY][mapPosX + 1];
lMapData[mapPosY][mapPosX + 1] = null;
lMapData[mapPosY][mapPosX + 2] = targetLuggageNum;
}else {
walkDirection = 4;
}
}
yuusha.changeDirection(3);
break;
}
}
//次のマスまで自動的に勇者を歩かせる
switch(walkDirection) {
case 0:
yuushaPos.y += SPEED;
break;
case 1:
yuushaPos.y -= SPEED;
break;
case 2:
yuushaPos.x -= SPEED;
break;
case 3:
yuushaPos.x += SPEED;
break;
}
if (walkDirection < 4) moveMap(yuushaPos);
//荷物を動かす
switch(luggDirection) {
case 0:
luggageArray[targetLuggageNum].y += SPEED;
break;
case 1:
luggageArray[targetLuggageNum].y -= SPEED;
break;
case 2:
luggageArray[targetLuggageNum].x -= SPEED;
break;
case 3:
luggageArray[targetLuggageNum].x += SPEED;
break;
}
}
/**-----------------------------------------------------
* キーボードのキーが押された時の処理。
* ----------------------------------------------------- */
private function onKeyDown(event:KeyboardEvent):void {
switch(event.keyCode) {
case 40: case 83: //↓ s
keyFlags[0] = true;
}
switch(event.keyCode) {
case 38: case 87: //↑ w
keyFlags[1] = true;
}
switch(event.keyCode) {
case 37: case 65: //← a
keyFlags[2] = true;
}
switch(event.keyCode) {
case 39: case 68: //→ d
keyFlags[3] = true;
}
}
/**-----------------------------------------------------
* キーボードのキーが離された時の処理。
* ----------------------------------------------------- */
private function onKeyUp(event:KeyboardEvent):void {
switch(event.keyCode) {
case 40: case 83: //↓ s
keyFlags[0] = false;
}
switch(event.keyCode) {
case 38: case 87: //↑ w
keyFlags[1] = false;
}
switch(event.keyCode) {
case 37: case 65: //← a
keyFlags[2] = false;
}
switch(event.keyCode) {
case 39: case 68: //→ d
keyFlags[3] = false;
}
}
/**-----------------------------------------------------
* クリアー判定
* ----------------------------------------------------- */
private function checkClear():void {
for (var j:uint = 0; j < MAPSIZE; j++) {
for (var i:uint = 0; i < MAPSIZE; i++) {
if ( int(lMapData[j][i]>=1) ^ gMapData[j][i]) {
return;
}
}
}
//全ての荷物がゴールに
gameClear();
}
private function gameClear():void {
removeEventListener(Event.ENTER_FRAME, onEnterFrame)
stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
stage.removeEventListener(KeyboardEvent.KEY_UP, onKeyUp);
var messageField:TextField;
messageField = new TextField();
stage.addChild(messageField);
messageField.autoSize = "center"
messageField.x = 0;
messageField.y = 200;
messageField.width = 465;
var format:TextFormat = new TextFormat();
format.size = 44;
format.color = 0xFFFFFF;
format.bold = true;
messageField.text = "Game Clear!!";
messageField.setTextFormat(format);
}
/**-----------------------------------------------------
* マップを作ります。
* この実装方法は良くないです。遅いし、何回も同じ画像をロードしてます。
* 画像が別ドメインにある時に、crossdomain.xmlがなくても大丈夫なようにしています。
* ----------------------------------------------------- */
private function createMap():void {
map = new Sprite();
for (var k:uint = 0; k < MAPSIZE; k++) {
bMapData[k] = []; //bMapDataを2次元配列にする
lMapData[k] = []; //lMapDataを2次元配列にする
gMapData[k] = []; //gMapDataを2次元配列にする
}
var count:int = 1;
for (var j:uint = 0; j < MAPSIZE; j++) {
for (var i:uint = 0; i < MAPSIZE; i++) {
var loader:Loader = new Loader();
var field:Field = fieldList[mapData[j][i]];
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e:Event):void{loaded++;}); //ロード完了したらloadedをカウントアップ
loader.load(new URLRequest(field.url), new LoaderContext(true));
loader.x = FLDSIZE * i;
loader.y = FLDSIZE * j;
loader.scaleX = loader.scaleY = SCALE;
if (mapData[j][i] == 19) loader.scaleX = loader.scaleY = FLDSIZE / 73; //Twitterのアイコンの時
map.addChild(loader);
bMapData[j][i] = field.isObstacle;
//荷物&ゴール
if (mapData[j][i] == 16) {
var l_loader:Loader = new Loader();
l_loader.load(new URLRequest(LuggageImage), new LoaderContext(true));
l_loader.x = FLDSIZE * i;
l_loader.y = FLDSIZE * j;
l_loader.scaleX = l_loader.scaleY = SCALE;
luggageArray[count] = l_loader;
map.addChild(l_loader);
lMapData[j][i] = count;
count++;
}else {
//荷物はないよ
lMapData[j][i] = null;
}
if (mapData[j][i] == 0) {
gMapData[j][i] = true;
}else {
gMapData[j][i] = false;
}
}
}
//荷物深度変更
var lastIndex:int = map.numChildren - 1;
for (i = 1; i < count; i++) {
map.setChildIndex(luggageArray[i], lastIndex);
}
}
/**-----------------------------------------------------
* マップの座標計算。
* ----------------------------------------------------- */
private function moveMap(pos:Point):void {
map.x = (SIZE-FLDSIZE)/2 - yuushaPos.x;
map.y = (SIZE-FLDSIZE)/2 - yuushaPos.y;
}
/**-----------------------------------------------------
* ロード画面を描く。
* ----------------------------------------------------- */
private function drawPrg():void {
var side:Number = SIZE / MAPSIZE,
yy:int = int(loaded / MAPSIZE),
xx:int = loaded - yy * MAPSIZE,
max:int = MAPSIZE;
prgSpr.graphics.clear();
prgSpr.graphics.beginFill(0xFFFFFF);
prgSpr.graphics.drawRect(0, 0, SIZE, yy * side);
if(yy%2)prgSpr.graphics.drawRect((MAPSIZE-xx)*side, yy*side, SIZE, side);
else prgSpr.graphics.drawRect(0, yy*side, xx*side, side);
prgSpr.graphics.endFill();
}
}
}
//import fl.controls.dataGridClasses.DataGridCellEditor;
import flash.display.Sprite;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.system.LoaderContext;
/**-----------------------------------------------------
* 勇者クラスです。勇者を作ったり、足踏させたり、向きを変えたりします。
* ----------------------------------------------------- */
class Yuusha extends Sprite {
public var direction:int = 0; //向き (0:前 1:後 2:左 3:右)
private var walkFlag:Boolean = true;//足踏み用
private var yuushaImages:Array = [];//勇者の画像集
/**-----------------------------------------------------
* コンストラクタ。
* ----------------------------------------------------- */
public function Yuusha():void {
for (var i:uint = 0; i < 8; i++) {
var loader:Loader = new Loader();
loader.load(new URLRequest(ImageURL[i]), new LoaderContext(true));
yuushaImages.push(loader);
if(i) yuushaImages[i].visible = false;
addChild(yuushaImages[i]);
}
}
/**-----------------------------------------------------
* 勇者の画像のURLリスト
* ----------------------------------------------------- */
private const ImageURL:Array = [
"http://flash-scope.com/wonderfl/WonderflQuest/yuusha/yuushaF1.png", //前向き1
"http://flash-scope.com/wonderfl/WonderflQuest/yuusha/yuushaF2.png", //前向き2
"http://flash-scope.com/wonderfl/WonderflQuest/yuusha/yuushaB1.png", //後ろ向き1
"http://flash-scope.com/wonderfl/WonderflQuest/yuusha/yuushaB2.png", //後ろ向き2
"http://flash-scope.com/wonderfl/WonderflQuest/yuusha/yuushaL1.png", //左向き1
"http://flash-scope.com/wonderfl/WonderflQuest/yuusha/yuushaL2.png", //左向き2
"http://flash-scope.com/wonderfl/WonderflQuest/yuusha/yuushaR1.png", //右向き1
"http://flash-scope.com/wonderfl/WonderflQuest/yuusha/yuushaR2.png" //右向き2
];
/**-----------------------------------------------------
* 足踏みさせます。
* ----------------------------------------------------- */
public function walk():void {
walkFlag = !walkFlag;
for (var i:uint = 0; i < 8; i++) {
if (i == 2*direction+int(walkFlag)) yuushaImages[i].visible = true;
else yuushaImages[i].visible = false;
}
}
/**-----------------------------------------------------
* 向きを変更します。
* numは勇者の向きを表します。(0~3)
* ----------------------------------------------------- */
public function changeDirection(num:int):void {
direction = num;
for (var i:uint = 0; i < 8; i++) {
if (i == 2*direction+int(walkFlag)) yuushaImages[i].visible = true;
else yuushaImages[i].visible = false;
}
}
}
/**-----------------------------------------------------
* Fieldクラスです。画像のURLと、そのフィールドが障害物か否かを保存します。
* ----------------------------------------------------- */
class Field {
public var url:String; //画像のURL
public var isObstacle:Boolean; //障害物か否か (true:障害物 false:障害物じゃない(歩ける))
public function Field(s:String, b:Boolean = false):void {
url = s;
isObstacle = b;
}
}