【问题标题】:Why does the height of the rectangles jump vary?为什么矩形跳跃的高度不同?
【发布时间】:2012-11-10 14:31:24
【问题描述】:

为什么矩形的跳跃高度不同?它似乎进入了一个循环。首先它跳得很低,然后它根本不跳,然后它跳得很高,然后它根本不跳。我不知道为什么使用相同的代码并且它是由相同的事件触发的。

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JFrame;
import javax.swing.JPanel;


@SuppressWarnings("serial")
 class Game extends JPanel{
Square square = new Square(this);
 Ground ground = new Ground (this);
public Game() {
    addKeyListener(new KeyListener() {
        @Override
        public void keyTyped(KeyEvent e) {
        }

        @Override
        public void keyReleased(KeyEvent e) {
            square.keyReleased(e);
        }

        @Override
        public void keyPressed(KeyEvent e) {
            square.keyPressed(e);
        }

    });
    setFocusable(true);
}
public static void main(String[] args) throws InterruptedException {

    JFrame frame = new JFrame("My Mario");
    Game game = new Game();
    frame.add(game);
    frame.setSize(600, 700);
    frame.setVisible(true);

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


    while (true) {
        game.move();
        game.repaint();
        Thread.sleep(30);





    }

}
private void move() {

    square.move();
}
@Override
public void paint(Graphics g) {
    super.paint(g);
    Graphics2D g2d = (Graphics2D) g;
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
    square.paint(g2d);
    ground.paint(g2d);
}
}

public class Square {

Square square;
int x,xa;
static int y;
int ya;
private Game game;
public static int fistX,fistY;
static int d = 60;
int wide;
boolean onGround;

public Square(Game game) {
this.game = game;
x = 100;
y = 631;
xa = 0;
ya = 0;
onGround = false;
wide = game.getWidth();
}

public void move() {


if (x + xa > 0 && x + xa < game.getWidth()-30)
    x = x + xa;

if (y + ya > 0 && y + ya < game.getHeight()-60){


    for(int i=12; i< 0; i--);
    ya+=10;
    y = y + ya;
}
if  (  collision()  ) {
    y-=10;
    onGround = true;

}

Square.y+=10;



}



public void paint(Graphics2D g) {
g.setColor(Color.RED);
g.fillRoundRect(x, y-d, 30, d, 10, 10);



}
private boolean collision() {
return game.ground.getBounds().intersects(getBounds());
}
public Rectangle getBounds() {
return new Rectangle(x, y, 30, 60);
}
public void keyReleased(KeyEvent e) {



if (e.getKeyCode() == KeyEvent.VK_LEFT)
xa=0;

if (e.getKeyCode() == KeyEvent.VK_RIGHT)
    xa=0;
if(e.getKeyCode() == KeyEvent.VK_DOWN)
    d = 60;

if(e.getKeyCode() == KeyEvent.VK_UP);





}



public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
if (e.getKeyCode() == KeyEvent.VK_LEFT)

    xa = xa -3;

if (e.getKeyCode() == KeyEvent.VK_RIGHT)

    xa = xa + 3;

if(e.getKeyCode() == KeyEvent.VK_DOWN)
    d = 30;

if(e.getKeyCode() == KeyEvent.VK_UP)

        ya  -= 60;





}









}


class Ground {

    int y,x,h,w;
public Ground(Game game){
    x = 0;
    y = game.getHeight()-30;
    w = game.getWidth();
    h = 30;
}
public void paint(Graphics2D g){
    g.setColor(Color.BLACK);
    g.fillRect(0, 700, 99999999, 30);

}
public Rectangle getBounds() {
return new Rectangle(0, 700, 99999999, 30);
}
}

【问题讨论】:

    标签: java swing animation graphics game-physics


    【解决方案1】:
    1. 不要阻塞 EDT(事件调度线程)——当这种情况发生时,GUI 将“冻结”。而不是调用 Thread.sleep(n) 实现一个 Swing Timer 用于重复的任务,如动画。有关详细信息,请参阅Concurrency in Swing
    2. frame.setSize(600, 700); 我建议改为设置内容的首选大小并围绕它打包框架。这表明在不同的 PLAF 或操作系统上游戏的大小是恒定的。
    3. 对于顶级容器以外的 Swing 组件(例如 JFrameJWindow),覆盖 paintComponent(Graphics) 而不是 paint(Graphics)
    4. 查看键绑定而不是 Swing 的键侦听器。

    前3个已实现,最后一个(以及代码中注释的其他一个)是TODO - BNI。

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    class SuperMarioGame extends JPanel {
    
        private static final long serialVersionUID = 1L;
        Square square = new Square(this);
        Ground ground = new Ground (this);
    
        public SuperMarioGame() {
            // TODO Update to Key Bindings
            addKeyListener(new KeyListener() {
                @Override
                public void keyTyped(KeyEvent e) {
                }
    
                @Override
                public void keyReleased(KeyEvent e) {
                    square.keyReleased(e);
                }
    
                @Override
                public void keyPressed(KeyEvent e) {
                    square.keyPressed(e);
                }
    
            });
            setFocusable(true);
    
            // Use a listener/timer combo.
            ActionListener gameAnimation = new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    move();
                    repaint();
                }
            };
            Timer timer = new Timer(30,gameAnimation);
            timer.start();
    
            // Set a preferred size for the panel.
            Dimension preferred = new Dimension(600,700);
            this.setPreferredSize(preferred);
        }
    
        public static void main(String[] args) throws InterruptedException {
            JFrame frame = new JFrame("My Mario");
            SuperMarioGame game = new SuperMarioGame();
            frame.add(game);
            // Pack the frame to the preferred size.
            frame.pack();
            frame.setVisible(true);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
    
        private void move() {
            square.move();
        }
    
        @Override
        // for Swing components, generally override 
        // paintComponent rather than paint
        //public void paint(Graphics g) {
        public void paintComponent(Graphics g) {
            super.paint(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            square.paint(g2d);
            ground.paint(g2d);
        }
    }
    
    class Square {
    
        Square square;
        int x,xa;
        static int y;
        int ya;
        private SuperMarioGame game;
        public static int fistX,fistY;
        static int d = 60;
        int wide;
        boolean onGround;
    
        public Square(SuperMarioGame game) {
            this.game = game;
            x = 100;
            y = 631;
            xa = 0;
            ya = 0;
            onGround = false;
            wide = game.getWidth();
        }
    
        public void move() {
            if (x + xa > 0 && x + xa < game.getWidth()-30)
                x = x + xa;
    
            if (y + ya > 0 && y + ya < game.getHeight()-60){
                for(int i=12; i< 0; i--);
                ya+=10;
                y = y + ya;
            }
    
            if  (  collision()  ) {
                y-=10;
                onGround = true;
            }
    
            Square.y+=10;
        }
    
        public void paint(Graphics2D g) {
            g.setColor(Color.RED);
            g.fillRoundRect(x, y-d, 30, d, 10, 10);
        }
    
        private boolean collision() {
            return game.ground.getBounds().intersects(getBounds());
        }
    
        public Rectangle getBounds() {
            return new Rectangle(x, y, 30, 60);
        }
    
        public void keyReleased(KeyEvent e) {
            // TODO Else-if would be better here..
            if (e.getKeyCode() == KeyEvent.VK_LEFT)
                xa=0;
            if (e.getKeyCode() == KeyEvent.VK_RIGHT)
                xa=0;
            if(e.getKeyCode() == KeyEvent.VK_DOWN)
                d = 60;
            if(e.getKeyCode() == KeyEvent.VK_UP);
        }
    
        public void keyPressed(KeyEvent e) {
            // TODO Else-if would be better here..
            if (e.getKeyCode() == KeyEvent.VK_LEFT)
                xa = xa -3;
            if (e.getKeyCode() == KeyEvent.VK_RIGHT)
                xa = xa + 3;
            if(e.getKeyCode() == KeyEvent.VK_DOWN)
                d = 30;
            if(e.getKeyCode() == KeyEvent.VK_UP)
                ya  -= 60;
        }
    }
    
    class Ground {
    
        int y,x,h,w;
    
        public Ground(SuperMarioGame game){
            x = 0;
            y = game.getHeight()-30;
            w = game.getWidth();
            h = 30;
        }
    
        public void paint(Graphics2D g){
            g.setColor(Color.BLACK);
            g.fillRect(0, 700, 99999999, 30);
        }
    
        public Rectangle getBounds() {
            return new Rectangle(0, 700, 99999999, 30);
        }
    }
    

    【讨论】:

      【解决方案2】:
      • 不要以任何方式阻塞事件调度线程,它会阻止 EDT 处理重绘请求(和其他事件),这会使您的程序看起来像是崩溃了。阅读Concurrency in Swing 了解更多信息。
      • 仅从 EDT 修改 UI,切勿从任何其他线程修改 UI,这包括创建 UI 元素
      • 优先使用键绑定而不是KeyListeners,它们更能解决焦点问题。阅读How to Use Key Bindings了解更多详情
      • 优先覆盖paintComponent 而不是paint。 Paint 做了很多重要的工作,如果可以的话,你应该避免弄乱这些工作。除了其他任何东西,paintComponent 将包含在组件的双缓冲中,而 paint 不包含(super.paint 设置它)
      • 尽可能避免使用static 状态变量
      • 我不知道这是不是故意的,但是,for (int i = 12; i &lt; 0; i--); 不会实现任何目标,因为最后的半角表示,计数 1 时什么也不做
      • 就个人而言,尽量不要对宽度和高度之类的东西使用绝对值,这实际上依赖于父容器。您还应该在可能的情况下提供大小提示,以允许父容器更好地决定它实际需要多少空间

      更新

      修复了我的移动代码中的错误:P

      我查看了您的碰撞检测代码(在move 中),坦率地说,我无法确定它的正面或反面。我更正了它并更改了 paint 方法的工作方式,使 x,y 始终是左上角

      public class TestGame {
      
          public static void main(String[] args) throws InterruptedException {
              new TestGame();
          }
      
          public TestGame() {
              EventQueue.invokeLater(new Runnable() {
                  @Override
                  public void run() {
                      try {
                          UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                      } catch (ClassNotFoundException ex) {
                      } catch (InstantiationException ex) {
                      } catch (IllegalAccessException ex) {
                      } catch (UnsupportedLookAndFeelException ex) {
                      }
      
                      Game game = new Game();
      
                      JFrame frame = new JFrame("Test");
                      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                      frame.setLayout(new BorderLayout());
                      frame.add(game);
                      frame.pack();
                      frame.setLocationRelativeTo(null);
                      frame.setVisible(true);
                  }
              });
          }
      
          public class GameThread extends Thread {
      
              private Game game;
      
              public GameThread(Game game) {
                  setDaemon(false);
                  this.game = game;
              }
      
              @Override
              public void run() {
                  while (true) {
                      game.move();
                      try {
                          long startedAt = System.currentTimeMillis();
                          SwingUtilities.invokeAndWait(new Runnable() {
                              @Override
                              public void run() {
                                  game.repaint();
                              }
                          });
                          long completedAt = System.currentTimeMillis();
                          long sleepFor = 30 - (completedAt - startedAt);
                          if (sleepFor < 0) {
                              sleepFor = 30;
                          }
                          Thread.sleep(sleepFor);
                      } catch (Exception exp) {
                          exp.printStackTrace();
                      }
                  }
      
              }
          }
      
          public class Game extends JPanel {
      
              Square square = new Square(this);
              Ground ground = new Ground(this);
      
              public Game() {
      //            addKeyListener(new KeyListener() {
      //                @Override
      //                public void keyTyped(KeyEvent e) {
      //                }
      //
      //                @Override
      //                public void keyReleased(KeyEvent e) {
      //                    square.keyReleased(e);
      //                }
      //
      //                @Override
      //                public void keyPressed(KeyEvent e) {
      //                    square.keyPressed(e);
      //                }
      //            });
                  setFocusable(true);
      
                  InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
                  ActionMap am = getActionMap();
      
                  im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "press-left");
                  im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "press-right");
                  im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "press-down");
                  im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "press-up");
      
                  im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), "release-left");
                  im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), "release-right");
                  im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "release-down");
                  im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "release-up");    
      
                  am.put("press-left", new PressLeftAction(square));
                  am.put("press-right", new PressRightAction(square));
                  am.put("press-down", new PressDownAction(square));
                  am.put("press-up", new PressUpAction(square));
      
                  am.put("release-left", new ReleaseLeftAction(square));
                  am.put("release-right", new ReleaseRightAction(square));
                  am.put("release-down", new ReleaseDownAction(square));
                  am.put("release-up", new ReleaseUpAction(square));
      
                  new GameThread(this).start();
      
      //        public void keyReleased(KeyEvent e) {
      //
      //
      //
      //            if (e.getKeyCode() == KeyEvent.VK_LEFT) {
      //                xa = 0;
      //            }
      //
      //            if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
      //                xa = 0;
      //            }
      //            if (e.getKeyCode() == KeyEvent.VK_DOWN) {
      //                d = 60;
      //            }
      //
      //            if (e.getKeyCode() == KeyEvent.VK_UP);
      //        }
      //
      //        public void keyPressed(KeyEvent e) {
      //// TODO Auto-generated method stub
      //            if (e.getKeyCode() == KeyEvent.VK_LEFT) {
      //                xa = xa - 3;
      //            }
      //
      //            if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
      //                xa = xa + 3;
      //            }
      //
      //            if (e.getKeyCode() == KeyEvent.VK_DOWN) {
      //                d = 30;
      //            }
      //
      //            if (e.getKeyCode() == KeyEvent.VK_UP) {
      //                ya -= 60;
      //            }
      //
      //
      //
      //
      //
      //        }
              }
      
              public void move() {
                  square.move();
              }
      
              @Override
              public Dimension getPreferredSize() {
                  return new Dimension(400, 400);
              }
      
              // Don't override paint, use paintComponent instead
      //        @Override
      //        public void paint(Graphics g) {
              @Override
              protected void paintComponent(Graphics g) {
                  super.paintComponent(g);
                  Graphics2D g2d = (Graphics2D) g.create();
                  g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                  square.paint(g2d);
                  ground.paint(g2d);
                  g2d.dispose();
              }
          }
      
          public class Square {
      
              Square square;
              private int x, xa;
      //        static int y;
              private int y;
              private int ya;
              private Game game;
      //        public static int fistX, fistY;
              private int fistX, fistY;
      //        static int d = 60;
              private int d = 60;
              private int wide;
              private boolean onGround;
      
              public Square(Game game) {
                  this.game = game;
                  x = 100;
                  y = 100;
                  xa = 0;
                  ya = 0;
                  onGround = false;
                  wide = game.getWidth();
              }
      
              public void move() {
      
                  y += ya;
                  x += xa;
      
                  if (x < 0) {
                      x = 0;
                  } else if (x + 30 > game.getWidth()) {
                      x = game.getWidth() - 30;
                  }
      
                  if (y < 0) {
                      y = 0;
                  } else if (collision()) {
                      onGround = true;
                      y = game.ground.getBounds().y - d;
                  }
      
      //            if (x + xa > 0 && x + xa < game.getWidth() - 30) {
      //                x = x + xa;
      //            }
      //
      //            if (y + ya > 0 && y + ya < game.getHeight() - 60) {
      //                // This was never going to do anything, look at the
      //                // end of the line...the `;` is going to prevent the
      //                // statemt ya += 10 from begin called within the loop
      ////                for (int i = 12; i < 0; i--);
      //                for (int i = 12; i < 0; i--) {
      //                    ya += 10;
      //                }
      //                y = y + ya;
      //            }
      //            if (collision()) {
      //                y -= 10;
      //                onGround = true;
      //
      //            }
      //
      //            y += 10;
      
              }
      
              public void paint(Graphics2D g) {
                  g.setColor(Color.RED);
                  System.out.println(x + "x" + (y - d));
                  g.fillRoundRect(x, y, 30, d, 10, 10);
              }
      
              private boolean collision() {
                  return game.ground.getBounds().intersects(getBounds());
              }
      
              public Rectangle getBounds() {
                  return new Rectangle(x, y, 30, 60);
              }
          }
      
          public class Ground {
      
              private Game game;
      
              public Ground(Game game) {
                  this.game = game;
              }
      
              public void paint(Graphics2D g) {
                  g.setColor(Color.BLACK);
                  g.fillRect(0, game.getHeight() - 30, game.getWidth(), 30);
              }
      
              public Rectangle getBounds() {
                  return new Rectangle(0, game.getHeight() - 30, game.getWidth(), 30);
              }
          }
      
          public abstract class AbstractSquareAction extends AbstractAction {
      
              private Square square;
      
              public AbstractSquareAction(Square square) {
                  this.square = square;
              }
      
              public Square getSquare() {
                  return square;
              }
      
          }
      
          public class PressLeftAction extends AbstractSquareAction {
      
              public PressLeftAction(Square square) {
                  super(square);
              }
      
              @Override
              public void actionPerformed(ActionEvent e) {
                  getSquare().xa = -3;
                  System.out.println("pressLeft");
              }
      
          }
      
          public class PressRightAction extends AbstractSquareAction {
      
              public PressRightAction(Square square) {
                  super(square);
              }
      
              @Override
              public void actionPerformed(ActionEvent e) {
                  getSquare().xa = 3;
              }
      
          }
      
          public class PressDownAction extends AbstractSquareAction {
      
              public PressDownAction(Square square) {
                  super(square);
              }
      
              @Override
              public void actionPerformed(ActionEvent e) {
                  getSquare().ya = 30;
              }
      
          }
      
          public class PressUpAction extends AbstractSquareAction {
      
              public PressUpAction(Square square) {
                  super(square);
              }
      
              @Override
              public void actionPerformed(ActionEvent e) {
                  getSquare().ya -= 30;
              }
      
          }
      
          public class ReleaseLeftAction extends AbstractSquareAction {
      
              public ReleaseLeftAction(Square square) {
                  super(square);
              }
      
              @Override
              public void actionPerformed(ActionEvent e) {
                  getSquare().xa = 0;
              }
      
          }
      
          public class ReleaseRightAction extends AbstractSquareAction {
      
              public ReleaseRightAction(Square square) {
                  super(square);
              }
      
              @Override
              public void actionPerformed(ActionEvent e) {
                  getSquare().xa = 0;
              }
      
          }
      
          public class ReleaseDownAction extends AbstractSquareAction {
      
              public ReleaseDownAction(Square square) {
                  super(square);
              }
      
              @Override
              public void actionPerformed(ActionEvent e) {
                  getSquare().ya = 0;
              }
      
          }
      
          public class ReleaseUpAction extends AbstractSquareAction {
      
              public ReleaseUpAction(Square square) {
                  super(square);
              }
      
              @Override
              public void actionPerformed(ActionEvent e) {
                  getSquare().ya = 0;
              }
      
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-30
        • 1970-01-01
        • 2015-01-10
        • 2015-09-09
        • 2019-10-21
        • 1970-01-01
        相关资源
        最近更新 更多