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

import {
  formatTime,
  Label,
  moveItem,
  MyAnimation,
  MySprite,
  removeItemFromArr,
  rotateItem,
  ShapeRect,
  tweenChange
} from './Unit';
import {res, resAudio} from './resources';

import {Subject} from 'rxjs';
import {debounceTime} from 'rxjs/operators';

import TWEEN from '@tweenjs/tween.js';


@Component({
  selector: 'app-play',
  templateUrl: './play.component.html',
  styleUrls: ['./play.component.css']
})
export class PlayComponent implements OnInit, OnDestroy {

  @ViewChild('canvas', {static: true}) canvas: ElementRef;
  @ViewChild('wrap', {static: true}) wrap: ElementRef;

  // 数据
  data;

  ctx;

  canvasWidth = 1280; // canvas实际宽度
  canvasHeight = 720; // canvas实际高度

  canvasBaseW = 1280; // canvas 资源预设宽度
  canvasBaseH = 720;  // canvas 资源预设高度

  mx; // 点击x坐标
  my; // 点击y坐标


  // 资源
  rawImages = new Map(res);
  rawAudios = new Map(resAudio);

  images = new Map();

  animationId: any;
  winResizeEventStream = new Subject();

  audioObj = {};

  renderArr;
  mapScale = 1;

  canvasLeft;
  canvasTop;

  saveKey = 'pu09';

  canTouch = true;

  borad;

  private rocketPipe: MySprite;
  private bg: MySprite;
  private currentTime: number;
  private progressBarBg: MySprite;
  private isClickedProgress: boolean;
  private curAudio: any;
  private sentences: any;
  private rocket: MySprite;
  private startView: ShapeRect;
  private allBtns: any;
  private showPetalFlag: boolean;
  private endPageArr: any;
  private petalTime: number;
  private isFly: boolean;
  private rocketBase: MySprite;


  @HostListener('window:resize', ['$event'])
  onResize(event) {
    this.winResizeEventStream.next();
  }


  ngOnInit() {

    this.data = {};

    // 获取数据
    const getData = (<any>window).courseware.getData;
    getData((data) => {

      if (data && typeof data == 'object') {
        this.data = data;
      }
      // console.log('data:' , data);

      // 初始化 各事件监听
      this.initListener();

      // 若无数据 则为预览模式 需要填充一些默认数据用来显示
      this.initDefaultData();

      // 初始化 音频资源
      this.initAudio();
      // 初始化 图片资源
      this.initImg();
      // 开始预加载资源
      this.load();

    }, this.saveKey);

  }

  ngOnDestroy() {
    window['curCtx'] = null;
    window.cancelAnimationFrame(this.animationId);
  }


  load() {

    // 预加载资源
    this.loadResources().then(() => {
      window['air'].hideAirClassLoading(this.saveKey, this.data);
      this.init();
      this.update();
    });
  }


  init() {

    this.initCtx();
    this.initData();
    this.initView();
  }

  initCtx() {
    this.canvasWidth = this.wrap.nativeElement.clientWidth;
    this.canvasHeight = this.wrap.nativeElement.clientHeight;
    this.canvas.nativeElement.width = this.wrap.nativeElement.clientWidth;
    this.canvas.nativeElement.height = this.wrap.nativeElement.clientHeight;


    this.ctx = this.canvas.nativeElement.getContext('2d');
    this.canvas.nativeElement.width = this.canvasWidth;
    this.canvas.nativeElement.height = this.canvasHeight;

    window['curCtx'] = this.ctx;
  }


  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.winResizeEventStream
      .pipe(debounceTime(500))
      .subscribe(data => {
        this.renderAfterResize();
      });


    // ---------------------------------------------
    const setParentOffset = () => {
      const rect = this.canvas.nativeElement.getBoundingClientRect();
      this.canvasLeft = rect.left;
      this.canvasTop = rect.top;
    };
    const setMxMyByTouch = (event) => {
      if (event.touches.length <= 0) {
        return;
      }
      if (this.canvasLeft == null) {
        setParentOffset();
      }
      this.mx = event.touches[0].pageX - this.canvasLeft;
      this.my = event.touches[0].pageY - this.canvasTop;
    };

    const setMxMyByMouse = (event) => {
      this.mx = event.offsetX;
      this.my = event.offsetY;
    };
    // ---------------------------------------------


    let firstTouch = true;

