当前位置: 首页 > 知识库问答 >
问题:

从多个地方在J面板上绘图

司空高义
2023-03-14

我目前正在为学校开发一款Java的2D游戏。我们必须使用抽象工厂设计模式。对于2D实现,我使用如下工厂:

public class Java2DFact extends AbstractFactory {
    public Display display;
    private Graphics g;
    public Java2DFact() {
        display = new Display(2000, 1200);
    }


    @Override
    public PlayerShip getPlayership()
    {
        return new Java2DPlayership(display.panel);
    }

在我的显示类中,我创建了一个 JFrame 和 Jpanel

public class Display {
    public JFrame frame;
    public JPanel panel;
    public int width, height;

    public Display(int width, int height) {
        this.width = width;
        this.height = height;

        frame = new JFrame();
        frame.setTitle("SpaceInvaders");
        frame.setSize(1200,800);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        
        panel = new JPanel(){
           @Override
            protected void paintComponent(Graphics g){
               super.paintComponent(g);
            }
        };
        panel.setFocusable(true);
        frame.add(panel);
    }
}

现在,从我的主gameloop中,我调用Java2DPLay的类中的可视化方法来可视化我的游戏体验

public class Java2DPlayership extends PlayerShip  {
    private JPanel panel;
    private Graphics2D g2d;
    private Image image;
    private BufferStrategy bs;


    public Java2DPlayership(JPanel panel) {
        super();
        this.panel = panel;
    }

    public void visualize()  {
        try {
            image = ImageIO.read(new File("src/Bee.gif"));
            Graphics2D g = (Graphics2D) bs.getDrawGraphics();
            //g.setColor(new Color(0, 0, 0));
            //g.fillRect(10, 10, 12, 8);
            g.drawImage(image, (int) super.getMovementComponent().x, (int) super.getMovementComponent().y, null);
            Toolkit.getDefaultToolkit().sync();
            g.dispose();
            panel.repaint();
        } catch(Exception e){
            System.out.println(e.toString());
        }
    }
}

我的目标是将JPanel传递给每个实体,并让它在显示之前将其内容绘制到面板上。然而,我似乎不知道该怎么做。当通过改变面板的图形来使用这种方法时,我会得到很多闪烁。

共有1个答案

章增
2023-03-14

这是一个功能齐全的示例,虽然很简单,但我前段时间写的。它只是有一堆从面板侧面反弹。请注意,Ball类render方法接受 中的图形上下文。如果我有更多需要渲染的类,我可以创建一个<code>Renderable</code>接口,并让每个类实现它。然后我可以有一个 Renderable对象的列表,然后遍历它们并调用该方法。但正如我所说,这需要迅速实现,以避免EDT被捆绑。

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

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

public class Bounce extends JPanel {
   private static final int    COLOR_BOUND  = 256;
   private final static double INC          = 1;
   private final static int    DIAMETER     = 40;
   private final static int    NBALLS       = 20;
   private final static int    DELAY        = 5;
   private final static int    PANEL_WIDTH  = 800;
   private final static int    PANEL_HEIGHT = 600;
   private final static int    LEFT_EDGE    = 0;
   private final static int    TOP_EDGE     = 0;
   private JFrame              frame;
   private double              rightEdge;
   private double              bottomEdge;
   private List<Ball>          balls        = new ArrayList<>();
   private Random              rand         = new Random();
   private List<Long>          times        = new ArrayList<>();
   private int width;
   private int height;
   
   public Bounce(int width, int height) {
      this.width = width;
      this.height = height;
      frame = new JFrame("Bounce");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.add(this);
      addComponentListener(new MyComponentListener());
      frame.pack();
      frame.setLocationRelativeTo(null);
      rightEdge = width - DIAMETER;
      bottomEdge = height - DIAMETER;
      for (int j = 0; j < NBALLS; j++) {
         int r = rand.nextInt(COLOR_BOUND);
         int g = rand.nextInt(COLOR_BOUND);
         int b = rand.nextInt(COLOR_BOUND);
         Ball bb = new Ball(new Color(r, g, b), DIAMETER);
         balls.add(bb);

      }
      frame.setVisible(true);
   }

   public Dimension getPreferredSize() {
       return new Dimension(width, height);
   }
   
   public static void main(String[] args) {
      new Bounce(PANEL_WIDTH, PANEL_HEIGHT).start();
   }

