flash on 2010-11-15
キャラクターの自然な移動等
/**
* Copyright TmskSt ( http://wonderfl.net/user/TmskSt )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/8T8p
*/
package {
[SWF(width="465", height="465")]
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
/**
* キャラクターの自然な移動等
*/
public class Main extends Sprite {
private var map:Map;
private var sp:Shape;
private var loader:Loader;
public function Main() {
this.addEventListener(Event.ADDED, init);
}
private function init(e:Event):void {
this.removeEventListener(Event.ADDED, init);
this.loadCompleted(null);
//loader = new Loader();
//loader.contentLoaderInfo.addEventListener(Event.COMPLETE,loadCompleted);
//loader.load(new URLRequest("image.png"));
}
private function loadCompleted(e:Event):void {
var tmp:Sprite = new Sprite();
tmp.graphics.beginFill(0x0);
tmp.graphics.drawCircle(100, 100, 50);
tmp.graphics.drawCircle(320, 220, 25);
tmp.graphics.drawRect(250, 300, 200, 50);
tmp.graphics.drawRect(120, 200, 50, 200);
tmp.graphics.endFill();
var bmd:BitmapData = new BitmapData(465, 465/*loader.width, loader.height*/);
bmd.draw(tmp/*loader*/);
var bitmap:Bitmap = new Bitmap(bmd);
this.addChild(bitmap);
sp = new Shape();
this.addChild(sp);
map = new Map(bitmap, 465, 465, 1);
stage.addEventListener(MouseEvent.CLICK, check);
}
private function check(e:MouseEvent = null):void {
var pp:Point = new Point(450, 50);
var v:Vector.<Position> = map.findPath(pp.x, pp.y, mouseX, mouseY);
sp.graphics.clear();
sp.graphics.moveTo(pp.x, pp.y);
for each(var p:Position in v) {
sp.graphics.lineStyle(5, 0xFFFFFF * Math.random());
sp.graphics.lineTo(p.x, p.y);
}
}
}
}
import flash.display.Bitmap;
import flash.geom.Point;
class Map {
/** */
private var _obstacle:Bitmap;
public function get obstacle():Bitmap { return _obstacle; }
public function set obstacle(value:Bitmap):void {
_obstacle = value;
}
/** */
private var _width:Number;
public function get width():Number { return _width; }
public function set width(value:Number):void {
_width = value;
}
/** */
private var _height:Number;
public function get height():Number { return _height; }
public function set height(value:Number):void {
_height = value;
}
/** */
private var _sfSize:Number;
public function get sfSize():Number { return _sfSize; }
public function set sfSize(value:Number):void {
_sfSize = value;
}
/** */
private var _hSize:Number;
public function get hSize():Number { return _hSize; }
public function set hSize(value:Number):void {
_hSize = value;
}
/** */
private var _vSize:Number;
public function get vSize():Number { return _vSize; }
public function set vSize(value:Number):void {
_vSize = value;
}
private const DIRECTIONS:Vector.<Direction> = Vector.<Direction>([
new Direction(0, "__north_west", -1, -1 ),
new Direction(1, "__west", -1, 0 ),
new Direction(2, "__south_west", -1, 1 ),
new Direction(3, "__south", 0, 1 ),
new Direction(4, "__south_east", 1, 1 ),
new Direction(5, "__east", 1, 0 ),
new Direction(6, "__north_east", 1, -1 ),
new Direction(7, "__north", 0, -1 )
]);
/**
*
* @param obstacleMC
* @param width
* @param height
* @param sfSize
*/
public function Map($obstacle:Bitmap, $width:Number, $height:Number, $sfSize:Number) {
this.obstacle = $obstacle;
this.width = $width;
this.height = $height;
this.sfSize = $sfSize;
this.hSize = Math.floor(width / sfSize);
this.vSize = Math.floor(height / sfSize);
}
/**
*
* @param nowX
* @param nowY
* @param distX
* @param distY
* @return
*/
public function findPath(nowX:Number, nowY:Number, distX:Number, distY:Number):Vector.<Position> {
var result:Vector.<Position> = new Vector.<Position>();
if ((distX < 0 || distX >= this.hSize || distY < 0 || distY >= this.vSize) || (distX == nowX && distY == nowY)) return result;
result.push(new Position(nowX, nowY));
var dist:Position = findStraightPath(nowX, nowY, distX, distY);
if (dist.x != nowX || dist.y != nowY) { result.push(dist); }
nowX = dist.x;
nowY = dist.y;
var prev:Link = new Link(-1, 0x7FFF), counter:int = 0;
while (dist.x != distX || dist.y != distY) {
var next:Direction = this.next(nowX, nowY, distX, distY, prev.distance);
if (next == null) { break; }
nowX += next.offsetX;
nowY += next.offsetY;
if (prev.dir == next.dir) { result.pop(); }
result.push(new Position(nowX, nowY, next.dir));
if (prev.dir != next.dir) {
prev = next;
dist = this.findStraightPath(nowX, nowY, distX, distY);
if (Math.abs(dist.x - nowX) > 1 || Math.abs(dist.y - nowY) > 1) {
result.push(dist);
nowX = dist.x;
nowY = dist.y;
prev = new Link(dist.dir, 0x7FFF);
}
}
if (++counter > 100) { break; }
}
return result;
}
/**
*
* @param nowX
* @param nowY
* @param distX
* @param distY
* @return
*/
private function findStraightPath(nowX:Number, nowY:Number, distX:Number, distY:Number):Position {
var atan:int = Math.round(4 * (1 + Math.atan2(distX - nowX, distY - nowY) / Math.PI) - 1);
if(atan >= 8){ atan -= 8; }
else if (atan < 0) { atan += 8; }
var bp:Bresenham = new Bresenham(nowX, nowY, distX, distY);
var px:Number = nowX, py:Number = nowY, pd:Number = 0, noobs:Boolean = true;
for (var i:int = 0; i < bp.dist1; i++) {
var lastpx:Number = px, lastpy:Number = py;
pd += bp.dist2;
if (pd >= bp.dist1) {
pd -= bp.dist1;
px += bp.addX2;
py += bp.addY2;
}
px += bp.addX1;
py += bp.addY1;
if (this.isObstacle(px, py)) {
distX = lastpx;
distY = lastpy;
break;
}
}
return new Position(distX, distY, atan);
}
/**
*
* @param xx
* @param yy
* @return
*/
private function isObstacle(xx:Number, yy:Number):Boolean {
var pt:Point = this.obstacle.localToGlobal(new Point(xx, yy));
return (this.obstacle.bitmapData.getPixel(pt.x, pt.y) == 0x0);
}
/**
*
* @param x1
* @param y1
* @param x2
* @param y2
* @param ox
* @param oy
* @return
*/
private function distance(x1:Number, y1:Number, x2:Number, y2:Number, ox:Number, oy:Number):Number {
return Math.pow(x2 - x1 - ox, 2) + Math.pow(y2 - y1 - oy, 2);
}
/**
*
* @param nowX
* @param nowY
* @param distX
* @param distY
* @param oldDist
* @return
*/
private function next(nowX:Number, nowY:Number, distX:Number, distY:Number, oldDist:Number):Direction {
var result:Direction;
var minDist:Number = this.distance(nowX, nowY, distX, distY, 0, 0);
if (minDist <= 2 && this.isObstacle(distX, distY)) { return null; }
for (var i:int = 0; i < 8; i++) {
var dir:Direction = DIRECTIONS[i];
if (this.isObstacle(nowX + dir.offsetX, nowY + dir.offsetY)) { continue; }
var dist:Number = this.distance(nowX, nowY, distX, distY, dir.offsetX, dir.offsetY);
if (dist > minDist) { continue; }
minDist = dist;
result = dir;
result.distance = minDist;
}
if (oldDist <= minDist) { return null; }
return result;
}
}
class Bresenham {
/**
*
* @param x1
* @param y1
* @param x2
* @param y2
*/
public function Bresenham(x1:Number, y1:Number, x2:Number, y2:Number) {
var addX:Number = 1;
var dstX:Number = x2 - x1;
if (dstX < 0) { dstX *= -1; addX = -1; }
var addY:Number = 1;
var dstY:Number = y2 - y1;
if (dstY < 0) { dstY *= -1; addY = -1; }
_dist1 = dstX; _dist2 = dstY;
_addX1 = addX; _addX2 = 0;
_addY1 = 0; _addY2 = addY;
if (dstX < dstY) {
_dist1 = dstY; _dist2 = dstX;
_addX1 = 0; _addX2 = addX;
_addY1 = addY; _addY2 = 0;
}
}
private var _dist1:Number;
public function get dist1():Number { return _dist1; }
private var _dist2:Number;
public function get dist2():Number { return _dist2; }
private var _addX1:Number;
public function get addX1():Number { return _addX1; }
private var _addX2:Number;
public function get addX2():Number { return _addX2; }
private var _addY1:Number;
public function get addY1():Number { return _addY1; }
private var _addY2:Number;
public function get addY2():Number { return _addY2; }
}
class Position {
/**
*
* @param $x
* @param $y
* @param $dir
*/
public function Position($x:Number, $y:Number, $dir:Number = -1) {
this.x = $x;
this.y = $y;
this.dir = $dir;
}
private var _x:Number;
public function get x():Number { return _x; }
public function set x(value:Number):void {
_x = value;
}
private var _y:Number;
public function get y():Number { return _y; }
public function set y(value:Number):void {
_y = value;
}
private var _dir:Number;
public function get dir():Number { return _dir; }
public function set dir(value:Number):void {
_dir = value;
}
}
class Link {
/**
*
* @param $dir
* @param $distance
*/
public function Link($dir:int, $distance:uint) {
this.dir = $dir;
this.distance = $distance;
}
private var _dir:int;
public function get dir():int { return _dir; }
public function set dir(value:int):void {
_dir = value;
}
private var _distance:uint;
public function get distance():uint { return _distance; }
public function set distance(value:uint):void {
_distance = value;
}
}
class Direction extends Link {
/**
*
* @param $dir
* @param $prop
* @param $offsetX
* @param $offsetY
*/
public function Direction($dir:int, $prop:String, $offsetX:int, $offsetY:int) {
super($dir, 0);
_prop = $prop;
_offsetX = $offsetX;
_offsetY = $offsetY;
}
private var _prop:String;
public function get prop():String { return _prop; }
private var _offsetX:int;
public function get offsetX():int { return _offsetX; }
private var _offsetY:int;
public function get offsetY():int { return _offsetY; }
}