Skip to content

Instantly share code, notes, and snippets.

@Shtaba09
Created October 24, 2018 21:09
Show Gist options
  • Save Shtaba09/44edfab03fdf0c3c40201215a0666b17 to your computer and use it in GitHub Desktop.
Save Shtaba09/44edfab03fdf0c3c40201215a0666b17 to your computer and use it in GitHub Desktop.
Игра арканоид примитив оставляю для личного изучения стороннего кода
package com.javarush.task.task24.task2413;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
/**
* Главный класс игры
*/
public class Arkanoid {
// ширина и высота
private int width;
private int height;
// список кирпичей
private ArrayList<Brick> bricks = new ArrayList<Brick>();
// шарик
private Ball ball;
// подставка
private Stand stand;
// игра закончена?
private boolean isGameOver = false;
public Arkanoid(int width, int height) {
this.width = width;
this.height = height;
}
public ArrayList<Brick> getBricks() {
return bricks;
}
public Ball getBall() {
return ball;
}
public void setBall(Ball ball) {
this.ball = ball;
}
public Stand getStand() {
return stand;
}
public void setStand(Stand stand) {
this.stand = stand;
}
/**
* Рисуем на холсте границы и все объекты.
*/
void draw(Canvas canvas) {
drawBorders(canvas);
// draw bricks
for (Brick brick : bricks) {
brick.draw(canvas);
}
// draw ball
ball.draw(canvas);
// draw stand
stand.draw(canvas);
}
/**
* Рисуем на холсте границы
*/
private void drawBorders(Canvas canvas) {
// draw game
for (int i = 0; i < width + 2; i++) {
for (int j = 0; j < height + 2; j++) {
canvas.setPoint(i, j, '.');
}
}
for (int i = 0; i < width + 2; i++) {
canvas.setPoint(i, 0, '-');
canvas.setPoint(i, height + 1, '-');
}
for (int i = 0; i < height + 2; i++) {
canvas.setPoint(0, i, '|');
canvas.setPoint(width + 1, i, '|');
}
}
/**
* Основной цикл программы.
* Тут происходят все важные действия
*/
void run() throws Exception {
// Создаем холст для отрисовки.
Canvas canvas = new Canvas(width, height);
// Создаем объект "наблюдатель за клавиатурой" и стартуем его.
KeyboardObserver keyboardObserver = new KeyboardObserver();
keyboardObserver.start();
// Исполняем цикл, пока игра не окончена
while (!isGameOver) {
// "наблюдатель" содержит события о нажатии клавиш?
if (keyboardObserver.hasKeyEvents()) {
KeyEvent event = keyboardObserver.getEventFromTop();
// Если "стрелка влево" - сдвинуть фигурку влево
if (event.getKeyCode() == KeyEvent.VK_LEFT)
stand.moveLeft();
// Если "стрелка вправо" - сдвинуть фигурку вправо
else if (event.getKeyCode() == KeyEvent.VK_RIGHT)
stand.moveRight();
// Если "пробел" - запускаем шарик
else if (event.getKeyCode() == KeyEvent.VK_SPACE)
ball.start();
}
// двигаем все объекты
move();
// проверяем столкновения
checkBricksBump();
checkStandBump();
// проверяем, что шарик мог улететь через дно.
checkEndGame();
// отрисовываем все объекты
canvas.clear();
draw(canvas);
canvas.print();
// пауза
Thread.sleep(300);
}
// Выводим сообщение "Game Over"
System.out.println("Game Over!");
}
/**
* Двигаем шарик и подставку.
*/
public void move() {
ball.move();
stand.move();
}
/**
* Проверяем столкновение с кирпичами.
* Если столкновение было - шарик отлетает в случайном направлении 0..360 градусов
*/
void checkBricksBump() {
for (Brick brick : new ArrayList<Brick>(bricks)) {
if (ball.isIntersec(brick)) {
double angle = Math.random() * 360;
ball.setDirection(angle);
bricks.remove(brick);
}
}
}
/**
* Проверяем столкновение с подставкой.
* Если столкновение было - шарик отлетает в случайном направлении вверх 80..100 градусов.
*/
void checkStandBump() {
if (ball.isIntersec(stand)) {
double angle = 90 + 20 * (Math.random() - 0.5);
ball.setDirection(angle);
}
}
/**
* Проверяем - не улетел ли шарик через дно.
* Если да - игра окончена (isGameOver = true)
*/
void checkEndGame() {
if (ball.getY() > height && ball.getDy() > 0)
isGameOver = true;
}
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 static Arkanoid game;
public static void main(String[] args) throws Exception {
game = new Arkanoid(20, 30);
Ball ball = new Ball(10, 29, 2, 95);
game.setBall(ball);
Stand stand = new Stand(10, 30);
game.setStand(stand);
game.getBricks().add(new Brick(3, 3));
game.getBricks().add(new Brick(7, 5));
game.getBricks().add(new Brick(12, 5));
game.getBricks().add(new Brick(16, 3));
game.run();
}
}
package com.javarush.task.task24.task2413;
/**
* Класс для шарика в игре
*/
public class Ball extends BaseObject {
// скорость
private double speed;
// направление (в градусах от 0 до 360)
private double direction;
// текущее значение вектора движения (dx,dy)
private double dx;
private double dy;
// заморожен ли объект или может двигаться
private boolean isFrozen;
public Ball(double x, double y, double speed, double direction) {
super(x, y, 1);
this.direction = direction;
this.speed = speed;
this.isFrozen = true;
}
public double getSpeed() {
return speed;
}
public void setSpeed(double speed) {
this.speed = speed;
}
public double getDirection() {
return direction;
}
public double getDx() {
return dx;
}
public double getDy() {
return dy;
}
/**
* Устанавливаем новое направление движения.
* Тут же вычисляем и новый вектор.
* Такой подход удобно использовать при отскоках от стен.
*/
void setDirection(double direction) {
this.direction = direction;
double angle = Math.toRadians(direction);
dx = Math.cos(angle) * speed;
dy = -Math.sin(angle) * speed;
}
/**
* Рисуем себя на "канвасе".
*/
@Override
void draw(Canvas canvas) {
canvas.setPoint(x, y, 'O');
}
/**
* Двигаем себя на один шаг.
*/
public void move() {
if (isFrozen) return;
x += dx;
y += dy;
checkRebound(1, Arkanoid.game.getWidth(), 1, Arkanoid.game.getHeight() + 5);
}
/**
* Проверяем не улетел ли шарик за стенку.
* Если да - отражаем его.
*/
void checkRebound(int minx, int maxx, int miny, int maxy) {
if (x < minx) {
x = minx + (minx - x);
dx = -dx;
}
if (x > maxx) {
x = maxx - (x - maxx);
dx = -dx;
}
if (y < miny) {
y = miny + (miny - y);
dy = -dy;
}
if (y > maxy) {
y = maxy - (y - maxy);
dy = -dy;
}
}
/**
* Запускам шарик.
* isFrozen = false.
* Пересчитываем вектор движения (dx,dy).
*/
void start() {
this.setDirection(direction);
this.isFrozen = false;
}
}
package com.javarush.task.task24.task2413;
/**
* Базовый класс для всех объектов игры.
*/
public abstract class BaseObject {
//координаты
protected double x;
protected double y;
//радиус объекта
protected double radius;
protected BaseObject(double x, double y, double radius) {
this.x = x;
this.y = y;
this.radius = radius;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
/**
* Метод рисует свой объект на "канвасе".
*/
abstract void draw(Canvas canvas);
/**
* Двигаем себя на один ход.
*/
abstract void move();
/**
* Проверяем - не выходит ли (x,y) за границы.
*/
void checkBorders(double minx, double maxx, double miny, double maxy) {
if (x < minx) x = minx;
if (x > maxx) x = maxx;
if (y < miny) y = miny;
if (y > maxy) y = maxy;
}
/**
* Проверяем - пересекаются ли переданный(o) и наш(this) объекты.
*/
boolean isIntersec(BaseObject o) {
double dx = x - o.x;
double dy = y - o.y;
double destination = Math.sqrt(dx * dx + dy * dy);
double destination2 = Math.max(radius, o.radius);
return destination <= destination2;
}
}
package com.javarush.task.task24.task2413;
/**
* Класс для объекта "кирпич".
*/
public class Brick extends BaseObject {
//картинка для отрисовки
private static int[][] matrix = {
{0, 0, 0, 0, 0},
{0, 1, 1, 1, 0},
{0, 1, 1, 1, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
};
public Brick(double x, double y) {
super(x, y, 3);
}
/**
* Рисуем себя на холсте
*/
@Override
void draw(Canvas canvas) {
canvas.drawMatrix(x - radius + 1, y, matrix, 'H');
}
/**
* Ничего не делаем - кирпич неподвижен
*/
@Override
void move() {
//do nothing
}
}
package com.javarush.task.task24.task2413;
/**
* Класс-холст для отрисовки.
*/
public class Canvas {
//ширина и высота
private int width;
private int height;
//матрица, где рисуем. символ - это цвет.
private char[][] matrix;
public Canvas(int width, int height) {
this.width = width;
this.height = height;
this.matrix = new char[height + 2][width + 2];
}
/**
* Очищаем холст
*/
void clear() {
this.matrix = new char[height + 2][width + 2];
}
/**
* Печатаем переданную фигуру в указанных координатах цветом c.
* Если переданный массив содержит единицы, то на холсте им будут соответствовать символы - с.
*/
void drawMatrix(double x, double y, int[][] matrix, char c) {
int height = matrix.length;
int width = matrix[0].length;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
if (matrix[i][j] == 1)
setPoint(x + j, y + i, c);
}
}
}
/**
* Ставим одну точку на холсте с координатами (x,y) и цветом - c.
*/
void setPoint(double x, double y, char c) {
int x0 = (int) Math.round(x);
int y0 = (int) Math.round(y);
if (y0 < 0 || y0 >= matrix.length) return;
if (x0 < 0 || x0 >= matrix[y0].length) return;
matrix[y0][x0] = c;
}
/**
* Печатаем содержимое холста на экран.
*/
void print() {
System.out.println();
for (int i = 0; i < height + 2; i++) {
for (int j = 0; j < width + 2; j++) {
System.out.print(" ");
System.out.print(matrix[i][j]);
System.out.print(" ");
}
System.out.println();
}
System.out.println();
System.out.println();
System.out.println();
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public char[][] getMatrix() {
return matrix;
}
}
package com.javarush.task.task24.task2413;
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.task.task24.task2413;
/**
* Подставка, с помощью которой отражаем мячик.
*/
public class Stand extends BaseObject {
//картинка для отрисовки
private static int[][] matrix = {
{1, 1, 1, 1, 1},
{1, 0, 0, 0, 1},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
};
//скорость
private double speed = 1;
//направление (-1 влево, +1 вправо)
private double direction = 0;
public Stand(double x, double y) {
super(x, y, 3);
}
/**
* Метод передвигает подставку в соответствии с текущим значением direction.
*/
void move() {
double dx = speed * direction;
x = x + dx;
checkBorders(radius, Arkanoid.game.getWidth() - radius + 1, 1, Arkanoid.game.getHeight() + 1);
}
/**
* direction устанавливается равным -1
*/
void moveLeft() {
direction = -1;
}
/**
* direction устанавливается равным +1
*/
void moveRight() {
direction = 1;
}
public double getSpeed() {
return speed;
}
public double getDirection() {
return direction;
}
/**
* Отрисовываем себя на холсте
*/
@Override
void draw(Canvas canvas) {
canvas.drawMatrix(x - radius + 1, y, matrix, 'M');
}
}
taskKey="com.javarush.task.task24.task2413.big20"
Арканоид(20)
Отличная работа! Я добавил пару методов, а также класс KeyboardObserver.
Немного отдохни перед новым уровнем и поиграй.
P.S. Только не забудь отрегулировать высоту консоли.
Требования:
1. Расслабься и получай удовольствие.
Арканоид(19)
Осталось совсем чуть-чуть.
В классе Arkanoid создай поле приватное isGameOver типа boolean.
Реализуй метод checkBricksBump.
В этом методе надо проверить - не столкнулся ли шарик с каким-нибудь из "кирпичей".
Для проверки столкновения используй метод isIntersec.
Если шарик все-таки попал в кирпич, то:
а) шарик отлетает в случайном направлении:
double angle = Math.random() * 360;
ball.setDirection(angle);
б) кирпич умирает - надо удалить его из списка всех кирпичей.
Реализуй метод checkStandBump.
В этом методе надо проверить - не ударился ли шарик о подставку.
Для проверки столкновения используй метод isIntersec.
Если шарик все-таки ударился о подставку, то:
шарик отлетает в случайным направлении вверх:
double angle = 90 + 20 * (Math.random() - 0.5);
ball.setDirection(angle);
Реализуй метод checkEndGame.
Если координата y шарика больше чем высота поля игры (height), значит шарик улетел вниз за границу экрана.
В этом случае надо переменную isGameOver установить в true.
Арканоид(18)
Теперь вернемся к классу Arkanoid.
Реализуй методы:
а) move()
В этом методе нужно двигать все движимые объекты (stand, ball).
б) draw(Canvas canvas)
В этом методе надо вызвать метод draw всех существующих объектов, которые его имеют.
Арканоид(17)
Еще подставке нужны методы:
а) move - см. move в BaseObject
Движение доски осуществляется горизонтально, поэтому мы меняем только координату х.
Подумай, как координата х зависит от направления (direction) и скорости (speed). Реализуй зависимость.
б) draw - см. draw в BaseObject
Его кодом я займусь сам.
в) moveLeft() - задает постоянное движение "подставки" влево
Просто присвой правильное значение переменной direction.
г) moveRight() - задает постоянное движение "подставки" вправо
Просто присвой правильное значение переменной direction.
Арканоид(16)
И наконец "подставка"!
Ей понадобятся такие приватные поля:
а) speed (скорость подставки) типа double;
б) direction (направление движения по оси x: 1 - вправо, -1 - влево, 0 - начальное значение, стоим на месте) типа double.
Также создай для них геттеры.
А еще с тебя конструктор, примерно вот такой:
public Stand(double x, double y) {
super(x, y, 3);
speed = 1;
direction = 0;
}
Арканоид(15)
Не поверишь, но и это еще не все.
Во-первых нужен метод setDirection,
который не только устанавливает значение переменной direction,
но и вычисляет новые значения переменных dx и dy.
Код должен выглядеть примерно так:
this.direction = direction;
double angle = Math.toRadians(direction);
dx = Math.cos(angle) * speed;
dy = -Math.sin(angle) * speed.
Во-вторых шарик может удариться о стенку.
При этом он должен от нее отскочить.
Для этого нам понадобится еще один метод:
void checkRebound(int minx, int maxx, int miny, int maxy)
Создай его, а кодом я займусь сам.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment