1

I have been trying to display the graphics for my game, but none of the graphics are being displayed on the panel.

Following is my code. The main class invokes the paint methods of the other two classes.

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Simulator extends JFrame implements KeyListener, Runnable, ActionListener {

    private final int WIDTH, HEIGHT;
    private Boolean right;
    private int xMotion;
    public Salt salt;
    public Player playR;
    Boolean running = false;
    private Thread thread;
    public static int score, highScore;
    private int saltSpeed;

    public Simulator(int width, int height) {
        JPanel panel = new JPanel();
        JFrame frame = new JFrame();
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        frame.setSize(width, height);
        panel.setBackground(Color.BLACK);
        frame.add(panel);

        playR = new Player();


        this.HEIGHT = height;
        this.WIDTH = width;
        int xCordSalt = (int) (Math.random() * 631);
        saltSpeed = 1;

        salt = new Salt(saltSpeed);
        right = true; 
        running = true;

    }


    public static void main(String[] args) {
        Simulator game = new Simulator(640, 480);

        game.start();
    }

    public void paintComponent(Graphics g)
    {


        salt.paint(g);
        playR.paint(g);



    }

    public void start() {

        running = true;
        thread = new Thread(this);
        thread.start();
        repaint();
        tick();
        run();


    }

    public void stop() {
        running = false;
        System.exit(0);
    }


    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_D) {
            right = true;
        } else if (e.getKeyCode() == KeyEvent.VK_A) {
            right = false;

        }

    }

    public void tick() {
        salt.tick(this, playR);
        playR.tick();

    }

    @Override
    public void keyReleased(KeyEvent e) {


    }

    @Override
    public void keyTyped(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_D)
        {
            playR.setDirection(true);
        }
        else if(e.getKeyCode() == KeyEvent.VK_A)
        {
            playR.setDirection(false);
        }

    }

    @Override
    public void run() {
        while (running) {
            tick();
            repaint();

            try {
                thread.sleep(7);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }



    public void incrementScore() {
        score++;

    }


    @Override
    public void actionPerformed(ActionEvent e) {
        repaint();
        tick();

    }

}

And here's the code for the method salt:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.ArrayList;



public class Salt extends Rectangle{

    private final int WIDTH = 10;
    private final int HEIGHT = 10;
    public int xCordSalt, yCordSalt;
    private int speed;
    Rectangle boundBox;
    public Salt(int speedx)
    {

        xCordSalt = (int)Math.random()*641;
        yCordSalt = 0;
        speed = speedx;
        boundBox = new Rectangle(xCordSalt, yCordSalt, WIDTH, HEIGHT);
        boundBox.setBounds(xCordSalt, yCordSalt, WIDTH, HEIGHT);



    }

    public void tick(Simulator sim, Player playR)
    {
        boundBox.setBounds(xCordSalt, yCordSalt, WIDTH, HEIGHT);

        if(yCordSalt >= 480)
        {
            //sim.stop();
        }

        else if(checkCollision(playR))
        {
            sim.incrementScore();
            speed++;
            yCordSalt = -speed;

        }


        yCordSalt = yCordSalt + speed;


    }




    public boolean checkCollision(Player playR)
    {
        if(this.getBoundBox().intersects(playR.getBoundBox()))
        {
            return true;
        }
        return false;
    }

    public void paint(Graphics g) {
        g.setColor(Color.WHITE);
        g.fillRect(xCordSalt, yCordSalt, WIDTH, HEIGHT);
    }

    public Rectangle getBoundBox()
    {
        return boundBox;
    }

    public double getSpeed()
    {
        return speed;
    }


}

And finally the method player, which uses the imageIcon class to display an image:

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

public class Player extends JPanel {
    private int xCord, yCord;
    public Rectangle boundBox;
    private static ImageIcon ryan;
    boolean isRight;

    public Player() {
        ryan = new ImageIcon("E:\ryan.png");
        xCord = 640/2;
        yCord = 460;
        boundBox = new Rectangle(xCord, yCord, 20, 20);


    }

    public static void main(String[] args) {

    }

    public void tick() {

    }

    public void setDirection(Boolean right)
    {
        if(right)
            isRight = true;
        else
            isRight = false;
    }


    public void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D)g;
        g2d.drawImage(ryan.getImage(), xCord, yCord, null);


    }

    public Rectangle getBoundBox()
    {
        return boundBox;
    }

}

