forked from: Camera & Model rotation Test

by zier forked from Camera & Model rotation Test (diff: 210)
forked from: Camera & Model rotation Test

カメラとモデル回転に対する視点変更のテストコード 2010/08/22 Zier
* 操作方法は onKeyDown() を見てください
* 
* モデルの回転処理に関しては KoheiTAKAMIYA さんの
* 『転がるサイコロver.1』 http://wonderfl.net/c/jhbr を
* 参考にさせていただきました。ありがとうございます。
* 
♥0 | Line 184 | Modified 2010-08-22 15:08:45 | MIT License
play

ActionScript3 source code

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

// forked from zier's Camera & Model rotation Test

/*
 * カメラとモデル回転に対する視点変更のテストコード 2010/08/22 Zier
 * 操作方法は onKeyDown() を見てください
 * 
 * モデルの回転処理に関しては KoheiTAKAMIYA さんの
 * 『転がるサイコロver.1』 http://wonderfl.net/c/jhbr を
 * 参考にさせていただきました。ありがとうございます。
 * 
 */
package {
    
    import com.bit101.components.Text;
    import flash.display.Sprite;
    import flash.events.Event
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    import org.papervision3d.core.math.Matrix3D;
    import org.papervision3d.core.math.Number3D;

    // Papervision3D 
    import org.papervision3d.view.BasicView
    import org.papervision3d.lights.*
    import org.papervision3d.materials.utils.MaterialsList;
    import org.papervision3d.materials.shadematerials.*
    import org.papervision3d.objects.primitives.*

    // tweener
    import caurina.transitions.*

    [SWF(width="400", height="400", backgroundColor='0x4e616b', frameRate="60")]
    public class Main extends BasicView {
        private const DEGREE_TO_RADIAN: Number = Math.PI / 180
        
        private var model: Cube = null
        private var cubeDir: CubeDirection;
        
        private var light:PointLight3D = new PointLight3D()
        private var white: FlatShadeMaterial = new FlatShadeMaterial(light, 0xFFFFFF, 0xFFFFFF)
        private var blue: FlatShadeMaterial = new FlatShadeMaterial(light, 0x0000FF, 0x0000FF)
        private var green: FlatShadeMaterial = new FlatShadeMaterial(light, 0x00FF00, 0x00FF00)
        private var red: FlatShadeMaterial = new FlatShadeMaterial(light, 0xFF0000, 0xFF0000)
        private var yellow: FlatShadeMaterial = new FlatShadeMaterial(light, 0xFFFF00, 0xFFFF00)
        private var orange: FlatShadeMaterial = new FlatShadeMaterial(light, 0xFF8000, 0xFF8000)
        private var black: FlatShadeMaterial = new FlatShadeMaterial(light, 0x000000, 0x000000)
        
        private function createCube(size: int): Cube {
            var list: MaterialsList = new MaterialsList()
            list.addMaterial(red, "front")
            list.addMaterial(white, "top")
            list.addMaterial(green, "right")
            list.addMaterial(yellow, "left")
            list.addMaterial(blue, "bottom")
            list.addMaterial(orange, "back")
            return new Cube(list, size, size, size, 1, 1, 1, 0, 0)
        }
        
        public function Main() {
            var text: Text = new Text(this, 5, 5, "");
            text.width = 80;
            text.height = 20;
            text.editable = false;
            
            model = createCube(500)
            scene.addChild(model)
            
            cubeDir = new CubeDirection(model)
            cubeDir.addEventListener(CubeDirection.CHANGE_FACE, function (): void { text.text = cubeDir.nearFaceName() } ); 
            cubeDir.refresh()
            
            startRendering()
            stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown)
            
            tweenCamera(-1, +1);
        }
        
        private function tweenCamera(dx: int, dy: int): void {
            const CAMERA_TIME: Number = 2.5
            const CAMERA_TRANSITION: String = "easeOutElastic"
            
            var _r: Number = (180 + dx * 25) * DEGREE_TO_RADIAN
            var _x: Number = 1000 * Math.sin(_r)
            var _y: Number = 400 * dy
            var _z: Number = 1000 * Math.cos(_r)
            Tweener.addTween(camera, { x: _x, y: _y, z: _z, time: CAMERA_TIME, transition: CAMERA_TRANSITION } );
        }
        
        private function onKeyDown(e: KeyboardEvent): void {
            switch (e.keyCode) {
            // cursor
            case 37: break // left
            case 38: break // up
            case 39: break // right
            case 40: break // down
            
            case 32: break // Space
            
            // camera control
            case 81: tweenCamera(+1, +1); break // Q 左上から
            case 69: tweenCamera(-1, +1); break // E 右上から
            case 90: tweenCamera(+1, -1); break // Z 左下から
            case 67: tweenCamera(-1, -1); break // C 右下から
            
            // model control
            case 82: cubeDir.reset();     break // R リセット
            case 87: cubeDir.pitchBack(); break // W 上の面を手前に
            case 65: cubeDir.yawLeft();   break // A 左の面を手前に
            case 83: cubeDir.reverse();   break // S 前の面を手前に
            case 68: cubeDir.yawRight();  break // D 右の面を手前に
            case 88: cubeDir.pitchFore(); break // X 下の面を手前に
            case 70: cubeDir.rollLeft();  break // F 上の面を右に
            case 71: cubeDir.rollRight(); break // G 右の面を上に
            }
        }
    }
}

