forked from: 3D VOCALOID RUNS!

by tepe forked from 3D VOCALOID RUNS! (diff: 454)
♥0 | Line 551 | Modified 2014-06-25 11:32:30 | MIT License
play

ActionScript3 source code

/**
 * Copyright tepe ( http://wonderfl.net/user/tepe )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/oUf0
 */

// forked from daniwell's 3D VOCALOID RUNS!
package  
{
    import alternativa.engine3d.core.Camera3D;
    import alternativa.engine3d.core.Object3D;
    import alternativa.engine3d.core.Resource;
    import alternativa.engine3d.core.View;
    import alternativa.engine3d.lights.AmbientLight;
    import alternativa.engine3d.lights.DirectionalLight;
    import alternativa.engine3d.lights.OmniLight;
    import alternativa.engine3d.materials.TextureMaterial;
    import alternativa.engine3d.primitives.Plane;
    import alternativa.engine3d.resources.BitmapTextureResource;
    import alternativa.engine3d.materials.TextureMaterial;
    import alternativa.types.Texture;
    import flash.display.*;
    import flash.display3D.Context3DRenderMode;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.geom.Point;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.system.LoaderContext;
    import flash.text.TextField;
    import flash.text.TextFormat;
    import flash.ui.Keyboard;
    import flash.text.*;
    import flash.geom.*;
    
    public class ModelRun extends Sprite 
    {
        // MMD でモーション付けて、Blender のプラグインで読み込んで COLLADA 書き出しするだけ
        // 但しモーションに IK は使えない
        private const PATH_DAEIDLE :Array = ["http://aidn.jp/_wonderfl/vr/miku_idle.dae",    "http://aidn.jp/_wonderfl/vr/rin_idle.dae",    "http://aidn.jp/_wonderfl/vr/len_idle.dae"];
        private const PATH_DAERUN  :Array = ["http://aidn.jp/_wonderfl/vr/miku_run.dae",     "http://aidn.jp/_wonderfl/vr/rin_run.dae",     "http://aidn.jp/_wonderfl/vr/len_run.dae"];
        private const PATH_TEXTURE :Array = ["http://aidn.jp/_wonderfl/vr/miku_texture.png", "http://aidn.jp/_wonderfl/vr/rin_texture.png", "http://aidn.jp/_wonderfl/vr/len_texture.png"];
        
        private const CAMERA_DISTANCE :Number = 600;
        private const BOX_NUMS        :int    = 30;
        
        private var _texture :BitmapData;
        private var _daeIdle :XML;
        private var _daeRun  :XML;
        
        private var _n :int = int(Math.random() * 3);
        
        private var _stage3D :Stage3D;
        private var _camera  :Camera3D;
        private var _scene   :Object3D;
        
        private var _model    :ColladaModel;
        private var _shadow   :Plane;
        private var _boxes    :/*CustomBox*/Array = [];
        private var _keyFlags :/*Boolean*/Array = [];
        
        private var _t      :Number = 0;
        private var _rot    :Number = 0;
        private var _rotTmp :Number = -90;
        
        private var _cameraZ :Number = 50;
        
        private var _tfLoading :TextField;
        
        private var cmap:CraftMap;// = new CraftMap();
        private var tf:TextField;
        
        public function ModelRun () {
            
            stage.scaleMode = "noScale";
            stage.align     = "TL";

            // Now Loading
            _tfLoading = addChild(new TextField()) as TextField;
            _tfLoading.defaultTextFormat = new TextFormat("_sans", 42, 0x999999, true);
            _tfLoading.autoSize = "left"; _tfLoading.text = "NOW LOADING...";
            stage.addEventListener(Event.ENTER_FRAME, _enterFrame);//メインループ

            // Stage3D
            _stage3D = stage.stage3Ds[0];
            _stage3D.addEventListener(Event.CONTEXT3D_CREATE, _contextCreate);// #01
            _stage3D.requestContext3D(Context3DRenderMode.AUTO);
            
            tf = new TextField();
            addChild(tf);
            tf.background = true;
            tf.text = "test\n";
        }
        
        // #01
        private function _contextCreate ( evt :Event ) :void {
            tf.appendText("1\n");
            _stage3D.removeEventListener(Event.CONTEXT3D_CREATE, _contextCreate);// #01
            
            // IDLE 時データ読み込み #02
            var ul :URLLoader = new URLLoader(); ul.addEventListener(Event.COMPLETE, _loadCompleteIdle); ul.load(new URLRequest(PATH_DAEIDLE[_n]));
        }
        
        // #02
        private function _loadCompleteIdle ( evt :Event ) :void  {
            tf.appendText("2\n");
            _daeIdle = XML(URLLoader(evt.target).data);
            
            // RUN 時データ読み込み #03
            var ul :URLLoader = new URLLoader(); ul.addEventListener(Event.COMPLETE, _loadCompleteRun); ul.load(new URLRequest(PATH_DAERUN[_n]));
        }
        
        // #03
        private function _loadCompleteRun ( evt :Event ) :void {
            tf.appendText("3\n");
            _daeRun = XML(URLLoader(evt.target).data);
            
            var l :Loader = new Loader();
            l.contentLoaderInfo.addEventListener(Event.COMPLETE, _loadCompleteTexture);// #04
            l.load(new URLRequest(PATH_TEXTURE[_n]), new LoaderContext(true));
        }
        
        // #04
        private function _loadCompleteTexture ( evt :Event ) :void {
            tf.appendText("4\n");
            _tfLoading.visible = false;
            _texture = Bitmap(evt.target.content).bitmapData;//テクスチャ画像
            
            _scene  = new Object3D();
            _camera = new Camera3D(1, 10000);
            
            _camera.view = new View(stage.stageWidth, stage.stageHeight);
            _camera.view.hideLogo();//ロゴ非表示 
            addChild(_camera.view);
            //addChild(_camera.diagram);//パフォーマンス表示
            
            _camera.rotationX = MathUtil.toRad(-90);
            _camera.x = 0; _camera.y = 0; _camera.z = 250;
            _camera.fov = 1.8;
            
            _scene.addChild(_camera);
            
            //cmap.initMap(100,100,100); 
            cmap = new CraftMap();
            cmap.initMap(100,100,100);
            
            tf.appendText("\n");
            //var n:int = cmap.sx;
            //tf.appendText(n.toString()+"\n");
            //tf.appendText(cmap.sx.toString()+"\n");
            // Box
 /*           for (var i :int = 0; i < BOX_NUMS; i ++){ 
            //for (var i :int = 0; i < cmap.sx; i ++){ 
                //if(100<i)break;
                //_boxes.push(new CustomBox(_scene));
                var b:Block = new Block(_scene);
                b.setColor(0xff0000);
                var k:int = Math.random()*10;
                b.setPos(i*200,k*100,-250);
                _boxes.push(b);
            }
            */
            var bmp3:BitmapData = tex();
            var ar:Array = new Array();
            var texAr:Array = new Array();
            for(i=0;i<16;i++){
                for(j=0;j<3;j++){
                    var bm4:BitmapData = func2(bmp3,i*16,j*16,16,16);
                    texAr.push(new Texture(bm4));  
                    //ar.push(new TextureMaterial(texAr[i*16+j],1,true,true));
                }
            }
///*            
            for(var i:int=0;i<cmap.sx;i++){
                //if(5<i)b
                for(var j:int=0;j<cmap.sy;j++){
                    for(var k:int=0;k<cmap.sz;k++){
                        if(cmap.getBlock(i,j,k)==0)continue;
                        var b:Block = new Block(_scene);
                        var n:int = cmap.getBlock(i,j,k);
                        if(n!=0){
                            //b.setMaterialToSurface(ar[n*3],"top");
                        }
                        
                        
                        if(cmap.getBlock(i,j,k)==9)b.setColor(0x0000ff);
                        else b.setColor(0xff0000);
                        
                        b.setPos(i*100,j*100,k*100);
                        _boxes.push(b); 
                    }

                }

            }
//*/

            
            // Model
            _model = new ColladaModel(_stage3D, _scene);
            _model.init(_daeIdle, _texture, 0, 0, -300, 100);
            _model.addAnimation(_daeIdle, 0);
            _model.addAnimation(_daeRun,  1);
            
            
            // Shadow
            var bmd :BitmapData = new BitmapData(128, 128, false, 0x0);
            var sp :Shape = new Shape(); sp.graphics.beginFill(0xffffff); sp.graphics.drawCircle(64, 64, 64); sp.graphics.endFill();
            bmd.draw(sp);
            
            var material :TextureMaterial = new TextureMaterial(new BitmapTextureResource(new BitmapData(128, 128, false, 0x333333)), new BitmapTextureResource(bmd));
            material.alphaThreshold = 1;
            
            _shadow = new Plane(100, 100);
            _shadow.setMaterialToAllSurfaces(material);
            _shadow.z = _model.z;
            _shadow.y = _model.y;
            _scene.addChild(_shadow);
            
            
            // Light
            var aLight :AmbientLight = new AmbientLight(0xffffff);
            aLight.intensity = 0.5;
            _scene.addChild(aLight);
            
            var oLight :OmniLight = new OmniLight(0xffffff, 1000, 10000);
            oLight.x = 100; oLight.y = 200; oLight.z = 200;
            _scene.addChild(oLight);
            
            var dLight :DirectionalLight = new DirectionalLight(0xffffff);
            dLight.x = 0; dLight.y = - 100; dLight.z = 100; dLight.intensity = 0.5; 
            _scene.addChild(dLight);
            
            
            // Resource
            for each (var resource :Resource in _scene.getResources(true)) resource.upload(_stage3D.context3D);
            
            
            // Event
            stage.addEventListener(KeyboardEvent.KEY_DOWN, _keyDown);
            stage.addEventListener(KeyboardEvent.KEY_UP,   _keyUp);
            
            stage.addEventListener(Event.RESIZE, _resize);
            _resize();
        }
        /* RESIZE */
        private function _resize ( evt :Event = null ) :void {
            _camera.view.width  = stage.stageWidth;
            _camera.view.height = stage.stageHeight;
        }
        /* KEY DOWN & KEY UP */
        private function _keyDown ( evt :KeyboardEvent ) :void { _keyFlags[evt.keyCode] =  true; if (evt.keyCode == Keyboard.UP) _model.changeAnimation(1, 1.8); }
        private function _keyUp   ( evt :KeyboardEvent ) :void { _keyFlags[evt.keyCode] = false; if (evt.keyCode == Keyboard.UP) _model.changeAnimation(0, 1.4); }
        
//メインループ
        private function _enterFrame ( evt :Event ) :void {
            // loading
            if (! _scene) {
                _tfLoading.visible = ! _tfLoading.visible;
                return;
            }
            
            if (_keyFlags[Keyboard.LEFT])  _model.rotationZ += MathUtil.toRad(5);//左旋回
            if (_keyFlags[Keyboard.RIGHT]) _model.rotationZ -= MathUtil.toRad(5);//右旋回
            
            if (_keyFlags[Keyboard.UP]) {//キャラ前進
                
                _model.moveFront(16);
                
                var p :Point, n :int = 0;
                var l :int = _boxes.length;
                /*
                for (var i :int = 0; i < l; i ++) {//衝突判定
                    
                    p = _boxes[i].hitTest(_model.x, _model.y, _model.prePosition.x, _model.prePosition.y);//当たり判定
                    if (p) {
                        _model.x = p.x;
                        _model.y = p.y;
                        i = -1; n ++; if (10 < n) break;
                    }
                }*/
                _shadow.x = _model.x;
                _shadow.y = _model.y;
            }
            
            _model.updataAnimation();//キャラのモーション
            
            // カメラの回転
                 if (_keyFlags[Keyboard.A]) _rotTmp  += 8;
            else if (_keyFlags[Keyboard.D]) _rotTmp  -= 8;
            else if (_keyFlags[Keyboard.W]) _cameraZ += 20;
            else if (_keyFlags[Keyboard.S]) _cameraZ -= 20;
            else if(_keyFlags[Keyboard.Q]) aa();
            _updateCameraPosition();//カメラ位置更新
            _camera.render(_stage3D);//描画
        }
        
        private function aa():void{
            _rotTmp = _model.rotationZ-_rot;
        }

        
        //カメラ位置更新
        private function _updateCameraPosition ( ) :void {
            
            _rot += (_rotTmp - _rot) / 6;
            
            var px :Number = _model.x + CAMERA_DISTANCE * Math.cos(MathUtil.toRad(_rot));
            var py :Number = _model.y + CAMERA_DISTANCE * Math.sin(MathUtil.toRad(_rot));
            
            _camera.x += (px - _camera.x) / 6;
            _camera.y += (py - _camera.y) / 6;
            _camera.z += (_cameraZ - _camera.z) / 6;
            
            _camera.x += Math.sin(_t / 210) * 11;
            _camera.y += Math.sin(_t / 300) * 9;
            _t += 11;
            
            var p :Point, n :int = 0;
            var l :int = _boxes.length;

            _camera.lookAt(_model.x, _model.y, _model.z);//対象方向に向ける
        }
        
        
        //ビットマップ切り出し
        private function func2(res:BitmapData,x:int,y:int,w:int,h:int):BitmapData{
            var dat:BitmapData = new BitmapData(w,h);
            var rect:Rectangle = new Rectangle(x,y,w,h);
            var ar:Vector.<uint> = res.getVector(rect);
            
            for(var i:int=0;i<w;i++){
                for(var j:int=0;j<h;j++){
                    var col:int = ar[i+j*w];
                    dat.setPixel32(i,j,col);
                }

            }

            return dat;
        }
                
        private function tex():BitmapData{
            initTexMap();
            var dat:BitmapData = new BitmapData(16*16,16*3,false,0xffffff);
            dat.lock();
            for ( var i:int = 1; i < 16; i++) {//ブロックの種類
                //var br:int = 255 - ((Math.random() * 96) | 0);
                for ( var y:int = 0; y < 16 * 3; y++) {
                    for ( var x:int = 0; x < 16; x++) {
                        var col:int = texmap[x + y * 16 + i * 256 * 3];
                        dat.setPixel32(x+(16*i),y,col);
                    }
                }
            }
            dat.unlock();
            return dat;
            

        }

        
        //テクスチャデータ
        private var texmap: Vector.<int> = new Vector.<int>(16 * 16 * 3 * 16, true);        
        //テクスチャ生成
        private function initTexMap():void {
            for ( var i:int = 1; i < 16; i++) {//ブロックの種類
                var br:int = 255 - ((Math.random() * 96) | 0);
                for ( var y:int = 0; y < 16 * 3; y++) {
                    for ( var x:int = 0; x < 16; x++) {
                        var color:int = 0x966C4A;
                        if (i == 4)color = 0x7F7F7F;
                        
                        if (i != 4 || ((Math.random() * 3) | 0) == 0) {
                            br = 255 - ((Math.random() * 96) | 0);
                        }
                        
                        if ((i == 1 && y < (((x * x * 3 + x * 81) >> 2) & 3) + 18)) {
                            color = 0x6AAA40;
                        }
                        else if ((i == 1 && y < (((x * x * 3 + x * 81) >> 2) & 3) + 19)) {
                            br = br * 2 / 3;
                        }
                        
                        if (i == 7) {//木
                            color = 0x675231;
                            if (x > 0 && x < 15
                                && ((y > 0 && y < 15) || (y > 32 && y < 47))) {
                                color = 0xBC9862;
                                var xd:int = (x - 7);
                                var yd:int = ((y & 15) - 7);
                                if (xd < 0)
                                xd = 1 - xd;
                                if (yd < 0)
                                yd = 1 - yd;
                                if (yd > xd)
                                xd = yd;

                                br = 196 - ((Math.random() * 32) | 0) + xd % 3 * 32;
                            } else if (((Math.random() * 2) | 0) == 0) {
                                br = br * (150 - (x & 1) * 100) / 100;
                            }
                        }

                        if (i == 5) {//レンガ
                            color = 0xB53A15;
                            if ((x + (y >> 2) * 4) % 8 == 0 || y % 4 == 0) {
                                color = 0xBCAFA5;
                            }
                        }
                        if(i == 10){
                            color = 0xeecc99;
                        }

                        
                        if (i == 9) {//水
                            color = 0x4040ff;
                        }
                        var brr:int = br;
                        if (y >= 32)
                        brr /= 2;

                        if (i == 8) {//葉っぱ
                            color = 0x50D937;
                            if (((Math.random() * 2) | 0) == 0) {
                                color = 0;
                                brr = 255;
                            }
                        }

                        var col:int = (((color >> 16) & 0xff) * brr / 255) << 16
                        | (((color >> 8) & 0xff) * brr / 255) << 8
                        | (((color) & 0xff) * brr / 255);
                        texmap[x + y * 16 + i * 256 * 3] = col;//ドットカラー
                    }//for
                }//for
            }//for
        }//function
        
    }
}

