using System;
 using System.Collections.Generic;
 using System.Drawing;
 using System.Text;
 namespace cForm
 {
 class xPoint
 {
 // Собственный статический генератор случайных чисел.
 // Используется в конструкторе.
 public static Random rnd = new Random();

 // Цвет объекта.
 public Color xColor;

 // Текущая позиция. Относительные значения координат X и Y.
 public Point p;

 // Обеспечение перемещения. Текущие значения координат могут
 // изменяться как по X, так и по Y.
 public Point direction;

 // Счетчик циклов сохранения выбранного направления.
 // Объект на протяжении фиксированного интервала времени может 
 // сохранять ранее избранное направление движения.
 // В течение n.X "тиков" для X в течение n.Y "тиков" для Y.
 public Point n;

 public xPoint(int X, int Y, int Xn, int Yn)
 {
 n = new Point(rnd.Next(0, Xn), rnd.Next(0, Yn));
 direction = new Point(rnd.Next(-1, 2), rnd.Next(-1, 2));
 p = new Point(X, Y);
 xColor = 
   Color.FromArgb(150, rnd.Next(0, 256), rnd.Next(0, 256), rnd.Next(0, 256));
 }

 // Статический метод. Еще вопрос, где следовало размещать его 
 // объявление... Определение нового положения амебы. 
 // Просматривается ВЕСЬ список.
 // Ее перемещение ограничивается физическими размерами клиентской области
 // окна приложения и определяется по двум координатам (X и Y).
 // В каждый момент она может оставаться на месте, либо изменить
 //  свое положение на один "шаг" по каждой из осей координат
 // ("вверх" или "вниз" по оси Y и "вперед" или "назад" по оси X).
 public static void setNextPosition(cForm cf, xPoint[] pt)
 {
 int i;
 float xy;

 // Итак, определение текущей позиции объекта.
 // Просмотр массива...
 for (i = 0; i < pt.Length; i++)
 {
 // Сначала разбираемся со значением координаты X.
 // Вычисляем возможную позицию после перемещения объекта.
 xy = (float)((pt[i].p.X + pt[i].direction.X) * cf.rPointGet);
 // Вполне возможно, что это вполне подходящая позиция.
 // И надо всего лишь проверить две вещи:
 // 1. не выскочит ли объект за пределы клиентской области окна 
 // приложения,
 // 2. не настало ли время поменять направление движения.
 if (
 xy < 0 || xy > cf.ClientSize.Width 	// 1. 
 ||
 pt[i].n.X > cf.NX                	// 2.
 )
 {
 pt[i].n.X = 0; // Обнулили счетчик циклов сохранения выбранного направления.
 // Процедура изменения направления перемещения по оси X.
 // На ближайшую перспективу объект может переместиться
 // вперед:            pt[i].direction.X == 1,
 // назад:             pt[i].direction.X == –1,
 // остаться на месте: pt[i].direction.X == 0.
 // Главное — это не выйти за пределы клиентской области окна приложения.
     pt[i].direction.X = xPoint.rnd.Next(-1, 2);
     xy = (float)((pt[i].p.X + pt[i].direction.X) * cf.rPointGet);
     if (xy >= 0 && xy <= cf.ClientSize.Width)
     {
         // Направление выбрано, перемещение произведено.
         pt[i].p.X += pt[i].direction.X;
     }
     else
     {
         // Выбранное направление движения приводит к выходу объекта
         // за пределы клиентской области окна приложения.
         // На ближайшие cf.NX тактов объект остается неподвижен по оси X.  
         pt[i].direction.X = 0;
     }
 }
 else
 {
 // Осуществили очередное перемещение по оси X.
 pt[i].p.X += pt[i].direction.X;
 pt[i].n.X++;
 }

 xy = (float)((pt[i].p.Y + pt[i].direction.Y) * cf.rPointGet);
 // Вполне возможно, что это вполне подходящая позиция.
 // И надо всего лишь проверить две вещи:
 // 1. не выскочит ли объект за пределы клиентской области 
 // окна приложения,
 // 2. не настало ли время поменять направление движения.
 if (
 xy < 0 || xy > cf.ClientSize.Height // 1. 
 ||
 pt[i].n.Y > cf.NY                   // 2.
 )
 {
 pt[i].n.Y = 0; // Обнулили счетчик циклов сохранения выбранного направления.
 // Процедура изменения направления перемещения по оси Y.
 // На ближайшую перспективу объект может переместиться
 // вверх:             pt[i].direction.Y == 1,
 // вниз:              pt[i].direction.Y == -1,
 // остаться на месте: pt[i].direction.Y == 0.
 // Главное — это не выйти за пределы клиентской области окна приложения.
 pt[i].direction.Y = xPoint.rnd.Next(-1, 2);
 xy = (float)((pt[i].p.Y + pt[i].direction.Y) * cf.rPointGet);
 if (xy >= 0 && xy <= cf.ClientSize.Height)
 {
     // Направление выбрано, перемещение произведено.
     pt[i].p.Y += pt[i].direction.Y;
 }
 else
 {
     // Выбранное направление движения приводит к выходу объекта
     // за пределы клиентской области окна приложения.
     // На ближайшие cf.NY тактов объект остается неподвижен по оси Y.  
     pt[i].direction.Y = 0;
 }
 }
 else
 {
 // Осуществили очередное перемещение по оси Y.
 pt[i].p.Y += pt[i].direction.Y;
 pt[i].n.Y++;
 }
 }
 }
 }
 }

Листинг 17.1.
Закрыть окно