@Override
  protected void onStart() {
    super.onStart();

    em = new EntityManager();
    MetaEntity.defaultEntityManager = em;
    Game game = new Game(em);

    /** create the surface + thread */
    SurfaceViewThePit surfaceView = new SurfaceViewThePit(this, game);
    RenderSystemSimpleDrawable renderSystem = new RenderSystemSimpleDrawable(em, surfaceView, game);
    MainRunThread runGameThread = new MainRunThread(this, em, surfaceView, renderSystem);
    runGameThread.loadAllCoreSubSystems();

    // runGameThread.setGameResult( gameToStart );
    SubsystemTouchHandler systemTh = new SubsystemTouchHandler(em);
    runGameThread.orderedSubSystems.addLast(systemTh); // MUST be before the Collision Subsystem
    TouchListenerPlayerMovement thv = new TouchListenerPlayerMovement(systemTh);

    SubsystemGhosts systemGhosts = new SubsystemGhosts(em, game);
    runGameThread.orderedSubSystems.addLast(systemGhosts);

    SubsystemMovementAndCollision systemCollision =
        new SubsystemMovementAndCollision(em, renderSystem);
    runGameThread.orderedSubSystems.addLast(systemCollision);

    SubsystemLighting systemLighting = new SubsystemLighting(em, game);
    runGameThread.orderedSubSystems.addLast(systemLighting);

    SubsystemTriggers systemTriggers = new SubsystemTriggers(this, em, game);
    runGameThread.orderedSubSystems.addLast(systemTriggers);

    surfaceView.setOnTouchListener(thv);
    surfaceView.thread = runGameThread;
    Log.i(getClass().getSimpleName(), "initialized thread and surface");

    /**
     * Finally ... tell the game that the ES is now valid, it's ship reference is OK, and it can do
     * game-setup
     */
    game.preSetupGame();
    renderSystem.shiftCanvasToKeepPositionOnScreen(
        new CPosition(
            game.initialPlayerLocation.x,
            game.initialPlayerLocation.y,
            game.mazeCellWidth,
            game.mazeCellHeight));

    // turn off the window's title bar
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow()
        .setFlags(
            WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

    setContentView(surfaceView);
  }
  public void run() {
    Log.i(getClass().getSimpleName(), "Starting thread (run method started)");

    boolean gameOverTriggered = false;
    long currentFrameIndex = 0;
    long currentFrameTimesAccumulated = 0;
    long lastLoopStartTime = System.currentTimeMillis();
    // Debug.startMethodTracing( "escapePitTrace" );

    // gameResult.status = GameResultStatus.RUNNING;

    loadFirstLevel();

    if (orderedSubSystems == null)
      throw new IllegalStateException(
          "Cannot start a MainRunThread until you've loaded all SubSystems; try calling loadAllCoreSubSystems() first");

    /**
     * ********************************************************************* START OF MAIN BODY OF
     * RUN LOOP **********************************************************************
     */
    while (myThread != null) {
      long loopStartTime = System.currentTimeMillis();
      long lastFrameTime = loopStartTime - lastLoopStartTime;
      currentFrameTimesAccumulated += lastFrameTime;

      Canvas c = surfaceView.getHolder().lockCanvas(null);
      try {
        /**
         * Critical: lots of things in rendering depend on the size / shape of the Canvas; => we
         * must make sure the renderingSystem has the latest, current, correct Canvas before we do
         * anything else
         */
        renderingSystem.canvas = c;

        for (SubSystem system : orderedSubSystems) {
          system.processOneGameTick(lastFrameTime);
        }

        synchronized (surfaceView.getHolder()) {
          renderingSystem.drawBackground();
          renderingSystem.processOneGameTick(lastFrameTime);
        }

        Thread.sleep(5);
      } catch (GameOverError goe) {
        Log.i(getClass().getSimpleName(), "GameOver; killing thread");

        myThread = null;

        Log.i(getClass().getSimpleName(), "GameOver; locking Entity System");
        es.freeze();

        gameOverTriggered = true;
      } catch (Throwable t) {
        Log.e(
            getClass().getSimpleName(),
            "Inside main draw loop, a major exception, killing draw thread:" + t);
        t.printStackTrace();
        myThread = null;
      } finally {
        // ANDROID EXAMPLE CODE COMMENT:
        // do this in a finally so that if an exception is thrown
        // during the above, we don't leave the Surface in an
        // inconsistent state
        if (c != null) {
          surfaceView.getHolder().unlockCanvasAndPost(c);
        }

        currentFrameIndex++;
        lastLoopStartTime = loopStartTime;
        int frameTimesPerSample = 25;
        if (currentFrameIndex % frameTimesPerSample == 0) {
          // DEBUG: Log.i( getClass().getSimpleName(), "Averaged frame rate = " +
          // frameTimesPerSample * 1000 / currentFrameTimesAccumulated + " fps" );
          currentFrameTimesAccumulated = 0;
        }
      }
    }
    // Debug.stopMethodTracing();

    if (gameOverTriggered) {
      /**
       * Another bad design decision from the Android authors? This is not a great way to manage
       * inter-Activity communication (is there a better way?)
       */
      Intent i = parentActivity.getIntent();
      parentActivity.setResult(Activity.RESULT_OK, i);
      parentActivity.finish();
    }

    Log.i(
        getClass().getSimpleName(),
        "Thread-stop COMPLETE: (run method expired; mythread was set to null)");
  }