I'm currently working on a schoolproject, where I have to code the game snake. Now I`m finished with the biggest part and tryed to make the game menue. I tryed to place a JButton for starting the game (startPlay). However, the button won't show up and I can't figure out why. Can someone help? Thanks in advance!!
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.Timer;
import java.util.TimerTask;
import javax.swing.*;
public class Main extends JPanel implements ActionListener, KeyListener{
public static int field[][];
public static GenerateField genField;
public static Snake snake;
public static GenerateFood food;
public static GenerateBarrier barrier;
public int difficultness;
public static int widthField;
public static int heightField;
public static TimerTask move, genBarriers;
public static Timer snakeTimer, barrierTimer;
public JButton startPlay;
public static boolean gameStarted;
public Main ()
{
startPlay = new JButton("Starte Spiel");
startPlay.setBounds(0,0,300,200);
startPlay.addActionListener(this);
add(startPlay);
difficultness = 15;
gameStarted = false;
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
widthField = 150;
heightField = 95;
genField = new GenerateField();
snake = new Snake();
food = new GenerateFood();
barrier = new GenerateBarrier();
barrierTimer = new Timer("Timer");
snakeTimer = new Timer("Timer");
genBarriers = new TimerTask() {
@Override
public void run() {
barrier.clearBarrier();
barrier.multiSpawnBarrier(difficultness);
}
};
move = new TimerTask()
{
public void run()
{
if(GenerateField.inGame)
{
snake.moveSnake();
repaint();
}
}
};
}
private static void startGame()
{
genField.generateField();
field = genField.getField();
snake.generateSnake(40, 75);
food.spawnFood();
snakeTimer.schedule(move,0,50);
barrierTimer.schedule(genBarriers, 0, 25000);
}
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(1520,1000);
frame.getContentPane().add(new Main());
frame.setLocationRelativeTo(null);
frame.setBackground(Color.LIGHT_GRAY);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
@Override
public void paint(Graphics g)
{
if(gameStarted) {
for (int iy = 0; iy < heightField; iy++) {
for (int ix = 0; ix < widthField; ix++) {
//Zeichnet schwarzen Hintergrund
if (genField.field[iy][ix] == 0) {
g.setColor(Color.BLACK);
g.fillRect(ix * 10, iy * 10, 10, 10);
}
//Zeichnet die Grenze an den Rändern
if (genField.field[iy][ix] == 1) {
g.setColor(Color.red);
g.fillRect(ix * 10, iy * 10, 10, 10);
}
//Zeichnet die Schlange
if (genField.field[iy][ix] == 2) {
g.setColor(Color.green);
g.fillRect(ix * 10, iy * 10, 10, 10);
}
//Zeichnet das "Futter"
if (genField.field[iy][ix] == 3) {
g.setColor(Color.orange);
g.fillRect(ix * 10, iy * 10, 10, 10);
}
//Zeichte die Hindernisse
if (genField.field[iy][ix] == 4) {
g.setColor(Color.blue);
g.fillRect(ix * 10, iy * 10, 10, 10);
}
}
}
}
}
@Override
public void actionPerformed(ActionEvent e)
{
startPlay.setVisible(false);
startGame();
gameStarted = true;
}
@Override
public void keyPressed (KeyEvent e)
{
int code = e.getKeyCode();
if ( code == KeyEvent.VK_LEFT)
{
if (snake.mRight == false)
{
snake.mLeft = true;
snake.mRight = false;
snake.mUp = false;
snake.mDown = false;
}
}
if ( code == KeyEvent.VK_RIGHT)
{
if (snake.mLeft == false)
{
snake.mLeft = false;
snake.mRight = true;
snake.mUp = false;
snake.mDown = false;
}
}
if ( code == KeyEvent.VK_UP)
{
if (snake.mDown == false)
{
snake.mLeft = false;
snake.mRight = false;
snake.mUp = true;
snake.mDown = false;
}
}
if ( code == KeyEvent.VK_DOWN)
{
if (snake.mUp == false)
{
snake.mLeft = false;
snake.mRight = false;
snake.mUp = false;
snake.mDown = true;
}
}
}
@Override
public void keyReleased(KeyEvent e)
{
}
@Override
public void keyTyped(KeyEvent e)
{
}
}
The over use of static
highlights issues with your design. static
is not your friend, you should use it sparingly and wisely.
You're trying to put all your eggs in single basket. This is just going to make the state management harder to handle.
Instead, start by separating your menu and game into separate classes and managing them independently of each other.
This then allows you to use a CardLayout
to manage the navigation between the different views.
The following is simple example to demonstrate how you might use CardLayout
to perform decoupled navigation
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
CardLayout cardLayout = new CardLayout();
JPanel base = new JPanel(cardLayout);
NavigationController controller = new NavigationController() {
@Override
public void show(Screen screen) {
cardLayout.show(base, screen.name());
}
};
base.add(new MainMenuPane(controller), Screen.MENU.name());
base.add(new GamePane(controller), Screen.GAME.name());
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(base);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public enum Screen {
MENU, GAME;
}
public interface NavigationController {
public void show(Screen scren);
}
public class MainMenuPane extends JPanel {
public MainMenuPane(NavigationController controller) {
setLayout(new GridBagLayout());
JButton start = new JButton("Start");
add(start);
start.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
controller.show(Screen.GAME);
}
});
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class GamePane extends JPanel {
private NavigationController controller;
public GamePane(NavigationController controller) {
this.controller = controller;
setLayout(new GridBagLayout());
add(new JLabel("Ready Player One"));
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
KeyListener
, use Key bindings instead , they will fix the focus related issues in a more reliable way paint
chain, which is part of your immediate problem - See Performing Custom Painting and Painting in Swing for more details about how painting works and how you should work with it java.util.Timer
is running the risk of dirty read/writes which could lead to any number of weird and near impossible to diagnose issues. Instead, you should be using Swing Timer instead, which will ensure that any updates you make are made within the context of the Event Dispatching Thread. You should also be using a single Timer
and scheduling everything in a simple update pass - this will generally improve performance
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.