showTeleport(action, targetBoardPosition) {
    let showDuration = 0.0;

    const scene = this.getScene();
    const gameLayer = scene && scene.getGameLayer();

    // show teleport if positions are different
    const sourceBoardPosition = UtilsEngine.transformScreenToBoard(this.getPosition());
    if (gameLayer != null && sourceBoardPosition != null && targetBoardPosition != null && this.canChangeState() && !UtilsPosition.getPositionsAreEqual(sourceBoardPosition, targetBoardPosition)) {
      this.stopShowingMove();
      this.stopShowingTeleport();
      this.showBaseState();

      const sourceTileMapPosition = UtilsEngine.transformBoardToTileMap(sourceBoardPosition);
      const targetTileMapPosition = UtilsEngine.transformBoardToTileMap(targetBoardPosition);
      const dx = targetBoardPosition.x - sourceBoardPosition.x;
      const dy = targetBoardPosition.y - sourceBoardPosition.y;
      const distance = Math.sqrt(dx * dx + dy * dy);

      // create fx
      const sourceFX = DATA.dataForIdentifiersWithFilter(action.getFXResource(), SDK.FXType.MoveSourceFX);
      const sourceFXSprites = NodeFactory.createFX(sourceFX, {
        targetBoardPosition: sourceBoardPosition,
        offset: this.centerOffset,
      });
      const sourceFXDelays = UtilsEngine.getDelaysFromFXSprites(sourceFXSprites);
      const targetFX = DATA.dataForIdentifiersWithFilter(action.getFXResource(), SDK.FXType.MoveTargetFX);
      const targetFXSprites = NodeFactory.createFX(targetFX, {
        targetBoardPosition,
        offset: this.centerOffset,
      });
      const targetFXDelays = UtilsEngine.getDelaysFromFXSprites(targetFXSprites);
      const moveFX = DATA.dataForIdentifiersWithFilter(action.getFXResource(), SDK.FXType.MoveFX);
      const moveFXSprites = NodeFactory.createFX(moveFX);

      // travel delays
      const startTravelDuration = 0.2;
      const endTravelDuration = 0.3;
      const travelDuration = distance * 0.05;
      const totalTravelDuration = startTravelDuration + travelDuration + endTravelDuration;

      // set showDuration
      const sourceDelay = sourceFXDelays.showDelay * 0.5;
      const targetDelay = targetFXDelays.showDelay * 0.25;
      showDuration += sourceDelay + totalTravelDuration + targetDelay;

      // set final move position
      this.setMovePosition(targetTileMapPosition);

      // start moving
      this.setIsMoving(true);

      // don't show readiness while moving
      this.removeReadinessVisualTag();

      // emit the start of the move
      gameLayer.getEventBus().trigger(EVENTS.before_show_move, { type: EVENTS.before_show_move, action });

      // setup final method
      const onFinishMove = function () {
        // set new node position
        this.setPosition(targetTileMapPosition);

        // stop moving
        this.setIsMoving(false);

        // restore opacity
        this.setOpacity(255.0);

        // emit the completion of the move
        gameLayer.getEventBus().trigger(EVENTS.after_show_move, { type: EVENTS.after_show_move, action });
      }.bind(this);

      this.whenResourcesReady(this.getCardResourceRequestId()).then((cardResourceRequestId) => {
        if (!this.getAreResourcesValid(cardResourceRequestId)) return; // card has changed
        if (this.canChangeState()) {
          // add source fx at source
          gameLayer.addNodes(sourceFXSprites);

          // run sequence
          const teleportAction = cc.sequence(
            cc.delayTime(sourceDelay),
            cc.callFunc(function () {
              // move moving fx from source to target
              const scene = this.getScene();
              const gameLayer = scene && scene.getGameLayer();
              gameLayer && gameLayer.addNodes(moveFXSprites);
              for (let i = 0, il = moveFXSprites.length; i < il; i++) {
                const moveFXSprite = moveFXSprites[i];
                moveFXSprite.setPosition(sourceTileMapPosition);
                // set lifespan of particles
                if (moveFXSprite instanceof BaseParticleSystem) {
                  moveFXSprite.setLife(totalTravelDuration * 2.0);
                }
                // move fx sprites
                moveFXSprite.runAction(cc.sequence(
                  cc.delayTime(startTravelDuration),
                  cc.moveTo(travelDuration, targetTileMapPosition),
                  cc.delayTime(endTravelDuration),
                  cc.fadeOut(CONFIG.FADE_MEDIUM_DURATION),
                ));
              }
            }, this),
            cc.fadeOut(CONFIG.FADE_FAST_DURATION),
            cc.callFunc(function () {
              onFinishMove();
              this.setOpacity(0.0);
            }, this),
            cc.delayTime(totalTravelDuration - CONFIG.FADE_FAST_DURATION),
            cc.callFunc(function () {
              // add target fx at target
              const scene = this.getScene();
              const gameLayer = scene && scene.getGameLayer();
              gameLayer && gameLayer.addNodes(targetFXSprites);
            }, this),
            cc.delayTime(targetDelay),
            cc.fadeIn(CONFIG.FADE_FAST_DURATION),
            cc.callFunc(function () {
              this._showTeleportAction = null;
            }, this),
          );
          teleportAction.setOnCancelledCallback(onFinishMove);
          this._showTeleportAction = teleportAction;
          this.runAction(teleportAction);
        } else {
          onFinishMove();
        }
      });
    }

    return showDuration;
  }
Shows unit as teleporting from its current position to a target position.
@param {SDK.MoveAction} action
@param {Vec2} targetBoardPosition
@returns {Number} duration of show