Reputation: 1
Whenever I create a new JFrame
screen the game won't run on my computer for some reason and I don't know why. I have tried fixing this issue but I think it has something to do with the buttons or the placement of the screen. The startStage
is what I need help on. If I'm missing something can you please tell me.
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
/**
* This class demonstrates basic animation using a timer, an action listener,
* and a key listener
*
*
*
*/
public class GameWindow extends JPanel implements ActionListener, KeyListener {
private static final long serialVersionUID = 1L;
JLabel player = new JLabel();
int playerSpeed = 1;
int FPS = 30;
// The keys set holds the keys being pressed
private final Set<Integer> keys = new HashSet<>();
public static void main(String[] args) {
// Open the GUI window
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// Create a new object and
// run its go() method
new GameWindow().go();
}
});
}
public GameWindow() {
// Run the parent class constructor
super();
// Allow the panel to get focus
setFocusable(true);
// Don't let keys change the focus
setFocusTraversalKeysEnabled(false);
//Make a new screen with a button and put it in the window
JPanel startStage = new JPanel(); // Create a new JPanel and add it to the card layout
startStage.setSize(getWidth(), getHeight()); // make the new JPanel fit the window
startStage.setBackground(Color.BLUE); // set the JPanel background to blue
startStage.setVisible(true); // show the JPanel
JButton playButton = new JButton("Play"); // Add a button to the panel
playButton.addMouseListener(new MouseAdapter() { // Set the button to switch to the game stage
@Override
public void mouseClicked(MouseEvent arg0) {
((CardLayout) getContentPane().getLayout()).show(
getContentPane(), "game");
}
});
startStage.add(playButton); // add the button to the stage
add(startStage, "start"); // add the stage to the window
}
protected void go() {
// Setup the window
JFrame jf = new JFrame();
// Add this panel to the window
jf.setContentPane(this);
// Set the window properties
jf.setTitle("Animation Demo");
jf.setSize(300, 200);
jf.setLocationRelativeTo(null);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setVisible(true);
// Setup the movable box
player.setBounds(10, 10, 10, 10);
player.setVisible(true);
player.setBackground(Color.BLUE);
// Opaque makes the background visible
player.setOpaque(true);
// Setup the key listener
addKeyListener(this);
// Null layout allows moving objects!!!
setLayout(null);
add(player);
// Set the timer
Timer tm = new Timer(1000 / FPS, this);
tm.start();
}
@Override
public void actionPerformed(ActionEvent arg0) {
// Move up if W is pressed
if (keys.contains(KeyEvent.VK_W)) {
player.setLocation(player.getX(), player.getY() - playerSpeed);
}
// Move right if D is pressed
if (keys.contains(KeyEvent.VK_D)) {
player.setLocation(player.getX() + playerSpeed, player.getY());
}
// Move down if S is pressed
if (keys.contains(KeyEvent.VK_S)) {
player.setLocation(player.getX(), player.getY() + playerSpeed);
}
// Move left if A is pressed
if (keys.contains(KeyEvent.VK_A)) {
player.setLocation(player.getX() - playerSpeed, player.getY());
}
}
@Override
public void keyPressed(KeyEvent e) {
// Add the key to the list
// of pressed keys
if (!keys.contains(e.getKeyCode())) {
keys.add(e.getKeyCode());
}
}
@Override
public void keyReleased(KeyEvent e) {
// Remove the key from the
// list of pressed keys
keys.remove((Integer) e.getKeyCode());
}
@Override
public void keyTyped(KeyEvent e) {
}
}
Upvotes: 0
Views: 59
Reputation: 347314
You seem to have issues with how container management works. Stop, take a step back for a second and re-think your approach.
You basically have a "menu" and a "game" panel. This should be two separate panels/class.
These should then be added to a "hub" panel, which manages when and how they are displayed.
MainPane
This is the "main", "hub" panel. It is responsible for displaying both the menu and the game panels. It's also responsible for deciding "how" this happens, in this example, I've simply used a CardLayout
public class MainPane extends JPanel {
public MainPane() {
setLayout(new CardLayout());
MenuPane menu = new MenuPane();
menu.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (getLayout() instanceof CardLayout) {
CardLayout layout = (CardLayout) getLayout();
layout.show(MainPane.this, "game");
}
}
});
GamePane game = new GamePane();
add(menu, "menu");
add(game, "game");
((CardLayout) getLayout()).show(this, "menu");
}
}
MenuPane
The "menu" is pretty simple. It simply displays the available options and provides a means for interested parties to be notified when an option is selected
public class MenuPane extends JPanel {
private JButton btn;
public MenuPane() {
setLayout(new GridBagLayout());
setBackground(Color.BLUE);
btn = new JButton("Start");
add(btn);
}
public void addActionListener(ActionListener listener) {
btn.addActionListener(listener);
}
public void removeActionListener(ActionListener listener) {
btn.removeActionListener(listener);
}
}
I'm not going into a lot about this, but you should have a look at How to Use Buttons, Check Boxes, and Radio Buttons and How to Write an Action Listener for more details
I'm been lazy, attaching the ActionListener
s directly to the buttons. Instead, you should manage the button listeners and the panel's listeners separately, this will prevent exposing the buttons and allow you better control over what to generate when a specific operation is executed.
GamePane
And finally, the "game" panel. As I've been saying for the last day, you should make use a custom painting route and How to Use Key Bindings. Together, they will solve a swagger of other issues we'd generally like not to have to be asked about, again
public interface Movable {
public void changeLocation(int xDelta, int yDelta);
}
public class GamePane extends JPanel implements Movable {
private Rectangle player;
public GamePane() {
String text = "X";
FontMetrics fm = getFontMetrics(getFont());
int width = fm.stringWidth(text);
int height = fm.getHeight();
player = new Rectangle(0, 0, width, height);
setupKeyBindings();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void setupKeyBindings() {
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), "down");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "right");
int xDelta = player.width;
int yDelta = player.height;
am.put("up", new MoveAction(this, 0, -yDelta));
am.put("down", new MoveAction(this, 0, yDelta));
am.put("left", new MoveAction(this, -xDelta, 0));
am.put("right", new MoveAction(this, xDelta, 0));
}
@Override
public void changeLocation(int xDelta, int yDelta) {
int xPos = player.x + xDelta;
int yPos = player.y + yDelta;
if (xPos + player.width > getWidth()) {
xPos = getWidth() - player.width;
} else if (xPos < 0) {
xPos = 0;
}
if (yPos + player.height > getHeight()) {
yPos = getHeight() - player.height;
} else if (xPos < 0) {
yPos = 0;
}
player.setLocation(xPos, yPos);
repaint();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.draw(player);
FontMetrics fm = g2d.getFontMetrics();
g2d.drawString("X", player.x, player.y + fm.getAscent());
g2d.dispose();
}
}
public class MoveAction extends AbstractAction {
private Movable movable;
private int xDelta;
private int yDelta;
public MoveAction(Movable movable, int xDelta, int yDelta) {
this.movable = movable;
this.xDelta = xDelta;
this.yDelta = yDelta;
}
@Override
public void actionPerformed(ActionEvent e) {
movable.changeLocation(xDelta, yDelta);
}
}
Putting it all together...
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Game {
public static void main(String[] args) {
new Game();
}
public Game() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MainPane extends JPanel {
public MainPane() {
setLayout(new CardLayout());
MenuPane menu = new MenuPane();
menu.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (getLayout() instanceof CardLayout) {
CardLayout layout = (CardLayout) getLayout();
layout.show(MainPane.this, "game");
}
}
});
GamePane game = new GamePane();
add(menu, "menu");
add(game, "game");
((CardLayout) getLayout()).show(this, "menu");
}
}
public class MenuPane extends JPanel {
private JButton btn;
public MenuPane() {
setLayout(new GridBagLayout());
setBackground(Color.BLUE);
btn = new JButton("Start");
add(btn);
}
public void addActionListener(ActionListener listener) {
btn.addActionListener(listener);
}
public void removeActionListener(ActionListener listener) {
btn.removeActionListener(listener);
}
}
public interface Movable {
public void changeLocation(int xDelta, int yDelta);
}
public class GamePane extends JPanel implements Movable {
private Rectangle player;
public GamePane() {
String text = "X";
FontMetrics fm = getFontMetrics(getFont());
int width = fm.stringWidth(text);
int height = fm.getHeight();
player = new Rectangle(0, 0, width, height);
setupKeyBindings();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void setupKeyBindings() {
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), "down");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "right");
int xDelta = player.width;
int yDelta = player.height;
am.put("up", new MoveAction(this, 0, -yDelta));
am.put("down", new MoveAction(this, 0, yDelta));
am.put("left", new MoveAction(this, -xDelta, 0));
am.put("right", new MoveAction(this, xDelta, 0));
}
@Override
public void changeLocation(int xDelta, int yDelta) {
int xPos = player.x + xDelta;
int yPos = player.y + yDelta;
if (xPos + player.width > getWidth()) {
xPos = getWidth() - player.width;
} else if (xPos < 0) {
xPos = 0;
}
if (yPos + player.height > getHeight()) {
yPos = getHeight() - player.height;
} else if (xPos < 0) {
yPos = 0;
}
player.setLocation(xPos, yPos);
repaint();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.draw(player);
FontMetrics fm = g2d.getFontMetrics();
g2d.drawString("X", player.x, player.y + fm.getAscent());
g2d.dispose();
}
}
public class MoveAction extends AbstractAction {
private Movable movable;
private int xDelta;
private int yDelta;
public MoveAction(Movable movable, int xDelta, int yDelta) {
this.movable = movable;
this.xDelta = xDelta;
this.yDelta = yDelta;
}
@Override
public void actionPerformed(ActionEvent e) {
movable.changeLocation(xDelta, yDelta);
}
}
}
Remember, one of your goals should be about "separation of responsibility", creating classes/components which do there job and do it well. This way you can use them as building blocks to devise much more complex solutions
Upvotes: 1