public void Colise() { var movements = new MovementSegment[] { new MovementSegment { startPoint = new Vector2(-12.5f, 3f), endPoint = new Vector2(-10.7f, 1.5f) }, new MovementSegment { startPoint = new Vector2(-10.41489f, 1.61148f), endPoint = new Vector2(-9.71394f, 3.34835f) }, new MovementSegment { startPoint = new Vector2(-7.5f, 3.3f), endPoint = new Vector2(-12.43711f, 3.59647f) }, new MovementSegment { startPoint = new Vector2(-11.17787f, 4.60138f), endPoint = new Vector2(-11.12205f, 3.31733f) }, new MovementSegment { startPoint = new Vector2(-10.3f, 3.9f), endPoint = new Vector2(-11.8f, 4.1f) }, }; var normals = new Vector2[] { new Vector2(-1.0f, 0.0f), new Vector2(0.0f, -1.0f), new Vector2(1.0f, 0.0f), new Vector2(0.0f, 1.0f), new Vector2(0.0f, 1.0f) }; var colisePoints = new Vector2[] { new Vector2(-12.0f, 2.6f), new Vector2(-10.3f, 2.0f), new Vector2(-10.0f, 3.5f), new Vector2(-11.2f, 4.0f), new Vector2(-11.3f, 4.0f) }; for (var i = 0; i < movements.Length; i++) { var result = _coliseController.CheckColise(movements[i], 0.0, _block); Assert.IsTrue(result.isColise, $"Fail movement vector: start point: {movements[i].startPoint} end point: {movements[i].endPoint}"); Assert.AreEqual(normals[i], result.normal, $"Uncorrect normal: start point: {movements[i].startPoint} end point: {movements[i].endPoint}"); Assert.AreEqual(colisePoints[i].x, result.colisePoint.x, 0.3, $"Uncorrect x coord colise point: start point: {movements[i].startPoint} end point: {movements[i].endPoint}"); Assert.AreEqual(colisePoints[i].y, result.colisePoint.y, 0.3, $"Uncorrect y coord colise point: start point: {movements[i].startPoint} end point: {movements[i].endPoint}"); } }
public void DontColise() { var movements = new MovementSegment[] { new MovementSegment { startPoint = new Vector2(-10.06561f, 4.32486f), endPoint = new Vector2(-9.1461f, 3.67668f) }, new MovementSegment { startPoint = new Vector2(-11.2275f, 1.79137f), endPoint = new Vector2(-11.31434f, 0.89192f) }, new MovementSegment { startPoint = new Vector2(-12.74106f, 3.38557f), endPoint = new Vector2(-12.4185f, 1.2579f) }, new MovementSegment { startPoint = new Vector2(-12.54256f, 4.52694f), endPoint = new Vector2(-8.78347f, 4.55175f) }, }; foreach (var movement in movements) { var result = _coliseController.CheckColise(movement, 0.0, _block); Assert.IsFalse(result.isColise, $"Fail movement vector: start point: {movement.startPoint} end point: {movement.endPoint}"); } }
/// <summary> /// <see cref="IColiseController.CheckColise(MovementSegment, Block)"/> /// </summary> public ColiseData CheckColise(MovementSegment segment, double radius, Block block, bool isInBlock = false) { var startPoint = segment.startPoint; var endPoint = segment.endPoint; double startX = segment.startPoint.x; double startY = segment.startPoint.y; double endX = segment.startPoint.x; double endY = segment.startPoint.y; double minX = Mathf.Min(startPoint.x, endPoint.x); double minY = Mathf.Min(startPoint.y, endPoint.y); double maxX = Mathf.Max(startPoint.x, endPoint.x); double maxY = Mathf.Max(startPoint.y, endPoint.y); double segmentDeltaY = startPoint.y - endPoint.y; double segmentDeltaX = startPoint.x - endPoint.x; double segmentK = startPoint.x * endPoint.y - endPoint.x * startPoint.y; var l = isInBlock ? -1.0f : 1.0f; var sides = new Side[] { new Side { K = block.TopK, deltaX = block.DeltaTop.x, deltaY = block.DeltaTop.y, normal = new Vector2(0.0f, l) }, new Side { K = block.RightK, deltaX = block.DeltaRight.x, deltaY = block.DeltaRight.y, normal = new Vector2(l, 0.0f) }, new Side { K = block.BottomK, deltaX = block.DeltaBottom.x, deltaY = block.DeltaBottom.y, normal = new Vector2(0.0f, -l) }, new Side { K = block.LeftK, deltaX = block.DeltaLeft.x, deltaY = block.DeltaLeft.y, normal = new Vector2(-l, 0.0f) } }; var result = new ColiseData(); var currSqrDistance = double.MaxValue; foreach (var side in sides) { var d = side.deltaX * segmentDeltaY - side.deltaY * segmentDeltaX; /// Отрезок параллелен прямой. if (d == 0) { continue; } var pointX = (side.K * segmentDeltaX - side.deltaX * segmentK) / d; var pointY = (side.K * segmentDeltaY - side.deltaY * segmentK) / d; double e = radius; if (pointX >= minX - e && pointX <= maxX + e && pointY >= minY - e && pointY <= maxY + e && block.IsOnBounds(pointX, pointY, e)) { var v = (pointX - startX) * (pointX - startX) + (pointY - startY) * (pointY - startY); if (v < currSqrDistance) { currSqrDistance = v; result.sqrDist = v; result.colisePoint = new Vector2((float)pointX, (float)pointY) + side.normal * (float)e * 1.05f; result.normal = side.normal; } } } result.isColise = currSqrDistance != double.MaxValue; return(result); }
/// <summary> /// Обработка перемещения шаров. /// </summary> private void HandleBalls() { var balls = _gameFieldView.Balls; for (var ballId = 0; ballId < balls.Count; ballId++) { var currentPos = balls[ballId].GetCenter(); var movementSegment = new MovementSegment() { startPoint = currentPos, endPoint = currentPos + balls[ballId].LastMoveDir * _gameParams.ballSpeed }; var coliseResult = _coliseController.CheckColise(movementSegment, balls[ballId].GetRadius(), _gameFieldView.FieldBlock, true); if (coliseResult.isColise) { if (coliseResult.normal.y == 1) { balls[ballId].Remove(); balls.RemoveAt(ballId); ballId--; if (balls.Count == 0) { HandleFailEnd(); } } else { var lastDir = _coliseController.CalculateRicochet(balls[ballId].LastMoveDir, coliseResult.normal); balls[ballId].Move(coliseResult.colisePoint - balls[ballId].GetCenter()); balls[ballId].LastMoveDir = lastDir; } continue; } var distance = double.MaxValue; var blocks = _gameFieldView.CurrentLvl.Blocks; var blockIdColise = 0; for (var blockId = _curFirstBlock; blockId < blocks.Length; blockId++) { var coliseInfo = _coliseController.CheckColise(movementSegment, balls[ballId].GetRadius(), blocks[blockId].GetBlockInfo()); if (coliseInfo.isColise) { var newDistance = coliseInfo.sqrDist; if (newDistance < distance) { coliseResult = coliseInfo; blockIdColise = blockId; distance = newDistance; } } } if (coliseResult.isColise) { var lastDir = _coliseController.CalculateRicochet(balls[ballId].LastMoveDir, coliseResult.normal); balls[ballId].Move(coliseResult.colisePoint - balls[ballId].GetCenter()); balls[ballId].LastMoveDir = lastDir; blocks[blockIdColise].Strike(); if (!blocks[blockIdColise].IsLive()) { if (blocks[blockIdColise].IsHasBonus) { _gameFieldView.AddBonus(blocks[blockIdColise].Bonus, blocks[blockIdColise].GetBlockInfo().GetCenter()); } var t = _gameFieldView.CurrentLvl.Blocks[blockIdColise]; _gameFieldView.CurrentLvl.Blocks[blockIdColise] = blocks[_curFirstBlock]; _gameFieldView.CurrentLvl.Blocks[_curFirstBlock] = t; _curFirstBlock++; if (_curFirstBlock == blocks.Length) { HandleSuccessEnd(); } } continue; } var slideBlock = _userSlideView.GetBlock(); coliseResult = _coliseController.CheckColise(movementSegment, balls[ballId].GetRadius(), slideBlock); if (coliseResult.isColise) { if (coliseResult.normal.y == 1) { var ricochet = _coliseController.CalculateRicochet(balls[ballId].LastMoveDir, coliseResult.normal); var center = slideBlock.GetCenter(); ricochet += new Vector2(center.x - coliseResult.colisePoint.x, 0); balls[ballId].Move(coliseResult.colisePoint - center); balls[ballId].LastMoveDir = ricochet; continue; } } balls[ballId].Move(balls[ballId].LastMoveDir * (_gameParams.ballSpeed + _speedBallBonus)); } }