/// <summary> /// Обнаружение столкновения с коллайдером лузы /// </summary> /// <param name="parBall">Шар</param> /// <param name="parPocket">Луза</param> /// <returns>True если есть столкновение</returns> private bool IsPocketCollision(BallModelData parBall, Pocket parPocket) { SpVector3 ballDistanceVector = parPocket.Center - parBall.Center; double centersDistance = ballDistanceVector.Length(); return(centersDistance <= parBall.Radius + parPocket.Radius); }
/// <summary> /// Обработка столкновения двух шаров /// </summary> /// <param name="parBall1">Шар 1</param> /// <param name="parBall2">Шар 2</param> /// <returns>True, если столкновение имело место быть</returns> private bool CheckCollisionsWithBalls(BallModelData parBall1, BallModelData parBall2) { if (DetectCollision(parBall1, parBall2)) { SpVector3 tmpVelocity = ChangeVelocities(parBall1, parBall2); parBall2.Velocity = ChangeVelocities(parBall2, parBall1); parBall1.Velocity = tmpVelocity; double tmpBallSpeed = Math.Max(parBall2.Speed * 0.8, parBall1.Speed * 0.8); double intersectionRadius = -(parBall2.Center - parBall1.Center).Length() + parBall2.Radius + parBall1.Radius; if (intersectionRadius <= 0) { intersectionRadius = 1; } double posModifier = intersectionRadius / 2; parBall1.Center = parBall1.Center + (parBall1.Center - parBall2.Center).Normalize() * (posModifier + 1); parBall2.Center = parBall2.Center + (parBall2.Center - parBall1.Center).Normalize() * (posModifier + 1); parBall1.Speed = tmpBallSpeed; parBall2.Speed = tmpBallSpeed; return(true); } return(false); }
/// <summary> /// Обнаружение столкновения между шарами /// </summary> /// <param name="parBall1">Шар первый</param> /// <param name="parBall2">Шар второй</param> /// <returns>True если есть столкновение</returns> private bool DetectCollision(BallModelData parBall1, BallModelData parBall2) { SpVector3 ballsDistanceVector = parBall2.Center - parBall1.Center; double centersDistance = ballsDistanceVector.Length(); return(centersDistance <= parBall1.Radius + parBall2.Radius); }
/// <summary> /// Вспомогательный метод для изменения векторов скоростей столкнувшихся шаров /// </summary> /// <param name="parBall1">Шар 1</param> /// <param name="parBall2">Шар 2</param> /// <returns>Новый вектор скорости для Шара 1</returns> private SpVector3 ChangeVelocities(BallModelData parBall1, BallModelData parBall2) { SpVector3 centersVector = parBall2.Center - parBall1.Center; SpVector3 ballOnePerpendicular = centersVector.PerpendicularComponent(parBall1.Velocity); SpVector3 ballTwoPerpendicular = centersVector.PerpendicularComponent(parBall2.Velocity); SpVector3 ballTwoParallel = centersVector.ParralelComponent(parBall2.Velocity); SpVector3 newBall1Velocity = ballTwoParallel + ballOnePerpendicular; return(newBall1Velocity); }
/// <summary> /// Проверка, не попал ли шар в лузу /// </summary> /// <param name="parBall">Проверяемый шар</param> /// <returns></returns> private bool CheckIfIsPocketed(BallModelData parBall) { foreach (var fieldPocket in Field.Pockets) { if (IsPocketCollision(parBall, fieldPocket)) { return(true); } } return(false); }
/// <summary> /// Запуск проверки всех столкновений на всем столе /// </summary> private void CheckCollisions() { for (int i = 0; i < BallsInGame.Count; i++) { BallModelData currentBall = BallsInGame[i]; if (CheckCollisionsWithBorders(currentBall)) { ParentGameObject.LinkedAppModel.GetSoundManager() .PlaySfx(EAppSfxAssets.BallCollisionWallSolid, false); } for (int j = i + 1; j < BallsInGame.Count; j++) { if (CheckCollisionsWithBalls(currentBall, BallsInGame[j])) { ParentGameObject.LinkedAppModel.GetSoundManager().PlaySfx(EAppSfxAssets.BallCollision, false); } } if (CheckIfIsPocketed(currentBall)) { ParentGameObject.LinkedAppModel.GetSoundManager().PlaySfx(EAppSfxAssets.BallPocketed, false); if (currentBall != PlayerWhiteBall) { BallsPocketed.Add(currentBall); BallsInGame.Remove(currentBall); _flagAtLeastOneBallIsPocketed = true; ActualPlayer.Score += 100; i--; } else { currentBall.ResetMovement(); currentBall.Center = _levelConfig.PlayerWhiteBall.StartCenterPosition; ActualPlayer.Score -= 200; ActualPlayer.LifeCount -= 2; } } } }
/// <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="parBall">Шар</param> /// <param name="parFixedDeltaTime">Время шага фиксированного обновления в секундах</param> internal void MoveBall(BallModelData parBall, double parFixedDeltaTime) { parBall.Center.X += parBall.Velocity.X * parBall.Speed * parFixedDeltaTime; parBall.Center.Y += parBall.Velocity.Y * parBall.Speed * parFixedDeltaTime; double modifierDecreasor = 0.3 * parFixedDeltaTime; double modifierActual = 1.00 - modifierDecreasor; parBall.Velocity.X = parBall.Velocity.X * modifierActual; parBall.Velocity.Y = parBall.Velocity.Y * modifierActual; parBall.Speed = parBall.Speed * modifierActual; if (Math.Abs(parBall.Velocity.X) < 0.1 && Math.Abs(parBall.Velocity.Y) < 0.1) { parBall.Velocity.X = 0; parBall.Velocity.Y = 0; parBall.Speed = 0; // ball.IsMoving = false; } }
/// <summary> /// Проверка столкновения с бортом /// </summary> /// <param name="parBall">Шар</param> /// <returns></returns> private bool CheckCollisionsWithBorders(BallModelData parBall) { foreach (var fieldCollisionLine in Field.CollisionLines) { if (fieldCollisionLine.CheckCollisionFunc(parBall)) { //столкновение произошло SpVector3 ballVelocity = parBall.Velocity; parBall.Velocity = 2 * ballVelocity + 2 * fieldCollisionLine.Normal * (-ballVelocity.DotProduct(fieldCollisionLine.Normal)) - ballVelocity; do { parBall.Center = parBall.Center + (fieldCollisionLine.Normal); } while (fieldCollisionLine.CheckCollisionFunc(parBall)); return(true); } } return(false); }