import {
  Component,
  ElementRef,
  ViewChild,
  OnInit,
  Input,
  OnDestroy,
  HostListener
} from "@angular/core";

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

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

import { Cartoon } from './Cartoon'
import { Subject } from "rxjs";
import { debounceTime, map, takeWhile } from "rxjs/operators";
import * as _ from "lodash";
import TWEEN from "@tweenjs/tween.js";

// const defauleFormData = {
//   bgMusic:"FC-Sonw",
//   dataArray:[
//     {type:"Image", image_url:"bee-demo", audio_url:"bee-demo"},
//     {type:"Text", text:"Apple", audio_url:"apple-demo"},
//     {type:"Image", image_url:"bee-demo", audio_url:"bee-demo"},
//     {type:"Text", text:"Apple", audio_url:"apple-demo"},
//     {type:"Image", image_url:"bee-demo", audio_url:"bee-demo"},
//     {type:"Text", text:"Apple", audio_url:"apple-demo"},
//     {type:"Image", image_url:"bee-demo", audio_url:"bee-demo"},
//     {type:"Text", text:"Apple", audio_url:"apple-demo"},
//     {type:"Image", image_url:"bee-demo", audio_url:"bee-demo"},
//     {type:"Text", text:"Apple", audio_url:"apple-demo"},
//     {type:"Image", image_url:"bee-demo", audio_url:"bee-demo"},
//     {type:"Text", text:"Apple", audio_url:"apple-demo"}
//   ],
//   cardContainerSetting: {
//     type: "A",
//     image_url: "dish"
//   }
// }

const defauleFormData = {
  bgMusic:"FC-Sonw",
  dataArray:[
    {type:"Image", image_url:"bee-demo", audio_url:"bee-demo"},
    {type:"Text", text:"Apple", audio_url:"apple-demo"}
  ],
  cardContainerSetting: {
    type: "A",
    image_url: "dish"
  }
}

const zIndexMap = {
  background: -1001,
  smallGrass: -1000,
  cylinder: 100,
  grass:10000,
  monkey:500,
  card:1000
}

