Skip to content

Instantly share code, notes, and snippets.

@Shtaba09
Created October 21, 2018 20:50
Show Gist options
  • Save Shtaba09/1de03be9b74485bb29dd153679ae2270 to your computer and use it in GitHub Desktop.
Save Shtaba09/1de03be9b74485bb29dd153679ae2270 to your computer and use it in GitHub Desktop.
Консольная змейка
package com.javarush.task.task23.task2312;
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);
static JFrame frame;
@Override
public void run() {
frame = new JFrame("KeyPress Tester");
frame.setTitle("Transparent JFrame Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setUndecorated(false);
frame.setSize((Room.game.getWidth() * 10) + 17, (Room.game.getHeight() * 10) + 40);
//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.task.task23.task2312;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
public class Layer extends JPanel {
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(java.awt.Color.GREEN); //Задаем цвет элементов зеленый
g.fillRect(Room.game.getWidth() * 10, 0, 10, (Room.game.getWidth() * 10) + 10); //Рисуем прямоугольник показывающий край поля справа
g.fillRect(0, Room.game.getHeight() * 10, (Room.game.getHeight() * 10) + 10, 10); //Рисуем прямоугольник показывающий край поля снизу
g.fillRect(Room.game.getMouse().getX()*10, Room.game.getMouse().getY()*10, 10, 10); //Рисуем прямоугольник показывающий мышь
ArrayList<SnakeSection> getsection = Room.game.getSnake().getSections(); //Получаем секции змейки
for (int i = 0; i < getsection.size(); i++) {
g.fillRect(getsection.get(i).getX()*10, getsection.get(i).getY()*10, 10, 10); //Рисуем по очереди секции змейки
}
}
}
package com.javarush.task.task23.task2312;
public class Mouse {
private int x;
private int y;
public Mouse(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
package com.javarush.task.task23.task2312;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
/**
* Основной класс программы.
*/
public class Room {
private int width;
private int height;
private Snake snake;
private Mouse mouse;
public Room(int width, int height, Snake snake) {
this.width = width;
this.height = height;
this.snake = snake;
game = this;
}
public Snake getSnake() {
return snake;
}
public Mouse getMouse() {
return mouse;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
public void setSnake(Snake snake) {
this.snake = snake;
}
public void setMouse(Mouse mouse) {
this.mouse = mouse;
}
/**
* Основной цикл программы.
* Тут происходят все важные действия
*/
public void run() {
//Создаем объект "наблюдатель за клавиатурой" и стартуем его.
KeyboardObserver keyboardObserver = new KeyboardObserver();
keyboardObserver.start();
//пока змея жива
while (snake.isAlive()) {
//"наблюдатель" содержит события о нажатии клавиш?
if (keyboardObserver.hasKeyEvents()) {
KeyEvent event = keyboardObserver.getEventFromTop();
//Если равно символу 'q' - выйти из игры.
if (event.getKeyChar() == 'q') return;
//Если "стрелка влево" - сдвинуть фигурку влево
if (event.getKeyCode() == KeyEvent.VK_LEFT)
snake.setDirection(SnakeDirection.LEFT);
//Если "стрелка вправо" - сдвинуть фигурку вправо
else if (event.getKeyCode() == KeyEvent.VK_RIGHT)
snake.setDirection(SnakeDirection.RIGHT);
//Если "стрелка вверх" - сдвинуть фигурку вверх
else if (event.getKeyCode() == KeyEvent.VK_UP)
snake.setDirection(SnakeDirection.UP);
//Если "стрелка вниз" - сдвинуть фигурку вниз
else if (event.getKeyCode() == KeyEvent.VK_DOWN)
snake.setDirection(SnakeDirection.DOWN);
}
snake.move(); //двигаем змею
print(); //отображаем текущее состояние игры
sleep(); //пауза между ходами
}
//Выводим сообщение "Game Over"
System.out.println("Game Over!");
}
/**
* Выводим на экран текущее состояние игры
*/
public void print() {
//Создаем массив, куда будем "рисовать" текущее состояние игры
int[][] matrix = new int[height][width];
//Рисуем все кусочки змеи
ArrayList<SnakeSection> sections = new ArrayList<SnakeSection>(snake.getSections());
for (SnakeSection snakeSection : sections) {
matrix[snakeSection.getY()][snakeSection.getX()] = 1;
}
//Рисуем голову змеи (4 - если змея мертвая)
matrix[snake.getY()][snake.getX()] = snake.isAlive() ? 2 : 4;
//Рисуем мышь
matrix[mouse.getY()][mouse.getX()] = 3;
//Выводим все это на экран
String[] symbols = {" . ", " x ", " X ", "^_^", "RIP"};
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
System.out.print(symbols[matrix[y][x]]);
}
System.out.println();
}
System.out.println();
System.out.println();
System.out.println();
}
/**
* Метод вызывается, когда мышь съели
*/
public void eatMouse() {
createMouse();
}
/**
* Создает новую мышь
*/
public void createMouse() {
int x = (int) (Math.random() * width);
int y = (int) (Math.random() * height);
mouse = new Mouse(x, y);
}
public static Room game;
public static void main(String[] args) {
game = new Room(20, 20, new Snake(10, 10));
game.snake.setDirection(SnakeDirection.DOWN);
game.createMouse();
game.run();
}
private int initialDelay = 520;
private int delayStep = 20;
/**
* Программа делает паузу, длинна которой зависит от длинны змеи.
*/
public void sleep() {
try {
int level = snake.getSections().size();
int delay = level < 15 ? (initialDelay - delayStep * level) : 200;
Thread.sleep(delay);
} catch (InterruptedException e) {
}
}
}
package com.javarush.task.task23.task2312;
import java.util.ArrayList;
/**
* Класс змея
*/
public class Snake {
// Направление движения змеи
private SnakeDirection direction;
// Состояние - жива змея или нет.
private boolean isAlive;
// Список кусочков змеи.
private ArrayList<SnakeSection> sections;
public Snake(int x, int y) {
sections = new ArrayList<SnakeSection>();
sections.add(new SnakeSection(x, y));
isAlive = true;
}
public boolean isAlive() {
return isAlive;
}
public int getX() {
return sections.get(0).getX();
}
public int getY() {
return sections.get(0).getY();
}
public SnakeDirection getDirection() {
return direction;
}
public void setDirection(SnakeDirection direction) {
this.direction = direction;
}
public ArrayList<SnakeSection> getSections() {
return sections;
}
/**
* Метод перемещает змею на один ход.
* Направление перемещения задано переменной direction.
*/
public void move() {
if (!isAlive) return;
if (direction == SnakeDirection.UP)
move(0, -1);
else if (direction == SnakeDirection.RIGHT)
move(1, 0);
else if (direction == SnakeDirection.DOWN)
move(0, 1);
else if (direction == SnakeDirection.LEFT)
move(-1, 0);
}
/**
* Метод перемещает змею в соседнюю клетку.
* Координаты клетки заданы относительно текущей головы с помощью переменных (dx, dy).
*/
private void move(int dx, int dy) {
// Создаем новую голову - новый "кусочек змеи".
SnakeSection head = sections.get(0);
head = new SnakeSection(head.getX() + dx, head.getY() + dy);
// Проверяем - не вылезла ли голова за границу комнаты
checkBorders(head);
if (!isAlive) return;
// Проверяем - не пересекает ли змея саму себя
checkBody(head);
if (!isAlive) return;
// Проверяем - не съела ли змея мышь.
Mouse mouse = Room.game.getMouse();
if (head.getX() == mouse.getX() && head.getY() == mouse.getY()) // съела
{
sections.add(0, head); // Добавили новую голову
Room.game.eatMouse(); // Хвост не удаляем, но создаем новую мышь.
} else // просто движется
{
sections.add(0, head); // добавили новую голову
sections.remove(sections.size() - 1); // удалили последний элемент с хвоста
}
}
/**
* Метод проверяет - находится ли новая голова в пределах комнаты
*/
private void checkBorders(SnakeSection head) {
if ((head.getX() < 0 || head.getX() >= Room.game.getWidth()) || head.getY() < 0 || head.getY() >= Room.game.getHeight()) {
isAlive = false;
}
}
/**
* Метод проверяет - не совпадает ли голова с каким-нибудь участком тела змеи.
*/
private void checkBody(SnakeSection head) {
if (sections.contains(head)) {
isAlive = false;
}
}
}
package com.javarush.task.task23.task2312;
public enum SnakeDirection {
UP,
RIGHT,
DOWN,
LEFT
}
package com.javarush.task.task23.task2312;
public class SnakeSection {
private int x;
private int y;
public SnakeSection(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SnakeSection that = (SnakeSection) o;
if (x != that.x) return false;
if (y != that.y) return false;
return true;
}
@Override
public int hashCode() {
int result = x;
result = 31 * result + y;
return result;
}
}
taskKey="com.javarush.task.task23.task2312.big18"
Змейка(18)
Отлично!
Запускаем и наслаждаемся змейкой.
Требования:
1. Змейка готова!
Змейка(17)
Теперь закончим класс Snake.
Змея состоит из кусочков. Давай каждый ход просто добавлять один кусочек со стороны головы,
а самый последний - удалять. Тогда получится, что змея ползет.
Добавлять кусочек нужно рядом с текущей головой (кусочком номер 0).
С какой стороны добавлять зависит от direction (UP, DOWN, LEFT, RIGHT).
Подсказка:
а) Как добавить кусочек змеи в начало списка sections?
sections.add(0, new_section);
б) А как удалить последний?
sections.remove(sections.size()-1);
Необходимо реализовать метод move(int dx, int dy):
a) проверить, не вылезла ли она за границу комнаты (если да, то змея умирает)
б) проверить, не совпадает ли она с уже существующими кусочками змеи (если да, то змея умирает)
в) добавить голову к змее (со стороны головы) и удалить последний кусочек из хвоста.
г) вызвать метод eatMouse у статического объекта game класса Room, если координаты мыши совпадают с координатами головы змеи.
д) если змея поймала мышь (координаты головы совпадают с координатами мыши), то удалять кусок из хвоста не надо.
Змейка(16)
Ничто не вечно.. Так и змея должна умирать, если она врезается в стену или саму себя.
Для определения, не пересекается ли змея сама с собой, можно сделать очень простую проверку:
содержит ли список sections "новую голову змеи".
Код для этого будет выглядеть примерно так:
if (sections.contains(head))
При этом head должен быть еще не добавлен в список sections, иначе будет всегда true.
Но чтобы этот код работал, надо реализовать методы сравнения объектов (equals и hashCode) в классе SnakeSection.
Подсказка:
Используй Alt+Insert в Intellij IDEA для автоматической генерации методов equals и hashCode.
Задание:
а) реализуй методы equals и hashCode в классе SnakeSection.
б) реализуй метод checkBorders(SnakeSection head): если голова змеи за границами комнаты - змея умирает (isAlive = false)
в) реализуй метод checkBody(SnakeSection head): если голова змеи пересекается с ее телом - змея умирает (isAlive = false)
Змейка(15)
Теперь осталось допилить змею.
Вот что я предлагаю насчет движения змеи:
Змея состоит из кусочков. Давай каждый ход просто добавлять один кусочек со стороны головы,
а самый последний - удалять. Тогда получится, что змея ползет.
Давай добавим два метода move, один без параметров, а другой с двумя параметрами типа int.
В методе move без параметров необходимо:
а) прекратить движение если змея умерла(isAlive == false)
б) вызвать метод move(0, -1) если направление движения равно SnakeDirection.UP
в) вызвать метод move(1, 0) если направление движения равно SnakeDirection.RIGHT
г) вызвать метод move(0, 1) если направление движения равно SnakeDirection.DOWN
д) вызвать метод move(-1, 0) если направление движения равно SnakeDirection.LEFT
Метод move с параметрами int, int пока оставим пустым.
Змейка(14)
Теперь поработаем над методом print().
Надо:
а) вывести на экран прямоугольник из точек размером width x height.
б) тело змеи отметить символом "x"-английское
в) голову змеи нарисовать символом "X"-английское.
Подсказка:
а) удобно сначала создать матрицу типа int[][] с размером (height x width)
б) затем пройтись по всем объектам и отрисовать их в матрицу.
Например, тело змеи - 1, голова змеи - 2, мышь - 3.
Змейка(13)
Предлагаю тебе в этот раз написать специальный метод sleep(), который будет делать паузу
в зависимости от длины змеи (количества элементов в sections).
Придумай какой-нибудь хитрый алгоритм. Чтобы на первом уровне пауза была 500 миллисекунд,
к 11 уровню постепенно уменьшилась до 300. А к 15 до 200. И дальше оставалась постоянной.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment