【问题标题】:JPanel not showing up in another JPanelJPanel 没有出现在另一个 JPanel 中
【发布时间】:2018-05-01 13:23:22
【问题描述】:

我正在尝试通过在 Jpanel 之上添加 Jpanel 来制作 2D 赛车游戏。这是通过使用我在下面发布的 2 个类来完成的。

问题是这辆车从来没有出现在赛道上……我真的不确定我错过了什么……任何帮助都非常受欢迎!

提前谢谢你!

汽车.java

public class Car extends JPanel implements Runnable 
{

   private static final long serialVersionUID = 007;
   private BufferedImage car = null;
   private float x = 100F, y = 100F;
   private Thread driveThread = new Thread(this);
   private double currentAngle = 0; // angel of the car
   private static int[] key = new int[256]; // keyboard input
   private float MAX_SPEED = 7F;
   private float speed = 0F; // speed of our racing car
   private float acceleration = 0.15F;
   private int player;
   private boolean playable = true;


   public Car(int player) 
   {

      this.player = player;

      this.setSize(super.getHeight(), super.getWidth());
      this.setFocusable(true); // enables keyboard

      try 
      {
         if (player == 1) 
         {
            //red car
            car = ImageIO.read(this.getClass().getResource(
                  "/imagesCar/first-0.png"));

            System.out.println(car.getColorModel());
         } else if(player == 2)
         {
            //blue car
            car = ImageIO.read(this.getClass().getResource(
                  "/imagesCar/second-0.png"));
            x = x +30;
         }

      } catch (IOException e) {
         System.out.println("dupi");
      }

      // starts the drive thread
      startGame();

   }

   private void startGame() {
      driveThread.start();
   }

   @Override
   protected void paintComponent(Graphics g) 
   {

      super.paintComponent(g);
      this.setOpaque(false);

      // rotation 
      Graphics2D g2d = (Graphics2D) g;
      AffineTransform rot = g2d.getTransform();
      // Rotation at the center of the car
      float xRot = x + 12.5F;
      float yRot = y + 20F;
      rot.rotate(Math.toRadians(currentAngle), xRot, yRot);
      g2d.setTransform(rot);
      //Draws the cars new position and angle
      g2d.drawImage(car, (int) x, (int) y, 50, 50, this);

   }

   protected void calculateCarPosition() {

      //calculates the new X and Y - coordinates 
      x += Math.sin(currentAngle * Math.PI / 180) * speed * 0.5;
      y += Math.cos(currentAngle * Math.PI / 180) * -speed * 0.5;

   }

   protected void carMovement() {

      // Player One Key's
      if (player == 1) {

         if (key[KeyEvent.VK_LEFT] != 0) {
            currentAngle-=2;

         } else if (key[KeyEvent.VK_RIGHT] != 0) {
            currentAngle+=2;
         }

         if (key[KeyEvent.VK_UP] != 0) {

            if (speed < MAX_SPEED) {

               speed += acceleration;
            }

         } else if (key[KeyEvent.VK_DOWN] != 0 && speed > -1) {
            speed = speed - 0.1F;
         }
         speed = speed * 0.99F;

      } else {

         //Player Two Key's

         if (key[KeyEvent.VK_A] != 0) {
            currentAngle -= 2;

         } else if (key[KeyEvent.VK_D] != 0) {
            currentAngle += 2;
         }

         if (key[KeyEvent.VK_W] != 0) {

            if (speed < MAX_SPEED) {

               speed += acceleration;
            }

         } else if (key[KeyEvent.VK_S] != 0 && speed > -1) {
            speed = speed - 0.1F;
         }
         //reduce speed when no key is pressed
         speed = speed * 0.99F;
      }

   }

   public void getUnderground() {

   }
   // get key events!
   final protected void processKeyEvent(KeyEvent e) {
      key[e.getKeyCode()] = e.getID() & 1;
   }

   @Override
   public void run() {
      while (true) {

         repaint();
         carMovement();
         calculateCarPosition();


         try {
            Thread.sleep(10);
         } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
         }

      }

   }

}

RaceTrack.java

public class RaceTrack extends JPanel
{

@Override
public void paintComponent(Graphics g)
{
    Color c1 = Color.green;

    g.setColor(c1);
    g.fillRect(150, 200, 550, 300);
    Color c2 = Color.black;
    g.setColor(c2);
    g.drawRect(50, 100, 750, 500); // outer edge
    g.drawRect(150, 200, 550, 300); // inner edge
    Color c3 = Color.yellow;
    g.setColor(c3);
    g.drawRect(100, 150, 650, 400); // mid-lane marker
    Color c4 = Color.white;
    g.setColor(c4);
    g.drawLine(425, 500, 425, 600); // start line

}
}

主要

public static void main(String[] args) {

    JFrame mainFrame = new JFrame();

    mainFrame.setSize(850,650);
    mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    Container content = mainFrame.getContentPane();

    RaceTrack track = new RaceTrack();

    Car carP1 = new Car(1);

    track.add(carP1);

    content.add(track);

    mainFrame.setVisible(true);
}

【问题讨论】:

  • 1. Car 没有定义尺寸提示,所以它的默认尺寸是0x0; 2.将Car添加到RaceTrack,使用FlowLayout将布局Car到它的首选大小0x0; 3. Swing 不是线程安全的,所以你可能还有一堆线程竞争条件/违规
  • 不确定这是否是解决此问题的正确方法,但我尝试在将 carP1.setPreferredSize(new Dimension(50,50)); 添加到 RaceTrack 之前添加它。似乎没有解决问题..
  • 不要为此任务使用组件。相反,你需要发展“实体”的概念,这些“实体”做“东西”,比如“油漆”。然后,您定义这些“实体”的列表(有时基于那里的功能在不同的列表中)。在您的渲染器中,您循环遍历“可绘制”实体并绘制它们。然后,您将拥有一个线程,其职责是更新所有“可移动”(或以其他方式随时间变化)的实体并安排绘制通道。简单来说,你可以使用 Swing Timer 有“主循环”

标签: java swing jpanel


【解决方案1】:
  1. 汽车没有定义尺寸提示,所以它的默认尺寸是0x0
  2. Car 添加到RaceTrack,使用FlowLayout 会将Car 布局到它的首选大小0x0
  3. Swing 不是线程安全的,因此您可能还有一堆线程竞争条件/违规行为

不确定这是否是解决此问题的正确方法

不要为此目的使用组件,这个问题只会让自定义绘画一路尖叫。

有很多关于基本游戏开发的博客和教程,所以我不想花太多时间去阅读相同的材料。

基本上,您需要为要在游戏中使用的对象(也称为“实体”)定义一系列“属性”。并非所有实体都需要可绘制,有些实体可能会触发其他操作或仅充当其他实体使用的“标记”。

在本例中,我定义了两个基本实体,“可移动”和“可绘制”。 “可绘制”实体可以是静态的(即轨道)或“可移动的”(即汽车)

目的是提供一个孤立的功能概念,可以轻松地将其应用于真实对象,以便“描述”它们在游戏中的功能和用途。

例如...

public interface MovableEntity extends Entity {
    public void update(Rectangle bounds);
}

public interface PaintableEntity extends Entity {
    public void paint(Graphics2D g2d, ImageObserver imageObserver, Rectangle bounds);
}

因此,在您的情况下,Car 既是 Paintable 又是 Movable

然后,您的“引擎”将维护这些“实体”的一个或多个列表并相应地处理它们。

此示例仅使用 Swing Timer 作为“主循环”

mainLoop = new Timer(5, new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        Rectangle bounds = new Rectangle(0, 0, getWidth(), getHeight());
        // Lots of collision detection and other awesome stuff
        for (MovableEntity entity : movableEntitys) {
            entity.update(bounds);
        }
        repaint();
    }
});
mainLoop.start();

这提供了一定程度的线程安全,因为Timer 是在事件调度线程的上下文中触发的,这意味着当我们更新实体时,它们不能被绘制。

那我们就简单的利用JPanelpaintComponent方法来充当渲染进程……

protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Rectangle bounds = new Rectangle(0, 0, getWidth(), getHeight());
    for (PaintableEntity paintable : paintableEntities) {
        Graphics2D g2d = (Graphics2D) g.create();
        paintable.paint(g2d, this, bounds);
        g2d.dispose();
    }
}

这是一个非常广泛的示例,它以简单的方式展示了基本概念。还有更复杂的可能解决方案,它们遵循相同的基本原则。

就我个人而言,我会定义某种“路径”作为轨道,然后汽车将在该轨道上根据不同的因素计算位置,但这是一个更复杂的解决方案,现在需要。但如果你真的感兴趣,它可能看起来像 like this

可运行示例...

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.ImageObserver;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    /*
    You could have entities which can collide which have collision detection
    capabilities

    Some entities don't need to be painted and may provide things like
    visual or audio affects
    */

    public interface Entity {
    }

    public interface MovableEntity extends Entity {
        public void update(Rectangle bounds);
    }

    public interface PaintableEntity extends Entity {
        public void paint(Graphics2D g2d, ImageObserver imageObserver, Rectangle bounds);
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new GamePane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class GamePane extends JPanel {

        // Could use a single list and filter it, but hay
        private List<PaintableEntity> paintableEntities;
        private List<MovableEntity> movableEntitys;

        private Timer mainLoop;

        public GamePane() {
            paintableEntities = new ArrayList<>(25);
            movableEntitys = new ArrayList<>(25);

            paintableEntities.add(new TrackEntity());

            CarEntity car = new CarEntity();
            paintableEntities.add(car);
            movableEntitys.add(car);

            mainLoop = new Timer(5, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Rectangle bounds = new Rectangle(0, 0, getWidth(), getHeight());
                    // Lots of collision detection and other awesome stuff
                    for (MovableEntity entity : movableEntitys) {
                        entity.update(bounds);
                    }
                    repaint();
                }
            });
            mainLoop.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Rectangle bounds = new Rectangle(0, 0, getWidth(), getHeight());
            for (PaintableEntity paintable : paintableEntities) {
                Graphics2D g2d = (Graphics2D) g.create();
                paintable.paint(g2d, this, bounds);
                g2d.dispose();
            }
        }

    }

    public class CarEntity implements PaintableEntity, MovableEntity {

        private int delta = 1;

        private int xDelta = 0;
        private int yDelta = delta;

        private int xPos = 2;
        private int yPos = 2;

        private int size = 4;

        @Override
        public void paint(Graphics2D g2d, ImageObserver imageObserver, Rectangle bounds) {
            g2d.translate(bounds.x, bounds.y);
            g2d.setColor(Color.RED);
            g2d.fillRect(xPos - size / 2, yPos - size / 2, size, size);
        }

        @Override
        public void update(Rectangle bounds) {
            xPos += xDelta;
            yPos += yDelta;

            if (xPos + (size / 2) > bounds.x + bounds.width) {
                xPos = bounds.x + bounds.width - (size / 2);
                xDelta = 0;
                yDelta = -delta;
            } else if (xPos - (size / 2) < bounds.x) {
                xPos = bounds.x + (size / 2);
                xDelta = 0;
                yDelta = delta;
            }

            if (yPos + (size / 2) > bounds.y + bounds.height) {
                yPos = bounds.y + bounds.height - (size / 2);
                xDelta = delta;
                yDelta = 0;
            } else if (yPos - (size / 2) < bounds.y) {
                yPos = bounds.y + (size / 2);
                xDelta = -delta;
                yDelta = 0;
            }
        }

    }

    public class TrackEntity implements PaintableEntity {

        @Override
        public void paint(Graphics2D g2d, ImageObserver imageObserver, Rectangle bounds) {
            g2d.translate(bounds.x, bounds.y);
            g2d.setColor(Color.BLUE);
            g2d.drawRect(2, 2, bounds.width - 4, bounds.height - 4);
        }

    }

}

【讨论】:

    猜你喜欢
    • 2011-05-11
    • 1970-01-01
    • 2017-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多