@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_enableMapDown = true; // 触摸使能
  g_enableMapUp = true; // 抬起使能
  g_enableMapMove = true; // 移动ss使能
  g_canvasLeft;
  g_canvasTop;
  g_animationId: any;
  g_mapScale = 1; // 缩放比例
  g_KEY = "DataKey_East_L215";
  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;
  // ------------------------------------

  // ------------  私有数据  ------------
  m_mapDownQueue = {} //按下事件处理队列
  m_mapUpQueue = {} //抬起事件处理队列
  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_allCardIds = []
  m_allCardContentIds = []
  m_runIntervalId = null
  m_runStatus = false;
  m_mouseInRunway = false;

  m_rightBuffer = []
  m_requestAfterCard = false;
  m_requestID = null;
  m_enableRunway = false;
  m_pickupCard = false;
  m_currentPickupCardID = null;
  m_allSelectedHotZone = [];
  m_moveAsstantIntervalId = null
  m_endGame = false;
  m_restartGame = false;
  // ------------------------------------


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


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


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

  // 映射预加载图片[网路]资源 返回包含图片路径的数组
  mapToImageArray(contentObj){
    let array = []
    if(contentObj.cardContainerSetting.type == "D"){
      array.push(contentObj.cardContainerSetting.image_url?contentObj.cardContainerSetting.image_url:"")
    }
    contentObj.dataArray.forEach(item => {
      if(item.type=="Image"){
        array.push(item.image_url?item.image_url:"")
      }
    });
    return array
  }

  // 映射预加载音频[网路]资源 返回包含音频路径的数组
  mapToAduioArray(contentObj){
    let array = []
    array.push(contentObj.bgMusic?contentObj.bgMusic:"")
    contentObj.dataArray.forEach(item => {
      array.push(item.audio_url?item.audio_url:"")
    });
    return array
  }

  restartGame() {
    this.initSystem();
    this.cleanGameVar()
    this.initGame()
    this.m_restartGame = true;
  }


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

  initGame(){
    this.initBackground();
    this.initTitle()
    this.initTable()
    this.initCardContainer()
    this.initCardRunway()
    this.initCards()
    this.initLights()
    this.cardRunControl(true)
    this.initSelectedCardArea()
    this.initStartButton()
    this.initBackgroundMusic()
    this.initRestartButton()
  }

  cleanGameVar(){
    this.stopAllInterval();
    this.stopAllTimeout()
    this.g_cartoon.stopAllAudio()

    this.m_allCardIds = []
    this.m_allCardContentIds = []
    this.cardRunControl(false)
    clearInterval(this.m_runIntervalId)
    this.m_runIntervalId = null
    this.m_rightBuffer = []
    this.m_requestAfterCard = false;
    this.m_requestID = null;
    this.m_enableRunway = false;
    this.m_pickupCard = false;
    this.m_currentPickupCardID = null;
    this.m_allSelectedHotZone = []
    this.m_endGame = false;
    this.m_restartGame = false;
    this.disableMoveAsstant()
  }

  endGame(){
    this.g_cartoon.stopAllAudio()
    this.g_cartoon.playAudio("sm-choice-complete", false, ()=>{
      setTimeout(() => {
        this.stopEndPatal()
        this.g_cartoon.getCartoonElement("restart-button").show();
      }, (500));
    })
    this.showEndPatal()
    this.cardRunControl(false)
    this.m_endGame = true;
  }

  // 播放背景音乐
  initBackgroundMusic(){
    let play = ()=>{
      this.g_cartoon.playAudio(this.g_formData.bgMusic, false, ()=>{
        play()
      })
    }
    if(!this.m_restartGame){
      play()
    }
  }

  // 背景
  initBackground(){
    let element = this.g_cartoon.createCartoonElementImage('my-background', "bg-background", this.g_canvasWidth, this.g_canvasHeight, this.g_canvasWidth/2, this.g_canvasHeight/2,)
    this.subscribeMapMoveEvent('my-background', ()=>{
      if(this.m_mouseInRunway){
        this.cardRunControl(true)
      }
      this.m_mouseInRunway = false;
      this.g_enableMapMove = true;
    })
    this.render(element.ref)
  }
  

  // 标题
  initTitle(){
    let titleText = "Drag and drop games"
    let element = this.g_cartoon.createCartoonElementImage('title', "bg_title", 576*this.g_mapScale, 66*this.g_mapScale, this.g_canvasWidth/2, this.g_cartoon.getOrigin().y+34*this.g_mapScale)
    let title = new Label()
    title.text = titleText
    title.fontColor = "#fffc1d";
    title.fontName = "BerlinSansFBDemi-Bold";
    title.fontSize = 58
    title.x = -288
    element.ref.addChild(title)
    this.render(element.ref)
  }


  // 跑道
  initCardRunway(){
    let element = this.g_cartoon.createCartoonElementImageFunc('card-runway', "bg_card_runway", (w,h)=>{
      return {
        sx: this.g_canvasWidth/w,
        sy: 300*this.g_mapScale/h
      }
    }, (w,h)=>{
      return {
        x: this.g_canvasWidth/2,
        y: this.g_cartoon.getOrigin().y+ (h/2)*this.g_mapScale + 78*this.g_mapScale
      }
    })

    this.subscribeMapMoveEvent('card-runway', ()=>{
      if(!this.m_mouseInRunway){
        this.cardRunControl(false)
      }
      this.m_mouseInRunway = true;
      this.g_enableMapMove = true;
      return true;
    },-1)

    this.render(element.ref)
  }


  // 桌子
  initTable(){
    let element = this.g_cartoon.createCartoonElementImageFunc('desk', "desk", (w,h)=>{
      return {
        sx: this.g_canvasWidth/w,
        sy: 228*this.g_mapScale/h
      }
    }, (w,h)=>{
      return {
        x: this.g_canvasWidth/2,
        y: this.g_cartoon.getOrigin().y+ (h/2)*this.g_mapScale + 492*this.g_mapScale
      }
    })
    this.render(element.ref)
  }

  // 卡片容器（盘子 桌布）
  initCardContainer(){
    let pos = {
      image:"",x:0, y:0, sx:0, sy:0
    }
    switch(this.g_formData.cardContainerSetting.type){
      case "A":
        pos.image = "dish";
        pos.x = this.g_canvasWidth/2;
        pos.y = 660*this.g_mapScale;
        pos.sx = 658*this.g_mapScale;
        pos.sy = 228*this.g_mapScale;
        break;
      case "B":
        pos.image = "box";
        pos.x = this.g_canvasWidth/2;
        pos.y = 720*this.g_mapScale;
        pos.sx = 771*this.g_mapScale*0.8;
        pos.sy = 282*this.g_mapScale*0.8;
        break;
      case "C":
        pos.image = "tablecloth";
        pos.x = this.g_canvasWidth/2;
        pos.y = 718*this.g_mapScale;
        pos.sx = 918*this.g_mapScale;
        pos.sy = 228*this.g_mapScale;
        break;
      default:
        pos.image = this.g_formData.cardContainerSetting.image_url;
        pos.x = this.g_canvasWidth/2;
        pos.y = 820*this.g_mapScale;
        pos.sx = 658*this.g_mapScale;
        pos.sy = 228*this.g_mapScale;
        break;  
    }
    let element = this.g_cartoon.createCartoonElementImageFunc('card-container', pos.image, (w,h)=>{
      return {
        sx: pos.sx/w,
        sy: pos.sy/h
      }
    }, (w,h)=>{
      return {
        x: pos.x,
        y: this.g_cartoon.getOrigin().y - (h/2)*this.g_mapScale + pos.y
      }
    })
    this.render(element.ref)
  }


  // 选择卡片
  initCards(){
    let boundingBox = this.g_cartoon.getCartoonElement('card-runway').ref.getBoundingBox()
    let cardWidth = 244*this.g_mapScale
    let cardNumber = Math.ceil(this.g_canvasWidth/cardWidth);
    let cardDetailArray = this.g_formData.dataArray
    for(let index=0; index<cardDetailArray.length; index++){
      let newCard = this.createCard(index,index*cardWidth,boundingBox.y,cardDetailArray[index]);
      if(index>=cardNumber){
        newCard.ref.x = -999
        newCard.waiting = true;
        this.m_rightBuffer.push(newCard.id)
      }
      if(newCard.ref.x + 115*this.g_mapScale > this.g_canvasWidth){
        this.m_enableRunway = true;
      }
      this.render(newCard.ref)
    }
  }

  createCard(index,x,y,data){
    this.m_allCardIds.push(`card-bckground-${index}`)
    this.m_allCardContentIds.push(`card-content-${index}`)
    let element = this.g_cartoon.createCartoonElementImageFunc(`card-bckground-${index}`, "bg_card", (w,h)=>{
      return {
        sx: 230*this.g_mapScale/w,
        sy: 209*this.g_mapScale/h
      }
    }, (w,h)=>{
      return {
        x: x + (w/2)*this.g_mapScale + 14*this.g_mapScale,
        y: y + 150*this.g_mapScale
      }
    })
    element.content = null;

    // 可移动卡片
    let cardContent = this.g_cartoon.createCartoonElementImageFunc(`card-content-${index}`, "card", (w,h)=>{
      return {
        sx: (180*this.g_mapScale)/w,
        sy: (180*this.g_mapScale)/h
      }
    }, (w,h)=>{
      return {
        x: element.ref.x,
        y: element.ref.y
      }
    })

    let hilightBackground = this.g_cartoon.createCartoonElementImage(`card-content-${index}-highlight`, "card-highlight", 310, 320, -3*this.g_mapScale,-5*this.g_mapScale,false);
    cardContent.ref.addChild(hilightBackground.ref)
    hilightBackground.ref.visible = false;
    cardContent.parentID = `card-bckground-${index}` 
    cardContent.canMove = false;
    cardContent.clickTime = null
    
    cardContent.handleClick = ()=>{
      this.g_cartoon.playAudio("sm-click")
      cardContent.canMove = true;
      if(cardContent.parentID && cardContent.parentID.indexOf("pos_")==-1){
        this.g_cartoon.getCartoonElement(cardContent.parentID).content = null
      }
      this.enableMoveAsstant(cardContent)
      this.m_pickupCard = true;
      this.m_currentPickupCardID = `card-content-${index}`
      // this.g_cartoon.getCartoonElement(`selected-card-hotzone`).show()
      this.topOfRenderArray(cardContent.ref)
      element.baseClick_x = this.g_clickX
      element.baseClick_y = this.g_clickY
      hilightBackground.ref.visible = true;
    }

    cardContent.handleMouseUp = (isSaveCurrentPickupCardID?)=>{
      cardContent.clickTime = null
      let savedPickupCardID = this.m_currentPickupCardID;
      if(cardContent.canMove){
        setTimeout(()=>{
          cardContent.canMove = false;
          cardContent.backToParent()
          if(isSaveCurrentPickupCardID){
            this.m_currentPickupCardID = savedPickupCardID
            this.m_pickupCard = false;
          }
          // this.g_cartoon.getCartoonElement(`selected-card-hotzone`).hide()
        },100)
      }
      if(!isSaveCurrentPickupCardID){
        this.disableMoveAsstant()
        this.g_enableMapUp = true;
      }
    }

    this.subscribeMapDownEvent(`card-content-${index}`, ()=>{
      if(this.m_endGame){
        if(cardContent.parentID.indexOf("hot") != -1){
          this.g_cartoon.playAudio(data.audio_url);
        }
        this.g_enableMapDown = true;
        return
      }
      if( cardContent.parentID.indexOf("hot") != -1 ){
        this.g_cartoon.playAudio(data.audio_url)
        cardContent.clickTime = new Date().getTime()
      }else{
        cardContent.handleClick()
      }
      this.g_enableMapDown = true;
    })

    this.subscribeMapMoveEvent(`card-content-${index}`, ()=>{
      if( cardContent.clickTime ){
        let a = cardContent.clickTime - new Date().getTime()
        if(Math.abs(a)>50){
          cardContent.handleClick()
          cardContent.clickTime = null
        }
      }
      if( cardContent.canMove  ){
        if(cardContent.parentID.indexOf("pos_") == -1 || this.m_renderArr.indexOf(cardContent.ref) == this.m_renderArr.length-1){
          cardContent.ref.x = this.g_clickX
          cardContent.ref.y = this.g_clickY
        }else if(cardContent.parentID.indexOf("pos_") != -1){
          cardContent.handleMouseUp(true)
        }
      }
      this.g_enableMapMove = true;
    })

    this.subscribeMapUpEvent(`card-content-${index}`, ()=>{
      cardContent.handleMouseUp()
    })
    element.content = cardContent

    cardContent.backToParent = ()=>{
      cardContent.canMove = false;
      this.m_pickupCard = false;

      if(cardContent.parentID){
        if(cardContent.parentID.indexOf("pos_") == -1){
          this.g_cartoon.getCartoonElement(cardContent.parentID).setContent(cardContent)
        }else{
          tweenChange(cardContent.ref, {x:cardContent.parentID.split("_")[1], y:cardContent.parentID.split("_")[2]}, 0.1)
        }
      }

      hilightBackground.ref.visible = false;
      this.m_currentPickupCardID = null;
    }
    this.render(cardContent.ref,999)
    // 

    if(data.type == "Text"){
      let textContent = new Label()
      textContent.text = data.text?data.text:"Demo"
      textContent.fontColor = "#e05e14";
      textContent.fontName = "BerlinSansFBDemi-Bold";
      textContent.textAlign = "center";
      textContent.x = textContent.width/2
      let textSize = 180*this.g_mapScale / textContent.text.length
      if(textSize>50){
        textSize = 50
      }
      textContent.fontSize = textSize
      cardContent.ref.addChild(textContent)
    }else{
      let imageContent = new MySprite()
      imageContent.init(this.g_cartoon.images.get(data.image_url?data.image_url:"_noImage"))
      imageContent.setScaleXY(Math.min( 110/imageContent.width, 110/imageContent.height ))
      cardContent.ref.addChild(imageContent)
    }
      
    element.moveLeft = (distance)=>{
      element.ref.x -= distance
      if(element.content){
        element.content.ref.x -= distance;
      }
    }

    element.readyGoOut = (x)=>{
      element.ref.x = x
      if(element.content){
        element.content.ref.x = x;
      }
    }

    element.setContent = (content)=>{
      tweenChange(content.ref, {x:element.ref.x, y:element.ref.y}, 0.1)
      element.content = content
      content.parentID = element.id
    }

    element.cleanContent = ()=>{
      element.content = null
    }

    this.subscribeMapUpEvent(`card-bckground-${index}`, ()=>{
      if(!element.content){
        if(this.m_currentPickupCardID){
          let card = this.g_cartoon.getCartoonElement(this.m_currentPickupCardID)
          if(card.parentID && card.parentID.indexOf("pos_").index==-1){
            this.g_cartoon.getCartoonElement(card.parentID).content = null;
          }
          element.setContent(this.g_cartoon.getCartoonElement(this.m_currentPickupCardID))
          this.g_cartoon.getCartoonElement("start-button").showHideCheck()
        }
      }
      this.g_enableMapUp = true;
    })
    return element;
  }

  // 跑道启停控制
  cardRunControl(status){
    if(!this.m_enableRunway || this.m_endGame ){
      return;
    }
    let step = Math.floor(this.g_mapScale*10000)/20000;
    let cardElement = null;
    this.m_runStatus = status
    if(!this.m_runIntervalId){
      this.m_runIntervalId = setInterval(()=>{
        if(!this.m_runStatus){
          return
        }
        this.m_allCardIds.forEach((id)=>{
          cardElement = this.g_cartoon.getCartoonElement(id)
          if(!cardElement.waiting){
            cardElement.moveLeft(step)
          }
          this.cardRecyclingAndPreparation(id)
        })
        this.m_runStatus = true;
      },10)
    }
  }


  // 灯光
  initLights(){
    let totalLightCount = Math.ceil(this.g_canvasWidth / (82*this.g_mapScale))
    let baseY = this.g_cartoon.getCartoonElement('card-runway').ref.y
    let height = this.g_cartoon.getCartoonElement('card-runway').ref.height*this.g_mapScale
    let pos_y = [
      baseY - height/2 + 22*this.g_mapScale,
      baseY + height/2 - 22*this.g_mapScale
    ]
    let base_x = 24*this.g_mapScale;
    for(let line=0; line<2; line++){
      for(let row=0; row<totalLightCount; row++){
        this.render(this.createLights(line,row,base_x,pos_y,true).ref)
      }
    }
    for(let line=0; line<2; line++){
      for(let row=0; row<totalLightCount; row++){
        this.render(this.createLights(line,row,base_x,pos_y,false).ref)
      }
    }
    this.runWaterLights(totalLightCount)
  }

  createLights(line, row, base_x, pos_y,stuats){
    if(stuats){
      let element = this.g_cartoon.createCartoonElementImage(`water-light-${line}-${row}-on`, "light-2", 48*this.g_mapScale, 48*this.g_mapScale, base_x + row*82*this.g_mapScale, pos_y[line])
      element.ref.visible = false;
      return element;
    }else{
      let element = this.g_cartoon.createCartoonElementImage(`water-light-${line}-${row}-off`, "light-1", 48*this.g_mapScale, 48*this.g_mapScale, base_x + row*82*this.g_mapScale, pos_y[line])
      return element;
    }
  }

  lightOn(line, row){
    this.g_cartoon.getCartoonElementRef(`water-light-${line}-${row}-on`).visible = true;
  }
  lightOff(line, row){
    this.g_cartoon.getCartoonElementRef(`water-light-${line}-${row}-on`).visible = false;
  }

  runWaterLights(totalLightCount){
    let runTime = 3//Math.floor(totalLightCount/5)
    for(let count=0; count<runTime; count++){
      this.m_setTimeoutIDs.push(setTimeout(()=>{
        let count_l0 = 0;
        let dir_l0 = true;
        this.m_setIntervalIDs.push(setInterval(()=>{
          this.lightOff(0,count_l0)
          if(dir_l0){
            count_l0++
          }else{
            count_l0--
          }
          if(count_l0 >= totalLightCount){
            count_l0--
            dir_l0 =! dir_l0;
          }else if(count_l0 <= -1){
            count_l0++
            dir_l0 =! dir_l0;
          }
          this.lightOn(0,count_l0)
        },100))
  
        let count_l1 = totalLightCount-1;
        let dir_l1 = true;
        this.m_setIntervalIDs.push(setInterval(()=>{
          this.lightOff(1,count_l1)
          if(dir_l1){
            count_l1++
          }else{
            count_l1--
          }
          if(count_l1 >= totalLightCount){
            count_l1--
            dir_l1 =! dir_l1;
          }else if(count_l1 <= -1){
            count_l1++
            dir_l1 =! dir_l1;
          }
          this.lightOn(1,count_l1)
        },100))
      }, count*500))
    }
    
  }

  // 卡片回收与准备控制
  cardRecyclingAndPreparation(id){
    let ele = this.g_cartoon.getCartoonElement(id)
    let x = ele.ref.x;
    let width = 230*this.g_mapScale;
    if( (x + width*0.5) < this.g_canvasWidth && ( (x+ width*0.5) > this.g_canvasWidth-14*this.g_mapScale) && !this.m_requestAfterCard ){
      if(this.m_requestID  != id){
        this.m_requestAfterCard = true;
        this.m_requestID = id
      }
    }

    if(this.m_rightBuffer[0] && this.m_requestAfterCard){
      this.m_requestAfterCard = false;
      this.g_cartoon.getCartoonElementRef(this.m_rightBuffer[0]).alpha = 0;
      // this.g_cartoon.getCartoonElementRef(this.m_rightBuffer[0]).x = this.g_cartoon.getCartoonElementRef(this.m_requestID).x + width + 14*this.g_mapScale
      this.g_cartoon.getCartoonElement(this.m_rightBuffer[0]).readyGoOut(this.g_cartoon.getCartoonElementRef(this.m_requestID).x + width + 14*this.g_mapScale)
      tweenChange(this.g_cartoon.getCartoonElementRef(this.m_rightBuffer[0]), {alpha: 1}, 0.2)
      this.g_cartoon.getCartoonElement(this.m_rightBuffer[0]).waiting = false;
      this.m_rightBuffer.splice(0,1)
    }

    if( x < -0.5*width && !this.g_cartoon.getCartoonElement(id).waiting){
      this.g_cartoon.getCartoonElement(id).waiting = true;
      this.m_rightBuffer.push(id)
    }
  }


  // 已选择卡片放置点
  initSelectedCardArea(){
    let totalLightCount = Math.floor(this.g_canvasWidth / (190*this.g_mapScale))-1
    let baseLine = null;
    switch(this.g_formData.cardContainerSetting.type){
      case "A": baseLine = 165*this.g_mapScale; break;
      case "B": baseLine = 125*this.g_mapScale; break;
      case "C": baseLine = 165*this.g_mapScale; break;
      default: baseLine = 165*this.g_mapScale;
    }
    let element = this.g_cartoon.createCartoonElementImageFunc(`selected-card-hotzone`, "bg_1280_250", (w,h)=>{
      return {
        sx: this.g_canvasWidth/w,
        sy: (280*this.g_mapScale)/h
      }
    }, (w,h)=>{
      return {
        x: this.g_canvasWidth/2,
        y: this.g_cartoon.getOrigin().y + 555*this.g_mapScale
      }
    })
    element.ref.alpha = 0;


    this.subscribeMapUpEvent(`selected-card-hotzone`, ()=>{

      if(this.m_currentPickupCardID){
        let card = this.g_cartoon.getCartoonElement(this.m_currentPickupCardID)
        if(card.parentID && card.parentID.indexOf("pos_")==-1){
          this.g_cartoon.getCartoonElement(card.parentID).content = null;
        }
        card.parentID = "pos_" + this.g_clickX + "_" + this.g_clickY
        this.g_cartoon.getCartoonElement("start-button").showHideCheck()
      }

      this.g_enableMapUp = true;
    })

    // let base_X = -1*(200*this.g_mapScale*totalLightCount)/2
    // for(let index=0; index<totalLightCount; index++){
    //   let a = index%2==1?-1:1
    //   element.ref.addChild(this.createSelectedCardArea(index,base_X + 190*this.g_mapScale*index,0))
    // }

    // element.show = ()=>{
    //   this.m_allSelectedHotZone.forEach((id)=>{
    //     tweenChange(this.g_cartoon.getCartoonElement(id).ref, {alpha:0.7}, 0.2)
    //   })
    // }
    // element.hide = ()=>{
    //   this.m_allSelectedHotZone.forEach((id)=>{
    //     tweenChange(this.g_cartoon.getCartoonElement(id).ref, {alpha:0}, 0.2)
    //   })
    // }


    this.render(element.ref)
  }
  
  createSelectedCardArea(index,x,y){
    let element = this.g_cartoon.createCartoonElementImageFunc(`selected-card-hotzone-${index}`, "bg_selected_card", (w,h)=>{
      return {
        sx: 180*this.g_mapScale/w,
        sy: 180*this.g_mapScale/h
      }
    }, (w,h)=>{
      return {
        x: x + 90*this.g_mapScale,
        y: y
      }
    })
    element.ref.alpha = 0;
    element.content = null
    element.setContent = (content)=>{
      let box = element.ref.getBoundingBox()
      tweenChange(content.ref, {x:box.x + box.width/2, y:box.y + box.height/2}, 0.2)
      element.content = content
      content.parentID = element.id
    }

    this.subscribeMapUpEvent(`selected-card-hotzone-${index}`, ()=>{
      if(!element.content){
        if(this.m_currentPickupCardID){
          let card = this.g_cartoon.getCartoonElement(this.m_currentPickupCardID)
          if(card.parentID){
            this.g_cartoon.getCartoonElement(card.parentID).content = null;
          }
          element.setContent(this.g_cartoon.getCartoonElement(this.m_currentPickupCardID))
          this.g_cartoon.getCartoonElement("start-button").showHideCheck()
        }
      }
      this.g_enableMapUp = true;


    })
    this.m_allSelectedHotZone.push(element.id)
    return element.ref
  }

  initStartButton(){
    let element = this.g_cartoon.createCartoonElementImageFunc("start-button", "btn-ok", (w,h)=>{
      return {
        sx: 128*this.g_mapScale/w,
        sy: 128*this.g_mapScale/h
      }
    }, (w,h)=>{
      return {
        x: this.g_canvasWidth - 36*this.g_mapScale - (h/2)*this.g_mapScale,
        y: 554*this.g_mapScale + (h/2)*this.g_mapScale
      }
    })
    element.ref.scaleX = 0;
    element.ref.scaleY = 0;
    element.showStatus = false;

    element.getAllCards = ()=>{
      let allSelectedCards = []
      // this.m_allSelectedHotZone.forEach(id=>{
      //   let content_id = this.g_cartoon.getCartoonElement(id).content?this.g_cartoon.getCartoonElement(id).content.id:null
      //   if(content_id){
      //     allSelectedCards.push(content_id)
      //   }
      // })

      this.m_allCardContentIds.forEach(id=>{
        let parentID = this.g_cartoon.getCartoonElement(id).parentID?this.g_cartoon.getCartoonElement(id).parentID:null
        if(parentID && parentID.indexOf("pos_")!=-1){
          allSelectedCards.push(parentID)
        }
      })
      return allSelectedCards
    }
    
    element.click = ()=>{
      tweenChange(element.ref, {scaleX:element.ref.initScaleX*0.9, scaleY:element.ref.initScaleY*0.9}, 0.2,  ()=>{
        tweenChange(element.ref, {scaleX:element.ref.initScaleX, scaleY:element.ref.initScaleY}, 0.2, ()=>{
          this.endGame()
        })
      })
      // let allIDs = element.getAllCards()
      // let cardWidth = 180*this.g_mapScale
      // let allWidth = allIDs.length * cardWidth
      // let base_x = (this.g_canvasWidth - allWidth + cardWidth)/2
      // if(allIDs.length>0){
      //   allIDs.forEach((id,index) => {
      //     tweenChange( this.g_cartoon.getCartoonElement(id).ref, {x:base_x+index*cardWidth}, 0.2)
      //   });
      // }
      element.ref.scaleX = 0;
      element.ref.scaleY = 0;
      element.ref.x = 100000;
      this.g_enableMapDown = true;
    }

    element.showHideCheck = ()=>{
      if( element.getAllCards().length>0 && !element.showStatus ){
        tweenChange(element.ref, {scaleX:element.ref.initScaleX, scaleY: element.ref.initScaleY}, 0.1, ()=>{
          jelly(element.ref, 0.5)
        })
        element.showStatus = true;
      }else if( element.getAllCards().length==0 && element.showStatus ){
        element.showStatus = false
        tweenChange(element.ref, {scaleX:0, scaleY: 0}, 0.1)
      }
    }

    this.subscribeMapDownEvent("start-button", ()=>{
      element.click()
    })

    this.render(element.ref)
  }


  initRestartButton(){
    let element = this.g_cartoon.createCartoonElementImageFunc("restart-button", "btn-go", (w,h)=>{
      return {
        sx: 128*this.g_mapScale/w,
        sy: 128*this.g_mapScale/h
      }
    }, (w,h)=>{
      return {
        x: this.g_canvasWidth - 36*this.g_mapScale - (h/2)*this.g_mapScale,
        y: 554*this.g_mapScale + (h/2)*this.g_mapScale
      }
    })
    element.ref.scaleX = 0;
    element.ref.scaleY = 0;
    element.show = ()=>{
      element.ref.scaleX = element.ref.initScaleX;
      element.ref.scaleY = element.ref.initScaleY;
    }

    element.hide = ()=>{
      element.ref.scaleX = 0;
      element.ref.scaleY = 0;
    }

    this.subscribeMapDownEvent("restart-button", ()=>{
      element.hide()
      this.restartGame()
    })

    this.render(element.ref)
  }


  enableMoveAsstant(element){
    if(this.m_moveAsstantIntervalId){
      clearInterval(this.m_moveAsstantIntervalId)
    }
    this.m_moveAsstantIntervalId = setInterval(()=>{
      element.ref.x = this.g_clickX;
      element.ref.y = this.g_clickY;
    },50)
  }

  disableMoveAsstant(){
    clearInterval(this.m_moveAsstantIntervalId)
  }













































  // --------------------------------------------------
  // --------------  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 ) {
      // console.log("Init default form data")
      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) {
    if (!this.g_enableMapDown) {
      return;
    }
    for(let cartoonID in this.m_mapDownQueue){
      if (this.checkClickTarget(this.g_cartoon.getCartoonElementRef(cartoonID))) {
        this.g_enableMapDown = false;
        this.m_mapDownQueue[cartoonID]();
      }
    }
  }

  mapMove(event) {
    // console.log(this.g_clickX, this.g_clickY)
    let myStopPropagation = false;
    if (!this.g_enableMapMove) {
      return;
    }

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

  mapUp(event) {
    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]();
      }
    }
  }


  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);
  }


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


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


  initListener() {
    this.g_winResizeEventStream.pipe(debounceTime(500)).subscribe(data => {
      this.renderAfterResize();
    });

    if (this.IsPC()) {
      this.canvas.nativeElement.addEventListener("mousedown", event => {
        setMxMyByMouse(event);
        this.mapDown(event);
      });

      this.canvas.nativeElement.addEventListener("mousemove", event => {
        setMxMyByMouse(event);
        this.mapMove(event);
      });

      this.canvas.nativeElement.addEventListener("mouseup", event => {
        setMxMyByMouse(event);
        this.mapUp(event);
      });

      const setMxMyByMouse = event => {
        this.g_clickX = event.offsetX;
        this.g_clickY = event.offsetY;
      };
    } else {
      this.canvas.nativeElement.addEventListener("touchstart", event => {
        setMxMyByTouch(event);
        this.mapDown(event);
      });

      this.canvas.nativeElement.addEventListener("touchmove", event => {
        setMxMyByTouch(event);
        this.mapMove(event);
      });

      this.canvas.nativeElement.addEventListener("touchend", event => {
        setMxMyByTouch(event);
        this.mapUp(event);
      });

      this.canvas.nativeElement.addEventListener("touchcancel", event => {
        setMxMyByTouch(event);
        this.mapUp(event);
      });

      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;
      };
    }
  }

  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){
    this.m_mapDownQueue[id] = callback
  }

  subscribeMapUpEvent(id,callback){
    this.m_mapUpQueue[id] = callback
  }

  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.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, -999999)
    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)
    }   
  }

















  













  












  // --------------------------------------------------
  // --------------  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) {
    this.m_elementPetalArr = [];
    this.m_showElementPetalFlag = true;
    this.addCorrectPetal(card_id);
    setTimeout(()=>{
      this.m_elementPetalArr = [];
      this.m_showElementPetalFlag = false;
    },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() {
    this.m_endPageArr = [];
    this.m_showPetalFlag = true;
    this.addPetal();
  }

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

  addPetal() {
    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"]);
    setTimeout(() => {
      this.addPetal();
    }, 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){
    let element = this.g_cartoon.getCartoonElement(element_id).ref
    tweenChange(element,{ scaleX: this.g_mapScale * 1.1 , scaleY: this.g_mapScale * 1.1 }, 0.1, ()=>{
      tweenChange(element,{ scaleX: this.g_mapScale * 0.9 , scaleY: this.g_mapScale * 0.9 }, 0.1, ()=>{
        tweenChange(element,{ scaleX: this.g_mapScale , scaleY: this.g_mapScale }, 0.1 )
      })
    })
  }

  showShakeAnimation(element_id){
    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 )
      })
    })
  }

  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){
    let rect =  element.getBoundingBox()
    showBlingBling(this.g_cartoon.images.get('_star'), rect, element, 0.5, 1, 0.08, 2);
    setTimeout(()=>{
      showBlingBling(this.g_cartoon.images.get('_star'), rect, element, 0.5, 1, 0.08, 1.8);
    },200)
    setTimeout(()=>{
      showBlingBling(this.g_cartoon.images.get('_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);
  }
}



  