Помощь в написании студенческих работ
Антистрессовый сервис

Объектно-ориентированное программирование

КурсоваяПомощь в написанииУзнать стоимостьмоей работы

Потоки В программе применяются кроме основного потока, реализуемого функцией Main () или main (), ещё рабочие потоки. Каждый из 10 (максимум) объектов кораблей, а также объект заправщика, располагает собственным потоком с потоковой функцией, причём если функционирование потоковых функций обычных объектов кораблей совпадают — они перемещают объекты кораблей по определенной траектории и отвечают… Читать ещё >

Объектно-ориентированное программирование (реферат, курсовая, диплом, контрольная)

Министерство общего и профессионального образования Российской Федерации Казанский государственный технический университет имени. А. Н. Туполева Кафедра КС Курсовая работа по дисциплине «Объектно-ориентированное программирование»

Исполнитель: студент группы 4201 Д. А. Павлов Руководитель: доц. кафедры АСОИУ В. И. Медведев Казань 2010

1. Задание

2. Уточнение задания

3. Описание разрабатываемой программы с точки зрения пользователя

4. Описание разрабатываемой программы с точки зрения программиста

4.1 Объектное представление программы

4.2 События

4.3 Потоки

5. Поэтапная разработка программной системы

5.1 Этап 1. Разработка класса корабля

5.2 Этап 2. Разработка класса прикладного окна

5.3 Этап 3. Разработка события but

5.4 Этап 4. Разработка класса основного окна и графики

5.5 Этап 5. Разработка дочерних окон

5.6 Этап 6. Разработка специального объекта (заправщик)

6. Описание проблем, возникших при разработке программной системы

7. Список используемой литературы Приложение 1. Диаграмма классов разработанной программы Приложение 2. Текст программы на языке C#

Приложение 3. Текст программы на языке Java

Приложение 4. Текст программы на языке C++/CLI

1. Задание программа приложение окно Луна освоена и на ней построены города, идет разработка полезных ископаемых. Между планетами курсируют корабли. Для перемещения от одной планеты к другой сначала надо выйти на орбиту, затем начать двигаться по заданной траектории. Если корабли встречаются, то один из них останавливается, отодвигается в сторону, пропуская другой. К ним подлетает специальный корабль-заправщик с Земли.

2. Уточнение задания Приложение включает прикладное окно, в котором отображается функционирование объектов, дочернее окно, содержащее интерфейсные элементы, управляющие программой, и дочернее окно, в которое выдается информация о состоянии и поведении объектов (пропускает другой корабль, размер топлива). Корабли перемещаются с помощью своих потоков. Среди интерфейсных элементов есть кнопка и редактор текста, с помощью которых можно добавить топливо. Программу реализовать на языках C#, Java и C++CLI.

3. Описание разрабатываемой программы с точки зрения пользователя Программа представлена прикладным и двумя дочерними окнами. В прикладном окне схематично изображены Земля, Луна, их орбиты и движущиеся по своим траекториям корабли. На каждом корабле написан его порядковый номер, над ним — текущее количество топлива.

Первое дочернее окно содержит текстовое поле и кнопки «Добавить корабль», «Добавить топливо», «Пауза». По нажатию на кнопку «Добавить корабль» с Земли запускается очередной корабль и начинает движение по орбите, потом полет к Луне. По нажатию на кнопку «Пауза» все корабли останавливаются, а надпись на кнопке сменяется на «Старт». При повторном нажатии корабли продолжают движение. По нажатию на кнопку «Добавить топливо» кораблю, чей номер задан в текстовом поле, добавляется 20 единиц топлива.

Диаграмма вариантов использования языка UML изображает действия, выполняемые пользователем программы. С точки зрения пользователя приложение предполагает три варианта использования:

— запустить новый корабль (start new ship),

— приостановить движение кораблей (suspend the ships moving),

— возобновить движение кораблей (resume the ships moving),

— добавить топливо выбранному кораблю (add fuel to selected ship).

Диаграмма вариантов использования представлена на рис. 3.1.

Рис. 3.1. Диаграмма вариантов использования приложения

4. Описание разрабатываемой программы с точки зрения программиста

4.1 Объектное представление программы

Программа включает объекты разных типов. Главными объектами программы являются объект прикладного окна класса Program и объекты дочерних окон класса Form или Frame. При создании объекта прикладного окна создаются дочерние окна, 1 объект обычного корабля класса Ship и один объект корабля-заправщика класса Charger. Объект обычного корабля сразу начинает взлет и движение по траектории, а заправщик — движение по орбите Земли против часовой стрелки.

Каждый обычный объект корабля движется в соответствии с потоковой функцией Move () или run () его собственного потока. При изменении координат, объект каждого обычного корабля генерирует событие ev или уведомление, на которое подписан обработчик mainEvent () или функция update () в классе прикладного окна. Параллельно с этим выполняется поток прикладного окна, который отслеживает взаимное положение кораблей и при их встрече «притормаживает» корабль с бОльшим номером.

Первое дочернее окно (Controls) содержит объекты кнопок AddShip, AddFuel и Pause и объект numShip текстового поля. Второе (Info) — массив из десяти текстовых полей, отражающих состояние каждого корабля (не запущен, в полёте, уступает, остановлен, исчез).

4.2 События В программе имеются несколько событий.

Объект обычного корабля генерирует событие ev или уведомление при каждом изменении его координат. Данное событие используется при перерисовке кораблей в прикладном окне. На эти события всех обычных объектов должен быть подписан один обработчик mainEvent или update (), инициирующий перерисовку окна.

Также в программе используются предопределённые событие Click, генерируемые при нажатии кнопок. На них реагирует обработчик ButPressed, выбирающий действия в зависимости от текста на кнопке, инициировавшей событие.

4.3 Потоки В программе применяются кроме основного потока, реализуемого функцией Main () или main (), ещё рабочие потоки. Каждый из 10 (максимум) объектов кораблей, а также объект заправщика, располагает собственным потоком с потоковой функцией, причём если функционирование потоковых функций обычных объектов кораблей совпадают — они перемещают объекты кораблей по определенной траектории и отвечают за расход топлива, то потоковая функция объекта заправщика отличается от них.

5. Поэтапная разработка программной системы Разработка приложения будет осуществляться поэтапно. Вначале разработаем класс Ship потокового объекта и протестируем его. Затем создадим и отладим класс Program потоковых объектов, который управляет кораблями.

В дальнейшем мы наследуем класс Program из базового класса Form или Frame и будем отображать корабли в области клиента прикладного окна (в форме) в виде кругов одного цвета. Нам придётся модифицировать класс Ship потокового объекта, добавив в него координаты и их приращения (вертикальную и горизонтальную скорости). Для обеспечения перерисовки кораблей мы воспользуемся событием или уведомлением, которое будет генерироваться после каждого изменения их координат.

Убедившись в совместном функционировании кораблей и их отображении в области клиента прикладного окна, мы перейдём к разработке дочернего окна, на котором разместим управляющие элементы — кнопки, а затем дочернего окна с текстовыми полями, содержащими информацию о текущем состоянии кораблей.

На последнем этапе мы создадим специальный объект заправщика класса Charger с его потоковой функцией, а в класс Ship обычного объекта корабля добавим переменную, содержащую значение топлива, и функции её изменения.

Для большей наглядности при создании приложений мы воспользуемся диаграммами классов языка UML.

В программе обычные объекты объединим в одномерном массиве длиной num = 10. При необходимости, изменив длину массива, можно создать необходимое количество обычных объектов.

5.1 Этап 1. Разработка класса корабля На первом этапе создадим основной класс Ship потокового объекта, который включает самые необходимые данные:

id — номер обычного объекта,

x — координата по горизонтали,

y — координата по вертикали,

speedX — горизонтальная скорость,

speedY — вертикальная скорость,

live — признак жизни потока (live= true — поток выполняется, live= false — поток завершён),

th — поток класса Thread.

Включим в класс Ship функции:

Ship (int ns) — конструктор класса,

Start () — начать движение обычного объекта,

Stop () — приостановить выполнение обычного объекта, Диаграмма класса Ship представлена на рис. 5.3.1.1.

Рис. 5.3.1.1. Диаграмма классов приложения первого этапа разработки В примере 5.3.1.1 приведена реализация первого этапа на языке C#.

Пример 5.3.1.1. Реализация приложения первого этапа на языке C#.

//C# File Program. cs

using System;

using System. Threading;

class Ship

{

Thread th;

int id; // Порядковый номер корабля

protected bool live;

protected double x, y; // позиция

protected double speedX, speedY; // скорость

// Конструктор класса. Принимает номер корабля.

public Ship (int ns)

{

this.id = ns; // Записываем номер корабля

this.live = false; // первоначально не движемся

this.x = 160; // начальная позиция по X

this.y = 300; // начальная позиция по Y

this.speedX = 0; // скорость движения по горизонтали

this.speedY = -3; // скорость движения по вертикали (старт с Земли)

Start (); // запускаем движение

}

// функция старта потока движения корабля

public void Start ()

{

if (live == false)

{

live = true;

th = new Thread (new ThreadStart (Move)); // Создаем объект-поток «движение корабля»

th.Start (); // Стартуем поток

}

}

// функция остановки потока движения корабля

public void Stop ()

{

live = false;

}

// Поток, отвечающий за движение корабля

void Move ()

{

while (live) // пока поток жив

{

x += speedX;

y += speedY;

Console.WriteLine («Координаты: «+ System.Convert.ToString (x) + «, «+ System.Convert.ToString (y));

Thread.Sleep (60); // спим

}

}

}

//——————————————————;

class Program1

{

static void Main (string[] args)

{

Ship Ship1= new Ship (1); // Создать первый обычный объект

Ship Ship2= new Ship (2); // Создать второй обычный объект

Console.WriteLine («Объекты функционируют»);

Thread.Sleep (20); // Объекты функционируют 20 мс

Ship1.Stop (); // Приостановить первый обычный объект

Ship2.Stop (); // Приостановить второй обычный й объект

Console.WriteLine («Объекты приостановлены и возобновлены»);

Ship1.Start (); // Возобновить выполнение первого объекта

Ship2.Start (); // Возобновить выполнение второго объекта

Thread.Sleep (20); // Объекты функционируют 20 мс

Ship1.Stop (); // Приостановить первый обычный объект

Ship2.Stop (); // Приостановить второй обычный объект

}

}

5.2 Этап 2. Разработка класса прикладного окна На этом этапе реализуем класс Program, содержащий массив обычных объектов класса Ship и осуществляющий их поочередный запуск, а также приостановку и возобновление функционирования. Дополнительно к указателю ship на массив обычных объектов, класс Program содержит потоковую функцию run (), отслеживающую встречи объектов кораблей. Для её работы в класс Ship добавляется булевская переменная vstrecha, являющаяся индикатором сближения кораблей.

Диаграмма классов Program-приложения второго этапа изображена на рис. 5.3.2.1.

Рис 5.3.2.1. Диаграмма классов Program-приложения второго этапа

Реализация второго этапа разработки Program-приложения на языке C# дана в примере 5.3.2.1.

Пример 5.3.2.1. Реализация второго этапа разработки Program-приложения на языке C#.

// C# File Program2. cs

// Файл Program2. cs полностью включает файл Program. cs, дополнив его

// нижеследующим описанием класса Program и изменённой функцией Main

.. .

//——————————————————;

class Program

