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
これすごいですね!!!
びっくりです。
hansさん ありがとうございます。
ちなみにこのブログで初めてコメントを頂きました。
Post a comment