метод repaint() не перерисовывается, анимация гравитации мяча

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

Я отлаживал много раз, и я просто не могу ударить его по голове.

Предполагается, что он... переместится туда, куда вы его перетащите >>> когда вы отпустите его, он должен упасть, пока не упадет на землю.

Спасибо заранее.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class DragBallPanel extends JPanel implements MouseListener, MouseMotionListener
{
     private static final int BALL_DIAMETER = 40;
     private int screen_size_x = 300;
     private int screen_size_y = 300;
     private int ground_lvl = screen_size_y - 15;

     private int _ballX     = ground_lvl/2;
     private int _ballY     = ground_lvl - BALL_DIAMETER;
     private final double GRAVITY = -9.8;
     private double velocity;
     private static final double TERM_VEL = -100;

     private int _dragFromX = 0;
     private int _dragFromY = 0;

     private boolean _canDrag  = false;


     public DragBallPanel() throws InterruptedException
     {
        setPreferredSize(new Dimension(screen_size_x, screen_size_y));
        setBackground(Color.darkGray);
        setForeground(Color.darkGray);

        this.addMouseListener(this); 
        this.addMouseMotionListener(this);
    }

    public void paintComponent(Graphics g)
     {
        super.paintComponent(g);   // Required for background.
          g.setColor (Color.green);
          g.fillRect (0, 280, 400, 50 );
          g.setColor (Color.black);
        g.fillOval(_ballX, _ballY, BALL_DIAMETER, BALL_DIAMETER);

    }

    public void mousePressed(MouseEvent e)
    {
        int x = e.getX();
        int y = e.getY();

        if (x >= _ballX && x <= (_ballX + BALL_DIAMETER)
                && y >= _ballY && y <= (_ballY + BALL_DIAMETER))\
          {
            _canDrag = true;
            _dragFromX = x - _ballX;
            _dragFromY = y - _ballY;
        } else
          {
            _canDrag = false;
        }
    }

    //===== mouseDragged ======
    /** Set x,y  to mouse position and repaint. */
    public void mouseDragged(MouseEvent e)
    {
        if (_canDrag)
          {   // True only if button was pressed inside ball.
            //--- Ball pos from mouse and original click displacement
            _ballX = e.getX() - _dragFromX;
            _ballY = e.getY() - _dragFromY;

            //--- Don't move the ball off the screen sides
            _ballX = Math.max(_ballX, 0);
            _ballX = Math.min(_ballX, getWidth() - BALL_DIAMETER);

            //--- Don't move the ball off top or bottom
            _ballY = Math.max(_ballY, 0);
            _ballY = Math.min(_ballY, getHeight() - BALL_DIAMETER);

            this.repaint();
        }
    }

    public void mouseExited(MouseEvent e)
    {
          while(_ballY < ground_lvl)
          {
                 simulateGravity();
          }   
    }

     public void simulateGravity()
     {
         if(_canDrag)
         {
             try{
                 velocity = velocity + GRAVITY;

               if (velocity < TERM_VEL)
                 {
                    velocity = TERM_VEL;
                 }

                if (_ballY >= ground_lvl - BALL_DIAMETER)
                {
                   velocity = velocity/4; 
                } 
                _ballY += velocity;
                 Thread.sleep(400);
                 this.repaint();//**problem occurs here**

              }catch(InterruptedException ie)
              {
              }
         }
     }

    public void mouseMoved   (MouseEvent e){}
    public void mouseEntered (MouseEvent e){}
    public void mouseClicked (MouseEvent e){}
    public void mouseReleased(MouseEvent e){}
}

основной () класс

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;


public class DragDemo extends JApplet
{
    public static void main(String[] args) throws InterruptedException
    {
        JFrame window = new JFrame();
        window.setTitle("Drag Demo");
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          //window.add(new DragBallPanel());
        window.setContentPane(new DragBallPanel());
          window.setResizable(false);
        window.pack();
        window.show();
    }

    public DragDemo() throws InterruptedException
    {
        new DragBallPanel();
    }
}

person CommonKnowledge    schedule 20.05.2012    source источник
comment
Чтобы быстрее получить помощь, опубликуйте SSCCE.   -  person Andrew Thompson    schedule 21.05.2012
comment
После добавления main и его запуска я не совсем понимаю проблему. Я могу перетащить мяч куда хочу, но если я перенесу его к левой стене, он застрянет там и больше не будет двигаться. Это намерение? Если нет, можете ли вы объяснить другими словами, что должно произойти?   -  person Andrew Thompson    schedule 21.05.2012
comment
Это очень небольшое количество кода, поэтому я разместил его целиком. Я только что отредактировал его, чтобы включить только необходимое. Спасибо...   -  person CommonKnowledge    schedule 21.05.2012
comment
Предполагается, что его нужно перетаскивать, а затем, как только вы отпустите мышь, он должен упасть, чтобы «симулировать гравитацию».   -  person CommonKnowledge    schedule 21.05.2012
comment
очень маленький объем кода «Проблема» заключалась не в том, что он включал, а в том, что он не включал! Пожалуйста, перейдите по ссылке и прочитайте о SSCCE и почему они хорошая идея.   -  person Andrew Thompson    schedule 21.05.2012
comment
Совет Если вы добавите этот код (метод main) в конец исходного кода, он станет SSCCE public static void main(String[] args) { SwingUtilities.invokeLater( new Runnable() { public void run() { DragBallPanel dbp = new DragBallPanel(); JOptionPane.showMessageDialog(null, dbp); } }); } Некоторые могут пожаловаться на то, что 133 строки кода не являются «короткими», но я с радостью проигнорирую их (199 строк по-прежнему мало, IMO).   -  person Andrew Thompson    schedule 21.05.2012
comment
Мне ужасно жаль, что я не включил класс драйвера main(). Я добавил это ниже. Надеюсь, это то, что вы имели в виду.   -  person CommonKnowledge    schedule 21.05.2012


Ответы (2)


Этот SSCCE начинает показывать проблемы в коде.

  1. Скомпилируйте код.
  2. Запустить его.
  3. Перетащите мяч вверх.
  4. Отпустите мяч.
  5. Уберите мышь из области рисования, чтобы увидеть...
  6. Мяч падает вверх!

Вы, кажется, перевернули значения Y. Они начинаются вверху экрана и идут вниз. Кроме того, код блокировал EDT в бесконечном цикле. Чтобы решить эту проблему, запустите анимацию с помощью Swing Timer.

Пожалуйста, прочтите документ по SSCCE и спросите, есть ли в нем что-то, что вам непонятно. Я могу объяснить. :)


import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class DragBallPanel extends JPanel implements MouseListener, MouseMotionListener
{

    private static final int BALL_DIAMETER = 40; // Diameter of ball

    private int screen_size_x = 300;
    private int screen_size_y = 300;
    private int ground_lvl = screen_size_y - 15;

    private int _ballX     = ground_lvl/2;
    private int _ballY     = ground_lvl - BALL_DIAMETER;
    private final double GRAVITY = -9.8;
    private double velocity;
    private static final double TERM_VEL = 100;

    private int _dragFromX = 0;    // pressed this far inside ball's
    private int _dragFromY = 0;    // bounding box.

    /** true means mouse was pressed in ball and still in panel.*/
    private boolean _canDrag  = false;

    public DragBallPanel()
    {
        setPreferredSize(new Dimension(screen_size_x, screen_size_y));
        setBackground(Color.darkGray);
        setForeground(Color.darkGray);

        this.addMouseListener(this);
        this.addMouseMotionListener(this);
    }

    public void paintComponent(Graphics g)
     {
        super.paintComponent(g);   // Required for background.
          g.setColor (Color.green);
          g.fillRect (0, 280, 400, 50 );
          g.setColor (Color.black);
        g.fillOval(_ballX, _ballY, BALL_DIAMETER, BALL_DIAMETER);

    }

    public void mousePressed(MouseEvent e)
    {
        int x = e.getX();   // Save the x coord of the click
        int y = e.getY();   // Save the y coord of the click

        if (x >= _ballX && x <= (_ballX + BALL_DIAMETER)
                && y >= _ballY && y <= (_ballY + BALL_DIAMETER)) {
            _canDrag = true;
            _dragFromX = x - _ballX;  // how far from left
            _dragFromY = y - _ballY;  // how far from top
        } else {
            _canDrag = false;
        }
    }

    //========= mouseDragged =================
    /** Set x,y  to mouse position and repaint. */
    public void mouseDragged(MouseEvent e)
    {
        if (_canDrag) {   // True only if button was pressed inside ball.
            //--- Ball pos from mouse and original click displacement
            _ballX = e.getX() - _dragFromX;
            _ballY = e.getY() - _dragFromY;

            //--- Don't move the ball off the screen sides
            _ballX = Math.max(_ballX, 0);
            _ballX = Math.min(_ballX, getWidth() - BALL_DIAMETER);

            //--- Don't move the ball off top or bottom
            _ballY = Math.max(_ballY, 0);
            _ballY = Math.min(_ballY, getHeight() - BALL_DIAMETER);

            this.repaint(); // Repaint because position changed.
        }
    }

    //====================================================== method mouseExited
    /** Turn off dragging if mouse exits panel. */
    public void mouseExited(MouseEvent e)
     {
         System.out.println("Exited: " + e);
        //_canDrag = false;
        runGravity();
        /*  while(_ballY < ground_lvl)
          {
             simulateGravity();
          }*/
    }

    Timer timer;
    ActionListener animate;

    public void runGravity() {
        if (animate==null) {
            animate = new ActionListener() {
                public void actionPerformed(ActionEvent ae) {
                    System.out.println("Ground: " + (_ballY-ground_lvl));
                    if (_ballY > ground_lvl) {
                        timer.stop();
                    } else {
                        simulateGravity();
                    }
                }
            };
            timer = new Timer(100,animate);
        }
        timer.start();
    }

     public void simulateGravity()
     {
         System.out.println("_canDrag: " + _canDrag);
         if(_canDrag)
         {

             velocity = velocity + GRAVITY;

           if (velocity > TERM_VEL)
             {
                velocity = TERM_VEL;
             }

            if (_ballY >= ground_lvl - BALL_DIAMETER)
            {
                //We have hit the "ground", so bounce back up. Reverse
                //the speed and divide by 4 to make it slower on bouncing.
                //Just change 4 to 2 or something to make it faster.
               velocity = velocity/4;
            }
            _ballY += velocity;
             //this.revalidate();
             this.repaint();
         }
    }

    public void mouseMoved   (MouseEvent e){}
    public void mouseEntered (MouseEvent e){}
    public void mouseClicked (MouseEvent e){}
    public void mouseReleased(MouseEvent e){}

    public static void main(String[] args) {
        SwingUtilities.invokeLater( new Runnable() {
            public void run() {
                DragBallPanel dbp = new DragBallPanel();
                JOptionPane.showMessageDialog(null, dbp);
            }
        });
    }
}
person Andrew Thompson    schedule 20.05.2012

Попробуйте updateUI() вместо repaint().

Если нет эффекта, удалите компонент и добавьте его снова.

person shadowdiver    schedule 20.05.2012
comment
Мне кажется (плохо нацеленным и) случайным предположением. Я сделал много анимации, и мне никогда не приходилось вызывать updateUI() как часть процесса. Второе предложение еще хуже. :( Пожалуйста, удалите это. Это не ответ, и это сделает комментарий плохим (при условии, что у вас есть представитель, чтобы опубликовать их). - person Andrew Thompson; 21.05.2012
comment
Извините, но у меня была именно эта проблема, и поиск решения занимает несколько часов. - person shadowdiver; 21.05.2012