package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.utils.Dictionary;
import loaders.ObjImporter;
import primitives.Object3d;
import flash.utils.getTimer;
/**
* ルービックキューブゲーム 斜め視点
*/
public class Main extends Sprite
{
private var angle:Number = 0.0; // 回転角度
private var rotM:Matrix4x4 = new Matrix4x4(); // 回転変換行列
private var viewM:Matrix4x4 = new Matrix4x4(); // 視点位置変換行列
private var persM:Matrix4x4 = new Matrix4x4(); // 透視投影変換行列
private var modelM:Matrix4x4 = new Matrix4x4(); // モデル変換行列
private var viewPos:Vector3d; // 視点位置
private var sp:Sprite; // 描画スクリーン
private var hitFlag:Boolean = false; // レイ交差判定に使用するフラグ
// オブジェクト
private var dice_01:Dice; // サイコロ1
private var dice_02:Dice; // サイコロ2
private var dice_03:Dice; // サイコロ3
private var dice_04:Dice; // サイコロ4
private var dice_05:Dice; // サイコロ5
private var dice_06:Dice; // サイコロ6
private var dice_07:Dice; // サイコロ7
private var dice_08:Dice; // サイコロ8
private var dice_09:Dice; // サイコロ9
private var dice_10:Dice; // サイコロ10
private var dice_11:Dice; // サイコロ11
private var dice_12:Dice; // サイコロ12
private var dice_13:Dice; // サイコロ13
private var dice_14:Dice; // サイコロ14
private var dice_15:Dice; // サイコロ15
private var dice_16:Dice; // サイコロ16
private var dice_17:Dice; // サイコロ17
private var dice_18:Dice; // サイコロ18
private var dice_19:Dice; // サイコロ19
private var dice_20:Dice; // サイコロ20
private var dice_21:Dice; // サイコロ21
private var dice_22:Dice; // サイコロ22
private var dice_23:Dice; // サイコロ23
private var dice_24:Dice; // サイコロ24
private var dice_25:Dice; // サイコロ25
private var dice_26:Dice; // サイコロ26
private var dice_27:Dice; // サイコロ27
private var diceArray:Array = new Array(); // サイコロオブジェクトを格納する
private var diceObject:Dice; // マウスイベントで使用
private var map:Map = new Map(); // マップ情報
public var hitDice:Array = new Array(7); // 判定処理で使用
private var textField:TextField; // デバッグエリア
public function Main():void
{
this.sp = new Sprite();
this.sp.graphics.beginFill(0x000000);
this.sp.graphics.drawRect(0, 0, 400, 300);
this.sp.focusRect = false;
this.sp.graphics.endFill();
this.addChild(this.sp);
//デバッグエリア
textField = new TextField();
textField.textColor = 0xffff00;
textField.border = false;
textField.mouseEnabled = false;
textField.x = 150;
textField.y = 130;
textField.width = 200;
textField.height = 100;
Debug.textField = textField;
//Debug.trace("サイコロの目は");
this.addChild(textField);
init();
}
public function init():void
{
// モデル変換行列の作成
// -------------------------------------------------------
// 視点位置変換行列を作成
viewPos = new Vector3d(100.0, 100.0, 100.0); // 視点位置
// 視点、注視点、上方向を指定
viewM.View(viewPos, new Vector3d(0.0, 0.0, 0.0), new Vector3d(0.0, 1.0, 0.0));
modelM.Mult(viewM);
// 透視投影変換行列の作成
// -------------------------------------------------------
var n:Number = 20.0; // ニアクリップ面
var f:Number = 1000; // ファークリップ面
var fov:Number = 45.0; // 視野角(FOV:Field Of View)
var aspect:Number = Number(400) / Number(300); // aspect比を計算
var PMv:Array = new Array(3); // 変換後の頂点を格納する
for (var i:int = 0; i < PMv.length; i++ ) {
PMv[i] = new Vertex();
}
// 透視投影行列を作成
persM.Projection(n, f, fov, aspect);
// 3Dオブジェクト作成
// -------------------------------------------------------
/*var cnt:int = 0;
for (i = 0; i < map.mapArray.length; i++ ) {
for (var j:int = 0; j < map.mapArray[i].length; j++ ) {
if (int(Math.random() * 10) < 5) {
map.mapArray[i][j] = new Dice(0, 0, 0);
//map.mapArray[i][j].initCreateCompositionM( (int(Math.random() * 6) - 3) * 20, 0, (int(Math.random() * 6) - 3) * 20, int(Math.random() * 10) * 90, int(Math.random() * 10) * 90, int(Math.random() * 10) * 90); // 合成行列作成
map.mapArray[i][j].initCreateCompositionM( changeIndexToPos(j), 0, changeIndexToPos(i), int(Math.random() * 10) * 90, int(Math.random() * 10) * 90, int(Math.random() * 10) * 90); // 合成行列作成
map.mapArray[i][j].createRotM2();
map.mapArray[i][j].init();
diceArray.push(map.mapArray[i][j]);
map.mapArray[map.mapArray[i][j].getIndexY()][map.mapArray[i][j].getIndexX()] = diceArray[cnt++]; // マップ配列に格納する
}
}
}*/
// サイコロ1
dice_01 = new Dice(0, 0, 0);
dice_01.initCreateCompositionM( -20, -20, -20, 0, 0, 0); // 合成行列作成
dice_01.createRotM2();
dice_01.init();
diceArray.push(dice_01);
//map.mapArray[dice_01.getIndexY()][dice_01.getIndexX()] = diceArray[0]; // マップ配列に格納する*/
// サイコロ2
dice_02 = new Dice(0, 0, 0);
dice_02.initCreateCompositionM( 0, -20, -20, 0, 0, 0); // 合成行列作成
dice_02.createRotM2();
dice_02.init();
diceArray.push(dice_02);
//map.mapArray[dice_02.getIndexY()][dice_02.getIndexX()] = diceArray[1]; // マップ配列に格納する
// サイコロ3
dice_03 = new Dice(0, 0, 0);
dice_03.initCreateCompositionM(20, -20, -20, 0, 0, 0); // 合成行列作成
dice_03.createRotM2();
dice_03.init();
diceArray.push(dice_03);
//map.mapArray[dice_03.getIndexY()][dice_03.getIndexX()] = diceArray[2]; // マップ配列に格納する
// サイコロ4
dice_04 = new Dice(0, 0, 0);
dice_04.initCreateCompositionM( -20, -20, 0, 0, 0, 0); // 合成行列作成
dice_04.createRotM2();
dice_04.init();
diceArray.push(dice_04);
//map.mapArray[dice_04.getIndexY()][dice_04.getIndexX()] = diceArray[3]; // マップ配列に格納する
// サイコロ5
dice_05 = new Dice(0, 0, 0);
dice_05.initCreateCompositionM( 0, -20, 0, 0, 0, 0); // 合成行列作成
dice_05.createRotM2();
dice_05.init();
diceArray.push(dice_05);
//map.mapArray[dice_05.getIndexY()][dice_05.getIndexX()] = diceArray[4]; // マップ配列に格納する
// サイコロ6
dice_06 = new Dice(0, 0, 0);
dice_06.initCreateCompositionM( 20, -20, 0, 0, 0, 0); // 合成行列作成
dice_06.createRotM2();
dice_06.init();
diceArray.push(dice_06);
//map.mapArray[dice_06.getIndexY()][dice_06.getIndexX()] = diceArray[5]; // マップ配列に格納する*/
// サイコロ7
dice_07 = new Dice(0, 0, 0);
dice_07.initCreateCompositionM( -20, -20, 20, 0, 0, 0); // 合成行列作成
dice_07.createRotM2();
dice_07.init();
diceArray.push(dice_07);
//map.mapArray[];
// サイコロ8
dice_08 = new Dice(0, 0, 0);
dice_08.initCreateCompositionM( 0, -20, 20, 0, 0, 0); // 合成行列作成
dice_08.createRotM2();
dice_08.init();
diceArray.push(dice_08);
// サイコロ9
dice_09 = new Dice(0, 0, 0);
dice_09.initCreateCompositionM( 20, -20, 20, 0, 0, 0); // 合成行列作成
dice_09.createRotM2();
dice_09.init();
diceArray.push(dice_09);
// サイコロ10
dice_10 = new Dice(0, 0, 0);
dice_10.initCreateCompositionM( -20, 0, -20, 0, 0, 0); // 合成行列作成
dice_10.createRotM2();
dice_10.init();
diceArray.push(dice_10);
// サイコロ11
dice_11 = new Dice(0, 0, 0);
dice_11.initCreateCompositionM( 0, 0, -20, 0, 0, 0); // 合成行列作成
dice_11.createRotM2();
dice_11.init();
diceArray.push(dice_11);
// サイコロ12
dice_12 = new Dice(0, 0, 0);
dice_12.initCreateCompositionM( 20, 0, -20, 0, 0, 0); // 合成行列作成
dice_12.createRotM2();
dice_12.init();
diceArray.push(dice_12);
// サイコロ13
dice_13 = new Dice(0, 0, 0);
dice_13.initCreateCompositionM( -20, 0, 0, 0, 0, 0); // 合成行列作成
dice_13.createRotM2();
dice_13.init();
diceArray.push(dice_13);
// サイコロ14
dice_14 = new Dice(0, 0, 0);
dice_14.initCreateCompositionM( 0, 0, 0, 0, 0, 0); // 合成行列作成
dice_14.createRotM2();
dice_14.init();
diceArray.push(dice_14);
// サイコロ15
dice_15 = new Dice(0, 0, 0);
dice_15.initCreateCompositionM( 20, 0, 0, 0, 0, 0); // 合成行列作成
dice_15.createRotM2();
dice_15.init();
diceArray.push(dice_15);
// サイコロ16
dice_16 = new Dice(0, 0, 0);
dice_16.initCreateCompositionM( -20, 0, 20, 0, 0, 0); // 合成行列作成
dice_16.createRotM2();
dice_16.init();
diceArray.push(dice_16);
// サイコロ17
dice_17 = new Dice(0, 0, 0);
dice_17.initCreateCompositionM( 0, 0, 20, 0, 0, 0); // 合成行列作成
dice_17.createRotM2();
dice_17.init();
diceArray.push(dice_17);
// サイコロ18
dice_18 = new Dice(0, 0, 0);
dice_18.initCreateCompositionM( 20, 0, 20, 0, 0, 0); // 合成行列作成
dice_18.createRotM2();
dice_18.init();
diceArray.push(dice_18);
// サイコロ19
dice_19 = new Dice(0, 0, 0);
dice_19.initCreateCompositionM( -20, 20, -20, 0, 0, 0); // 合成行列作成
dice_19.createRotM2();
dice_19.init();
diceArray.push(dice_19);
// サイコロ20
dice_20 = new Dice(0, 0, 0);
dice_20.initCreateCompositionM( 0, 20, -20, 0, 0, 0); // 合成行列作成
dice_20.createRotM2();
dice_20.init();
diceArray.push(dice_20);
// サイコロ21
dice_21 = new Dice(0, 0, 0);
dice_21.initCreateCompositionM( 20, 20, -20, 0, 0, 0); // 合成行列作成
dice_21.createRotM2();
dice_21.init();
diceArray.push(dice_21);
// サイコロ22
dice_22 = new Dice(0, 0, 0);
dice_22.initCreateCompositionM( -20, 20, 0, 0, 0, 0); // 合成行列作成
dice_22.createRotM2();
dice_22.init();
diceArray.push(dice_22);
// サイコロ23
dice_23 = new Dice(0, 0, 0);
dice_23.initCreateCompositionM( 0, 20, 0, 0, 0, 0); // 合成行列作成
dice_23.createRotM2();
dice_23.init();
diceArray.push(dice_23);
// サイコロ24
dice_24 = new Dice(0, 0, 0);
dice_24.initCreateCompositionM( 20, 20, 0, 0, 0, 0); // 合成行列作成
dice_24.createRotM2();
dice_24.init();
diceArray.push(dice_24);
// サイコロ25
dice_25 = new Dice(0, 0, 0);
dice_25.initCreateCompositionM( -20, 20, 20, 0, 0, 0); // 合成行列作成
dice_25.createRotM2();
dice_25.init();
diceArray.push(dice_25);
// サイコロ26
dice_26 = new Dice(0, 0, 0);
dice_26.initCreateCompositionM( 0, 20, 20, 0, 0, 0); // 合成行列作成
dice_26.createRotM2();
dice_26.init();
diceArray.push(dice_26);
// サイコロ27
dice_27 = new Dice(0, 0, 0);
dice_27.initCreateCompositionM( 20, 20, 20, 0, 0, 0); // 合成行列作成
dice_27.createRotM2();
dice_27.init();
diceArray.push(dice_27);
for (i = 0; i < hitDice.length; i++ ) {
hitDice[i] = new Array();
for (var j:int = 0; j < hitDice[i].length; j++ ) {
hitDice[i][j] = false;
}
}
this.addEventListener(Event.ENTER_FRAME, loading);
}
// サイコロを読み込んでからループ処理を呼び出す
private function loading(e:Event):void
{
var cnt:int = 0;
for each(var dice:Dice in diceArray) {
if (dice.objImport_dice.completeFlag) {
dice.update(this.sp, persM, modelM, viewPos); // 面の法線を求めなければならない
dice.setDiceNumberInit(); // サイコロの目を設定する
dice.setDiceNumber();
cnt++;
}
}
if (cnt == diceArray.length) {
// リスナー登録
//----------------------------------
//this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
// マウスの左ボタンが押されたときに呼び出されるイベント
stage.addEventListener(MouseEvent.MOUSE_DOWN, MouseLDownFunc);
// マウスの左ボタンが離されたときに呼び出されるイベント
//stage.addEventListener(MouseEvent.MOUSE_UP, MouseLUpFunc);
this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
this.removeEventListener(Event.ENTER_FRAME, loading);
}
}
private function onEnterFrame(e:Event):void
{
sp.graphics.clear();
/* if (diceArray.length == 0) {
Debug.trace(" You did it !" + "\n" +
"completed the Stage");
}*/
/* if (Dice.AfterRotFlag) { // 回転後なら
Dice.AfterRotFlag = false;
judge();
}*/
diceArraySort();
// サイコロ1
// -------------------------------------------------------
//this.dice_01.update(this.sp, persM, modelM, viewPos);
// サイコロ2
// -------------------------------------------------------
//this.dice_02.update(this.sp, persM, modelM, viewPos);
/*for each(var dice:Dice in diceArray) {
dice.update(this.sp, persM, modelM, viewPos);
}*/
/*for (var i:int = 0; i < map.mapArray.length; i++ ) {
for (var j:int = 0; j < map.mapArray[i].length; j++ ) {
if (map.mapArray[i][j] is Dice) {
map.mapArray[i][j].update(this.sp, persM, modelM, viewPos);
}
}
}*/
for each(var dice:Dice in diceArray) {
dice.update(this.sp, persM, modelM, viewPos);
}
/*this.rotM = new Matrix4x4();
angle += 1;
angle = 0;
if (angle > 360.0) {
angle -= 360.0;
}
rotM.RotateY(angle * Math.PI / 180);*/
}
private var oldMouseX:Number = 0;
private var oldMouseY:Number = 0;
public function MouseLDownFunc(event:MouseEvent):void
{
if (diceArray.length == 0) // サイコロがなければリターン
return;
//if (cubeFlag) return; // キューブが回転中ならリターン
var screenY:Number;
var screenX:Number;
screenY = -((mouseY - 150) / 150);
screenX = (mouseX - 200) / 200;
var fov:Number = 45.0; // 視野角(FOV:Field Of View)
var aspect:Number = Number(400) / Number(300); // aspect比を計算
// ベクトルαを求める
var d:Vector3d = new Vector3d(0 - this.viewPos.x, 0 - this.viewPos.y, 0 - viewPos.z); // ベクトルdを求める
var dd:Number = Math.sqrt((d.x * d.x) + (d.y * d.y) + (d.z * d.z) ); // ベクトルdの大きさを求める
var h:Number = Number(dd * Math.tan(fov * (Math.PI / 180)));
var temp:Vector3d = new Vector3d();
temp.x = viewM.m10 * h * screenY;
temp.y = viewM.m11 * h * screenY;
temp.z = viewM.m12 * h * screenY;
// ベクトルβを求める
var beta:Vector3d = new Vector3d(1, 0, -1); //ベクトルαを求める
beta.Normalize();
var temp2:Vector3d = new Vector3d();
temp2.x = (beta.x * (h * aspect)) * screenX;
temp2.y = (beta.y * (h * aspect)) * screenX;
temp2.z = (beta.z * (h * aspect)) * screenX;
var temp_2:Vector3d = new Vector3d();
var temp_3:Vector3d = new Vector3d();
//temp_2.Add(temp, temp2, temp_3);
temp_2.x = temp.x + temp2.x;
temp_2.y = temp.y + temp2.y;
temp_2.z = temp.z + temp2.z;
var screenY2:Number = temp_2.y;
var screenX2:Number = temp_2.x;
var screenZ:Number = temp_2.z;
// スクリーンzを求めるための直線の方程式
// p = x + tv : レイの方程式
// (p - p0)・n = 0 : 平面の方程式
// t = (x - p0)・v / v・n
// e : 視点ベクトル
// x : スクリーン座標
// n : 法線ベクトル
// v : 方向ベクトル v = x - eye
var boolean:Boolean;
var tv:Vector3d = new Vector3d();
for each(var dice:Dice in diceArray) {
for each(var face:Face in dice.obj3d_dice.face) {
if (_Math._round(face.normal.x) == 0 && _Math._round(face.normal.y) == 1 && _Math._round(face.normal.z)== 0) {
var _face:Face = face; // 面を取得
boolean = Intersect(_face, screenX2, screenY2, screenZ, tv);
if (boolean)
break;
}
}
if (boolean)
break;
}
this.diceObject = dice; // createCompositionメソッドで使用
if (boolean) { // trueなら
dice.selectFlag = true;
dice.changeTexture(); // テクスチャを変更
oldMouseX = mouseX;
oldMouseY = mouseY;
stage.addEventListener(MouseEvent.MOUSE_MOVE, MouseMoveFunc);
}
}
private function Intersect(face:Face, screenX2:Number, screenY2:Number, screenZ:Number, tv:Vector3d):Boolean
{
var _x:Vector3d = new Vector3d(100, 100, 100); // 視点
var screenVec:Vector3d = new Vector3d(screenX2, screenY2, screenZ); // スクリーンをクリック座標を取得
// 方向ベクトルを求める
var v:Vector3d = new Vector3d();
screenVec.Subtract(screenVec, _x, v); // vに方向ベクトルを格納する
v.Normalize();
var xp:Vector3d = new Vector3d();
_x.Subtract(face.Mv[0].v, _x, xp);
var upNum:Number = xp.DotProduct(face.normal);
var downNum:Number = v.DotProduct(face.normal);
var t:Number = upNum / downNum;
// p(x, y, z)を求める
tv.x = _x.x + v.x * t;
tv.y = _x.y + v.y * t;
tv.z = _x.z + v.z * t;
//Debug.trace(tv.x + " " + tv.y + " " + tv.z);
// 交点が三角形の内部にあるかを判定する
var d0:Vector3d = new Vector3d();
var d1:Vector3d = new Vector3d();
var c:Vector3d = new Vector3d();
d0.Subtract(tv, face.Mv[0].v, d0);
d1.Subtract(face.Mv[1].v, face.Mv[0].v, d1);
c.crossProduct(d1, d0, c);
c.Normalize();
//Debug.trace(c.x + " " + c.y + " " + c.z );
if (face.normal.DotProduct(c) < 0)
return false;
d0.Subtract(tv, face.Mv[1].v, d0);
d1.Subtract(face.Mv[2].v, face.Mv[1].v, d1);
c.crossProduct(d1, d0, c);
c.Normalize();
if (face.normal.DotProduct(c) < 0)
return false;
d0.Subtract(tv, face.Mv[2].v, d0);
d1.Subtract(face.Mv[0].v, face.Mv[2].v, d1);
c.crossProduct(d1, d0, c);
c.Normalize();
if (face.normal.DotProduct(c) < 0)
return false;
return true;
}
private function MouseMoveFunc(event:MouseEvent):void
{
var dx:Number = mouseX - oldMouseX;
var dy:Number = mouseY - oldMouseY;
var radians:Number = Math.atan2(dy, dx);
var rotation:Number = radians * 180 / Math.PI;
if ( -45 <= rotation && rotation < 0 || 0 <= rotation && rotation < 45) {
if (!map.hitJudge("RIGHT", diceObject)) { // 移動できないなら
return;
}
//Debug.trace("右");
Dice.AfterRotFlag = false; // 回転中
diceObject.mouseState = "RIGHT";
diceObject.moveFlag = true;
}else if (90 <= rotation && rotation < 135 || 45 <= rotation && rotation < 90) {
if (!map.hitJudge("FRONT", diceObject)) { // 移動できないなら
return;
}
//Debug.trace("前");
Dice.AfterRotFlag = false; // 回転中
diceObject.mouseState = "FRONT";
diceObject.moveFlag = true;
}else if ( -180 <= rotation && rotation < -135 || 135 <= rotation && rotation <= 180) {
if (!map.hitJudge("LEFT", diceObject)) { // 移動できないなら
return;
}
//Debug.trace("左");
Dice.AfterRotFlag = false; // 回転中
diceObject.mouseState = "LEFT";
diceObject.moveFlag = true;
}else if ( -90 <= rotation && rotation < -45 || -135 <= rotation && rotation < -90) {
if (!map.hitJudge("BACK", diceObject)) { // 移動できないなら
return;
}
//Debug.trace("後");
Dice.AfterRotFlag = false; // 回転中
diceObject.mouseState = "BACK";
diceObject.moveFlag = true;
}
/*trace("マップ情報は" + "\n");
for (var i:int = 0; i < map.mapArray.length; i++ ) {
trace(map.mapArray[i][0] + " " + map.mapArray[i][1] + " " + map.mapArray[i][2] + " " + map.mapArray[i][3] + " " + map.mapArray[i][4] + " " + map.mapArray[i][5] + " " + map.mapArray[i][6] + " ");
}*/
stage.removeEventListener(MouseEvent.MOUSE_MOVE, MouseMoveFunc); // マウスムーブ関数リスナー解除
}
public function diceArraySort():void
{
// diceArray = new Array();
// 視点からサイコロの距離の値でソートする
var dic:Dictionary = new Dictionary();
/* for (var i:int = 0; i < map.mapArray.length; i++ ) {
for (var j:int = 0; j < map.mapArray[i].length; j++ ) {
if (map.mapArray[i][j] is Dice) {
diceArray.push(map.mapArray[i][j]);
dic[map.mapArray[i][j]] = map.mapArray[i][j].getDistance(viewPos);
}
}
}*/
for each(var dice:Dice in diceArray) {
dic[dice] = dice.getDistance(viewPos);
}
diceArray.sort(function(a:Dice, b:Dice):Number
{
return dic[b] - dic[a];
});
}
public function judge():void
{
for (var i:int = 0; i < map.mapArray.length; i++ ) {
for (var j:int = 0; j < map.mapArray[i].length; j++ ) {
if (map.mapArray[i][j] is Dice) {
if(j-1 >= 0)
if (map.mapArray[i][j - 1] is Dice) { // 左
if (map.mapArray[i][j].diceNumber == map.mapArray[i][j - 1].diceNumber) {
hitDice[i][j] = true;
hitDice[i][j - 1] = true;
}
}
if(j+1 <= 6)
if (map.mapArray[i][j + 1] is Dice) { // 右
if (map.mapArray[i][j].diceNumber == map.mapArray[i][j + 1].diceNumber) {
hitDice[i][j] = true;
hitDice[i][j + 1] = true;
}
}
if (i - 1 >= 0)
if (map.mapArray[i - 1][j] is Dice) { // 上
if (map.mapArray[i][j].diceNumber == map.mapArray[i - 1][j].diceNumber) {
hitDice[i][j] = true;
hitDice[i - 1][j] = true;
}
}
if (i + 1 <= 6)
if (map.mapArray[i + 1][j] is Dice) { // 下
if (map.mapArray[i][j].diceNumber == map.mapArray[i + 1][j].diceNumber) {
hitDice[i][j] = true;
hitDice[i + 1][j] = true;
}
}
}
}
}
for (i = 0; i < hitDice.length; i++ ) {
for (j = 0; j < hitDice[i].length; j++ ) {
if (hitDice[i][j]) {
hitDice[i][j] = false;
map.mapArray[i][j] = null;
}
}
}
}
public function changeIndexToPos(index:int):int
{
return (index - 3) * 20;
}
}
}