import {
  Component,
  ElementRef,
  ViewChild,
  OnInit,
  Input,
  OnDestroy,
  HostListener
  
} from "@angular/core";
import { UUID } from 'angular2-uuid';

import {
  MySprite,
  RichText,
  getMinScale,
  ShapeRect,
  ShapeCircle,
  tweenChange,
  randomSortByArr,
  Label,
  showPopParticle,
  moveItem,
  removeItemFromArr,
  rotateItem,
  hideItem,
  showItem,
  ShapeRectNew,
  scaleItem,
  showBlingBling,
  waterWave,
  jelly,
  getAngleByPos,
  getPosDistance,
  shake
} from "./Unit";

import { localImages, localAudios, multiSizeBackground} from "./resources";

import { Cartoon } from './Cartoon'
import { Subject } from "rxjs";
import { debounceTime, map, takeWhile, retry } from "rxjs/operators";
import * as _ from "lodash";
import TWEEN from "@tweenjs/tween.js";
import defauleFormData from '../../assets/play/default/formData/defaultData.js'

const zIndexMap = {
  mainBackground: 0,
  boy: 10,
  mainDesk: 20,
  Curtain_A: 100,
  Curtain_B: 100,
  Curtain_C: 99,
  Curtain_D: 99,
  Curtain_E: 110,
  startButton: 120,
  drum: 30,
  hand: 35,
  animation: 80,
  EndPatal: 90,
  light: 2
}

@Component({
  selector: "app-play",
  templateUrl: "./play.component.html",
  styleUrls: ["./play.component.scss"]
})



export class PlayComponent implements OnInit, OnDestroy {
  
  g_cartoon = new Cartoon()

  // ------------  全局数据  ------------
  g_stage; //中心舞台
  // g_background_color = "#rgb(0,0,0,0)"
  g_background_color = "#ffe197"
  g_enableMapDown = true; // 触摸使能
  g_enableMapUp = true; // 抬起使能
  g_enableMapMove = true; // 移动ss使能
  g_canvasLeft;
  g_canvasTop;
  g_animationId: any;
  g_mapScale = 1; // 缩放比例
  g_KEY = "DataKey_East_L226";
  g_canvasWidth = 1280;
  g_canvasHeight = 720;
  g_canvasBaseW = 1280;
  g_canvasBaseH = 720;
  g_winResizeEventStream = new Subject();
  g_clickX; // 点击坐标 X
  g_clickY; // 点击坐标 Y
  g_ctx; // canvas 实例
  g_data; // 数据
  g_formData; // 核心表单数据
  g_teacherFlag = false; // 默认角色
  g_currentUser;
  g_firstTouch = true;
  g_partTitle_x = null;
  g_mainTitle_x = null;
  // ------------------------------------

  // ------------  私有数据  ------------
  m_mapDownQueue = {} //按下事件处理队列
  m_mapDownArray = [] //按下事件处理队列
  m_mapDownObject = []

  m_mapUpQueue = {} //抬起事件处理队列
  m_mapUpArray = [] //抬起事件处理队列
  m_mapUpObject = []

  m_mapMoveArray = [] //移动事件处理队列
  m_mapMoveObject = []
  m_endPageArr = []; // 花瓣
  m_showPetalFlag;
  m_elementPetalArr;
  m_showElementPetalFlag;
  m_PetalImage = "_scrap-pic-"  // 飘落动画
  m_renderArr // 渲染队列
  m_renderObject = [];
  m_defaultZindex = 0;
  m_setTimeoutIDs = [];
  m_setIntervalIDs = [];
  m_moveAsstantIntervalId = null;
  m_frontCurtainArr = []; // 前置幕布
  // ------------------------------------
  

  // ------------  游戏逻辑数据  ------------
  m_startGame = false;
  m_allDrums = [];
  m_dataArrayNew = [];
  m_restartGameFlag: boolean = false;
  m_drumFontSize: any = 84;
  // ------------------------------------


  // ------------  消息  ------------
  
  // ------------------------------------


  // ------------  调试变量  ------------
  g_EnableStageRuler = false; // 使能舞台背景格尺
  g_ForceChangeDefaultRole = false // 强制当前角色为默认角色
  g_EnableTestSendEvent = false // 发送模拟Web数据
  g_showLeftCornerTest= false // 测试左上角图标
  // ------------------------------------


  // 当数据加载完毕后，执行
  systemReady(){
    this.setLeftCornerTest()
    this.initGame()
  }
  
  // 屏幕尺寸变化后执行
  handleScreenResize(){
    this.initSystem();
    this.cleanSystemVar()
    this.cleanGameVar();
    this.setLeftCornerTest()
    this.initGame()
  }

  // 映射预加载图片[网路]资源 返回包含图片路径的数组
  mapToImageArray(contentObj){
    let array = []

    this.g_formData.dataArray.forEach(element => {
      if(element.image_url){
        array.push(element.image_url)
      }
    });

    return array
  }

  // 映射预加载音频[网路]资源 返回包含音频路径的数组
  mapToAduioArray(contentObj){
    let array = []

    this.g_formData.dataArray.forEach(element => {
      if(element.audio_url){
        array.push(element.audio_url)
      }
    });

    return array
  }

  // ------------------------------------------------------------------------------
  // 游戏核心处理区
  // ------------------------------------------------------------------------------
  // ------------------------------------------------------------------------------
  // 
  // 
  // 
  // ------------------------------------------------------------------------------
  // ------------------------------------------------------------------------------

  initGame(){
    console.log(this.g_formData);
    this.m_drumFontSize = this.getMaxFontSize()
    this.initBackground();
    this.initBoy();
    this.initCurtain();
    this.initStartButton();
    this.initRestartButton();
    this.initDrum();
    this.initLight();
    console.log(this.m_drumFontSize)
  }

  cleanGameVar(){
    this.m_startGame = false;
  }

  startGame(){
    this.m_startGame = true;
  }

  restartGame(){
    this.cleanGameVar();
    this.stopEndPatal();
    this.startGame();
    this.randomAllDrum();
  }

  endGame(){
    this.showEndPatal(3000)
    this.g_enableMapDown = false;
    this.g_cartoon.getCartoonElement("restart-button").in()
  }

  getMaxFontSize(){
    let lengthAll = []
    this.g_formData.dataArray.forEach(element => {
      if(element.type == "Text"){
        lengthAll.push(element.text.length)
      }
    });
    let maxLength = Math.max(...lengthAll)
    if(maxLength<=5){
      return 84
    }else if(maxLength>5 && maxLength<=10){
      return 42
    }else if(maxLength>10 && maxLength<=15){
      return 28
    }else if(maxLength>15 && maxLength<=20){
      return 21
    }else if(maxLength>20 && maxLength<=25){
      return 16
    }else{
      return 7
    }
  }

  initBackground(){
    let mainBG = this.g_cartoon.createCartoonElementImageFunc("main-background", "background", (w ,h)=>{
      return {
        sx: this.g_canvasWidth / w,
        sy: this.g_canvasHeight / h
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 2,
        y: this.g_canvasHeight / 2,
      }
    })
    this.render(mainBG.ref, zIndexMap.mainBackground)

    let bg_Desk = this.g_cartoon.createCartoonElementImageFunc("main-background-desk", "hengban", (w ,h)=>{
      return {
        sx: this.g_canvasWidth / w,
        sy: 84 * this.g_mapScale / h
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 2,
        y: this.g_canvasHeight / 2 + 315 * this.g_mapScale
      }
    })
    this.render(bg_Desk.ref, zIndexMap.mainDesk)

    let bg_Desk_bg = this.g_cartoon.createCartoonElementImageFunc("main-background-desk", "hengban_bg", (w ,h)=>{
      return {
        sx: this.g_canvasWidth / w,
        sy: (this.g_canvasHeight / 2 - 315 * this.g_mapScale) / h
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 2,
        y: this.g_canvasHeight / 2 + 315 * this.g_mapScale + (this.g_canvasHeight / 2 - 315 * this.g_mapScale) / 2
      }
    })
    this.render(bg_Desk_bg.ref, zIndexMap.mainDesk)

    let bg_Light = this.g_cartoon.createCartoonElementImageFunc("main-background-light", "dengqiu1", (w ,h)=>{
      return {
        sx: 1032 * this.g_mapScale / w,
        sy: 317 * this.g_mapScale / h
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 2,
        y: this.g_canvasHeight / 2 - 200 * this.g_mapScale
      }
    })
    this.render(bg_Light.ref, zIndexMap.mainBackground + 5)
  }

  initBoy(){
    let standPos = [
      [
        {x: this.g_canvasWidth / 2, y: this.g_canvasHeight / 2 + 45 * this.g_mapScale}
      ],
      [
        {x: this.g_canvasWidth / 2 + 317 * this.g_mapScale / 2, y: this.g_canvasHeight / 2 + 45 * this.g_mapScale}
      ],
      [
        {x: this.g_canvasWidth / 2, y: this.g_canvasHeight / 2 + 45 * this.g_mapScale}
      ],
      [
        {x: this.g_canvasWidth / 2 + 317 * this.g_mapScale / 2, y: this.g_canvasHeight / 2 + 45 * this.g_mapScale},
        {x: this.g_canvasWidth / 2 - 317 * this.g_mapScale / 2, y: this.g_canvasHeight / 2 + 45 * this.g_mapScale}
      ],
      [
        {x: this.g_canvasWidth / 2, y: this.g_canvasHeight / 2 + 45 * this.g_mapScale},
        {x: this.g_canvasWidth / 2 - 317 * this.g_mapScale, y: this.g_canvasHeight / 2 + 45 * this.g_mapScale},
        {x: this.g_canvasWidth / 2 + 317 * this.g_mapScale, y: this.g_canvasHeight / 2 + 45 * this.g_mapScale}
      ]
    ]

    let element = this.g_cartoon.createCartoonElementImageFunc("boy", "boy_1", (w ,h)=>{
      return {
        sx: 550 * this.g_mapScale / w,
        sy: 800 * this.g_mapScale / h
      }
    }, (w, h)=>{
      return standPos[this.g_formData.dataArray.length][0]
    })
    this.render(element.ref, zIndexMap.boy)
    element.ref.visible = true

    // 准备动画
    element.play = this.g_cartoon.createAnimation("boy", 30, 1000)
    element.play.x = element.ref.x;
    element.play.y = element.ref.y;
    element.play.scaleX = element.ref.scaleX
    element.play.scaleY = element.ref.scaleY
    element.play.loop = true;
    element.isPlay = false;
    element.play.visible = false;
    this.render(element.play, zIndexMap.boy)

    element.startReadyAni = ()=>{
      element.play.play()
      element.ref.visible = false
      element.play.visible = true
      element.isPlay = true;
      element.firstClick = true;
    }

    element.endReadyAni = ()=>{
      element.play.stop()
      element.ref.visible = true
      element.play.visible = false
      element.isPlay = false;
    }

    // 手
    element.leftHand = this.g_cartoon.createCartoonElementImageFunc("boy-leftHand", "hand2", (w ,h)=>{
      return {
        sx: 180 * this.g_mapScale / w,
        sy: 100 * this.g_mapScale / h
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 2 - 160 * this.g_mapScale,
        y: this.g_canvasHeight / 2 + 75 * this.g_mapScale
      }
    })
    this.render(element.leftHand.ref, zIndexMap.hand)
    element.leftHand.ref.visible = false

    element.rightHand = this.g_cartoon.createCartoonElementImageFunc("boy-rightHand", "hand", (w ,h)=>{
      return {
        sx: 180 * this.g_mapScale / w,
        sy: 100 * this.g_mapScale / h
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 2 + 160 * this.g_mapScale,
        y: this.g_canvasHeight / 2 + 75 * this.g_mapScale
      }
    })
    this.render(element.rightHand.ref, zIndexMap.hand)
    element.rightHand.ref.visible = false

    if(this.g_formData.dataArray.length == 4){
      element.leftHandIndex = 1
      element.rightHandIndex = 2
    }else if(this.g_formData.dataArray.length == 3){
      element.leftHandIndex = 0.5
      element.rightHandIndex = 1.5
    }else if(this.g_formData.dataArray.length == 2){
      element.leftHandIndex = 0
      element.rightHandIndex = 1
    }else if(this.g_formData.dataArray.length == 1){
      element.leftHandIndex = -1
      element.rightHandIndex = 0.5
    }else{
      element.leftHandIndex = -1
      element.rightHandIndex = -1
    }

    element.currentPosition = 0
    element.firstClick = true;
    element.currentSide = ""

    element.updateHandPos = () => {
      element.leftHand.ref.x = element.ref.x - 160 * this.g_mapScale
      element.rightHand.ref.x= element.ref.x + 160 * this.g_mapScale
    }
    // 敲打动画
    element.beat = (index, callback?) =>{
      element.currentSide = ""
      if(this.g_formData.dataArray.length == 4){
        if(element.currentPosition == 0){
          if(index == 0){
            element.ref.x = standPos[this.g_formData.dataArray.length][1].x
            element.currentPosition = 1;
            element.currentSide = "left"
          }else if(index == 1){
            element.currentSide = "left"
          }else if(index == 2){
            element.currentSide = "right"
          }else{
            element.ref.x = standPos[this.g_formData.dataArray.length][2].x
            element.currentPosition = 2;
            element.currentSide = "right"
          }
        }else if(element.currentPosition == 1){
          if(index == 0){
            element.currentSide = "left"
          }else if(index == 1){
            element.currentSide = "right"
          }else if(index == 2){
            element.ref.x = standPos[this.g_formData.dataArray.length][0].x
            element.currentPosition = 0;
            element.currentSide = "right"
          }else{
            element.ref.x = standPos[this.g_formData.dataArray.length][2].x
            element.currentPosition = 2;
            element.currentSide = "right"
          }
        }else{
          if(index == 0){
            element.ref.x = standPos[this.g_formData.dataArray.length][1].x
            element.currentPosition = 1;
            element.currentSide = "left"
          }else if(index == 1){
            element.ref.x = standPos[this.g_formData.dataArray.length][0].x
            element.currentPosition = 0;
            element.currentSide = "left"
          }else if(index == 2){
            element.currentSide = "left"
          }else{
            element.currentSide = "right"
          }
        }
      } else if(this.g_formData.dataArray.length == 3){
        if(element.currentPosition == 0){
          if(index == 0){
            element.ref.x = standPos[this.g_formData.dataArray.length][1].x
            element.currentPosition = 1;
            element.currentSide = "left"
          }else if(index == 1){
            element.currentSide = "left"
          }else {
            element.currentSide = "right"
          }
        }else if(element.currentPosition == 1){
          if(index == 0){
            element.currentSide = "left"
          }else if(index == 1){
            element.currentSide = "right"
          }else {
            element.ref.x = standPos[this.g_formData.dataArray.length][0].x
            element.currentPosition = 0;
            element.currentSide = "right"
          }
        }else{
          if(index == 0){
            element.ref.x = standPos[this.g_formData.dataArray.length][1].x
            element.currentPosition = 1;
            element.currentSide = "left"
          }else if(index == 1){
            element.ref.x = standPos[this.g_formData.dataArray.length][0].x
            element.currentPosition = 0;
            element.currentSide = "left"
          }else {
            element.currentSide = "left"
          }
        }
      } else if(this.g_formData.dataArray.length == 2){
        if(index == 0){
          element.currentSide = "left"
        }else{
          element.currentSide = "right"
        }
      }else if(this.g_formData.dataArray.length == 1){
        element.currentSide = "left"
      }else{
        element.currentSide = "left"
      }
      element.updateHandPos();

      element.currentSide = element.currentSide? element.currentSide: "left"
      if(element.firstClick){
        element.endReadyAni()
        element.leftHand.ref.visible = true
        element.rightHand.ref.visible = true
        element.firstClick = false;
      }
      element.beatAnimate = this.g_cartoon.createAnimation(`beat_${element.currentSide}`, 30, 1000, ()=>{
        callback && callback()
      })
      if(element.currentSide=="left"){
        element.beatAnimate.x = element.leftHand.ref.x
        element.beatAnimate.y = element.leftHand.ref.y
      }else{
        element.beatAnimate.x = element.rightHand.ref.x
        element.beatAnimate.y = element.rightHand.ref.y
      }
      if(element.currentSide == "left"){
        element.leftHand.ref.visible = false
      }else{
        element.rightHand.ref.visible = false
      }
      element.beatAnimate.setScaleXY(this.g_mapScale)
      this.render(element.beatAnimate, zIndexMap.animation)
      element.beatAnimate.play()
    }

    element.backToReady = () => {
      // element.ref.x = standPos[this.g_formData.dataArray.length][0].x
      // element.currentPosition = 0;
      // element.updateHandPos();
    }

    element.beatReset = (callback) => {
      element.beatAnimate.visible = false;
      this.deleteElementInRender(element.beatAnimate.id)
      if(element.currentSide == "left"){
        element.leftHand.ref.visible = true
      }else{
        element.rightHand.ref.visible = true
      }
      callback && callback()
    }

    element.reset = () => {
      element.endReadyAni()
      element.leftHand.ref.visible = false
      element.rightHand.ref.visible = false
    }

  }

  initCurtain(){
    let A = this.g_cartoon.createCartoonElementImageFunc("Curtain-A", "lianzir", (w ,h)=>{
      return {
        sx: 357 * this.g_mapScale / w,
        sy: this.g_canvasHeight / h
      }
    }, (w, h)=>{
      return {
        x: 357 * this.g_mapScale / 2,
        y: this.g_canvasHeight / 2
      }
    })
    A.open = (time=7)=>{
      this.m_setTimeoutIDs.push(setTimeout(() => {
        tweenChange(A.ref, {x: (-357 / 2 + 100) * this.g_mapScale}, time/2)
      }, time * 500))
      
    }
    A.close = ()=>{
      this.m_setTimeoutIDs.push(setTimeout(() => {
        tweenChange(A.ref, {x: A.initX}, 2.5)
      }, 1500))
    }

    let B = this.g_cartoon.createCartoonElementImageFunc("Curtain-B", "lianzil", (w ,h)=>{
      return {
        sx: 357 * this.g_mapScale / w,
        sy: this.g_canvasHeight / h
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth - 357 * this.g_mapScale / 2,
        y: this.g_canvasHeight / 2
      }
    })
    B.open = (time = 7)=>{
      this.m_setTimeoutIDs.push(setTimeout(() => {
        tweenChange(B.ref, {x: this.g_canvasWidth + (357 / 2 - 100) * this.g_mapScale}, time / 2)
      }, time * 500))
    }
    B.close = ()=>{
      this.m_setTimeoutIDs.push(setTimeout(() => {
        tweenChange(B.ref, {x: B.initX}, 2.5)
      }, 1500))
    }

    let C = this.g_cartoon.createCartoonElementImageFunc("Curtain-C", "lianzi4", (w ,h)=>{
      return {
        sx: this.g_canvasWidth / 2 / w,
        sy: this.g_canvasHeight / h
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 4,
        y: this.g_canvasHeight / 2
      }
    })
    C.open = (time = 7)=>{
      tweenChange(C.ref, {x: -this.g_canvasWidth / 4}, time)
    }
    C.close = (time = 4)=>{
      tweenChange(C.ref, {x: C.initX}, time)
    }
    
    let D = this.g_cartoon.createCartoonElementImageFunc("Curtain-D", "lianzi3", (w ,h)=>{
      return {
        sx: this.g_canvasWidth / 2 / w,
        sy: this.g_canvasHeight / h
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth - this.g_canvasWidth / 4 - 10 * this.g_mapScale,
        y: this.g_canvasHeight / 2
      }
    })
    D.open = (time = 7)=>{
      tweenChange(D.ref, {x: this.g_canvasWidth + this.g_canvasWidth / 4}, time)
    }
    D.close = (time = 4)=>{
      tweenChange(D.ref, {x: D.initX}, time)
    }

    let E = this.g_cartoon.createCartoonElementImageFunc("Curtain-E", "lianzi0", (w ,h)=>{
      return {
        sx: this.g_canvasWidth / w,
        sy: 95 * this.g_mapScale / h
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 2,
        y: (95 / 2) * this.g_mapScale
      }
    })

    this.m_frontCurtainArr.push(C.ref)
    this.m_frontCurtainArr.push(D.ref)
    this.m_frontCurtainArr.push(A.ref)
    this.m_frontCurtainArr.push(B.ref)
    this.m_frontCurtainArr.push(E.ref)
  }

  curtainContral(status, callback?){
    let all = ["Curtain-A", "Curtain-B", "Curtain-C", "Curtain-D"]
    let _this = this
    this.g_cartoon.playAudio("tongshenghuanhu")
    this.m_setTimeoutIDs.push(setTimeout(() => {
      this.g_cartoon.playAudio("gusheng_kaitou")
    }, 2000))
    if(status){
      let openTime = this.m_restartGameFlag?3:7
      all.forEach(item=>{
        _this.g_cartoon.getCartoonElement(item).open(openTime)
      })
      this.m_setTimeoutIDs.push(setTimeout(()=>{
        this.m_allDrums.forEach(function(item,index){
          _this.g_cartoon.getCartoonElement(item).show(index)
        })
      }, openTime * 500))
      this.m_setTimeoutIDs.push(setTimeout(()=>{
        callback && callback()
      }, openTime * 1000))
    }else{
      all.forEach(item=>{
        _this.g_cartoon.getCartoonElement(item).close()
      })
      this.m_setTimeoutIDs.push(setTimeout(()=>{
        callback && callback()
      }, 4000))
    }
  }

  initStartButton(){
    let element = this.g_cartoon.createCartoonElementImageFunc("start-button", "btn_start", (w ,h)=>{
      return {
        sx: 331 * this.g_mapScale / w,
        sy: 112 * this.g_mapScale / h
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 2 + 450 * this.g_mapScale,
        y: this.g_canvasHeight / 2 + 250 * this.g_mapScale
      }
    })
    
    this.m_frontCurtainArr.push(element.ref)
    this.subscribeMapDownEvent(element.id, ()=>{
      this.g_cartoon.playAudio("dianji")
      this.showJellyAnimation(element.id, ()=>{
        tweenChange(element.ref, {x: this.g_canvasWidth +  331 * this.g_mapScale}, 0.5)
      })
      this.g_cartoon.getCartoonElement("boy").startReadyAni()
      this.startGame()
      this.curtainContral(true, ()=>{
        this.g_enableMapDown = true;
      })
      return true;
    }, 100)
  }

