Как заставить двигаться объект в java
Перейти к содержимому

Как заставить двигаться объект в java

  • автор:

Как заставить объект двигаться?

Новенький в JavaFX. Хочу сделать игру Xonix. Есть поле размером 1920 * 1080. Сейчас проблема в том, что нужно заставить квадратик двигаться нажимая на кнопки вверх, вниз и т.д. Как это можно реализовать через JavaFX?

Отслеживать
48.9k 17 17 золотых знаков 56 56 серебряных знаков 100 100 бронзовых знаков
задан 24 мар 2018 в 9:26
Andrei Viktor Andrei Viktor
59 4 4 бронзовых знака

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

Простой пример (без проверок на границы). Комментарии к этому коду тоже вроде не нужны:

import javafx.application.Application; import javafx.concurrent.Task; import javafx.event.EventHandler; import javafx.geometry.Side; import javafx.scene.Scene; import javafx.scene.input.KeyEvent; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.stage.Stage; public class App extends Application < @Override public void start(Stage primaryStage) throws Exception < GameUnit gameUnit = new GameUnit(150, 0, 10, 10); Scene scene = new Scene(new Pane(gameUnit), 300, 275); scene.setOnKeyPressed(gameUnit); primaryStage.setScene(scene); primaryStage.show(); >private static class GameUnit extends Rectangle implements EventHandler  < public GameUnit(double x, double y, double width, double height) < super(x, y, width, height); setFill(Color.BLACK); >private void checkInitBehavior() < if ( behavior == null ) < behavior = new GameUnitBehavior(); new Thread(behavior).start(); >> private GameUnitBehavior behavior; @Override public void handle(KeyEvent event) < checkInitBehavior(); switch (event.getCode()) < case LEFT: behavior.moveToSide(Side.LEFT); break; case RIGHT: behavior.moveToSide(Side.RIGHT); break; case UP: behavior.moveToSide(Side.TOP); break; case DOWN: behavior.moveToSide(Side.BOTTOM); break; >> private class GameUnitBehavior extends Task < private boolean vertical = false; private boolean positiv = false; private double step = 10.0; @Override protected Object call() throws Exception < while ( getScene().getWindow().isShowing() ) < if ( vertical ) < setX(getX() + (positiv ? step : -step)); >else < setY(getY() + (positiv ? step : -step)); >Thread.sleep(100); > return null; > public void moveToSide(Side side) < vertical = side.isVertical(); positiv = side == (vertical ? Side.RIGHT : Side.BOTTOM ); >> > > 

Отслеживать
ответ дан 24 мар 2018 в 13:22
Александр Савостьянов Александр Савостьянов
1,344 1 1 золотой знак 7 7 серебряных знаков 15 15 бронзовых знаков

А теперь с помощью этого кода, как мне сделать так. Есть поле, и когда квадратик проходит по нему, часть этого поля исчезает, как бы «отрезается»? Если не поняли, пожалуйста, можете посмотреть gameplay игры xonix. Буду очень благодарен

24 мар 2018 в 16:47

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

Движение к заданной точке

Author24 — интернет-сервис помощи студентам

