/// <summary> /// Замена конструктора, процедура инициализации компонента /// </summary> /// <param name="parEntGameObject">Родительский игровой объект</param> /// <param name="parLevelStartConfig">Стартовая конфигурация игрового уровня</param> public PocketGameViewProvider Init(GameObject parEntGameObject, LevelStartConfig parLevelStartConfig, Player parPlayerData) { base.Init(parEntGameObject, false, true); _levelConfig = parLevelStartConfig; Field = parLevelStartConfig.LevelGameField; BallsPocketed = new List <BallModelData>(); BallsInGame = new List <BallModelData>(); foreach (var ball in parLevelStartConfig.LevelBalls) { BallsInGame.Add(new BallModelData(ball.BallType) { Center = ball.StartCenterPosition }); } PlayerWhiteBall = new BallModelData(parLevelStartConfig.PlayerWhiteBall.BallType) { Center = parLevelStartConfig.PlayerWhiteBall.StartCenterPosition }; BallsInGame.Add(PlayerWhiteBall); ActualPlayer = parPlayerData; PlayerCurrentAimingAngle = START_PLAYER_ANGLE; PlayerChosenShotForce = POWER_MIN; CurrentGameState = EPocketGameState.Init; _playersInputManager = parEntGameObject.LinkedAppModel.GetPlayersManager(); EndLevelResult = ELevelEndResult.None; GameReady = true; return(this); }
/// <summary> /// Сигнал фиксированного обновления модели (используется преимущественно для обработки физики и ввода) /// </summary> /// <param name="parFixedDeltaTime">Время шага фиксированного обновления в секундах</param> public override void FixedUpdate(double parFixedDeltaTime) { base.FixedUpdate(parFixedDeltaTime); switch (CurrentGameState) { case EPocketGameState.Init: { break; } case EPocketGameState.Aiming: { _forceBackwardsDirection = false; double currentAimChangeSpeed = _playersInputManager.IsButtonHolding(ActualPlayer.PlayerInput, EGameActionButton.Button_Bumper_Shift) ? CHANGE_AIM_ANGLE_SPEED_PRECISE : CHANGE_AIM_ANGLE_SPEED_DEFAULT; //вверх, влево, вниз, вправо для изменения угла удара if (_playersInputManager.IsButtonHolding(ActualPlayer.PlayerInput, EGameActionButton.Dpad_Menu_Up)) { //наверх if (Math.Abs(PlayerCurrentAimingAngle - AIM_ANGLE_UP) < COMPARISON_TOLERANCE) { // готово } else if (PlayerCurrentAimingAngle > AIM_ANGLE_UP && PlayerCurrentAimingAngle <= AIM_ANGLE_BOTTOM) { PlayerCurrentAimingAngle -= parFixedDeltaTime * currentAimChangeSpeed; if (PlayerCurrentAimingAngle < AIM_ANGLE_UP) { PlayerCurrentAimingAngle = AIM_ANGLE_UP; } } else if (PlayerCurrentAimingAngle < AIM_ANGLE_UP) { PlayerCurrentAimingAngle += parFixedDeltaTime * currentAimChangeSpeed; if (PlayerCurrentAimingAngle > AIM_ANGLE_UP) { PlayerCurrentAimingAngle = AIM_ANGLE_UP; } } else if (PlayerCurrentAimingAngle > AIM_ANGLE_BOTTOM && PlayerCurrentAimingAngle <= AIM_ANGLE_CONVERTION_THRESHOLD) { PlayerCurrentAimingAngle = PlayerCurrentAimingAngle + parFixedDeltaTime * currentAimChangeSpeed; } } else if (_playersInputManager.IsButtonHolding(ActualPlayer.PlayerInput, EGameActionButton.Dpad_Menu_Left)) { //налево if (Math.Abs(PlayerCurrentAimingAngle - AIM_ANGLE_LEFT) < COMPARISON_TOLERANCE) { //готово } else if (PlayerCurrentAimingAngle < AIM_ANGLE_LEFT) { PlayerCurrentAimingAngle += parFixedDeltaTime * currentAimChangeSpeed; if (PlayerCurrentAimingAngle > AIM_ANGLE_LEFT) { PlayerCurrentAimingAngle = AIM_ANGLE_LEFT; } } else if (PlayerCurrentAimingAngle > AIM_ANGLE_LEFT) { PlayerCurrentAimingAngle -= parFixedDeltaTime * currentAimChangeSpeed; if (PlayerCurrentAimingAngle < AIM_ANGLE_LEFT) { PlayerCurrentAimingAngle = AIM_ANGLE_LEFT; } } } else if (_playersInputManager.IsButtonHolding(ActualPlayer.PlayerInput, EGameActionButton.Dpad_Menu_Down)) { //вниз if (Math.Abs(PlayerCurrentAimingAngle - AIM_ANGLE_BOTTOM) < COMPARISON_TOLERANCE) { //готово } else if (PlayerCurrentAimingAngle < AIM_ANGLE_BOTTOM && PlayerCurrentAimingAngle >= AIM_ANGLE_UP) { PlayerCurrentAimingAngle += parFixedDeltaTime * currentAimChangeSpeed; if (PlayerCurrentAimingAngle > AIM_ANGLE_BOTTOM) { PlayerCurrentAimingAngle = AIM_ANGLE_BOTTOM; } } else if (PlayerCurrentAimingAngle > AIM_ANGLE_BOTTOM && PlayerCurrentAimingAngle < AIM_ANGLE_CONVERTION_THRESHOLD) { PlayerCurrentAimingAngle -= parFixedDeltaTime * currentAimChangeSpeed; if (PlayerCurrentAimingAngle < AIM_ANGLE_BOTTOM) { PlayerCurrentAimingAngle = AIM_ANGLE_BOTTOM; } } else if (PlayerCurrentAimingAngle < AIM_ANGLE_UP) { PlayerCurrentAimingAngle -= parFixedDeltaTime * currentAimChangeSpeed; } } else if (_playersInputManager.IsButtonHolding(ActualPlayer.PlayerInput, EGameActionButton.Dpad_Menu_Right)) { //вправо if (Math.Abs(PlayerCurrentAimingAngle - AIM_ANGLE_RIGHT) < COMPARISON_TOLERANCE) { //готово } else if (PlayerCurrentAimingAngle <= AIM_ANGLE_LEFT) { PlayerCurrentAimingAngle -= parFixedDeltaTime * currentAimChangeSpeed; if (PlayerCurrentAimingAngle >= AIM_ANGLE_BOTTOM) { PlayerCurrentAimingAngle = AIM_ANGLE_RIGHT; } } else if (PlayerCurrentAimingAngle > AIM_ANGLE_LEFT) { PlayerCurrentAimingAngle += parFixedDeltaTime * currentAimChangeSpeed; if (_playerCurrentAimingAngle <= AIM_ANGLE_UP) { PlayerCurrentAimingAngle = AIM_ANGLE_RIGHT; } } } else if (_playersInputManager.IsActionButtonPressed(ActualPlayer.PlayerInput)) { PlayerChosenShotForce = POWER_MIN; //теперь начинаем выбирать силу удара CurrentGameState = EPocketGameState.ChooseShotPower; } break; } case EPocketGameState.ChooseShotPower: { if (!_forceBackwardsDirection) { if (PlayerChosenShotForce < POWER_MAX) { PlayerChosenShotForce += parFixedDeltaTime * POWER_CHANGE_SPEED; if (PlayerChosenShotForce > POWER_MAX) { PlayerChosenShotForce = POWER_MAX; _forceBackwardsDirection = !_forceBackwardsDirection; } } } else { PlayerChosenShotForce -= parFixedDeltaTime * POWER_CHANGE_SPEED; if (PlayerChosenShotForce < POWER_MIN) { PlayerChosenShotForce = POWER_MIN; _forceBackwardsDirection = !_forceBackwardsDirection; } } if (_playersInputManager.IsActionButtonPressed(ActualPlayer.PlayerInput)) { //совершаем удар PlayerWhiteBall.Speed = PlayerChosenShotForce; PlayerWhiteBall.Velocity = Angle.RadiansToVector(Angle.DegreesToRadians(GetAngleApproximated())); _flagAtLeastOneBallIsPocketed = false; ParentGameObject.LinkedAppModel.GetSoundManager().PlaySfx(EAppSfxAssets.BallShotByCue, false); CurrentGameState = EPocketGameState.BallsMovingInProgress; } break; } case EPocketGameState.BallsMovingInProgress: { //подождем пока все завершат свое движение if (!UpdateGameField(parFixedDeltaTime)) { //посмотрим, вдруг мы уже выиграли или проиграли if (!_flagAtLeastOneBallIsPocketed) { //уменьшим счетчик жизней ActualPlayer.LifeCount--; } if (ActualPlayer.LifeCount <= 0) { //мы проиграли... EndLevelResult = ELevelEndResult.Lose; Console.WriteLine("Player lost!"); } if (BallsInGame.Count == 1) { if (BallsInGame.First() == PlayerWhiteBall) { //мы выиграли! EndLevelResult = ELevelEndResult.Win; Console.WriteLine("Player completed the level!"); } else { throw new ApplicationException("Game Session state machine is broken!"); } } if (EndLevelResult != ELevelEndResult.None) { CurrentGameState = EPocketGameState.LevelEnd; } else { CurrentGameState = EPocketGameState.Aiming; } GC.Collect(); } break; } case EPocketGameState.Paused: { break; } case EPocketGameState.LevelEnd: { GameLevelEnd?.Invoke(); CurrentGameState = EPocketGameState.Init; break; } default: throw new ArgumentOutOfRangeException(); } if (CurrentGameState != EPocketGameState.Init) { ViewUpdateSignal(parFixedDeltaTime); } }
/// <summary> /// Начать игру на уровне /// </summary> public void StartGameLevel() { Console.WriteLine("Game level started"); CurrentGameState = EPocketGameState.Aiming; ParentGameObject.LinkedAppModel.GetSoundManager().PlayBgMusic(_levelConfig.LevelBackgroundMusic, true); }