开发者

Graphics not appearing in JFrame (SSCCE included)

开发者 https://www.devze.com 2023-03-11 07:27 出处:网络
I am making a game (see my previous threads) and have encountered a lot of problems on the way. All I know is that he code compiles, runs, but nothing appears in the window, it\'s just grey. At Andrew

I am making a game (see my previous threads) and have encountered a lot of problems on the way. All I know is that he code compiles, runs, but nothing appears in the window, it's just grey. At Andrew Thompson's suggestion, I am posting the entire compilable version here. Sorry for the length but it is ALL the code in the program. And a lot of things will probably not make sense (unused ActionPerformed to name one), partially because I implemented code in the event that I would need it but mostly because I have never done this before.

Also, so far I have no multithreading, because once again, I am new to this, so ideally I would like to keep it that way, if only for the sake of my sanity.

EDIT: Forgot to mention I have 4 PNGs in there representing the 4 different objects that appear. My code is flexible enough for you to supply your own. Here is the image I am using for ships

Graphics not appearing in JFrame (SSCCE included)

and here is the one for bullets

Graphics not appearing in JFrame (SSCCE included)

just make copies, put them the source file and name them "Enemy-ship" "ship2" "Ebullet" and "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 v开发者_如何学Pythonoid 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;
    }


}


I can't believe your write 700 lines of code without doing any testing along the way. Its time you go back to the beginning and start with something simple. That is the whole point of a SSCCE. Start with painting a couple of compononents. Once you get that working you add some movement. Once that is working you add collision logic.

The only thing I noticed with a quick broswe is that you override paintComponents(). There is no need to do that custom painting is done in the pantComponent() method.

If you can't produce a smaller sized SSCCE, then all I can do is wish you good luck.


Ok, so I think I have figured most of it out.

You have a couple problems.

First, you should only see a grey screen with a black rectangle in the middle since you have nothing in your Bullet and Enemy Arrays. This is what I got when I ran your code (after removing references to endEvent cuz it couldn't find it). So to fix this, just give it something to draw

The second problem is apparent once you give it something to draw. I manually put in a line of code to draw the Player, for which I used one of my own pngs. When you do this it will fail to compile with a null pointer exception. The reason is because in your GameView class, you have your Graphics object called "graphics" set to null, but then you proceed to call paintComponents(graphics). As mentioned before, this only compiled before because you never actually drew anything. To fix this, you can just remove

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

}

and let the overridden paintComponent(Graphics g) method above it do all the work. Additionally, instead of the paintComponents(graphics) calls, use repaint(). Also you can get rid of the first call to paintComponents(graphics) in the constructor as it will paint the first time by default. If you really want to use your own method then you have to create a Graphics object and pass that in.

Lastly, in the overridden paintComponents(Graphics g) method, you have the last line being to draw the giant black box. This will then cover up anything you've drawn before. So you should have that as the first line and draw everything else in order such that the thing you want to be on top should be drawn last. I was able to get my test image to show up with the following code for that class. I don't think I changed anything else.

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) {


}


}

The other thing is in some of your other classes you have @Override over the actionPerformed method. My IDE doesn't like that, although it does compile. It says "@Override is not allowed when implementing interface methods."

Hopefully this works for you.


try adding repaint(); after you make a change to a content pane. I dont think concurrency is going to be a problem unless you clog up your EDT.

0

精彩评论

暂无评论...
验证码 换一张
取 消