Now some of it is incomplete, but I cannot realize why it is displaying no graphics whatsoever. When ran, only a black frame / panel appears. I added some print statements to the tick() methods of each class, the paint() methods of each class and the paintComponent() method, and the start() method. The game will start, run each class's tick method, but paintComponent() or any of the paint() methods are ever called!

  • You need to change `"E:\ryan.png"` to `"E:\\ryan.png"`. The backslash ( \ ) is an escape character; to place an actual backslash in a string, you need to escape the backslash with another backslash. – VGR May 13 '16 at 18:53
  • @ursinusTheStrong oh man how could I forget about escape sequences! Thanks for reminding me! – ERIK UMHOEFER May 13 '16 at 20:13
  • JFrame doesn't have a paintComponent method, so it never be called, this is why you should use @Override. Create class that extends from a JPanel, override it's paintComponent method and perform your custom panting there,make sure you call super.paintComponent first. One idea is to create an Entity, which describes some element in your game, high do "stuff" one of those elements would then be "paintable", which has some method you can pass a reference of Graphics to and which draw itself, this way, all you need to do is maintain a List of entities, update the, and paint them – MadProgrammer May 13 '16 at 21:20
  • @MadProgrammer /@Override gives me this error: https://gyazo.com/13aee2a2ac1ffa81669c38dfcb05def8 So you are saying I should make a separate class to handle graphics? I am a little confused what you are saying I should do. – ERIK UMHOEFER May 13 '16 at 22:27
  • Yes, the reason I suggested adding @Override is because it gives you a compiler warning when you "think" you're overriding a method when your not, it's a nice sanity check. Yes, I'd use a separate class for all you custom painting (I this case) – MadProgrammer May 13 '16 at 23:10
  • @MadProgrammer so a separate class handling painting would help in what way? I'm kind of confused how a separate class would help. Also, if you look at my new edits, i believe the problem is with the repaint() method. As the tick method runs perfectly, and even if I move repaint() above tick() tick still is being called every time, so I cannot figure out for the life of me why the graphics aren't displaying? Am I incorrectly using repaint()? – ERIK UMHOEFER May 13 '16 at 23:16
  • The problem is, you have multiple panels sitting on top of each which are opaque, what I'm suggesting is, you use a single `JPanel` to handle ALL your (related) custom painting requirements. The other problem is `JFrame` doesn't have a `paintComponent` method and overriding `paint` puts you back into the same position you have right now ... plus ... – MadProgrammer May 13 '16 at 23:19
  • Why you don't want to override `paint` of a `JFrame`, [because](http://stackoverflow.com/questions/13734069/how-can-i-set-in-the-midst/13734319#13734319), [because](http://stackoverflow.com/questions/16473627/java-jframe-setsizex-y-not-working/16473639#16473639), [because](http://stackoverflow.com/questions/13457237/how-to-get-the-exact-middle-of-a-screen-even-when-re-sized/13460914#13460914), [because](http://stackoverflow.com/questions/17157956/why-is-overriding-paint-in-a-top-level-container-so-bad/17158482#17158482), – MadProgrammer May 13 '16 at 23:21
  • [because](http://stackoverflow.com/questions/34835767/java-jframe-boundaries/34836046#34836046) ... need I really go on – MadProgrammer May 13 '16 at 23:21
  • @MadProgrammer I'm really sorry I'm pretty stupid, but are you saying that my objects may be off the actual "panel" where you draw, and that the graphics I am trying to portray are just offscreen? And are you saying that I should use just a JPanel to handle all my methods instead of using the JFrame at all, and just use draw onto the panel? Sorry again, I looked at all the links but am still a little confused, I just see how the drawings may go off the screen. – ERIK UMHOEFER May 13 '16 at 23:31
  • Your graphics aren't been drawn because the `paintComponent` in `JFrame` is NEVER called, it's not part of the prescribed paint chain. It'd recommend using a `JPanel` and override its `paintComponent` because that's the recommended method for performing custom painting – MadProgrammer May 13 '16 at 23:34
  • @MadProgrammer OK I see what you are getting at, using a JPanel and JPanel alone is what I need to do in order to get the graphics to draw, as there's a problem with the JFrame and JPanel class's paint/paintComponent method interacting. So I guess I'll have to look up how to make a jpanel, thanks for all the help man, you must have the patience of a God in order to deal with a newb like me! – ERIK UMHOEFER May 13 '16 at 23:38
  • @ERIKUMHOEFER I have a four year old, patience is the only way I survive ;) – MadProgrammer May 13 '16 at 23:41
  • @MadProgrammer so I have successfully drawn to a panel! My only problem is that, now that I have a separate class that creates a JPanel, how do I use the class that creates the JPanel and draws to it to call paint() for salt and playR? the separate class I am using to draw can set background and draw on the screen manually, but how do I use it to call the other paint methods? – ERIK UMHOEFER May 14 '16 at 00:06
  • You don't, the panel itself should manage these things – MadProgrammer May 14 '16 at 00:25

