Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Java Модуль 1.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
2.24 Mб
Скачать

Занятие 11. Создание компьютерной игры "Новогодний дождь" (окончание)

На этом занятии мы завершим написание компьютерной игры и увидим окончательный результат. Осталось доработать финальную часть игры –если пропущенный подарок падает вниз, и он не пойман игроком, значит,происходит окончание игры.

Прежде, чем вернуться к компьютерной игре, необходимо в корень диска C:\ поместить недостающее изображение, которое будет использоваться в игре. Поместим туда изображение, символизирующее окончание игры – файл под названием end_game.png. Это изображение будет выводиться момент завершения игры (см. рисунок 67).

Рисунок 67

Размер изображения 240 пикселей в ширину и 38 пикселей в высоту. Для этих целей можно использовать и другое изображение. Откроем программу. Она состоит из 4 классов. На сегодняшнем занятии осталось доработать лишь класс pole.Остальные 3 класса представляют собой законченный вариант, их программный код меняться уже не будет. Осталось доработать финальную часть – завершение игры.Запустим программу на исполнение. Пока мы имеем игру, не имеющую окончания,работающую бесконечно, т. к. наши подарки, падая вниз, даже если они пропускаются, просто исчезают с игрового поля. Окончания игры не происходит.Доработаем программу. К имеющимся переменным класса добавим еще одну:переменная закрытого (private) типа Image (картинка), под названием end_game:

private Image shapka; // Закрытая Переменная класса, в которую загружается шапка

private Image fon; // Закрытая Переменная класса, в которую загружается фон

public int x = 400; // Открытая Переменная класса, в которую загружается шапка

private int slogn; // Переменная сложности игры

private podar[] gamePodar; // Массив подарков

private Image end_game; // Изображение Окончания игры

Это изображение, отвечающее за окончание игры, добавленное в корень диска C:\. Далее запишем строки программного кода, который загружает изображение в программу. Чтобы их записать – давайте скопируем строки для загрузки изображения фона, вставим их ниже и несколько изменим, получится следующее:

// Загрузка изображения фона из файла

try

{

fon = ImageIO.read(new File("c:\\fon.png"));

}

catch(IOException ex) {}

//Загрузка изображения Окончания игры

try

{

end_game = ImageIO.read(new File("c:\\end_game.png"));

}

catch(IOException ex) {}

Корректировки были следующие: вместо переменной fon указана переменная end_game, вместо названия файла fon.png указано название файла end_game.png. Таким образом, в переменную end_game загружается файл, изображение под названием end_game.png, символизирующее окончание игры. Это изображение будет выведено в центральную часть игрового поля в случае, если игроку не удастся поймать хотя бы один подарок. Далее, перейдём в ту часть программного кода, где определяются таймеры. У нас 2 таймера: первый называется timerUpdate,второй – timerDraw. Таймер timerUpdateотвечает за появление подарка на игровом поле в верхней части, он срабатывает раз в 3 секунды. Таймер timerDrawотвечает за перерисовку игрового поля, делает он это 20 раз в секунду. Сделаем следующее: объявим эти 2 таймера как переменные класса, объявим их в самой верхней части класса. Это даст возможность обращаться к таймерам из других методов класса, эти переменные будут там доступны. Удаляем название типа (Timer) в описании таймера timerUpdate и удаляем название типа (Timer) в описании таймера timerDraw.

timerUpdate = new Timer(3000,new ActionListener() { //Слева удален тип Time

public void actionPerformed(ActionEvent e) {

updateStart(); // Метод для проверки и добавление подарков на игровое поле

}

});

timerUpdate.start(); // Запуск таймера timerUpdate

timerDraw = new Timer(50,new ActionListener() { // Слева удален тип Timer

public void actionPerformed(ActionEvent e) {

repaint(); // Запуск метода перерисовки поля (public void paintComponent(Graphics gr))

}

});

timerDraw.start(); //Запуск таймера для перерисовки

Далее перемещаемся в верхнюю часть класса, добавляем здесь еще 2 переменные, открытые, public,указываем тип Timer, далее – название таймеров –timerUpdate,и, через запятую, второй таймер – timerDraw.

private Image shapka; // Закрытая Переменная класса, в которую загружается шапка

private Image fon; // Закрытая Переменная класса, в которую загружается фон

public int x = 400; // Открытая Переменная класса, в которую загружается шапка

private int slogn; // Переменная сложности игры

private podar[] gamePodar; // Массив подарков

private Image end_game; // Изображение Окончания игры

public Timer timerUpdate,timerDraw; // Два таймера

Таким образом, 2 таймера объявлены как переменные класса,теперь с ними можно работать из любого места программы внутри класса, т. е., из любого другого метода. Раньше эти 2 таймера были описаны внутри конструктора класса, за пределами этого конструктора к ним обратиться было нельзя. Допустим,если бы в определенный момент понадобилось их остановить, например, из метода updateStart(), сделать это было бы невозможно, так как эти переменные раньше были объявлены только внутри конструктора класса, за пределами конструктора они были недоступны. Объявив их как переменные в самом верху класса, мы получили возможность доступа к ним из любого другого метода класса.

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

Переместимся в метод paintComponent(),в цикл, где производится отрисовка подарков на игровом поле. Этот цикл постоянно пробегает массив с подарками и рисует их на игровом поле. Поставим проверку внутри этого цикла: после отрисовки очередного подарка, если подарок находится у самой нижней границы, и под ним не присутствует шапка, считаем, что игра закончена и выводим изображение end_game. Цикл for в paintComponent()необходимо дополнить таким кодом:

// Цикл, который отображает подарки на игровом поле и проверяет пропущенные подарки

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

{

gamePodar[i].draw(gr); // Отображение подарка

if (gamePodar[i].act==true) // Если подарок из массива подарков активен

{

// Если подарок достиг нижней границы

if ((gamePodar[i].y+gamePodar[i].img.getHeight(null))>=470)

{

if (Math.abs(gamePodar[i].x - x) > 75) // Если подарок пропущен

{

gr.drawImage(end_game, 300, 300, null); // Вывод картинки Окончания игры

timerDraw.stop(); // Оставнока таймера timerDraw

timerUpdate.stop(); // Оставнока таймера timerUpdate

break; // Прерывание цикла

}

else gamePodar[i].act=false; // Снятие подарка с игрового поля,если он пойман шапкой

}

}

}

Здесь задействована конструкция if.В круглых скобках конструкции if идёт обращение к названию массива подарков gamePodar,внутри квадратных скобок указано значение переменной i.Значение переменной iменяется внутри цикла for, она проходит значение 0, 1, 2, 3, 4, 5,6, и цикл for последовательно обращается ко всем подаркам, находящимся в массиве. Происходит проверка: если активность подарка равна true (истина),подарок активен на игровом поле. Если он неактивен, смысла его проверять нет,так как его нет на игровом поле. Поэтому первая проверка – это проверка факта присутствия подарка на игровом поле. Далее идёт проверка, достиг ли подарок нижней границы. Для этого используется другая конструкция if, если. В ее круглых скобках указано условие: если отступ верхней части подарка от верхней части игрового поля(координата y текущего подарка в пикселях),плюс высота этого подарка больше либо равно 470, это значит, что подарок достиг самой нижней границы. Т. е., в круглых скобках оператора if сравниваются между собой две величины.

Первая величина – это сумма: (координата у текущего подарка gamePodar[i].y) + высота подарка (gamePodar[i].img.getHeigth (null)). Вторая величина – это нижняя граница по y, на которой находится шапка деда Мороза (предельная нижняя граница для местоположения подарка), т.е., 470 пикселей. Рассмотрим подробнее программный код каждой из этих составляющих.

Координата у текущего подарка: gamePodar[i].y: т.е. в этом случае идёт последовательное обращение ко всем 7 подаркам,находящимся в массиве gamePodar[i],и определяется величина отступа верхней части текущего подарка от верхней части игрового поля (координата у). Высота подарка gamePodar[i].img.getHeigth(null).

Здесь также идёт последовательное обращениеко всем 7 подаркам, находящимся в массиве gamePodar[i], и определяется свойство текущего подарка, картинки img– высота. Картинку, характеризующую подарок, мы описывали внутри класса podar. Откроем его на некоторое время. Одна из переменных, описанных в этом классе, называется img, ей присвоен тип Image, картинка. Метод getHeigth() возвращает высоту картинки в пикселях – определяет её автоматически. В нашем случае высота всех картинок 80 пикселей, но мы оставим этот метод – пусть он автоматически вычисляет высоту картинки – на тот случай, если мы захотим поместить картинки другой высоты. Тогда программа все равно будет работать правильно. 470 пикселей– это отступ сверху, и 470 пикселей – это как раз нижняя граница, где находится верхняя часть шапки деда Мороза. Таким образом, если выполняется условие if, то подарок либо начал пересекать самую нижнюю границу, либо уже её чуть-чуть пересёк. Далее, после условия конструкции if, идет программный код внутри открывающей и закрывающей фигурной скобки. Они определяют тело оператора if. Все действия, описанные в теле оператора if, выполняются, только если выполняется условие,записанное выше, в круглых скобках. Каждый оператор if имеет свое тело, заключённое в фигурные скобки. Если посмотреть на первый оператор if,записанный выше, проверяющий активность подарка, его тело содержит в себе другой, вложенный оператор if. Таким образом, вложенный оператор ifсрабатывает только в том случае, если выполняется вышестоящий оператор: т. е.,если подарок активен, присутствует на игровом поле. В этом случае происходит проверка: в каком положении находится подарок – в самом нижнем или ещё нет. В тело вложенного оператора if помещена ещё одна конструкция if, чтобы проверить, в каком месте по оси x находится в данный текущий момент шапка Деда Мороза – под подарком или нет. В круглых скобках, где записывается условие если, снова идёт обращение к массиву подарковgamePodar[i],через квадратные скобки – к текущему подарку i,и, далее, к его координате x. Координата x – это отступ в пикселях от левой части игрового поля, положение подарка по горизонтали. Из этого значения вычитается значение координаты x – координаты шапки Деда Мороза. Перейдём на время в верхнюю часть класса. Переменная x, объявлена как переменная класса целого типа и изначально равна 400. 400 – как раз и есть начальное положение шапочки на игровом поле. Вычитая одно значение из другого, получаем интервал, расстояние в пикселях между шапочкой и подарком.

Дадим пользователю некоторый запасной интервал. Допустим,шапка Деда Мороза ловит хотя бы половину подарка – мы это зачитываем игроку как пойманный подарок, – не требуем, чтобы шапка была строго под подарком. Поэтому условие выглядит так: если разница координат xменьше 75, то у пользователя есть запас 75 пикселей вправо или влево - шапку он может держать не совсем точно. Но если она находится дальше, значит, она где-то уже совсем в стороне, и подарок действительно пропущен.

Мы записали разницу в координатах по x.Может получиться, что шапка находится правее подарка, если он падает в левой части игрового поля, а шапка находится в правой. Тогда, значение координаты x шапки больше, чем значение координаты x подарка, и, при вычитании одного из другого, получается отрицательное значение. Нас же интересует само расстояние между объектами,поэтому нам нужно получать здесь всегда положительное значение. Для таких случаев используется модуль. Чтобы записать модуль, обращаемся к классу под названием Math,через оператор (.) вызываем метод abs().Метод abs() берёт модуль значения,помещённого внутри его круглых скобок, в данном случае, разницу между координатами. Модуль работает так: он убирает знак минус (-).Если значение изначально положительное, оно так и остается положительным; если значение отрицательное – становится положительным. Например, модуль -5есть 5. Таким образом, используя модуль, можно исключить возникновение отрицательных чисел.

Если условие выполняется, пользователь подарок пропустил,так как интервал между шапочкой и подарком более 75 пикселей. Это означает окончание игры. Если подарок пропущен, то выполняется следующее: метод,записанный в первой строке, выводит изображение, символизирующее окончание игры. Обращаемся к переменной типа Graphics с названием gr (через эту переменную всегда производится рисование каких-то элементов), через оператор (.) вызываем метод drawImage().Внутри круглых скобок метода drawImage() указываем изображение, которое нужно вывести, в данном случае, это end_game (именно в эту переменную загружена картинка,символизирующая окончание игры). Указываем координаты её верхней левой угловой точки x и y.Это, соответственно, отступ в пикселях слева и отступ в пикселях сверху, берем 300,300, последний параметр – null– не указывается.

Далее идёт обращение к таймеру timerDrawи, через оператор (.), вызывается команда stop(),– останавливается таймер, отвечающий за отрисовку игрового поля, так как игра закончена. Точно так же идёт обращение к таймеру timerUpdate,отвечающему за обновление игрового поля, т. е., за выведение подарков сверху;через оператор (.) вызывается для него метод stop(). Таймеры остановлены. И последнее – прерывание цикла for при помощи оператора break. Так как игра закончилась, дальше продолжать цикл смысла нет. Самый внутренний оператор if имеет и вторую часть else (иначе) - в ней активность подарка устанавливается false (ложь).Получается, что эта часть срабатывает, если подарок пойман, его активность делается false (ложь)и он убирается с поля.

Попробуем сыграть в игру, выбираем максимальную сложность.Начинают появляться подарки, сложность максимальная, поэтому приходится ловить подарки максимально энергично. В определенный момент пропустим один подарок, не будем его ловить. Мы увидели окончание игры. В момент, когда подарок был пропущен, появляется сообщение об окончании игры, ENDGAME. По нажатию клавиши Escape можно выйти из игры.

Теперь можно сказать об успешном окончании создания нашей игры!!!

Игра состоит их четырех классов. Ниже приведен полный программный код всей игры:

Класс game:

// Подключения необходимых библиотек

import javax.swing.*;

// Главный класс игры

public class game {

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

public static void main(String[] args) {

// Вызов диалогового окна для ввода сложности игры

String rez =

JOptionPane.showInputDialog(null,"Введите сложность игры от 1до 7:","Сложность игры",1);

// Помещение результата выбора в переменную целого типа

int slogn = rez.charAt(0)-'0';

// Проверка, что введена цифра от 1 до 7

if ((slogn>=1)&&(slogn<=7))

{

// Создание окна, в котором находится игровое поле

okno window = new okno(slogn);

}

}

}

Класс okno:

// Подключения необходимых библиотек

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

// Класс окна, в котором размещено игровое поле

class okno extends JFrame

{

private pole gameP; // Закрытая Переменная класса - игровое поле

private int slogn; // Закрытая Переменная класса - сложность игры

// Обработчик событий нажатий на клавиши

private class myKey implements KeyListener

{

// Метод, который срабатывает при нажатии

public void keyPressed(KeyEvent e)

{

// Получение кода нажатой клавиши

int key_ = e.getKeyCode();

// Выход из программы, если нажат - Esc

if (key_==27) System.exit(0);

else if (key_==37) // Если нажата стрелка влево

{

// Контроль перемещения влево за пределы окна

if (gameP.x-30>-48) gameP.x-=30;

else gameP.x=752;

}

else if (key_==39) // Если нажата стрелка вправо

{

// Контроль перемещения вправо за пределы окна

if (gameP.x+30<752) gameP.x+=30;

else gameP.x=-48;

}

}

public void keyReleased(KeyEvent e) {}

public void keyTyped(KeyEvent e) {}

}

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

public okno(int slogn)

{

// Помещение сложности, выбранной пользователем в переменную класса

this.slogn = slogn;

// Подключение обработчика события для клавиатуры к окну

addKeyListener(new myKey());

// Установка активности окна

setFocusable(true);

// Задание размеров и положения окна

setBounds(0,0,800,600);

// Задание заголовка окна

setTitle("Игра: Новогодний дождь");

// Создание объекта - игрового поля

gameP = new pole(slogn);

// Прикрепление (вложение) панели - игрового поля в окно

Container con = getContentPane();

con.add(gameP);

// Сделать окно видимым

setVisible(true);

}

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]