class CraftMap{
    //マップサイズ
    private var _sx:int=14;
    private var _sy:int=14; 
    private var _sz:int=2;
    private var _waterlevel:int;
    //マップデータ
    public var map:Vector.<int>;
    
    public function CraftMap(){ 
         map = new Vector.<int>(128 * 64 * 64, true);
         //initMap();
    }
    
    public function getBlock(x:int,y:int,z:int):int{
        var x2:int = x%_sx;
        var y2:int = y%_sy;
        var z2:int = z%_sz;
        var i:int = z2*_sz + y2*_sy + x2;
        return map[i];
    }
    
    public function setBlock(x:int,y:int,z:int,t:int=0):void{
        var x2:int = x%_sx;
        var y2:int = y%_sy;
        var z2:int = z%_sz;
        var i:int = z2*_sz + y2*_sy + x2;
        map[i]=t;
    }
    
    public function get sx():int{
        return _sx;
    }
    public function get sy():int{
        return _sy;
    }
    public function get sz():int{
        return _sz;
    }



    
    public function initMap(s: int = 0, w: int = 0, f: int = 0): void {
            //var noise: BitmapData = new BitmapData(_sx, _sy, false); 
            //noise.lock();
            var p1: Point = new Point(), p2: Point = new Point();
            var offset: Array = [p1, p2];
            var seed: int = s || Math.random() * 0xFFFFFF;
            //水位
            var waterlevel: int = w || 19 + Math.random() * 10;
            _waterlevel = waterlevel;
            var flora: int = f || Math.random() * 10000;

            for ( var z: int = 0; z < _sz; z++){
                // 擬似PerlinNoise3D
                p1.x = z, p2.x = -z;
                //noise.perlinNoise(_sx/2, _sy/2, 2, seed, false, true, 7, true, offset);//ノイズ生成
                for ( var x: int = 0; x < _sx; x++){
                    for ( var y: int = 0; y < _sy; y++){
                        var i:int = z*_sy*_sx + y*_sx + x;
                        map[i] = 4; //(Math.random() * 16) | 0;
                        if (Math.random() > 0.8){
                            map[i] = 0;//ブロックなし
                        }
                    }
                }
            }
            
/*           
            //noise.dispose();
            for( z = 0; z < _sz; z++){
                for( x = 0; x < _sx; x++){
                    for( y = 0; y < _sy; y++){

                        i = z*_sy*_sx + y*_sx + x;//z << 12 | y << 6 | x;
                        if (map[i] == 0 && y>64-waterlevel){ //ブロックがなくて海抜より低い位置は水ブロックを設置
                            map[i] = 9;//水ブロック
                        }
                        else
                        if(map[i] != 0){
                            var j:int = z*_sy*_sx + (y-1)*_sx + x;
                            if(map[j] == 0)//ブロックの上に空間があれば
                                map[i] = 1;//草ブロック
                            else{//上にブロックがある場合
                               j = z*_sz + (y-2)*_sy + x;
                               if(map[j] == 0)//深さ2ブロックまでは土ブロックとする
                                   map[i] = 2;//土ブロック
                               else map[i] = Math.random()*3+2;//深さ2ブロック以降
                           }
                        }
                    }
                }
            }
///*
            for ( var b: int = 0; b < flora; b++ ){
               x = Math.random()*_sx;
               y = Math.random()*_sy;
               z = Math.random()*_sz;

               i = z*_sy*_sx + (y+1)*_sx + x;
               var c:int = map[i];
               i = z*_sy*_sx + y*_sx + x;
               var c2:int = map[i];
               if (c2 != 0){
                   y--;
                   i = z << 12 | y << 6 | x;
                   c2 = map[i];
                   while (c2 != 0 && y>1){
                      y--;
                       i = z << 12 | y << 6 | x;
                       c=c2;
                       c2 = map[i];
                      //c2 = 0;
                  }
               }
               if (c2==0 && c!=9 && c!=0) map[i] = 8;
           }
*/
        }
}







