Layout Editor (for Dijkstra Particle Streams (Ver.1.1))
----------------------------------------------------------------------------------
* Dijkstra Particle Streams (Ver.1.1) 用のエディタ
* http://wonderfl.net/code/8bf10095433ea8cad0aff3f911f3aed6b15c6a36
* ----------------------------------------------------------------------------------
* [操作方法]
* マウスのみ。ショートカットキー等は一切ございません。
* ----------------------------------------------------------------------------------
* [マニュアル]
* 右上のボタン:上から壁編集、スタート編集、ゴール編集モードへの切り替え
* 右下のボタン:上から読み込み、書き出し、マップ全消去
*
* [壁編集モード]
* ・マップをクリックすることで壁を設置・除去できます。
* ・removableのチェックを入れると、実行時に除去できる壁を設置できます。
*
* [スタート編集モード]
* ・マップのノードをクリックすると、右にウインドウが表示されます。
* ・例えば、(ID.0)にチェックを入れると、
* そのノードからID.0のゴールへ向かうスタート地点が1つ作成されます。
* (実行時、ID.0のゴールが存在しなければ、そこからパーティクルは出現しません)
* ・2つチェックを入れると、そのノードにスタート地点が2つ作成されます。
*
* [ゴール編集モード]
* ・マップのノードをクリックすると、右にウインドウが表示されます。
* ・例えば、ID.0を選択すると、そのノードにID.0のゴール地点が1つ作成されます。
* (同じノードに2つ以上の異なるゴール地点を作成することはできません)
* ・異なるノードに同じIDのゴール地点を作成することはできます。
* その場合、パーティクルは同じIDを持つゴール地点の中で、
* 一番近いゴール地点を目的地として進みます。
*
* [読み込み・
/**
* Copyright o8que ( http://wonderfl.net/user/o8que )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/9sOc
*/
/* ----------------------------------------------------------------------------------
* Dijkstra Particle Streams (Ver.1.1) 用のエディタ
* http://wonderfl.net/code/8bf10095433ea8cad0aff3f911f3aed6b15c6a36
* ----------------------------------------------------------------------------------
* [操作方法]
* マウスのみ。ショートカットキー等は一切ございません。
* ----------------------------------------------------------------------------------
* [マニュアル]
* 右上のボタン:上から壁編集、スタート編集、ゴール編集モードへの切り替え
* 右下のボタン:上から読み込み、書き出し、マップ全消去
*
* [壁編集モード]
* ・マップをクリックすることで壁を設置・除去できます。
* ・removableのチェックを入れると、実行時に除去できる壁を設置できます。
*
* [スタート編集モード]
* ・マップのノードをクリックすると、右にウインドウが表示されます。
* ・例えば、(ID.0)にチェックを入れると、
* そのノードからID.0のゴールへ向かうスタート地点が1つ作成されます。
* (実行時、ID.0のゴールが存在しなければ、そこからパーティクルは出現しません)
* ・2つチェックを入れると、そのノードにスタート地点が2つ作成されます。
*
* [ゴール編集モード]
* ・マップのノードをクリックすると、右にウインドウが表示されます。
* ・例えば、ID.0を選択すると、そのノードにID.0のゴール地点が1つ作成されます。
* (同じノードに2つ以上の異なるゴール地点を作成することはできません)
* ・異なるノードに同じIDのゴール地点を作成することはできます。
* その場合、パーティクルは同じIDを持つゴール地点の中で、
* 一番近いゴール地点を目的地として進みます。
*
* [読み込み・書き出し]
* ・下のコピペ用テキストエリアに、然るべきXMLをペーストして
* importボタンを押すと、XMLのデータが読み込まれます。
* ・exportボタンを押すと、現在のマップ(壁、スタート、ゴール)の状態が
* 下のコピペ用テキストエリアに、XML形式で出力されます。
*
* [作成したレイアウトの適用方法]
* ・Dijkstra Particle Streams (Ver.1.1)をForkします。
* ・650行辺りに変数dataに代入されているXMLがあるので全部消します。
* ・変数dataにexportで出力されたXMLをコピペして書き換えます。
* ・成功すれば、あなたが作成したレイアウトで実行されるでしょう!
* ----------------------------------------------------------------------------------
* [Tips]
* ・マップの一番外側の黒いノードは画面外になります。
* ・ノードは、スタート地点があると緑、ゴール地点があると赤、両方あると紫になります。
* ・パーティクルの経路探索は各ゴール地点が行っているので、
* ゴール地点を増やしすぎると、処理が重くなる可能性があります。
* (同IDの異なるゴール地点も、それぞれ地点ごとに別に計算しているので注意)
* ・コピペ用テキストエリアには、最初「Dijkstra Particle Streams (Ver.1.1)」の
* XMLデータが入っています。importして見てみると感じが掴めると思います。
* ・コピペは全て選択からのコピーで
* ----------------------------------------------------------------------------------
* [作例]
* Juggle Them!! (ジャグれ!!)
* http://wonderfl.net/code/71ba419847037961758341adf477c4fc0faee767
* "LIFE" (「命」)
* http://wonderfl.net/code/9d0f2ea71c617566ad145782ba6c1bb5c336f15b
*/
package {
import com.bit101.components.*;
import flash.display.*;
import flash.events.*;
[SWF(frameRate=10)]
public class main extends Sprite {
public static var nodes:Array;
public static var walls:Array;
private var _mode:Mode;
// 各コンポーネントの参照
private var _map:Sprite;
private var _wallLayer:Sprite;
private var _cursor:Shape;
private var _currentMode:Text;
private var _wallSelect:PushButton;
private var _startSelect:PushButton;
private var _goalSelect:PushButton;
private var _IOTextField:Text;
private var _importButton:PushButton;
private var _exportButton:PushButton;
private var _clearButton:PushButton;
public function main() {
graphics.beginFill(0x000000);
graphics.drawRect(0, 0, 465, 465);
graphics.endFill();
initializeMap();
initializeComponents();
initializeMode();
}
private function initializeMap():void {
_map = new Sprite();
_map.x = _map.y = 5;
addChild(_map);
initializeNodes();
_wallLayer = new Sprite();
_map.addChild(_wallLayer);
_cursor = new Shape();
_map.addChild(_cursor);
_map.addEventListener(MouseEvent.MOUSE_MOVE, moveCursor);
}
private function initializeNodes():void {
main.nodes = [];
main.walls = [];
for (var row:int = 0; row < 33; row++) {
main.nodes[row] = [];
for (var col:int = 0; col < 33; col++) {
var node:Node = new Node(col, row);
main.nodes[row][col] = node;
_map.addChild(node);
}
}
}
private function moveCursor(e:MouseEvent):void {
_cursor.x = Math.min(_map.mouseX - (_map.mouseX % 11), 352);
_cursor.y = Math.min(_map.mouseY - (_map.mouseY % 11), 352);
}
private function initializeComponents():void {
// モード選択用パネルの作成
_currentMode = new Text(this, 373, 5);
_currentMode.width = 87, _currentMode.height = 20, _currentMode.editable = false;
var modeSelectPanel:Panel = new Panel(this, 373, 25);
modeSelectPanel.width = 87, modeSelectPanel.height = 72;
_wallSelect = new PushButton(modeSelectPanel, 3, 3, "build a Wall", changeToWallMode);
_startSelect = new PushButton(modeSelectPanel, 3, 26, "set a Start", changeToStartMode);
_goalSelect = new PushButton(modeSelectPanel, 3, 49, "set a Goal", chageToGoalMode);
_wallSelect.width = _startSelect.width = _goalSelect.width = 81;
// コピペフィールド・インポート・エクスポート・クリアの作成
_IOTextField = new Text(this, 5, 373, "");
_IOTextField.width = 363;
_IOTextField.height = 87;
setDefaultXML();
_importButton = new PushButton(this, 373, 378, "import", importXML);
_exportButton = new PushButton(this, 373, 406.5, "export", exportXML);
_clearButton = new PushButton(this, 373, 435, "clear all", clearAll);
_importButton.width = _exportButton.width = _clearButton.width = 87;
}
private function changeToWallMode(e:Event):void {
_mode.exit();
_mode = WallMode.instance;
_mode.enter();
}
private function changeToStartMode(e:Event):void {
_mode.exit();
_mode = StartMode.instance;
_mode.enter();
}
private function chageToGoalMode(e:Event):void {
_mode.exit();
_mode = GoalMode.instance;
_mode.enter();
}
private function initializeMode():void {
// 擬似ヌルオブジェクト
_mode = new Mode();
WallMode.instance.setContext(this);
StartMode.instance.setContext(this);
GoalMode.instance.setContext(this);
changeToWallMode(null);
_map.addEventListener(MouseEvent.CLICK, clickMap);
}
private function clickMap(e:MouseEvent):void {
_mode.clickMap(e);
}
private function importXML(e:MouseEvent):void {
clearAll(null);
var xml:XML = new XML(_IOTextField.text);
for each(var w:XML in xml.walls.*) {
var removable:Boolean = ((w.@rem == "t") ? true : false);
addWall(new Wall(int(w.@x), int(w.@y), removable));
}
var node:Node;
for each(var s:XML in xml.starts.*) {
node = main.nodes[int(s.@y)][int(s.@x)];
node.startDests[int(s.@goal)] = true;
node.draw(false);
}
for each(var g:XML in xml.goals.*) {
node = main.nodes[int(g.@y)][int(g.@x)];
node.goalID = int(g.@id);
node.draw(false);
}
}
private function exportXML(e:MouseEvent):void {
var xml:XML = <root><walls /><starts /><goals /></root>;
for (var i:int = 0; i < main.walls.length; i++) {
var wall:XML = <wall />
wall.@x = main.walls[i].tilex, wall.@y = main.walls[i].tiley;
wall.@rem = ((main.walls[i].removable) ? "t" : "f");
xml.walls.appendChild(wall);
}
for (var row:int = 0; row < 33; row++) {
for (var col:int = 0; col < 33; col++) {
var node:Node = main.nodes[row][col];
for (var dest:int = 0; dest < 16; dest++) {
if (node.startDests[dest]) {
var start:XML = <start />;
start.@goal = dest, start.@x = col, start.@y = row;
xml.starts.appendChild(start);
}
}
if (node.goalID != -1) {
var goal:XML = <goal />;
goal.@id = node.goalID, goal.@x = col, goal.@y = row;
xml.goals.appendChild(goal);
}
}
}
_IOTextField.text = xml.toXMLString();
}
private function clearAll(e:MouseEvent):void {
for (var row:int = 0; row < 33; row++) {
for (var col:int = 0; col < 33; col++) {
var node:Node = main.nodes[row][col];
for (var dest:int = 0; dest < 16; dest++) {
node.startDests[dest] = false;
}
node.goalID = -1;
node.draw(false);
}
}
for (var i:int = main.walls.length - 1; i >= 0; i--) {
main.walls[i].remove();
}
_mode.exit();
_mode.enter();
}
public function addWall(wall:Wall):void {
_wallLayer.addChild(wall);
main.walls.push(wall);
}
public function setCurrentModeText(str:String):void {
_currentMode.text = str;
}
public function drawCursor(size:int):void {
_cursor.graphics.clear();
_cursor.graphics.lineStyle(1, 0xffffff);
_cursor.graphics.drawRect(0.5, 0.5, size - 1, size - 1);
}
private function setDefaultXML():void {
var xml:XML =
<root>
<walls>
<wall x="0" y="0" rem="f"/><wall x="2" y="0" rem="f"/>
<wall x="4" y="0" rem="f"/><wall x="6" y="0" rem="f"/>
<wall x="8" y="0" rem="f"/><wall x="10" y="0" rem="f"/>
<wall x="21" y="0" rem="f"/><wall x="23" y="0" rem="f"/>
<wall x="25" y="0" rem="f"/><wall x="27" y="0" rem="f"/>
<wall x="29" y="0" rem="f"/><wall x="31" y="0" rem="f"/>
<wall x="0" y="31" rem="f"/><wall x="2" y="31" rem="f"/>
<wall x="4" y="31" rem="f"/><wall x="6" y="31" rem="f"/>
<wall x="8" y="31" rem="f"/><wall x="10" y="31" rem="f"/>
<wall x="21" y="31" rem="f"/><wall x="23" y="31" rem="f"/>
<wall x="25" y="31" rem="f"/><wall x="27" y="31" rem="f"/>
<wall x="29" y="31" rem="f"/><wall x="31" y="31" rem="f"/>
<wall x="0" y="2" rem="f"/><wall x="0" y="4" rem="f"/>
<wall x="0" y="6" rem="f"/><wall x="0" y="8" rem="f"/>
<wall x="0" y="10" rem="f"/><wall x="0" y="21" rem="f"/>
<wall x="0" y="23" rem="f"/><wall x="0" y="25" rem="f"/>
<wall x="0" y="27" rem="f"/><wall x="0" y="29" rem="f"/>
<wall x="31" y="2" rem="f"/><wall x="31" y="4" rem="f"/>
<wall x="31" y="6" rem="f"/><wall x="31" y="8" rem="f"/>
<wall x="31" y="10" rem="f"/><wall x="31" y="21" rem="f"/>
<wall x="31" y="23" rem="f"/><wall x="31" y="25" rem="f"/>
<wall x="31" y="27" rem="f"/><wall x="31" y="29" rem="f"/>
</walls>
<starts>
<start goal="0" x="13" y="0"/><start goal="0" x="14" y="0"/>
<start goal="0" x="15" y="0"/><start goal="0" x="16" y="0"/><start goal="0" x="17" y="0"/>
<start goal="0" x="18" y="0"/><start goal="0" x="19" y="0"/>
<start goal="1" x="0" y="13"/><start goal="1" x="0" y="14"/>
<start goal="1" x="0" y="15"/><start goal="1" x="0" y="16"/><start goal="1" x="0" y="17"/>
<start goal="1" x="0" y="18"/><start goal="1" x="0" y="19"/>
</starts>
<goals>
<goal id="0" x="13" y="32"/><goal id="0" x="14" y="32"/>
<goal id="0" x="15" y="32"/><goal id="0" x="16" y="32"/><goal id="0" x="17" y="32"/>
<goal id="0" x="18" y="32"/><goal id="0" x="19" y="32"/>
<goal id="1" x="32" y="13"/><goal id="1" x="32" y="14"/>
<goal id="1" x="32" y="15"/><goal id="1" x="32" y="16"/><goal id="1" x="32" y="17"/>
<goal id="1" x="32" y="18"/><goal id="1" x="32" y="19"/>
</goals>
</root>;
_IOTextField.text = xml.toXMLString();
}
}
}
//package {
import flash.display.*;
//public
class Node extends Sprite {
public var isWall:Boolean;
public var startDests:Array;
public var goalID:int;
private var _tilex:int;
private var _tiley:int;
public function Node(tilex:int, tiley:int) {
_tilex = tilex;
_tiley = tiley;
x = _tilex * 11;
y = _tiley * 11;
initialize();
draw();
}
public function initialize():void {
isWall = false;
startDests = [];
for (var i:int = 0; i < 16; i++) {
startDests.push(false);
}
goalID = -1;
}
public function draw(selected:Boolean = false):void {
graphics.clear();
if (selected) {
graphics.lineStyle(1, 0xffff00);
}else {
graphics.lineStyle(1, 0x333333);
}
if (hasStart() && hasGoal()) {
graphics.beginFill(0xff00ff);
}else if (hasStart()) {
graphics.beginFill(0x00ff00);
}else if (hasGoal()) {
graphics.beginFill(0xff0000);
}else if (_tilex == 0 || _tilex == 32 || _tiley == 0 || _tiley == 32) {
graphics.beginFill(0x111111);
}else {
graphics.beginFill(0x222222);
}
graphics.drawRect(0.25, 0.25, 10.5, 10.5);
graphics.endFill();
}
private function hasStart():Boolean {
for each(var dest:Boolean in startDests) {
if (dest) { return true; }
}
return false;
}
private function hasGoal():Boolean {
return (goalID != -1);
}
// 壁やスタート・ゴールノードになっていないかどうか
public function isFree():Boolean {
return !(isWall || hasStart() || hasGoal());
}
}
//}
//package {
import flash.display.*;
import flash.geom.Point;
//public
class Wall extends Sprite {
private var _tilex:int;
private var _tiley:int;
private var _removable:Boolean;
public function get tilex():int { return _tilex; }
public function get tiley():int { return _tiley; }
public function get removable():Boolean { return _removable; }
public function Wall(tilex:int, tiley:int, removable:Boolean) {
_tilex = tilex;
_tiley = tiley;
_removable = removable;
x = _tilex * 11;
y = _tiley * 11;
setNodePassablity(true);
draw();
}
// 壁を設置した部分のノードの通行可能性を変更する
private function setNodePassablity(isWall:Boolean):void {
main.nodes[_tiley][_tilex].isWall = isWall;
main.nodes[_tiley][_tilex + 1].isWall = isWall;
main.nodes[_tiley + 1][_tilex].isWall = isWall;
main.nodes[_tiley + 1][_tilex + 1].isWall = isWall;
}
// 壁の画像を描画する
private function draw():void {
if (_removable) {
graphics.lineStyle(1, 0x666666);
graphics.beginFill(0x444444);
graphics.drawRect(0.25, 0.25, 21.5, 21.5);
graphics.endFill();
}else {
graphics.beginFill(0x444444);
graphics.drawRect(0, 0, 22, 22);
graphics.endFill();
}
}
// 壁を取り除く際に呼ぶ関数
public function remove():void {
setNodePassablity(false);
parent.removeChild(this);
main.walls.splice(main.walls.indexOf(this), 1);
}
// 指定した位置に壁が設置できるか
public static function buildable(tilex:int, tiley:int):Boolean {
if (tilex == 32 || tiley == 32) {
return false;
}
return (main.nodes[tiley][tilex].isFree() &&
main.nodes[tiley][tilex + 1].isFree() &&
main.nodes[tiley + 1][tilex].isFree() &&
main.nodes[tiley + 1][tilex + 1].isFree());
}
}
//}
//package {
import flash.events.MouseEvent;
class Mode {
protected var _context:main;
public function setContext(context:main):void {
_context = context;
}
public function enter():void { }
public function exit():void { }
public function clickMap(e:MouseEvent):void { }
}
//}
//package {
import com.bit101.components.*;
import flash.events.*;
//public
class WallMode extends Mode {
private static var _instance:WallMode;
private var _wallPanel:Panel;
private var _removableCheck:CheckBox;
private var _removable:Boolean;
public static function get instance():WallMode {
if (WallMode._instance == null) {
_instance = new WallMode(new SingletonEnforcer());
}
return _instance;
}
public function WallMode(enforcer:SingletonEnforcer) {
_wallPanel = new Panel(null, 373, 102);
_wallPanel.width = 87, _wallPanel.height = 20;
_removableCheck = new CheckBox(_wallPanel, 5, 5, "removable", reverseRemovability);
_removable = false;
}
private function reverseRemovability(e:Event):void {
_removable = e.currentTarget.selected;
}
override public function enter():void {
_context.setCurrentModeText("Wall edit mode");
_context.drawCursor(22);
_context.addChild(_wallPanel);
_removable = _removableCheck.selected = false;
}
override public function exit():void {
if (_context.contains(_wallPanel)) {
_context.removeChild(_wallPanel);
}
}
override public function clickMap(e:MouseEvent):void {
if (e.target is Wall) {
e.target.remove();
}else if (e.target is Node) {
var tilex:int = int(e.target.x / 11);
var tiley:int = int(e.target.y / 11);
if (Wall.buildable(tilex, tiley)) {
_context.addWall(new Wall(tilex, tiley, _removable));
}
}
}
}
//}
//class SingletonEnforcer { }
//package {
import com.bit101.components.*;
import flash.events.*;
//public
class StartMode extends Mode {
private static var _instance:StartMode;
private var _startPanel:Panel;
private var _destChecks:Array;
private var _selectedNode:Node;
public static function get instance():StartMode {
if (StartMode._instance == null) {
_instance = new StartMode(new SingletonEnforcer());
}
return _instance;
}
public function StartMode(enforcer:SingletonEnforcer) {
_startPanel = new Panel(null, 373, 102);
_startPanel.width = 87, _startPanel.height = 245;
_destChecks = [];
for (var i:int = 0; i < 16; i++) {
var destCheck:CheckBox = new CheckBox(_startPanel, 5, 5 + i * 15, "to Goals(ID." + i + ")", clickDestCheck);
_destChecks.push(destCheck);
}
cancelSelection();
}
private function clickDestCheck(e:MouseEvent):void {
for (var i :int = 0; i < 16; i++) {
_selectedNode.startDests[i] = _destChecks[i].selected;
}
_selectedNode.draw(true);
}
private function cancelSelection():void {
// 擬似ヌルオブジェクト
_selectedNode = new Node(0, 0);
}
override public function enter():void {
_context.setCurrentModeText("Start edit mode");
_context.drawCursor(11);
_selectedNode.draw(true);
}
override public function exit():void {
_selectedNode.draw(false);
cancelSelection();
if (_context.contains(_startPanel)) {
_context.removeChild(_startPanel);
}
}
override public function clickMap(e:MouseEvent):void {
if (!(e.target is Node)) {
if (_context.contains(_startPanel)) {
_context.removeChild(_startPanel);
}
return;
}
_selectedNode.draw(false);
_selectedNode = e.target as Node;
_selectedNode.draw(true);
for (var i:int = 0; i < 16; i++) {
_destChecks[i].selected = _selectedNode.startDests[i];
}
_context.addChild(_startPanel);
}
}
//}
//class SingletonEnforcer { }
//package {
import com.bit101.components.*;
import flash.events.*;
//public
class GoalMode extends Mode {
private static var _instance:GoalMode;
private var _goalPanel:Panel;
private var _goalButtons:Array;
private var _selectedNode:Node;
public static function get instance():GoalMode {
if (GoalMode._instance == null) {
_instance = new GoalMode(new SingletonEnforcer());
}
return _instance;
}
public function GoalMode(enforcer:SingletonEnforcer) {
_goalPanel = new Panel(null, 373, 102);
_goalPanel.width = 87, _goalPanel.height = 260;
_goalButtons = [new RadioButton(_goalPanel, 5, 5, "none", false, clickGoalButton)];
for (var i:int = 0; i < 16; i++) {
var goalButton:RadioButton = new RadioButton(_goalPanel, 5, 20 + i * 15, "ID." + i, false, clickGoalButton);
_goalButtons.push(goalButton);
}
cancelSelection();
}
private function clickGoalButton(e:MouseEvent):void {
for (var i:int = 0; i < 16; i++) {
if (_goalButtons[i + 1].selected) {
_selectedNode.goalID = i;
break;
}
}
if (i == 16) {
_selectedNode.goalID = -1;
}
_selectedNode.draw(true);
}
private function cancelSelection():void {
// 擬似ヌルオブジェクト
_selectedNode = new Node(0, 0);
}
override public function enter():void {
_context.setCurrentModeText("Goal edit mode");
_context.drawCursor(11);
_selectedNode.draw(true);
}
override public function exit():void {
_selectedNode.draw(false);
cancelSelection();
if (_context.contains(_goalPanel)) {
_context.removeChild(_goalPanel);
}
}
override public function clickMap(e:MouseEvent):void {
if (!(e.target is Node)) {
if (_context.contains(_goalPanel)) {
_context.removeChild(_goalPanel);
}
return;
}
_selectedNode.draw(false);
_selectedNode = e.target as Node;
_selectedNode.draw(true);
_goalButtons[_selectedNode.goalID + 1].selected = true;
_context.addChild(_goalPanel);
}
}
//}
class SingletonEnforcer { }