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

ワンダフルクエスト用マップエディタ

ワンダフルクエスト用のマップエディタを作成しました。
* http://wonderfl.net/code/e3ad9058e4ee2e00d7ff7a40e806e7ed82fdb0ef
* 
* ワンダフルクエストのmapData(80行目あたり)の値を、
* exportで出力したテキストで置き換えることで簡単にマップを変更できます。
* 
*
* 作成するにあたり「外部画像をビットマップ化する」はかなり参考になりました。
* http://wonderfl.net/code/5c164cb968b9883d1eee01b236c5206956e57545

---------------------------------------------------------------------------------------
* マップエディタを作成できます。
* ---------------------------------------------------------------------------------------
* [操作方法]
* 操作はマウスのみです。
* ---------------------------------------------------------------------------------------
* [マニュアル]
* ・右下のマップチップのリストから、クリックでマップチップを選択できます。
* ・選択中のマップチップは右上の枠内に表示されます。
* ・左上のマップをクリックすると、選択中のマップチップを配置できます。
*  (ドラッグ操作で、連続で配置することもできます)
* ・マップが画面内に収まらない大きさなら上下左右のスライダーでスライドできます。
* 
* ・exportボタンで現在のマップをテキストフィールドに出力することができます。
* ・importボタンは逆にテキストフィールドのテキストを読み込んでマップに反映させます。
* ---------------------------------------------------------------------------------------
* [いじりどころ]
* MapContextクラスをいじると、
* マップ
/**
 * Copyright o8que ( http://wonderfl.net/user/o8que )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/3okH
 */

// forked from o8que's ドット絵エディタ(マップエディタメーカー)
// forked from nengafl's nengafl
/*
 * ワンダフルクエスト用のマップエディタを作成しました。
 * http://wonderfl.net/code/e3ad9058e4ee2e00d7ff7a40e806e7ed82fdb0ef
 * 
 * ワンダフルクエストのmapData(80行目あたり)の値を、
 * exportで出力したテキストで置き換えることで簡単にマップを変更できます。
 * 
 *
 * 作成するにあたり「外部画像をビットマップ化する」はかなり参考になりました。
 * http://wonderfl.net/code/5c164cb968b9883d1eee01b236c5206956e57545
 */
/* ---------------------------------------------------------------------------------------
 * マップエディタを作成できます。
 * ---------------------------------------------------------------------------------------
 * [操作方法]
 * 操作はマウスのみです。
 * ---------------------------------------------------------------------------------------
 * [マニュアル]
 * ・右下のマップチップのリストから、クリックでマップチップを選択できます。
 * ・選択中のマップチップは右上の枠内に表示されます。
 * ・左上のマップをクリックすると、選択中のマップチップを配置できます。
 *  (ドラッグ操作で、連続で配置することもできます)
 * ・マップが画面内に収まらない大きさなら上下左右のスライダーでスライドできます。
 * 
 * ・exportボタンで現在のマップをテキストフィールドに出力することができます。
 * ・importボタンは逆にテキストフィールドのテキストを読み込んでマップに反映させます。
 * ---------------------------------------------------------------------------------------
 * [いじりどころ]
 * MapContextクラスをいじると、
 * マップのサイズを変更したり、他のマップチップ画像を読み込んだり、
 * 他のテキスト形式での入出力が可能になります。
 * ---------------------------------------------------------------------------------------
 * 
 * サンプルとして、シンプルなドット絵エディタっぽい感じにしてます。
 * 
 * [ビギナー向け(?)いじりどころ]
 * ・MapContextのGRID_SIZE, GRID_COLS, GRID_ROWS(293~295行目)の値をいじると、
 *  キャンバスのサイズを変更できます。
 * ・MapContext.load()内の変数sample(310行目)をいじると、パレットの色を追加・変更できます。
 * ・MapContext.DEFAULT_MAPDATA(296行目)の値を、exportで出力したテキストで置き換えると、
 *  自分が作ったドット絵を初期の配置にすることができます。
 * 
 */

package {
	import com.bit101.components.HSlider;
	import com.bit101.components.PushButton;
	import com.bit101.components.Text;
	import com.bit101.components.VSlider;
	import flash.display.DisplayObject;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	
	[SWF(frameRate=10)]
	public class LevelEditor extends Sprite {
		private var _selectedChipType:int;		// 選択中のマップチップの種類を保持する
		private var _isMouseDownOnMap:Boolean;	// (マップ上で)マウス左ボタンが押されているか
		private var _mapModel:Array;			// マップモデル
		
		// 各コンポーネントの参照
		private var _map:Sprite;
		private var _mapScrollTop:HSlider;
		private var _mapScrollBottom:HSlider;
		private var _mapScrollLeft:VSlider;
		private var _mapScrollRight:VSlider;
		
		private var _IOTextField:Text;
		private var _importButton:PushButton;
		private var _exportButton:PushButton;
		
		private var _selectedChip:MapChip;
		private var _chipList:Sprite;
		private var _chipListSlider:VSlider;
		
		public function LevelEditor() {
			graphics.beginFill(0x000000);
			graphics.drawRect(0, 0, 465, 465);
			graphics.endFill();
			
			MapContext.instance.addEventListener(Event.COMPLETE, initialize);
			MapContext.instance.load();
		}
		
		private function initialize(e:Event):void {
			MapContext.instance.removeEventListener(Event.COMPLETE, initialize);
			
			initializeData();
			initializeMap();
			initializeSelectedChip();
			initializeChipList();
			initializeComponents();
			
			MapContext.instance.setReference(_mapModel, _IOTextField);
		}
		
		private function initializeData():void {
			_selectedChipType = 0;
			_isMouseDownOnMap = false;
		}
		
		// マップを作成する
		private function initializeMap():void {
			_map = new Sprite();
			_mapModel = [];
			for (var row:int = 0; row < MapContext.GRID_ROWS; row++) {
				_mapModel[row] = [];
				for (var col:int = 0; col < MapContext.GRID_COLS; col++) {
					var mapChip:MapChip = new MapChip(MapContext.DEFAULT_MAPDATA[row][col]);
					mapChip.x = MapContext.GRID_SIZE * col;
					mapChip.y = MapContext.GRID_SIZE * row;
					_map.addChild(mapChip);
					_mapModel[row][col] = mapChip;
				}
			}
			addDisplayWindow(_map, 20, 20, 350, 350);
			
			// マップ上でのマウスイベントリスナの登録
			_map.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownMap);
			_map.addEventListener(MouseEvent.MOUSE_UP, mouseUpMap);
			_map.addEventListener(MouseEvent.ROLL_OUT, mouseUpMap);
			_map.addEventListener(MouseEvent.MOUSE_OVER, mouseOverMap);
			_map.addEventListener(MouseEvent.MOUSE_OUT, mouseOutMap);
		}
		
		// 選択中のマップチップの画像を表示する枠を作成する
		private function initializeSelectedChip():void {
			_selectedChip = new MapChip(_selectedChipType);
			_selectedChip.x = _selectedChip.y = int((50 - MapContext.GRID_SIZE) / 2);
			addDisplayWindow(_selectedChip, 395, 5, 50, 50);
		}
		
		// マップチップのリストを作成する
		private function initializeChipList():void {
			_chipList = new Sprite();
			var chipNum:int = MapChip.images.length;
			var chipPosX:int = int((50 - MapContext.GRID_SIZE) / 2);
			for (var num:int = 0; num < chipNum; num++) {
				var mapChip:MapChip = new MapChip(num);
				mapChip.x = chipPosX;
				mapChip.y = MapContext.GRID_SIZE * num;
				_chipList.addChild(mapChip);
			}
			addDisplayWindow(_chipList, 395, 60, 50, 400);
			
			// マップチップのリスト上でのマウスイベントリスナの登録
			_chipList.addEventListener(MouseEvent.CLICK, mouseClickChipList);
			_chipList.addEventListener(MouseEvent.MOUSE_OVER, mouseOverChipList);
			_chipList.addEventListener(MouseEvent.MOUSE_OUT, mouseOutChipList);
		}
		
		// 引数で指定したDisplayObject用の窓を作成して、表示リストに追加する
		private function addDisplayWindow(displayObject:DisplayObject, posx:int, posy:int, width:int, height:int):void {
			// マスクで表示範囲を制限する
			var maskShape:Shape = new Shape();
			maskShape.graphics.beginFill(0xffffff);
			maskShape.graphics.drawRect(0, 0, width, height);
			maskShape.graphics.endFill();
			displayObject.mask = maskShape;
			
			// 位置を調整するコンテナを作成し表示させる
			var container:Sprite = new Sprite();
			container.x = posx;
			container.y = posy;
			container.addChild(displayObject);
			container.addChild(maskShape);
			addChild(container);
		}
		
		// 画面に配置するコンポーネントを作成する
		private function initializeComponents():void {
			// マップのスクロール用スライダー作成
			_mapScrollTop = new HSlider(this, 20, 5, scrollMapHorizontal);
			_mapScrollBottom = new HSlider(this, 20, 375, scrollMapHorizontal);
			_mapScrollLeft = new VSlider(this, 5, 20, scrollMapVertical);
			_mapScrollRight = new VSlider(this, 375, 20, scrollMapVertical);
			_mapScrollTop.width = _mapScrollBottom.width =
			_mapScrollLeft.height = _mapScrollRight.height = 350;
			_mapScrollTop.maximum = _mapScrollBottom.maximum = Math.max(MapContext.MAP_WIDTH - 350, 0);
			_mapScrollLeft.value = _mapScrollRight.value = 
			_mapScrollLeft.maximum = _mapScrollRight.maximum = Math.max(MapContext.MAP_HEIGHT - 350, 0);
			
			// 入出力用テキストフィールド・インポートボタン・エクスポートボタン作成
			_IOTextField = new Text(this, 10, 395, "");
			_IOTextField.width = 370;
			_IOTextField.height = 35;
			_importButton = new PushButton(this, 10, 435, "import", MapContext.instance.importMapData);
			_exportButton = new PushButton(this, 280, 435, "export", MapContext.instance.exportMapData);
			
			// 選択中のマップチップの表示用の枠作成
			graphics.beginFill(0x999999);
			graphics.drawRect(394, 4, 52, 52);
			graphics.endFill();
			graphics.beginFill(0x000000);
			graphics.drawRect(395, 5, 50, 50);
			graphics.endFill();
			
			// マップチップのリスト用スライダー作成
			_chipListSlider = new VSlider(this, 450, 60, slideChipList);
			_chipListSlider.height = 400;
			_chipListSlider.maximum = Math.max((MapContext.GRID_SIZE * MapChip.images.length) - 400, 0);
			_chipListSlider.value = _chipListSlider.maximum;
		}
		
		private function mouseDownMap(e:MouseEvent):void {
			_isMouseDownOnMap = true;
			MapChip(e.target).type = _selectedChipType;
		}
		
		private function mouseUpMap(e:MouseEvent):void {
			_isMouseDownOnMap = false;
		}
		
		private function mouseOverMap(e:MouseEvent):void {
			MapChip(e.target).showFrame();
			if (_isMouseDownOnMap) {
				MapChip(e.target).type = _selectedChipType;
			}
		}
		
		private function mouseOutMap(e:MouseEvent):void {
			MapChip(e.target).hideFrame();
		}
		
		private function mouseClickChipList(e:MouseEvent):void {
			_selectedChipType = MapChip(e.target).type;
			_selectedChip.type = _selectedChipType;
		}
		
		private function mouseOverChipList(e:MouseEvent):void {
			MapChip(e.target).showFrame();
		}
		
		private function mouseOutChipList(e:MouseEvent):void {
			MapChip(e.target).hideFrame();
		}
		
		private function scrollMapHorizontal(e:Event):void {
			_mapScrollTop.value = _mapScrollBottom.value = HSlider(e.target).value;
			_map.x = -(int(_mapScrollTop.value));
		}
		
		private function scrollMapVertical(e:Event):void {
			_mapScrollLeft.value = _mapScrollRight.value = VSlider(e.target).value;
			_map.y = -(_mapScrollLeft.maximum - int(_mapScrollLeft.value));
		}
		
		private function slideChipList(e:Event):void {
			_chipList.y = -(_chipListSlider.maximum - int(_chipListSlider.value));
		}
	}
}

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Shape;
import flash.display.Sprite;

class MapChip extends Sprite {
	public static var images:Array = [];	// BitmapDataの配列
	
	private var _type:int;
	private var _image:Bitmap;
	private var _frame:Shape;
	
	public function get type():int { return _type; }
	public function set type(t:int):void {
		if (t != _type) {
			_type = t;
			_image.bitmapData = images[_type];
		}
	}
	
	public function MapChip(type:int) {
		_type = type;
		_image = new Bitmap(images[_type]);
		_frame = new Shape();
		
		addChild(_image);
		addChild(_frame);
		
		hideFrame();
	}
	
	// 枠をハイライト表示させる
	public function showFrame():void {
		_frame.graphics.clear();
		
		_frame.graphics.lineStyle(1, 0xffff00);
		_frame.graphics.drawRect(0, 0, MapContext.GRID_SIZE - 0.5, MapContext.GRID_SIZE - 0.5);
	}
	
	// 枠をぼんやり見える程度にする
	public function hideFrame():void {
		_frame.graphics.clear();
		
		_frame.graphics.lineStyle(1, 0xffffff, 0.5);
		_frame.graphics.drawRect(0, 0, MapContext.GRID_SIZE - 0.5, MapContext.GRID_SIZE - 0.5);
	}
}

import com.bit101.components.Text;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.geom.Matrix;
import flash.net.URLRequest;
import flash.system.LoaderContext;

