Главная » Java » Возвращаемся к графике. Пинг-Понг

0

В  главах  5,  6  и  7  мы  использовали  некоторые  компоненты  изAWT  и  Swing  библиотек.  Теперь  я  покажу  вам,  как  можно  рисовать  и двигать  такие фигуры, как овалы, прямоугольники и линии внутри окна.  Также,   вы узнаете,   как обрабатывать   события   мыши   и клавиатуры.  Чтобы  добавить  немного  веселья  в  эти  скучные  темы,  в этой  главе  мы будем изучать их при создании игры  пинг-­?понг.  В игребудут  два участника, я называю их ребенок и компьютер.Стратегия

Давайте  установим правила игры:

?? Игра  продолжается,  пока  один  из игроков  (ребенок или компьютер)  не наберет 21 очко.?? Ракетка  ребенка будет управляться с помощью мыши.?? Счет  игры будет отображаться в нижней части окна.?? Новая  игра начинается при нажатии кнопки N на клавиатуре, Q –завершает  игру и S – подает мяч. ?? Подать  мяч может только ребенок.?? Для  того, что выиграть очко, мяч должен попасть в область завертикальной  линией ракетки, когда ракетка не блокирует мяч.

?? Когда  компьютер отбивает мяч, мяч может двигаться толькогоризонтально  вправо.?? Если мяч касается ракетки в верхней половине стола, он может двигаться  только  влево  и  вверх.  Если  мяч  находился  в нижнейчасти  стола, он может двигаться только вниз и влево.

Должно  быть,  вы  думаете,  что  написать такую программу очень  сложно. Хитрость в том, чтобы разбить    сложную  задачу  на  несколько  маленьких  и  простых  задач  и  сделать  каждую  из  них  отдельно.

Эта     хитрость     называется  аналитическим  мышлением и она  помогает  не     только     в  программировании, но   и в повседневной   жизни.    Не расстраивайтесь,   если  вы   не  можете  достичь   большой цели,  разбейте  ее  на  маленькие  и  выполняйте по отдельности.

Поэтому  первая    версия программы  будет    выполнять только некоторые  из  правил  –  программа  будет  рисовать  стол,  перемещать  ракетку     и  показывать координаты  кликов  мыши.Вместо  того, чтобы говорить«Мой  компьютер не работает» (большая проблема), попробуйте посмотреть, что именно не работает (найдите проблему поменьше).

1.  Подключен ли компьютер крозетке?  (да/нет)?  Да.

2.Когда  я запускаю компьютер, отображаются ли иконки на экране (да/нет)?  Да.

3. Можно ли перемещать мышь по экрану (да/нет)?  Нет.

4.  Правильно ли подключен кабель мыши (да/нет)?  Нет.

Просто   подключите   кабель  мыши   и  компьютер  опять  будет  работать!   Большая  проблема  решается всего лишь подключением кабеля мыши.КодИгра  будет состоять из трех классов:

??  Класс  PingPongGreenTable возьмет на себя визуальную часть. Втечение  игры он будет отображать стол, ракетки и мяч. ??  Класс  PingPongGameEngine,  который  будет  считать координаты мяча  и ракеток, начинать и завершать игру, подавать  мяч. Класс  будет  передавать  текущие  координаты  компонентов  классу  PingPongGreenTable,   который   будет  перерисовываться   в  соответствии с данными. ??  Интерфейс  GameConstants   будет   объявлять   все  константы,  которые  понадобятся  в  игре,  например  длину  и  ширину  стола, начальные позиции ракеток и т.д. Вот  как будет выглядеть стол для пинг-­?понга:

Первая  версия этой игры будет делать только три вещи:

??  Отображать  зеленый стол для пинг-­?понга.

??  Отображать  координаты указателя мыши, когда вы кликаете.??  Двигать  ракетку ребенка вверх и вниз. Через  две    страницы   вы   сможете    увидеть    наш    класс PingPongGreenTable,   который наследуется от класса JPanel из Swing. Посмотрите на этот код, пока читайте текст ниже.Так  как  наша программа должна знать точные координаты  указателя мыши,   конструктор PingPongGreenTable будет создавать объект класса-­?обработчика событий PingPongGameEngine.

Этот   класс   будет   выполнять   некоторые   действия,   когда  ребенок кликает  на   кнопку   мыши   или   просто   двигает   ее.   Метод addPaneltoFrame()  создает   текстовый   элемент,   который   будет отображать координаты мыши.

Этот  класс  не  апплет,  поэтому  взамен  метода  paint(),  используется paintComponent().  Этот метод может быть вызван как JVM, когда нужно перерисовать окно, так и нашей программой, с помощью метода repaint().   Да, вы  прочли правильно, метод   repaint() внутри вызывает paintComponent() и предоставляет вашему классу доступ к объекту Graphics, чтобы вы смогли рисовать внутри окна. Мы будем вызывать этот метод каждый раз  после пересчета координат ракеток или мяча для их правильного отображения.

Чтобы нарисовать ракетку, сначала задайте цвет, а потом заполните им прямоугольник с помощью метода fillRect(). Этот метод  должен знать  X и Y координаты верхнего левого угла прямоугольника, а так же ширину и высоту в пикселях.

Круг рисуется с помощью метода  fillOval(), для  этого  надо  знать координаты  центра овала, его высоту и ширину. Когда высота и ширина одинаковы, овал выглядит как круг.

Координата  X в окне увеличивается слева направо, координата Y растет сверху вниз.   Допустим,  ширина  вот этого  прямоугольника  100 пикселей, а высота – 70:

              Координаты X и Y углов прямоугольника показаны в скобках.

Еще  один интересный метод – getPreferredSize(). Для того, чтобы установить  размеры  стола, мы  создадим экземпляр класса Dimension из  Swing.  Виртуальной  машине  Java  нужно  знать  о  размерах  окна, поэтому  она   вызывает   метод   getPreferredSize()   объекта

PingPongGreenTable.  Этот  метод  возвращает  объект  Dimension,который  мы создали в соответствии с размерами нашего стола.

Оба    класса    PingPongGreenTable   и  PingPongGameEngine используют  некоторые константы, которые не меняются. Например, в классе  PingPongGreenTable используется ширина и высота стола, а PingPongGameEngine должен знать, на сколько пикселей двигать мяч–  чем меньше это значение, тем более плавным будет движение.

 Удобно  хранить  все  константы  (переменные  final)  в  интерфейсе.  В нашей  игре  интерфейс  называется  GameConstants.  Если  в  классе понадобятся    эти  значения,  просто  добавьте     implements GameConstants   к  объявлению   класса   и   используйте   любые переменные  final  из  этого  интерфейса  так,  как  будто  они  заданы  в этом   же  классе!  Поэтому  оба  класса  PingPongGreenTable  и PingPongGameEngine реализуют интерфейс GameConstants.

Если  вы решите  поменять  размер  стола,  мяча  или  ракетки, единственное место, где  это нужно будет сделать – интерфейс GameConstants.   Давайте   посмотрим   на   код   класса PingPongGreenTable и интерфейс GameConstants.

package screens;

import javax.swing.JPanel; import javax.swing.JFrame; import javax.swing.BoxLayout; import javax.swing.JLabel;

import javax.swing.WindowConstants;

import java.awt.Point; import java.awt.Dimension; import java.awt.Container; import java.awt.Graphics; import java.awt.Color;

import engine.PingPongGameEngine;

/**

Этот класс рисует стол для пинг-понга и отображает координаты точки,где пользователь кликнул мышью

*/

publicclass PingPongGreenTable extends JPanel

implements GameConstants{ JLabel label;

public Point point = new Point(0,0);

public int ComputerRacket_X =15;

private int kidRacket_Y =KID_RACKET_Y_START;

Dimension preferredSize= new Dimension(TABLE_WIDTH,TABLE_HEIGHT);

// Этот метод устанавливает размер

// Вызывается виртуальной Java машиной

public Dimension getPreferredSize() {

return preferredSize;

}

//Конструктор. Создает обработчик событий мыши. PingPongGreenTable(){

PingPongGameEngine gameEngine =new PingPongGameEngine(this);

// Обрабатывает клики мыши для отображения ее координат

  addMouseListener(gameEngine);

// Обрабатывает движения мыши для передвижения ракеток

  addMouseMotionListener(gameEngine);

}

// Добавить панель с JLabel в окно

void addPaneltoFrame(Container container) {

container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));

container.add(this);

label = new JLabel("Click to see coordinates");

container.add(label);

}

// Перерисовать окно. Этот метод вызывается виртуальной

// машиной, когда нужно обновить экран или

// вызывается метод repaint() из PingPointGameEngine publicvoid paintComponent(Graphics g) {

super.paintComponent(g);

g.setColor(Color.GREEN);

// Нарисовать стол g.fillRect(0,0,TABLE_WIDTH,TABLE_HEIGHT); g.setColor(Color.yellow);

// Нарисовать правую ракетку g.fillRect(KID_RACKET_X_START,kidRacket_Y,5,30); g.setColor(Color.blue);

// Нарисовать левую ракетку g.fillRect(ComputerRacket_X,100,5,30); g.setColor(Color.red);

g.fillOval(25,110,10,10); //Нарисовать мяч

g.setColor(Color.white);

g.drawRect(10,10,300,200);

g.drawLine(160,10,160,210);

// Отобразить точку как маленький квадрат 2×2 пикселей

if (point != null) {

label.setText("Coordinates (x,y): " + point.x +

", " + point.y);

g.fillRect(point.x, point.y, 2, 2);

}

}

// Установить текущее положение ракетки ребенка

public void setKidRacket_Y(int xCoordinate){

this.kidRacket_Y = xCoordinate;

}

// Вернуть текущее положение ракетки ребенка

public int getKidRacket_Y(int xCoordinate){

return kidRacket_Y;

}

publicstaticvoid main(String[] args) {

// Создать экземпляр окна

JFrame f = new JFrame("Ping Pong Green Table");

// Убедиться, что окно может быть закрыто по нажатию на

//крестик в углу

f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); PingPongGreenTable table = new PingPongGreenTable(); table.addPaneltoFrame(f.getContentPane());

// Установить размер окна и сделать его видимым

f.pack();

f.setVisible(true);

}

}

Теперь посмотрим  на интерфейс  GameConstants. Все значения переменных в пикселях. В названиях final переменных используйте заглавные буквы:

package screens;

public interface GameConstants {

public final int TABLE_WIDTH =  320;

public final int TABLE_HEIGHT = 220;

public final int KID_RACKET_Y_START = 100; public final int KID_RACKET_X_START = 300; public final int TABLE_TOP = 12;

public final int TABLE_BOTTOM = 180;

public final int RACKET_INCREMENT = 4;

}

Запущенная  программа не сможет поменять значения этих переменных, потому что они объявлены  как  final.  Но, если вы  решите поменять, например, размер стола, достаточно изменить значения TABLE_WIDTH

и TABLE_HEIGHT и перекомпилировать интерфейс GameConstants.

Решения  в этой игре принимает класс PingPongGameEngine, которыйреализует  2 интерфейса, связанных с событиями мыши.

MouseListener будет использоваться в методе mousePressed(). На каждое  нажатие  мыши  этот  метод  будет  рисовать  маленькую  белую точку  на  столе  и  отображать  ее  координаты.  Честно  говоря,  в  нашей игре  этот код бесполезен, но он покажет простой способ  достать из объекта MouseEvent координаты мыши, которые были переданы JVM.

Метод  mousePressed() передает координаты  нажатой кнопки мыши переменной  point.  После того, как  координаты  переданы, этот метод просит виртуальную машину перерисовать стол.MouseMotionListener отслеживает движение мыши над столом, а метод mouseMoved() будет использоваться для перемещения ракетки ребенка вниз или вверх.

Метод mouseMoved() считает следующую позицию ракетки игрока.  Если указатель мыши находится над ракеткой (координата Y мыши меньше, чем координата Y ракетки), то этот метод гарантирует, что ракетка  не выйдет за пределы стола.Когда  конструктор PingPongGreenTable создает объект класса  PingPongGameEngine, он  передает  в  него  ссылку  объекта  стола (ключевое  слово this означает ссылку на область памяти с объектом PingPongGreenTable).   Теперь, PingPongGameEngine   может«разговаривать»   со  столом,  например,  устанавливать  новые

координаты  мяча или перерисовать стол, когда нужно. Если эта часть не  совсем понятна, перечитайте раздел главы 6 о передаче данных между классами.

В  нашей игре ракетки перемещаются вертикально по 4 пикселя, как мы задали  в интерфейсе GameConstants (класс PingPongGameEngine реализует этот интерфейс). Например, следующая строка отнимает 4 от значения переменной kidRacket_Y:kidRacket_Y -= RACKET_INCREMENT;

Например,  если координата Y ракетки была 100, после этой строки кодаона становится равной 96 и ракетка должна подняться вверх. Тот же результат  можно получить таким выражением:kidRacket_Y = kidRacket_Y – RACKET_INCREMENT;

Если вы  помните, мы  говорили о разных способах изменить значение переменной в Главе 3.

Далее  – класс PingPongGameEngine.

package engine;

import java.awt.event.MouseEvent;

import java.awt.event.MouseListener;

import java.awt.event.MouseMotionListener;

import screens.*;

public class PingPongGameEngine  implements

MouseListener, MouseMotionListener, GameConstants{ PingPongGreenTable table;

public int kidRacket_Y = KID_RACKET_Y_START;

// Конструктор. Содержит ссылку на объект стола public PingPongGameEngine(PingPongGreenTable  greenTable){

table = greenTable;

}

// Обязательные методы из интерфейса MouseListener

public void  mousePressed(MouseEvent e) {

// Взять X и Y координаты указателя мыши

// и установить их "белой точке" на столе

table.point.x = e.getX();

table.point.y = e.getY();

// Внутри вызывает метод paintComponent()и обновляет окно

table.repaint();

}

public void mouseReleased(MouseEvent e) {}; public void mouseEntered(MouseEvent e) {}; public void mouseExited(MouseEvent e) {}; public void mouseClicked(MouseEvent e) {};

// Обязательные методы из интерфейса MouseMotionListener

public void mouseDragged(MouseEvent e) {}

public void  mouseMoved(MouseEvent e) {

int mouse_Y = e.getY();

// Если мышь находится выше ракетки ребенка

// и не выходит за пределы стола –

// передвинуть ее вверх, в противном случае – опустить вниз

if (mouse_Y < kidRacket_Y && kidRacket_Y > TABLE_TOP){

kidRacket_Y -= RACKET_INCREMENT;

}else if (kidRacket_Y < TABLE_BOTTOM) {

kidRacket_Y += RACKET_INCREMENT;

}

// Установить новое положение ракетки

table.setKidRacket_Y(kidRacket_Y);     table.repaint();

}

}

Источник: Java  Programming for Kids, Parents and Grandparents by Yakov Fain

По теме:

  • Комментарии