  initRestartButton(){
    let element = this.g_cartoon.createCartoonElementImageFunc("restart-button", "restart", (w ,h)=>{
      return {
        sx: 331 * this.g_mapScale / w,
        sy: 112 * this.g_mapScale / h
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 2 + 450 * this.g_mapScale,
        y: this.g_canvasHeight / 2
      }
    })
    element.ref.x = this.g_canvasWidth +  331 * this.g_mapScale
    this.m_frontCurtainArr.push(element.ref)

    element.in = (callback?)=>{
      tweenChange(element.ref, {x: element.initX}, 0.5, ()=>{
        callback && callback()
      })
    }

    element.out = (callback?)=>{
      tweenChange(element.ref, {x: this.g_canvasWidth +  331 * this.g_mapScale}, 0.5, ()=>{
        callback && callback()
      })
    }

    this.subscribeMapDownEvent(element.id, ()=>{
      this.showJellyAnimation(element.id, ()=>{
        element.out()
      })
      this.g_cartoon.playAudio("jiazigu_changgusheng")
      this.m_setTimeoutIDs.push(setTimeout(() => {
        this.g_cartoon.playAudio("guzhang")
      }, 1000))
      this.m_restartGameFlag = true;
      this.curtainContral(false, ()=>{
        this.g_cartoon.getCartoonElement("boy").reset()
        this.g_cartoon.getCartoonElement("boy").startReadyAni()
        this.restartGame()
        this.curtainContral(true, ()=>{
          this.g_enableMapDown = true;
        })
      })

      return true
    }, 100)
  }

  initDrum(){
    if(this.g_formData.dataArray.length == 0){
      return
    }
    let totalDrumNum = this.g_formData.dataArray.length - 1// s20 * this.g_mapScale
    let baseX = [
      this.g_canvasWidth / 2,
      this.g_canvasWidth / 2 - (317 / 2) * this.g_mapScale,
      this.g_canvasWidth / 2 - (317) * this.g_mapScale,
      this.g_canvasWidth / 2 - (317 / 2) * 3 * this.g_mapScale
    ]

    this.m_dataArrayNew = this.randomArray_shuffle(this.g_formData.dataArray)
    this.m_dataArrayNew.forEach((item, index) => {
      let element = this.createDrum(index, item, baseX[totalDrumNum])
      this.m_allDrums.push(element.id)
      this.render(element.ref, zIndexMap.drum)
    });

  }

  createDrum(index, data, baseX){
    let color = ["red", "blue", "yellow", "green"]
    let element = this.g_cartoon.createCartoonElementImageFunc(`drum-${index}`, color[index], (w ,h)=>{
      return {
        sx: 317 * this.g_mapScale / w,
        sy: 312 * this.g_mapScale / h
      }
    }, (w, h)=>{
      return {
        x: baseX + index * 317 * this.g_mapScale,
        y: this.g_canvasHeight / 2 + 200 * this.g_mapScale
      }
    })
    
    element.light = this.g_cartoon.createCartoonElementImageFunc(`drum-${index}-light`, "drum_highlight", (w ,h)=>{
      return {
        sx: 464 * 0.9 / w,
        sy: 454 * 0.9 / h
      }
    }, (w, h)=>{
      return {
        x: 0,
        y: 0
      }
    })

    element.ref.addChild(element.light.ref)
    element.light.ref.visible = false;
    if(index<=1){
      element.handSide = "left"
    }else{
      element.handSide = "right"
    }

    element.content = null;
    element.imageContainer = null;
    element.textContainer = null;
    element.resetContent = (contentData)=>{
      element.isOpen = false;
      if(contentData.type == "Image"){
        if(element.content){
          element.ref.removeChild(element.content)
        }
        element.imageContainer = this.g_cartoon.createImage("card_bg", (w, h)=>{
          return {
            sx: 261 / w,
            sy: 178 / h
          }
        }, (w, h)=>{
          return {
            x: 0,
            y: 60
          }
        })
        element.imageContainer.visible = false;
        element.imageContainer.setScaleXY(0)
        element.content = element.imageContainer

        element.image = this.g_cartoon.createImage(contentData.image_url, (w, h)=>{
          let sx = 261 * 0.85 / w
          let sy = 178 * 0.85 / h
          let s = Math.min(sx, sy)
          return {
            sx: s,
            sy: s
          }
        }, (w, h)=>{
          return {
            x: 0,
            y: 0
          }
        })

        element.ref.addChild(element.imageContainer)
        element.imageContainer.addChild(element.image)
      }else{
        if(element.content){
          element.ref.removeChild(element.content)
        }
        element.textContainer = this.g_cartoon.createImage("card_bg", (w, h)=>{
          return {
            sx: 261 / w,
            sy: 178 / h
          }
        }, (w, h)=>{
          return {
            x: 0,
            y: 60
          }
        })
        element.textContainer.alpha = 0; 
        element.textContainer.visible = false;
        element.textContainer.setScaleXY(0)
        element.content = element.textContainer
        element.text = this.g_cartoon.createLabel(contentData.text, "BerlinSansFBDemi-Bold", "#b94918", this.m_drumFontSize)
        element.text.outline = 15;

        element.ref.addChild(element.textContainer)
        element.textContainer.addChild(element.text)
      }
    }
    element.resetContent(data, true)
    

    element.highlight = () => {
      this.m_setTimeoutIDs.push(setTimeout(() => {
        this.g_cartoon.getCartoonElement("boy").beatReset()
        tweenChange(element.ref, {scaleX: element.initScaleX, scaleY: element.initScaleY}, 0.2, ()=>{
          element.light.ref.visible = false;
          this.setRenderZIndex(element.ref, zIndexMap.drum)
          this.checkAllOpen()
          this.g_cartoon.getCartoonElement("boy").backToReady()
          this.g_enableMapDown = true;
        })
      }, 500))
    }

    element.isOpen = false;
    this.subscribeMapDownEvent(element.id, ()=>{
      if(!this.m_startGame || element.isOpen){
        if(element.isOpen){
          this.g_cartoon.stopAllAudio();
          this.g_cartoon.playAudio(`gusheng_${index+1}`, false, ()=>{
            if(data.audio_url){
              this.g_cartoon.playAudio(data.audio_url)
            }
          })
          this.g_cartoon.getCartoonElement("boy").beat(index, ()=>{
            this.g_cartoon.getCartoonElement("boy").beatReset()
            this.g_enableMapDown = true;
          })
        }else{
          this.g_enableMapDown = true;
        }
        return
      }
      this.g_cartoon.stopAllAudio();
      this.g_cartoon.playAudio(`gusheng_${index+1}`, false, ()=>{
        if(data.audio_url){
          this.g_cartoon.playAudio(data.audio_url)
        }
      })
      this.setRenderZIndex(element.ref, zIndexMap.drum + 1)
      tweenChange(element.ref, {scaleX: element.initScaleX * 1.1, scaleY: element.initScaleY * 1.1}, 0.2, ()=>{
        if(element.content){
          element.content.visible = true;
          tweenChange(element.content, {scaleX: element.content.initScaleX, scaleY: element.content.initScaleY}, 0.2)
        }
        element.light.ref.visible = true;
        element.isOpen = true;
        this.g_cartoon.getCartoonElement("boy").beat(index, ()=>{
          element.highlight()
        })
      })
    })

    element.show = (index)=>{
      this.m_setTimeoutIDs.push(setTimeout(() => {
        this.setRenderZIndex(element.ref, zIndexMap.drum + 1)
        tweenChange(element.ref, {scaleX: element.initScaleX * 1.05, scaleY: element.initScaleY * 1.05}, 0.1, ()=>{
          this.m_setTimeoutIDs.push(setTimeout(() => {
            tweenChange(element.ref, {scaleX: element.initScaleX, scaleY: element.initScaleY}, 0.1, ()=>{
              this.setRenderZIndex(element.ref, zIndexMap.drum)
            })
          }, 200))
        })
      }, 500 * index))
    }

    return element
  }

  randomAllDrum(){
    let drum = null;
    this.m_dataArrayNew = this.randomArray_shuffle(this.g_formData.dataArray)
    let _this = this
    this.m_allDrums.forEach(function(item, index){
      drum = _this.g_cartoon.getCartoonElement(item)
      drum.resetContent(_this.m_dataArrayNew[index])
    })
  }

  checkAllOpen(){
    let endGame = true
    for(let index = 0; index<this.m_allDrums.length; index++){
      if(!this.g_cartoon.getCartoonElement(this.m_allDrums[index]).isOpen){
        endGame = false;
      }
    }
    if(endGame){
      this.endGame()
    }
  }

