【问题标题】:Graphics not appearing in JFrame (SSCCE included)图形未出现在 JFrame 中(包括 SSCCE)
【发布时间】:2011-06-07 21:35:35
【问题描述】:

我正在制作一款游戏(请参阅我之前的帖子),并且在制作过程中遇到了很多问题。我所知道的是他的代码编译,运行,但窗口中什么也没有出现,它只是灰色的。在 Andrew Thompson 的建议下,我在这里发布了整个可编译版本。对不起,它是程序中的所有代码。而且很多事情可能没有意义(未使用的 ActionPerformed 举个例子),部分原因是我在需要时实现了代码,但主要是因为我以前从未这样做过。

另外,到目前为止,我还没有多线程,因为我还是新手,所以理想情况下,我希望保持这种状态,即使只是为了我的理智。

编辑:忘了提我有 4 个 PNG 代表出现的 4 个不同对象。我的代码足够灵活,您可以自己提供。这是我用于船舶 的图像,这是用于子弹 的图像,只需复制,将它们放入源文件并将它们命名为“Enemy-ship”“ship2”“Ebullet”和“PBullet”

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;

import javax.swing.JFrame;


public class GameController extends JFrame implements ActionListener {

    /**
     * 
     */
    private static final long serialVersionUID = -3599196025204169130L;
    private static GameView window;
    private static Timer time;

    public GameController()
    {
        setTitle("Space Shooter");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800, 600);

        //window = new GameView(800,600);
        //window.setVisible(true);

        //
    }
    //TODO spawn
    /*public static void main(String args[])
    {
        //GameController c = new GameController();
        window = new GameView(800,600);
        window.setVisible(true);

        time = new Timer(40, this);
        time.schedule( new TimerTask(){
            public void run(){GameState.update(); 
            window.paintComponents(null);}
            },0, 40);

    }*/




    public void display() {
        add(new GameView(800,600));
        pack();        
        setMinimumSize(getSize());// enforces the minimum size of both frame and component
        setVisible(true);
    }

    public static void main(String[] args) {
        GameController main = new GameController();
        main.display();
        time = new Timer(40, main);
    }


    @Override
    public void actionPerformed(ActionEvent e) {
        if(e instanceof EndEvent)//TODO fix this
        {

        }
        else
        {
            repaint();
        }

    }
}



package Game;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class GameView extends JComponent implements ActionListener{

    /**
     * 
     */
    private static final long serialVersionUID = -2869672245901003704L;
    private static final Graphics Graphics = null;
    private boolean liveGame;//used so that buttons cannot be clicked after game is complete
    private GameState gs;
    private Player p;
    private int w, h;

    public GameView(int width, int height)
    {
        liveGame = true;
        gs = new GameState();
        GameState.init(width, height);
        p = new Player(width/2,(height*7)/8);
        this.setBackground(Color.BLACK);
        paintComponents(Graphics);
        w = width;
        h = height;
    }
       @Override
        public Dimension getMinimumSize() {
            return new Dimension(w, h);
        }

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

        @Override
        public void paintComponent(Graphics g) {
            int margin = 10;
            Dimension dim = getSize();
            super.paintComponent(g);
            g.setColor(Color.black);
            GameState.update();

            for(Bullet j : GameState.getEnBullets()){
                g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
            for(Enemy j : GameState.getEnemies()){
                g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
            for(Bullet j : GameState.getPlayBullets()){
                g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
            g.fillRect(margin, margin, dim.width - margin * 2, dim.height - margin * 2);
        }

    public void paintComponents (Graphics g)
    {

        for(Bullet j : GameState.getEnBullets()){
            g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
        for(Enemy j : GameState.getEnemies()){
            g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
        for(Bullet j : GameState.getPlayBullets()){
            g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
        this.paint(g);
    }



    public void refreshImage()
    {
        this.removeAll();
        paintComponents(Graphics);
    }


    public void actionPerformed(ActionEvent e) {


    }


}


package Game;
import java.awt.event.ActionEvent;
import java.util.ArrayList;

import javax.swing.JFrame;
public class GameState {

    private static ArrayList<Bullet> playBullets;
    public static ArrayList<Bullet> getPlayBullets() {
        return playBullets;
    }

    public static ArrayList<Bullet> getEnBullets() {
        return enBullets;
    }

    public static ArrayList<Enemy> getEnemies() {
        return enemies;
    }

    public static Player getP() {
        return p;
    }

    private static ArrayList<Bullet> enBullets;
    private static ArrayList<Enemy> enemies;
    private static int X, Y;//for limit of screen so nothing can go outside of screen
    private static Player p;
    private static int score;

    public GameState(){

    }

    public static void init(int x, int y)
    {
        playBullets = new ArrayList<Bullet>();
        enBullets = new ArrayList<Bullet>();
        enemies = new ArrayList<Enemy>();
        X=x;
        Y=y;
        p = null;
        score =0;
    }

    public static int xLimit(){return X;}
    public static int yLimit(){return Y;}

    public static int getScore(){return score;}

    public static void add (Location e)
    {
        if(e instanceof Bullet)
        {
            if(((Bullet) e).getOwner() instanceof Enemy){
                enBullets.add((Bullet) e);
            }
            else
                playBullets.add((Bullet) e);
        }
        else if(e instanceof Enemy){enemies.add((Enemy)e);}
        else
            p=(Player)e;
    }

    public static void spawn()
    {
        Enemy e = new Enemy(((int)(Math.random()*(X-56))+28), 0, 1);
    }


    public static void playerCD()//detects  if player has collided with anything, removes whatever collided with it, and causes the player to take damage
    {
        if(enemies.size()>0){
        for(int i =0; i < enemies.size(); i++)
        {
            if (p.getLocation().intersects(enemies.get(i).getLocation()))
            {
                p.takeDamage(enemies.get(i).getDamage());
                enemies.get(i).takeDamage(p.getDamage());

            }
        }
        if(enBullets.size()>0)
        for(int i =0; i < enBullets.size(); i++)
        {
            if (p.getLocation().intersects(enBullets.get(i).getLocation()))
            {
                p.takeDamage(enBullets.get(i).getDamage());
                enBullets.remove(i);
                i--;

            }
        }
        }
    }

    public static void enemyCD()
    {
        for(int i =0; i < enemies.size(); i++)
        {
            for(int n =0; n < playBullets.size(); n++)
            {
                if (playBullets.get(n).getLocation().intersects(enemies.get(i).getLocation()))
                    {
                        enemies.get(i).takeDamage(playBullets.get(i).getDamage());
                        playBullets.remove(n);
                        n--;
                        score+=50;
                    }
                }
            }

        }

    public static void checkForDead()//clears away dead and things gone offscreen
    {

        for(int i =0; i < enemies.size(); i++)
        {
            if(enemies.get(i).getY()>Y)
            {
                enemies.remove(i);
                i--;
            }
        }


        for(int i =0; i < enBullets.size(); i++)
        {
            if(enBullets.get(i).getY()>Y)
            {
                enBullets.remove(i);
                i--;
            }
        }

        for(int i =0; i < enemies.size(); i++)
        {
            if(enemies.get(i).getHealth()>0)
            {
                enemies.remove(i);
                i--;
                score+=200;
            }
        }

        if(p.getHealth()<=0)
        {
            ActionEvent e = new EndEvent(null, 0, "end");
        }
    }

    public static void update()
    {
        move();
        playerCD();
        enemyCD();
        checkForDead();
    }

    public static void move()
    {
        p.move();
        for(int i =0; i < enemies.size(); i++){enemies.get(i).move();}
        for(int i =0; i < enBullets.size(); i++){enBullets.get(i).move();}
        for(int i =0; i < playBullets.size(); i++){playBullets.get(i).move();}
    }





}


package Game;

import java.awt.Rectangle;
import java.awt.event.ActionListener;

public abstract class Fights extends Location implements ActionListener {

    public Fights(Rectangle location) {
        super(location);
        // TODO Auto-generated constructor stub
    }

    public Fights(){}
    protected int health;
    protected int maxHealth;//in the event that I want to have healing items
    protected int shotCooldown;//in milliseconds
    protected int shotDmg;
    protected long currentCool; //cooldown tracker, represents time that shot will be cooled down by (System time @ last shot + shotCooldown
    protected int xVel, yVel;
    public abstract boolean shoot();
    public abstract int takeDamage(int damage);//returns remaining health
    protected boolean shoots;//determines whether thing can shoot. possible implementation in some enemy class
    public boolean move;
    public int getHealth(){return health;}
    public abstract boolean move();
    public int getDamage(){return shotDmg;}
    public boolean isDead()
    {
        return health<=0;
    }


}



package Game;

import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;



public class Location {
    protected Rectangle loc;
    protected Image image;

    public Location(){};

    public Location (Rectangle location)
    {
        loc = location;
    }

    public Rectangle getLocation()
    {
        return loc;
    }

    public void setLocation(Rectangle l)
    {
        loc = l;
    }

    public void updateLocation(int x, int y)
    {
        loc.setLocation(x, y);
    }

    public Image getImage()
    {
        return image;
    }

    public int getX()
    {
        return (int)loc.getX();
    }

    public int getY()
    {
        return (int)loc.getY();
    }
        }

package Game;

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.Rectangle;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class Player extends Fights implements KeyListener{

    int speed = 4;

    public Player(Rectangle location) {
        super(location);
        GameState.add(this);
        image = null;
        try{
            image = ImageIO.read(new File("ship2.png"));
        }catch(IOException e){}
    }

    public Player(int x, int y) {

        maxHealth = 1;
        health = maxHealth;
        image = null;
        try{
            image = ImageIO.read(new File("ship2.png"));
        }catch(IOException e){}


        this.setLocation(new Rectangle(x, y, image.getWidth(null), image.getHeight(null)));
        GameState.add(this);
    }

    public void resetVelocity()
    {
        xVel = 0;
        yVel = 0;
    }


    @Override
    public boolean shoot() {
        if(currentCool - System.currentTimeMillis() >0){return false;}
        else
        {
            new Bullet(this);
            currentCool = System.currentTimeMillis() + shotCooldown;
        }//spawns bullet in the center and slightly in front of player
        return true;
    }

    @Override
    public int takeDamage(int damage) {

        return health-=damage;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public boolean move() {//moves in a direction only if it won't exceed screen boundary, boolean just in case i need it later
        int newX = this.getX(), newY=this.getY();
        if((xVel+ this.getX()+this.getLocation().width)<GameState.xLimit()&& this.getX()+xVel>=0)
        {
            newX +=xVel;
        }
        if((yVel+ this.getY()+this.getLocation().height)<GameState.yLimit()&& this.getY()+yVel>=0)
        {
            newY +=yVel;
        }
        this.updateLocation(newX, newY);
        this.resetVelocity();

        return true;
    }

    @Override
    public void keyPressed(KeyEvent arg0) {

        if (arg0.getKeyCode()== KeyEvent.VK_LEFT)
        {
            xVel -= speed;
        }


        if (arg0.getKeyCode()== KeyEvent.VK_RIGHT)
        {
            xVel += speed;
        }

        if (arg0.getKeyCode()== KeyEvent.VK_UP)
        {
            yVel -= speed;
        }


        if (arg0.getKeyCode()== KeyEvent.VK_DOWN)
        {
            yVel += speed;
        }

        if(arg0.getKeyCode()==KeyEvent.VK_SPACE)
        {
            this.shoot();
        }


    }

    @Override
    public void keyReleased(KeyEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void keyTyped(KeyEvent arg0) {
        // TODO Auto-generated method stub

    }

}


package Game;

import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class Enemy extends Fights {

    public Enemy(Rectangle location) {
        super(location);
        GameState.add(this);
        image = null;
        try{
            image = ImageIO.read(new File("Enemy-Ship.png"));
        }catch(IOException e){}
    }
    public Enemy(int x, int y, int d) {
        image = null;
        try{
            image = ImageIO.read(new File("Enemy-Ship.png"));
        }catch(IOException e){}


        this.setLocation(new Rectangle(x, y, image.getWidth(null), image.getHeight(null)));
        GameState.add(this);

        shotCooldown =(int)(Math.random()*2000);

        xVel = (int)((Math.pow(-1, (int)(Math.random())))*((int)(Math.random()*6))+2);
        yVel = (int)(Math.random()*3+1);
        shotDmg =d;
    }


    public void actionPerformed(ActionEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public boolean shoot() {
        if(currentCool - System.currentTimeMillis() >0){return false;}
        else
        {
            new Bullet(this);
            currentCool = System.currentTimeMillis() + shotCooldown;
        }//spawns bullet in the center and slightly in front of player
        return true;
    }

    @Override
    public int takeDamage(int damage)//returns remaining health
    {
        health = health-damage;
        return health;
    }
    @Override
    public boolean move() {
        int newX = this.getX(), newY=this.getY();
        if((xVel+ this.getX()+this.getLocation().width)<GameState.xLimit()&& this.getX()+xVel>=0)
        {
            xVel=-xVel;
            newX +=xVel;
        }
        if(this.getY()+yVel>=0)
        {
            newY +=yVel;
        }
        this.updateLocation(newX, newY);

        return true;
    }

}

package Game;

import java.awt.Rectangle;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class Bullet extends Location{
    private Fights bulletOwner;
    private int damage;
    private int velocity;

    public Bullet(Fights owner)//eventually change to singleton pattern for efficiency
    {
        bulletOwner = owner;
        damage = owner.getDamage();
        image = null;
        if(owner instanceof Enemy)
        {
            try{
                image = ImageIO.read(new File("Ebullet.png"));
            }catch(IOException e){}
            this.setLocation(new Rectangle(owner.getX(), owner.getY()+((int)(owner.getLocation().getHeight()/2)), image.getWidth(null), image.getHeight(null)));
            velocity = 5;

        }

        else
        {
            try{
                image = ImageIO.read(new File("Pbullet.png"));
            }catch(IOException e){}
            this.setLocation(new Rectangle(owner.getX(), owner.getY()-((int)(owner.getLocation().getHeight()/2)), image.getWidth(null), image.getHeight(null)));
            velocity = -15;

        }
        GameState.add(this);


    }

    public Fights getOwner(){return bulletOwner;}
    public int getDamage(){return damage;}
    public int getVelocity(){return velocity;}
    public boolean move()
    {
        this.updateLocation(this.getX(), this.getY()+velocity);
        return true;
    }


}

【问题讨论】:

  • Andrew 不建议您发布整个代码。在发布不正确的链接之前,请至少阅读创建sscce 的链接。
  • 我确实读过它。我发布了我的代码的工作版本,它一点也不短,但根据定义,代码是短的(小于 20 KB)。该代码是自包含的,并显示了在 GameController 类中调用 main 方法时的示例。
  • 通过注释掉 GameView 类中的每个子弹循环,我能够将该组件添加到 JFrame 并显示黑色背景。我的猜测是它在那些子弹的某个地方。
  • @Will: 'under 20 KB' 不幸的是,作者(我)选择的这个数字非常糟糕。老实说,我在得出这个数字时没有进行实际测量,它是“天上掉下来的”。我还不如使用Random 来确定数字。很高兴你得到了正确的答案。 :-)

标签: java debugging swing graphics jframe


【解决方案1】:

我不敢相信你写了 700 行代码却没有做任何测试。是时候回到起点,从简单的事情开始了。这就是 SSCCE 的全部意义所在。从绘制几个组件开始。一旦你开始工作,你就会添加一些动作。一旦它工作了,你就可以添加碰撞逻辑。

我在快速浏览时注意到的唯一一件事是您覆盖了paintComponents()。不需要在 pantComponent() 方法中完成自定义绘制。

如果你不能生产更小尺寸的 SSCCE,那么我能做的就是祝你好运。

【讨论】:

    【解决方案2】:

    好的,所以我想我已经弄清楚了大部分。

    你有几个问题。

    首先,您应该只看到中间有一个黑色矩形的灰色屏幕,因为您的子弹和敌人阵列中没有任何内容。这是我在运行您的代码时得到的(在删除对 endEvent 的引用后,因为找不到它)。所以要解决这个问题,只需给它一些东西来绘制

    第二个问题一旦你给它画点就很明显了。我手动输入了一行代码来绘制 Player,为此我使用了自己的一个 png。当您这样做时,它将无法编译并出现空指针异常。原因是因为在您的 GameView 类中,您将名为“graphics”的 Graphics 对象设置为 null,但随后您继续调用 paintComponents(graphics)。如前所述,这只是之前编译的,因为您实际上从未绘制过任何东西。要解决此问题,您只需删除

    public void paintComponents (Graphics g)
    {
    
        for(Bullet j : GameState.getEnBullets()){
            g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
        for(Enemy j : GameState.getEnemies()){
            g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
        for(Bullet j : GameState.getPlayBullets()){
            g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
        this.paint(g);
    
    }
    

    并让其上面的重写paintComponent(Graphics g) 方法完成所有工作。此外,使用 repaint() 代替 paintComponents(graphics) 调用。您还可以在构造函数中摆脱对paintComponents(graphics) 的第一次调用,因为默认情况下它将第一次绘制。如果您真的想使用自己的方法,那么您必须创建一个 Graphics 对象并将其传入。

    最后,在被覆盖的 paintComponents(Graphics g) 方法中,最后一行是绘制巨大的黑盒子。然后,这将掩盖您之前绘制的任何内容。因此,您应该将其作为第一行并按顺序绘制其他所有内容,以便最后绘制您想要位于顶部的东西。我能够让我的测试图像显示为该类的以下代码。我不认为我改变了其他任何东西。

    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.*;
    
    public class GameView extends JComponent implements ActionListener{
    
    /**
     * 
     */
    private static final long serialVersionUID = -2869672245901003704L;
    private boolean liveGame;//used so that buttons cannot be clicked after game is complete
    private GameState gs;
    private Player p;
    private int w, h;
    
    public GameView(int width, int height)
    {
        liveGame = true;
        gs = new GameState();
        GameState.init(width, height);
        p = new Player(width/2,(height*7)/8);
        this.setBackground(Color.BLACK);
        w = width;
        h = height;
    }
       @Override
        public Dimension getMinimumSize() {
            return new Dimension(w, h);
        }
    
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(w, h);
        }
    
        @Override
        public void paintComponent(Graphics g) {
            int margin = 10;
            Dimension dim = getSize();
            super.paintComponent(g);
            g.setColor(Color.black);
            GameState.update();
    
            g.fillRect(margin, margin, dim.width - margin * 2, dim.height - margin * 2);
    
            for(Bullet j : GameState.getEnBullets()){
                g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
            for(Enemy j : GameState.getEnemies()){
                g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
            for(Bullet j : GameState.getPlayBullets()){
                g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
    
            g.drawImage(p.getImage(),p.getX(),p.getY(),null);
        }
    
    
    
    
    public void refreshImage()
    {
        this.removeAll();
        repaint();
    }
    
    
    public void actionPerformed(ActionEvent e) {
    
    
    }
    
    
    }
    

    另一件事是在您的其他一些类中,您在 actionPerformed 方法上使用了 @Override。我的 IDE 不喜欢这样,尽管它可以编译。它说“实现接口方法时不允许使用@Override。”

    希望这对你有用。

    【讨论】:

      【解决方案3】:

      尝试添加 repaint();更改内容窗格后。我认为除非您堵塞 EDT,否则并发性不会成为问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-02-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多