Как обнулить гравитацию не насовсем?
Я решил написать небольшую программу, в которой нужно управлять прямоугольником. Если нажать на клавишу "U", то прямоугольник будет двигаться вверх, а если "D", опускаться вниз. У него есть своя скорость, при запуске программы он сам по себе опускается вниз, а при нажатии клавиш скорость не обнуляется, поэтому получается своего рода гравитация, которая постоянно тянет его вниз.
Также, помимо всех выше перечисленных свойств, я хочу написать такое условие: если ничего не нажато, скорость равна 70 (т.е работает), а если что-то нажато (либо U либо D) скорость обнуляется и сила гравитации не мешает ему подниматься вверх.
У меня не получается это сделать (точнее получается, но при первом нажатии скорость обнуляется насовсем, даже если кнопку отпустить, а мне это не нужно). Подскажите пожалуйста, как это реализовать!
Первый класс:
package Gravitation;
import javax.swing.*;
public class GameWindow extends JFrame {
public static GameWindow window;
public static JTextField textField;
public static void main(String[] args) {
window = new GameWindow();
window.setSize(728,563);
GameField gameField = new GameField();
textField = new JTextField();
window.add(gameField);
Management.management();
GameField.field();
gameField.add(textField);
window.setVisible(true);
window.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
Второй класс:
package Gravitation;
import javax.swing.*;
import java.awt.*;
public class GameField extends JPanel {
public static float x = 509, y = 218, v = 70;
public static long last_frame_time;
public static void field(){
last_frame_time = System.nanoTime();
}
public static void onRepaint(Graphics g){
long c_time = System.nanoTime();
float delta_time = (last_frame_time-c_time) * 0.000000001f;
last_frame_time = c_time;
y = y - v * delta_time;
g.setColor(Color.BLACK);
g.fill3DRect((int)x,(int)y,75,45,true);
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
onRepaint(g);
repaint();
}
}
Третий класс:
package Gravitation;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
public class Management {
public static void management(){
GameWindow.textField.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_U){
GameField.y-=4;
}
if(e.getKeyCode()==KeyEvent.VK_D){
GameField.y+=4;
}
}
});
}
}
Ответы (1 шт):
Способ реализации вашей программы странный. Обычно это делается по-другому. Давайте сделаем шаг назад и посмотрим, как:
- Давайте сначала определим, что должна делать ваша фигура. Создадим интерфейс
MovableFigure
:
public interface MovableFigure {
enum Motion{UP, DOWN}
Motion getMotion();
void setMotion(Motion motion);
void move();
int getX();
int getY();
}
Хорошо. Теперь напишем его реализацию:
public class MyFigure implements MovableFigure {
private int x;
private int y;
private MovableFigure.Motion motion;
public MyFigure(Movable.Motion defaultMotion) {
setMotion(defaultMotion);
}
@Override
public void setMotion(MovableFigure.Motion motion) {
if(motion == null) {
throw new IlltgalArgumentException("motion can't be null!");
}
this.motion = motion;
}
@Override
public MovableFigure.Motion getMotion() {
return motion;
}
@Override
public int getX() {
return x;
}
@Override
public int getY() {
return y;
}
@Override
public void move() {
if(motion == MovableFigure.Motion.UP) {
//Двигаем фигуру вверх
y -= 5;
} else {
//Двигаем фигуру вниз
y += 5;
}
}
}
Создадим поле в вашем классе GameField:
public static MovableFigure figure = new MyFigure(MovableFigure.Motion.DOWN);
- В прослушивателе клавиш вызываем
setMotion()
у нашего объекта-фигуры:
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_U) {
GameField.figure.setMotion(MovableFigure.Motion.UP);
}
if(e.getKeyCode() == KeyEvent.VK_D){
GameField.figure.setMotion(MovableFigure.Motion.DOWN);
}
}
- А теперь самое главное: как сделать так, чтобы фигура двигалась? Как вызывать метод
move()
раз в какое-то время? В этом нам поможет классjava.util.Timer
. Сначала создадим объектjava.util.TimerTask
и в методеrun()
укажем, что нужно будет делать нашему таймеру каждый раз:
public class Animation extends TimerTask {
@Override
public void run() {
GameField.figure.move(); //Двигаем фигуру
GameWindow.window.repaint(); //Перерисовываем окно
}
}
- И где-нибудь запускаем наш таймер:
Timer timer = new Timer();
timer.schedule(new Animation(), //Ссылка на объект с методом run()
0, //Насколько надо "отложить" назначение таймера (0 означает, что не будем откладывать)
100); //Время (в миллисекундах) через которое каждый раз будет запускаться метод run().
- И не забудем удалить старый код из класса
GameField
, который отвечал за передвижение фигуры. А также ОБЯЗАТЕЛЬНО нужно убрать вызовrepaint()
изpaintComponent()
. Иначе получитеStackOverflowError
, ведьrepaint()
в конечном итоге вызоветpaintComponent()
.