Общее описание игры здесь. Первая часть здесь. Вторая часть здесь.

Обратите внимание на статью про отладку приложения.

Дедлайны:

  • 9-1: 8 февраля
  • 10-1: 2 февраля
  • 11-1: 2 февраля

После первой и второй части остались лишь некоторые мелкие детали и тестирование/отладка всей игры в целом.

Например метод update() в World еще не готов - поэтому нужно его доделать по вашему собственному представлению. Т.е. он должен проверять - прошло ли достаточно времени с предыдущего обновления, и если прошло, то:

  • Продвинуть змейку на один шаг
  • Проверить, не врезалась ли змейка в край игрового поля/свой хвост (а значит игра окончена, т.к. змейка заснула)
  • Проверить, не наползла ли змейка на яблоко (а значит она стала длиннее на одну клетку)

Кроме этого еще не готово управление. Обработку кнопок осуществляет MainFrame. Чтобы это сделать, он должен заявить себя “Великим Слушателем Кнопок” - KeyListener, т.е. обязаться реализовать три функции обработки нажатия кнопок: keyTyped, keyPressed, keyReleased. Нас интересует нажатие кнопки - т.е. например метод keyTyped или keyPressed. И наш “Великий Слушатель Кнопок” должен оповестить окно о том, что он хочет обрабатывать все нажатия кнопок в этом окне.

Теперь более подробно:

1) Надо релизовать интерфейс KeyListener

Было:

public class MainFrame extends JFrame {
    ...
}

Стало:

public class MainFrame extends JFrame implements KeyListener {
    ...
}

2) Реализация трех методов

Обратите внимание что у вас сразу будет подсвечено красным implements KeyListener. Т.к. теперь MainFrame обязуется реализовать упомянутые три метода, но все еще не реализовал их. Чтобы просто создать объявления этих реализаций с пустым кодом - достаточно поставить каретку ввода на implements KeyListener (кликнув туда мышью), затем Alt+Enter, затем Implement methods, затем выделить все три метода и нажать Ok.

Появится что-то вроде:

public class MainFrame extends JFrame implements KeyListener {

    // ...
    // Какой-то ваш код
    // ...

    @Override
    public void keyTyped(KeyEvent e) {
        
    }

    @Override
    public void keyPressed(KeyEvent e) {
        // TODO: обработать событие нажатой кнопки нужно здесь
    }

    @Override
    public void keyReleased(KeyEvent e) {
        
    }
    
    // ...
    // Какой-то ваш код
    // ...

}

3) Обработка нажатой кнопки

Делается это примерно следующим образом - вы узнаете у события, какой int keyCode описывает код нажатой кнопкой - сверяете его: “а не совпал ли он с одной из стрелочек”, и если совпал - делаете какую-нибудь логику (например выставляете соответствующее направление движения у Snake через World).

int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_UP) {
    // Ваша обработка нажатия стрелки вверх (змейка должна теперь ползти вверх)
} else if (keyCode == KeyEvent.VK_RIGHT) {
    // ...
} else if (keyCode == KeyEvent.VK_DOWN) {
    // ...
} else if (keyCode == KeyEvent.VK_LEFT) {
    // ...
}

Обратите внимание что если пользователь при движении змейки вверх жмет стрелку вниз - то такие нажатия хочется игнорировать (змейка не умеет делать смертельный разворот на 180 градусов).

4) Оповещение окна о KeyListener

Теперь MainFrame является полноценным KeyListener. В целом обработку нажатия кнопок можно вынести в отдельный класс KeyHandler, но для простоты пусть обработка кнопок будет в MainFrame.

Осталось лишь сообщить окну о том, что у нас появился обработчик нажатия кнопок - это делается через метод addKeyListener(KeyListener listener). Метод этот принадлежит JFrame, а значит наследуется и в MainFrame - нашем игровом окне (соответственно вызываться он будет у него). Аргумент функции - обработчик нажатия кнопок, т.е. любой, кто реализует интерфейс KeyListener, в данном случае это объект MainFrame, поэтому может получиться слегка странный код this.addKeyListener(this).

5) Тестирование и отправка задания

Чтобы запустить приложение нужно нажать правой кнопкой на класс с функцией main (вероятно MainFrame) и там нажать Run (или Debug).

Чтобы отлаживать приложение:

  • Нужно читать ошибки, и смотреть в каких строчках они упали (в случае runtime-exception, например NullPointerException (обращение к null-объекту через точку, т.е. не созданному объекту) или IndexOutOfBoundsException (выход за пределы массива)).
  • Можно запускать под отладчиком с выставленными точками остановки (так называемые breakpoints) - их можно выставить нажав левой кнопкой мыши в серое поле слева от строки исходника (чтобы запустить отладчик надо вместо Run нажать Debug)

Обратите внимание на статью про отладку приложения.

Ваше приложение должно показывать примерно следующее: мир, в нем змея ползет, меняет направление от нажатия стрелочек, если змея наезжает на себя или край мира - игра замирает (змея перестает ползти). Съеденное яблоко должно увеличивать длину змейки.

Отправляйте выполненное задание ввиде zip-архива src папки, и пожалуйста:

  • Тему письма называйте правильно (номер этого задания, как написано в самом верху - 33)
  • zip-архив (или 7zip) называйте по тем же правилам, как назывались патчи (только расширение файла теперь не .patch, а .zip, например 33_16_1_polyarniy_nikolay.zip)

Т.е. формат такой же как и про патч, только вместо .patch вы шлете .zip.