C# Winforms Рикошет мяча от блока
Я создаю простую игру используя только C# и Winforms. В игре есть мяч, блоки и другие собираемые мячи (когда игрок их собирает, у него увеличивается количество мячей). Смысл в том, чтобы игрок сперва задал направление мяча так, чтобы мяч попал в блоки, а потом таким образом избавился от всех блоков. У меня не получается реализовать отскок/рикошет мяча от блока.
У меня есть формула с помощью которой я определяю траекторию полета мяча.
private void Background_MouseDown(object sender, MouseEventArgs e)
{
if (Если курсор на мяче)
{
StartPoint = MousePosition;
EndPoint = MousePosition;
isClicked = true;
}
}
private void Background_MouseMove(object sender, MouseEventArgs e)
{
if (isClicked)
{
ControlPaint.DrawReversibleLine(StartPoint, EndPoint, Color.Black);
EndPoint = MousePosition;
ControlPaint.DrawReversibleLine(StartPoint, EndPoint, Color.Black);
trajectory = true;
}
}
private void Background_MouseUp(object sender, MouseEventArgs e)
{
if (trajectory)
{
ControlPaint.DrawReversibleLine(StartPoint, EndPoint, Color.Black);
EndPoint = e.Location;
angle = Math.Atan2((Ball.arr[0].rect.X - EndPoint.X), (Ball.arr[0].rect.Y - EndPoint.Y));
isClicked = false;
Movement.angle = angle;
Movement.ClientSize = ClientSize;
MovingBalls(); // Функция которая запускает движение мячей
}
}
Ниже представлен сам код для движения мяча (находится в одном файле).
public void Move()
{
while (true)
{
if (x - velocityX * Math.Sin(Movement.angle) > Movement.ClientSize.Width - размер мяча || x - velocityX * Math.Sin(Movement.angle) < 0)
{
velocityX *= -1;
}
if (y - velocityY * Math.Cos(Movement.angle) < 0)
{
velocityY *= -1;
}
if (y - velocityY * Math.Cos(Movement.angle) >= Movement.defaultPosition.Y)
{
return;
}
x -= velocityX * Math.Sin(Movement.angle);
y -= velocityY * Math.Cos(Movement.angle);
rect.X = (int)x;
rect.Y = (int)y;
if (Block.arr != null)
{
foreach (Block block in Block.arr)
{
if (rect.IntersectsWith(block.rect))
{
if (CollisionWithTopOrBottom(block))
{
velocityY *= -1;
}
else if (CollisionWithSides(block))
{
velocityX *= -1;
}
block.currentHp--;
if (block.currentHp == 0)
{
block.Destroy();
}
}
}
}
}
}
public bool CollisionWithTopOrBottom(Block victim)
{
bool topBottomIntersection = !((rect.Top + 1 != victim.rect.Bottom) && rect.Bottom - 1 != victim.rect.Top);
return topBottomIntersection;
}
public bool CollisionWithSides(Block victim)
{
bool sideIntersection = (rect.Bottom >= victim.rect.Top || rect.Top <= victim.rect.Bottom) && (rect.Right > victim.rect.Left || rect.Left < victim.rect.Right);
return sideIntersection;
}
Дополнительные сведения:
В каждом блоке написано свое количество жизней (то есть, если написано 5 то игрок должен попасть по блоку 5 раз, чтобы разрушить его).
Скорость полета мяча (то есть velocityX и velocityY) равен одному.
Почему в функции CollisionWithTopOrBottom есть непонятная цифра "+ 1" и "- 1"?
Объясню, когда метод intersectionWith возвращает true (имею в виду, тот случай когда мяч коснулся нижней или верхней части блока), в этот момент координаты мяча и блока отличаются на одну единицу.
Сама проблема:
Представленный код работает когда скорость мяча равен одному, но как только скорость увеличивается мяч уже пролетает сквозь блоков или отскакивает в неправильную сторону.
Я попробовал решить проблему с помощью векторов и нормали, но так и не получилось.
Измененный код в методе Move():
if (rect.IntersectsWith(block.rect))
{
int dot = rect.X * block.rect.X + rect.Y * block.rect.Y;
Point trajectory = new Point(rect.X - 2 * dot * block.rect.X, rect.Y - 2 * dot * block.rect.Y);
angle = Math.Atan2((rect.X - trajectory.X), (rect.Y - trajectory.Y));
x -= velocityX * Math.Sin(angle);
y -= velocityY * Math.Cos(angle);
rect.X = (int)x;
rect.Y = (int)y;
block.currentHp--;
if (block.currentHp == 0)
{
block.Destroy();
}
}
Ответы (1 шт):
Если я правильно понял - то разрабатывается арканоид.
В арканоиде должно быть 2 логики - одна применима на блок (и на стенки уровня), вторая применима на игрока.
- Блок и стенки уровня отражают мяч с тем же(!!!!) углом с которым мяч летел только в иную сторону:
- А вот с игроком уже интереснее. У игрока угол должен отличатся в зависимости от удаления от центра. Центр должен отбивать мяч ровно вверх. А крайние углы блока должны отбивать на какой-то очень большой максимальный угол:
И чем ближе к центру - тем ближе к вертикальнй траэктории должно быть.
Чем ближе к левой стороне - тем более тупой угол должен быть вплоть до, например, 80 градусов относительно вертикали.
Чем ближе к правой стороне - тем более тупой угол в иную сторону.
Кстате, в интернете есть множество реализаций арканоида где ты можешь посмотреть нужные тебе расчеты. Но их уже найдешь сам