  initLight(){
    let light1 = this.g_cartoon.createAnimation("light1", 90, 5000)
    light1.x = 225 * this.g_mapScale;
    light1.y = (200 + 225) * this.g_mapScale;
    light1.setScaleXY(this.g_mapScale)
    light1.loop = true;
    this.render(light1, zIndexMap.light)
    light1.play()

    let light2 = this.g_cartoon.createAnimation("light2", 60, 4000)
    light2.x = (100 + 400) * this.g_mapScale;
    light2.y = 400 * this.g_mapScale;
    light2.setScaleXY(this.g_mapScale)
    light2.loop = true;
    this.render(light2, zIndexMap.light)
    light2.play()

    let light3 = this.g_cartoon.createAnimation("light3", 60, 6000)
    light3.x = (300 + 525) * this.g_mapScale;
    light3.y = 525 * this.g_mapScale;
    light3.setScaleXY(this.g_mapScale)
    light3.loop = true;
    this.render(light3, zIndexMap.light)
    light3.play()

    let light4 = this.g_cartoon.createAnimation("light4", 60, 5000)
    light4.x = (360) * this.g_mapScale;
    light4.y = 360 * this.g_mapScale;
    light4.setScaleXY(this.g_mapScale)
    light4.loop = true;
    this.render(light4, zIndexMap.light)
    light4.play()
  }























































  // --------------------------------------------------
  // --------------  Template function  ---------------
  // --------------------------------------------------
  // --------------------------------------------------
  // --------------------------------------------------
  // 
  //                                  _________
  //                                 /         /.
  //           .-------------.      /_________/ |
  //         /             / |      |         | |
  //        /+============+\ |      | |====|  | |
  //        ||C:\>        || |      |         | |
  //        ||            || |      | |====|  | |
  //        ||            || |      |   ___   | |
  //        ||            || |      |  |166|  | |
  //        ||            ||/@@@    |   ---   | |
  //        \+============+/    @   |_________|./.
  //                          @          ..  ....'
  //        ..................@     __.'.'  ''
  //      /oooooooooooooooo//     ///
  //      /................//     /_/
  //      ------------------
  //
  // --------------------------------------------------

  @ViewChild("canvas") canvas: ElementRef;
  @ViewChild("wrap") wrap: ElementRef;
  @HostListener("window:resize", ["$event"])
  onResize(event) {
    this.g_winResizeEventStream.next();
  }
  ngOnDestroy() {
    window["curCtx"] = null;
    window.cancelAnimationFrame(this.g_animationId);
  }
  ngOnInit() {
    const getData = (<any>window).courseware.getData;
    getData(data => {
      if (window['air'].airClassInfo.user.classRole == 'tea') {
        if(!this.g_ForceChangeDefaultRole){
          this.g_teacherFlag = true;
        }
      }
      this.g_currentUser = window['air'].airClassInfo.user;
      if (data && typeof data == "object") {
        this.g_data = data;
        this.g_formData = data.contentObj;
      } else {
        this.g_data = {};
      }

      
      if (!this.g_data.contentObj) {
        this.g_data.contentObj = {};
        this.g_formData = {};
      }

      this.initDefaultData();
      this.initAudio();
      this.initImg();

       // 预加载资源
       this.g_cartoon.loadResources().then(() => {
        window["air"].hideAirClassLoading(this.g_KEY, this.g_data);
        this.initSystem();
        this.update();
        this.systemReady()
      });

      this.initListener();
    }, this.g_KEY);
  }

  // ----------------------------------
  // 初始化默认数据
  // ----------------------------------
  initDefaultData() {
    if ( Object.keys(this.g_formData).length===0 || this.g_formData.version != defauleFormData.version ) {
      this.g_formData = defauleFormData;
    }
  }


  // ----------------------------------
  // 初始化音乐
  // ----------------------------------
  initAudio() {
    const contentObj = this.g_formData;
    if (!contentObj) {
      return;
    }
    // 添加用户上传音效
    let images:Array<string> = this.mapToAduioArray(contentObj)
    images.forEach(image => {
      this.g_cartoon.addAudio( image, image );
    });

    // 添加本地音效
    for( var key in localAudios ){
      this.g_cartoon.addAudio( key, localAudios[key] );
    }
  }

  // ----------------------------------
  // 初始化图片
  // ----------------------------------
  initImg() {
    const contentObj = this.g_formData;
    if (contentObj) {
      const addPicUrl = url => {
        if (url) {
          this.g_cartoon.addImage(url, url);
        }
      };
      let images:Array<string> = this.mapToImageArray(contentObj)
      images.forEach(image => {
        addPicUrl(image)
      });
    }
    // 添加本地图片
    for( var key in localImages ){
     this.g_cartoon.addImage( key, localImages[key] );
    }
  }


  mapDown(event) {
    let myStopPropagation = false;
    if (!this.g_enableMapDown) {
      return;
    }
    // console.log("All click event subscribers:", this.m_mapDownArray)
    this.m_mapDownArray.forEach((item)=>{
      if(!myStopPropagation){
        if (this.checkClickTarget(this.g_cartoon.getCartoonElementRef(item.id))) {
          this.g_enableMapDown = false;
          // console.log("Click event - target id:["+item.id+"]")
          if(item.callback()){
            myStopPropagation = true;
          }
        }
      }
    })


  }

  mapMove(event) {
    let myStopPropagation = false;
    if (!this.g_enableMapMove) {
      return;
    }

    this.m_mapMoveArray.forEach((item)=>{
      if(!myStopPropagation){
        if (this.checkClickTarget(this.g_cartoon.getCartoonElementRef(item.id))) {
          this.g_enableMapMove = false;
          if(item.callback()){
            myStopPropagation = true;
          }
        }
      }
    })
  }

  mapUp(event) {
    let myStopPropagation = false;
    if (!this.g_enableMapUp) {
      return;
    }
    // for(let cartoonID in this.m_mapUpQueue){
    //   if (this.checkClickTarget(this.g_cartoon.getCartoonElementRef(cartoonID))) {
    //     this.g_enableMapUp = false;
    //     this.m_mapUpQueue[cartoonID]();
    //   }
    // }
    this.m_mapUpArray.forEach((item)=>{
      if(!myStopPropagation){
        if (this.checkClickTarget(this.g_cartoon.getCartoonElementRef(item.id))) {
          this.g_enableMapUp = false;
          if(item.callback()){
            myStopPropagation = true;
          }
        }
      }
    })

  }


  update() {
    this.g_animationId = window.requestAnimationFrame(this.update.bind(this));
    // 清除画布内容
    this.g_ctx.clearRect(0, 0, this.g_canvasWidth, this.g_canvasHeight);
    TWEEN.update();
    this.updateArr(this.m_renderArr);
    this.updateArr(this.m_endPageArr);
    this.updateArr(this.m_elementPetalArr);
    this.updateArr(this.m_frontCurtainArr)
  }


  updateItem(item) {
    if (item) {
      item.update();
    }
  }


  updateArr(arr) {
    if (!arr) {
      return;
    }
    for (let i = 0; i < arr.length; i++) {
      arr[i].update(this);
    }
  }