Реализовал следующее: имеется окно, внутри которого располагается маленькое изображение. При щелчке мышью в любом месте окна картинка начинает двигаться по прямой к указанной точке. В чем проблема: щелчок мыши в окне не всегда вызывает ответную реакцию, т.е. картинка может продолжать двигаться к точке указанной раннее.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
package simple8PG; import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.io.*; import java.awt.geom.*; import javax.imageio.*; public class ActionComponent8 { private MainDragon mainDragon; public ActionComponent8() { mainDragon = new MainDragon(); EventQueue.invokeLater(new Runnable() { @Override public void run() { JFrame frame = new JFrame(); frame.setSize(550, 550); Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); frame.setLocation(d.width / 2 - frame.getWidth() / 2, d.height / 2 - frame.getHeight() / 2); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(mainDragon); frame.addMouseListener(new MouseControl()); frame.setVisible(true); } }); } private class MouseControl extends MouseAdapter { @Override public void mouseClicked(MouseEvent event) { mainDragon.movePoint(event.getX(), event.getY()); } } private class MainDragon extends JPanel implements ActionListener { private Image dragon; private Point2D point; private Timer timer; private double speedX; private double speedY; private final double speedXY; private MainDragon() { setSize(100, 70); //загрузить изображение персонажа try { dragon = ImageIO.read(new File( "D:\\JAVA\\myExperiments\\eventsPG\\src\\simple8PG\\hero.png")); } catch (Exception e) { e.printStackTrace(); } speedXY = 4d; point = new Point2D.Float(); timer = new Timer(50, this); timer.start(); } //указать новое положение точки, к которой будет двигаться герой public void movePoint(int x, int y) { point.setLocation(x, y); } @Override public void paintComponent(Graphics g) { g.drawImage(dragon, 0, 0, 100, 70, null); } @Override public void actionPerformed(ActionEvent event) { synchronized (this) { double x = point.getX() - (this.getX() + this.getWidth() / 2); double y = point.getY() - (this.getY() + this.getHeight()); double xy = Math.sqrt(x * x + y * y); /*прикращать движение нужно на расстоянии большем, чем скорость перемещение, иначе вместо остановки в назначенной точки изображение будет дергаться*/ if (xy >= 5) { speedX = speedXY * (x / xy); speedY = speedXY * (y / xy); this.setLocation((int) (getX() + speedX), (int) (getY() + speedY)); } } } } }

Простая анимация на java

сертификат

По сути дела ничего сложного: создаем синий круг, по нажатию кнопки его можно заставить двигаться по диагонали с верхнего левого угла к нижнему правому. В конструкторе класса MovingCircle два параметра — это цвет и скорость (точнее, наоборот, величина замедления). Кроме этого, скорость регулируют еще две строки 57 (x++; — скорость движения по горизонтали) и 58 (y++; — скорость движения по вертикали).

Итак, рисуем кружок зеленого цвета, задаем параметры. В итоге на экране после запуска программы появляется окно с размерами 600 на 550 точек (строка кода 89). В этом окне два поля: рабочая область слева с белым фоном на котором герой нашей статьи — зеленый круг, а справа кнопка: по нажатию кружок начинает двигаться, нажать еще раз — останавливается.

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

А вот и сам код. Можно его скопировать, а можно просто скачать готовый архив с файлом исходника и классами — MovingCircle.zip, либо уже готовый к употреблению архив jar — MovingCircle.jar. Для компилирования и запуска использовалась Java SE Development Kit 7u45 на Windows 7, а также Ubunty 12.04, но должно заработать на любом компьютере, на котором установлена хотя бы jre, хотя бы 2 версии.

import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.Ellipse2D; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; import javax.swing.Timer; @SuppressWarnings("serial") public class MovingCircle extends JComponent implements ActionListener < private double scale; private Color color; private Timer timer; public double x =10; public double y =10; public MovingCircle(Color color, int delay) < scale = 1.0; timer = new Timer(delay, this); this.color = color; setPreferredSize(new Dimension(500, 500)); >public void start() < timer.start(); >public void stop() < timer.stop(); >@Override public void actionPerformed(ActionEvent arg0) < repaint(); >@Override protected void paintComponent(Graphics g) < Graphics2D g2d = (Graphics2D) g; g2d.setColor(Color.white); int width = 500; int height = 500; g.fillRect(0, 0, width, height); g2d.setColor(Color.black); g2d.drawRect(0, 0, width - 1, height - 1); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setColor(color); g2d.scale(scale, scale); x++; y++; Ellipse2D el = new Ellipse2D.Double(x, y, 20, 20); g2d.fill(el); >public static void main(String[] args) < SwingUtilities.invokeLater(new Runnable() < public void run() < JFrame frame = new JFrame("Moving Circle"); JPanel panel = new JPanel(); final MovingCircle MovingCircleGreen = new MovingCircle(Color.green, 20); panel.add(MovingCircleGreen); frame.getContentPane().add(panel); final JButton button = new JButton("Start"); button.addActionListener(new ActionListener() < private boolean pulsing = false; @Override public void actionPerformed(ActionEvent e) < if (pulsing) < pulsing = false; MovingCircleGreen.stop(); button.setText("Start"); >else < pulsing = true; MovingCircleGreen.start(); button.setText("Stop"); >> >); panel.add(button); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(600, 550); frame.setVisible(true); > >); > >

Автор этого материала — я — Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML — то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.

статьи IT, java, анимация

  • Java: центрирование окна
  • Создание графика по точкам на Java
  • Топ 6 онлайн компиляторов Java для студентов

Оставить комментарий
Отправляя сообщение я подтверждаю, что ознакомлен и согласен с политикой конфиденциальности данного сайта.

Пишем 2-d игру на Java #2

Доброго времени суток всем! Продолжение 1-ого урока (ссылка на первый).

Задачи

Сегодня мы должны создать игрока, и реализовать в нем метод движения

Начало

Приступим. Для начала создадим новый класс Player.java.

Создадим несколько переменных, типа int. Первая это x, вторая это y, и третья speed. Пускай они будут приватными, во избежание дальнейших ошибок(установите сразу им значения, x=0, y=0, speed = любая скорость, я буду ставить 2). Также, создадим три метода — getSpeed(), getX() и getY(). Они выглядят так:

 public int getX() < return x; >public int getY() < return y; >public int getSpeed()

Они будут возвращать нам текущие x и y координаты нашего игрока, а также скорость игрока.

Теперь, нам нужен метод, отвечающий за движение. Так его и назовем — move. Пока у нас нету слушателя клавиш, по этому, просто напишем:

 public void move()

Возвращаемся в наш класс Main.java и в нем, создаем объект нашего игрока:

Player player = new Player();

Далее, в методе actionPerformed() пишем:

player.move();

Теперь, у нас при каждом обновлении таймера будет двигаться игрок. Но сейчас мы это движение не увидим, т.к. координаты игрока мы нигде не используем. Сейчас я коротко объясню как происходит движение на экране. Двигается не сама картинка нашего игрока, а задний план, который имитирует движение игрока. Так что, переходим в метод paint() и там, вместо координат отрисовки, вписываем player.getX() и player.getY(). Должно выйти так:

g.drawImage(img, player.getX(), player.getY(),frame.getWidth(), frame.getHeight(), null);

Запускаем, и видим что наш фон двигается.

Теперь я объясню, что мы не совсем корректно сделали.

Мы должны иметь две отдельные координаты — координата карты и координата игрока. Для чего это нужно? Сейчас мы слой отрисовываем относительно координаты игрока. В дальнейшем, у нас появятся объекты, находящиеся на карте, и проверять, взаимодействует ли с ними игрок будет проще, имея координаты карты. Надеюсь, объяснил понятно, а теперь мы это реализуем.

По-хорошему, мы должны иметь отдельный объект, Universe (Вселенная) в котором и будет содержаться информация о нашей карте(время суток, координаты и т.п.). В последующих уроках мы это сделаем, а пока, просто добавим в классе игрока две новые переменные: mapX и mapY, и сразу установим им значения, 0 и 0. И, как в случае с x и y, создадим 2 getter’a.

Теперь подкорректируем наш метод move().

Напишем вместо x+=speed это:

x-=speed; mapX+=speed;

И вернемся к методу paint и поменяем

g.drawImage(img, player.getX(), player.getY(),frame.getWidth(), frame.getHeight(), null);
g.drawImage(img, player.getMapX(), player.getMapY(),frame.getWidth(), frame.getHeight(), null);

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

Но мы видим, что картинка одна, и за ней остается след. И вот мы подошли к такой развилке. Мы можем создать игру, в которой мир будет постоянно расширяться, в зависимости оттого, в каком направлении идет игрок. Либо, сделать игру с определенного размера локацией, за пределы которой выйти нельзя, но локации смогут меняться. С какими проблемами я столкнулся, при создании этих двух вариантов. Если будем создавать игру без границ, то:

  1. Надо будет осуществить генерацию этого мира, и если у нее нет пределов, то её надо делать случайной, т.е. будут баги прорисовки, с которыми мы будем сталкиваться постоянно.
  1. Либо она будет прямолинейной, с сюжетом, либо смена локаций будет случайна, но в таком случае возникает проблема номер 2.
  2. Локаций должно быть много, чтобы человеку не надоело играть в эту игру.

Хорошо, пока обойдемся без дополнительных слоев, создадим слушателя нажатий на клавиши.

В конструкторе класса Main.java допишем такую строку:

frame.addKeyListener(new KeyAdapter() < >);

Некоторые могут спросить, почему мы используем метод «добавить слушателя», а добавляем адаптер? Просто адаптер позволяет не использовать все три метода класса слушателя, а допустим, как в нашем случае, мы реализуем в нем только два:

 @Override public void keyPressed(KeyEvent e) < // TODO Auto-generated method stub >@Override public void keyReleased(KeyEvent e) < // TODO Auto-generated method stub >

Первый метод отвечает за нажатие на клавишу, а второй за ее отпускание. Третий метод реагирует на короткое нажатие клавиши, а не задерживание её, как в первом методе. Теперь, чтобы у нас не получилась белеберда, и чтобы не усложнять себе жизнь, сделаем точно такие же два метода в классе игрока. И теперь в наших методах, находящихся в классе Main.java напишем:

player.keyPressed(e);
player.keyReleased(e);

Готово! Теперь у нас есть слушатель нажатий на клавиши. Давайте проверим его работоспособность, просто написав в каждом из методов в классе Player.java такую строку:

System.out.println(e.getKeyCode());

Запускаем программу, смотрим в нашу консоль, и нажимаем на клавиши.

Если при каждом нажатии на клавишу выписываются цифры в консоль, это означает что вы сделали все правильно. Не бойтесь, запоминать все эти клавиши не надо, за нас это уже сделал класс KeyEvent.

Теперь создадим энум, который будет отвечать за направление игрока. Для тех, кто не знает, энум, это такая переменная, которая может иметь несколько значений, которые мы заранее прописали. Создаем энум, под названием Direction. В него, через запятую, пишем такие значения: UP, DOWN, LEFT, RIGHT, NONE. Теперь, в классе Player создаем новую переменную типа Direction, которую назовем playerDirection (сразу поставьте значение Direction.NONE). Теперь, сделаем так, чтобы при нажатии соответствующих кнопок, направление игрока изменялось. Кстати, мы всегда будем работать с методами keyPressed и keyReleased из класса Player.java, в классе Main.java их не трогайте. Так вот, для начала, в методе keyPressed объявим переменную, типа int, которая равна e.getKeyCode(). Мы делаем это для удобства, чтобы в дальнейшем каждый раз не прописывать одно и то же. Так вот, дальше пишем:

if(key == KeyEvent.VK_W) < playerDirection = Direction.UP; >if(key == KeyEvent.VK_S) < playerDirection = Direction.DOWN; >if(key == KeyEvent.VK_A) < playerDirection = Direction.LEFT; >if(key == KeyEvent.VK_D)

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

Далее, изменим метод move. Он должен будет выглядеть так:

switch(playerDirection)

Для тех, кто не знает, switch это тоже самое что и if, только в более удобной форме. Запускаем программу, и любуемся!

На сегодня все. Опять же, оставляю весь код, для тех, кто запутался.

Player.java

import java.awt.event.KeyEvent; public class Player < private int x = 0; private int y = 0; private int speed = 2; private int mapX = 0; private int mapY = 0; private Direction playerDirection = Direction.NONE; public void move() < switch(playerDirection) < case UP: mapY+=speed; break; case DOWN: mapY-=speed; break; case LEFT: mapX+=speed; break; case RIGHT: mapX-=speed; break; default: break; >> public void keyPressed(KeyEvent e) < int key = e.getKeyCode(); if(key == KeyEvent.VK_W) < playerDirection = Direction.UP; >if(key == KeyEvent.VK_S) < playerDirection = Direction.DOWN; >if(key == KeyEvent.VK_A) < playerDirection = Direction.LEFT; >if(key == KeyEvent.VK_D) < playerDirection = Direction.RIGHT; >> public void keyReleased(KeyEvent e) < System.out.println(e.getKeyCode()); >public int getX() < return x; >public int getY() < return y; >public int getSpeed() < return speed; >public int getMapX() < return mapX; >public int getMapY() < return mapY; >> 

Main.java

import java.awt.Graphics; import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.Timer; public class Main extends JPanel implements ActionListener < Image img = new ImageIcon("2.png").getImage(); Timer timer = new Timer(20, this); Player player = new Player(); JFrame frame; public Main(JFrame frame) < this.frame = frame; timer.start(); frame.addKeyListener(new KeyAdapter() < @Override public void keyPressed(KeyEvent e) < // TODO Auto-generated method stub player.keyPressed(e); >@Override public void keyReleased(KeyEvent e) < // TODO Auto-generated method stub player.keyReleased(e); >>); > public void paint(Graphics g) < g.drawImage(img, player.getMapX(), player.getMapY(),frame.getWidth(), frame.getHeight(), null); >@Override public void actionPerformed(ActionEvent e) < // TODO Auto-generated method stub repaint(); player.move(); >> 

Display.java

Никак не поменялся.

Спасибо за внимание! Не забудьте проголосовать.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *