Beautifl - Flash Gallery

Thumbnail : ドット絵エディタ(マップエディタメーカー)
ドット絵エディタ(マップエディタメーカー)
o8que 2010-01-25 MIT License

再生するにはFlash Playerが必要です。デスクトップのブラウザでご覧ください。

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

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;
					if (MapContext.DEFAULT_MAPDATA[row] == undefined || MapContext.DEFAULT_MAPDATA[row][col] == undefined) {
						mapChip = new MapChip(0);
					}else {
						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, 0x000000, 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.events.Event;
import flash.events.EventDispatcher;

class MapContext extends EventDispatcher {
	public static const GRID_SIZE:int = 35;	// グリッドの大きさ
	public static const GRID_COLS:int = 10;	// グリッドの横の数
	public static const GRID_ROWS:int = 10;	// グリッドの縦の数
	
	// 初期のマップ配置
	public static const DEFAULT_MAPDATA:Array =
	[[1,1,1,8,8,8,8,1,1,1],
	[1,1,8,8,8,8,8,8,1,1],
	[1,8,8,0,8,8,0,8,8,1],
	[8,8,8,0,8,8,0,8,8,8],
	[8,8,8,8,8,8,8,8,8,8],
	[8,8,8,8,8,8,8,8,8,8],
	[8,8,5,5,5,5,5,5,8,8],
	[1,8,8,5,5,5,5,8,8,1],
	[1,1,8,8,8,8,8,8,1,1],
	[1,1,1,8,8,8,8,1,1,1]];
	
	// マップチップ画像(BitmapDataオブジェクト)の読み込み
	public function load():void {
		var sample:Array = [
		0x333333, 0x666666, 0x999999, 0xcccccc, 0xffffff, 0xff0000,
		0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff
		];
		
		var sampleNum:int = int(sample.length);
		for (var i:int = 0; i < sampleNum; i++) {
			MapChip.images.push(new BitmapData(MapContext.GRID_SIZE, MapContext.GRID_SIZE, false, sample[i]));
		}
		
		// 読み込み完了イベント送出
		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 {}