{

Ship[] ship;

int num;

int s1, s2; // Номера встретившихся кораблей

Thread th;

bool live;

// Констуктор

public Program ()

{

num = 1; // стартовое кол-во кораблей

ship = new Ship[10]; // Массив из 10 кораблей

for (int i = 0; i < num; i++) // Перебираем массив кораблей

{

ship[i] = new Ship (i); // Создаем новый объект-корабль и помещаем его в массив

}

live = true; // стартуем поток

th = new Thread (new ThreadStart (run));

th.Start ();

}

// потоковая функция

void run ()

{

while (live)

{

// перебираем корабли

for (int i = 0; i < num; i++)

{

for (int j = i + 1; j < num; j++)

{

if (i < j) // Уступает корабль с бОльшим номером

{

s2 = j;

s1 = i;

}

else

{

s2 = i;

s1 = j;

}

if (Math.Abs (ship[s1]. X — ship[s2]. X) < 20 && Math. Abs (ship[s1]. Y — ship[s2]. Y) < 20)

{

ship[s2]. vstrecha = true; // Встреча началась

if (!ship[s1]. isStopped && !ship[s2]. isStopped) ship[s2]. Stop ();

else if (ship[s2]. vstrecha)

{

ship[s2].Start (); // Если пропускал, то продолжить движение

ship[s2]. vstrecha = false; // Встреча

}

}

Thread.Sleep (31);

}

}

}

// основная функция

static void Main ()

{

Program prog = new Program ();

Application.Run (prog);

}

}

5.3 Этап 3. Разработка события but

Включим в класс Ship обычного объекта событие ev и уведомление, сигнализирующее об очередном цикле выполнения потока. Это событие и уведомление обрабатывается функцией MainEvent или update () класса Program, что будет использовано при перерисовке кораблей в области клиента прикладного окна на четвёртом этапе. На рис. 5.3.3.1 и в примере 5.3.3.1 представлены диаграмма классов третьего этапа и программа, реализующая её.

Рис. 5.3.3.1. Диаграмма классов приложения третьего этапа Пример 5.3.3.1. Реализация третьего этапа разработки приложения.

// С# File Program3. cs

// Файл Program3. cs полностью включает файл Program2. cs, дополнив

// его объявлением события ev в классе Ship и функцией MainEvent

// класса Program, обеспечивающей обработку этого события.

// Изменения файла Program2. cs выделены жирным шрифтом.

.. .

//——————————————————;

delegate void delEv (); // Объявление типа delEv делегата события ev

class Ship

{

public event delEv ev; // Объявление события ev

.. .

//———————;

void Move () // Выполнить поток

{

while (live)

{

x += speedX;

y += speedY;

Console.WriteLine («Координаты: «+ System.Convert.ToString (x) + «, «+ System.Convert.ToString (y));

Thread.Sleep (60); // спим

if (ev ≠ null) // Если событие активизировано, то

{

Console.WriteLine («Event»);

ev (); // вызвать событие

}

Thread.Sleep (10);

}

}

};

//——————————————————;

class Program // Класс потоковых объектов

{

Ship [] pShip;

void MainEvent () // Обработчик события ev

{

Console.WriteLine («MainEvent»);

}

public Program () // Конструктор

{

num = 1; // стартовое кол-во кораблей

ship = new Ship[10]; // Массив из 10 кораблей

for (int i = 0; i < num; i++)

{

ship[i] = new Ship (i);

ship[i]. ev += new delEv (MainEvent); // Добавить

}

live = true; // стартуем поток

th = new Thread (new ThreadStart (run));

th.Start ();

}

.. .

}

5.4 Этап 4. Разработка класса основного окна и графики Наступил этап разработки, когда появится прикладное окно приложения с перемещающимися кораблями.

Наследовав класс Form или Frame, класс Program существенно расширит свою функциональность. Теперь можно создать прикладное окно (основную форму) и дочернее окно (дочернюю форму). Но дочернее окно будет создано потом в классе Controls, также порождённом из класса Form или Frame. Пока мы добавляем в класс Ship новые переменные, необходимые для задания его траектории, и описываем эту траекторию в потоковой функции корабля Move. Потоковая функция класса Program, отслеживающая взаимодействие кораблей, также изменяется: теперь при встрече корабль с бОльшим номером будет притормаживать, не мешая соседнему. Диаграмма классов и реализация этого этапа представлены на рис. 5.3.4.1 и в примере 5.3.4.1.

Рис. 5.3.4.1. Диаграмма классов Program-приложения четвёртого этапа Пример 5.3.4.1. Реализация четвёртого этапа разработки Program-приложения на языке C#.

// C# File Program4. cs

// Файл Program4. cs полностью включает файл Program3. cs, дополнив его

// данными класса Program, необходимыми для рисования кораблей, и

// свойствами класса Ship для работы с его переменными.

// В результате наследования класса Program из базового класса Form появилось

// прикладное окно, свойства которого установлены в конструкторе класса

// Program. Переопределена функция OnPaint перерисовки. Функция MainEvent,

// реагируя на событие ev из потоков, вызывает перерисовку кораблей.

// Функция run «притормаживает» корабли при встречах.

// Изменения файла Program3. cs выделены жирным шрифтом

using System;

using System. Drawing;

using System.Windows.Forms;

using System. Threading;

class Ship

{

Thread th;

int id; // Порядковый номер корабля

protected bool live;

protected double x, y; // позиция

protected double speedX, speedY; // скорость

protected bool WasOnMoon; // был ли на Луне

protected bool start1; // только что стартовал

protected bool comeback1; // первое возвращение

public bool vstrecha; // индикатор встречи

void Move ()

{

while (live) // пока поток жив

{

if ((x > 0 && x < 420 && y > 210 && y < 600) && !(x == 160 && y > 232)) // Орбита Земли

{

if (WasOnMoon == false) // Если на Луне еще не был, разгон

{ // по орбите и полет к Луне

if (start1)

{

fi = -Math.PI / 2 — 0.2;

start1 = false;

}

speedY = 6 * Math. Cos (fi);

speedX = -6 * Math. Sin (fi);

y -= 0.16;

if (fi > Math. PI / 2) fuel -= 0.5; // Разгон: топливо уменьшается

else fuel -= 0.05;

}

else // Если возвращается с Луны, становится на орбиту

{ // с вращением против часовой стрелки

if (comeback1 && x < 230)

{

fi = -Math.PI / 2;

comeback1 = false;

}

if (!comeback1)

{

speedY = 6 * Math. Cos (fi);

speedX = 6 * Math. Sin (fi);

y -= 0.05;

fuel -= 0.05;

}

}

}

if (x == 160 && y > 225 && y < 235) // Земля — Луна

{

speedX = -speedY + 3;

};

if (x > 465 && x < 630 && y < 180) // Орбита Луны

{

if (!WasOnMoon)

{

fi = Math. PI+0.4;

WasOnMoon = true;

comeback1 = true;

}

speedY = 4*Math.Cos (fi);

speedX = -4*Math.Sin (fi);

x += 0.04;

if (fi > Math. PI*2−0.3 || fi < Math. PI/2) fuel -= 0.5; // Разгон: топливо уменьшается

else fuel -= 0.05;

}

/*if (x > 461 && x < 630) // Орбита Луны (старое)

{

if (kM)

{

fi = Math. PI+0.36;

kM = false;

}

speedY = 4*Math.Cos (fi);

speedX = -4*Math.Sin (fi);

y -= 0.065;

}*/

x += speedX; y += speedY; // движемся

if (fi < 2 * Math. PI) // изменяем угол фи

{

if (x > 425) fi += 0.051;

else fi += 0.032;

}

else fi = 0;

if (ev ≠ null) ev (); // событие

Thread.Sleep (60); // спим

}

}

public int X

{

get { return (int)x; } // чтение координаты х

}

public int Y

{

get { return (int)y; } // чтение координаты х

}

public double setY

{

set { y = value; } // запись координаты у

}

public double setX

{

set { x = value; } // запись координаты х

}

public bool isStopped { get { return! this.th.IsAlive; } }

}

//——————————————————;

class Program: Form

{

Ship[] ship;

int num;

int s1, s2; // Номера встретившихся кораблей

Thread th;

bool live;

public Program ()

{

num = 1;

Text = «Objects» ;

Size = new Size (675, 675);

FormBorderStyle = FormBorderStyle. FixedSingle;

FormClosed += new FormClosedEventHandler (exit);

this.Show ();

Location = new Point (200, 50);

ship = new Ship[10];

for (int i = 0; i < num; i++)

{

ship[i] = new Ship (i);

ship[i]. ev += new delEv (MainEvent);

}

DoubleBuffered = true;

live = true;

th = new Thread (new ThreadStart (run));

th.Start ();

}

// потоковая функция

void run ()

{

while (live)

{

// перебираем корабли

for (int i = 0; i < num; i++)

{

for (int j = i + 1; j < num; j++)

{

if (i < j) // Уступает корабль с бОльшим номером

{

s2 = j;

s1 = i;

}

else

{

s2 = i;

s1 = j;

}

if (Math.Abs (ship[s1]. X — ship[s2]. X) < 20 && Math. Abs (ship[s1]. Y — ship[s2]. Y) < 20)

{

ship[s2]. vstrecha = true; // Встреча началась

if (!ship[s1]. isStopped && !ship[s2]. isStopped) ship[s2]. Stop ();

}

else if (ship[s2]. vstrecha)

{

ship[s2].Start ();

ship[s2]. vstrecha = false;

}

}

Thread.Sleep (31);

}

}

// перерисовка содержимого окна

protected override void OnPaint (PaintEventArgs arg)

{

Pen grayPen = new Pen (Color.LightGray);

Pen blackPen = new Pen (Color.Black);

Brush blackBrush = new SolidBrush (Color.Black);

Brush whiteBrush = new SolidBrush (Color.White);

Brush greenBrush = new SolidBrush (Color.Lime);

Font ArialF = new Font («Arial», 10);

arg.Graphics.FillRectangle (blackBrush, 0,0,1280,960); // Фон

arg.Graphics.DrawEllipse (grayPen, 40, 230, 370, 370); // Орбита Земли

arg.Graphics.DrawEllipse (grayPen, 468, 28, 162, 162); // Орбита Луны

arg.Graphics.FillEllipse (new SolidBrush (Color.DeepSkyBlue), 100, 290, 250, 250); // Земля

arg.Graphics.FillEllipse (new SolidBrush (Color.DarkKhaki), 500, 60, 100, 100); // Луна

for (int i = 0; i < num; i++) // перебираем корабли

{

arg.Graphics.FillEllipse (greenBrush, ship[i]. X, ship[i]. Y, 16, 16); // корабль

arg.Graphics.DrawEllipse (blackPen, ship[i]. X, ship[i]. Y, 16, 16); // обводим корабль

arg.Graphics.DrawString (ship[i]. id + «», ArialF, blackBrush, ship[i]. X + 4, ship[i]. Y); // номер

}

}

void MainEvent ()

{

Console.WriteLine («MainEvent»);

Invalidate ();

}

.. .

static void Main ()

{

Program prog = new Program ();м

Application.EnableVisualStyles ();

Application.Run (prog);

}

}

5.5 Этап 5. Разработка дочерних окон Создадим два дочерних окна: первое с кнопками, функции которых описаны выше, второе с массивом текстовых полей, показывающих состояние кораблей. Поскольку одна из кнопок должна добавлять топливо, введем в классе Ship соответствующую переменную и добавим в потоковую функцию операции ее изменения при движении. Диаграмма классов и реализация пятого этапа представлены на рис. 5.3.5.1 и в примере 5.3.5.1.

Рис 5.3.5.1. Диаграмма классов Program-приложения пятого этапа Пример 5.3.5.1. Реализация пятого этапа разработки Program-приложения на языке C#.

// C# File Program5. cs

// Файл Program5. cs полностью включает файл Program4. cs, дополнив его

// новым классом Controls, порождённым из класса Form. Класс Controls

// содержит управляющие элементы-кнопки и текстовое поле.

// Изменения файла ProgramCs4. cs выделены жирным шрифтом

.. .

class Controls: Form // Класс пользователя кораблей

{

Button AddShip; // Добавить новый корабль

Button AddFuel; // Добавить топливо

Button Pause; // Приостановка всех кораблей

TextBox numShip; // Номер корабля, которому добавляется топливо

Point[] Koord;

TextBox[] Sost; // Сообщения о состоянии кораблей

public event delBut but; // Привязываем к делегату события нажатия кнопок

// конструктор

public Controls ()

{

// кнопки

AddShip = new Button ();

AddShip.Location = new Point (10, 50);

AddShip.Text = «Добавить корабль» ;

AddShip.Size = new Size (120, 25);

AddShip.Click += new EventHandler (onAdd);

AddFuel = new Button ();

AddFuel.Location = new Point (10, 80);

AddFuel.Text = «Добавить топливо» ;

AddFuel.Size = new Size (120, 25);

AddFuel.Click += new EventHandler (onAddFuel);

Pause = new Button ();

Pause.Location = new Point (20, 110);

Pause.Size = new System.Drawing.Size (100, 25);

Pause.Text = «Пауза» ;

Pause.Click += new EventHandler (onPause);

// текстовое поле

numShip = new TextBox ();

numShip.Location = new Point (35, 20);

numShip.Text = «0» ;

numShip.Size = new Size (65, 25);

Koord = new Point[10];

for (int i = 0; i < 10; i++)

Koord[i] = new Point (15, i*21 + 5);

Sost = new TextBox[10]; ;

for (int i = 0; i < 10; i++)

{

Sost[i] = new TextBox ();

Sost[i]. Location= Koord[i];

Sost[i].Text = Convert. ToString (i)+". Не запущен" ;

Sost[i]. Size = new Size (90, 20);

}

Sost[0]. Text = «0. В полёте» ;

// окошко с кнопками управления

Form ctrl = new Form ();

ctrl.Text = «Controls» ;

ctrl.Size = new Size (150, 200);

ctrl.Controls.Add (AddShip);

ctrl.Controls.Add (AddFuel);

ctrl.Controls.Add (Pause);

ctrl.Controls.Add (numShip);

ctrl.Show (); // показываем окно

ctrl.Location = new Point (10, 50); // позиционируем

// окошко с информацией

Form Info = new Form ();

Info.Text = «Info» ;

Info.Size = new Size (150, 260);

for (int i = 0; i < 10; i++) Info.Controls.Add (Sost[i]); // Массив сообщений во 2 окне

ctrl.Location = new Point (10, 50); // позиционируем

ctrl.Show (); // показываем окно

Info.Location = new Point (10, 250);

Info.Show ();

}

public void SetStatus (int num, string str)

{

this.Sost[num]. Text = Convert. ToString (num) + «. «+ str;

}

public bool IsntDisappeared (int i) // Проверка статуса на «исчезновение»

{

if (Sost[i]. Text == Convert. ToString (i) + «. Исчез»)

return false;

else return true;

}

// обработчик кнопки добавления корабля

void onAdd (object obj, EventArgs arg)

{

if (but ≠ null) but («add», 0);

}

// обработчик кнопки приостановки

void onPause (object obj, EventArgs arg)

{

if (but ≠ null)

{

if (Pause.Text == «Пауза»)

{

Pause.Text = «Старт»; // меняем текст кнопки

but («stop», 0); // генерируем событие приостановки

}

else

{

Pause.Text = «Пауза» ;

but («start», 0); // генерируем событие запуска

}

}

}

// обработчик кнопки добавления топлива

void onAddFuel (object obj, EventArgs arg)

{

if (but ≠ null) but («fuel», Convert. ToInt32(this.numShip.Text));

}

}

Class Program: Form

{

public Program ()

{

.. .

ContForm = new Controls ();

ContForm.but += new delBut (ButPressed); // привязываем события нажатия кнопок

.. .

}

void ButPressed (string btn, int numship)

{

if (btn == «add»)

{

if (num < 10)

{ // если кол-во < 10

ship[num] = new Ship (num); // создаём

ship[num]. ev += new delEv (MainEvent); // привязываем

ContForm.SetStatus (num, «В полёте»);

num++;

}

else

{

MessageBox.Show («Не больше 10!»);

}

}

else if (btn == «start»)

{

for (int i = 0; i < num; i++)

{

if (ContForm.IsntDisappeared (i))

{

ship[i]. Start (); // стартуем все корабли, кроме исчезнувших

ContForm.SetStatus (i, «В полёте»);

}

}

}

else if (btn == «stop»)

{

for (int j = 0; j < num; j++)

{

if (ContForm.IsntDisappeared (j))

{

ship[j]. Stop (); // приостанавливаем все корабли

ContForm.SetStatus (j, «Остановлен»);

}

}

}

else if (btn == «fuel») // добавляем 20 единиц топлива

{

if (ship[numship] ≠ null)

{

ship[numship]. fuel += 20;

if (ship[numship]. fuel > 99) ship[numship]. fuel = 99; }

}

}

}

5.6 Этап 6. Разработка специального объекта (заправщик) В последнем этапе разработаем класс Charger специального объекта (заправщика), добавим его объект в класс, содержащий массив обычных объектов. Заправщик должен постоянно находиться на орбите Земли, двигаясь против часовой стрелки и добавляя топливо кораблям при сближении. Создадим специальный объект в теле конструктора класса Program. Добавим в потоковую функцию, отслеживающую сближение кораблей, обработку их взаимодействия с заправщиком. Диаграмма классов и реализация последнего этапа представлены на рис. 5.3.7.1 и в примере 5.3.7.1.

Рис. 5.3.7.1. Диаграмма классов приложения шестого этапа

Пример 5.3.7.1. Реализация шестого этапа разработки приложения на языке C#.

// C# File Program6. cs

// Файл Program6. cs полностью включает файл Program5. cs, дополнив его новым

// классом Charger специального объекта. В классе Program создан

// специальный объект, потоковая функция класса Program дополнена.

// Изменения файла ProgramCs6. cs выделены жирным шрифтом

.. .

class Charger: Ship // Класс заправщика

{

public Charger (): base (10)

{

this.speedY = 0;

this.y = 225; // начальная позиция по высоте (орбита Земли)

this.x = 230;

this.fi = -Math.PI / 2 — 0.05; // начальная позиция на орбите

Stop (); // останавливаем запущенный поток

StartCh (); // запускаем движение

}

public void StartCh ()

{

if (live == false)

{

th.Abort (); // Отключаем стандартный поток кораблей

live = true;

th = new Thread (new ThreadStart (Move)); // Создаем новый поток

th.Start (); // Стартуем поток

}

}

void Move ()

{

while (live)

{

speedY = 12 * Math. Cos (fi);

speedX = 12 * Math. Sin (fi);

if (y > 415) y -= 0.27; else y -= 0.05;

x += speedX; y += speedY; // движемся

if (fi < 2 * Math. PI) fi += 0.065; // изменяем угол фи

else fi = 0;

Thread.Sleep (60); // спим

}

}

}

//——————————————————;

class Program: Form // Класс потоковых объектов

{

Ship[] ship;

Charger charger;

Controls ContForm;

int num;

int s1, s2; // Номера встретившихся кораблей

Thread th;

bool live;

public Program ()

{

.. .

ship = new Ship[10]; // Массив из 10 кораблей

charger = new Charger ();

.. .

}

void run ()

{

while (live)

{

for (int i = 0; i < num; i++)

{

if (Math.Abs (ship[i]. X — charger. X) < 20 && Math. Abs (ship[i]. Y — charger. Y) < 20) // Заправка

if (!charger.isStopped)

{

if (ship[i]. fuel <= 89) ship[i]. fuel += 10; else ship[i]. fuel = 99;

}

if (ship[i]. fuel <= 0) // Исчезновение

{

ship[i]. Stop ();

ship[i].setX = 1000;

ship[i]. setY = 1000 + 50*i;

this.Invoke (new EventHandler (delegate // Сообщение статуса

{

ContForm.SetStatus (i, «Исчез»);

}));

.. .

}

}

.. .

//———————;

protected override void OnPaint (PaintEventArgs arg) // Перерисовать

{

.. .

arg.Graphics.FillEllipse (new SolidBrush (Color.DarkRed), charger. X, charger. Y, 16, 16); // заправщик

arg.Graphics.DrawEllipse (blackPen, charger. X, charger. Y, 16, 16);

arg.Graphics.DrawString («C», ArialF, blackBrush, charger. X + 2, charger. Y);

}

.. .

}

.. .

6. Описание проблем, возникших при разработке программной системы При переводе программы на язык Java возникли трудности с описанием уведомлений и потоков. При отладке пришлось изменить порядок создания объектов классов и размещение обработчиков.

Список используемой литературы

1. Медведев В. И. Особенности объектно-ориентированного программирования на C++/CLI, C# и Java — Казань: РИЦ «Школа», 2010. — 444 c.: ил. — (Серия «Современная прикладная математика и информатика»).

2. Веб-ресурс http://msdn.microsoft.com и другие.

Приложение 1. Диаграмма классов разработанной программы

Приложение 2. Текст программы на языке C#

using System;

using System. Drawing;

using System.Windows.Forms;

using System. Threading;

namespace Unite

{

delegate void delEv (); // делегат события

delegate void delBut (string btn, int numship); // делегат события кнопок

// класс формы с кнопками

class Controls

{

Button AddShip; // Добавить новый корабль

Button AddFuel; // Добавить топливо

Button Pause; // Приостановка всех кораблей

TextBox numShip; // Номер корабля, которому добавляется топливо

Point[] Koord;

TextBox[] Sost; // Сообщения о состоянии кораблей

public event delBut but; // Привязываем к делегату события нажатия кнопок

// конструктор формы

public Controls ()

{

// кнопки

AddShip = new Button ();

AddShip.Location = new Point (10, 50);

AddShip.Text = «Добавить корабль» ;

AddShip.Size = new Size (120, 25);

AddShip.Click += new EventHandler (onAdd);

AddFuel = new Button ();

AddFuel.Location = new Point (10, 80);

AddFuel.Text = «Добавить топливо» ;

AddFuel.Size = new Size (120, 25);

AddFuel.Click += new EventHandler (onAddFuel);

Pause = new Button ();

Pause.Location = new Point (20, 110);

Pause.Size = new System.Drawing.Size (100, 25);

Pause.Text = «Пауза» ;

Pause.Click += new EventHandler (onPause);

// текстовое поле

numShip = new TextBox ();

numShip.Location = new Point (35, 20);

numShip.Text = «0» ;

numShip.Size = new Size (65, 25);

Koord = new Point[10];

for (int i = 0; i < 10; i++)

Koord[i] = new Point (15, i*21 + 5);

Sost = new TextBox[10]; ;

for (int i = 0; i < 10; i++)

{

Sost[i] = new TextBox ();

Sost[i]. Location= Koord[i];

Sost[i].Text = Convert. ToString (i)+". Не запущен" ;

Sost[i]. Size = new Size (90, 20);

}

Sost[0]. Text = «0. В полёте» ;

// окошко с кнопками управления

Form ctrl = new Form ();

ctrl.Text = «Controls» ;

ctrl.Size = new Size (150, 200);

ctrl.Controls.Add (AddShip);

ctrl.Controls.Add (AddFuel);

ctrl.Controls.Add (Pause);

ctrl.Controls.Add (numShip);

ctrl.Show (); // показываем окно

ctrl.Location = new Point (10, 50); // позиционируем

// окошко с информацией

Form Info = new Form ();

Info.Text = «Info» ;

Info.Size = new Size (150, 260);

for (int i = 0; i < 10; i++) Info.Controls.Add (Sost[i]); // Массив сообщений во 2 окне

ctrl.Location = new Point (10, 50); // позиционируем

ctrl.Show (); // показываем окно

Info.Location = new Point (10, 250);

Info.Show ();

}

public void SetStatus (int num, string str)

{

this.Sost[num]. Text = Convert. ToString (num) + «. «+ str;

}

public bool IsntDisappeared (int i) // Проверка статуса на «исчезновение»

{

if (Sost[i]. Text == Convert. ToString (i) + «. Исчез»)

return false;

else return true;

}

// обработчик кнопки добавления корабля

void onAdd (object obj, EventArgs arg)

{

if (but ≠ null) but («add», 0);

}

// обработчик кнопки приостановки

void onPause (object obj, EventArgs arg)

{

if (but ≠ null)

{

if (Pause.Text == «Пауза»)

{

Pause.Text = «Старт»; // меняем текст кнопки

but («stop», 0); // генерируем событие приостановки

}

else

{

Pause.Text = «Пауза» ;

but («start», 0); // генерируем событие запуска

}

}

}

// обработчик кнопки добавления топлива

void onAddFuel (object obj, EventArgs arg)

{

if (but ≠ null) but («fuel», Convert. ToInt32(this.numShip.Text));

}

}

// Класс корабля.

class Ship

{

protected Thread th;

public int id; // Порядковый номер корабля

protected bool live;

protected double x, y; // позиция

protected double speedX, speedY; // скорость

protected double fi; // положение на окружности орбиты

public double fuel; // топливо

protected bool WasOnMoon; // был ли на Луне

protected bool start1; // только что стартовал

protected bool comeback1; // первое возвращение

public bool vstrecha; // индикатор встречи

public event delEv ev; // событие смены движения, по которому взаимодействуют корабли

// Конструктор класса. Принимает номер корабля.

public Ship (int ns)

{

this.id = ns; // Записываем номер корабля

this.live = false; // первоначально не движемся

this.x = 160; // начальная позиция (поверхность Земли)

this.y = 300; // начальная позиция по высоте (поверхность Земли)

this.speedX = 0; // скорость движения по горизонтали

this.speedY = -3; // скорость движения по вертикали (старт с Земли)

this.fuel = 50; // начальный запас топлива

this.fi = Math. PI;

this.WasOnMoon = false; // на Луне не был

this.start1 = true; // первый старт — да

this.comeback1 = false; // первое возвращение — нет

this.vstrecha = false; // встречи нет

Start (); // запускаем движение

}

// функция старта потока движения корабля

public void Start ()

{

if (live == false)

{

live = true;

th = new Thread (new ThreadStart (Move)); // Создаем объект-поток «движение корабля»

th.Start (); // Стартуем поток

}

}

// функция остановки потока движения корабля

public void Stop ()

{

live = false;

}

// Поток, отвечающий за движение корабля

void Move ()

{

while (live) // пока поток жив

{

if ((x > 0 && x < 420 && y > 210 && y < 600) && !(x == 160 && y > 232)) // Орбита Земли

{

if (WasOnMoon == false) // Если на Луне еще не был, разгон

{ // по орбите и полет к Луне

if (start1)

{

fi = -Math.PI / 2 — 0.2;

start1 = false;

}

speedY = 6 * Math. Cos (fi);

speedX = -6 * Math. Sin (fi);

y -= 0.16;

if (fi > Math. PI / 2) fuel -= 0.5; // Разгон: топливо уменьшается

else fuel -= 0.05;

}

else // Если возвращается с Луны, становится на орбиту

{ // с вращением против часовой стрелки

if (comeback1 && x < 230)

{

fi = -Math.PI / 2;

comeback1 = false;

}

if (!comeback1)

{

speedY = 6 * Math. Cos (fi);

speedX = 6 * Math. Sin (fi);

y -= 0.05;

fuel -= 0.05;

}

}

}

if (x == 160 && y > 225 && y < 235) // Земля — Луна

{

speedX = -speedY + 3;

};

if (x > 465 && x < 630 && y < 180) // Орбита Луны

{

if (!WasOnMoon)

{

fi = Math. PI+0.4;

WasOnMoon = true;

comeback1 = true;

}

speedY = 4*Math.Cos (fi);

speedX = -4*Math.Sin (fi);

x += 0.04;

if (fi > Math. PI*2−0.3 || fi < Math. PI/2) fuel -= 0.5; // Разгон: топливо уменьшается

else fuel -= 0.05;

}

/*if (x > 461 && x < 630) // Орбита Луны (старое)

{

if (kM)

{

fi = Math. PI+0.36;

kM = false;

}

speedY = 4*Math.Cos (fi);

speedX = -4*Math.Sin (fi);

y -= 0.065;

}*/

x += speedX; y += speedY; // движемся

if (fi < 2 * Math. PI) // изменяем угол фи

{

if (x > 425) fi += 0.051;

else fi += 0.032;

}

else fi = 0;

if (ev ≠ null) ev (); // событие

Thread.Sleep (60); // спим

}

}

// публичные сеттеры/геттеры

public int X

{

get { return (int)x; } // чтение координаты х

}

public int Y

{

get { return (int)y; } // чтение координаты х

}

public double setY

{

set { y = value; } // запись координаты у

}

public double setX

{

set { x = value; } // запись координаты х

}

public bool isStopped { get { return! this.th.IsAlive; } }

}

class Charger: Ship // Класс заправщика

{

public Charger (): base (10)

{

this.speedY = 0;

this.y = 225; // начальная позиция по высоте (орбита Земли)

this.x = 230;

this.fi = -Math.PI / 2 — 0.05; // начальная позиция на окружности орбиты

Stop (); // останавливаем запущенный поток для движения кораблей

StartCh (); // запускаем движение по стабильной орбите против часовой стрелки

}

public void StartCh ()

{

if (live == false)

{

th.Abort (); // Отключаем стандартный поток кораблей

live = true;

th = new Thread (new ThreadStart (Move)); // Создаем новый поток с другой функцией движения

th.Start (); // Стартуем поток

}

}

void Move ()

{

while (live) // пока поток жив

{

speedY = 12 * Math. Cos (fi);

speedX = 12 * Math. Sin (fi);

if (y > 415) y -= 0.27; else y -= 0.05;

x += speedX; y += speedY; // движемся

if (fi < 2 * Math. PI) fi += 0.065; // изменяем угол фи

else fi = 0;

Thread.Sleep (60); // спим

}

}

}

// основной класс, использующий формы

class Program: Form

{

Ship[] ship;

Charger charger;

Controls ContForm;

int num;

int s1, s2; // Номера встретившихся кораблей

Thread th;

bool live;

// Констуктор

public Program ()

{

num = 1; // стартовое кол-во кораблей

Text = «Objects»; // заголовок окна

Size = new Size (675, 675); // размер окна

FormBorderStyle = FormBorderStyle. FixedSingle;

FormClosed += new FormClosedEventHandler (exit);

this.Show (); // показываем

Location = new Point (200, 50); // позиционируем окно

ContForm = new Controls (); // подключаем класс формы с кнопками управления

ContForm.but += new delBut (ButPressed); // привязываем события нажатия кнопок

ship = new Ship[10]; // Массив из 10 кораблей

charger = new Charger ();

for (int i = 0; i < num; i++) // Перебираем массив кораблей

{

ship[i] = new Ship (i); // Создаем новый объект-корабль и помещаем его в массив

ship[i]. ev += new delEv (MainEvent); // привязываем обработчик событий

}

DoubleBuffered = true; // буферизация — устраняет мелькание

live = true; // стартуем

th = new Thread (new ThreadStart (run));

th.Start ();

}

// потоковая функция

void run ()

{

while (live)

{

// перебираем корабли

for (int i = 0; i < num; i++)

{

if (Math.Abs (ship[i]. X — charger. X) < 20 && Math. Abs (ship[i]. Y — charger. Y) < 20) // Заправка

if (!charger.isStopped)

{

if (ship[i]. fuel <= 89) ship[i]. fuel += 10; else ship[i]. fuel = 99;

}

if (ship[i]. fuel <= 0) // Если кончается топливо, корабль «исчезает» .

{

ship[i]. Stop ();

ship[i].setX = 1000;

ship[i]. setY = 1000 + 50*i;

this.Invoke (new EventHandler (delegate // Сообщение статуса

{

ContForm.SetStatus (i, «Исчез»);

}));

}

for (int j = i + 1; j < num; j++)

{

if (i < j) // Уступает корабль с бОльшим номером

{

s2 = j;

s1 = i;

}

else

{

s2 = i;

s1 = j;

}

if (Math.Abs (ship[s1]. X — ship[s2]. X) < 20 && Math. Abs (ship[s1]. Y — ship[s2]. Y) < 20)

{

ship[s2]. vstrecha = true; // Встреча началась

if (!ship[s1]. isStopped && !ship[s2]. isStopped) ship[s2]. Stop ();

this.Invoke (new EventHandler (delegate

{

if (ContForm.IsntDisappeared (s2)) ContForm. SetStatus (s2, «Уступает»);

}));

}

else if (ship[s2]. vstrecha)

{

ship[s2].Start (); // Если пропускал, то продолжить движение

ship[s2]. vstrecha = false; // Встреча закончилась

this.Invoke (new EventHandler (delegate // Сообщение статуса

{

ContForm.SetStatus (s2, «В полёте»);

}));

}

}

//Invalidate ();

Thread.Sleep (31);

}

}

}

// обработчик события

void MainEvent ()

{

Invalidate ();

}

// перерисовка содержимого окна

protected override void OnPaint (PaintEventArgs arg)

{

Pen grayPen = new Pen (Color.LightGray);

Pen blackPen = new Pen (Color.Black);

Brush blackBrush = new SolidBrush (Color.Black);

Brush whiteBrush = new SolidBrush (Color.White);

Brush greenBrush = new SolidBrush (Color.Lime);

Font ArialF = new Font («Arial», 10);

arg.Graphics.FillRectangle (blackBrush, 0,0,1280,960); // Фон

arg.Graphics.FillRectangle (whiteBrush, 100, 150, 2, 2); // Звезды

arg.Graphics.DrawEllipse (grayPen, 40, 230, 370, 370); // Орбита Земли

arg.Graphics.DrawEllipse (grayPen, 468, 28, 162, 162); // Орбита Луны

arg.Graphics.FillEllipse (new SolidBrush (Color.DeepSkyBlue), 100, 290, 250, 250); // Земля

arg.Graphics.FillEllipse (new SolidBrush (Color.DarkKhaki), 500, 60, 100, 100); // Луна

for (int i = 0; i < num; i++) // перебираем корабли

{

arg.Graphics.FillEllipse (greenBrush, ship[i]. X, ship[i]. Y, 16, 16); // корабль

arg.Graphics.DrawEllipse (blackPen, ship[i]. X, ship[i]. Y, 16, 16); // обводим корабль

arg.Graphics.DrawString (ship[i]. id + «», ArialF, blackBrush, ship[i]. X + 4, ship[i]. Y); // номер

arg.Graphics.DrawString (Math.Round (ship[i]. fuel) + «», ArialF, whiteBrush, ship[i]. X — 1, ship[i]. Y — 15); // топливо

}

arg.Graphics.FillEllipse (new SolidBrush (Color.DarkRed), charger. X, charger. Y, 16, 16); // заправщик

arg.Graphics.DrawEllipse (blackPen, charger. X, charger. Y, 16, 16); // обводим корабль

arg.Graphics.DrawString («C», ArialF, blackBrush, charger. X + 2, charger. Y); // номер

}

// обработчик событий кнопок формы управления

void ButPressed (string btn, int numship)

{

if (btn == «add»)

{

if (num < 10)

{ // если кол-во < 10

ship[num] = new Ship (num); // создаём

ship[num]. ev += new delEv (MainEvent); // привязываем

ContForm.SetStatus (num, «В полёте»);

num++;

}

else

{

MessageBox.Show («Не больше 10!»);

}

}

else if (btn == «start»)

{

for (int i = 0; i < num; i++)

{

if (ContForm.IsntDisappeared (i))

{

ship[i]. Start (); // стартуем все корабли, кроме исчезнувших

ContForm.SetStatus (i, «В полёте»);

}

}

charger.StartCh ();

}

else if (btn == «stop»)

{

for (int j = 0; j < num; j++)

{

if (ContForm.IsntDisappeared (j))

{

ship[j]. Stop (); // приостанавливаем все корабли

ContForm.SetStatus (j, «Остановлен»);

}

}

charger.Stop ();

}

else if (btn == «fuel») // добавляем 20 единиц топлива

{

//for (int i = 0; i < num; i++) ship[i]. fuel = 99; // для отладки

if (ship[numship] ≠ null)

{

ship[numship]. fuel += 20;

if (ship[numship]. fuel > 99) ship[numship]. fuel = 99; // если значение топлива превысит 99, то устанавливается в 99

}

}

}

// событие закрытия окна, завершаем потоки и зaкрываем программу

protected override void OnClosed (EventArgs args)

{

exit (null, null);

}

// обработчик выхода из программы

void exit (object obj, EventArgs arg)

{

for (int i = 0; i < num; i++)

{

ship[i]. Stop ();

}

charger.Stop ();

th.Abort ();

th.Join ();

Application.Exit ();

}

// основная функция

static void Main ()

{

Program prog = new Program (); // создаём ссылку на класс, инициализируем

Application.EnableVisualStyles ();

Application.Run (prog); // запускаем программу по созданной ссылке

}

}

}

Приложение 3. Текст программы на языке Java

import java.util.*;

import java.awt.*;

import java.awt.event.*;

class Ship extends Observable implements Runnable// Класс корабля

{

protected Thread th;

public int id; // Порядковый номер корабля

protected boolean live;

protected double x, y; // позиция

protected double speedX, speedY; // скорость

protected double fi; // положение на окружности орбиты

public double fuel; // топливо

protected boolean WasOnMoon; // был ли на Луне

protected boolean start1; // только что стартовал

protected boolean comeback1; // первое возвращение

public boolean vstrecha; // индикатор встречи

public Ship (int ns)// Конструктор

{

this.id = ns; // Записываем номер корабля

this.live = false; // первоначально не движемся

this.x = 160; // начальная позиция (поверхность Земли)

this.y = 300; // начальная позиция по высоте (поверхность Земли)

this.speedX = 0; // скорость движения по горизонтали

this.speedY = -3; // скорость движения по вертикали (старт с Земли)

this.fuel = 50; // начальный запас топлива

this.fi = Math. PI;

this.WasOnMoon = false; // на Луне не был

this.start1 = true; // первый старт — да

this.comeback1 = false; // первое возвращение — нет

this.vstrecha = false; // встречи нет

Start (); // запускаем движение

}

public void Start () // Функция старта

{

if (live == false)

{

live = true;

th = new Thread (this); // Создаем объект-поток «движение корабля»

th.start (); // Стартуем поток

}

}

public void Stop ()// Функия остановки

{

live = false;

}

public void run () // Выполнить поток

{

while (live) // Пока существует, выполнять

{

if ((x > 0 && x < 420 && y > 210 && y < 600) && !(x == 160 && y > 232)) // Орбита Земли

{

if (WasOnMoon == false) // Если на Луне еще не был, разгон

{ // по орбите и полет к Луне

if (start1)

{

fi = -Math.PI / 2 — 0.2;

start1 = false;

}

speedY = 6 * Math. cos (fi);

speedX = -6 * Math. sin (fi);

y -= 0.16;

if (fi > Math. PI / 2) fuel -= 0.5; // Разгон: топливо уменьшается

else fuel -= 0.05;

}

else // Если возвращается с Луны, становится на орбиту

{ // с вращением против часовой стрелки

if (comeback1 && x < 230)

{

fi = -Math.PI / 2;

comeback1 = false;

}

if (!comeback1)

{

speedY = 6 * Math. cos (fi);

speedX = 6 * Math. sin (fi);

y -= 0.05;

fuel -= 0.05;

}

}

}

if (x == 160 && y > 225 && y < 235) // Земля — Луна

{

speedX = -speedY + 3;

};

if (x > 465 && x < 630 && y < 180) // Орбита Луны

{

if (!WasOnMoon)

{

fi = Math. PI + 0.4;

WasOnMoon = true;

comeback1 = true;

}

speedY = 4 * Math. cos (fi);

speedX = -4 * Math. sin (fi);

x += 0.04;

if (fi > Math. PI * 2 — 0.3 || fi < Math. PI / 2) fuel -= 0.5; // Разгон: топливо уменьшается

else fuel -= 0.05;

}

x += speedX; y += speedY; // движемся

if (fi < 2 * Math. PI) // изменяем угол фи

{

if (x > 425) fi += 0.051;

else fi += 0.032;

}

else fi = 0;

try

{

Thread.sleep (60); // спим

}

catch (InterruptedException iE) { }

setChanged ();

notifyObservers (new Integer (0));

}

}

// публичные сеттеры/геттеры

public double X ()

{

return x; // чтение координаты х

}

public double Y ()

{

return y; // чтение координаты у

}

public void setY (double value)

{

y = value; // запись координаты у

}

public void setX (double value)

{

x = value; // запись координаты х

}

public boolean isStopped () { return! this.th.isAlive (); }

}

class Charger extends Ship// Класс заправщика

{

public Charger ()

{

super (10);

this.speedY = 0;

this.y = 225; // начальная позиция по высоте (орбита Земли)

this.x = 230;

this.fi = -Math.PI / 2 — 0.05; // начальная позиция на окружности орбиты

Stop (); // останавливаем запущенный поток для движения кораблей

StartCh (); // запускаем движение по стабильной орбите против часовой стрелки

}

public void StartCh ()

{

if (live == false)

{

th.interrupt (); // Отключаем стандартный поток кораблей

live = true;

th = new Thread (this); // Создаем новый поток с другой функцией движения

th.start (); // Стартуем поток

}

}

public void run ()

{

while (live) // пока поток жив

{

speedY = 9 * Math. cos (fi);

speedX = 9 * Math. sin (fi);

if (y > 415) y -= 0.21;

x += speedX; y += speedY; // движемся

if (fi < 2 * Math. PI) fi += 0.049; // изменяем угол фи

else fi = 0;

try

{

th.sleep (60); // спим

}

catch (InterruptedException iE) { }

setChanged ();

notifyObservers (new Integer (0));

}

}

}

class Program extends Frame implements Observer// Класс формы с объектами

{

Ship[] ship;

Charger charger;

public int num;

int s1, s2; // Номера встретившихся кораблей

private double dx, dy;

Thread th;

private boolean live;

protected int numship;

public Program () // Конструктор

{

num = 1; // стартовое кол-во кораблей

this.setTitle («Objects»); // заголовок окна

this.setSize (675, 675); // размер окна

this.setResizable (false);

this.setLocation (200, 50);// позиционируем окно

ship = new Ship[10]; // Массив из 10 кораблей (макс)

for (int i = 0; i < num; i++) // Перебираем массив кораблей

{

ship[i] = new Ship (i); // Создаем новый объект-корабль и помещаем его в массив

ship[i]. addObserver (this);// привязываем обработчик событий

}

charger = new Charger ();

charger.addObserver (this);

this.addWindowListener (new WindowAdapter ()// Обработчик закрытия программы

{

public void windowClosing (WindowEvent wE)

{

Exit (null, null);

}

});

this.show ();

}

public void update (Observable obj, Object arg) // Обработчик события встречи

{

for (int i = 0; i < num; i++)

{

if (Math.abs (ship[i]. X () — charger. X ()) < 20 && Math. abs (ship[i]. Y () — charger. Y ()) < 20) // Заправка

if (!charger.isStopped ())

{

if (ship[i]. fuel <= 89) ship[i]. fuel += 10; else ship[i]. fuel = 99;

}

if (ship[i]. fuel <= 0) // Если кончается топливо, корабль «исчезает» .

{

ship[i]. Stop ();

ship[i].setX (1000);

ship[i].setY (1000 + 50*i);

}

for (int j = i + 1; j < num; j++)

{

if (i < j) // Уступает корабль с бОльшим номером

{

s2 = j;

s1 = i;

}

else

{

s2 = i;

s1 = j;

}

if (Math.abs (ship[s1]. X () — ship[s2]. X ()) < 20 && Math. abs (ship[s1]. Y () — ship[s2]. Y ()) < 20)

{

ship[s2]. vstrecha = true; // Встреча началась

if (!ship[s1]. isStopped () && !ship[s2]. isStopped ()) ship[s2]. Stop ();

}

else if (ship[s2]. vstrecha)

{

ship[s2].Start (); // Если пропускал, то продолжить движение

ship[s2]. vstrecha = false; // Встреча закончилась

}

}

}

repaint ();

}

public void paint (Graphics arg)

{

super.paint (arg);

Color gray = Color. gray;

Color darkGray = Color. darkGray;

Color black = Color. black;

Color white = Color. white;

setBackground (new Color (0, 0, 0)); // Фон

arg.setColor (gray);

arg.drawOval (40, 230, 370, 370); // Орбита Земли

arg.drawOval (468, 28, 162, 162); // Орбита Луны

arg.setColor (new Color (0, 128, 255));

arg.fillOval (100, 290, 250, 250); // Земля

arg.setColor (new Color (128, 128, 64));

arg.fillOval (500, 60, 100, 100); // Луна

for (int i = 0; i < num; i++) // перебираем корабли

{

arg.setColor (new Color (0, 255, 64));

arg.fillOval (System.Convert.ToInt32(ship[i]. X ()), System.Convert.ToInt32(ship[i]. Y ()), 16, 16); // корабль

arg.setColor (darkGray);

arg.drawOval (System.Convert.ToInt32(ship[i]. X ()), System.Convert.ToInt32(ship[i]. Y ()), 16, 16); // обводим корабль

arg.setColor (black);

arg.drawString (System.Convert.ToString (ship[i]. id), System.Convert.ToInt32(ship[i]. X () + 4), System.Convert.ToInt32(ship[i]. Y ()+12)); // номер

arg.setColor (white);

arg.drawString (System.Convert.ToString (Math.round (ship[i]. fuel)), System.Convert.ToInt32(ship[i]. X () — 1), System.Convert.ToInt32(ship[i]. Y () — 3));

}

arg.setColor (new Color (128, 0, 0));

arg.fillOval (System.Convert.ToInt32(charger.X ()), System.Convert.ToInt32(charger.Y ()), 16, 16); // заправщик

arg.setColor (black);

arg.drawOval (System.Convert.ToInt32(charger.X ()), System.Convert.ToInt32(charger.Y ()), 16, 16); // обводим корабль

arg.drawString («C», System.Convert.ToInt32(charger.X () + 4), System.Convert.ToInt32(charger.Y ()+12)); // номер

}

// обработчик выхода из программы

void Exit (Object obj, System. EventArgs arg)

{

for (int i = 0; i < num; i++)

{

ship[i]. Stop ();

ship[i].th.interrupt ();

}

charger.Stop ();

charger.th.interrupt ();

System.exit (0);

}

}

class Controls extends Frame implements ActionListener // Класс окон с кнопками

{

Program prog;// Форма с объектами

Button AddShip; // Добавить новый корабль

Button AddFuel; // Добавить топливо

Button Pause; // Приостановка всех кораблей

TextField numShip; // Номер корабля, которому добавляется топливо

Point[] Koord;

TextField[] Sost; // Сообщения о состоянии кораблей

Frame ctrl, Info;

public Controls ()

{

prog = new Program ();// Создаем окно с объектами

// текстовое поле

numShip = new TextField ();

numShip.setLocation (35, 20);

numShip.setText («0»);

numShip.setSize (65, 25);

// кнопки

AddShip = new Button («Добавить корабль»);

AddShip.setLocation (10, 50);

AddShip.setSize (120, 25);

AddShip.addActionListener (new ActionListener ()

{

public void actionPerformed (ActionEvent aE)

{

if (prog.num < 10)

{ // если кол-во < 10

prog.ship[prog.num] = new Ship (prog.num); // создаём

prog.ship[prog.num]. addObserver (prog); // привязываем

SetStatus (prog.num, «В полёте»);

prog.num++;

}

else

{

System.Windows.Forms.MessageBox.Show («Не больше 10!»);

}

}

});

AddFuel = new Button («Добавить топливо»);

AddFuel.setLocation (10, 80);

AddFuel.setSize (120, 25);

AddFuel.addActionListener (new ActionListener ()

{

public void actionPerformed (ActionEvent aE)

{

if (prog.ship[System.Convert.ToInt32(numShip.getText ())] ≠ null)

{

prog.ship[System.Convert.ToInt32(numShip.getText ())]. fuel += 20;

if (prog.ship[System.Convert.ToInt32(numShip.getText ())]. fuel > 99)

prog.ship[System.Convert.ToInt32(numShip.getText ())]. fuel = 99;

}

}

});

Pause = new Button («Пауза»);

Показать весь текст
Заполнить форму текущей работой