var that;
var stagemousedownListener;
var stagemousemoveListener;
var stagemouseupListener;
var movie=new Array();
var debugObject;
var stage2D;		
var referenceWidth = 1920;
var referenceHeight = 1080;
var camInitialPos={ x: 0, y: 0, z: 0 };
var debugObjects = [];
let debugCameraTarget={yaw:Math.PI/2,pitch:Math.PI/2,radius:camInitialPos.z};
var scene3D, camera, renderer;
var onTickPaused=true;
var exitBtn;
var keysPressed = {};
var myRightHandGroup;
var foods=[];
var question;
var itemSubject,itemDescription,itemTime,itemLevel,itemFood,itemCut,itemDemo,itemDifficulty,itemSensitivity,itemQuestion,itemScore,itemEscape;
var itemIndicator,turnLeftBtn,confirmBtn,turnRightBtn;
var arrowHint;var raycaster = new THREE.Raycaster(); // For mouse click detection
var mouse = new THREE.Vector2();
let drag=false;
var mousePos={lx:0,ly:0};
var popupDebug1;
var popupMessage;
var clickReady=false;
var streetLights=[];
var PI_H=Math.PI / 180;
var keyLRHolding ; // -1 = left, 0 = stop, 1 = right
var bgSound;
var rafId = null;
var netAngle ;
var lastUpdateNetAngle ;
var incrementFrameCounter ;
var circles;
var inProcessingHit;
var onStageMouseDownEnabled;
//=========================================================================
// Constructor
//========================================================================= 
function SceneGame() {
    this.onClick = onClick;
    this.onRollover = onRollover;
    this.onRollout = onRollout;
    that = this;
    layer3DSetup();
    layerContent();
}
//=========================================================================
// INIT LAYERS
//=========================================================================
function layer3DSetup() {
    if (cr.start==true){
        cr.start=false;
        cr.level=0;
        cr.result={startDatetime:new Date().getTime(),alertCount:100,score:0};
    }
    
    scene3D = new THREE.Scene();
    scene3D.background= new THREE.Color("black"); // Light blue
    // 2. 建立相機 (視角, 長寬比, 近平面, 遠平面)
    camera = new THREE.PerspectiveCamera(50, referenceWidth / referenceHeight, 1, 1000);
    camera.position.set(0, 0, 0); // 移動相機，否則會跟物體重疊
    camera.rotation.set(0, 0, 0);
    // camera.lookAt(0,0,0);
    // Camera X rotation 360 degrees continuously 
    var canvasWebGL = document.getElementById('canvasWebGL');
    renderer = new THREE.WebGLRenderer({ canvas: canvasWebGL});
    renderer.setSize(referenceWidth, referenceHeight);
    renderer.setPixelRatio(window.devicePixelRatio || 1);
    renderer.sortObjects = true; // 啟用物體排序，使 renderOrder 生效
    canvasWebGL.style.position = 'absolute';
    canvasWebGL.style.top = '0';
    canvasWebGL.style.left = '0';

    // === 加入光源 (簡化為早上風格) ===
    // Overhead streetlight - radiates in all directions (4八方散發)
    var startZ=40,padZ=20
    for(var i=0;i<6;i++){

        var streetLight = new THREE.PointLight(0xffffff,0.35);
        if (cr.result.alertCount<1){
            streetLight.color.setHex(0xff0000); // Red when escape count is low
        }
        streetLight.position.set(0, 14, startZ-(i*padZ));
        streetLight.originalPosition = {x: streetLight.position.x, y: streetLight.position.y, z: streetLight.position.z};
        streetLight.originalRotation = {x: streetLight.rotation.x, y: streetLight.rotation.y, z: streetLight.rotation.z};
        streetLight.distance = 160;
        streetLight.decay = 1;
        scene3D.add(streetLight);
        streetLights[streetLights.length]=streetLight;
    }

    // ── Map ─────────────────────────────────────────────────────────
    APL.map.visible = true;
    APL.map.type = "object";
    APL.map.objectId = "map";
    APL.map.renderOrder = 1;
    APL.map.position.set(0.000, -3.700, -53.000);
    APL.map.rotation.set(0, 0, 0);
    APL.map.scale.set(1, 1, 1);
    APL.map.doors=new Array();
    APL.map.traverse(function(child) {
        var doors = [   'wheel1','look_top1','look_bottom1','look_left1','look_right1','wholeDoor1',
                        'wheel2','look_top2','look_bottom2','look_left2','look_right2','wholeDoor2',
                        'wheel3','look_top3','look_bottom3','look_left3','look_right3','wholeDoor3',
                        'wheel4','look_top4','look_bottom4','look_left4','look_right4','wholeDoor4'
                    ];
        for (var d = 0; d < doors.length; d++) {
            if (child.name === doors[d]) {
                child.originalPos=child.position.clone();
                child.originalRot=child.rotation.clone();
                child.originalScale=child.scale.clone();
                // doors[d].obj[doors[d].bones[b]] = child;
                APL.map.doors[child.name]=child;
            }
        }
    });
    debugObjects.push(APL.map);
    scene3D.add(APL.map);
}
//-------------------------------------------------------------------------
function layerContent() {
    netAngle = 0.00;
    lastUpdateNetAngle = 0.00;
    incrementFrameCounter=0;
    keyLRHolding = 0;
    var canvas2D = document.getElementById('canvas2D');
    canvas2D.width = referenceWidth;
    canvas2D.height = referenceHeight;
    canvas2D.style.zIndex = '10';
    
    stage2D = new createjs.Stage("canvas2D");
    stage2D.enableMouseOver();
    // createjs.Sound.play("game_bgm22", {loop: -1});
    if (bgSound===undefined) {
        bgSound=createjs.Sound.play("game_bgm2", {loop: -1});
    }    
    bgSound.volume = 0.6;

    // ========== Instrument Scale Indicator (itemIndicator) ==========
    // Range: -5 to 5, 100 divisions (0.1 each), white background, black ticks, red pointer
    itemIndicator = cr.UIManager.addContainer(stage2D, 960, 750, 1, 1, 0, "itemIndicator", 0, 0);
    itemIndicator.alpha=0;
    var indWidth = 780;
    var indHeight = 70;
    var indBg = new createjs.Shape();
    indBg.graphics.beginFill("#ffffff").drawRect(-indWidth/2, -indHeight/2, indWidth, indHeight);
    indBg.graphics.beginStroke("#000000").setStrokeStyle(1.5).drawRect(-indWidth/2, -indHeight/2, indWidth, indHeight);

    var indTicks = new createjs.Shape();
    var g = indTicks.graphics;
    itemIndicator.totalDivisions = 100;    // -5 to 5 in steps of 0.1
    var padding =20; // inner padding
    var tickAreaWidth = indWidth -padding; // inner padding
    itemIndicator.limitLR=((itemIndicator.totalDivisions/2)-(padding/2))/10; // 50 ticks to the left of center
    for (var i = 0; i <= itemIndicator.totalDivisions; i++) {
        var tx = -tickAreaWidth/2 + i * (tickAreaWidth / itemIndicator.totalDivisions);
        var isMajor = (i % 10 === 0);   // every 1.0 unit
        var isMid   = (i % 5 === 0);    // every 0.5 unit
        var tickH   = isMajor ? 18 : (isMid ? 12 : 7);
        g.beginStroke("#000000").setStrokeStyle(isMajor ? 1.5 : 1)
         .moveTo(tx, -indHeight/2 + 2)
         .lineTo(tx, -indHeight/2 + 2 + tickH);
        if (isMajor) {
            var labelVal = -5 + i * 0.1;
            var lbl = new createjs.Text(labelVal.toFixed(0), "bold 18px Arial", "#000000");
            lbl.textAlign = "center";
            lbl.textBaseline = "top";
            lbl.x = tx;
            lbl.y = indHeight*0.5;
            itemIndicator.addChild(lbl);
        }
    }
    var indPointer = new createjs.Shape();
    indPointer.graphics.setStrokeStyle(8).beginStroke("#a31c49")
     .moveTo(0, -indHeight/2 + 2).lineTo(0, indHeight/2 - 2);
    indPointer.alpha = 1;
    var indArea = new createjs.Shape();
    indArea.alpha = 1;
    itemIndicator.indArea=indArea;
    itemIndicator.addChild(indBg, indTicks, indArea, indPointer);
    // Internal helper: map value [-5,5] to local x
    var _indTickW = indWidth - 20;
    function _indValToX(v) { return (Math.max(-5, Math.min(5, v)) / 10) * _indTickW; }
    function _updateIndArea() {
        var x1 = _indValToX(itemIndicator.targetStartPT._x);
        var x2 = _indValToX(itemIndicator.targetEndPT._x);
        var left = Math.min(x1, x2);
        var width = Math.abs(x2 - x1);
        indArea.graphics.clear().beginFill("#1100ff").drawRect(left, -indHeight/2 + 2, width, indHeight - 4);
    }
    itemIndicator.centerPT = {
        _x: 0,
        get x() { return this._x; },
        set x(v) { this._x = v; indPointer.x = _indValToX(v); }
    };
    itemIndicator.centerPT.x = 0;
    itemIndicator.targetStartPT = {
        _x: 0,
        get x() { return this._x; },
        set x(v) { this._x = v; _updateIndArea(); }
    };
    itemIndicator.targetEndPT = {
        _x: 0,
        get x() { return this._x; },
        set x(v) { this._x = v; _updateIndArea(); }
    };
    itemIndicator.targetStartPT.x = 0;
    itemIndicator.targetEndPT.x = 0;
    itemIndicator.setValue = function(val) { itemIndicator.centerPT.x = val; };
    // ========================================================
    itemIndicator.centerPT.x=0;
    // movie[movie.length] = TweenMax.to(circleRight, 1, {x: 1800,  repeat: -1});

    question = new Array();
    question.currentRowId = 0;
    question.simulateEveryStepZ = 0.085;
    question.simulateEverySecZ =6;  // 0.2 秒 at 30 FPS
    question.tolerateAngle = 0.2; // left and right tolerate
    // test
    // question.currentRowId =4;
    question.noOfLevel=4;
    question.title = "轉盤開門";
    question.noOfQuestion=5;
    question.rangeValues = [[ 0.5,1,1.25  -0.5, -1,-1.25],
                        [0.5,1,1.25,1.5,   -0.5,-1,-1.25,-1.5],
                        [0.5,1,1,1.25,1.5,1.75,        -0.5,-1,-1,-1.25,-1.5,-1.75],
                        [0.75,1,1.25,1.5,1.75,2       -0.75,-1,-1.25,-1.5,-1.75,-2]
                    ];
    question.trunRange=question.rangeValues[cr.level];
    var array=[2,3,4,4];
    if (cr.difficulty === 'hard' ) {
        array=[3,4,5,5];
    }
    question.noOfOption=array[cr.level];
    question.listOfCircleVal=new Array();
    var centerVal=0, debugI=0;;
    for(var i=0; i<question.noOfQuestion;i++){
        question.listOfCircleVal[i]=new Array();
        for(var j=0;j<question.noOfOption;j++){
            question.listOfCircleVal[i][j]=undefined;
            
        }
    }
    var startXMapNOC=[undefined ,960    ,1080    ,1180    ,1300    ,1408    ,1548];
    var padXMapNOC=[undefined   ,0      ,230    ,220    ,220    ,220    ,250];
    //-----------------------question circles--------------
    var startX= startXMapNOC[question.noOfOption];
    var padX= padXMapNOC[question.noOfOption];
    circles = new Array(); 
    for (var i = 0; i < question.listOfCircleVal.length; i++) {
        for (var j = 0; j < question.listOfCircleVal[question.currentRowId].length; j++) {
            var x = startX - (j * padX);
            var circle = cr.UIManager.addContainer(stage2D, x, 970, 0.85, 0.85, 0, circles.length, 0, 0);
            circle.alpha=0;
            var val=undefined;
            var outerBorder = new createjs.Shape();
            outerBorder.graphics.setStrokeStyle(16).beginStroke("#e6ff57").drawRoundRect(-76.67, -56.67, 153.33, 113.33, 30);
            outerBorder.alpha = 0;
            circle.outerBorder=outerBorder;
            var ranLR=cr.Common.getRandomArray([-1,1]);
            var bgLeft = new createjs.Shape();
            var bgColor ="#0f172a" 
            bgLeft.graphics.beginFill(bgColor).drawRoundRect(-70, -50, 140, 100, 22);
            var borderColorL = "#38bdf8" ;
            bgLeft.graphics.setStrokeStyle(4).beginStroke(borderColorL).drawRoundRect(-70, -50, 140, 100, 22);
            bgLeft.alpha = 0;
            circle.bgLeft=bgLeft;
            var bgRight = new createjs.Shape();
            var bgColor = "#0f172a" ;
            bgRight.graphics.beginFill(bgColor).drawRoundRect(-70, -50, 140, 100, 22);
            var borderColorR =  "#fb923c";
            bgRight.graphics.setStrokeStyle(4).beginStroke(borderColorR).drawRoundRect(-70, -50, 140, 100, 22);
            bgRight.alpha = 0;
            circle.bgRight=bgRight;

            var iconLeft = new createjs.Text("↶", "bold 72px Arial", borderColorL);
            iconLeft.alpha = 0;
            iconLeft.textAlign = "center";
            iconLeft.textBaseline = "middle";
            iconLeft.x=5;
            iconLeft.y = 4;
            circle.iconLeft=iconLeft;
            
            var iconRight = new createjs.Text("↷", "bold 72px Arial", borderColorR);
            iconRight.alpha = 0;
            iconRight.textAlign = "center";
            iconRight.textBaseline = "middle";
            iconRight.x=5;
            iconRight.y = 4;
            circle.iconRight=iconRight;
            if (ranLR[0]==-1){
                circle.bgLeft.alpha=0.92;
                iconLeft.alpha = 1;
                
            }else{
                circle.bgRight.alpha=0.92;
                iconRight.alpha = 1;
            }
            var txt = new createjs.Text(val, "bold 25px Arial", "#ffffff");
            txt.x=-20;
            txt.textAlign = "center";
            txt.textBaseline = "middle";
            txt.y = 36;
            txt.alpha=0.01;
            var txt2 = new createjs.Text("圈 id:"+circles.length, "bold 25px Arial", "#ffffff");
            txt2.alpha=0.01;
            txt2.x=41;
            txt2.y = 16;
            var checkMark = new createjs.Shape();
            checkMark.graphics.setStrokeStyle(15, 'round', 'round').beginStroke("#00dd00");
            // Draw checkmark: small line from bottom-left to middle, then long line up-right
            checkMark.graphics.moveTo(-36, -216).lineTo(-6, -174).lineTo(42, -246);
            checkMark.scaleX =checkMark.scaleY= 0.7;
            checkMark.alpha = 0;
            checkMark.y=80;
            circle.checkMark=checkMark;
            circle.netAngle=val;
            circle.focusScale=1;
            circle.txt2=txt2;
            circle.addChild(outerBorder, bgLeft,bgRight, iconLeft, iconRight, txt, txt2, checkMark);
            circle.rowId=i;
            circle.txt = txt;
            circle.colEnd=false;
            if (j==question.listOfCircleVal[question.currentRowId].length-1){
                circle.colEnd=true;
            }
            circles.focusing=false;
            if (question.currentRowId===circle.rowId && j==0){
                circle.focusing=true;
            }
            stage2D.addChild(circle);
            circles[circles.length]=circle;
        }
    }
    //-----------------------items and button--------------
    var fontSize=38, startY=50,padY=80;
    itemSubject = cr.UIManager.addContainer(stage2D, 180,startY+(padY*0), 1, 1, 0, "", 0, 0);
    var bg = cr.UIManager.addShape(stage2D, "drawRoundRect", [0, 0, 330,75, 8],  "#2ecc71", -163,0, "", 0, undefined, 0);
    bg.alpha=0.35;
    var title = cr.UIManager.addText(stage2D, "項目:", "bold "+fontSize+"px Arial", "blank", -140, 0, "");
    title.textAlign="left";
    title.regX=0;
    var txt = cr.UIManager.addText(stage2D, question.title, "bold "+fontSize+"px Arial", "blank", -32, 0, "");
    txt.textAlign="left";
    txt.lineWidth = 318;
    txt.regX=0;
    itemSubject.txt=txt;
    itemSubject.addChild(bg,title,txt);
    var currentTime=new Date().getTime();
    var diffSec = Math.round((currentTime-cr.result.startDatetime)/1000 * 10) / 10;
    itemTime=addItemSqure("時間:",new Date((diffSec*1000)).toISOString().substr(14, 5),180,startY+(padY*1),"#ffffff","#333",fontSize);
    itemTime.totalDistance=0;

    itemDifficulty = cr.UIManager.addContainer(stage2D, 180,startY+(padY*2), 1, 1, 0, "", 0, 0);
    var bg = cr.UIManager.addShape(stage2D, "drawRoundRect", [0, 0, 295,75, 8], "#3b82f6", -160,0, "", 0, undefined, 0);
    bg.alpha=0.35;
    var title = cr.UIManager.addText(stage2D, "難度:", "bold "+fontSize+"px Arial", "#333", -140, 0, "");
    title.textAlign="left";
    title.regX=0;
    var difficultyLabel = (cr.difficulty === 'easy') ? '普通' :  '難';
    var txt = cr.UIManager.addText(stage2D,difficultyLabel, "bold "+fontSize+"px Arial", "#333", -19, 0, "");
    txt.textAlign="left";
    txt.regX=0;
    itemDifficulty.txt=txt;
    itemDifficulty.addChild(bg,title,txt);

    itemLevel = cr.UIManager.addContainer(stage2D, 180,startY+(padY*3), 1, 1, 0, "", 0, 0);
    var bg = cr.UIManager.addShape(stage2D, "drawRoundRect", [0, 0, 295,75, 8], "yellow", -160,0, "", 0, undefined, 0);
    bg.alpha=0.35;
    var title = cr.UIManager.addText(stage2D, "等級:", "bold "+fontSize+"px Arial", "#333", -140, 0, "");
    title.textAlign="left";
    title.regX=0;
    var txt = cr.UIManager.addText(stage2D,cr.level+1, "bold "+fontSize+"px Arial", "#333", -17, 0, "");
    txt.textAlign="left";
    var val=" / "+(question.noOfLevel)+"";
    var txt2 = cr.UIManager.addText(stage2D, val, "bold "+fontSize+"px Arial", "#333", 2, 0, "");
    txt2.textAlign="left";
    txt2.regX=0;
    itemLevel.txt=txt;
    itemLevel.addChild(bg,title,txt,txt2);

    itemQuestion = cr.UIManager.addContainer(stage2D, 180,startY+(padY*4), 1, 1, 0, "", 0, 0);
    var bg = cr.UIManager.addShape(stage2D, "drawRoundRect", [0, 0, 295,75, 8], "#ec4899", -160,0, "", 0, undefined, 0);
    bg.alpha=0.35;
    var title = cr.UIManager.addText(stage2D, "題目:", "bold "+fontSize+"px Arial", "#333", -140, 0, "");
    title.textAlign="left";
    title.regX=0;
    var txt = cr.UIManager.addText(stage2D, question.currentRowId+1, "bold "+fontSize+"px Arial", "#333", -17, 0, "");
    txt.textAlign="left";
    var val=" / "+(question.noOfQuestion);
    var txt2 = cr.UIManager.addText(stage2D, val, "bold "+fontSize+"px Arial", "#333", 2, 0, "");
    txt2.textAlign="left";
    txt2.regX=0;
    itemQuestion.txt=txt;
    itemQuestion.addChild(bg,title,txt,txt2);

    itemScore = cr.UIManager.addContainer(stage2D, 180,startY+(padY*5), 1, 1, 0, "", 0, 0);
    var bg = cr.UIManager.addShape(stage2D, "drawRoundRect", [0, 0, 295,75, 8], "#10b981", -160,0, "", 0, undefined, 0);
    bg.alpha=0.7;
    var title = cr.UIManager.addText(stage2D, "分數:", "bold "+(fontSize+5)+"px Arial", "#333", -140, 4, "");
    title.textAlign="left";
    title.regX=0;
    var txt = cr.UIManager.addText(stage2D, cr.result.score, "bold "+(fontSize+5)+"px Arial", "#333", 25, 4, "");
    txt.textAlign="left";
    var scoreBadge = cr.UIManager.addText(stage2D, "-10", "bold 70px Arial", "#ff4444", 30, 65, "");
    scoreBadge.textAlign="left";
    scoreBadge.alpha=0;
    itemScore.scoreBadge=scoreBadge;
    itemScore.txt=txt;
    itemScore.addChild(bg,title,txt,scoreBadge);

    itemEscape = cr.UIManager.addContainer(stage2D, 1750,startY+(padY*5), 1, 1, 0, "", 0, 0);
    var bg = cr.UIManager.addShape(stage2D, "drawRoundRect", [0, 0, 280,75, 8], "#ff6b35", -160,0, "", 0, undefined, 0);
    bg.alpha=0.7;
    var title = cr.UIManager.addText(stage2D, "🔔警鐘", "bold "+(fontSize)+"px Arial", "#fff", -140, 4, "");
    title.textAlign="left";
    title.regX=0;
    itemEscape.countInitialDown=100;
    var txt = cr.UIManager.addText(stage2D,cr.result.alertCount.toFixed(0), "bold "+(fontSize)+"px Arial", "#fff", 40, 4, "");
    txt.textAlign="left";
    var alertBadge = cr.UIManager.addText(stage2D, "+"+itemEscape.countInitialDown, "bold 70px Arial", "#44ff44", 37, 65, "");
    alertBadge.textAlign="left";
    alertBadge.alpha=0;
    itemEscape.alertBadge=alertBadge;
    itemEscape.txt=txt;
    itemEscape.addChild(bg,title,txt,alertBadge);

    
    // ========== Direction Control Buttons (Circular Style with Icons) - Top Center ==========
    var topMargins=[491,494,488,495]
    var topMargin = topMargins[cr.level];
    var circleBtnRadius = 40;
    var btnSpacing = 340;
    var centerX = referenceWidth / 2;
    
    // Turn Left Button (轉左) - Icon: ⟲ - Left position - Red
    turnLeftBtn = cr.UIManager.addContainer(stage2D, centerX - btnSpacing, topMargin, 1, 1, 0, "turnLeftBtn", 0, 0);
    turnLeftBtn.alpha=0;
    var bgTurnLeft = new createjs.Shape();
    bgTurnLeft.graphics.beginFill("#a0a0a0").drawCircle(0, 0, circleBtnRadius);
    bgTurnLeft.alpha = 0.85;
    var txtTurnLeft = new createjs.Text("⟲", "bold 48px Arial", "#ffffff");
    txtTurnLeft.textAlign = "center";
    txtTurnLeft.textBaseline = "middle";
    turnLeftBtn.addChild(bgTurnLeft, txtTurnLeft);
    turnLeftBtn.cursor = "pointer";
    stage2D.addChild(turnLeftBtn);
    cr.Common.addBasicEvent([turnLeftBtn], that);
    
    // Confirm Button (中間鍵) - Icon: ⊙ - Center position - Orange
    confirmBtn = cr.UIManager.addContainer(stage2D, centerX, topMargin, 1, 1, 0, "confirmBtn", 0, 0);
    confirmBtn.alpha=0;
    var bgConfirm = new createjs.Shape();
    bgConfirm.graphics.beginFill("#a0a0a0").drawCircle(0, 0, 33);
    bgConfirm.alpha = 0.85;
    var txtConfirm = new createjs.Text("⊙", "bold 48px Arial", "#ffffff");
    txtConfirm.textAlign = "center";
    txtConfirm.textBaseline = "middle";
    arrowHint = new createjs.Container();
    arrowHint.alpha=0;
    arrowHint.x = 0;
    arrowHint.y = -70;
    arrowHint.alpha = 1;
    var arrowShape = new createjs.Shape();
    arrowShape.y=10;
    arrowShape.graphics.beginFill("#ffff00").setStrokeStyle(3).beginStroke("#ffffff");
    arrowShape.graphics.moveTo(-35, 40).lineTo(35, 40).lineTo(0, -10).closePath();
    arrowShape.rotation = 180;
    var exclaimTxt = new createjs.Text("按一下", "bold 35px Arial", "#ffffff");
    exclaimTxt.textAlign = "center";
    exclaimTxt.textBaseline = "middle";
    exclaimTxt.y = -65;
    arrowHint.addChild(arrowShape, exclaimTxt);
    confirmBtn.arrowHint=arrowHint;
    confirmBtn.addChild(bgConfirm, txtConfirm, arrowHint);
    confirmBtn.cursor = "pointer";
    stage2D.addChild(confirmBtn);
    cr.Common.addBasicEvent([confirmBtn], that);
    
    // Turn Right Button (轉右) - Icon: ⟳ - Right position - Green
    turnRightBtn = cr.UIManager.addContainer(stage2D, centerX + btnSpacing, topMargin, 1, 1, 0, "turnRightBtn", 0, 0);
    turnRightBtn.alpha=0;
    var bgTurnRight = new createjs.Shape();
    bgTurnRight.graphics.beginFill("#9e9e9e").drawCircle(0, 0, circleBtnRadius);
    bgTurnRight.alpha = 0.85;
    var txtTurnRight = new createjs.Text("⟳", "bold 48px Arial", "#ffffff");
    txtTurnRight.textAlign = "center";
    txtTurnRight.textBaseline = "middle";
    turnRightBtn.addChild(bgTurnRight, txtTurnRight);
    turnRightBtn.cursor = "pointer";
    stage2D.addChild(turnRightBtn);
    cr.Common.addBasicEvent([turnRightBtn], that);
  
    exitBtn = cr.UIManager.addContainer(stage2D, referenceWidth - 90, 50, 1, 1, 0, "exit", 0, 0);
    var exitBtnBg = cr.UIManager.addShape(stage2D, "drawRoundRect", [0, 0, 140, 60, 8], "#FF6B6B", 0, 0, "", undefined, undefined, 1);
    exitBtn.addChild(exitBtnBg);
    var exitBtnText = cr.UIManager.addText(stage2D, "返回", "bold 25px Arial", "#FFFFFF", 0, 3, "");
    exitBtn.addChild(exitBtnText);
    stage2D.addChild(exitBtn);
    cr.Common.addBasicEvent([exitBtn], that);

    popupFinish = cr.UIManager.addContainer(stage2D, referenceWidth / 2, referenceHeight / 2, 1, 1, 0, "", 0, 0);
    var gameOverBg = cr.UIManager.addShape(stage2D, "drawRoundRect", [0, 0, 1920, 1080,0], "#000000", 0, 0, "", undefined, undefined);
    gameOverBg.alpha=0.6;       
    var popupBg = cr.UIManager.addShape(stage2D, "drawRoundRect", [0, 0, 500, 480,30], "#ffffff", 0, 0, "", undefined, undefined);
    popupBg.alpha=1; 
    popupFinish.addChild(gameOverBg,popupBg); 
    var finishText = cr.UIManager.addText(stage2D, "訓練完成!", "bold 52px Arial", "darkred", 0, -110, "");
    popupFinish.addChild(finishText);
    var finishInfoText = cr.UIManager.addText(stage2D, "花費時間: 00:00\n等級:"+question.noOfLevel+"\n分數:"+cr.result.score, "bold 35px Arial", "black", 235, 4, "",undefined);
    finishInfoText.lineHeight=50;
    popupFinish.txt=finishInfoText;
    finishInfoText.textAlign="center";
    popupFinish.addChild(finishInfoText);
    var exitBtn = cr.UIManager.addContainer(stage2D, 0, 150, 1, 1, 0, "exit", 0, 0);
    var exitBtnBg = cr.UIManager.addShape(stage2D, "drawRoundRect", [0, 0, 200, 70, 10], "#FF6B6B", 0, 0, "", undefined, undefined);
    exitBtn.addChild(exitBtnBg);
    var exitBtnText = cr.UIManager.addText(stage2D, "返回", "bold 25px Arial", "#FFFFFF", 0, 0, "");
    exitBtn.addChild(exitBtnText);
    cr.Common.addBasicEvent([exitBtn], that);
    popupFinish.addChild(exitBtn);
    stage2D.addChild(popupFinish);
    popupFinish.alpha = 0;

    popupMessage = cr.UIManager.addContainer(stage2D, referenceWidth / 2, referenceHeight / 2, 1, 1, 0, "", 0, 0);
    var shadow = cr.UIManager.addShape(stage2D, "drawRoundRect", [0, 0, 400, 230, 25], "#000000", 0, 0, "", undefined, undefined, 0.3);
    shadow.alpha = 0.4;
    shadow.filters = [];  // Prepare for blur effect
    popupMessage.addChild(shadow);
    var bg = cr.UIManager.addShape(stage2D, "drawRoundRect", [0, 0, 420, 220, 25], "#1a1a2e", 0, 0, "", undefined, undefined, 1);
    bg.alpha = 0.65;
    if (cr.level>0){
        bg.alpha= 0;
        shadow.alpha=0;
    }
    popupMessage.addChild(bg);
    var msg=cr.level==0?"開始訓練":"升級了!";
    var txt1 = cr.UIManager.addText(stage2D, msg, "bold 65px Arial", "#ffffff", 130, -10, "");
    txt1.textAlign="center";
    var txt2 = cr.UIManager.addText(stage2D, "級數:"+(cr.level+1), "bold 45px Arial", "#ffffff", 60, 70, "");
    txt2.textAlign="center";
    popupMessage.addChild(txt1,txt2);
    popupMessage.txt1=txt1;
    popupMessage.txt2=txt2;
    stage2D.addChild(popupMessage);
    popupMessage.alpha=0;
    movie[movie.length] = TweenMax.from(popupMessage, 2, {delay:0.5,alpha: 1,ease:Power4.easeIn});

    var y = 0;
    question.goCamPos = [
        [0, y, 0],[0, y, -51.652],
        [0, y, -63.356],[25.717, y, -97.706],
        [34.725, y, -109.475], [7.912, y, -133.655],
        [-9.849, y, -146.847], [-29.340, y, 36.930],
        [-29.220, y, 51.419]
    ];
    question.goCamRos = [
        [0,0,0],[0,0,0],
        [0,0,0],[0,-36.3,0],
        [0,-37,0],[0,53,0],
        [0,53,0],[0,180,0],
        [0,180,0]
    ];
    for (var i = 0; i < question.goCamRos.length; i++) {
        question.goCamRos[i][0] *= PI_H;
        question.goCamRos[i][1] *= PI_H;
        question.goCamRos[i][2] *= PI_H;
    }
    question.openPos = [-1.370, 0, -9.950];  
    question.openRos = [0.000, 88 * PI_H, 0.000];
    question.openFinalPos = [14.212, 0, -9.950];  
    question.openFinalRos = [0.000, 88 * PI_H, 0.000];

    var startIndLv=[0,2,4,6];
    question.startIndLv=startIndLv;
    var x = question.goCamPos[startIndLv[cr.level]][0];
    var y = question.goCamPos[startIndLv[cr.level]][1];
    var z = question.goCamPos[startIndLv[cr.level]][2];
    camera.position.set(x, y, z);
    x = question.goCamRos[startIndLv[cr.level]][0];
    y = question.goCamRos[startIndLv[cr.level]][1];
    z = question.goCamRos[startIndLv[cr.level]][2];
    camera.rotation.set(x, y, z);
    // console.log("Camera Start Pos: ", camera.position, camera.rotation);
    var delayOp = 1
    if (cr.level >0) {
        delayOp = 0;
    }
    var destIndexLv=[0,2,3,7];
    var durOps = [3.5,3.5,3.5,6];
    if (cr._DEBUG== true){
        delayOp=0;
        durOps= [1,1,1,1];
    }
    for (var i = startIndLv[cr.level]; i <startIndLv[cr.level]+2; i++) {
        var wp = question.goCamPos[i];
        var wr = question.goCamRos[i];
        // console.log("Camera Move To: ", wp, wr);
        movie[movie.length] = TweenMax.to(camera.position, durOps[cr.level], 
            {delay: delayOp,x: wp[0], y: wp[1], z: wp[2],ease: Power2.easeInOut
        });
        movie[movie.length] = TweenMax.to(camera.rotation, durOps[cr.level], 
            {delay: delayOp,x: wr[0], y: wr[1], z: wr[2],ease: Power1.easeOut,
                onComplete: function() {
                    bgSound.volume = 0.4;
                    for(var j=0;j<circles.length;j++){
                        if (circles[j].rowId === question.currentRowId) {
                            circles[j].alpha=1;
                            if (circles[j].focusing===true){
                                onTickPaused=false;
                                turnLeftBtn.alpha=1;
                                confirmBtn.alpha=1;
                                turnRightBtn.alpha=1;
                            }
                        }
                    }
                }
        });
    }
    onStageMouseDownEnabled=true;
    inProcessingHit=false;
    callResetWheel();
    frameUpdate3D();
    window.addEventListener('resize', onResize);
    onResize();
    createjs.Ticker.framerate = 30;
    stagemousedownListener=stage2D.on("stagemousedown",stagemousedown);
    stagemouseupListener=stage2D.on("stagemouseup",stagemouseup);
    stagemousemoveListener=stage2D.on("stagemousemove",stagemousemove);
    $(document).off('keydown');
    $(document).off('keyup');
    $(document).keydown(onKeydown);
    $(document).keyup(onKeyup);
    createjs.Ticker.addEventListener("tick", onTick);
}
//=========================================================================
//Event handle
//=========================================================================
function onTick(evt) {
    stage2D.update();
    for(var i=0;i<streetLights.length;i++){
        streetLights[i].position.x=camera.position.x+streetLights[i].originalPosition.x;
        streetLights[i].position.y=camera.position.y+streetLights[i].originalPosition.y;
        streetLights[i].position.z=camera.position.z+streetLights[i].originalPosition.z;
        streetLights[i].rotation.x=camera.rotation.x;
        streetLights[i].rotation.y=camera.rotation.y;
        streetLights[i].rotation.z=camera.rotation.z;
    }
    var currentTime=new Date().getTime();
    var diffSec = Math.round((currentTime-cr.result.startDatetime)/1000 * 10) / 10;
    var clockText=new Date((diffSec*1000)).toISOString().substr(14, 5);
    itemTime.txt.text = clockText;
    itemTime.txt.regX = 0;
    
    cr.result.spentSecond=diffSec;
    if (onTickPaused===true){
        return;
    }

    // Update itemEscape countdown
    cr.result.alertCount -= 1/30;
    if (cr.result.alertCount < 0) {
        cr.result.alertCount = 0;
        // Timeout: change lights to red and play alarm
        if (!itemEscape.hasTimedOut) {
            itemEscape.hasTimedOut = true;
            itemEscape.timeoutStart = Date.now();
            for (var i = 0; i < streetLights.length; i++) {
                (function(index) {
                    // Animate light red (255, 107, 107) to deep red (255, 0, 0)
                    var colorProxy = { r: 255, g: 107, b: 107 };
                    movie["streetLightFlash_" + index] = TweenMax.to(colorProxy, 1, { r: 255,g: 0,b: 0,
                        repeat: -1,yoyo: true,ease: Power0.easeNone,
                        onUpdate: function() {
                            var hex = (Math.round(colorProxy.r) << 16) | (Math.round(colorProxy.g) << 8) | Math.round(colorProxy.b);
                            streetLights[index].color.setHex(hex);
                        }
                    });
                })(i);
            }
            createjs.Sound.play("sfc_ambulance", { volume: 1 });
            var reduceScore=100;
            cr.result.score -= reduceScore; // Penalize score, but not below 0
            itemScore.txt.text = cr.result.score;
            itemScore.scoreBadge.text = "-" + reduceScore;
            movie[movie.length] = TweenMax.from(itemScore.scoreBadge, 2, {alpha: 1, ease: Power2.easeIn});
        }
    } else {
        itemEscape.hasTimedOut = false;
        itemEscape.timeoutStart = undefined;
        // Reset lights to white
        for (var i = 0; i < streetLights.length; i++) {
            if (movie["streetLightFlash_" + i]) {
                movie["streetLightFlash_" + i].kill();
                movie["streetLightFlash_" + i] = undefined;
            }
            streetLights[i].color.setHex(0xffffff);
        }
    }
    itemEscape.txt.text = cr.result.alertCount.toFixed(0);

    // Show arrow hint if timeout has lasted more than 15 seconds
    if (itemEscape.hasTimedOut && itemEscape.timeoutStart !== undefined) {
        var timeSinceTimeout = (Date.now() - itemEscape.timeoutStart) / 1000;
        if (timeSinceTimeout > 12) {
            confirmBtn.arrowHint.alpha = Math.sin(Date.now() * 0.01) * 0.5 + 0.5; // Blinking
        } else {
            confirmBtn.arrowHint.alpha = 0;
        }
    } else {
        confirmBtn.arrowHint.alpha = 0;
    }


    if (inProcessingHit === true) {
        return;
    }
    inProcessingHit = true;

    if (keyLRHolding !== 0) {
        incrementFrameCounter++;
        if (incrementFrameCounter >= question.simulateEverySecZ) { // 0.2 秒 at 30 FPS
            netAngle += question.simulateEveryStepZ * keyLRHolding * -1;
            incrementFrameCounter = 0;
        }
    } else {
        incrementFrameCounter = 0;
    }

    var turnIt = false
    if (movie["netAngle"] === undefined) {
        if (lastUpdateNetAngle != netAngle) {
            lastUpdateNetAngle = netAngle;
            turnIt = true;
        }
    } else {
        if (lastUpdateNetAngle != netAngle) {
            lastUpdateNetAngle = netAngle;
            if (movie["netAngle"].totalProgress() != 1) {
                movie["netAngle"].totalProgress(1);
            }
            turnIt = true;
        }
    }
    if (turnIt === true) {
        itemIndicator.centerPT.x=netAngle;
        var value = netAngle * Math.PI * 2 * -1;
        createjs.Sound.play("safe_tuning", { loop: 0 });
        var obj = APL.map.doors["wheel" + (cr.level + 1)];
        movie["netAngle"] = TweenMax.to(obj.rotation, 0.2, { z: value, ease: Power0.easeOut });
    }

    var target;
    for (var i=0;i<circles.length;i++){
        if (circles[i].focusing===true){
            target=circles[i]
            if (target.netAngle===undefined){
                var ran=cr.Common.getRandomArray(question.trunRange);
                var ranPositives = ran.filter(function(val) { return val > 0; });
                var ranNegatives = ran.filter(function(val) { return val < 0; });
                
                if (i==0){
                    var newAngle=ranNegatives[0];
                    if (target.bgRight.alpha>0){
                        newAngle=ranPositives[0];
                    }
                    target.netAngle=newAngle;
                    target.txt.text=newAngle;
                    updateItemIndicator(target.netAngle);
                    target.scaleX=target.scaleY=target.focusScale;  
                    target.outerBorder.alpha=1;
                    movie[movie.length] = TweenMax.from(target.outerBorder, 0.5, {scaleX: 0.5, scaleY: 0.5});
                    break;
                }
                
                for(var j=0;j<ran.length;j++){
                    if (circles[i-1].netAngle===ran[j]){
                            continue;
                    }
                    if ( target.bgRight.alpha>0){
                        if (ran[j]<0){
                            continue;
                        }
                    }else if ( target.bgLeft.alpha>0){
                        if (ran[j]>0){
                            continue;
                        }  
                    }
                    if (circles[i-1].netAngle===undefined){
                        alert("Error: previous circle netAngle is undefined");

                    }
                    var newAngle=ran[j]+circles[i-1].netAngle;
                    if (newAngle>itemIndicator.limitLR || newAngle<-itemIndicator.limitLR){
                        console.log("Generated newAngle out of limit: ", newAngle);
                        newAngle=0;
                        if (circles[i-1].netAngle>0){
                            target.bgRight.alpha=0;
                            target.bgLeft.alpha=0.92;
                            target.iconRight.alpha=0;
                            movie[movie.length] = TweenMax.from(target.iconLeft, 1.5, {rotation: 360});
                            target.iconLeft.alpha=1;
                        }else{
                            target.bgRight.alpha=0.92;
                            target.bgLeft.alpha=0;
                            target.iconRight.alpha=1;
                            movie[movie.length] = TweenMax.from(target.iconRight, 1.5, {rotation: 360});
                            target.iconLeft.alpha=0;
                        }
                        
                    }
                    target.netAngle=newAngle;
                    target.txt.text=newAngle;
                    updateItemIndicator(newAngle);
                    
                    target.scaleX=target.scaleY=target.focusScale;  
                    target.outerBorder.alpha=1;
                    movie[movie.length] = TweenMax.from(target.outerBorder, 0.5, {scaleX: 0.5, scaleY: 0.5});
                    break;
                }
            }
        };
    }
    var currentValue = Math.abs(target.netAngle - netAngle);
    if (target.startNetAngle!==undefined){
        var realNetAngle=netAngle-target.startNetAngle;
        // console.log("startNetAngle: "+target.startNetAngle);
        currentValue = Math.abs(target.netAngle - realNetAngle);
    }
   
    if (target.lastValue === undefined) {
        target.lastValue = currentValue;
        target.lastChangeTime = Date.now();
    } else if (Math.abs(target.lastValue - currentValue) > 0.001) {
        target.lastValue = currentValue;
        target.lastChangeTime = Date.now();
        target.isFlashing = false; // Cancel previous flashing
    }
    
    // Check if value is within range AND hasn't changed for 0.5 seconds
    
    if (netAngle <= itemIndicator.targetStartPT.x && netAngle >= itemIndicator.targetEndPT.x && itemIndicator.alpha != 0   ) {
        // console.log("Checking range: netAngle="+netAngle.toFixed(2)+", targetStart="+itemIndicator.targetStartPT.x.toFixed(2)+", targetEnd="+itemIndicator.targetEndPT.x.toFixed(2)+", alpha="+itemIndicator.alpha);
        target.checkMark.alpha = 1;
        var doSpark=false;
        if (movie["inAreaSpark"]===undefined){
            doSpark=true;
        }
        if (movie["inAreaSpark"]!==undefined && movie["inAreaSpark"].totalProgress() == 1) {
            doSpark=true;
        }
        if (doSpark===true){
            movie["inAreaSpark"] = TweenMax.from(itemIndicator.indArea, 0.1, {alpha: 0.1, ease: Power0.easeNone});
        }
        
        var timeSinceLastChange = (Date.now() - target.lastChangeTime) / 1000;
        if (timeSinceLastChange >= 0.5 && !target.isFlashing) {
            target.isFlashing = true;
            cr.result.score += 10;
            itemScore.txt.text = cr.result.score;
            // Flash outerBorder alpha 0/1 three times (3 cycles)
            createjs.Sound.play("slide", { volume: 0.5 });
            target.scaleX = target.scaleY = 0;
            target.alpha = 1; //
            movie[movie.length] = TweenMax.from(target, 0.3, {scaleX: 1, scaleY: 1,alpha:1,
                ease: Power0.easeNone,
                onComplete: function() {
                    this.target.parent.isFlashing = false;
                    // this.target.parent.alpha = 0; // Reset to original
                }
            });

            target.focusing = false; // Stop focusing after flashing
            // target.alpha = 0; // Reset alpha to original
            var newId=target.objectId+1;
            if (target.colEnd===true){

                if (question.currentRowId==question.noOfQuestion-1){
                    onStageMouseDownEnabled=false;      
                    onTickPaused=true;
                    if (cr.level<question.noOfLevel){
                        itemIndicator.alpha=0;
                        turnLeftBtn.alpha=0;
                        confirmBtn.alpha=0;
                        turnRightBtn.alpha=0;
                        cr.level+=1;
                        var delay = 2
                        var durOp = 1.5;
                        var pos=question.openPos;
                        var ros=question.openRos;
                        if (cr.level===question.noOfLevel){
                            pos=question.openFinalPos;
                            ros=question.openFinalRos;
                        }
                        movie[movie.length] = TweenMax.to(APL.map.doors["wholeDoor"+(cr.level)].position, 
                            durOp, {delay:delay,x: pos[0], y: pos[1], z: pos[2], ease: Power2.easeInOut});
                        movie[movie.length] = TweenMax.to(APL.map.doors["wholeDoor"+(cr.level)].rotation, 
                            durOp, {delay:delay,x: ros[0], y: ros[1], z: ros[2], ease: Power2.easeInOut
                                ,onStart:function(){
                                    createjs.Sound.play("safe_open", { volume: 1 });
                                }
                        });
                        var delayGo = delay+durOp+1.2;
                        var durGo = 2;
                        var wp = question.goCamPos[question.startIndLv[cr.level]];
                        var wr = question.goCamRos[question.startIndLv[cr.level]];
                        if (cr.level===question.noOfLevel){
                            wp = question.goCamPos[question.goCamPos.length-1];
                            wr = question.goCamRos[question.goCamRos.length-1];
                        }
                        // console.log("Camera Move To: ", wp, wr);
                        movie[movie.length] = TweenMax.to(camera.position, durGo, 
                            {delay: delayGo,x: wp[0], y: wp[1], z: wp[2],ease: Power1.easeIn
                        });
                        movie[movie.length] = TweenMax.to(camera.rotation, durGo, 
                            {delay: delayGo,x: wr[0], y: wr[1], z: wr[2],ease: Power1.easeIn,
                                onComplete: function() {
                                    if (cr.level!==question.noOfLevel){
                                        console.log("cr.result.score: ",cr.result.score);
                                        begin();
                                    }else{
                                        popupFinish.txt.text="花費時間: "+itemTime.txt.text+"\n等級:"+question.noOfLevel+"\n分數:"+cr.result.score;
                                        popupFinish.alpha=0;
                                        movie[movie.length] = TweenMax.to(popupFinish, 2, {alpha: 1,ease:Power4.easeIn});
                                    }
                                    
                                }});
                        return;    
                    }
                }
                question.currentRowId+=1;
                itemQuestion.txt.text = question.currentRowId+1;
                for(var i=0;i<circles.length;i++){
                    if (circles[i].rowId === question.currentRowId) {
                        circles[i].alpha=1;
                        movie[movie.length] = TweenMax.from(circles[i], 1.5, {alpha: 0,scaleX: 0, scaleY: 0, ease: Power4.easeIn});
                    }
                }

            }
            circles[newId].focusing = true;
            circles[newId].alpha = 1; // Set next circle to fully visible
            movie[movie.length] = TweenMax.delayedCall(0.5, function() {
                circles[newId].outerBorder.alpha = 1; // Set next circle's outer border to fully visible
                circles[newId].scaleX = circles[newId].scaleY = circles[newId].focusScale; // Set next circle to focus scale
            });
            // console.log("netAngle: "+netAngle);
            circles[newId].startNetAngle=netAngle;
         
            if (  circles[newId].netAngle<0){
                itemIndicator.targetStartPT.x=(netAngle+circles[newId].netAngle) + question.tolerateAngle;
                itemIndicator.targetEndPT.x=(netAngle+circles[newId].netAngle) - question.tolerateAngle;
            }else  if (  circles[newId].netAngle>0){
                itemIndicator.targetStartPT.x=(netAngle+circles[newId].netAngle) + question.tolerateAngle;
                itemIndicator.targetEndPT.x=(netAngle+circles[newId].netAngle) - question.tolerateAngle;
            }
            // console.log("Set target range: "+itemIndicator.targetStartPT.x.toFixed(2)+" to "+itemIndicator.targetEndPT.x.toFixed(2));
            
        }
    }else{
        target.checkMark.alpha = 0;
    }

    inProcessingHit=false;
}
//-------------------------------------------------------------------------
function onRollover(evt) {
    var obj=evt.currentTarget;
    obj.cursor = "pointer";
    createjs.Sound.play("button_mouseover");
    movie[movie.length]=TweenMax.to(obj, .1, {	scaleX:obj.rolloverScale,scaleY:obj.rolloverScale});
};
//-------------------------------------------------------------------------
function onRollout(evt) {
    var obj=evt.currentTarget;
    obj.cursor = "default";
    movie[movie.length]=TweenMax.to(obj, .1, {	scaleX:obj.rolloutScale,scaleY:obj.rolloutScale});
};
//-------------------------------------------------------------------------
function onClick(evt) {
    var obj = evt.currentTarget;
    // alert("Clicked on: " + obj.objectId);
    if (obj.objectId === "exit") {
        createjs.Sound.play("sound_button_click");
        obj.scaleX = obj.scaleY = obj.rolloutScale * 0.95;
        movie[movie.length] = TweenMax.delayedCall(0.3, function(){
            window.location.href = "index.html";
        });
    }else if (obj.objectId === "confirmBtn") {
            createjs.Sound.play("safe_confirm");
            var name="wheel"+(cr.level+1);
            if (movie[name+"po"]!==undefined && movie[name+"po"].totalProgress()!==1){
                movie[name+"po"].repeat(0);
                movie[name+"po"].totalProgress(1);
                console.log("Stop "+name+"po");
                APL.map.doors[name].position.copy(APL.map.doors[name].originalPos);
                APL.map.doors[name].rotation.copy(APL.map.doors[name].originalRot);
            }
            var sZ=APL.map.doors[name].position.z-0.2;
            movie[name+"po"] = TweenMax.to(APL.map.doors[name].position, 0.1,{ z: sZ,repeat: 1, yoyo: true });
            if (movie[name+"sc"]!==undefined && movie[name+"sc"].totalProgress()!==1){
                movie[name+"sc"].repeat(0);
                movie[name+"sc"].totalProgress(1);
                APL.map.doors[name].scale.copy(APL.map.doors[name].originalScale);
                console.log("Stop "+name+"sc");
            }
            var sX=APL.map.doors[name].scale.x-0.2, sY=APL.map.doors[name].scale.y-0.2;
            movie[name+"sc"] = TweenMax.to(APL.map.doors[name].scale, 0.1,{ x: sX, y: sY,repeat: 1, yoyo: true });
            itemEscape.hasTimedOut = false;
            cr.result.alertCount=itemEscape.countInitialDown;
            itemEscape.txt.text = cr.result.alertCount.toFixed(1);
            // cr.result.score -= 15;
            itemScore.txt.text = cr.result.score;
            if (movie["updateAlert"]!==undefined && movie["updateAlert"].totalProgress()!==1){
                movie["updateAlert"].totalProgress(1);
            }
            if (movie["updateScore"]!==undefined && movie["updateScore"].totalProgress()!==1){
                movie["updateScore"].totalProgress(1);
            }
            movie["updateAlert"] = TweenMax.from(itemEscape.alertBadge, 2, {alpha: 1, ease: Power2.easeIn
                ,onComplete:function(){
                    stage2D.removeChild(this.target);
                },});

    }
    APL.handLeft.position.x = -0.5;
}
//-------------------------------------------------------------------------
function onKeydown(evt) {
    if (onStageMouseDownEnabled===false){
        return;
    }
    if (evt.cSharpSType !== undefined) {
        if (evt.cSharpSType === "k") {
            onClick({ currentTarget: { objectId: "confirmBtn" } });
        } else {
            netAngle = evt.netAngle;
        }
    }
}
//-------------------------------------------------------------------------
function onKeyup(evt) {
   
}
//-------------------------------------------------------------------------
function stagemouseup(evt){
    var pt = stage2D.globalToLocal(evt.stageX, evt.stageY);
    keyLRHolding=0;
    if (evt.relatedTarget === null) {
        return;
    }
    var obj = evt.relatedTarget.parent;
    obj.scaleX = obj.scaleY = obj.rolloutScale;
};
//-------------------------------------------------------------------------
function stagemousedown(evt){
    if (onStageMouseDownEnabled===false){
        return;
    }
    // console.log("stagemousedown"); 
    // var obj={originalEvent:{key:"skip"}}	
    var pt = stage2D.globalToLocal(evt.stageX, evt.stageY);
    if (!evt.relatedTarget) return;
    var obj = evt.relatedTarget.parent;
    
    if (obj.objectId === "turnLeftBtn" || obj.objectId === "turnRightBtn") {
        if (obj.objectId === "turnLeftBtn") {
            keyLRHolding=1;
        }else if (obj.objectId === "turnRightBtn") {
            keyLRHolding=-1;
        }
        obj.scaleX = obj.scaleY = obj.scaleX*0.85;
        netAngle += question.simulateEveryStepZ * keyLRHolding * -1;
    }
}
//-------------------------------------------------------------------------
function stagemousemove(evt){
    var pt = stage2D.globalToLocal(evt.stageX, evt.stageY);
    // var obj = evt.relatedTarget.parent;
    // console.log("stagemousemove:" + pt);
}
//-------------------------------------------------------------------------
function onResize() {
    // console.log('窗口大小改變，重新計算畫布縮放');
    var canvas = document.getElementById('canvas2D');
    var canvasWebGL = document.getElementById('canvasWebGL');
    var container = document.getElementById('gameContainer');
    if (!canvas || !container) return;
    canvas.width = referenceWidth;
    canvas.height = referenceHeight;
    var containerWidth = container.offsetWidth;
    var containerHeight = container.offsetHeight;
    var canvasRatio = referenceWidth / referenceHeight;
    var containerRatio = containerWidth / containerHeight;
    var scale;
    
    if (containerRatio > canvasRatio) {
        scale = containerHeight / referenceHeight;
    } else {
        scale = containerWidth / referenceWidth;
    }
    scale = Math.min(scale, 1);
    var scaledWidth = referenceWidth * scale;
    var scaledHeight = referenceHeight * scale;
    var offsetX = (containerWidth - scaledWidth) / 2;
    var offsetY = (containerHeight - scaledHeight) / 2;
    var transformStr = 'translate(' + offsetX + 'px, ' + offsetY + 'px) scale(' + scale + ')';
    canvas.style.transformOrigin = 'top left';
    canvas.style.transform = transformStr;
    canvasWebGL.style.transformOrigin = 'top left';
    canvasWebGL.style.transform = transformStr;
    camera.aspect = referenceWidth / referenceHeight;
    camera.updateProjectionMatrix();
    canvasScale = scale;
    canvasOffsetX = offsetX;
    canvasOffsetY = offsetY;
}
//=========================================================================
// Method
//=========================================================================
function frameUpdate3D() {
    rafId = requestAnimationFrame(frameUpdate3D);
    if (renderer && scene3D && camera) renderer.render(scene3D, camera);
};
//-------------------------------------------------------------------------
async function callResetWheel(){
    // netAngle=0;
    if (window.chrome && window.chrome.webview && window.chrome.webview.hostObjects) {
        await window.chrome.webview.hostObjects.native.resetWheel();
    }
}
//-------------------------------------------------------------------------
function updateItemIndicator(targetAngle){
    itemIndicator.alpha=1;
    if (targetAngle<0){
        itemIndicator.targetStartPT.x=targetAngle + question.tolerateAngle;
        itemIndicator.targetEndPT.x=targetAngle - question.tolerateAngle;
    }else{
        itemIndicator.targetStartPT.x=targetAngle + question.tolerateAngle;
        itemIndicator.targetEndPT.x=targetAngle - question.tolerateAngle;
    }
}
//-------------------------------------------------------------------------
function addItemSqure(title,txt,x,y,bgkolor,fontcolor,fontSize){
    var con = cr.UIManager.addContainer(stage2D, x,y, 1, 1, 0, "", 0, 0);
    var bg = cr.UIManager.addShape(stage2D, "drawRoundRect", [0, 0, 295,75, 8], bgkolor, -160,0, "", 0, undefined, 0);
    bg.alpha=0.35;
    var title = cr.UIManager.addText(stage2D, title, "bold "+fontSize+"px Arial", fontcolor, -140, 0, "");
    title.textAlign="left";
    title.regX=0;
    var txt = cr.UIManager.addText(stage2D, txt, "bold " + fontSize + "px Arial", fontcolor, -30, 0, "");
    txt.textAlign="left";
    txt.regX=0;
    con.txt=txt;
    con.addChild(bg,title,txt);
    stage2D.addChild(con);
    return con;
};
//-------------------------------------------------------------------------
function begin(){
    end();
    layer3DSetup();
    layerContent();
};
//-------------------------------------------------------------------------
function end(){
    if (rafId !== null) { cancelAnimationFrame(rafId); rafId = null; }
    createjs.Ticker.removeEventListener("tick", onTick);
    window.removeEventListener('resize', onResize);
    $(document).off('keydown').off('keyup');

    if (stage2D) {
        stage2D.off("stagemousemove", stagemousemoveListener);
        stage2D.off("stagemousedown", stagemousedownListener);
        stage2D.off("stagemouseup", stagemouseupListener);
        stage2D.removeAllChildren();
    }
    stage2D = null;
    for (var key in movie) { if (movie[key] && movie[key].kill) movie[key].kill(); }
    movie = new Array();

    for (var key in APL) {
        if (APL[key] && APL[key].orignalObject) {
            APL[key].clear();
            APL[key].copy(APL[key].orignalObject, true);
        }
    }
    if (scene3D) {
        scene3D.traverse(function(child) {
            if (child.geometry) child.geometry.dispose();
            if (child.material) {
                if (Array.isArray(child.material)) {
                    child.material.forEach(function(mat) { mat.dispose(); });
                } else {
                    child.material.dispose();
                }
            }
        });
        scene3D.clear();
        scene3D = null;
    }
    if (renderer) { renderer.dispose(); renderer = null; }
    camera = null;
}