- •Занятие 1. "Постановка задания для разработки игры Змейка. Работа с двумерным массивом"
- •Правила самостоятельной разработки игр данного курса
- •Работа с двумерным массивом в Java
- •Применение двумерного массива при создании игр
- •Постановка задания по созданию игры Змейка
- •Разделение задания для трех уровней сложности
- •План разработки проекта
- •Алгоритм для реализации игры Змейка
- •Перемещать голову змейки в нужном направлении.
- •Удалять хвост змейки. Удаление хвоста равносильно записи нулевого значения в элемент массива, где находилось число, отвечающее за хвост змейки.
- •Итог занятия
- •Занятие 2. "Постановка задания для разработки игры Морской бой"
- •Постановка задания по созданию игры Морской бой
- •Разделение задания для трех уровней сложности
- •Рекомендации для реализации игровых полей игры Морской бой
- •Алгоритм для реализации игры "Морской бой"
- •Генерация кораблей на игровом поле
- •Итог занятия
- •Занятие 3. "Постановка задания для разработки игры Пасьянс-Косынка"
- •Правила игры Пасьянс-Косынка
- •Упаковка файлов изображений внутрьJar-архива
- •Работа со списком в Java
- •Import java.Util.ArrayList;
- •Постановка задания по созданию игры Пасьянс-Косынка
- •Разделение задания для трех уровней сложности
- •Алгоритм перемешивания карт в колоде
- •Создание массива списков значений
- •Итог занятия
- •Заключение
- •Занятие 1. "Разработка игры Змейка. Первый и второй уровень сложности"
- •Рекомендации для изучения программного кода игр
- •Изучаемый программный код необходимо самостоятельно вводить с клавиатуры в среде разработки, глядя на образец в печатном издании.
- •Каждую строчку, каждый фрагмент программного кода стараться максимально разобрать и понять смысл. Не следует бездумно переписывать программный код и запускать!
- •Моменты, которые вызывают особые сложности в понимании, стараться нарисовать на бумаге или пройти пошагово.Например, цикл, который использует формулу с изменяющимися переменными в цикле.
- •Старайтесь больше экспериментировать с записанным программным кодом. Изменяйте значение кого-нибудь параметра и запускайте программу. Смотрите на изменения.
- •После разбора фрагмента программного кода –закрывайте книгу и начинайте пытаться записать свой программный код,который выполняет тоже самое, при этом, не заглядывая в книгу - с чистого листа.
- •Реализация первого уровня сложности игры Змейка Подготовка изображений для игры Змейка
- •Создание проекта и файлов классов игры Змейка
- •Реализация второго уровня сложности игры Змейка(начало)
- •Итог занятия
- •Занятие 2. "Разработка игры Змейка. Второй и третий уровень сложности"
- •Реализация второго уровня сложности игры Змейка(завершение)
- •Реализация третьего уровня сложности игры Змейка
- •Механизм перемещения змейки
- •Итог занятия
- •Занятие 3. "Разработка игры Морской бой. Первый уровень сложности"
- •Создание проекта и файлов классов игры Морской бой
- •Итог занятия
- •Занятие 4. "Разработка игры Морской бой. Второй уровень сложности"
- •Реализация второго уровня сложности игры Морской бой
- •Обозначения состояния ячейки игрового поля
- •Отрисовка игрового поля на основании двумерного массива
- •Ситуация выхода за пределы массива
- •Генерация однопалубных кораблей
- •Генерация четырехпалубного корабля
- •Итог занятия
- •Занятие 5. "Разработка игры Морской бой. Третий уровень сложности"
- •Реализация третьего уровня сложности игры Морской бой
- •Выполнение ходов игроком и компьютером
- •Стратегия ходов компьютера
- •Итог занятия
- •Занятие 6. "Разработка игры Пасьянс-Косынка. Начало первого уровня сложности"
- •Подготовка изображений для игры
- •Создание проекта и файлов классов игры Пасьянса-Косынка
- •Реализация класса kosinka
- •Реализация класса okno
- •Import javax.Swing.*;
- •Import java.Awt.*;
- •Реализация класса pole
- •Реализация класса karta
- •Import javax.Imageio.*;
- •Import java.Awt.*;
- •Import java.Io.*;
- •Итог занятия
- •Занятие 7. "Разработка игры Пасьянс-Косынка. Завершение первого уровня сложности"
- •Реализация класса stopka
- •Import java.Util.ArrayList;
- •Начало реализации класса game
- •Реализация класса pole
- •Завершение реализации класса game для первого уровня сложности
- •Vidacha();
- •Итог занятия
- •Занятие 8. "Разработка игры Пасьянс-Косынка. Второй уровень сложности"
- •Перерисовка всех стопок карт
- •Stopki[I].Get(stopki[I].Size()-2).Draw(gr);
- •Раздача карт в нижние семь стопок
- •Начало реализации третьего уровня сложности
- •Итог занятия
- •Занятие 9. "Разработка игры Пасьянс-Косынка. Третий уровень сложности"
- •// Получаем номер верхней карты
- •Тестирование переноса
- •Vidacha();
- •Заключение
- •Итог занятия
Начало реализации третьего уровня сложности
Продолжим создание нашей игры. Еще предстоит многое сделать.
Нам осталось запрограммировать перенос карт или группы карт мышью.
Автоматическую отправку карты в домашние стопки (номера2,3,4,5) при двойном щелчке мышью по карте. При переносах карт мы должны контролировать пользователя по правилам игры. Также в конце игры (при успешном раскладе пасьянса)необходимо выполнить эффект по окончании игры. В первую очередь добавим дополнительные переменные класса. Под существующими переменными добавим:
//Изображение рубашки карты
public Image rubashka;
// Массив стопок карт
private stopka[] stopki;
// Признак первой выдачи карт из верхней
// левой стопки
private boolean pervVidacha;
// Признак окончания игры
public boolean endGame;
// Номер стопки захваченной пользователем
private int nomStopki;
// Номер карты в стопке захваченной пользователем
private int nomKarti;
// Смещения координат курсора мыши
//относительно координат карты
private int dx ,dy;
// Координаты карты до начала переноса мышью
private int oldX ,oldY;
// Таймер для эффекта окончания игры
private Timer tmEndGame;
Переменная nomStopki –это номер стопки, захваченной мышью. Это стопка, карту или группу карт которой,пользователь захватил мышью и начинает перемещать по игровому полю. ПеременнаяnomKarti–это номер карты в захваченной стопке. Карта, на которую пользователь навел курсор мыши и нажал левую клавишу для захвата. Переменныеdx, dy –это смещения в пикселях от верхнего левого угла карты до курсора мыши. Эти смещения необходимы при переносе захваченных карт. Переменные oldX, oldY –это координаты карты до начала переноса.Эти координаты мы будем запоминать в отдельных переменных. Если перенос будет неверным, то будем возвращать карты назад.Переменная tmEndGame –это таймер, который будет выполнять эффект при окончании игры.Когда игра закончится, переменная endGame будет иметь значение true. В этот момент таймер будет запускаться.Найдем конструктор класса game. Перед вызовом метода start() (см. рис. 5),
Рис. 5
добавим программный код для таймера:
// Таймер для эффекта при окончании игры
//будет запускаться при успешном завершении игры
//скорость работы - 10 раз в секунду.
tmEndGame = new Timer(100,new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
// Перебираем четыре домашние стопки
for (int i=2;i<=5;i++)
{
// Получаем самую нижнюю карту
karta getKarta = stopki[i].get(0);
// Нижнюю карту добавляем наверх
stopki[i].add(getKarta);
// Удаляем нижнюю карту
stopki[i].remove(0);
}
}
});
Обратите внимание, что таймер пока не запускается! Таймер будет при запуске работать 10 раз в секунду.Запускаться он будет в момент, когда все карты находятся в домашних стопках, и сверху в домашних стопках лежат короли. Всего домашних стопок четыре (номера 2,3,4,5). В каждой стопке находится отдельная масть. При каждом срабатывании таймера в цикле перебираются все четыре стопки. В каждой стопке мы берем нижнюю карту, добавляем нижнюю карту сверху стопки, а снизу ее удаляем. Другими словами, со скоростью десять раз в секунду,все нижние карты домашних стопок будут перемещаться наверх. В итоге получится эффект прокручивания всех карт домашних стопок. Таймер будет выполнять такое прокручивание, пока пользователь не начнет новую игру или не закроет окно с игрой.
Далее добавим метод для проверки факта окончания игры:
// Проверка окончания игры
private void testEndGame()
{
//Проверяем, что во всех четырех
//домашних стопках по 13 карт
if ((stopki[2].size()==13) &&
(stopki[3].size()==13) &&
(stopki[4].size()==13) &&
(stopki[5].size()==13))
{
// Признак окончания игры
endGame = true;
// Запускаем таймер
tmEndGame.start();
}
}
Метод testEndGame()будет вызываться после каждого добавления карты в домашнюю стопку. Как только во всех четырех домашних стопках будет по 13карт –это значит, пасьянс разложен. Именно в этот момент будет запускаться таймер для эффекта окончания игры. И признак конца игры будет изменяться на true.
Добавим следующий метод. Он будет автоматически открывать верхние карты в нижних стопках. После каждого переноса карт из одной стопки в другую –мы будем вызывать этот метод:
// Автоматическое открытие верхней карт
// в нижних стопках
private void openKarta()
{
//Перебираем все нижние стопки карт
for (int i=6;i<=12;i++)
{
// Если в стопке есть карты
if (stopki[i].size()>0)
{
// Номер последней карты в стопке
int nomPoseld = stopki[i].size()-1;
// Получаем последнюю карту
karta getKarta = stopki[i].get(nomPoseld);
// Если карты отображается рубашкой,
// то открываем ее
if (getKarta.tipRubashka==true) getKarta.tipRubashka = false;
}
}
}
В цикле перебираем все нижние стопки, если в стопке имеются карты,то получаем самую верхнюю. Если карта закрыта (отображается рубашкой), то открываем карту. Таким образом, после переноса карт или групп карт между стопками –верхние карты будут открываться автоматически.
Теперь перейдем в методstart() и в самом конце метода добавим:
//Номер выбранной карты
nomKarti =-1;
//Номер выбранной стопки
nomStopki =-1;
При старте игры на игровом поле не будет выбранной стопки и карты. Если стопка и карта не выбраны, то будем записывать в эти переменные значениеминус единица.Это будет означать, что на игровом поле нет переносимых мышью карт.
На третьем уровне сложности необходимо реализовать перерисовку карт в режиме переноса карт.Поэтому выполним доработку метода drawKoloda().
У каждой карты имеется свойство vibrana–это признак захваченной мышью карты. Если значение этого свойства true–это значит, что пользователь подвел курсор к карте, нажал левую клавишу мыши и удерживает левую клавишу, чтобы выполнить перенос. В этот момент в переменной nomStopki
будет находиться номер выбранной стопки. Перейдем в самый конец метода drawKoloda() и найдем циклы, которые перерисовывают нижние семь стопок (см. рис.6).
Рис. 6
Модернизируем эти циклы так:
//НИЖНИЕ СЕМЬ СТОПОК
for (int i=6;i<13;i++)
{
//Если в стопке есть карты
if (stopki[i].size()>0)
{
// Перебираем все карты из стопки
for (int j=0;j<stopki[i].size();j++)
{
// Если находим выбранную карту,
// то прерываем цикл
if (stopki[i].get(j).vibrana==true) break;
// Рисуем карты
stopki[i].get(j).draw(gr);
}
}
}
Внутри циклов добавилась новая строка:
// Если находим выбранную карту,
// то прерываем цикл
if (stopki[i].get(j).vibrana==true) break;
Если при переборе карт в стопке мы находим выбранную карту, то прерываем цикл. Другим словами, не перерисовываем карты, которые в данный момент переносятся пользователем.
В самом низу методаdrawKoloda() добавим последний фрагмент кода, который перерисовывает захваченные мышью карты:
// ПЕРЕНОСИМЫЕ МЫШЬЮ КАРТЫ
// Если имеется выбранная стопка
if (nomStopki!=-1)
{
// Перебираем карты от выбранной и до конца стопки
for (int i=nomKarti;i<stopki[nomStopki].size();i++)
{
// Рисуем карты
stopki[nomStopki].get(i).draw(gr);
}
}
nomKarti –это номер карты в выбранной стопке, nomStopki–это номер выбранной стопки. Если на текущий момент пользователь ничего не переносит в режиме захвата мышью, то значения этих переменных раны минус единице. Теперь метод drawKoloda()является полностью законченным и его код выглядит так:
//Метод отрисовки всех стопок карт
public void drawKoloda(Graphics gr)
{
//ВЕРХНЯЯ ЛЕВАЯ СТОПКА
// Если в стопке есть карты
if (stopki[0].size()>0)
{
// Получаем и рисуем самую верхнюю карту
stopki[0].get(stopki[0].size()-1).draw(gr);
}
//ВТОРАЯ СЛЕВА ВЕРХНЯЯ СТОПКА
// Если в стопке более одной карты
if (stopki[1].size()>1)
{
// Получаем и рисуем вторую сверху карту
stopki[1].get(stopki[1].size()-2).draw(gr);
// Получаем и рисуем самую верхнюю карту
stopki[1].get(stopki[1].size()-1).draw(gr);
}
else if (stopki[1].size()==1) // если в стопке одна карта
{
// Получаем и рисуем самую верхнюю карту
stopki[1].get(stopki[1].size()-1).draw(gr);
}
//ЧЕТЫРЕ ДОМАШНИЕ СТОПКИ
for (int i=2;i<=5;i++)
{
//Если в стопке более одной карты
if (stopki[i].size()>1)
{
// Получаем и рисуем вторую сверху карту
stopki[i].get(stopki[i].size()-2).draw(gr);
// Получаем и рисуем самую верхнюю карту
stopki[i].get(stopki[i].size()-1).draw(gr);
}
else if (stopki[i].size()==1) // если в стопке одна карта
{
// Получаем и рисуем самую верхнюю карту
stopki[i].get(stopki[i].size()-1).draw(gr);
}
}
//НИЖНИЕ СЕМЬ СТОПОК
for (int i=6;i<13;i++)
{
//Если в стопке есть карты
if (stopki[i].size()>0)
{
// Перебираем все карты из стопки
for (int j=0;j<stopki[i].size();j++)
{
// Если находим выбранную карту,
// то прерываем цикл
if (stopki[i].get(j).vibrana==true) break;
// Рисуем карты
stopki[i].get(j).draw(gr);
}
}
}
// ПЕРЕНОСИМЫЕ МЫШЬЮ КАРТЫ
// Если имеется выбранная стопка
if (nomStopki!=-1)
{
// Перебираем карты от выбранной и до конца стопки
for (int i=nomKarti;i<stopki[nomStopki].size();i++)
{
// Рисуем карты
stopki[nomStopki].get(i).draw(gr);
}
}
}
Найдем метод mouseDragged()–это метод, который вызывается при захвате мышью. Курсор мыши перемещается с зажатой левой клавишей мыши. В этом методе нам необходимо изменять координаты выбранной карты в соответствии с курсором мыши. Если переносится сразу группа карт, то все карты, которые ниже выбранной карты должны иметь смещения вниз(координату по Y)по 20 пикселей, а координата по Xдля всех карт будет одинаковой. Запишем код в метод mouseDragged():
// При захвате карты мышью
public void mouseDragged(int mX, int mY)
{
// Если стопка выбрана
if (nomStopki>=0)
{
// Получаем выбранную карту
karta getKarta = stopki[nomStopki].get(nomKarti);
// Изменяем координаты карты по курсору мыши
getKarta.x = mX-dx;
getKarta.y = mY-dy;
// Ограничение области переноса карт
if (getKarta.x<0) getKarta.x = 0;
if (getKarta.x>720) getKarta.x = 720;
if (getKarta.y<0) getKarta.y = 0;
if (getKarta.y>650) getKarta.y = 650;
// Все остальные карты в переносимой группе карт
// размещаем со сдвигом вниз на 20пикселей
int y=20;
for (int i=nomKarti+1;i<stopki[nomStopki].size();i++)
{
stopki[nomStopki].get(i).x = getKarta.x;
stopki[nomStopki].get(i).y = getKarta.y + y;
y += 20;
}
}
}
В методе mouseDragged() имеются ограничения в области перемещения карт. ПоXот 0до 720, по Yот 0до 650.
