In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

ワンダフルクエスト【倉庫番】

=====================================================
* 
* ワンダフルクエストを倉庫番に。
* 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;
	}
}