import alternativa.engine3d.animation.AnimationClip;
import alternativa.engine3d.animation.AnimationController;
import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.loaders.ParserCollada;
import alternativa.engine3d.materials.TextureMaterial;
import alternativa.engine3d.materials.VertexLightTextureMaterial;
import alternativa.engine3d.objects.Mesh;
import alternativa.engine3d.primitives.Box;
import alternativa.engine3d.resources.BitmapTextureResource;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Stage3D;
import flash.geom.*;
import mx.core.BitmapAsset;


/* -----------------------------------------------------------------
 * ColladaModel
 */
class ColladaModel extends Object3D
{
    private var _stage3D  :Stage3D;
    private var _material :TextureMaterial;
    
    private var _animationController :AnimationController;
    private var _animationClips      :/*AnimationClip*/Array = [];
    
    private var _textureResources :/*BitmapTextureResource*/Array = [];
    
    private var _pre :Point;
    
    public function ColladaModel ( stage3D :Stage3D, parent :Object3D = null )  {
        _stage3D = stage3D;
        if (parent) parent.addChild(this);
    }
    
    public function init ( dae :*, texture :*, x :Number = 0, y :Number = 0, z :Number = 0, scale :Number = 1 ) :void {
        
        if (! (dae is XML)) dae = new XML(dae);
        if (texture is Bitmap || texture is BitmapAsset) texture = texture.bitmapData;
        
        this.x = x; this.y = y; this.z = z;
        scaleX = scaleY = scaleZ = scale;
        _pre = new Point(x, y);
        
        // Parser
        var parser :ParserCollada = new ParserCollada();
        parser.parse(dae);
        
        // Texture
        var texResource :BitmapTextureResource = new BitmapTextureResource(texture);
        texResource.upload(_stage3D.context3D);
        var txtRes :BitmapTextureResource = texResource;
        _material = new TextureMaterial(txtRes);
        
        // Mesh
        for each (var obj :Object3D in parser.objects) {
            var mesh :Mesh = obj as Mesh;
            if (mesh) { mesh.setMaterialToAllSurfaces(_material); addChild(obj); }
        }
    }
    
