public void MakeTurn() { if (_playerBalls == null) { _makeTurnAfterLoading = true; return; } int[] playerIds = Enumerable.Range(0, _gameLogic.NumberOfPlayers).ToArray(); // shuffling players for (int i = 0; i < _gameLogic.NumberOfPlayers; i++) { int tmp = playerIds[i]; int j = Random.Range(i, _gameLogic.NumberOfPlayers); playerIds[i] = playerIds[j]; playerIds[j] = tmp; } HitInfo bestHit = new HitInfo(this, _playerId, 0, 0); for (int playerIndex = 0; playerIndex < _gameLogic.NumberOfPlayers; ++playerIndex) { int playerId = playerIds[playerIndex]; var ballPosition = _gameLogic.PlayerBalls[playerId].transform.position; var targetPosition = _gameLogic.PlayerBalls[playerId].GoalHint; float goalDirection = ballPosition.xz().LookAt(targetPosition.xz()) - (playerId == _playerId ? 0 : 180); float minDirectionDelta = playerId == _playerId ? MinAngle : 0; float maxDirectionDelta = playerId == _playerId ? MaxAngle : 0; for (float angle = goalDirection + minDirectionDelta; angle <= goalDirection + maxDirectionDelta; angle += AngleStep) { HitInfo bestForceHit = new HitInfo(this, playerId, angle, MinForce); for (float force = MinForce; force <= MaxForce; force += LinearSearchStep) { HitInfo newForceHit = new HitInfo(this, playerId, angle, force); if (newForceHit.CompareTo(bestForceHit) < 0 && Random.value < 0.9) { bestForceHit = newForceHit; } } float forceL = Math.Max(MinForce, bestForceHit.HitForce - LinearSearchStep); float forceR = Math.Min(MaxForce, bestForceHit.HitForce + LinearSearchStep); for (int step = 0; step < BinarySearchSteps; ++step) { float forceMl = (forceL * 2 + forceR) / 3; HitInfo hitMl = new HitInfo(this, playerId, angle, forceMl); float forceMr = (forceL + 2 * forceR) / 3; HitInfo hitMr = new HitInfo(this, playerId, angle, forceMr); int comparisonResult = hitMl.CompareTo(hitMr) * (playerId == _playerId ? -1 : 1); if (comparisonResult <= 0) { forceL = forceMl; } if (comparisonResult >= 0) { forceR = forceMr; } } HitInfo newHit = new HitInfo(this, playerId, angle, (forceL + forceR) / 2); if (newHit.CompareTo(bestHit) < 0 && (playerId == _playerId || Random.value < 0.9)) { bestHit = newHit; } } } _gameLogic.HitBall(bestHit.PlayerId, bestHit.HitAngle, bestHit.HitForce); }