import flash.events.Event
import flash.events.EventDispatcher;
import org.papervision3d.core.math.Number3D;
import org.papervision3d.objects.primitives.Cube
import caurina.transitions.*

// 立方体の向き管理用クラス
class CubeDirection extends EventDispatcher {
    public static const CHANGE_FACE: String = "changeFace";
    
    private static const TOP: String = "TOP";
    private static const FRONT: String = "FRONT";
    private static const RIGHT: String = "RIGHT";
    private static const BACK: String = "BACK";
    private static const LEFT: String = "LEFT";
    private static const BOTTOM: String = "BOTTOM";
    
    private static const CUBE_TIME: Number = 1.0
    private static const CUBE_TRANSITION: String = "easeOutBack"
    
    private var _cube: Cube = null
    
    private var _x: Number = 0
    private var _y: Number = 0
    private var _z: Number = 0
    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(value: Number): void { _x = value }
    public function set y(value: Number): void { _y = value }
    public function set z(value: Number): void { _z = value }
    
    public function direction(): Number3D { return new Number3D( _x, _y, _z ); }
    
    // _state は X, Y, Z 軸の + 方向を示す。初期値は X: right(green), Y: top(white), Z: front(red)
    private var _state: Array = [RIGHT, TOP, FRONT];

    private var prevLocal: Number3D = null;    
    private var resetFlag: Boolean = false
    
    public function CubeDirection(cube: Cube, x: String = RIGHT, y: String = TOP, z: String = FRONT) {
        _cube = cube
        reset(x, y, z)
    }
    
    private function roll(c: uint, ... faces): void {
        
        if (resetFlag) return
        
        var shift: Array = [0, 0, 0];
        
        // c は処理回数 : 通常1だが、半回転をサポートするために用意している。
        while (0 < c--) {
            var i: int = 0
            for each (var state: String in _state) {
                if (state == faces[0]) shift[i] -= 90;
                else if (state == faces[1]) shift[i] += 90;
                else if (state == faces[2]) _state[i] = faces[3]
                else if (state == faces[3]) _state[i] = faces[4]
                else if (state == faces[4]) _state[i] = faces[5]
                else if (state == faces[5]) _state[i] = faces[2]
                i++;
            }
        }
        
        _x += shift[0]
        _y += shift[1]
        _z += shift[2]
        
        // この補正が無いと軸の違う回転を行った場合にモデル自体が傾いてしまう
        if (null != prevLocal) {
            _cube.localRotationX = prevLocal.x
            _cube.localRotationY = prevLocal.y
            _cube.localRotationZ = prevLocal.z
        }
        
        Tweener.addTween(_cube, { localRotationX: _x, localRotationY: _y, localRotationZ: _z, 
            time: CUBE_TIME, transition: CUBE_TRANSITION, onComplete: onComplete } );
        prevLocal = direction();
        
        refresh()
    }

    public function reset(x: String = RIGHT, y: String = TOP, z: String = FRONT): void {
        _x = _y = _z = 0
        _state = [x, y, z]
        
        Tweener.addTween(_cube, { localRotationX: 0, localRotationY: 0, localRotationZ: 0, 
            rotationX: 0, rotationY: 0, rotationZ: 0, 
            time: CUBE_TIME, transition: CUBE_TRANSITION, onComplete: onComplete} );
        resetFlag = true
        
        refresh()
    }
    
    // pitch control - X
    public function pitchFore(): void { roll(1, RIGHT, LEFT, TOP, FRONT, BOTTOM, BACK) }
    public function pitchBack(): void { roll(1, LEFT, RIGHT, TOP, BACK, BOTTOM, FRONT) }
    
    // yaw control - Y 
    public function yawRight(): void { roll(1, TOP, BOTTOM, FRONT, RIGHT, BACK, LEFT) }
    public function yawLeft(): void { roll(1, BOTTOM, TOP, FRONT, LEFT, BACK, RIGHT) }
    
    // roll control - Z
    public function rollRight(): void { roll(1, FRONT, BACK, TOP, LEFT, BOTTOM, RIGHT) }
    public function rollLeft(): void { roll(1, BACK, FRONT, TOP, RIGHT, BOTTOM, LEFT) }
    
    public function reverse(): void { roll(2, RIGHT, LEFT, TOP, FRONT, BOTTOM, BACK) }
        
    public function refresh(): void { dispatchEvent(new Event(CHANGE_FACE)); }
    
    private function onComplete(e: Event = null): void {
        function adjust(value: Number): Number {
            if ((value -  90) % 360 == 0) return  90
            if ((value +  90) % 360 == 0) return -90
            if ((value + 180) % 360 == 0) return 180
            return 0
        }
        
        _x = _cube.localRotationX = adjust(_cube.localRotationX)
        _y = _cube.localRotationY = adjust(_cube.localRotationY)
        _z = _cube.localRotationZ = adjust(_cube.localRotationZ)
        
        resetFlag = false
        prevLocal = null
    }
    
    // 今どの面が手前にあるか?
    public function nearFaceName(): String {
        if (_state[0] == FRONT) return "Yellow"
        if (_state[0] == BACK)  return "Green"
        if (_state[1] == FRONT) return "Blue"
        if (_state[1] == BACK)  return "White"
        if (_state[2] == FRONT) return "Orange"
        if (_state[2] == BACK)  return "Red"
        return "UNKNOWN";
    }
}