    const touchDownFunc = (e) => {
      if (firstTouch) {
        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 (firstTouch) {
        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 element = this.canvas.nativeElement;

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

    addMouseListener();
    addTouchListener();
  }


  playAudio(key, now = true, callback = null, volume = null) {

    console.log('key: ', key);

    const audio = this.audioObj[key];
    console.log('audio: ', audio);

    if (audio) {
      if (now) {
        audio.pause();
        audio.currentTime = 0;
      }

      if (callback) {
        audio.onended = () => {
          callback();
        };
      }

      if (volume) {
        audio.volume = volume;
      }
      audio.play();
    }
  }


  loadResources() {
    const pr = [];
    this.rawImages.forEach((value, key) => {// 预加载图片

      const p = this.preload(value)
        .then(img => {
          this.images.set(key, img);
        })
        .catch(err => console.log(err));

      pr.push(p);
    });

    this.rawAudios.forEach((value, key) => {// 预加载音频

      const a = this.preloadAudio(value)
        .then(() => {
          // this.images.set(key, img);
        })
        .catch(err => console.log(err));

      pr.push(a);
    });
    return Promise.all(pr);
  }

  preload(url) {
    return new Promise((resolve, reject) => {
      const img = new Image();
      // img.crossOrigin = "anonymous";
      img.onload = () => resolve(img);
      img.onerror = reject;
      img.src = url;
    });
  }

  preloadAudio(url) {
    return new Promise((resolve, reject) => {
      const audio = new Audio();
      audio.oncanplay = (a) => {
        resolve();
      };
      audio.onerror = () => {
        reject();
      };
      audio.src = url;
      audio.load();
    });
  }


  renderAfterResize() {
    this.canvasWidth = this.wrap.nativeElement.clientWidth;
    this.canvasHeight = this.wrap.nativeElement.clientHeight;
    this.init();
  }


  checkClickTarget(target) {

    const rect = target.getBoundingBox();

    if (this.checkPointInRect(this.mx, this.my, 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;
  }


  addUrlToAudioObj(key, url = null, vlomue = 1, loop = false, callback = null) {

    const audioObj = this.audioObj;

    if (url == null) {
      url = key;
    }

    this.rawAudios.set(key, url);

    const audio = new Audio();
    audio.src = url;
    audio.load();
    audio.loop = loop;
    audio.volume = vlomue;

    audioObj[key] = audio;

    if (callback) {
      audio.onended = () => {
        callback();
      };
    }
  }

  addUrlToImages(url) {
    this.rawImages.set(url, url);
  }


  // ======================================================编写区域==========================================================================


  /**
   * 添加默认数据 便于无数据时的展示
   */
  initDefaultData() {

    if (!this.data.pic_url) {
      this.data.pic_url = 'assets/play/default/pic.jpg';
      this.data.pic_url_2 = 'assets/play/default/pic.jpg';
    }

    if (!this.data.sentences) {
      this.data.sentences = [
        {
          text: '1. test sentence ____ .'
        },
        {
          text: '2. test sentence ____ .'
        }
      ];
    }

    if (!this.data.audio_url) {
      this.data.audio_url = 'assets/play/default/audio.mp3';
    }
  }


  /**
   * 添加预加载图片
   */
  initImg() {
    this.addUrlToImages(this.data.pic_url);
  }

  /**
   * 添加预加载音频
   */
  initAudio() {

    // 音频资源
    this.addUrlToAudioObj(this.data.audio_url);



    // 音效
    this.addUrlToAudioObj('start_mp3', this.rawAudios.get('start_mp3'), 1);
    this.addUrlToAudioObj('right_mp3', this.rawAudios.get('right_mp3'), 0.1);
    this.addUrlToAudioObj('refuel_mp3', this.rawAudios.get('refuel_mp3'), 0.1);
    this.addUrlToAudioObj('smoke_mp3', this.rawAudios.get('smoke_mp3'), 0.1);
    this.addUrlToAudioObj('fly_mp3', this.rawAudios.get('fly_mp3'), 0.1);
    this.addUrlToAudioObj('finish_mp3', this.rawAudios.get('finish_mp3'), 0.1);

  }


  /**
   * 初始化数据
   */
  initData() {

    const sx = this.canvasWidth / this.canvasBaseW;
    const sy = this.canvasHeight / this.canvasBaseH;
    const s = Math.min(sx, sy);
    this.mapScale = s;

    // this.mapScale = sx;
    // this.mapScale = sy;


    this.renderArr = [];

    this.canTouch = true;

    this.currentTime = 0;
    this.sentences = [];
    this.allBtns = [];
    this.endPageArr = [];
    this.isFly = false;

  }


  /**
   * 初始化试图
   */
  initView() {
    this.initBg();
    this.initBoard();
    this.initAudioPlayer();
    this.initSentences();
    this.initRocket();
    this.initStartView();

    // initBoard();
    // initAudioPlayer();


    // this.initPic();

    // this.initBottomPart();
  }

  initRocket() {

    const rocketBase = this.createSprite('rocket_base');
    rocketBase.x = this.borad.x;
    rocketBase.y = this.canvasHeight - 20 * this.mapScale;
    rocketBase.setScaleXY(this.mapScale);
    this.rocketBase = rocketBase;

    const rocket = this.createSprite('rocket');
    rocket.y = -rocket.height / 2 - 30;
    rocketBase.addChild(rocket);
    this.rocket = rocket;

    const rocketPipe = this.createSprite('rocket_pipe');
    rocketPipe.x = rocketBase.x - 200 * this.mapScale;
    rocketPipe.y = rocketBase.y - 90 * this.mapScale;
    rocketPipe.setScaleXY(this.mapScale);
    this.rocketPipe = rocketPipe;

    const pipeClip = this.createSprite('pipe_clip');
    pipeClip.x = -62;
    pipeClip.y = 42;
    rocketPipe.addChild(pipeClip)

    this.renderArr.push(rocketBase);
    this.renderArr.push(rocket);
  }

  initSentences() {
    const sentences = this.data.sentences;
    const baseX = this.canvasWidth - 350 * this.mapScale;
    const baseY = this.canvasHeight - 530 * this.mapScale;
    const offY = 90 * this.mapScale;

    sentences.forEach((sentenceData, i) => {
      const sentence = this.createSentenceContainer(sentenceData);
      sentence.x = baseX;
      sentence.y = baseY + i * offY;
      this.sentences.push(sentence);
    });
  }

  initBoard() {
    const pic = new MySprite();
    pic.init(this.images.get('board'));
    pic.setScaleXY(this.mapScale);
    pic.x = (pic.width / 2 - 130) * this.mapScale;
    pic.y = this.canvasHeight - pic.height / 2 * this.mapScale - 0 * this.mapScale;

    this.addScreenPicToBoard(pic);
    this.renderArr.push(pic);
    this.borad = pic;
  }

  mapDown(event) {

    if (!this.canTouch) {
      return;
    }

    if (this.startView.visible) {
      this.allBtns.forEach((btn) => {
        if (this.checkClickTarget(btn)) {
          btn._onTouchStart();
          return;
        }
      });
      return;
    }


    if (this.checkClickTarget(this.progressBarBg)) {
      this.isClickedProgress = true;
      this.touchDownProgressBar(this.progressBarBg);
      return;
    }

    if (this.checkClickTarget(this.curAudio.playBtn)) {
      this.touchDownAudioBtn(this.curAudio);
      return;
    }

    this.sentences.forEach((sentence) => {
      if (this.checkClickTarget(sentence) || this.checkClickTarget(sentence.ufoBtn)) {
        this.touchDownSentence(sentence);
        return;
      }
    });



  }

  mapMove(event) {
    if (!this.isClickedProgress) {
      return;
    }

    this.touchDownProgressBar(this.progressBarBg);

  }

  mapUp(event) {

    this.allBtns.forEach((btn) => {
      // if (this.checkClickTarget(btn)) {
      if (btn._isDown) {
        btn._onTouchEnd();
      }
      // }
    });

    this.isClickedProgress = false;
  }

  update() {

    // ----------------------------------------------------------
    this.animationId = window.requestAnimationFrame(this.update.bind(this));
    // 清除画布内容
    this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
    // tween 更新动画
    TWEEN.update();
    // ----------------------------------------------------------


    this.updateItem(this.bg);
    this.updateItem(this.rocketPipe);
    this.updateArr(this.renderArr);
    this.updateArr(this.endPageArr);
    this.updateTime();

  }

  private createSentenceContainer(sentence) {
    const sentenceBg: any = new MySprite();
    sentenceBg.init(this.images.get('sentence_bg'));
    sentenceBg.setScaleXY(this.mapScale);

    const labelOffX = 10;
    const labelMaxWidth = sentenceBg.width - labelOffX * 2;
    const label = new Label();
    label.text = sentence.text;
    label.fontColor = '#f3f1da';
    label.fontSize = 45;
    label.fontName = 'MMTextBook';
    label.x = -sentenceBg.width / 2 + labelOffX;
    label.y = -5;
    label.setMaxSize(labelMaxWidth);
    sentenceBg.addChild(label);

    const ufoBtn = this.createSprite('btn_ufo_1')
    sentenceBg.addChild(ufoBtn);
    ufoBtn.x = sentenceBg.width / 2 + 45;
    ufoBtn.y = sentenceBg.height / 2 - 8;

    const ufoBtnLight = this.createSprite('btn_ufo_2');
    ufoBtn.addChild(ufoBtnLight);
    this.hide(ufoBtnLight);

    sentenceBg.ufoBtn = ufoBtn;
    sentenceBg.ufoBtnLight = ufoBtnLight;
    this.renderArr.push(sentenceBg);

    return sentenceBg;
  }

  private addScreenPicToBoard(board: MySprite) {
    const pic = new MySprite();
    pic.init(this.images.get(this.data.pic_url));

    const scaleX = 564 / pic.width;
    const scaleY = 373 / pic.height;
    const scale = Math.min(scaleX, scaleY);

    pic.setScaleXY(scale);
    pic.x = -0.7;
    pic.y = -138;

    board.addChild(pic);
  }

  private initBg() {
    const pic = new MySprite();
    pic.init(this.images.get('bg'));
    pic.x = this.canvasWidth / 2;
    const scaleX = this.canvasWidth / pic.width;
    const scaleY = this.canvasHeight / pic.height;
    const scale = Math.max(scaleX, scaleY);
    pic.setScaleXY(scale);
    pic.y = this.canvasHeight - pic.height / 2 * scale;
    this.bg = pic;
  }

  private initAudioPlayer() {
    this.curAudio = this.audioObj[this.data.audio_url];
    this.curAudio.onended = () => {
      this.setAudioState(this.curAudio, false);
      this.curAudio.currentTime = 0;
    }

    const audioPlayer = this.createAudioPlayer();
    audioPlayer.setScaleXY(this.mapScale);
    audioPlayer.x = this.canvasWidth - 520 * this.mapScale;
    audioPlayer.y = this.canvasHeight - 630 * this.mapScale;
    this.renderArr.push(audioPlayer);
  }

  private createAudioPlayer() {
    const audioPlayer = new MySprite();

    audioPlayer.addChild(this.createPlayPauseButton());
    const progressBar = this.createProgressBar();
    progressBar.x = 80;
    progressBar.y = 20;
    audioPlayer.addChild(progressBar);

    return audioPlayer;
  }

  private createPlayPauseButton() {
    const button = this.createSprite('btn_play');

    const btnPause = new MySprite();
    btnPause.init(this.images.get('btn_pause'));
    this.hide(btnPause);
    button.addChild(btnPause);

    this.curAudio.playBtn = button;
    this.curAudio.stopBtn = btnPause;

    return button;
  }

  private createSprite(key: string) {
    const sprite = new MySprite();
    sprite.init(this.images.get(key));
    return sprite;
  }

  private hide(element: MySprite) {
    element.alpha = 0;
  }
  private show(element: MySprite) {
    element.alpha = 1;
  }


  private createProgressBar() {
    const container = new MySprite();
    const progressBarBg = this.createSprite('progressbar_bg');
    progressBarBg.anchorX = 0;
    this.progressBarBg = progressBarBg;

    const progressBarPlayed = this.createSprite('progressbar_played');
    progressBarPlayed.anchorX = 0;
    progressBarPlayed.scaleX = 0;
    progressBarBg['bar'] = progressBarPlayed;

    const btn = this.createSprite('btn_current_position')
    btn.y = -3;
    progressBarBg['btn'] = btn;

    const currentTime = this.createTime();
    currentTime.text = formatTime('mm:ss', new Date(this.currentTime * 1000));
    currentTime.x = -10;
    currentTime.y = -40;
    progressBarBg['timeLabel'] = currentTime;

    const totalTime = this.createTime();
    totalTime.text = formatTime('mm:ss', new Date(this.curAudio.duration * 1000));
    totalTime.refreshSize();
    totalTime.x = progressBarBg.width - totalTime.width;
    totalTime.y = currentTime.y;

    container.addChild(progressBarBg);
    container.addChild(progressBarPlayed);
    container.addChild(btn);
    container.addChild(currentTime)
    container.addChild(totalTime)
    return container;
  }

  private createTime() {
    const label = new Label();
    label.fontSize = 28;
    label.fontColor = '#FFFFFF';
    return label;
  }


  private setAudioProgress(target: any, progress: number) {
    target.btn.x = target.width * progress;
    target.bar.scaleX = progress;

    this.currentTime = Math.floor(progress * this.curAudio.duration);
    target.timeLabel.text = formatTime('mm:ss', new Date(this.currentTime * 1000));
  }

  private touchDownProgressBar(target) {
    this.setAudioState(this.curAudio, false);

    const rect = target.getBoundingBox();
    const tmpW = (this.mx - rect.x) / this.mapScale;
    if (tmpW >= 0 && tmpW <= target.width) {
      const progress = tmpW / target.width;
      this.curAudio.currentTime = progress * this.curAudio.duration;
      this.setAudioProgress(target, progress);
    }
  }


  private setAudioState(audio: any, isPlay: boolean) {
    if (isPlay) {
      this.hide(audio.playBtn);
      this.show(audio.stopBtn);
      audio.play();
    } else {
      this.hide(audio.stopBtn);
      this.show(audio.playBtn);
      audio.pause();
    }
  }

  private touchDownAudioBtn(audio) {
    if (audio.paused) {
      audio.play();
      this.setAudioState(audio, true);
    } else {
      audio.pause();
      this.setAudioState(audio, false);
    }
  }

  private updateTime() {
    if (!this.isClickedProgress) {
      const progress = this.curAudio.currentTime / this.curAudio.duration;
      this.setAudioProgress(this.progressBarBg, progress);
    }
  }

  private touchDownSentence(sentence: any) {
    if (this.isShow(sentence.ufoBtnLight)) {
      return;
    }

    this.hide(sentence.ufoBtn);
    this.show(sentence.ufoBtnLight);
    this.refuel();

    this.playAudio('right_mp3');
    this.playAudio('refuel_mp3');

  }

  private refuel() {
    // this.canTouch = false;
    this.showRefuelAnima();
    this.animationId = setTimeout(() => {
      this.showRefuelAnima(this.checkFly.bind(this));
    }, 390);
  }

  private showRefuelAnima(callback = null) {

    const ball = this.createSprite('refuel_ball');
    ball.x = this.rocketPipe.width / 2 - 53;
    ball.y = -this.rocketPipe.height / 2 + 20;
    this.rocketPipe.addChild(ball, 0);

    const time = 1;
    const endX = -this.rocketPipe.width / 2 + 24;
    const endY = 25;

    tweenChange(ball, {x: endX, y: endY}, time);

    tweenChange(ball, {scaleX: 1.5, scaleY: 1.5}, time * 0.6, () => {
      tweenChange(ball, {scaleX: 0.9, scaleY: 0.9}, time * 0.4, () => {
        this.rocketPipe.removeChild(ball);
        if (callback) {
          callback();
        }
      });
    }, TWEEN.Easing.Quintic.Out);
  }

  private isShow(emelent: any) {
    return emelent.alpha > 0;
  }

  private isHide(element: any) {
    return element.alpha === 0;
  }

  private checkFly() {
    this.canTouch = true;

    for(let i = 0; i < this.sentences.length; i++) {
      if (this.isHide(this.sentences[i].ufoBtnLight)) {
        // this.showSmoke();
        return;
      }
    }

    if (this.isFly) {
      return;
    }
    this.isFly = true;

    this.showSmoke();

    this.animationId = setTimeout(() => {
      this.rocketFly();
    }, 100);
  }

  private rocketFly() {

    const flyTime = 2.7 ;
    tweenChange(this.rocket, {x: this.rocket.x, y: -(this.canvasHeight * 1.5 + this.rocket.height) / this.rocketBase.scaleY}, flyTime, () => {
      this.showEndPatal();
    }, TWEEN.Easing.Quintic.In);

    const fire = this.createSprite('rocket_fire');
    fire.y = this.rocket.height / 2 - 30;
    this.rocket.addChild(fire, -1);
    fire.anchorY = 0;
    fire.scaleY = 0;

    tweenChange(fire, {scaleY: 1}, flyTime * 0.8, TWEEN.Easing.Quintic.In);

    const baseX = this.rocket.x;
    const shakeTime = 0.08;
    const shakeOffArr = [
      [8],
      [-8],
      [6],
      [-6],
      [4],
      [-4],
      [2],
      [-2],
      [0],
    ];

    const shakeAnima = (data) => {
      const offX = data[0] / 3;
      tweenChange(this.rocket, {x: baseX + offX}, shakeTime, () => {
        if (shakeOffArr.length > 0) {
          const shakeData = shakeOffArr.shift();
          shakeAnima(shakeData);
        }
      });
    }

    const shakeData = shakeOffArr.shift();
    shakeAnima(shakeData);

    setTimeout(() => {
      this.playAudio('fly_mp3');
    }, 700);
  }

  private initStartView() {
    const startViewBg = new ShapeRect();
    startViewBg.fillColor = '#000000';
    startViewBg.setSize(this.canvasWidth, this.canvasHeight);
    startViewBg.alpha = 0.5;
    this.renderArr.push(startViewBg);

    const startBtn = this.createBtn('btn_start');
    startBtn.x = startViewBg.width / 2;
    startBtn.y = startViewBg.height * 0.4;
    startBtn.setScaleXY(this.mapScale);
    startViewBg.addChild(startBtn);

    const btnLight = this.createSprite('btn_light');
    startBtn.addChild(btnLight, -1);
    btnLight.alpha = 0;
    btnLight.anchorY = 0;

    startBtn.onTouchStart = () => {
      btnLight.alpha = 1;
    };
    startBtn.onClick = () => {
      btnLight.alpha = 0;
      setTimeout(() => {
        this.startView.visible = false;
        // this.playAudio('start_mp3');
      }, 100);

    };
    this.startView = startViewBg;
  }

  private createBtn(url_up: string, url_down: string = null, isDownChange: boolean = true) {
    const btnUp: any = this.createSprite(url_up);
    let btnDown;
    if (url_down) {
      btnDown = this.createSprite(url_down);
      btnUp.addChild(btnDown);
    }
    btnUp.btnDown = btnDown;

    btnUp._onTouchStart = () => {
      if (btnDown) {
        btnDown.alpha = 1;
        btnUp.alpha = 0;
      }
      if (!btnUp.baseScale) {
        btnUp.baseScale = btnUp.scaleX;
      }
      if (isDownChange) {
        btnUp.setScaleXY(btnUp.baseScale * 0.9);
      }
      if (btnUp.onTouchStart) {
        btnUp.onTouchStart();
      }
      btnUp._isDown = true;
    };

    btnUp._onTouchMove = () => {};

    btnUp._onTouchEnd = () => {
      if (btnDown) {
        btnDown.alpha = 0;
      }
      btnUp.alpha = 1;
      btnUp.setScaleXY(btnUp.baseScale);
      if (btnUp.onClick) {
        btnUp.onClick();
      }
      btnUp._isDown = false;
    };

    this.allBtns.push(btnUp);
    return btnUp;
  }

  private showSmoke() {

    const anima = new MyAnimation();
    anima.y = this.rocket.height / 2 - 30;
    this.rocket.addChild(anima, -1);

    for (let i = 1; i < 10; i++) {
      anima.addFrameByImg(this.images.get('smoke_' + i));
    }
    anima.delayPerUnit = 0.1;
    anima.loop = false;

    // anima.playEndFunc = this.rocketFly.bind(this);
    anima.playEndFunc = () => {
      anima.visible = false;
    }
    anima.play();

    this.playAudio('smoke_mp3');
  }








  showEndPatal() {

    console.log('showEndPetal');
    this.petalTime = 0;
    this.showPetalFlag = true;
    this.addPetal();
    this.playAudio('finish_mp3');

    setTimeout(() => {
      this.showPetalFlag = false;
    }, 5000);
  }

  addPetal() {

    if (!this.showPetalFlag) {
      return;
    }

    const petal = this.getPetal();

    this.endPageArr.push(petal);

    moveItem(petal, petal.x, this.canvasHeight + petal.height * petal.scaleY, petal['time'], () => {
      removeItemFromArr(this.endPageArr, petal);
    });

    rotateItem(petal, petal['tr'], petal['time']);

    setTimeout(() => {
      this.addPetal();
    }, 0 + this.petalTime);

    this.petalTime +=  5;
  }


  getPetal() {

    const petal = new MySprite();

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

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

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

    const randomX = Math.random() * this.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;
  }

}
