0

I'm new to java and trying yo create a basic game and right now and trying to program the player class. However only the JFRame appears when i run the game. These are my thress classes and they show no errors.

import java.awt.Color;

import javax.swing.JFrame;

public class Game extends JFrame {
    public
 final static int WIDTH = 700, HEIGHT = 450;
    public
 GamePanel panel;

    public Game() {
        setSize(WIDTH, HEIGHT);
        setTitle("Game");
        setBackground(Color.WHITE);
        setResizable(false);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        panel = new GamePanel(this);
         add(panel);
    }

    public GamePanel getPanel() {
        return panel;
    }

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

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 javax.swing.JPanel;

public class GamePanel extends JPanel implements ActionListener, KeyListener {
    public
 Game game;
    public
 Player player;

    public GamePanel(Game game) {
        setBackground(Color.GREEN);
        this.game = game;
        player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);
        addKeyListener(this);
        setFocusable(true);
    }

    public
 void update() {
        player.update();
    }

    public void actionPerformed(ActionEvent e) {
        update();
        repaint();
    }

        public Player getPlayer(int playerNo) {
          return player; 
        }

    public void keyPressed(KeyEvent e) {
        player.pressed(e.getKeyCode());
    }

    public void keyReleased(KeyEvent e) {
        player.released(e.getKeyCode());
    }

    public void keyTyped(KeyEvent e) {
        ;
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        player.paint(g);
    }
}

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

public class Player {
    public
 static final int WIDTH = 50, HEIGHT = 50;
    public
 Game game;
    public
 int left, right;
    public
 int y;
    public
 int x, xa;

    public Player(Game game, int left, int right, int x) {
        this.game = game;
        this.x = x;
        y = game.getHeight() - 20;
        this.left = left;
        this.right = right;
        this.y = y;
        x = game.getWidth() - 36;
    }

    public void update() {
        if (x > 0 && x < game.getWidth() - WIDTH - 36)
            x += xa;
        else if (x == 0)
            x++;
        else if (x == game.getWidth() - WIDTH - 36)
            x--;
    }

    public void pressed(int keyCode) {
        if (keyCode == left)
            xa = -1;
        else if (keyCode == right)
            xa = 1;
    }

    public void released(int keyCode) {
        if (keyCode == left || keyCode == right)
            xa = 0;
    }

    public Rectangle getBounds() {
        return new Rectangle(x, y, WIDTH, HEIGHT);
    }

    public void paint(Graphics g) {
        g.fillRect(x, y, WIDTH, HEIGHT);
        g.setColor(Color.ORANGE);
    }
}
  • Take `setVisible(true);` and move it it to the last of the `Game` constructor. Also you should make sure you're working within the context of the EDT when building your UI's, see [Initial Threads](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html) for more details – MadProgrammer Mar 24 '16 at 00:23
  • i did what u said but sadly i still cant see my player class – Java Beginner Mar 24 '16 at 00:26
  • There are a few other issues with your code, when you try and set the position of the player been one (as the window has no definable size yet) and the fact that you're assign `y` to `y` which is also kind of weird. – MadProgrammer Mar 24 '16 at 00:40

1 Answers1

2

Take setVisible(true); and move it it to the last of the Game constructor. Also you should make sure you're working within the context of the EDT when building your UI's, see Initial Threads for more details

import java.awt.Color;
import java.awt.EventQueue;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Game extends JFrame {

    public final static int WIDTH = 700, HEIGHT = 450;
    public GamePanel panel;

    public Game() {
        setTitle("Game");
        setBackground(Color.WHITE);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        panel = new GamePanel(this);
        add(panel);
        setResizable(false);
        setSize(WIDTH, HEIGHT);
        setVisible(true);
    }

    public GamePanel getPanel() {
        return panel;
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                new Game();
            }
        });
    }
}

Basically, Swing's layout management is lazy, it won't try to update the container hierarchy until you tell it (revalidate) or it becomes realised or resized, this is a good thing, as the operation can be expensive.

Next, take a look at player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);

You're setting the position of the player to be 36 pixels less than the components width, but when this is called, the width will be 0.

Basically, you need to allow the UI to "settle" before making this types of calls. This is actually not that easy. You could use a ComponentListener and monitor for the componentResized event, but a window can be resized a number of times when it's first initialized, to this end, you need to "wait" until the size is "settled", for example...

public Game() {
    addComponentListener(new ComponentAdapter() {
        private boolean initalised = false;
        private Timer timer = new Timer(250, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                initalised = true;
                panel.init();
                timer.stop();
            }
        });

        @Override
        public void componentResized(ComponentEvent e) {
            if (!initalised) {
                timer.restart();
            }
        }
    });

Then you would need to update GamePanel to provide an init method...

public class GamePanel extends JPanel implements ActionListener, KeyListener {

    public Game game;
    public Player player;

    public GamePanel(Game game) {
        setBackground(Color.GREEN);
        this.game = game;
        addKeyListener(this);
        setFocusable(true);
    }

    public void init() {
        player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);
        repaint();
    }
    //...
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (player != null) {
            player.paint(g);
        }
    }
}

You have a wide range of "magic" numbers, which don't equate to what you're actually trying to do, for example...

player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);

shouldn't that be game.getWidth() - Player.WIDTH?

And then in Player...

public Player(Game game, int left, int right, int x) {
    this.game = game;
    this.x = x;
    y = game.getHeight() - 20;
    //...
    this.y = y;
    x = game.getWidth() - 36;
}

You assign the parameter x to the field x, but then change it at the end of the constructor? Also, this.y = y makes no sense!?

Now, let's talk about what a bad idea setSize(WIDTH, HEIGHT);, which relates to why your player doesn't appear where you want it to...

Windows have decorations, so your viewable area will ALWAYS be smaller than the actual window size, what's worse, the size of the decorations are variable. Instead, you should use JFrame#pack to pack the window around it's contents and have the contents provide hints about big it wants to be.

Have a look at How can I set in the midst? for more details.

Instead of setting the size of the frame, you should be using pack...

public class Game extends JFrame {

    public GamePanel panel;

    public Game() {
        addComponentListener(new ComponentAdapter() {
            private boolean initalised = false;
            private Timer timer = new Timer(250, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    initalised = true;
                    panel.init();
                    timer.stop();
                }
            });

            @Override
            public void componentResized(ComponentEvent e) {
                if (!initalised) {
                    timer.restart();
                }
            }
        });
        setTitle("Game");
        setBackground(Color.WHITE);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        panel = new GamePanel(this);
        add(panel);
        setResizable(false);
        pack();
        setVisible(true);
    }

And allowing GamePanel to make decisions about how big it wants to be...

public static class GamePanel extends JPanel implements ActionListener, KeyListener {

    public final static int WIDTH = 700, HEIGHT = 450;

    public Game game;
    public Player player;

    public GamePanel(Game game) {
        setBackground(Color.GREEN);
        this.game = game;
        addKeyListener(this);
        setFocusable(true);
    }

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

This also means that instead of passing Game to your objects, you should be passing GamePanel to them and using its dimensions, for example...

public static class Player {
    //...
    public Player(GamePanel game, int left, int right, int x) {
        this.game = game;
        this.left = left;
        this.right = right;
        this.x = x;
        y = game.getHeight() - HEIGHT;
    }

You should also not be using KeyListener and instead should be using the Key Bindings API instead, which will solve the focus related issue and make it easier to configure the key strokes

Basically, you're missing some core understandings about how the Swing framework works, which is causing no end of issues, I'd take the time to learn more about how the framework works generally before diving into something as complex as game development

Runnable example...

Now, because I've basically butchered your code to get it to work...

Happy Player

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Game extends JFrame {

    public GamePanel panel;

    public Game() {
        addComponentListener(new ComponentAdapter() {
            private boolean initalised = false;
            private Timer timer = new Timer(250, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    initalised = true;
                    panel.init();
                    timer.stop();
                }
            });

            @Override
            public void componentResized(ComponentEvent e) {
                if (!initalised) {
                    timer.restart();
                }
            }
        });
        setTitle("Game");
        setBackground(Color.WHITE);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        panel = new GamePanel(this);
        add(panel);
        setResizable(false);
        pack();
        setVisible(true);
    }

    public GamePanel getPanel() {
        return panel;
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                new Game();
            }
        });
    }

    public static class GamePanel extends JPanel implements ActionListener, KeyListener {

        public final static int WIDTH = 700, HEIGHT = 450;

        public Game game;
        public Player player;

        public GamePanel(Game game) {
            setBackground(Color.GREEN);
            this.game = game;
            addKeyListener(this);
            setFocusable(true);
        }

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

        public void init() {
            System.out.println("!!");
            player = new Player(this, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, getWidth() - 50);
            repaint();
        }

        public void update() {
            player.update();
        }

        public void actionPerformed(ActionEvent e) {
            update();
            repaint();
        }

        public Player getPlayer(int playerNo) {
            return player;
        }

        public void keyPressed(KeyEvent e) {
            player.pressed(e.getKeyCode());
        }

        public void keyReleased(KeyEvent e) {
            player.released(e.getKeyCode());
        }

        public void keyTyped(KeyEvent e) {
            ;
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (player != null) {
                player.paint(g);
            }
        }
    }

    public static class Player {

        public static final int WIDTH = 50, HEIGHT = 50;
        public GamePanel game;
        public int left, right;
        public int y;
        public int x, xa;

        public Player(GamePanel game, int left, int right, int x) {
            this.game = game;
            this.left = left;
            this.right = right;
            this.x = x;
            y = game.getHeight() - HEIGHT;
        }

        public void update() {
            if (x > 0 && x < game.getWidth() - WIDTH - 36) {
                x += xa;
            } else if (x == 0) {
                x++;
            } else if (x == game.getWidth() - WIDTH - 36) {
                x--;
            }
        }

        public void pressed(int keyCode) {
            if (keyCode == left) {
                xa = -1;
            } else if (keyCode == right) {
                xa = 1;
            }
        }

        public void released(int keyCode) {
            if (keyCode == left || keyCode == right) {
                xa = 0;
            }
        }

        public Rectangle getBounds() {
            return new Rectangle(x, y, WIDTH, HEIGHT);
        }

        public void paint(Graphics g) {
            System.out.println(x + "x" + y);
            g.fillRect(x, y, WIDTH, HEIGHT);
            g.setColor(Color.ORANGE);
        }
    }
}
Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366