Как обнулить гравитацию не насовсем?

Я решил написать небольшую программу, в которой нужно управлять прямоугольником. Если нажать на клавишу "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 шт):

Автор решения: Зонтик

Способ реализации вашей программы странный. Обычно это делается по-другому. Давайте сделаем шаг назад и посмотрим, как:

  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);
  1. В прослушивателе клавиш вызываем 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);
    }
}
  1. А теперь самое главное: как сделать так, чтобы фигура двигалась? Как вызывать метод move() раз в какое-то время? В этом нам поможет класс java.util.Timer. Сначала создадим объект java.util.TimerTask и в методе run() укажем, что нужно будет делать нашему таймеру каждый раз:
public class Animation extends TimerTask {
    @Override
    public void run() {
        GameField.figure.move(); //Двигаем фигуру
        GameWindow.window.repaint(); //Перерисовываем окно
    }
}
  1. И где-нибудь запускаем наш таймер:
Timer timer = new Timer();
timer.schedule(new Animation(), //Ссылка на объект с методом run()
        0, //Насколько надо "отложить" назначение таймера (0 означает, что не будем откладывать)
        100); //Время (в миллисекундах) через которое каждый раз будет запускаться метод run().
  1. И не забудем удалить старый код из класса GameField, который отвечал за передвижение фигуры. А также ОБЯЗАТЕЛЬНО нужно убрать вызов repaint() из paintComponent(). Иначе получите StackOverflowError, ведь repaint() в конечном итоге вызовет paintComponent().
→ Ссылка