text: import {
    computeCameraInitalPosition,
    resetPropCounter
  } from './utils'
  import Stage from './Stage'
  import PropCreator from './PropCreator'
  import Prop from './Prop'
  import LittleMan from './LittleMan'
  
  class JumpGameWorld {
    constructor ({
      container,
      canvas,
      needDefaultCreator = true,
      axesHelper = false
    }) {
      const { offsetWidth, offsetHeight } = container
      this.G = 9.8
      this.container = container
      this.canvas = canvas
      this.width = offsetWidth
      this.height = offsetHeight
      this.needDefaultCreator = needDefaultCreator
      this.axesHelper = axesHelper
  
      const [min, max] = [~~(offsetWidth / 6), ~~(offsetWidth / 3.5)]
      this.propSizeRange = [min, max]
      this.propHeight = ~~(max / 2)
      this.propDistanceRange = [~~(min / 2), max * 2]
  
      this.stage = null
      this.propCreator = null
      this.littleMans = []
      this.props = []
  
      this.init()
    }
  
    init () {
      this.initStage()
      this.initPropCreator()
      this.computeSafeClearLength()
      // 第一个道具
      this.createProp(0)
      // 第二个道具
      this.createProp(0)
      // 首次调整相机
      this.moveCamera(0)
      this.initLittleMan()
  
      // 测试
      // const autoMove = () => {
      //   setTimeout(() => {
      //     autoMove()
      //     this.createProp()
      //     this.moveCamera()
      //   }, 2000)
      // }
      // autoMove()
    }
  
    // 游戏销毁
    destroy () {
      this.clear()
    }
  
    // 让游戏回到初始状态
    clear () {
      this.stage && this.stage.reset()
      
      this.props.forEach(prop => prop.destroy())
      this.props = []
      resetPropCounter()
  
      this.littleMans.forEach(littleMan => littleMan.destroy())
      this.littleMans = []
    }
  
    // 初始化舞台
    initStage () {
      const { canvas, axesHelper, width, height } = this
      const cameraNear = 0.1
      const cameraFar = 2000
      // 计算相机应该放在哪里
      const cameraInitalPosition = this.cameraInitalPosition = computeCameraInitalPosition(35, 225, height / 2, height / 2, cameraNear, cameraFar)
      const lightInitalPosition = this.lightInitalPosition = { x: -300, y: 600, z: 200 }
  
      this.stage = new Stage({
        width,
        height,
        canvas,
        axesHelper,
        cameraNear,
        cameraFar,
        cameraInitalPosition,
        lightInitalPosition
      })
    }
  
    // 初始化道具生成器
    initPropCreator () {
      const { needDefaultCreator, propSizeRange, propHeight } = this
  
      // 管理所有道具
      this.propCreator = new PropCreator({
        propHeight,
        propSizeRange,
        needDefaultCreator
      })
    }
  
    // 对外的新增生成器的接口
    createPropCreator (...args) {
      this.propCreator.createPropCreator(...args)
    }
  
    // 初始化小人
    initLittleMan () {
      const { stage, propHeight, G, props } = this
      const littleMan = new LittleMan({
        world: this,
        color: 0x386899,
        G
      })
      littleMan.enterStage(stage, { x: 0, y: propHeight + 80, z: 0 }, props[0])
      littleMan.jump()
  
      this.littleMans.push(littleMan)
    }
  
    // 创建盒子
    createProp (enterHeight = 100, index = -1) {
      const {
        propCreator,
        propHeight,
        propSizeRange: [min, max],
        propDistanceRange,
        stage, props,
        props: { length }
      } = this
      const currentProp = props[length - 1]
      const prop = new Prop({
        world: this,
        stage,
        // 头2个盒子用第一个创造器生成
        body: propCreator.createProp(index === -1 ? length < 3 ? 0 : index : index),
        height: propHeight,
        prev: currentProp,
        enterHeight,
        distanceRange: propDistanceRange
      })
      const size = prop.getSize()
  
      if (size.y !== propHeight) {
        console.warn(`高度: ${size.y},盒子高度必须为 ${propHeight}`)
      }
      if (size.x < min || size.x > max) {
        console.warn(`宽度: ${size.x}, 盒子宽度必须为 ${min} - ${max}`)
      }
      if (size.z < min || size.z > max) {
        console.warn(`深度: ${size.z}, 盒子深度度必须为 ${min} - ${max}`)
      }
  
      if (currentProp) {
        currentProp.setNext(prop)
      }
  
      prop.enterStage()
      props.push(prop)
  
      return prop
    }
  
    // 移动相机，总是看向最后2个盒子的中间位置
    moveCamera (duration = 500) {
      const {
        stage,
        height,
        cameraInitalPosition: { x: cameraX, y: cameraY, z: cameraZ },
        lightInitalPosition: { x: lightX, y: lightY, z: lightZ }
      } = this
      // 将可视区向上偏移一点，这样看起来道具的位置更合理
      const cameraOffsetY = height / 10
  
      const { x, y, z } = this.getLastTwoCenterPosition()
      const cameraTo = {
        x: x + cameraX + cameraOffsetY,
        y: cameraY, // 高度是不变的
        z: z + cameraZ + cameraOffsetY
      }
      const lightTo = {
        x: x + lightX,
        y: lightY,
        z: z + lightZ
      }
  
      // 移动舞台相机
      const options = {
        cameraTo,
        lightTo,
        center: { x, y, z }
      }
      stage.moveCamera(
        options,
        () => {
          this.clearProps()
        },
        duration
      )
    }
  
    // 计算最新的2个盒子的中心点
    getLastTwoCenterPosition () {
      const { props, props: { length } } = this
      const { x: x1, z: z1 } = props[length - 2].getPosition()
      const { x: x2, z: z2 } = props[length - 1].getPosition()
  
      return {
        x: x1 + (x2 - x1) / 2,
        z: z1 + (z2 - z1) / 2
      }
    }
  
    // 销毁道具
    clearProps () {
      const {
        safeClearLength,
        props,
        props: { length }
      } = this
      const point = 4
  
      if (length > safeClearLength) {
        props.slice(0, point).forEach(prop => prop.destroy())
        this.props = props.slice(point)
      }
    }
  
    // 估算销毁安全值
    computeSafeClearLength () {
      const { width, height, propSizeRange } = this
      const minS = propSizeRange[0]
      const hypotenuse = Math.sqrt(minS * minS + minS * minS)
      this.safeClearLength = Math.ceil(width / minS) + Math.ceil(height / hypotenuse / 2) + 1
    }
  }
  
  export default JumpGameWorld