   public void start() {
      /**
       * Note: Using sleep gives a better response time than
       * either the Swing timer or the utility timer. For a DELAY
       * of 5 msecs between updates, the sleep "wakes up" every 5
       * to 6 msecs while the other two options are about every
       * 15 to 16 msecs. Not certain why this is happening though
       * since the other timers are run on threads.
       * 
       */
     Timer timer = new Timer(0,(ae)-> {repaint();
         for (Ball b : balls) {
            b.updateDirection(); 
         }} );
      timer.setDelay(5); // 5 ms.
      timer.start();
   }
   
  
   public void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2d = (Graphics2D) g;
      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      
      for (Ball ball : balls) {
         ball.render(g2d);
      }
   }

   class MyComponentListener extends ComponentAdapter {
      public void componentResized(ComponentEvent ce) {
         Component comp = ce.getComponent();
         rightEdge = comp.getWidth() - DIAMETER;
         bottomEdge = comp.getHeight() - DIAMETER;
         for (Ball b : balls) {
            b.init();
         }
      }
   }
   class Ball {
      private Color  color;
      public double  x;
      private double y;
      private double yy;
      private int    ydir = 1;
      private int    xdir = 1;
      private double slope;
      private int    diameter;

      public Ball(Color color, int diameter) {
         this.color = color;
         this.diameter = diameter;
         init();
      }

      public void init() {
         // Local constants not uses outside of method
         // Provides default slope and direction for ball
         slope = Math.random() * .25 + .50;
         x = (int) (rightEdge * Math.random());
         yy = (int) (bottomEdge * Math.random()) + diameter;
         xdir = Math.random() > .5 ? -1
                                   : 1;
         ydir = Math.random() > .5 ? -1
                                   : 1;
         y = yy;
      }

      public void render(Graphics2D g2d) {
         g2d.setColor(color);
         g2d.fillOval((int) x, (int) y, diameter, diameter);
      }

      public void updateDirection() {
         x += (xdir * INC);
         yy += (ydir * INC);
         y = yy * slope;
         if (x < LEFT_EDGE || x > rightEdge) {
            xdir = -xdir;
         }
         if (y < TOP_EDGE || y > bottomEdge) {
            ydir = -ydir;
         }
      }
   }
}
 类似资料:
  • 我正在尝试构建一个基于按钮的动态应用程序,这些按钮从创建的面板内部切换JFrame的主面板(这是我的应用程序的顶部内容)。 这个问题更多的是设计问题,而不是开发问题。我不确定我的设计,但我会试着解释一下。 我有一个JFrame代表我的应用程序,其中包含一个JTabbedPane(和多个Tabs)。每个选项卡都包含一个默认的JPanel,在那个JPanel中,我调用一个正在呈现我的视图的控制器(我正

  • 如果可以选择在单个JPanel中进行所有渲染,或者在多个JPanel中进行渲染(使用override paintComponent),并且不使用任何其他Swing组件,例如JButtons、JTextBox、JComboxes等(面板所在的JFrame除外)。如果只使用drawLine、drawRectangle、fillRect等进行绘图,那么在一个面板中绘制所有内容还是将绘图展开到多个面板上更

  • 我在想哪里出了问题。我以前做过这个,但由于某种原因,这次我不能让它工作。 我用Netbeans设计了这个项目。最相关的部分是initTiras方法,它被认为可以绘制一些东西,但它没有。我包含了NetBeans生成的代码。 这是代码的最简化版本,但它仍然没有绘制任何内容。 所以我在项目中创建了一个新的框架。然后我把一个JPanel放进去(在设计模式下)。JPanel称为ElPanel和JFrame

  • 我将用Netbeans GUI-builder制作的GUI转移到Eclipse。我想知道GUI构建器在代码中输入的这条看起来吓人的消息是否仍然相关:

  • 问题内容: 我编写的代码可以一次打开16位数字。目前,它们都以单独的图形打开。我希望他们在同一页面上全部打开。不一样的图。我希望在单个页面/窗口上有16个独立的图形。同样由于某种原因,numbins和defaultreallimits的格式也无法保存在图1之前。我是否需要使用subplot命令?我不明白为什么我必须这样做,但不知道我还要做什么? 问题答案: 要回答您的主要问题,您想使用subplo

  • 我现在正在做一个项目,但我找不到解决问题的方法。 这就是我的问题:我有一个JFrame,然后我添加了一个容器JPanel,并向这个容器面板添加了另外两个JPanel,第一个面板(InputPanel)用于用户输入,第二个面板(Board)用于根据用户输入显示指定的算法。 请注意,在我的Board类中,我重写了paintComponent(图形g)来绘制算法。 主框架中的我的代码: 我最初的计划是在