从多个位置在JPanel上绘图 [英] Drawing on a JPanel from multiple places

查看:50
本文介绍了从多个位置在JPanel上绘图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm currently working on a 2D game in Java for school. We have to use an Abstract Factory design pattern. For the 2D implementation I use a factory as follows:

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

In my display class I create a JFrame and 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);
    }
}

现在从主游戏循环中,我在Java2DPLayership类中调用visualize方法来可视化Playership

Now from my main gameloop I call the visualize method inside the Java2DPLayership class to visualize my Playership

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传递给每个实体,并使其在显示之前将其内容绘制到面板上.但是我似乎无法弄清楚如何做到这一点.通过更改面板的图形使用这种方法时,会出现很多闪烁.

My goal is to pass around the JPanel to every entity and let it draw its contents onto the panel before showing it. However I can't seem to figure out how to do this. When using this approach by changing the Graphics of the panel I get a lot of flickering.

推荐答案

这是一个功能齐全的示例,尽管很简单,但我还是在前一段时间写的.它只有一堆 balls 从面板的侧面弹起.请注意, Ball类 render 方法接受 paintComponent 中的图形上下文.如果我有更多需要渲染的类,则可以创建一个 Renderable 接口,并让每个类都实现它.然后我可以列出 Renderable 对象,然后遍历它们并调用该方法.但是,正如我也说过的那样,这需要尽快进行,以避免占用EDT.

Here is a fully functional, albeit simple example, I wrote some time ago. It just has a bunch of balls bouncing off the sides of the panel. Notice that the render method of the Ball class accepts the graphics context from paintComponent. If I had more classes that needed to be rendered, I could have created a Renderable interface and have each class implement it. Then I could have a list of Renderable objects and just go thru them and call the method. But as I also said, that would need to happen quickly to avoid tying up the 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());
      timer.setDelay(5); // 15 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);
         updateDirection();
      }

      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;
         }
      }
   }
}

这篇关于从多个位置在JPanel上绘图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