1

我正在使用javax.swing.JFrame双缓冲策略绘制游戏动画。首先,我设置了框架。

JFrame frame = new JFrame();
frame.setVisible(true);

现在,我画一个像这样的对象(让它是一个圆圈,没关系)。

frame.createBufferStrategy(2);
bufferStrategy = frame.getBufferStrategy();
Graphics g = bufferStrategy.getDrawGraphics();
circle.draw(g);
bufferStrategy.show();

问题是在绘图时框架并不总是完全设置好。

似乎 JFrame 需要最多三个步骤来调整自身大小,直到达到最终大小。这有时会使绘图滑出框架或阻碍它完全出现。

我已经设法使用SwingUtilities.invokeLater(). 虽然这改善了结果,但有时绘图会滑开/看起来过早地绘制。

有什么想法/策略吗?提前致谢。

编辑:好的,谢谢。我没有提到我一开始就写了一个小小的乒乓球游戏。抱歉给我带来了困惑 我真正寻找的是用 Java 完成的加速游戏动画的正确设置。在阅读建议时,我发现我的问题在这里得到了回答(虽然是间接的) ,这个例子让我明白了。

对此的总结可能是在 Java 中为游戏图形制作动画,第一步是摆脱 GUI 逻辑开销。

有一篇关于被动渲染和主动渲染区别的教程文章。这可能有助于清理新手的头......

4

4 回答 4

2

您可以使用 GlassPane,也可以简单地将 LayerUI 放在顶部,例如:

一些可以缩放的东西

当您调整框架大小时,圆圈会重新缩放。

import java.awt.*;
import java.awt.geom.Ellipse2D;

import javax.swing.*;
import javax.swing.plaf.LayerUI;

/**
 */
public class ALittleSomething {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame("A Little Something");
                JLayer<JComponent> aLittleSomething = new JLayer<>(new ALittleSomethingPanel(), new ALittleSomethingUI());
                frame.getContentPane().add(aLittleSomething);
                frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
                frame.setMinimumSize(new Dimension(800, 450));
                frame.setLocationRelativeTo(null); // Center
                frame.pack();
                frame.setVisible(true);
            }
        });
    }

    static class ALittleSomethingPanel extends JPanel {

        private JLabel aLittleSomethingLabel = new JLabel("A Little Something");

        ALittleSomethingPanel() {
            add(aLittleSomethingLabel);
            aLittleSomethingLabel.setFont(aLittleSomethingLabel.getFont().deriveFont(42f));
        }
    }

    static class ALittleSomethingUI extends LayerUI<JComponent> {

        @Override
        public void paint(Graphics g, JComponent c) {
            Graphics2D g2 = (Graphics2D) g.create();
            super.paint(g2, c);
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

            int height = c.getHeight();
            int width = c.getWidth();

            Shape circle = new Ellipse2D.Double(5, 5, width - 10, height - 10);

            g2.setPaint(new GradientPaint(15, 0, new Color(90, 97, 105), 15, 30, new Color(132, 142, 152)));
            g2.setStroke(new BasicStroke(5));
            g2.draw(circle);

            g2.dispose();
        }
    }
}
于 2012-11-09T18:02:55.470 回答
2

您最好绘制到自定义组件并将其添加到您的框架中,首先查看如何使用根窗格,了解为什么直接绘制到框架是一个坏主意(上面已经有很多东西了它)然后看一下这个这个以及这个使用 Swing 完成的(基本)动画的例子——所有这些都只有默认的缓冲策略

您可能还想看看Performing Custom PaintingGraphics2D就像一些入门书一样

于 2012-11-09T21:23:59.310 回答
1

我会自己回答这个问题,因为这个问题有点误导,而且在我真正了解这些工具之前,我混合了一些东西。我从中学到的一点是,对于 Java 中的图形编程,有两种方法:被动渲染和主动渲染。

虽然被动渲染发生在事件调度线程 (EDT) 中,这是让操作系统和 VM 确定绘制组件的正确时间的过程,但实际上不可能或不想确定绘制事物的确切时间. 这不是创建动画游戏图形的正确方法。

相反,您需要的是主动渲染 stargetey,如本文这样的文章中所述。在那里,您可以完全禁用渲染事件调度,并通过自己的缓冲区翻转或 blitting 主动重绘整个场景(请参阅 BufferStrategy)。

AWT/Swing 中的被动渲染主动渲染之间的区别在 java 教程中有简短的解释。

于 2012-11-10T11:01:46.890 回答
0

像这样的东西怎么样:

private void createAndShowGUI()
{
  frame = new JFrame();
  frame.createBufferStrategy(2);
  bufferStrategy = frame.getBufferStrategy();
  Graphics g = bufferStrategy.getDrawGraphics();
  circle.draw(g);
  bufferStrategy.show();
  frame.setVisible(true);
}

并从构造函数或其他任何地方调用它:

public MyClass()
{
   SwingUtilities.invokeLater(new Runnable()
   {
      public void run()
      {
         createAndShowGUI();
      }
   });

   try
   {
      while(frame == null || !frame.isVisible())
         Thread.sleep(1);
   }
   catch(InterruptedException e)
   {
     e.printStackTrace();
     System.exit(1);
   }
}

像这样的东西,对不起,我匆忙发布这个,我的一些代码可能是错误的。

于 2012-11-09T16:47:08.493 回答