2 Answers2

2

Let's start with the obvious...

public class Simulator extends JFrame ... {
    //...
    public void paintComponent(Graphics g) {

        salt.paint(g);
        playR.paint(g);

    }

JFrame doesn't have a method called paintComponent, so your paintComponent will never be called, so salt and playR will never painted.

You can test this by adding @Override to the paintComponent which does a compile time sanity check for you

public class Simulator extends JFrame ... {
    //...
    @Override
    public void paintComponent(Graphics g) {

        salt.paint(g);
        playR.paint(g);

    }

This will fail to compile.

Now, you could override paint instead, but because, because, because, because, because ... I wouldn't recommend it ...

Take a step back for a second. What is the JFrame really responsible for? Providing a container onto which you can add you gui and have it displayed on the screen. You're not really adding any new functionality to the JFrame, so I wouldn't use it as your "main" component, instead, I'd just create an instance of it and add what ever components you want to use to it.

Instead, I'd start with a JPanel and override its paintComponent method and put all your custom painting into it.

I would then use this component as a starting point for your core logic and controllers.

You might even create several components to act as things like the menu and option views and use a CardLayout or OverlayoutLayout to display them.

I'd also recommend having a look at How to Use Key Bindings instead of KeyListener while you're at it, this will answer your next question.

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Any reason for the down vote? Does it not answer the ops question? In what ways could it be improved? – MadProgrammer May 14 '16 at 20:32
  • Not your down voter; I agree that "Swing programs should override `paintComponent()` instead of overriding `paint()`."—[*Painting in AWT and Swing: The Paint Methods*](http://www.oracle.com/technetwork/java/painting-140037.html#callbacks). – trashgod May 15 '16 at 06:21
0

First you are creating a frame in excess - the class itself is a frame so no need for more:

    setSize(width, height);
    setVisible(true);

Second you add a panel on to it: that will cover everything;

Third JFrame doesn't have paintComponent - instead use paint().

Fourth, in starting the thread by calling start() the run() method will automatically be called - no need to call run().

Here's my working constructor and paint method:

public Simulator(int width, int height) {
    setSize(width, height);
    panel.setBackground(Color.BLACK);
    setVisible(true);

    try {
      bim=ImageIO.read(new File(.....));
    }
    catch (Exception ex) { ex.printStackTrace(); }


    this.HEIGHT = height;
    this.WIDTH = width;
    int xCordSalt = (int) (Math.random() * 631);
    saltSpeed = 1;

    right = true; 
    running = true;

}


public void paint(Graphics g)
{

  g.setColor(Color.magenta);
  g.fillRect(0, 0, 100, 100);
  g.drawImage(bim, 100, 0, null);

}
gpasch
  • 2,672
  • 3
  • 10
  • 12
  • then in the paint method should I add salt.paint(with parameters) and playR.paint()? Also, thanks a ton for the help! Me and my peers were very confused why it wasn't working. – ERIK UMHOEFER May 13 '16 at 20:13
  • 1
    Do not paint directly on a JFrame. Paint using the paintComponent method of a JPanel that's added to a JFrame. Here's an [example](http://stackoverflow.com/questions/34981403/bufferedimage-not-being-cleared-before-each-rendering/35002727#35002727). – Gilbert Le Blanc May 13 '16 at 21:01
  • @GilbertLeBlanc this is what I did in my program though, so why doesn't it print anything to the screen? Here it what happens if I run the unedited code: https://gyazo.com/a4540ae5d3233c22c791cf7f0fb7afec I also used a print statement in the paintComponent method, paint method for salt and player class and none of those are printing anything, which means they must not be being called. – ERIK UMHOEFER May 13 '16 at 22:18