图形不出现在JFrame中(包括SSCCE)

时间:2011-06-07 21:35:35

标签: java debugging swing graphics jframe

我正在制作游戏(参见我之前的主题)并且在途中遇到了很多问题。我所知道的是他的代码编译,运行,但窗口中没有任何内容,它只是灰色。在Andrew Thompson的建议中,我在这里发布了整个可编译版本。抱歉长度,但它是程序中的所有代码。很多事情可能没有意义(使用未使用的ActionPerformed来命名),部分是因为我在需要它的事件中实现了代码,但主要是因为我以前从未这样做过。

此外,到目前为止,我没有多线程,因为我再次对此不熟悉,所以理想情况下我希望保持这种方式,只是为了我的理智。

编辑:忘记提及我有4个PNG代表出现的4个不同的对象。我的代码足够灵活,您可以自己提供。这是我用于船只enter image description here的图像,这里是子弹enter image description here只需制作副本,将它们作为源文件并命名为“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;
    }


}

3 个答案:

答案 0 :(得分:5)

我不相信你写的700行代码没有做任何测试。是时候回到起点,从简单的事情开始。这就是SSCCE的重点。首先绘制几个组件。一旦你开始工作,你就会增加一些动作。一旦它工作,你添加碰撞逻辑。

我唯一注意到快速浏览的是你覆盖paintComponents()。没有必要在pantComponent()方法中完成自定义绘制。

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

答案 1 :(得分:2)

好的,所以我想我已经弄明白了。

你有几个问题。

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

一旦你给它一些东西,第二个问题就显而易见了。我手动输入一行代码来绘制播放器,为此我使用了自己的一个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) {


}


}

另一件事是你的其他一些类中有@Override而不是actionPerformed方法。我的IDE不喜欢它,虽然它确实编译。它说“实现接口方法时不允许@Override。”

希望这适合你。

答案 2 :(得分:0)

尝试添加repaint();对内容窗格进行更改后。我不认为并发会成为一个问题,除非你堵塞​​你的EDT。