  initListener() {
    const element = this.canvas.nativeElement;
    this.g_winResizeEventStream.pipe(debounceTime(500)).subscribe(data => {
      this.renderAfterResize();
    });
    
    const addTouchListener = () => {
      element.addEventListener('touchstart', touchDownFunc);
      element.addEventListener('touchmove', touchMoveFunc);
      element.addEventListener('touchend', touchUpFunc);
      element.addEventListener('touchcancel', touchUpFunc);
    };
    const removeTouchListener = () => {
      element.removeEventListener('touchstart', touchDownFunc);
      element.removeEventListener('touchmove', touchMoveFunc);
      element.removeEventListener('touchend', touchUpFunc);
      element.removeEventListener('touchcancel', touchUpFunc);
    };

    const addMouseListener = () => {
      element.addEventListener('mousedown', mouseDownFunc);
      element.addEventListener('mousemove', mouseMoveFunc);
      element.addEventListener('mouseup', mouseUpFunc);
    };
    const removeMouseListener = () => {
      element.removeEventListener('mousedown', mouseDownFunc);
      element.removeEventListener('mousemove', mouseMoveFunc);
      element.removeEventListener('mouseup', mouseUpFunc);
    };

    const touchDownFunc = (e) => {
      if (this.g_firstTouch) {
        this.g_firstTouch = false;
        removeMouseListener();
      }
      setMxMyByTouch(e);
      this.mapDown(e);
    };
    const touchMoveFunc = (e) => {
      setMxMyByTouch(e);
      this.mapMove(e);
    };
    const touchUpFunc = (e) => {
      setMxMyByTouch(e);
      this.mapUp(e);
    };

    const mouseDownFunc = (e) => {
      if (this.g_firstTouch) {
        this.g_firstTouch = false;
        removeTouchListener();
      }
      setMxMyByMouse(e);
      this.mapDown(e);
    };
    const mouseMoveFunc = (e) => {
      setMxMyByMouse(e);
      this.mapMove(e);
    };
    const mouseUpFunc = (e) => {
      setMxMyByMouse(e);
      this.mapUp(e);
    };

    const setMxMyByTouch = event => {
      if (event.touches.length <= 0) {
        return;
      }
      if (this.g_canvasLeft == null) {
        setParentOffset();
      }
      this.g_clickX = event.touches[0].pageX - this.g_canvasLeft;
      this.g_clickY = event.touches[0].pageY - this.g_canvasTop;
    };

    const setParentOffset = () => {
      const rect = this.canvas.nativeElement.getBoundingClientRect();
      this.g_canvasLeft = rect.left;
      this.g_canvasTop = rect.top;
    };

    const setMxMyByMouse = (event) => {
      this.g_clickX = event.offsetX;
      this.g_clickY = event.offsetY;
    };

    addMouseListener();
    addTouchListener();
  }

  showArr(arr) {
    if (!arr) {
      return;
    }
    for (let i = 0; i < arr.length; i++) {
      arr[i].visible = true;
    }
  }

  hideArr(arr) {
    if (!arr) {
      return;
    }
    for (let i = 0; i < arr.length; i++) {
      arr[i].visible = false;
    }
  }

  IsPC() {
    if (window["ELECTRON"]) {
      return false; // 封装客户端标记
    }
    if (
      document.body.ontouchmove !== undefined &&
      document.body.ontouchmove !== undefined
    ) {
      return false;
    } else {
      return true;
    }
  }

  renderAfterResize() {
    this.g_canvasWidth = this.wrap.nativeElement.clientWidth;
    this.g_canvasHeight = this.wrap.nativeElement.clientHeight;
    this.update();
    this.handleScreenResize()
  }

  checkClickTarget(target) {
    if (!target) {
      return false;
    }
    const rect = target.getBoundingBox();
    if (this.checkPointInRect(this.g_clickX, this.g_clickY, rect)) {
      return true;
    }
    return false;
  }

  getWorlRect(target) {
    let rect = target.getBoundingBox();
    if (target.parent) {
      const pRect = this.getWorlRect(target.parent);
      rect.x += pRect.x;
      rect.y += pRect.y;
    }
    return rect;
  }

  checkPointInRect(x, y, rect) {
    if (x >= rect.x && x <= rect.x + rect.width) {
      if (y >= rect.y && y <= rect.y + rect.height) {
        return true;
      }
    }
    return false;
  }


  getPosByAngle(angle, len) {
    const radian = (angle * Math.PI) / 180;
    const x = Math.sin(radian) * len;
    const y = Math.cos(radian) * len;
    return { x, y };
  }


  getPosDistance(sx, sy, ex, ey) {
    const _x = ex - sx;
    const _y = ey - sy;
    const len = Math.sqrt(Math.pow(_x, 2) + Math.pow(_y, 2));
    return len;
  }


  subscribeMapDownEvent(id,callback, zIndex?){
    zIndex = zIndex?zIndex:0
    this.m_mapDownObject.push({id:id, zIndex:zIndex?zIndex:1, callback:callback})
    this.m_mapDownObject.sort((a,b)=>{
      return b.zIndex-a.zIndex
    })
    this.m_mapDownArray = []
    this.m_mapDownObject.forEach(item=>{
      this.m_mapDownArray.push(item)
    })
  }

  subscribeMapUpEvent(id,callback, zIndex?){
    zIndex = zIndex?zIndex:0
    this.m_mapUpObject.push({id:id, zIndex:zIndex?zIndex:1, callback:callback})
    this.m_mapUpObject.sort((a,b)=>{
      return b.zIndex-a.zIndex
    })
    this.m_mapUpArray = []
    this.m_mapUpObject.forEach(item=>{
      this.m_mapUpArray.push(item)
    })
  }

  subscribeMapMoveEvent(id, callback, zIndex?){
    zIndex = zIndex?zIndex:0
    this.m_mapMoveObject.push({id:id, zIndex:zIndex?zIndex:1, callback:callback})
    this.m_mapMoveObject.sort((a,b)=>{
      return a.zIndex - b.zIndex
    })
    this.m_mapMoveArray = []
    this.m_mapMoveObject.forEach(item=>{
      this.m_mapMoveArray.push(item)
    })
  }


  // 全局初始化入口，当资源加载完毕后执行
  initSystem() {
    
    this.g_canvasWidth = this.wrap.nativeElement.clientWidth;
    this.g_canvasHeight = this.wrap.nativeElement.clientHeight;

    const sx = this.g_canvasWidth / this.g_canvasBaseW;
    const sy = this.g_canvasHeight / this.g_canvasBaseH;
    const s = Math.min(sx, sy);

    this.g_mapScale = s;
    this.g_cartoon.mapScale = this.g_mapScale;
    this.g_cartoon.clientWidth = this.wrap.nativeElement.clientWidth;
    this.g_cartoon.clientHeight = this.wrap.nativeElement.clientHeight;

    this.m_renderArr = [];
    this.m_renderObject = [];
    this.m_frontCurtainArr = [];
    this.g_enableMapDown = true;

    this.g_ctx = this.canvas.nativeElement.getContext("2d");
    this.canvas.nativeElement.width = this.g_canvasWidth;
    this.canvas.nativeElement.height = this.g_canvasHeight;
    window["curCtx"] = this.g_ctx;

    // 初始化舞台
    this.initStage();
    this.update();
  }
  

  initStage() {
    const bgWidth = 1280;
    const bgHeight = 720;
    this.g_cartoon.stageWidth = bgWidth*this.g_mapScale;
    this.g_cartoon.stageHeight= bgHeight*this.g_mapScale;

    const imageColor = this.g_cartoon.createCartoonElement("background-color", "ShapeRect").ref;
    // console.log( "stageWidth: " + this.g_cartoon.stageWidth + " stageHeight" + this.g_cartoon.stageHeight)
    // console.log( "clientWidth: " + this.g_cartoon.clientWidth + " clientHeight" + this.g_cartoon.clientHeight)
    // console.log( "canvasWidth: " + this.g_canvasWidth + " canvasHeight" + this.g_canvasHeight)
    // console.log( "mapScale: " + this.g_mapScale )
    imageColor.x = this.g_cartoon.clientWidth / 2 ;
    imageColor.y = this.g_cartoon.clientHeight / 2 ;
    imageColor.setSize(this.g_cartoon.clientWidth, this.g_cartoon.clientHeight);
    imageColor.init();
    imageColor.fillColor = this.g_background_color;
    this.render(imageColor, -999999)

    const image = this.g_cartoon.createCartoonElement("bg_1280_720_Ruler", "MySprite").ref;
    image.init(this.g_cartoon.images.get("_bg_1280_720_Ruler"));
    image.x = this.g_canvasWidth / 2;
    image.y = this.g_canvasHeight /2;
    image.visible = this.g_EnableStageRuler
    this.g_cartoon.setOrigin( image.x-(bgWidth/2*this.g_mapScale), image.y-(bgHeight/2*this.g_mapScale)  )
    this.g_cartoon.setRelativeOrigin( -bgWidth/2, -bgHeight/2)
    image.setScaleXY(this.g_mapScale);
    this.render(image, -999)
    this.g_stage = image
  }

  render(ele, zIndex?:number){
    this.m_renderObject.push({element:ele, zIndex:zIndex?zIndex:1})
    this.m_renderObject.sort((a,b)=>{
      return a.zIndex - b.zIndex
    })
    this.m_renderArr = []
    this.m_renderObject.forEach(item=>{
      this.m_renderArr.push(item.element)
    })    
  }

  sendServerEvent(key, data) {
    const c = (<any> window).courseware;
    c.sendEvent(key, JSON.stringify(data));
  }

  addServerListener(msg_key, callback) {
    const c = (<any> window).courseware;
    c.onEvent(msg_key, (data,next) => {
      callback(JSON.parse(data))
      next && next();
    });
  }

  randomArray_shuffle(array) {
    var input = array;
    for (var i = input.length-1; i >=0; i--) {
        var randomIndex = Math.floor(Math.random()*(i+1));
        var itemAtIndex = input[randomIndex];
        input[randomIndex] = input[i];
        input[i] = itemAtIndex;
    }
    return input;
  }

  paginationArray(pageNo, pageSize, array) {
    var offset = (pageNo - 1) * pageSize;
    return (offset + pageSize >= array.length) ? array.slice(offset, array.length) : array.slice(offset, offset + pageSize);
  }

  stopAllTimeout(){
    this.m_setTimeoutIDs.forEach(id=>clearTimeout(id))
    this.m_setTimeoutIDs = []
  }

  stopAllInterval(){
    this.m_setIntervalIDs.forEach(id=>clearInterval(id))
    this.m_setIntervalIDs = []
  }

  topOfRenderArray(element){
    let index = this.m_renderArr.indexOf(element)
    if(index !=-1){
      this.m_renderArr.splice(index, 1)
      this.m_renderArr.push(element)
    }
  }

  setRenderZIndex(element, zIndex){
    let index = null;
    for(let i=0; i<this.m_renderObject.length; i++){
      if( this.m_renderObject[i].element.id == element.id ){
        index = i
      }
    }
    if(index){
      this.m_renderObject.splice(index, 1)
      this.m_renderObject.push({element:element, zIndex:zIndex?zIndex:1})
      this.m_renderObject.sort((a,b)=>{
        return a.zIndex - b.zIndex
      })
  
      this.m_renderArr = []
      this.m_renderObject.forEach(item=>{
        this.m_renderArr.push(item.element)
      })
    }
  }
  
  deleteElementInRender(id){
    let index = null;
    for(let i=0; i<this.m_renderObject.length; i++){
      if( this.m_renderObject[i].element.id == id ){
        index = i
      }
    }
    if(index){
      this.m_renderObject.splice(index, 1)
      this.m_renderObject.sort((a,b)=>{
        return a.zIndex - b.zIndex
      })
      this.m_renderArr = []
      this.m_renderObject.forEach(item=>{
        this.m_renderArr.push(item.element)
      })
    }else{
      console.warn("Can not found element id:" + id)
    }
  }

  enableMoveAsstant(callback){
    if(this.m_moveAsstantIntervalId){
      clearInterval(this.m_moveAsstantIntervalId)
    }
    this.m_moveAsstantIntervalId = setInterval(()=>{
      callback()
    },50)
  }

  disableMoveAsstant(){
    clearInterval(this.m_moveAsstantIntervalId)
  }

  cleanSystemVar(){
    this.m_mapDownQueue = {}
    this.m_mapDownArray = []
    this.m_mapDownObject = []
    this.m_mapMoveArray = []
    this.m_mapMoveObject = []
    this.m_mapUpQueue = {}
    this.m_mapUpArray = []
    this.m_mapUpObject = []
    this.stopAllInterval();
    this.stopAllTimeout()
    this.g_cartoon.stopAllAudio()
  }

  getMaxSubstringLength(str){
    let maxLength = 0;
    let subSubstring = str.split(" ")
    for (let index=0; index<subSubstring.length; index++) {
      if(subSubstring[index].length > maxLength){
        maxLength = subSubstring[index].length;
      }
    }
    return maxLength
  }

  setLeftCornerTest(){
    const bgRect = new ShapeRect();
    bgRect.setSize(57, 65);
    bgRect.fillColor = '#f8c224';
    const sx = this.g_canvasWidth / this.g_canvasBaseW;
    bgRect.setScaleXY(sx);
    bgRect.x = 65 * sx;
    this.g_partTitle_x = bgRect.x
    this.g_mainTitle_x = bgRect.x + 80 * sx
    bgRect.alpha = 0.5
    bgRect.visible = this.g_showLeftCornerTest
    this.render(bgRect, 9999);
  }

  alignCenter(elementArray, spacing, withAni?, callback?){
    let totlaWidth = 0
    let length = elementArray.length
    elementArray.forEach(element => {
      let bd = element.ref.getBoundingBox()
      totlaWidth += bd.width
    });
    totlaWidth += (elementArray.length-1) * spacing
    let laseX = this.g_canvasWidth / 2 - totlaWidth/2;
    elementArray.forEach((element, index) => {
      let bd = element.ref.getBoundingBox()
      if(withAni){
        tweenChange(element.ref, {x: laseX + bd.width / 2}, 0.2, ()=>{
          this.g_cartoon.saveSize(element.id)
          if(length == (index+1)){
            callback && callback()
          }
        })
      }else{
        element.ref.x = laseX + bd.width / 2
        this.g_cartoon.saveSize(element.id)
        if(length == (index+1)){
          callback && callback()
        }
      }

      laseX = (laseX + bd.width + spacing)
    });
  }

  alignLeft(elementArray, spacing, startX = 0, withAni?, callback?){
    let laseX = startX;
    elementArray.forEach((element, index) => {
      let bd = element.ref.getBoundingBox()
      if(withAni){
        tweenChange(element.ref, {x: laseX + bd.width / 2}, 0.2, ()=>{
          this.g_cartoon.saveSize(element.id)
          if(length == (index+1)){
            callback && callback()
          }
        })
      }else{
        element.ref.x = laseX + bd.width / 2
        this.g_cartoon.saveSize(element.id)
        if(length == (index+1)){
          callback && callback()
        }
      }

      laseX = (laseX + bd.width + spacing)
    });
  }

  createTestLine(x, y, height, color?){
    var colorAll = ['#ff0000','#eb4310','#f6941d','#fbb417','#ffff00','#cdd541','#99cc33','#3f9337','#219167','#239676','#24998d','#1f9baa','#0080ff','#3366cc','#333399','#003366','#800080','#a1488e','#c71585','#bd2158'];
    color = color ? color : colorAll[Math.floor(Math.random()*20)]
    this.render(this.g_cartoon.createRectangula({
      width: 5,
      height: height,
      x: x,
      y: y,
      fillColor: color
    }), 9999)
  }

  getSuitSizeBackground(key, width){
    let bgAll = multiSizeBackground[key]
    if(!bgAll){
      return ""
    }
    let suitFileName = ""
    for(let fileName in bgAll){
      if(  Number(fileName) >= width){
        suitFileName = bgAll[fileName]
        break
      }
    }
    return suitFileName
  }












  













  