    /* 前進 */
    public function moveFront ( d :Number ) :void {
        _pre.x = this.x;
        _pre.y = this.y;
        
        var radZ :Number = this.rotationZ;
        this.x += d * Math.sin(radZ);
        this.y -= d * Math.cos(radZ);
    }
    
    /* アニメーションのアップデート */
    public function updataAnimation ( ) :void { _animationController.update(); }
    
    /* アニメーションを追加 */
    public function addAnimation ( dae :*, id :int ) :void {
        if (! (dae is XML)) dae = new XML(dae);
        
        // Animation Clip
        var animationClip :AnimationClip = ParserCollada.parseAnimation(dae);
        animationClip.attach(this, true);
        
        _animationClips[id] = animationClip;
        
        // Animation Controller
        if (! _animationController) {
            _animationController      =  new AnimationController();
            _animationController.root = animationClip;
        }
    }
    /* アニメーションの切り替え */
    public function changeAnimation ( id :int, speed :Number = 1.0, loop :Boolean = true ) :void {
        _animationClips[id].speed = speed;
        _animationClips[id].loop  = loop;
        _animationController.root = _animationClips[id];
    }
    
    public function get prePosition ( ) :Point { return _pre; }
}

/* -----------------------------------------------------------------
 * Box
 */
class CustomBox extends Box
{
    private var _p :/*Point*/Array = [];
    
    public function CustomBox ( parent :Object3D = null ) {
        
        var w :int = MathUtil.rand(100, 500);
        var l :int = MathUtil.rand(100, 500);//奥行き
        var h :int = MathUtil.rand(100, 2500);//高さ
        
        super(w, l, h);
        
        const RANGE :int = 3000;
        if (Math.random() < 0.5) {
            x = MathUtil.rand(-RANGE, RANGE);
            y = (Math.random() < 0.5) ? MathUtil.rand(-RANGE, -l/2) : MathUtil.rand(l/2, RANGE);
        } else {
            x = (Math.random() < 0.5) ? MathUtil.rand(-RANGE, -w/2) : MathUtil.rand(w/2, RANGE);
            y = MathUtil.rand(-RANGE, RANGE);
        }
        
        
        z = - 300 + h /2;
        setMaterialToAllSurfaces(new VertexLightTextureMaterial(new BitmapTextureResource(new BitmapData(8, 8, false, 0xffffff))));
        if (parent) parent.addChild(this);
        
        var rad :Number = rotationZ = MathUtil.toRad(MathUtil.rand(0, 45));
        var cw :Number = (w + 90) / 2;
        var cl :Number = (l + 90) / 2;
        _p[0] = new Point(x + (-cw * Math.cos(rad) + cl * Math.sin(rad)), y + (-cw * Math.sin(rad) - cl * Math.cos(rad)));
        _p[1] = new Point(x + (-cw * Math.cos(rad) - cl * Math.sin(rad)), y + (-cw * Math.sin(rad) + cl * Math.cos(rad)));
        _p[2] = new Point(x + ( cw * Math.cos(rad) - cl * Math.sin(rad)), y + ( cw * Math.sin(rad) + cl * Math.cos(rad)));
        _p[3] = new Point(x + ( cw * Math.cos(rad) + cl * Math.sin(rad)), y + ( cw * Math.sin(rad) - cl * Math.cos(rad)));
        
        /*
        // Show HitArea
        var zz :Number = z - h / 2;
        var vec :Vector.<Vector3D> = new <Vector3D>[
            new Vector3D(_p[0].x, _p[0].y, zz),
            new Vector3D(_p[1].x, _p[1].y, zz),
            new Vector3D(_p[2].x, _p[2].y, zz),
            new Vector3D(_p[3].x, _p[3].y, zz),
            new Vector3D(_p[0].x, _p[0].y, zz)
        ];
        var wire :WireFrame = WireFrame.createLineStrip(vec, 0x999999, 1, 2);
        parent.addChild(wire);
        //*/
    }
    
