不思議のダンジョン(ダンジョン自動生成&移動&戦闘)
参考:http://d.hatena.ne.jp/Gemma/20070816
/**
* Copyright takimo ( http://wonderfl.net/user/takimo )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/lcMA
*/
// forked from takimo's 不思議のダンジョン自動生成
package
{
import flash.display.Bitmap;
import flash.utils.IDataInput;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.geom.Rectangle;
import flash.display.Sprite;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.text.AntiAliasType;
//参考:http://d.hatena.ne.jp/Gemma/20070816
[SWF(backgroundColor="#000000")]
public class Rogue extends Sprite
{
private var _debug:TextField;
private var _mapText:TextField;
private var _status:TextField;
private var _fontSize:uint = 12;
private var _rectArray:Array;
private var _dungeon:Array;
private var _map:Array;
private var _format:TextFormat;
private var _commandManager:CommandManager;
private var _user:User;
private var _players:Array;
private var _floor:Floor;
private var _enemies:Array;
public function Rogue()
{
super();
_debug = new TextField();
createTextField(_debug, 400, 40, 0, 0, 12, 0xffffff, 'h,j,k,lで移動。@がPlayer。アルファベットは敵');
_mapText = new TextField();
// game 用
//createTextField(_mapText, 300, 300, 100, 100, 20, 0xffffff);
// debug 用
createTextField(_mapText, 400, 400, 0, 0, 10, 0xffffff);
_status = new TextField();
createTextField(_status, 100, 400, 350, 0, 12, 0xffffff);
_user = new User();
_user.symbol = "@";
_user.hitpoint = 10;
_commandManager = new CommandManager();
_commandManager.addEventListener(CommandEvent.COMPLETE, commandManager_completeHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, stage_keyUpHandler);
_floor = new Floor(this);
_floor.addEventListener(DungeonEvent.NEXT_FLOOR, dungeon_nextfloorHandler);
nextFloor();
renderMap();
_status.appendText("\n");
displayStatus();
}
private function displayStatus():void
{
_status.text = "";
_status.appendText("Floor : " + String(_floor.count) + "\n");
_status.appendText("HP : " + String(_user.hitpoint) + "\n");
_status.appendText("LEVEL : " + String(_user.level) + "\n");
_status.appendText("EXP : " + String(_user.exp) + "\n");
}
private function nextFloor():void
{
_floor.generate();
//render(floor.map.toString());
_enemies = new Array();
_floor.dungeon = _floor.map;
_user.position = _floor.randomPosition();
generateEnemies(["A", "B", "C", "D"]);
setEnemies();
_floor.dungeon[_user.position.y][_user.position.x] = _user;
_map = generateMap(_floor.dungeon);
}
private function generateEnemies(enemySymbols:Array):void
{
var enemy:Enemy;
for each(var enemySymbol:String in enemySymbols)
{
enemy = new Enemy();
enemy.position = _floor.randomPosition();
enemy.symbol = enemySymbol;
enemy.hitpoint = 3;
_enemies.push(enemy);
}
}
private function setEnemies():void
{
for each(var enemy:Enemy in _enemies)
{
if(enemy.hitpoint > 0)
_floor.dungeon[enemy.position.y][enemy.position.x] = enemy;
else
//debug(_floor.map[enemy.position.y][enemy.position.x]);
_floor.dungeon[enemy.position.y][enemy.position.x] = _floor.map[enemy.position.y][enemy.position.x];
}
}
private function workEnemies():void
{
_enemies.map(moveEnemy);
/**
for each(var enemy:Enemy in _enemies)
{
}
*/
}
private function moveEnemy(enemy:Enemy, index:int, array:Array):void
{
if(enemy.hitpoint > 0)
{
var position:Point = enemy.position.clone();
var way:uint = randomRange(0, 4);
switch(way)
{
case 0:
enemy.position = _floor.move(enemy, Command.MOVE_RIGHT);
break;
case 1:
enemy.position = _floor.move(enemy, Command.MOVE_LEFT);
break;
case 2:
enemy.position = _floor.move(enemy, Command.MOVE_UP);
break;
case 3:
enemy.position = _floor.move(enemy, Command.MOVE_DOWN);
break;
default:
break;
}
_floor.dungeon[enemy.position.y][enemy.position.x] = enemy;
}
else
{
//debug(_floor.map[enemy.position.y][enemy.position.x]);
}
}
private function generateMap(map:Array, position:Point = null):Array
{
var dungeon:Array = new Array();
var tmp:Array;
for each (var row:Array in map)
{
tmp = new Array();
for each (var column:* in row)
{
if (column is Wall)
tmp.push(column.symbol);
else if (column is Ground)
tmp.push(".");
else if (column is Road)
tmp.push("#");
else if (column is Door)
tmp.push(column.symbol);
else if (column is Stairs)
tmp.push(column.symbol);
else if (column is User)
tmp.push(column.symbol);
else if (column is Enemy)
tmp.push(column.symbol);
else
//debug(String(column));
tmp.push(" ");
}
dungeon.push(tmp);
}
return dungeon;
}
public function debug(message:String, isBreak:Boolean = true):void
{
if (isBreak) message += "\n";
//_debug.appendText(message);
_debug.text = message;
}
private function render(message:String, isBreak:Boolean = true):void
{
if (isBreak) message += "\n";
_mapText.appendText(message);
}
private function renderMap():void
{
var rect:Rectangle = new Rectangle(0, 0, 60, 30);
//var rect:Rectangle = new Rectangle(_user.position.x - 10 , _user.position.y - 5, 20, 10);
render("");
_mapText.text = "";
for (var i:int = rect.top; i < rect.bottom; i++)
{
for (var j:int = rect.left; j < rect.right; j++)
{
if(i < 0 || j < 0 || i > _floor.height || j > _floor.width || !_map[i][j])
render(" ", false);
else
render(_map[i][j], false);
}
render('\n', false);
}
}
private function createTextField(textField:TextField, width:int, height:int, x:int = 0, y:int = 0, fontsize:int=12, color:int = 0xffffff, text:String = " "):void
{
var format:TextFormat = new TextFormat();
format.font = '_等幅';
format.size = fontsize;
format.color = color;
textField.height = height;
textField.width = width;
textField.x = x;
textField.y = y;
//textField.border = true;
textField.text = text;
textField.setTextFormat(format);
this.addChild(textField);
}
private function stage_keyUpHandler(event:KeyboardEvent):void
{
_commandManager.input(event.keyCode);
//debug(String(event.keyCode));
}
private function commandManager_completeHandler(event:CommandEvent):void
{
_user.position = _floor.move(_user, event.action);
_floor.dungeon = new Array();
_floor.dungeon = _floor.map;
setEnemies();
_floor.dungeon[_user.position.y][_user.position.x] = _user;
_map = generateMap(_floor.dungeon);
renderMap();
displayStatus();
workEnemies();
}
private function dungeon_nextfloorHandler(event:DungeonEvent):void
{
nextFloor();
}
private function randomRange(min:int, max:int):int
{
if(min > max) return 0;
else if(min == max) return min;
else return Math.floor(Math.random() * (max - min)) + min;
}
}
}
import flash.events.EventDispatcher;
class CommandManager extends EventDispatcher
{
private var _command:String;
public function CommandManager():void
{
_command = "";
}
public function input(command:int):void
{
_command += String(command);
switch(_command)
{
case "27":
_command = "";
break;
case "72":
dispatch(Command.MOVE_LEFT);
break;
case "74":
dispatch(Command.MOVE_DOWN);
break;
case "75":
dispatch(Command.MOVE_UP);
break;
case "76":
dispatch(Command.MOVE_RIGHT);
break;
default:
dispatch("error");
}
}
private function dispatch(action:String):void
{
var event:CommandEvent = new CommandEvent(CommandEvent.COMPLETE);
event.action = action;
dispatchEvent(event);
_command = "";
}
}
import flash.geom.Point;
import flash.geom.Rectangle;
class Dungeon
{
public function get floor():Floor
{
return _floor;
}
private var _floor:Floor;
public function set floor(floor:Floor):void
{
_floor = floor;
}
public function get enemies():Array
{
return _enemies;
}
private var _enemies:Array;
public function set enemies(enemies:Array):void
{
_enemies = enemies;
}
public function Dungeon():void
{
}
public function generateFloor():void
{
}
public function generateEnemies():void
{
}
public function renderFloor():String
{
return "";
}
public function setPlayer():void
{
}
public function setItems(items:Array):void
{
}
public function move():void
{
}
}
import flash.geom.Rectangle;
import flash.utils.ByteArray;
import flash.events.EventDispatcher;
class Floor extends EventDispatcher
{
private var _dungeonWidth:uint = 60;
private var _dungeonHeight:uint = 30;
private var _margin:uint = 8;
private var _self:*;
public function get count():uint
{
return _count;
}
private var _count:uint;
public function set count(count:uint):void
{
_count = count;
}
public function get width():uint
{
return _dungeonWidth;
}
public function get height():uint
{
return _dungeonHeight;
}
public function get rooms():Array
{
return _rooms;
}
private var _rooms:Array;
public function set rooms(rooms:Array):void
{
_rooms = rooms;
}
public function get map():Array
{
var tmp:Array = new Array();
for each(var colmun:Array in _map)
tmp.push(colmun.concat());
return tmp;
//return _map;
}
private var _map:Array;
public function set map(map:Array):void
{
_map = map;
}
public function get dungeon():Array
{
/**
var tmp:Array = new Array();
for each(var colmun:Array in _dungeon)
tmp.push(colmun.concat());
return tmp;
*/
return _dungeon;
}
private var _dungeon:Array;
public function set dungeon(dungeon:Array):void
{
_dungeon = dungeon;
}
public function Floor(self:*):void
{
_self = self;
_count = 0;
}
public function generate():void
{
var rect:Rectangle = new Rectangle(0, 0, _dungeonWidth - 1, _dungeonHeight - 1);
_map = new Array(_dungeonHeight);
for (var j:int=0; j<_dungeonHeight; j++)
{
_map[j] =new Array(_dungeonWidth);
for(var i:int=0; i < _dungeonWidth; i++)
{
_map[j][i] = null;
}
}
var compartments:Array = flatten(split(rect), []);
_rooms = compartments.map(createRoom);
for each (var room:Rectangle in _rooms)
{
setRoom(room);
}
createRoad(compartments, _rooms);
setStairs(_rooms);
_count++;
}
public function move(character:*, way:String):Point
{
var point:Point = character.position.clone();
switch(way)
{
case Command.MOVE_RIGHT:
point.x++;
break;
case Command.MOVE_LEFT:
point.x--;
break;
case Command.MOVE_UP:
point.y--;
break;
case Command.MOVE_DOWN:
point.y++;
break;
default:
break;
}
var dungeon:* = _dungeon[point.y][point.x];
//_self.debug(dungeon.toString());
if ((dungeon is Ground) || (dungeon is Road) || (dungeon is Door))
{
return point;
}
else if(!(character is Enemy))
{
if ((dungeon is Enemy))
{
dungeon.protec();
}
else if (dungeon is Stairs)
{
var event:DungeonEvent = new DungeonEvent(DungeonEvent.NEXT_FLOOR);
dispatchEvent(event);
}
return character.position;
}
else
{
if ((dungeon is User))
{
dungeon.protec();
}
return character.position;
}
}
public function attack(enemy:Enemy):void
{
enemy.hitpoint--;
}
private function half(n:int):int
{
return int(n >> 1);
}
private function setRoad(rect:Rectangle):void
{
var min_j:int = Math.min(rect.top, rect.bottom);
var max_j:int = Math.max(rect.top, rect.bottom);
var min_i:int = Math.min(rect.left, rect.right);
var max_i:int = Math.max(rect.left, rect.right);
for (var j:int = min_j; j <= max_j; j++)
for (var i:int = min_i; i <= max_i; i++)
_map[j][i] = new Road();
}
private function setRoom(rect:Rectangle):void
{
var min_j:int = Math.min(rect.top, rect.bottom);
var max_j:int = Math.max(rect.top, rect.bottom);
var min_i:int = Math.min(rect.left, rect.right);
var max_i:int = Math.max(rect.left, rect.right);
for (var j:int = min_j; j <= max_j; j++)
for (var i:int = min_i; i <= max_i; i++)
_map[j][i] = new Ground();
for (j = min_j; j <= max_j; j++)
{
_map[j][min_i] = new Wall(Wall.LEFT);
_map[j][max_i] = new Wall(Wall.RIGHT);
}
for (i = min_i; i <= max_i; i++)
{
_map[min_j][i] = new Wall(Wall.TOP);
_map[max_j][i] = new Wall(Wall.BOTTOM);
}
}
private function setDoor(rect:Rectangle):void
{
var min_j:int = Math.min(rect.top, rect.bottom);
var max_j:int = Math.max(rect.top, rect.bottom);
var min_i:int = Math.min(rect.left, rect.right);
var max_i:int = Math.max(rect.left, rect.right);
for (var j:int = min_j; j <= max_j; j++)
for (var i:int = min_i; i <= max_i; i++)
_map[j][i] = new Door();
}
private function setStairs(rects:Array):void
{
var position:Point = randomPosition();
_map[position.y][position.x] = new Stairs();
}
private function randomRange(min:int, max:int):int
{
if(min > max) return 0;
else if(min == max) return min;
else return Math.floor(Math.random() * (max - min)) + min;
}
private function createRoad(compartments:Array, rooms:Array):void
{
var connectList:Array = new Array();
for (var i:int = 0; i < compartments.length - 1; i++)
connectList.push([i, i + 1]);
for (var k:int = 0; k < compartments.length; k++)
for (var j:int = k + 1; j < compartments.length; j++)
if (randomRange(0,5) == 0)
if (compartments[k].left == compartments[j].right ||
compartments[k].right == compartments[j].left ||
compartments[k].top == compartments[j].bottom ||
compartments[k].bottom == compartments[j].top)
connectList.push([k,j]);
for each (var connect:Array in connectList)
{
var from:int = connect[0];
var to:int = connect[1];
var parentCompartment:Rectangle = compartments[from];
var childrenCompartment:Rectangle = compartments[to];
var parentRoom:Rectangle = rooms[from];
var childrenRoom:Rectangle = rooms[to];
if (parentCompartment.bottom == childrenCompartment.top)
{
// N 縦
var a:int = randomRange(parentRoom.left + 1, parentRoom.right - 1);
var b:int = randomRange(childrenRoom.left + 1, childrenRoom.right - 1);
setDoor(point2Rect(a, parentRoom.bottom, a, parentRoom.bottom));
setRoad(point2Rect(a, parentRoom.bottom + 1, a, parentCompartment.bottom));
setRoad(point2Rect(b, childrenRoom.top - 1, b, childrenCompartment.top));
setDoor(point2Rect(b, childrenRoom.top, b, childrenRoom.top));
setRoad(point2Rect(a, parentCompartment.bottom, b, childrenCompartment.top));
}
else if (parentCompartment.right == childrenCompartment.left)
{
// Z 横
a = randomRange(parentRoom.top + 1, parentRoom.bottom - 1);
b = randomRange(childrenRoom.top + 1, childrenRoom.bottom - 1);
setDoor(point2Rect(parentRoom.right, a, parentRoom.right, a));
setRoad(point2Rect(parentRoom.right + 1, a, parentCompartment.right, a));
setRoad(point2Rect(childrenRoom.left - 1, b, childrenCompartment.left, b));
setDoor(point2Rect(childrenRoom.left, b, childrenRoom.left, b));
setRoad(point2Rect(parentCompartment.right, a, childrenCompartment.left, b));
}
}
}
private function point2Rect(x0:int, y0:int, x1:int, y1:int):Rectangle
{
var rect:Rectangle = new Rectangle();
rect.topLeft = new Point(Number(x0), Number(y0));
rect.bottomRight = new Point(Number(x1), Number(y1));
return rect;
}
private function createRoom(rect:Rectangle, index:int=0, array:Array=null):Rectangle
{
var room:Rectangle = new Rectangle();
room.left = rect.left + randomRange(2, half(rect.right - rect.left) - 1);
room.top = rect.top + randomRange(2, half(rect.bottom - rect.top) - 1);
room.right = rect.right - randomRange(2, half(rect.right - rect.left) - 1);
room.bottom = rect.bottom - randomRange(2, half(rect.bottom - rect.top) - 1);
return room;
}
private function split(rect:Rectangle, index:int=0, array:Array=null):Array
{
if ((rect.right - rect.left < _margin * 2) || (rect.bottom - rect.top < _margin * 2))
{
return [rect];
}
var rect1:Rectangle = new Rectangle();
var rect2:Rectangle = new Rectangle();
// 縦(0) or 横(1)
var direction:int = Math.floor(Math.random() * 2);
//debug("direction : " + String(direction));
// 分割
var point:Point = new Point();
// 縦分割
if(direction)
{
point.x = randomRange(rect.left + _margin, rect.right - _margin);
rect1.topLeft = rect.topLeft;
rect1.bottomRight = new Point(point.x, rect.bottom);
rect2.topLeft = new Point(point.x, rect.top);
rect2.bottomRight = rect.bottomRight;
}
else
{
point.y =randomRange(rect.top + _margin, rect.bottom - _margin);
rect1.topLeft = rect.topLeft;
rect1.bottomRight = new Point(rect.right, point.y);
rect2.topLeft = new Point(rect.x, point.y);
rect2.bottomRight = rect.bottomRight;
}
return [rect1, rect2].map(split);
}
private function flatten(array:*, tmp:Array):Array
{
//debug("flatten");
for each (var item:* in array)
{
if(item as Array) tmp = flatten(item, tmp);
if(item as Rectangle) tmp.push(item);
}
return tmp;
}
public function randomPosition():Point
{
var target:int = randomRange(0, _rooms.length);
var rect:Rectangle = _rooms[target];
var point:Point = new Point();
point.x = randomRange(rect.left + 1, rect.right - 1);
point.y = randomRange(rect.top + 1, rect.bottom - 1);
return point;
}
public function clone(source:Object):*
{
var tmp:ByteArray = new ByteArray();
tmp.writeObject(source);
tmp.position = 0;
return(tmp.readObject());
}
}
import flash.events.Event;
class CommandEvent extends Event
{
public static const COMPLETE:String = "complete";
/**
* action
*/
public function get action():String
{
return _action;
}
private var _action:String;
public function set action(action:String):void
{
_action = action;
}
public function CommandEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false):void
{
super(type, bubbles, cancelable);
}
public override function clone():Event {
return new CommandEvent(type, bubbles, cancelable);
}
}
class Command
{
public static const MOVE_LEFT:String = "move_left";
public static const MOVE_RIGHT:String = "move_right";
public static const MOVE_UP:String = "move_up";
public static const MOVE_DOWN:String = "move_down";
public function Command():void
{
}
}
import flash.events.Event;
class DungeonEvent extends Event
{
public static const NEXT_FLOOR:String = "next_floor";
public function DungeonEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false):void
{
super(type, bubbles, cancelable);
}
}
class DungeonObject
{
public function get symbol():String
{
return _symbol;
}
protected var _symbol:String;
public function set symbol(symbol:String):void
{
_symbol = symbol;
}
public function DungeoObject():void
{
}
}
class Wall extends DungeonObject
{
public static const TOP:String = "top";
public static const BOTTOM:String = "bottom";
public static const LEFT:String = "left";
public static const RIGHT:String = "right";
public function get type():String
{
return _type;
}
private var _type:String;
public function set type(type:String):void
{
_type = type;
}
override public function get symbol():String
{
if(_type == TOP || _type == BOTTOM)
return "-";
else if(_type == LEFT || _type == RIGHT)
return "|";
else
return " ";
}
public function Wall(type:String):void
{
_type = type;
}
}
class Road extends DungeonObject
{
public function Road():void
{
}
}
class Door extends DungeonObject
{
public function Door():void
{
_symbol = "+";
}
}
class Ground extends DungeonObject
{
public function Ground():void
{
}
}
import flash.geom.Point;
class Character extends DungeonObject
{
public function get position():Point
{
return _position;
}
protected var _position:Point;
public function set position(position:Point):void
{
_position = position;
}
public function get hitpoint():int
{
return _hitpoint;
}
protected var _hitpoint:int
public function set hitpoint(hitpoint:int):void
{
_hitpoint = hitpoint;
}
public function get items():Array
{
return _items;
}
protected var _items:Array
public function set items(items:Array):void
{
_items = items;
}
public function get level():int
{
return _level;
}
protected var _level:int
public function get exp():int
{
return _exp;
}
protected var _exp:int;
public function addExp(exp:int):void
{
_exp += exp;
}
public function Character():void
{
}
public function protec():void
{
_hitpoint--;
}
}
import flash.geom.Point;
class User extends Character
{
public function User():void
{
_level = 1;
_exp = 0;
_items = [":", ")", "[", "!", "?", "="]
}
}
import flash.geom.Point;
class Enemy extends Character
{
public function Enemy():void
{
_level = 0;
_exp = 0;
_items = [];
}
}
class Stairs extends DungeonObject
{
public function Stairs():void
{
_symbol = "%";
}
}