  // --------------------------------------------------
  // --------------  Template function  ---------------
  // --------------------------------------------------
  // --------------------------------------------------
  // --------------------------------------------------
  // 
  //                .-~~~~~~~~~-._       _.-~~~~~~~~~-.
  //            __.'              ~.   .~              `.__
  //          .'//                  \./                  \\`.
  //        .'//                     |                     \\`.
  //      .'// .-~"""""""~~~~-._     |     _,-~~~~"""""""~-. \\`.
  //    .'//.-"                 `-.  |  .-'                 "-.\\`.
  //  .'//______.============-..   \ | /   ..-============.______\\`.
  //.'______________________________\|/______________________________`.
  //
  // --------------------------------------------------
  // showParticle( element_id )                 泡泡效果
  // --------------------------------------------------
  // showEndPatal()  /  stopEndPatal()  花瓣飘落结束动画 
  // --------------------------------------------------
  // showCorrectPatal()                 指定元素上面飘花
  // --------------------------------------------------
  // convertPercentToRadian()   将百分比转换为弧长 第一个参数是百分比，第二个参数是方向 true为逆时针，false为顺时针。用于ShapeCircle换圆弧
  // --------------------------------------------------
  // movePaoWuxian()                        元素抛物线跳
  // --------------------------------------------------
  // showJellyAnimation()------------------------------
  // showBlingStar()----------------------显示星星效果--
  // --------------------------------------------------
  


  // 泡泡
  showParticle(card) {
    let myCard = this.g_cartoon.getCartoonElementRelativePosition(card.id)
    showPopParticle(this.g_cartoon.images.get("_bubble"), { x: myCard.x , y: myCard.y }, this.g_stage);
  }

  // 选择正确动画
  showCorrectPatal(card_id, showTime, callback?) {
    this.m_elementPetalArr = [];
    this.m_showElementPetalFlag = true;
    this.addCorrectPetal(card_id);
    setTimeout(()=>{
      this.m_elementPetalArr = [];
      this.m_showElementPetalFlag = false;
      callback && callback()
    },showTime)
  }
  stopAllCorrectPatal(){
    this.m_elementPetalArr = [];
    this.m_showElementPetalFlag = false;
  }

  addCorrectPetal(card_id) {
    if (!this.m_showElementPetalFlag) {
      return;
    }

    let element = this.g_cartoon.getCartoonElement(card_id)
    const petal = new MySprite(this.g_ctx);

    const id = Math.ceil(Math.random() * 3);
    petal.init(this.g_cartoon.images.get(this.m_PetalImage + id));

    const randomS = (Math.random() * 0.4 + 0.6) * this.g_mapScale * 0.5;
    petal.setScaleXY(randomS);

    const randomR = Math.random() * 360;
    petal.rotation = randomR;

    const randomX = Math.random() * element.ref.width * this.g_mapScale;

    petal.x = element.ref.x - (element.ref.width * this.g_mapScale / 2) + randomX;
    petal.y = element.ref.y - (element.ref.height * this.g_mapScale / 2);

    const randomT = 1 + Math.random() * 2;
    petal["time"] = randomT;

    let randomTR = 360 * Math.random(); // - 180;
    if (Math.random() < 0.5) {
      randomTR *= -1;
    }
    petal["tr"] = randomTR;

    this.m_elementPetalArr.push(petal);
    moveItem(
      petal,
      petal.x,
      element.ref.y + (element.ref.height * this.g_mapScale / 2),
      petal["time"],
      () => {
        removeItemFromArr(this.m_elementPetalArr, petal);
      }
    );
    rotateItem(petal, petal["tr"], petal["time"]);
    setTimeout(() => {
      this.addCorrectPetal(card_id);
    }, 200);
  }


  // 结束动画花瓣飘落
  showEndPatal(totalTimes?) {
    this.m_endPageArr = [];
    this.m_showPetalFlag = true;
    this.addPetal(totalTimes);
  }

  stopEndPatal() {
    this.m_endPageArr = [];
    this.m_showPetalFlag = false;
  }

  addPetal(totalTimes?) {
    if (!this.m_showPetalFlag) {
      return;
    }
    const petal = this.getPetal();
    this.m_endPageArr.push(petal);
    moveItem(
      petal,
      petal.x,
      this.g_canvasHeight + petal.height * petal.scaleY,
      petal["time"],
      () => {
        removeItemFromArr(this.m_endPageArr, petal);
      }
    );
    rotateItem(petal, petal["tr"], petal["time"]);
    totalTimes -= 100
    if(totalTimes>=0){
      setTimeout(() => {
        this.addPetal(totalTimes);
      }, 100);
    }
  }

  getPetal() {
    const petal = new MySprite(this.g_ctx);

    const id = Math.ceil(Math.random() * 3);
    petal.init(this.g_cartoon.images.get(this.m_PetalImage + id));

    const randomS = (Math.random() * 0.4 + 0.6) * this.g_mapScale;
    petal.setScaleXY(randomS);

    const randomR = Math.random() * 360;
    petal.rotation = randomR;

    const randomX = Math.random() * this.g_canvasWidth;
    petal.x = randomX;
    petal.y = (-petal.height / 2) * petal.scaleY;

    const randomT = 2 + Math.random() * 5;
    petal["time"] = randomT;

    let randomTR = 360 * Math.random(); // - 180;
    if (Math.random() < 0.5) {
      randomTR *= -1;
    }
    petal["tr"] = randomTR;

    return petal;
  }


  showJellyAnimation(element_id, callback?){
    let element = this.g_cartoon.getCartoonElement(element_id).ref
    tweenChange(element,{ scaleX: element.initScaleX * 1.2 , scaleY: element.initScaleY * 1.1 }, 0.1, ()=>{
      tweenChange(element,{ scaleX: element.initScaleX * 0.8 , scaleY: element.initScaleY * 0.9 }, 0.1, ()=>{
        tweenChange(element,{ scaleX: element.initScaleX , scaleY: element.initScaleY }, 0.1, ()=>{
          callback && callback()
        })
      })
    })
  }

  showShakeAnimation(element_id, callback?){
    let element = this.g_cartoon.getCartoonElement(element_id).ref
    let originX = element.x
    tweenChange(element,{ x: originX - 10*this.g_mapScale }, 0.1, ()=>{
      tweenChange(element,{ x: originX + 10*this.g_mapScale }, 0.1, ()=>{
        tweenChange(element,{ x: originX }, 0.1, ()=>{
          callback && callback()
        })
      })
    })
  }

  convertPercentToRadian(per, direction){
    let radian = 0;
    if(direction) { //逆时针
      if(per*360 > 270){
        radian = 361 - (per*360 - 270)
      }else{
        radian = 270 - per*360
      }
    }else{ //顺时针
      if(per*360 > 90){
        radian = per*360 - 90
      }else{
        radian = 270 + per*360
      }
    }
    return (radian * Math.PI) / 180;
  }

  showBlingStar(element, callback?){
    let rect =  element.getBoundingBox()
    showBlingBling(this.g_cartoon.images.get('icon_star'), rect, element, 0.5, 1, 0.08, 0.5);
    this.m_setTimeoutIDs.push(setTimeout(() => {
      callback && callback()
    }, 2000))
    // setTimeout(()=>{
    //   showBlingBling(this.g_cartoon.images.get('icon_star'), rect, element, 0.5, 1, 0.08, 1.8);
    // },200)
    // setTimeout(()=>{
    //   showBlingBling(this.g_cartoon.images.get('icon_star'), rect, element, 0.5, 1, 0.08, 1.6);
    // },400)
  }

  movePaoWuxian(element,dis,time,callback?){
    let disX = dis.x - element.x
    let disY = (element.y - dis.y) 
    let count = 0
    let runTime = time/5
    let vx = disX/runTime
    let a = -0.05
    let vy0 = disY/runTime - 0.5*a*runTime
    let id = setInterval(()=>{
      element.x += vx
      element.y -= vy0 + a*count
      count++;
      if(count>runTime){
        clearInterval(id)
        callback && callback()
      }
    }, 5);
  }
}

