private void SpawnBall() {
    mBall.WorldPosition(new mw2_Vector2());
    int choose = new Random().nextInt(mBallSpawnAngles.length);
    mBallVelocity =
        new mw2_Vector2(
            (float) Math.cos(mBallSpawnAngles[choose] * Math.PI / 180),
            (float) Math.sin(mBallSpawnAngles[choose] * Math.PI / 180));
    mBallVelocity.x *= mBallSpawnDirection;

    if (mBallSpawnDirection == -1) {
      mBall_fill.mColor = mFillColor2;
      mBall_line.mColor = mLineColor2;
    } else {
      mBall_fill.mColor = mFillColor1;
      mBall_line.mColor = mLineColor1;
    }

    mIsBallLost = false;
  }
  @Override
  public void Update(float deltaTime) {
    // player control
    if (mw2_Input.GetKey(mw2_Input.Key.W)) {
      mPaddle1.TranslateWorld(new mw2_Vector2(0, -mPaddleSpeed * deltaTime));
    }
    if (mw2_Input.GetKey(mw2_Input.Key.S)) {
      mPaddle1.TranslateWorld(new mw2_Vector2(0, mPaddleSpeed * deltaTime));
    }
    if (mw2_Input.GetKey(mw2_Input.Key.ARROW_UP)) {
      mPaddle2.TranslateWorld(new mw2_Vector2(0, -mPaddleSpeed * deltaTime));
    }
    if (mw2_Input.GetKey(mw2_Input.Key.ARROW_DOWN)) {
      mPaddle2.TranslateWorld(new mw2_Vector2(0, mPaddleSpeed * deltaTime));
    }

    // clamp paddle position
    mw2_Vector2 p1 = mPaddle1.WorldPosition();
    p1.y = Clamp(p1.y, -mTopDownMargin + mPaddleSize.y / 2, mTopDownMargin - mPaddleSize.y / 2);
    mPaddle1.WorldPosition(p1);

    mw2_Vector2 p2 = mPaddle2.WorldPosition();
    p2.y = Clamp(p2.y, -mTopDownMargin + mPaddleSize.y / 2, mTopDownMargin - mPaddleSize.y / 2);
    mPaddle2.WorldPosition(p2);

    // ball position update
    mBall.TranslateWorld(mBallVelocity.Mul(deltaTime * mBallSpeed));

    // check top-bottom margins
    if (mBall.WorldPosition().y + mBallRadius >= mTopDownMargin) {
      mBallVelocity.y = -Math.abs(mBallVelocity.y);
      mBoundarySound.PlayOnce();
    }
    if (mBall.WorldPosition().y - mBallRadius <= -mTopDownMargin) {
      mBallVelocity.y = Math.abs(mBallVelocity.y);
      mBoundarySound.PlayOnce();
    }

    // check paddle collision
    if (!mIsBallLost
        && mBall.WorldPosition().x - mBallRadius
            <= mPaddle1.WorldPosition().x + mPaddleSize.x / 2) {
      if (mPaddle1.WorldPosition().y + mPaddleSize.y / 2 >= mBall.WorldPosition().y
          && mBall.WorldPosition().y >= mPaddle1.WorldPosition().y - mPaddleSize.y / 2) {
        // ball hits paddle 1
        mBallVelocity.x = Math.abs(mBallVelocity.x);
        mPaddleSound.PlayOnce();
        mBall_fill.mColor = mFillColor1;
        mBall_line.mColor = mLineColor1;
      } else if (mBall.WorldPosition().x < mPaddle1.WorldPosition().x + mPaddleSize.x / 2) {
        mIsBallLost = true;
        mLostSound.PlayOnce();
      }
    }

    if (!mIsBallLost
        && mBall.WorldPosition().x + mBallRadius
            >= mPaddle2.WorldPosition().x - mPaddleSize.x / 2) {
      if (mPaddle2.WorldPosition().y + mPaddleSize.y / 2 >= mBall.WorldPosition().y
          && mBall.WorldPosition().y >= mPaddle2.WorldPosition().y - mPaddleSize.y / 2) {
        // ball hits paddle 2
        mBallVelocity.x = -Math.abs(mBallVelocity.x);
        mPaddleSound.PlayOnce();
        mBall_fill.mColor = mFillColor2;
        mBall_line.mColor = mLineColor2;
      } else if (mBall.WorldPosition().x > mPaddle2.WorldPosition().x - mPaddleSize.x / 2) {
        mIsBallLost = true;
        mLostSound.PlayOnce();
      }
    }

    // check left-right boundaries
    if (mBall.WorldPosition().x + mBallRadius >= mLeftRightMargin) {
      mBallSpawnDirection = -1;
      mScore1 += 1;
      SpawnBall();
    }
    if (mBall.WorldPosition().x - mBallRadius <= -mLeftRightMargin) {
      mBallSpawnDirection = 1;
      mScore2 += 1;
      SpawnBall();
    }

    // update scores
    mScoreText1.mText = this.PrettyScore(mScore1);
    mScoreText2.mText = this.PrettyScore(mScore2);

    // check game over
    if (mScore1 == mWinCondition) {
      mw2_Globals.SetString("winner", "1");
      mw2_Application.LoadScene(new EndScene(), new EndManager());
    }
    if (mScore2 == mWinCondition) {
      mw2_Globals.SetString("winner", "2");
      mw2_Application.LoadScene(new EndScene(), new EndManager());
    }

    // check for R-restart or ESC-exit
    if (mw2_Input.GetKeyOnce(mw2_Input.Key.R)) {
      mw2_Application.LoadScene(new StartScene(), new StartManager());
    }
    if (mw2_Input.GetKeyOnce(mw2_Input.Key.ESC)) {
      mw2_Application.Exit();
    }
  }