- •Введение
- •Занятие 1. Знакомство с языком программирования Java
- •Занятие 2. Работа с переменными
- •Import javax.Swing.*; // Подключение библиотеки для работы с окнами
- •Следующая тема нашего занятия – Переменные.
- •Занятие 3. Основные алгоритмические конструкции
- •Занятие 4. Основы объектно-ориентированного программирования
- •Import javax.Swing.*; // Подключение библиотеки для работы с окнами
- •Занятие 5. Основы компьютерной графики языка Java
- •Занятие 6. Работа с графическими изображениями
- •Занятие 7. Конструкторы классов, обработчики событий
- •Занятие 8. Создание компьютерной игры "Новогодний дождь" (начало)
- •Занятие 9. Создание компьютерной игры "Новогодний дождь" (продолжение)
- •Занятие 10. Создание компьютерной игры "Новогодний дождь" (продолжение)
- •Занятие 11. Создание компьютерной игры "Новогодний дождь" (окончание)
- •Класс pole:
- •Класс podar:
- •Занятие 12. Создание jar-архива игры "Новогодний дождь"
- •Заключение
Занятие 8. Создание компьютерной игры "Новогодний дождь" (начало)
На этом занятии мы начнём создавать компьютерную игру.
Каждый класс – это отдельный файл, имя класса должно всегда совпадать с именем файла с учётом регистра букв (маленькая и заглавная – разные буквы). Ранее все созданные классы мы размещали в одном файле. Cоздадим новый проект и назовём его game. В дальнейшем этот проект мы будем использовать в течение нескольких занятий, дорабатывая его до тех пор, пока не закончим писать нашу первую компьютерную игру.
На предыдущих занятиях использовался фрагмент программы,состоящий из трёх классов.
Используя тот программный код, создадим три класса внутри проекта game. Классы назовем game, okno, pole (см. рисунок 57).
Рисунок 57
Каждый класс будет находиться на отдельной закладке, в отдельном файле (см. рисунок 58). В эти файлы вставим программные коды,созданные ранее. Класс будет game главным классом программы, в классе okno будет класс описывающий окно в котором будет находиться игровое поле и класс pole будет описывать игровое поле, на котором все будет происходить.
Рисунок 58
В класс game поместим следующий программный код:
//Главный класс игры
public class game {
//Главный метод, который запускает игру
public static void main(String[] args) {
// Создание окна, в котором находится игровое поле
okno window = new okno();
}
}
В класс okno поместим следующий программный код:
//Подключения необходимых библиотек
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
//Класс окна, в котором размещено игровое поле
class okno extends JFrame
{
private pole gameP; // Закрытая Переменная класса - игровое поле
// Обработчик событий нажатий на клавиши
private class myKey implements KeyListener
{
// Метод, который срабатывает при нажатии
public void keyPressed(KeyEvent e)
{
// Получение кода нажатой клавиши
int key_ = e.getKeyCode();
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
}
//Конструктор класса
public okno()
{
// Подключение обработчика события для клавиатуры к окну
addKeyListener(new myKey());
//Установка активности окна
setFocusable(true);
// Задание размеров и положения окна
setBounds(0,0,800,600);
// Задание заголовка окна
setTitle("Игра: Новогодний дождь");
// Создание объекта - игрового поля
gameP = new pole();
// Прикрепление (вложение) панели - игрового поля в окно
Container con = getContentPane();
con.add(gameP);
// Сделать окно видимым
setVisible(true);
}
}
В класс pole поместим следующий программный код:
//Подключения необходимых библиотек
import javax.imageio.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
//Класс панели, которая является игровым полем
class pole extends JPanel
{
// Конструктор класса
public pole()
{
//Создание таймера, который будет перерисовывать игровое поле //20 раз в секунду
Timer timerDraw = new Timer(50,new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Запуск метода перерисовки поля (public void paintComponent(Graphics gr))
repaint();
}
});
timerDraw.start(); // Запуск таймерадля перерисовки
}
// Метод, который отрисовывает графические объекты на панели
public void paintComponent(Graphics gr)
{
}
}
Вкратце рассмотрим, что описывает этот программный код.Здесь есть главный класс программы под названием game,название класса совпадает с именем файла. Т. е., game.java – название файла, game– название класса. Внутри этого класса находится метод main.Он производит старт приложения, или, другими словами, запуск приложения происходит при помощи метода main. Внутри метода main написана лишь одна строка, в ней создаётся объект. Объект – окно, которое в дальнейшем выводится на экран.Внутри окна находится игровое поле и, соответственно, в нём будет размещаться игра. Таким образом, внутри класса game создаётся окно, а всё,что происходит внутри этого окна и настройки окна – будет реализовано в следующих двух классах. Соответственно, в классе okno будет описано всё, что связано непосредственно с окном. В классе pole –всё, что связано с панелью, которая вкладывается внутрь этого окна и которая является игровым полем. В классе okno создаётся класс для окна.Он наследуется от класса JFrame, класса всех окон. В самом начале определена одна переменная под названием gameP.
private pole gameP; // Закрытая Переменная класса -игровое поле
Эта переменная связана с панелью, которая вкладывается внутрь окна. Далее идёт фрагмент программного кода, отвечающий за обработку нажатых клавиш:
// Обработчик событий нажатий на клавиши
private class myKey implements KeyListener
{
// Метод, которыйсрабатывает при нажатии
public void keyPressed(KeyEvent e)
{
// Получение кода нажатойклавиши
int key_ = e.getKeyCode();
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
}
Похожий фрагмент мы уже использовали.
В строке
int key_ = e.getKeyCode();
сканируется код нажатой клавиши пользователя, и далее мы сможем его обработать. Затем идёт конструктор класса:
public okno()
Конструктор – метод, производящий инициализацию, стартовые действия при создании объекта. В данном случае, подключается обработчик событий для клавиатуры, обработчик событий myKey,описанный выше:
addKeyListener(new myKey());
В строке:
setFocusable(true);
окно делается активным, становится в фокусе.
Затем, в строках:
setBounds(0,0,800,600);
setTitle("Игра: Новогодний дождь");
задаются размеры, расположение окна и его название. Окно для игры выбираем размером 800x600.
Затем создаётся панель, которая будет вкладываться в окно:
gameP = new pole();
Container con = getContentPane();
con.add(gameP);
Класс для панели находится рядом на другой закладке. И наконец, окно делается видимым, т. е., отображается строкой:
setVisible(true);
Это всё, что происходит внутри класса okno. Объект на основании этого класса создаётся в файле game.java.
Обратите внимание, тип переменной под названием window (тип переменной okno),как раз и есть название этого класса. То есть на основании класса okno мы в соседнем файле создаём объект.
okno window = new okno();
При создании объекта мы получаем реальное окно, видимое на экране. В самом верху класса oknoподключено три библиотеки:
import javax.swing.*; // Для работы с окнами
import java.awt.*; // Для работы с графикой
import java.awt.event.*; // Для обработки событий
Это библиотеки, позволяющие работать с окнами, работать с графикой и работать с событиями, происходящими внутри окна, т. е., позволяют подключать обработчики событий. Теперь рассмотрим программный код третьего класса pole.
В самом верху подключаются библиотеки, кроме трех вышеописанных здесь присутствуют еще две:
import javax.imageio.*;
import java.io.*;
они необходимы для загрузки файлов с изображениями, которые мы будем использовать в нашей игре. Класс poleнаследуется от класса панелей JPanel, которые вкладываются в окно. На панели окна мы будем отображать всю нашу графику, и далее будем вкладывать эту панель в окно. Внутри класса poleпервое – это конструктор класса, метод, производящий инициализацию класса.
public pole()
Он запускается сразу же при создании объекта. Как только создаётся объект, этот метод сразу срабатывает, его содержимое запускается на исполнение. Внутри конструктора происходит подключение таймера, выполняющего определённые действия через заданный промежуток времени, в данном случае, через пятьдесят тысячных секунды. Такой же таймер мы использовали на предыдущих занятиях:
// Создание таймера, который будет перерисовывать игровое
// поле 20 раз всекунду
Timer timerDraw = new Timer(50,new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Запуск метода перерисовки поля (public void paintComponent(Graphics gr))
repaint();
}});
Далее таймер запускается:
timerDraw.start();
Выполняется команда start, и таймер запускается. Без этой команды он работать не начнёт.
Внутри таймера находится один метод – repaint() – перерисовка панели. При вызове метода repaint() срабатывает метод, находящийся в самом низу класса, метод paintComponent():
// Метод,который отрисовывает графические объекты на панели
public void paintComponent(Graphics gr)
{
}
Всё, указанное внутри метода paintComponent(), будет происходить, соответственно, через каждые пятьдесят тысячных секунды. Это структура программы, которую мы использовали и рассматривали ранее. Ничего нового нет, основное отличие лишь в том, что мы разбили программу на три класса. Именно так и рекомендуется при создании программ на языке Java. Сохраним приложение: нажмём сверху слева в меню Файл → Сохранить все, и мы сохраним сразу три класса нашего приложения.
Пока наше приложение при запуске выводит только пустое окно с наименованием Игра: "Новогодний дождь".
Прежде чем приступить к доработке программы, сформулируем общиепринципы написания игр на примере игры, которую мы будем создавать.
Смысл игры заключается в следующем: в нижней части игрового поля находится шапка Деда Мороза, при помощи клавиатуры её можно перемещать вправо и влево. Сверху, случайным образом, в разных местах экрана,появляются разные новогодние подарки и падают вниз. Задача игры состоит в том,чтобы ловить их при помощи шапки Деда Мороза в нижней части экрана. Если хоть один подарок поймать не удалось - игра на этом заканчивается. В зависимости от сложности игры – на экране будет разное количество подарков, падающих вниз.
Наша первоначальная задача: создать игровое поле, то есть окно. Размер окна в нашем конкретном примере возьмем 800x600 (800 – ширина, 600– высота). Для фона игрового поля необходимо использовать готовое изображение.
В самом низу нужно отобразить шапку Деда Мороза, которую можно передвигать вправо и влево при помощи клавиатуры. Если шапка Деда Мороза выходит за пределы экрана вправо или влево, она должна появляться с другой стороны,т. е., она как бы перемещается по кругу.
Игра несложная, но на примере её создания можно изучить общие принципы написания компьютерных игр.
Три основных блока, составляющие схему реализации игры, заключаются в следующем:
Первый блок – загрузка графики, или контента. В данном случае, мы будем загружать в приложение изначально созданные и хранящиеся на диске графические файлы. Первое, что происходит при инициализации игры, на старте – загрузка графики в игру. После этого можно начать игру. Её выполнение делится на две части. Первая часть – отображение графики на игровом поле. Отображение графики на игровом поле осуществляется при помощи отдельного метода, постоянно перерисовывающего игровое поле. В данном случае, для этого используется метод paintComponent(): каждые пятьдесят тысячных секунды он заново перерисовывает игровое поле. Сначала он снова будет выводить фон игрового поля. Выводя заново фон, он полностью стирает всё, что было на игровом поле до этого, очищает поле. Далее, метод размещает все игровые объекты в заданных точках экрана. Смысл этого метода в том, что он постоянно, через равные промежутки времени отрисовывает поле. Независимо, от того, где находятся объекты: перемещаются или остаются на месте, метод перерисовки постоянно работает. Он работает отдельно, по своей схеме. Ему не важно, что делает пользователь при помощи клавиатуры. Его задача заключается только в одном - постоянно перерисовывать игровое поле с теми координатами объектов на игровом поле,которые ему будут указаны. Таймер, созданный выше, служит для перерисовки игрового поля: каждые пятьдесят тысячных секунды вызывается метод repaint() – перерисовка панели. Метод repaint() запускает на исполнение содержимое метода paintComponent().
Второй блок – изменение логики игры– изменение происходящего в игре. Допустим, пользователь нажимает какие-то клавиши. Соответственно, в программе обрабатываются данные, привязанные к этим клавишам, осуществляется выполнение действий на основе этих данных, происходят определённые изменения, видимые на экране. Допустим, изменяются координаты объекта (координаты его нахождения на игровом поле). Тогда перерисовщик отрисует игровой объект в новой точке: логическая часть программы выполнит свою работу, отрисовщик – свою.
Приступим к созданию игры. В корень диска C:\помещаем два файла: fon.png и shapka.png. Эти файлы будут загружаться из программы в самом начале при загрузке контента, загрузке графики. В режиме разработки(пока идёт разработка компьютерной игры), эти файлы будут находиться в корне диска C:\. Файлы должны быть в формате png (этот формат необходим для прозрачного фона изображений). Размеры картинки: fon.png– 800(ширина) x 600(высота), размеры картинки shapka.png - 100(ширина) x 94(высота). Изображения могут быть любыми, можно приготовить любые изображения заданных размеров и с данными наименованиями. Доработаем класс pole. В самом верху класса, над конструктором, создадим три переменных класса:
// Класс панели,которая является игровым полем
class pole extends JPanel
{
private Image shapka;
private Image fon;
public int x = 400;
// Конструктор класса
public pole()
Первые две переменные типа Image– картинка. Переменные закрытые, private, они доступны только внутри класса. Название первой переменной shapka– шапка Деда Мороза - она будет отвечать за картинку, представляющую собой шапку, в которую нужно ловить подарки. Название второй переменной – fon- данная переменная отвечает за фон игрового поля. Третья переменная целого типа int, она открытая – public, т.е., переменная доступна за пределами класса: создав объект, через оператор "."можно к ней обратиться и поменять её значение либо прочитать, т. е. узнать её текущее значение. Название переменной - x.Установим ей начальное значение 400. Эта переменная отвечает за координату шапки Деда Мороза, положение, где она находится в текущий момент.Меняя переменную x, можно менять расположение шапки при помощи клавиатуры: нажимая клавиши вправоили влево, мы будем увеличивать или уменьшать значение переменнойx. Соответственно, отрисовка шапки будет происходить уже в новой точке. Далее, загрузим графику, контент. Загрузку добавим внутри конструктора класса pole.
//Конструктор класса
public pole()
{
try
{
shapka = ImageIO.read(new File("c:\\shapka.png"));
}
catch(IOException ex) {}
try
{
fon = ImageIO.read(new File("c:\\fon.png"));
}
catch(IOException ex) {}
Почему мы поместили загрузку внутри конструктора? При создании объекта конструктор сразу же запускается на исполнение, как раз в этот момент необходимо загрузить графику.
Для того чтобы загрузить графику, была использована конструкция try-catch (конструкция попытка-исключение).Как она здесь работает? Внутри блока tryзаписывается выполняемый программный код, в переменную типа Image загружается изображение из файла с диска C:\. Команда ImageIO.read загружает изображение, т. е., связывает его с переменной shapka. Через new File происходит создание объекта типа File по указанному в скобках пути к файлу. Путь указывается в двойных кавычках и при указании пути ставятся именно две косые черты \\,т. к. одна косая черта является специальным символом. В дальнейшем, после выполнения этой операции мы можем, используя переменные shapka иfon, выводить загруженные изображения на экран. Почему же загрузка помещена в try-catch?try – попытка выполнения действий,описанных внутри фигурных скобок { } блока try. Если попытка оказывается неудачной, срабатывает блок catch. В данном случае, фигурные скобки блока catchпустые, т. е. если попытка неудачная, ничего не происходит. В каком случае попытка может оказаться неудачной? Допустим, указано имя файла, которого не существует, соответственно загрузка в этом случае не удастся, попытка окажется неуспешной. Поэтому подобные вещи указываются, прописываются внутри конструкциипопытка-исключение, try-catch.Например, можно в блоке catch вывести пользователю сообщение: Не удалось загрузить файл!, т. е. на эту ситуацию отреагировать и выполнить предусмотренные на этот случай действия, описанные в фигурных скобках блока catch. Первый блок блока try-catchзагружает шапку Деда Мороза, второй из них загружает фон игрового поля.
Часть, состоящая из двух блоков try-catch,и есть загрузка контента, загрузка графики, как раз тот первый этап, о котором говорилось в самом начале. Теперь перейдём в самый нижний метод класса pole,метод paintComponent().
Метод paintComponent() отвечает за отрисовку игрового поля,постоянно его обновляет. Если объекты перемещаются, они отображаются в новом месте. Внутри метода paintComponent() записываем три строки программного кода:
//Метод, который отрисовывает графические объекты на панели
public void paintComponent(Graphics gr)
{
super.paintComponent(gr);
gr.drawImage(fon,0,0,null);
gr.drawImage(shapka,x,465,null);
}
Первая строка super.paintComponent(gr); в скобках содержит параметр gr типа Graphics. Эта строка программного кода отвечает за перерисовку самой панели, на которой располагается наша графика.Вторая строка при помощи метода DrawImage(); выводит фон. Фон стирает всё, что было до этого на экране. Таким образом, мы производим полное очищение экрана. Первый параметр – имя переменной fon. Эта переменная связана с картинкой фона, находящейся на диске C:\.Вторая и третья переменные – это координаты верхней левой угловой точки. Если указать значения (0,0), фон отобразится в самой верхней левой точке внутри окна. Фон начнёт полностью закрывать окно с самого его начала.
Следующая строка также выводит изображение – шапку Деда Мороза.Координаты её вывода идут по следующей схеме:
Первая координата – переменная x,объявленная в классе pole и имеющая начальное значение 400. 400 – это как раз середина экрана, так как ширина экрана 800. Начальное положение шапки получится по центру экрана. Второе значение – это отступ от верхней части окна.Мы указываем 465, таким образом, шапка будет находиться в нижней части экрана. Переменную, являющуюся отступом сверху, мы указали фиксированным числом, она изменяться не будет, и шапка будет двигаться только по горизонтали,вправо или влево. Значение, определяющее сдвиг от левой части окна, мы указали как переменную x, именно её мы сможем менять в части программы, которая отвечает за изменение логики игры. Переменнаяx будет меняться именно в тот момент,когда пользователь нажмёт какую-либо клавишу на клавиатуре. Запускаем программу на исполнение. Мы увидим фон и шапку Деда Мороза (см. рисунок 59).
Рисунок 59
Мы видим окно, выведенное на экран. Оно выводится, начиная с угловой точки экрана, потому что мы указали в настройках окна координаты (0,0).Ширина окна 800 пикселей, высота окна 600 пикселей.fon – картинка, находящаяся на диске C:\, fon.png.Внизу, по центру экрана, мы видим шапку Деда Мороза, которая как раз находится в файле shapka.png. Произошла загрузка контента – загрузился фон, и загрузилась шапка Деда Мороза. В отрисовщике, методе paintComponent() через промежуток времени пятьдесят тысячных секунды, т. е., 20 раз в секунду (этого вполне достаточно), постоянно происходит такое действие: заново отрисовывается фон и заново отрисовывается шапка Деда Мороза. Так как картинки не перемещаются, картинка статическая. На самом деле происходит постоянная, очень быстрая перерисовка игрового поля: 20раз в секунду. Мы этого не видим – всё происходит слишком быстро для человеческого глаза. Отрисовщик постоянно работает благодаря запущенному таймеру, вызывающему метод repaint() через каждые пятьдесят тысячных секунды: 20 раз в секунду. Начнём теперь менять логику игры. Логика игры – это третий этап. Первые два этапа мы уже создали:первый – загрузка контента при помощи двух блоков try,второй этап – отрисовка в методе paintComponent(). И наконец, третий этап –минимальный необходимый элемент для начала функционирования игры: мы должны задать изменения логики игры. Перейдём в класс okno,в его часть, отвечающую за событие нажатия на клавиши, где мы сможем проанализировать код нажатой клавиши:
// Получение кода нажатой клавиши
int key_ = e.getKeyCode();
Переменной key_ при помощи метода e.getKeyCode() присваивается код нажатой клавиши. Прежде всего, пропишем обработку нажатия клавиши Escape. При нажатии клавиши сделаем выход из игры, т.е. закрываем окно. Как это сделать? Прописываем, если key_ равно 27, а 27 – это код нажатой клавиши Escape, то вызывается команда System.exit(0);, которая инициирует выход из программы. После выполнения этой команды программа будет завершаться, окно закрываться.
public void keyPressed(KeyEvent e)
{
//Получение кода нажатой клавиши
int key_ = e.getKeyCode();
if (key_==27) System.exit(0);
Запустим на исполнение и проверим, будет ли происходить выход из программы при нажатии клавиши Escape.Нажимаем клавишу Escape, окошко закрывается, и работа программы завершается. Таким образом, мы отработали нажатие одной клавиши. Далее необходимо отработать нажатия клавиш-стрелочек влевои вправо. При нажатии этих стрелочек необходимо, чтобы графический объект shapka начинал перемещаться вправо и влево. Поэтому дальше добавляем конструкцию анализа кодов нажатых клавиш:
int key_ = e.getKeyCode();
if (key_==27) System.exit(0);
else if(key_==37) // Если нажатаклавиша влево
{
}
else if(key_==39) // Если нажата клавиша вправо
{
}
Между фигурными скобками должна помещаться часть программного кода, выполняемая при нажатии стрелочки влево.Стрелочка влево имеет код клавиши 37, поэтому определяя в условии else if (иначе если)для переменной key_ значение 37,можно обработать нажатие клавиши влево. И точно также при нажатии стрелочки вправо. Код клавиши вправо – 39,поэтому можно обработать его в части программы, находящейся внутри фигурных скобок. Эта конструкция будет работать следующим образом. Если код нажатой клавиши 27, будет выполняться команда выхода из программы. Иначе если (т. е., если код нажатой клавиши не 27) идёт проверка на возможность того, что он равен 37 – нажата клавиша влево.Если условие выполняется, значит, нажата клавиша влево. Если же условие не выполняется, идёт выполнение следующего блока иначе если: если код нажатой клавиши 39, значит нажата клавиша вправо и выполняется часть программы, которая находится ниже, в фигурных скобках. Может выполниться только один из этих трёх блоков - одновременно три условия выполниться не могут. Теперь там, где идёт обработка нажатой клавиши стрелочки влево,напишем следующую конструкцию:
else if(key_==37) // Если нажата клавиша влево
{
if (gameP.x-30>-48) gameP.x-= 30;
else gameP.x = 752;
}
Мы обратились к переменной gameP.Переменная gameP объявлена в самом верху как переменная класса pole, переменная закрытая – private. Тип у этой переменнойpole. Именно этот тип создаётся при помощи класса pole. Таким образом,переменная pole связана с панелью JPanel, находящейся в соседнем классе pole. Так как мы переменную x сделали открытой, publicint x, при нажатии оператора "."после ввода имени переменной gameP, в списке есть доступная переменная x,которой мы можем присвоить какое-то значение (см. рисунок 60). При нажатии стрелочки влево необходимо перемещать шапку влево,строка:
gameP.x -= 30;
изменяет координату x,уменьшая ее на 30 пикселей, значит, шапка будет рисоваться уже левее. Но нам необходимо проверять, где находится шапка в момент нажатия стрелочки влево,если она уже ушла за пределы игрового поля с левой стороны, то необходимо ее координату x сделать такой, чтобы она появилась с правого края игрового поля.
Рисунок 60
В добавленной части программного кода делается проверка, чтоесли новое положение шапки при смещении влево больше чем -48, (-48 – это значение, при котором шапка уйдет больше чем на половину своей ширины), то уменьшаем координату x на 30 пикселей, иначе координате x присваиваем значение 752 (это положение, при котором шапка будет находиться в правой части, –выглядывать наполовину). Теперь там, где идёт обработка нажатой клавиши стрелочки вправо, напишем следующую конструкцию:
else if(key_==39) // Если нажата клавиша вправо
{
if (gameP.x+30<752) gameP.x+=30;
else gameP.x=-48;
}
При нажатии стрелочки вправо происходит все в точности наоборот. Координата x увеличивается на 30 пикселей, а при уходе шапки вправо более чем на половину ее ширины, – она помещается с левой стороны так, чтобы она выглядывала слева на половину своей ширины. Запустим программу и проверим,что все работает правильно.
При обработке нажатых стрелочек вправо и влевомы изменяли координату xшапки, это и есть изменение логики игры. Так как мы меняем значение переменной x, в методе paintComponent()значение переменной x будет меняться.
Соответственно, фон будет, как обычно, выводиться во всё окно, а положение шапки Деда Мороза будет меняться, так как переменная x будет иметь разные значения. Получается, что перерисовка игрового поля и логика игры работают по своим схемам. Задача перерисовщика в методе paintComponent() состоит только в одном - перерисовывать игровое поле, не анализируя, что происходит в самой игре. А изменение логики игры происходит отдельно - в данном случае это изменение координаты x при нажатии клавиш-стрелочек:
// Метод,который отрисовывает графические объекты на панели
public void paintComponent(Graphics gr)
{
super.paintComponent(gr);
gr.drawImage(fon,0,0,null);
gr.drawImage(shapka,x,465,null);
}
Итак, мы создали проект с тремя классами, определили основные этапы создания нашей игры, создали фон игрового поля и настроили управление шапкой Деда Мороза при помощи клавиатуры. На следующих занятиях мы будем наполнять нашу игру новым функционалом.
