Отскок шарика от стен
Подводящее упражнение 1
public Form1()
{
InitializeComponent();
// создадим таймер анимации
Timer timer = new Timer();
timer.Start();
timer.Tick += Timer_Tick;
timer.Interval = 2;
DoubleBuffered = true; // включим двойую буферизацию
Paint += Form1_Paint; //подпишемся на событие отрисовки
BallY = ClientSize.Height / 2; // зададим стартовое положение шарика по центру экрана
}
Создадим обработчик для таймера анимации:
private void Timer_Tick(object? sender, EventArgs e)
{
Invalidate();
}
Создадим обработкчик события Paint
private void Form1_Paint(object? sender, PaintEventArgs e)
{
// здесь можно будет вызвать нужную функцию, либо можно перенести весь код отрисовки целиком сюда, тогда создание функий не потребуется
BounceOnlyHorizontal(e.Graphics);
//MoveLeftAndTeleport(e.Graphics);
}
Объявим переменные необходимые для данной демо-сцены.
float BallX = 100; //текущая координата шарика по Х
float BallY = 100; //текущая координата шарика по Y
float BallRadius = 30; // радиус шарика для отрисовки
float Speed = 2; // скорость шарика
public void MoveLeftAndTeleport(Graphics gr)
{
gr.Clear(Color.Black); // очищаем экран
BallX -= Speed; // смещаем наш шарик влево на велчину Speed
if (BallX < 0) // если шар вышел за пределы окна
BallX = Width; // то телепортируем его на правый кран
//рисуем шарик
gr.FillEllipse(Brushes.Blue, BallX - BallRadius, BallY - BallRadius, BallRadius * 2, BallRadius * 2);
gr.DrawEllipse(Pens.White, BallX - BallRadius, BallY - BallRadius, BallRadius * 2, BallRadius * 2);
}
Запустим и получим следующий результат:

Задачи:
1. Шарик исчезает с экрана уже в момент когда он находится только наполовину за пределами экрана слева. Модифицируйту условный оператор таким образом чтобы дожидаться пока шарик скроется целиком с экрана
2. Аналогично: шарик появляется справа уже нарисованный на половину. Модифицируйте телепорт шарика таким образом чтобы он появлялся полностью за пределами экрана справа, и только потом плавно выезжал
Подводящее упражнение 2
Теперь сделаем чтобы чтобы шарик не телепортировался направо, а отскакивал от стены и летел в противоположную сторону. Для того чтобы на каждом кадре отрисоки знать в какую сторону сейчас летит шарик введем новый флаг (bool переменную) в которой будем хранить напралвение движение шарика (влево или вправо).
К существующим переменным добавим новую
bool IsMovingLeft = false; // флаг движения
float BallX = 100;
float BallY = 100;
float BallRadius = 20;
float Speed = 2;
Для определения смещения на каждом шагу в зависимости от текущего направления движения будем использовать тернарный оператор (который можно заменить на if-else при желании)
public void BounceOnlyHorizontal(Graphics gr)
{
gr.Clear(Color.Black);
// смещаем шарик в зависимости от его текущего направления движения
BallX += IsMovingLeft ? -Speed : Speed;
// проверяем если шарик вышел за пределы окна слева или справа, то переключаем направление
if (BallX >= (ClientRectangle.Width) || BallX <= 0)
IsMovingLeft = !IsMovingLeft;
gr.FillEllipse(Brushes.Blue, BallX - BallRadius, BallY - BallRadius, BallRadius * 2, BallRadius * 2);
gr.DrawEllipse(Pens.White, BallX - BallRadius, BallY - BallRadius, BallRadius * 2, BallRadius * 2);
}
Запустим код:

Задания:
1. По аналогии с предудыщими заданиями модифицировать код так, чтобы шарик отскакивал полностью, а не от середины.
Теперь вы можете самостоятельно добавить вертикальное движение шарика по аналогии с горизонтальным. Вы должны получить следующее поведение шарика на экране:

Исходный код данного примера вы можете найти здесь
Упражнения
- Сделать несколько одинаковых летающих шариков (с разными стартовыми координатами и направлениями)
- Сделать несколько разных летающих объектов (шарик, квадратик), с разными цветами и разной скоростью