Задание 17 Я тут немножечко подправил код. Но в целом - отлично. Запускаем и наслаждаемся тетрисом. P.S. Не забудь отрегулировать высоту консоли Задание 16 Напиши свою реализацию методов left(), right(), up(), down() в классе Figure. Подумай, что должны делать эти методы? Задание 15 Напиши реализацию метода step в классе Tetris. В методе надо переместить фигурку вниз на один шаг. Если после перемещения положить фигурку на текущее место невозможно, то: а) поднять ее обратно (up) б) "приземлить" ее (landed) в) удалить все "полные линии" в объекте field г) создать новую фигурку взамен старой. Задание 14 Напиши реализацию метода removeFullLines в классе Field Надо а) удалить все строки из матрицы, которые полностью заполнены (состоят из одних единиц) б) сместить оставшиеся строки вниз в) создать новые строки взамен отсутствующих. ВАЖНО! matrix[y][x] содержит элемент с координатами (x,y) matrix[i] содержит i-ю строку а) Мы можем удалить стоку: matrix[i] = null б)Скопировать [ссылку на] строку: matrix[i+1] = matrix[i]; в)Создать новую строку: matrix[i] = new int[width]; Задание 13 Теперь приступим к реализации созданных методов. Напиши реализацию метода print в классе Field а) Метод должен выводить на экран прямоугольник. б) Высота прямоугольника равна height, ширина - width в) Если данная клетка пустая - вывести точку, если не пустая - английский X Подсказка: if (matrix[y][x]==0) ... Задание 12 В тетрисе мы управляем движением фигурки с помощью клавиатуры. Тут есть 4 действия: движение влево (кнопка влево) движение вправо (кнопка влево) поворот фигурки (цифра 5 на доп.клавиатуре справа) падение вниз (пробел) Мы будем обрабатывать ввод с клавиатуры в методе run() класса Tetris. И тут у меня для тебя две новости: хорошая и плохая Плохая новость состоит в том, что java не позволяет считать нажатые символы с клавиатуры, пока пользователь не нажмет enter. Не очень удобно, правда? Хорошая новость состоит в том, я написал специальный класс (KeyboardObserver), который позволяет обойти это ограничение. Так что ты можешь воспользоваться им. Есть еще и отличная новость. Ты до сих пор отлично справлялся, поэтому я помогу тебе немного. Я написал за тебя методы: а) createRandomFigure в FigureFactory б) run в Tetris Изучи их внимательно и переходи дальше. Задание 11 Теперь создай класс FigureFactory. С его помощью мы будем создавать фигуры различных форм. Пока он будет содержать только один статический метод createRandomFigure: public static Figure createRandomFigure(int x,int y) Задание 10 Так же нам понадобятся методы для управления фигуркой. Добавь в класс Figure методы: left() - для движения фигурки влево. right() - для движения фигурки вправо. down() - для движения фигурки вниз. up() - для движения фигурки вверх. downMaximum() - падение фигурки в низ до дна. rotate() - для поворота фигурки вокруг главной диагонали. boolean isCurrentPositionAvailable() - проверка - может ли фигурка быть помещена в текущую позицию. Для теста захардкодь результат в true. landed() - вызывается, когда фигурка достигла дна или уперлась в другую фигурку Все ее занятые клетки теперь должны добавиться в Field. Задание 9 Если ты обратил внимание, мы пишем программу "сверху вниз". Сначала решили, какие классы нам нужны. Затем - какие методы. А потом уже начнем писать код этих методов. Таким образом мы разбиваем большую задачу на множество маленьких. Когда код всех методов будет готов, останется только проверить - так ли все работает, как должно быть. И если надо - внести некоторые изменения. Задание 8 Теперь создадим костяк класса Figure. Этот класс будет описывать падающую фигурку. Нам понадобятся ее координаты и форма. За координаты будут отвечать две переменные x и y. За форму - матрица. Двумерный массив 3x3, состоящий из единиц и нулей. Единицей мы обозначаем что клетка есть, нулем - что она пустая. Добавь в класс Figure два поля поля: x типа int, y типа int. Еще добавь двумерный массив: matrix(матрица) типа int[][]. Там же добавь getter'ы для созданных переменных. Добавь конструктор с тремя параметрами x, y, matrix. Задание 7 Нам понадобится еще 4 метода в классе Field: а) print() - объект будет отрисовывать на экран свое текущее состояние; б) removeFullLines() - будет удалять из матрицы полностью заполненные строки и сдвигать вышележащие строки вниз; в) Integer getValue(int x, int y) - возвращает значение которое находится в матрице с координатами x и y; г) void setValue(int x, int y, int value) - устанавливает переданное значение в ячейку массива (матрицы) с координатами x, y. Задание 6 Теперь перейдем к классу Field. Он будет отвечать за хранение данных о текущих занятых и свободных клетках на поле игры. Добавь в класс Field два поля поля: width (ширина) типа int, height(высота) типа int. Так же нам понадобится матрица - двумерный массив: matrix(матрица) типа int[][]; Там же добавь getter'ы для созданных переменных. Добавь конструктор с двумя параметрами width и height. И не забудь про матрицу. ВАЖНО! Двумерный массив можно представить как массив массивов или как прямоугольную матрицу. При этом первой координатой в массиве у нас будет номер строки, а второй - столбца. Другими словами ячейка с координатами x, y - это matrix[y][x]. Задание 5 Теперь нужно создать объект самого Тетриса. Добавь в класс Tetris статическую переменную game. (тип - Tetris, видимость - public) Затем в методе main создай объект типа Тетрис и сохрани его в эту переменную. Затем добавь вызов метода run. Должно получиться что-то типа такого: game = new Tetris(); game.run(); Задание 4 Так же еще нам понадобится пара методов. Добавь в класс Tetris методы run() и step(): run() будет отвечать за всю игру. А step() - за один шаг в игре. Задание 3 Отлично! Теперь добавь в Tetris две переменные: field типа Field и figure типа Figure. С их помощью мы будем хранить информацию о текущей фигурке и о состоянии дел на "поле клеток". Так же добавь getter'ы для созданных переменных. Задание 2 А еще нам понадобится метод main. Как же без него. Добавь метод main в класс Tetris Задание 1 Давай напишем игру Тетрис. Наш Тетрис будет состоять из двух вещей: поля из клеток и фигурки, которая падает. Поэтому для начала создай три класса: Field(поле с клетками), Figure(фигура) и сам Tetris.
package com.javarush.test.level22.lesson18.big01; import java.awt.event.KeyEvent; /** * Класс Tetris - содержит основной функционал игры. */ public class Tetris { public static Tetris game; private Field field; //Поле с клетками private Figure figure; //Фигурка private boolean isGameOver; //Игра Окончена? public Tetris(int width, int height) { field = new Field(width, height); figure = null; } public static void main(String[] args) throws Exception { game = new Tetris(10, 20); game.run(); } /** * Геттер переменной field. */ public Field getField() { return field; } /** * Сеттер для field */ public void setField(Field field) { this.field = field; } /** * Геттер переменной figure. */ public Figure getFigure() { return figure; } /** * Сеттер для figure */ public void setFigure(Figure figure) { this.figure = figure; } /** * Основной цикл программы. * Тут происходят все важные действия */ public void run() throws Exception { //Создаем объект "наблюдатель за клавиатурой" и стартуем его. KeyboardObserver keyboardObserver = new KeyboardObserver(); keyboardObserver.start(); //выставляем начальное значение переменной "игра окончена" в ЛОЖЬ isGameOver = false; //создаем первую фигурку посередине сверху: x - половина ширины, y - 0. figure = FigureFactory.createRandomFigure(field.getWidth() / 2, 0); //пока игра не окончена while (!isGameOver) { //"наблюдатель" содержит события о нажатии клавиш? if (keyboardObserver.hasKeyEvents()) { //получить самое первое событие из очереди KeyEvent event = keyboardObserver.getEventFromTop(); //Если равно символу 'q' - выйти из игры. if (event.getKeyChar() == 'q') return; //Если "стрелка влево" - сдвинуть фигурку влево if (event.getKeyCode() == KeyEvent.VK_LEFT) figure.left(); //Если "стрелка вправо" - сдвинуть фигурку вправо else if (event.getKeyCode() == KeyEvent.VK_RIGHT) figure.right(); //Если код клавиши равен 12 ("цифра 5 на доп. клавиатуре") - повернуть фигурку else if (event.getKeyCode() == 12) figure.rotate(); //Если "пробел" - фигурка падает вниз на максимум else if (event.getKeyCode() == KeyEvent.VK_SPACE) figure.downMaximum(); } step(); //делаем очередной шаг field.print(); //печатаем состояние "поля" Thread.sleep(300); //пауза 300 миллисекунд - 1/3 секунды } //Выводим сообщение "Game Over" System.out.println("Game Over"); } public void step() { //опускам фигурку вниз figure.down(); //если разместить фигурку на текущем месте невозможно if (!figure.isCurrentPositionAvailable()) { figure.up(); //поднимаем обратно figure.landed(); //приземляем isGameOver = figure.getY() <= 1;//если фигурка приземлилась на самом верху - игра окончена field.removeFullLines(); //удаляем заполненные линии figure = FigureFactory.createRandomFigure(field.getWidth() / 2, 0); //создаем новую фигурку } } }
package com.javarush.test.level22.lesson18.big01; import javax.swing.*; import java.awt.*; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; public class KeyboardObserver extends Thread { private Queue<KeyEvent> keyEvents = new ArrayBlockingQueue<KeyEvent>(100); private JFrame frame; @Override public void run() { frame = new JFrame("KeyPress Tester"); frame.setTitle("Transparent JFrame Demo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setUndecorated(true); frame.setSize(400, 400); frame.setExtendedState(JFrame.MAXIMIZED_BOTH); frame.setLayout(new GridBagLayout()); frame.setOpacity(0.0f); frame.setVisible(true); frame.addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) { //do nothing } @Override public void focusLost(FocusEvent e) { System.exit(0); } }); frame.addKeyListener(new KeyListener() { public void keyTyped(KeyEvent e) { //do nothing } public void keyReleased(KeyEvent e) { //do nothing } public void keyPressed(KeyEvent e) { keyEvents.add(e); } }); } public boolean hasKeyEvents() { return !keyEvents.isEmpty(); } public KeyEvent getEventFromTop() { return keyEvents.poll(); } }
package com.javarush.test.level22.lesson18.big01; /** * Класс Figure описывает фигурку тетриса */ public class Figure { //метрица которая определяет форму фигурки: 1 - клетка не пустая, 0 - пустая private int[][] matrix; //координаты private int x; private int y; public Figure(int x, int y, int[][] matrix) { this.x = x; this.y = y; this.matrix = matrix; } public int getX() { return x; } public int getY() { return y; } public int[][] getMatrix() { return matrix; } /** * Поворачаиваем фигурку. * Для простоты - просто вокруг главной диагонали. */ public void rotate() { int[][] matrix2 = new int[3][3]; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { matrix2[i][j] = matrix[j][i]; } } matrix = matrix2; } /** * Двигаем фигурку влево. * Проверяем не вылезла ли она за границу поля и/или не залезла ли на занятые клетки. */ public void left() { x--; if (!isCurrentPositionAvailable()) x++; } /** * Двигаем фигурку вправо. * Проверяем не вылезла ли она за границу поля и/или не залезла ли на занятые клетки. */ public void right() { x++; if (!isCurrentPositionAvailable()) x--; } /** * Двигаем фигурку вверх. * Используется, если фигурка залезла на занятые клетки. */ public void up() { y--; } /** * Двигаем фигурку вниз. */ public void down() { y++; } /** * Двигаем фигурку вниз до тех пор, пока не залезем на кого-нибудь. */ public void downMaximum() { while (isCurrentPositionAvailable()) { y++; } y--; } /** * Проверяем - может ли фигурка находится на текущей позици: * а) не вылазиет ли она за границы поля * б) не залазиет ли она на занятые клетки */ public boolean isCurrentPositionAvailable() { Field field = Tetris.game.getField(); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (matrix[i][j] == 1) { if (y + i >= field.getHeight()) return false; Integer value = field.getValue(x + j, y + i); if (value == null || value == 1) return false; } } } return true; } /** * Приземляем фигурку - добавляем все ее непустые клетки к клеткам поля. */ public void landed() { Field field = Tetris.game.getField(); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (matrix[i][j] == 1) field.setValue(x + j, y + i, 1); } } } }
package com.javarush.test.level22.lesson18.big01; /** * Клсс FigureFactory отвечает за создание объектов-фигурок. */ public class FigureFactory { /** * Набор из шести шаблонов для фигурок */ public static final int[][][] BRICKS = {{ {1, 1, 0}, // X X {0, 1, 1}, // X X {0, 0, 0}}, { // {1, 0, 0}, // X {1, 1, 0}, // X X {0, 1, 0}}, { // X {0, 1, 0}, // X {0, 1, 0}, // X {0, 0, 0}}, { // X {1, 1, 0}, // X X {1, 1, 0}, // X X {0, 0, 0}}, { // {1, 1, 1}, // X X X {0, 1, 0}, // X {0, 0, 0}}, { // {1, 1, 1}, // X X X {1, 1, 1}, // X X X {0, 0, 0}} // }; /** * Метод выбирает случайный шаблон и создает с ним новую фигурку. */ public static Figure createRandomFigure(int x, int y) { int index = (int) (Math.random() * 6); return new Figure(x, y, BRICKS[index]); } }
package com.javarush.test.level22.lesson18.big01; import java.util.ArrayList; /** * Класс Field описывает "поле клеток" игры Тетрис */ public class Field { //ширина и высота private int width; private int height; //матрица поля: 1 - клетка занята, 0 - свободна private int[][] matrix; public Field(int width, int height) { this.width = width; this.height = height; matrix = new int[height][width]; } public int getWidth() { return width; } public int getHeight() { return height; } public int[][] getMatrix() { return matrix; } /** * Метод возвращает значение, которое содержится в матрице с координатами (x,y) * Если координаты за пределами матрицы, метод возвращает null. */ public Integer getValue(int x, int y) { if (x >= 0 && x < width && y >= 0 && y < height) return matrix[y][x]; return null; } /** * Метод устанавливает переданное значение(value) в ячейку матрицы с координатами (x,y) */ public void setValue(int x, int y, int value) { if (x >= 0 && x < width && y >= 0 && y < height) matrix[y][x] = value; } /** * Метод печатает на экран текущее содержание матрицы */ public void print() { //Создаем массив, куда будем "рисовать" текущее состояние игры int[][] canvas = new int[height][width]; //Копируем "матрицу поля" в массив for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { canvas[i][j] = matrix[i][j]; } } //Копируем фигурку в массив, только непустые клетки int left = Tetris.game.getFigure().getX(); int top = Tetris.game.getFigure().getY(); int[][] brickMatrix = Tetris.game.getFigure().getMatrix(); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (top + i >= height || left + j >= width) continue; if (brickMatrix[i][j] == 1) canvas[top + i][left + j] = 2; } } //Выводим "нарисованное" на экран, но начинаем с "границы кадра". System.out.println("---------------------------------------------------------------------------\n"); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { int index = canvas[i][j]; if (index == 0) System.out.print(" . "); else if (index == 1) System.out.print(" X "); else if (index == 2) System.out.print(" X "); else System.out.print("???"); } System.out.println(); } System.out.println(); System.out.println(); } /** * Удаляем заполненные линии */ public void removeFullLines() { //Создаем список для хранения линий ArrayList<int[]> lines = new ArrayList<int[]>(); //Копируем все непустые линии в список. for (int i = 0; i < height; i++) { //подсчитываем количество единиц в строке - просто суммируем все ее значения int count = 0; for (int j = 0; j < width; j++) { count += matrix[i][j]; } //Если сумма строки не равно ее ширине - добавляем в список if (count != width) lines.add(matrix[i]); } //Добавляем недостающие строки в начало списка. while (lines.size() < height) { lines.add(0, new int[width]); } //Преобразуем список обратно в матрицу matrix = lines.toArray(new int[height][width]); } }
Leave A Comment