function main() {
  //-------------------------------------------------------------------------
  // 6. THE GAME LOOP
  //-------------------------------------------------------------------------

  var counter = 0,
    dt = 0,
    now,
    last = timestamp(),
    fpsmeter = new FPSMeter({
      decimals: 0,
      graph: true,
      theme: 'dark',
      left: '5px',
    })

  function frame() {
    fpsmeter.tickStart()
    now = timestamp()
    dt = dt + Math.min(1, (now - last) / 1000)
    while (dt > step) {
      dt = dt - step

      // * Update wird pausiert bei Toggle 'p'.
      if (!paused) {
        update(step)
      }
    }

    render(ctx, counter, dt, currentLevel)

    last = now
    counter++
    fpsmeter.tick()
    requestAnimationFrame(frame, canvas)
  }

  document.addEventListener(
    'keydown',
    function (ev) {
      return onkey(ev, ev.key, true)
    },
    false
  )
  document.addEventListener(
    'keyup',
    function (ev) {
      return onkey(ev, ev.key, false)
    },
    false
  )

  // * EventListener für Pause-Taste
  window.addEventListener('keydown', function (e) {
    var key = e.key
    if (key === 'p') {
      // p key
      togglePause()
    }
  })
  // * EventListener für DevInfos Toggle
  window.addEventListener('keydown', function (e) {
    var key = e.key
    if (key === 'o') {
      // p key
      toggleDevInfos()
    }
  })

  // * Touch Controls

  function touchControl(ev, button, down) {
    switch (button) {
      case 'jump':
        player.jump = down
        ev.preventDefault()
        return false
      case 'shoot':
        shoot(player)
        ev.preventDefault()
        return false
      case 'left':
        player.left = down
        ev.preventDefault()
        return false
      case 'right':
        player.right = down
        ev.preventDefault()
        return false
      case 'up':
        player.up = down
        ev.preventDefault()
        return false
      case 'down':
        player.down = down
        ev.preventDefault()
        return false
    }
  }

  const buttonA = document.getElementById('button-a')
  const buttonB = document.getElementById('button-b')
  const dpadLeft = document.getElementById('dpad-left')
  const dpadRight = document.getElementById('dpad-right')
  const dpadUp = document.getElementById('dpad-up')
  const dpadDown = document.getElementById('dpad-down')

  buttonA.addEventListener(
    'touchstart',
    function (ev) {
      return touchControl(ev, 'jump', true)
    },
    false
  )
  buttonA.addEventListener(
    'touchend',
    function (ev) {
      return touchControl(ev, 'jump', false)
    },
    false
  )
  buttonB.addEventListener(
    'touchstart',
    function (ev) {
      return touchControl(ev, 'shoot', true)
    },
    false
  )
  buttonB.addEventListener(
    'touchend',
    function (ev) {
      return touchControl(ev, 'shoot', false)
    },
    false
  )
  dpadLeft.addEventListener(
    'touchstart',
    function (ev) {
      return touchControl(ev, 'left', true)
    },
    false
  )
  dpadLeft.addEventListener(
    'touchend',
    function (ev) {
      return touchControl(ev, 'left', false)
    },
    false
  )
  dpadRight.addEventListener(
    'touchstart',
    function (ev) {
      return touchControl(ev, 'right', true)
    },
    false
  )
  dpadRight.addEventListener(
    'touchend',
    function (ev) {
      return touchControl(ev, 'right', false)
    },
    false
  )
  dpadUp.addEventListener(
    'touchstart',
    function (ev) {
      return touchControl(ev, 'up', true)
    },
    false
  )
  dpadUp.addEventListener(
    'touchend',
    function (ev) {
      return touchControl(ev, 'up', false)
    },
    false
  )
  dpadDown.addEventListener(
    'touchstart',
    function (ev) {
      return touchControl(ev, 'down', true)
    },
    false
  )
  dpadDown.addEventListener(
    'touchend',
    function (ev) {
      return touchControl(ev, 'down', false)
    },
    false
  )

  // ! Vielleicht kann ich statt des setup() an dieser Stelle auch eine gameStart() Funktion erstellen, die beim erstmaligen Start alles erledigt. Später wird dann ja immer die _initLevel() aufgerufen.
  setup(currentLevel.levelData) // ! Was brauche ich hier, damit das variabel alle Level laden kann?

  frame()
}

// * window onload function
;(function () {
  //-------------------------------------------------------------------------
  // POLYFILLS
  //-------------------------------------------------------------------------

  if (!window.requestAnimationFrame) {
    // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
    window.requestAnimationFrame =
      window.webkitRequestAnimationFrame ||
      window.mozRequestAnimationFrame ||
      window.oRequestAnimationFrame ||
      window.msRequestAnimationFrame ||
      function (callback, element) {
        window.setTimeout(callback, 1000 / 60)
      }
  }

  main()
})()
