等角投エッシャー
----------------------------------------------------------------------------
* 等角投影オブジェクトでペンローズの階段をつくる。
*
* [related link]
* css3 penrose stair
* http://jsdo.it/9re/penrose_stair
*
* AdvancED ActionScript 3.0 Animation (詳解 ActionScript 3.0アニメーション)
* http://www.friendsofed.com/book.html?isbn=9781430216087
* http://www.oreilly.co.jp/books/9784873114378/
* ----------------------------------------------------------------------------
/**
* Copyright o8que ( http://wonderfl.net/user/o8que )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/dtQq
*/
/* ----------------------------------------------------------------------------
* 等角投影オブジェクトでペンローズの階段をつくる。
*
* [related link]
* css3 penrose stair
* http://jsdo.it/9re/penrose_stair
*
* AdvancED ActionScript 3.0 Animation (詳解 ActionScript 3.0アニメーション)
* http://www.friendsofed.com/book.html?isbn=9781430216087
* http://www.oreilly.co.jp/books/9784873114378/
* ----------------------------------------------------------------------------
*/
package {
import flash.display.Sprite;
public class Main extends Sprite {
private static const BOX_SIZE:int = 30; // 箱ブロックのサイズ
private static const BOX_COLS:int = 9; // 上の列数
private static const BOX_ROWS:int = 10; // 右の行数
private static const LINE_DEC:int = 4; // 下の列数・左の行数の減分
private var _boxList:Vector.<IsoBox>;
public function Main() {
graphics.beginFill(0x000000);
graphics.drawRect(0, 0, 465, 465);
graphics.endFill();
_boxList = new Vector.<IsoBox>();
var sprite:Sprite = addChild(new Sprite()) as Sprite;
sprite.x = 187;
sprite.y = 400;
var height:Number = 200;
var i:int;
var heightIncrease:Number = (BOX_SIZE * LINE_DEC) / (2 * (BOX_COLS + BOX_ROWS - LINE_DEC) - 4) / IsometricPoint.Y_CORRECT;
// 上
for (i = 0; i < BOX_COLS; i++, height += heightIncrease) {
_boxList.push(new IsoBox(i * BOX_SIZE, 0, BOX_SIZE, height));
}
// 右
for (i = 1; i < BOX_ROWS; i++, height += heightIncrease) {
_boxList.push(new IsoBox((BOX_COLS - 1) * BOX_SIZE, i * BOX_SIZE, BOX_SIZE, height));
}
// 下
for (i = BOX_COLS - 2; i >= LINE_DEC; i--, height += heightIncrease) {
_boxList.push(new IsoBox(i * BOX_SIZE, (BOX_ROWS - 1) * BOX_SIZE, BOX_SIZE, height));
}
// 左
for (i = BOX_ROWS - 2; i >= LINE_DEC + 1; i--, height += heightIncrease) {
_boxList.push(new IsoBox(LINE_DEC * BOX_SIZE, i * BOX_SIZE, BOX_SIZE, height));
}
// Zソートして表示
_boxList.sort(IsoBox.compareDepth);
for (i = 0; i < _boxList.length; i++) { sprite.addChild(_boxList[i]); }
}
}
}
//package {
import flash.display.Sprite;
//public
class IsoBox extends Sprite {
private var _position:IsometricPoint;
private var _height:Number;
public function get topX():Number { return _position.x; }
public function get topY():Number { return -_height; }
public function get topZ():Number { return _position.z; }
public function IsoBox(worldX:Number, worldZ:Number, size:int, height:Number) {
_position = IsometricPoint.createFromWorldPos(worldX, 0, worldZ);
x = _position.screenX;
y = _position.screenY;
_height = height;
var h:Number = _height * IsometricPoint.Y_CORRECT;
// 上面
graphics.beginFill(0xffffff);
graphics.lineStyle(0, 0x888888, 0.5);
graphics.moveTo( -size, -h);
graphics.lineTo(0, -size * 0.5 - h);
graphics.lineTo(size, -h);
graphics.lineTo(0, size * 0.5 - h);
graphics.lineTo( -size, -h);
graphics.endFill();
// 左側面
graphics.beginFill(0x888888);
graphics.lineStyle();
graphics.moveTo( -size, -h);
graphics.lineTo(0, size * 0.5 - h);
graphics.lineTo(0, size * 0.5);
graphics.lineTo( -size, 0);
graphics.lineTo( -size, -h);
graphics.endFill();
// 右側面
graphics.beginFill(0xbbbbbb);
graphics.lineStyle();
graphics.moveTo(0, size * 0.5 - h);
graphics.lineTo(size, -h);
graphics.lineTo(size, 0);
graphics.lineTo(0, size * 0.5);
graphics.lineTo(0, size * 0.5 - h);
graphics.endFill();
}
// Zソート用比較メソッド
public static function compareDepth(a:IsoBox, b:IsoBox):Number {
return IsometricPoint.compareDepth(a._position, b._position);
}
}
//}
//package {
//public
class IsometricPoint {
public static const Y_CORRECT:Number = Math.cos( -30 * Math.PI / 180) * Math.SQRT2;
// ワールド座標値
private var _worldX:Number;
private var _worldY:Number;
private var _worldZ:Number;
// 画面座標値
private var _screenX:Number;
private var _screenY:Number;
private var _screenZ:Number;
private var _isInvalidWorldPos:Boolean; // ワールド座標値を更新する必要があるかどうか
private var _isInvalidScreenPos:Boolean; // 画面座標値を更新する必要があるかどうか
// ワールド座標値からインスタンスを作成する
public static function createFromWorldPos(x:Number = 0, y:Number = 0, z:Number = 0):IsometricPoint {
return new IsometricPoint(true, x, y, z);
}
// 画面座標値からインスタンスを作成する
public static function createFromScreenPos(x:Number = 0, y:Number = 0):IsometricPoint {
return new IsometricPoint(false, x, y, 0);
}
public function IsometricPoint(isWorldPos:Boolean, x:Number, y:Number, z:Number) {
if (isWorldPos) {
_worldX = x;
_worldY = y;
_worldZ = z;
updateScreenPos();
}else {
_screenX = x;
_screenY = y;
updateWorldPos();
}
_isInvalidWorldPos = false;
_isInvalidScreenPos = false;
}
private static const COS30:Number = Math.cos( -30 * Math.PI / 180);
private static const COS45:Number = Math.cos(45 * Math.PI / 180);
private function updateWorldPos():void {
_worldX = _screenY + _screenX * 0.5;
_worldY = 0;
_worldZ = _screenY + _screenZ * 0.5;
_screenZ = (_worldX + _worldZ) * COS30;
}
private function updateScreenPos():void {
_screenX = _worldX - _worldZ;
_screenY = _worldY * IsometricPoint.Y_CORRECT + (_worldX + _worldZ) * 0.5;
_screenZ = (_worldX + _worldZ) * COS30 - _worldY * COS45;
}
// Zソート用比較メソッド
public static function compareDepth(a:IsometricPoint, b:IsometricPoint):Number {
a.validateWorldPos(); a.validateScreenPos();
b.validateWorldPos(); b.validateScreenPos();
if (a._screenZ < b._screenZ) { return -1; }
if (a._screenZ > b._screenZ) { return 1; }
return 0;
}
// ワールド座標値を有効にする
private function validateWorldPos():void {
if (_isInvalidWorldPos) {
updateWorldPos();
_isInvalidWorldPos = false;
}
}
// 画面座標値を有効にする
private function validateScreenPos():void {
if (_isInvalidScreenPos) {
updateScreenPos();
_isInvalidScreenPos = false;
}
}
public function get x():Number { validateWorldPos(); return _worldX; }
public function get y():Number { validateWorldPos(); return _worldY; }
public function get z():Number { validateWorldPos(); return _worldZ; }
public function get screenX():Number { validateScreenPos(); return _screenX; }
public function get screenY():Number { validateScreenPos(); return _screenY; }
public function set x(value:Number):void { validateWorldPos(); _worldX = value; _isInvalidScreenPos = true; }
public function set y(value:Number):void { validateWorldPos(); _worldY = value; _isInvalidScreenPos = true; }
public function set z(value:Number):void { validateWorldPos(); _worldZ = value; _isInvalidScreenPos = true; }
public function set screenX(value:Number):void { validateScreenPos(); _screenX = value; _isInvalidWorldPos = true; }
public function set screenY(value:Number):void { validateScreenPos(); _screenY = value; _isInvalidWorldPos = true; }
}
//}