    //当たり判定
    public function hitTest (nx :Number, ny :Number, px :Number, py :Number) :Point {
        
        var f :Boolean = MathUtil.boxContainsPos(_p[0].x, _p[0].y, _p[1].x, _p[1].y, _p[2].x, _p[2].y, _p[3].x, _p[3].y, nx, ny);
        if (! f) return null;
        
        for (var i :int = 0; i < 4; i ++) {
            
            var p1x :Number = _p[i].x;
            var p1y :Number = _p[i].y;
            var p2x :Number = _p[(i+1)%4].x;
            var p2y :Number = _p[(i+1)%4].y;
            
            f = MathUtil.intersectLineSegment(px, py, nx, ny, p1x, p1y, p2x, p2y);
            if (f) {
                var pt :Point = MathUtil.getCrossPoint(p1x, p1y, p2x, p2y, nx, ny);
                return new Point(pt.x + (pt.x - nx) * 0.2, pt.y + (pt.y - ny) * 0.2);
            }
        }
        return null;
    }
    
}



class Block extends Box{
    private var _p :/*Point*/Array = [];
    
    public function setPos(px:Number=0,py:Number=0,pz:Number=0):void{
        x = px;
        y = py;
        z = pz;
        updateHitPos();
    }
    
    private function updateHitPos():void{
        var w:int = 100;
        
        var rad :Number = rotationZ = 0;//MathUtil.toRad(MathUtil.rand(0, 45));
        var cw :Number = (w + 90) / 2;
        var cl :Number = (w + 90) / 2;
        _p[0] = new Point(x + (-cw * Math.cos(rad) + cl * Math.sin(rad)), y + (-cw * Math.sin(rad) - cl * Math.cos(rad)));
        _p[1] = new Point(x + (-cw * Math.cos(rad) - cl * Math.sin(rad)), y + (-cw * Math.sin(rad) + cl * Math.cos(rad)));
        _p[2] = new Point(x + ( cw * Math.cos(rad) - cl * Math.sin(rad)), y + ( cw * Math.sin(rad) + cl * Math.cos(rad)));
        _p[3] = new Point(x + ( cw * Math.cos(rad) + cl * Math.sin(rad)), y + ( cw * Math.sin(rad) - cl * Math.cos(rad)));
    }