class MapContext extends EventDispatcher {
	public static const GRID_SIZE:int = 48;	// グリッドの大きさ
	public static const GRID_COLS:int = 16;	// グリッドの横の数
	public static const GRID_ROWS:int = 16;	// グリッドの縦の数
	
	// 初期のマップ配置
	public static const DEFAULT_MAPDATA:Array =
	[[0,6,9,18,10,10,10,10,10,18,2,18,11,11,11,11],
	[0,0,9,18,16,16,2,2,2,18,2,18,3,3,15,16],
	[0,0,9,18,2,2,2,2,2,18,2,18,3,3,3,3],
	[7,0,9,18,2,2,2,2,2,18,2,18,3,3,3,3],
	[0,0,9,18,10,10,10,10,2,13,2,14,3,11,11,11],
	[0,0,9,18,2,2,2,2,2,2,2,2,2,2,2,2],
	[0,0,9,18,2,2,2,2,2,2,2,12,10,10,10,10],
	[0,0,9,18,2,2,2,2,2,2,2,2,2,2,2,16],
	[0,0,9,18,2,2,2,2,2,2,2,18,2,2,2,2],
	[1,0,9,18,19,15,2,17,2,2,17,18,2,2,2,2],
	[1,1,9,10,10,10,10,10,2,2,10,10,10,10,10,10],
	[1,1,9,9,9,9,9,9,4,4,9,9,9,9,9,9],
	[1,1,0,0,0,9,9,0,0,0,0,6,0,0,0,7],
	[1,1,1,0,0,5,5,0,0,0,0,0,0,0,0,0],
	[8,1,1,1,9,9,9,9,0,0,1,1,0,0,6,0],
	[1,1,1,9,9,9,9,9,9,9,9,9,1,1,1,0]];
	
	private var _loadedA:int;
	private var _loaderAList:Array;
	private var _loadedB:int;
	private var _loaderBList:Array;
	
