スポンサーサイト

-------- | --:--

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

[ActionScript 3.0] PaperVision3Dでルービックキューブ

2007-08-21 | 20:55

黒い矢印をクリックして回転。

RubikCube.as
package {
    import flash.display.*;
    import flash.events.*;
    import flash.utils.*;
 
    import org.papervision3d.core.*;
    import org.papervision3d.scenes.*;
    import org.papervision3d.objects.*;
    import org.papervision3d.cameras.*;
    import org.papervision3d.materials.*;
 
    [SWF(width="400", height="400", backgroundColor="#ffffff")]
    public class RubikCube extends Sprite{

        private var canvas : Sprite;
        private var scene     : Scene3D;
        private var camera    : Camera3D;
        private var rootNode  : DisplayObject3D;
 
        private var cubes:Array = new Array();

        private var animationIndex:int=0;
        private var animeTimer:Timer;
        private var moveCubes:Array;

        [Embed(source="down.gif")]
            private var buttonDown:Class;
        [Embed(source="right.gif")]
            private var buttonRight:Class;

        public function RubikCube():void
        {
            stage.frameRate = 60;
            stage.quality   = "MEDIUM";
            stage.scaleMode = "noScale";
            stage.align = StageAlign.TOP_LEFT;
 
            canvas = new Sprite();
            canvas.x = 200;
            canvas.y = 200;
            stage.addChild( canvas );
 
            scene = new Scene3D( canvas );
 
            rootNode = new DisplayObject3D();
            scene.addChild( rootNode );
 
            for(var z:int = 0 ; z < 3 ; z++){
                for(var y:int = 0 ; y < 3 ; y++){
                    for(var x:int = 0 ; x < 3 ; x++){
                        var mList:MaterialsList = new MaterialsList();

                        mList.addMaterial( new ColorMaterial(0x00ff00 , 0.9) , "face1" );
                        mList.addMaterial( new ColorMaterial(0xff8000 , 0.9) , "face2" );
                        mList.addMaterial( new ColorMaterial(0xffff00 , 0.9) , "face3" );
                        mList.addMaterial( new ColorMaterial(0xff0000 , 0.9) , "face4" );
                        mList.addMaterial( new ColorMaterial(0x00ffff , 0.9) , "face5" );
                        mList.addMaterial( new ColorMaterial(0x0000ff , 0.9) , "face6" );

                        var cube:MyCube = new MyCube(mList, 180,180,180 );
                        //if(x==0&&y==0&&z==0)
                        scene.addChild( cube );
                        cubes.push(cube);
                        cube.x = -200 + (x*200);
                        cube.y = 200 - y*200;
                        cube.z = -200 + z*200;
                    }
                }
            }

            createButton(90,300,"left", new buttonDown());
            createButton(135,330,"center", new buttonDown());
            createButton(180,350,"right", new buttonDown());

            createButton(30,130,"top", new buttonRight());
            createButton(40,180,"middle", new buttonRight());
            createButton(50,230,"bottom", new buttonRight());

            createButton(230,340,"front", new buttonDown());
            createButton(250,300,"cross", new buttonDown());
            createButton(270,260,"back", new buttonDown());

            camera = new Camera3D();
            camera.x = 500;
            camera.y = 500;
            camera.z = -800;
            camera.focus = 100;
            camera.zoom = 3;

            stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);

            scene.renderCamera( camera );
        }

        private function createButton(x:int, y:int, name:String, b:DisplayObject):void{
            var button:SimpleButton = new SimpleButton();
            button.x = x;
            button.y = y;
            button.name = name;
            button.upState = b;
            button.overState = button.upState;
            button.hitTestState = button.upState;
            addChild(button);
            button.addEventListener(MouseEvent.MOUSE_DOWN, onMouseClick);
        }

        private function onMouseClick(e:MouseEvent):void{
            if(animationIndex != 0)
                return;

            animationIndex++;

            var button:SimpleButton = SimpleButton(e.target);
            moveCubes = getCubes(button.name);

            for(var i:int = 0 ; i < moveCubes.length ; i++){
                var cube:MyCube = moveCubes[i];
                var animeFrom:Quaternion = new Quaternion(0, new Vector3(cube.x, cube.y, cube.z));
                var animeTo:Quaternion;
                var rad:Number = Math.PI/2;
                var x:Number = cube.x;
                var y:Number = cube.y;
                var z:Number = cube.z;
                var axis:Vector3;
                if(button.name == "left" || button.name == "center" || button.name == "right"){
                    animeTo = new Quaternion(0,
                            new Vector3(x,
                                y*Math.cos(rad) + z*Math.sin(rad),
                                -y*Math.sin(rad) + z*Math.cos(rad)));
                    axis = new Vector3(1,0,0);
                }
                if(button.name == "top" || button.name == "middle" || button.name == "bottom"){
                    animeTo = new Quaternion(0,
                            new Vector3(x*Math.cos(rad) - z*Math.sin(rad),
                                y,
                                x*Math.sin(rad) + z*Math.cos(rad)));
                    axis = new Vector3(0,1,0);
                }
                if(button.name == "front" || button.name == "cross" || button.name == "back"){
                    animeTo = new Quaternion(0,
                            new Vector3(x*Math.cos(rad) + y*Math.sin(rad),
                                -x*Math.sin(rad) + y*Math.cos(rad),
                                z));
                    axis = new Vector3(0,0,1);
                }

                cube.animationPos = new Array();
                cube.animationAngle = new Array();
                if(cube.quaternion == null)
                    cube.quaternion = new Quaternion(1, new Vector3(0,0,0));
                for(var t:Number = 0, j:int = 1 ; t <= 1.0 ; t += 0.1, j++){
                    cube.animationPos.push(
                            animeFrom.multiplScalar((Math.sin((1-t)*rad))
                                /Math.sin(rad)).add(
                                animeTo.multiplScalar(Math.sin(rad*t)/Math.sin(rad))));

                    var rotateQ:Quaternion = Quaternion.rotateQuaternion(rad*(j/11.0), axis);
                    cube.animationAngle.push(cube.quaternion.multiply(rotateQ));
                }
            }

            animeTimer = new Timer(100);
            animeTimer.addEventListener(TimerEvent.TIMER, animation);
            animeTimer.start();

        }

        private function animation(e:TimerEvent):void{
            for(var i:int = 0 ; i < moveCubes.length ; i++){
                var cube:MyCube = moveCubes[i];

                cube.quaternion = cube.animationAngle[animationIndex];
                cube.transform = cube.animationAngle[animationIndex].convert2Matrix3D();
                cube.x = int(cube.animationPos[animationIndex].x);
                cube.y = int(cube.animationPos[animationIndex].y);
                cube.z = int(cube.animationPos[animationIndex].z);

                if(animationIndex == 10){
                    if(cube.x > 150) 
                        cube.x = 200;
                    else if(cube.x < -150) 
                        cube.x = -200;
                    else
                        cube.x = 0;
                    if(cube.y > 150) 
                        cube.y = 200;
                    else if(cube.y < -150) 
                        cube.y = -200;
                    else
                        cube.y = 0;
                    if(cube.z > 150) 
                        cube.z = 200;
                    else if(cube.z < -150) 
                        cube.z = -200;
                    else
                        cube.z = 0;
                }
            }
            if(++animationIndex > 10){
                animeTimer.removeEventListener(TimerEvent.TIMER, animation);
                animationIndex = 0;
                return;
            }
        }

        private function getCubes(v:String):Array{
            var a:Array = new Array();
            for each(var cube:Cube in cubes){
                if((v == "left" && int(cube.x) < -150) ||
                        (v == "center" && int(cube.x) == 0) ||
                        (v == "right" && int(cube.x) > 150) ||
                        (v == "top" && int(cube.y) > 150) ||
                       (v == "middle" && int(cube.y) == 0) ||
                       (v == "bottom" && int(cube.y) < -150) ||
                       (v == "front" && int(cube.z) < -150) ||
                       (v == "cross" && int(cube.z) == 0) ||
                       (v == "back" && int(cube.z) > 150))
                    a.push(cube);
            }

            return a;
        }

        private function rotateCamera(rad:Number):void{
            var x:Number = camera.x;
            var z:Number = camera.z;
            camera.x = Math.cos(rad)*x - Math.sin(rad)*z;
            camera.z = Math.sin(rad)*x + Math.cos(rad)*z;
        }

        private function onEnterFrame( event:Event ):void
        {
            scene.renderCamera( camera );
        }
    }
}
MyCube.as
package {
    import org.papervision3d.objects.*;
 
    public class MyCube extends Cube{

        public var quaternion:Quaternion = null;
        public var animationPos:Array;
        public var animationAngle:Array;
 
	public function MyCube( materialArg:Object=null, width:Number=500, depth:Number=500, height:Number=500, segmentsS:Number=1, segmentsT:Number=1, segmentsH:Number=1, initObject:Object=null )
	{
        super(materialArg,width,depth,height,segmentsS,segmentsT,segmentsH,initObject);

    }
    }
}
Quaternion.as
package{
    import org.papervision3d.core.Matrix3D;
    public class Quaternion{
        private var _w:Number;
        private var _x:Number;
        private var _y:Number;
        private var _z:Number;

        public function Quaternion(w:Number=0, v:Vector3=null){
            _w = w;
            if(v != null){
                _x = v.x;
                _y = v.y;
                _z = v.z;
            }
        }
        /*
         * 回転を表すクォータニオンを返す
         */
        public static function rotateQuaternion(r:Number, v:Vector3):Quaternion{
            var q:Quaternion = new Quaternion();
            var s:Number = Math.sin(r/2.0);
            q._w = Math.cos(r/2.0);
            q._x = v.x * s;
            q._y = v.y * s;
            q._z = v.z * s;
            return q;
        }
        /*
         * スカラー倍したクォータニオンを返す
         */
        public function multiplScalar(s:Number):Quaternion{
            var q:Quaternion = new Quaternion();

            q._w = _w * s;
            q._x = _x * s;
            q._y = _y * s;
            q._z = _z * s;

            return q;
        }
        /*
         * 積を返す
         */
        public function multiply(o:Quaternion):Quaternion{
            var q:Quaternion = new Quaternion();

            q._w = _w * o._w - _x * o._x - _y * o._y - _z * o._z;
            q._x = _y * o._z - _z * o._y + _w * o._x + _x * o._w;
            q._y = _z * o._x - _x * o._z + _w * o._y + _y * o._w;
            q._z = _x * o._y - _y * o._x + _w * o._z + _z * o._w;

            return q;
        }
        /*
         * 
         */
        public function add(rhs:Quaternion):Quaternion{
            var q:Quaternion = new Quaternion();

            q._w = _w + rhs._w;
            q._x = _x + rhs._x;
            q._y = _y + rhs._y;
            q._z = _z + rhs._z;

            return q;
        }
        /*
         * 共役クォータニオンを返す 
         */
        public function conjugation():Quaternion{
            var q:Quaternion = new Quaternion();

            q._w = _w ;
            q._x = -_x ;
            q._y = -_y ;
            q._z = -_z ;

            return q;
        }

        public function convert2Matrix3D():Matrix3D{
            var m:Matrix3D = new Matrix3D();

            var sx:Number = _x * _x;
            var sy:Number = _y * _y;
            var sz:Number = _z * _z;
            var cx:Number = _y * _z;
            var cy:Number = _x * _z;
            var cz:Number = _x * _y;
            var wx:Number = _w * _x;
            var wy:Number = _w * _y;
            var wz:Number = _w * _z;

            m.n11 = 1.0 - 2.0 * (sy + sz);
            m.n12 = 2.0 * (cz + wz);
            m.n13 = 2.0 * (cy - wy);
            m.n21 = 2.0 * (cz - wz);
            m.n22 = 1.0 - 2.0 * (sx + sz);
            m.n23 = 2.0 * (cx + wx);
            m.n31 = 2.0 * (cy + wy);
            m.n32 = 2.0 * (cx - wx);
            m.n33 = 1.0 - 2.0 * (sx + sy);

            return m;
        }

        public function get w():Number{
            return _w;
        }

        public function get x():Number{
            return _x;
        }

        public function get y():Number{
            return _y;
        }

        public function get z():Number{
            return _z;
        }

        public function set w(v:Number):void{
            _w = v;
        }

        public function set x(v:Number):void{
            _x = v;
        }

        public function set y(v:Number):void{
            _y = v;
        }

        public function set z(v:Number):void{
            _z = v;
        }
    }
}
Vector3.as
package{
    public class Vector3{
        private var _x:Number;
        private var _y:Number;
        private var _z:Number;

        public function Vector3( x:Number=0.0,y:Number=0.0,z:Number=0.0){
            _x = x ;
            _y = y ;
            _z = z ;
        }

        public function normalize():void{
            var lenv:Number = Math.sqrt(_x*_x + _y*_y + _z*_z);
            _x = _x / lenv;
            _y = _y / lenv;
            _z = _z / lenv;
        }

        public function length():Number{
            return Math.sqrt(_x*_x + _y*_y + _z*_z);
        }

        public function cross(rhs:Vector3):Number{
            return _y*rhs.z - _z*rhs.y + _z*rhs.x - _x*rhs.z + _x*rhs.y - _y*rhs.x;
        }

        public function get x():Number{
            return _x;
        }

        public function get y():Number{
            return _y;
        }

        public function get z():Number{
            return _z;
        }

        public function set x(v:Number):void{
            _x = v;
        }

        public function set y(v:Number):void{
            _y = v;
        }

        public function set z(v:Number):void{
            _z = v;
        }
    }
}
スポンサーサイト

Comment

これすごいですね!!!
びっくりです。

  • 2007-08-30 | 11:45 |
  • hans URL :
  • edit

hansさん ありがとうございます。
ちなみにこのブログで初めてコメントを頂きました。

  • 2007-08-31 | 21:37 |
  • yamasv URL :
  • edit

Post a comment

Secret

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。