    public function setColor(c:uint):void{
        setMaterialToAllSurfaces(new VertexLightTextureMaterial(new BitmapTextureResource(new BitmapData(8, 8, false, c))));
    }
    
    public function set X(n:Number):void{
        x += n;
        updateHitPos();
    }
    public function set Y(n:Number):void{
        y += n;
        updateHitPos();
    }
    
    public function set Z(n:Number):void{
        z += n;
        updateHitPos();
    }


    
    public function Block( parent :Object3D = null ) {
        
        var w :int = 100;
        
        super(w,w,w);
        x = 0;
        y = 0;
        
        z = 0;
        var col:uint = Math.random()*0xffffff;
        setMaterialToAllSurfaces(new VertexLightTextureMaterial(new BitmapTextureResource(new BitmapData(8, 8, false, col))));
        if (parent) parent.addChild(this);
        
        var rad :Number = rotationZ = 0;//MathUtil.toRad(MathUtil.rand(0, 45));
        var cw :Number = (w + 90) / 2;
        var cl :Number = (w + 90) / 2;
        _p[0] = new Point(x + (-cw * Math.cos(rad) + cl * Math.sin(rad)), y + (-cw * Math.sin(rad) - cl * Math.cos(rad)));
        _p[1] = new Point(x + (-cw * Math.cos(rad) - cl * Math.sin(rad)), y + (-cw * Math.sin(rad) + cl * Math.cos(rad)));
        _p[2] = new Point(x + ( cw * Math.cos(rad) - cl * Math.sin(rad)), y + ( cw * Math.sin(rad) + cl * Math.cos(rad)));
        _p[3] = new Point(x + ( cw * Math.cos(rad) + cl * Math.sin(rad)), y + ( cw * Math.sin(rad) - cl * Math.cos(rad)));
        
    }
    