	// マップチップ画像(BitmapDataオブジェクト)の読み込み
	public function load():void {
		_loadedA = _loadedB = 0;
		_loaderAList = [];
		_loaderBList = [];
		
		for (var i:int = 0; i < 20; i++) {
			var loader:Loader = new Loader();
			_loaderAList[i] = loader;
			loader.contentLoaderInfo.addEventListener(Event.INIT, loaderALoaded);
			if(i < 19){
				loader.load(
					new URLRequest("http://flash-scope.com/wonderfl/WonderflQuest/map/map" + i +".png"),
					new LoaderContext(true)
				);
			}else {
				loader.load(
					new URLRequest("http://usericons.relucks.org/twitter/osamX"),
					new LoaderContext(true)
				);
			}
		}
	}
	
	private function loaderALoaded(e:Event):void {
		e.target.removeEventListener(Event.INIT, loaderALoaded);
		_loadedA++;
		
		if (_loadedA == 20) {
			for (var i:int = 0; i < 20; i++) {
				var loader:Loader = new Loader();
				_loaderBList[i] = loader;
				loader.contentLoaderInfo.addEventListener(Event.INIT, loaderBLoaded);
				loader.loadBytes(_loaderAList[i].contentLoaderInfo.bytes);
			}
		}
	}
	
	private function loaderBLoaded(e:Event):void {
		e.target.removeEventListener(Event.INIT, loaderBLoaded);
		_loadedB++;
		
		if (_loadedB == 20) {
			for (var i:int = 0; i < 20; i++) {
				var bitmapData:BitmapData = new BitmapData(MapContext.GRID_SIZE, MapContext.GRID_SIZE, false);
				var matrix:Matrix = new Matrix();
				if (i < 19) {
					matrix.scale(3, 3);
				}else {
					matrix.scale(MapContext.GRID_SIZE / 73, MapContext.GRID_SIZE / 73);
				}
				bitmapData.draw(_loaderBList[i], matrix);
				MapChip.images.push(bitmapData);
			}
			
			// 読み込み完了イベント送出
			dispatchEvent(new Event(Event.COMPLETE));
		}
	}
	
	// インポート(読み込み)ボタンの処理
	public function importMapData(e:Event):void {
		var mapData:Array = _IOTextFieldReference.text.match(/\d+/g);
		
		for (var row:int = 0; row < MapContext.GRID_ROWS; row++) {
			for (var col:int = 0; col < MapContext.GRID_COLS; col++) {
				// マップ上の各マップチップの種類を変更する
				MapChip(_mapModelReference[row][col]).type = mapData[(row * MapContext.GRID_COLS) + col];
			}
		}
	}
	
	// エクスポート(書き出し)ボタンの処理
	public function exportMapData(e:Event):void {
		var mapDataText:String = "[";
		
		for (var row:int = 0; row < MapContext.GRID_ROWS; row++) {
			mapDataText += "[";
			for (var col:int = 0; col < MapContext.GRID_COLS; col++) {
				mapDataText += MapChip(_mapModelReference[row][col]).type.toString();
				if (col < MapContext.GRID_COLS - 1) { mapDataText += ","; }
			}
			mapDataText += "]";
			if (row < MapContext.GRID_ROWS - 1) { mapDataText += ",\n"; }
		}
		mapDataText += "];";
		
		// テキストフィールドに出力する
		_IOTextFieldReference.text = mapDataText;
	}
	
	/* ここから上をいじる */
	/********************************************************************************/
	
	public static const MAP_WIDTH:int = MapContext.GRID_SIZE * MapContext.GRID_COLS;
	public static const MAP_HEIGHT:int = MapContext.GRID_SIZE * MapContext.GRID_ROWS;
	
	private static var _instance:MapContext = null;
	private var _mapModelReference:Array;	// マップモデルの参照
	private var _IOTextFieldReference:Text;	// テキスト表示エリアの参照
	
	public static function get instance():MapContext {
		if (MapContext._instance == null) {
			MapContext._instance = new MapContext(new SingletonEnforcer());
		}
		return MapContext._instance;
	}
	
	public function MapContext(enforcer:SingletonEnforcer) {
	}
	
	public function setReference(mapModel:Array, textField:Text):void {
		_mapModelReference = mapModel;
		_IOTextFieldReference = textField;
	}
}
class SingletonEnforcer {}