    //当たり判定
    public function hitTest (nx :Number, ny :Number, px :Number, py :Number) :Point {
        
        var f :Boolean = MathUtil.boxContainsPos(_p[0].x, _p[0].y, _p[1].x, _p[1].y, _p[2].x, _p[2].y, _p[3].x, _p[3].y, nx, ny);
        if (! f) return null;
        
        for (var i :int = 0; i < 4; i ++) {
            
            var p1x :Number = _p[i].x;
            var p1y :Number = _p[i].y;
            var p2x :Number = _p[(i+1)%4].x;
            var p2y :Number = _p[(i+1)%4].y;
            
            f = MathUtil.intersectLineSegment(px, py, nx, ny, p1x, p1y, p2x, p2y);
            if (f) {
                var pt :Point = MathUtil.getCrossPoint(p1x, p1y, p2x, p2y, nx, ny);
                return new Point(pt.x + (pt.x - nx) * 0.2, pt.y + (pt.y - ny) * 0.2);
            }
        }
        return null;
    }
    
}


/* -----------------------------------------------------------------
 * MathUtil
 */
class MathUtil
{
    /* min ~ max の範囲で乱数生成 */
    public static function rand ( min :Number, max :Number ) :Number { return Math.random() * ( max - min ) + min; }
    /* 角度からラジアンに変換 */
    public static function toRad ( deg :Number ) :Number { return deg * Math.PI / 180; }
    
    /* 外積 */
    public static function intersect ( p1x :Number, p1y :Number, p2x :Number, p2y :Number, p3x :Number, p3y :Number, p4x :Number, p4y :Number ) :Number {
        
        var n :Number = ((p1x - p2x) * (p3y - p1y) + (p1y - p2y) * (p1x - p3x)) * ((p1x - p2x) * (p4y - p1y) + (p1y - p2y) * (p1x - p4x));
        return n;
    }
    /* 任意の三角形の中に任意の点が内包されているかどうか */
    public static function triContainsPos ( p1x :Number, p1y :Number, p2x :Number, p2y :Number, p3x :Number, p3y :Number, psx :Number, psy :Number ) :Boolean {
        
        if ((p1x - p3x) * (p1y - p2y) == (p1x - p2x) * (p1y - p3y)) return false;
        
        if (intersect(p1x, p1y, p2x, p2y, psx, psy, p3x, p3y) < 0) return false;
        if (intersect(p1x, p1y, p3x, p3y, psx, psy, p2x, p2y) < 0) return false;
        if (intersect(p2x, p2y, p3x, p3y, psx, psy, p1x, p1y) < 0) return false;
        
        return true;
    }
    /* 任意の四角形の中に任意の点が内包されているかどうか(凸のみ) */
    public static function boxContainsPos ( p1x :Number, p1y :Number, p2x :Number, p2y :Number, p3x :Number, p3y :Number, p4x :Number, p4y :Number, psx :Number, psy :Number ) :Boolean {
        
        if (triContainsPos(p1x, p1y, p2x, p2y, p3x, p3y, psx, psy)) return true;
        if (triContainsPos(p1x, p1y, p3x, p3y, p4x, p4y, psx, psy)) return true;
        
        return false;
    }
    /* 線分の交差判定 */
    public static function intersectLineSegment ( p1x :Number, p1y :Number, p2x :Number, p2y :Number, p3x :Number, p3y :Number, p4x :Number, p4y :Number) :Boolean {
        
        if (intersect(p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y) < 0)
            if (intersect(p3x, p3y, p4x, p4y, p1x, p1y, p2x, p2y) < 0) return true;
        return false;
    }
    /* 点から直線におろした垂線の交点の座標 */
    public static function getCrossPoint ( p1x :Number, p1y :Number, p2x :Number, p2y :Number, psx :Number, psy :Number ) :Point {
        
        var a :Number = p2y - p1y;
        var b :Number = p1x - p2x;
        var c :Number = (p1y - p2y) * p1x + (p2x - p1x) * p1y;
        
        var d :Number = (a * psx + b * psy + c) / (a * a + b * b);
        
        var x :Number = psx - d * a;
        var y :Number = psy - d * b;
        
        return new Point(x, y);
    }
}

Forked