I am trying to make a version of Snake Game in Java that uses a JFrame JPanel combination in which the JPanel contains an all black background and draws a grid of squares with a white outline (drawRect) and fill it with the color dark gray (fillRect) that are each 5 x 5 in width and height. However when adding each Node/Square to the panels gridLayout, running the program simply does not display the window at all. Only after commenting out the initNodes function does it display a window with a black background. How would I be able to make interact-able squares within a JPanel grid layout?
Board.java
package snakegame;
import java.awt.Color;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Board {
JFrame window;
JPanel panel;
Graphics g;
protected final Node[][] nodes = new Node[800][1000];
protected static int WINDOW_WIDTH = 1000;
protected static int WINDOW_HEIGHT = 800;
public Board(){
initBoard();
}
private void initPanel(){
panel = new JPanel();
panel.setBackground(Color.BLACK);
panel.setLayout(new GridLayout(800,1000));
initNodes();
window.getContentPane().add(panel);
}
private void initNodes(){
for(int row = 0; row < nodes.length; row ){
for(int col = 0; col < nodes[row].length; col ){
nodes[row][col] = new Node(row, col); //Whenever this is called this should draw a square at each node
panel.add(nodes[row][col]); //Add to panel grid layout
}
}
}
private void initBoard(){
window = new JFrame();
window.setTitle("JSnake!");
window.setSize(WINDOW_WIDTH,WINDOW_HEIGHT);
window.setResizable(false);
window.setLocationRelativeTo(null);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initPanel();
window.pack();
window.setVisible(true);
}
}
Node.java
package snakegame;
import javax.swing.*;
import java.awt.Color;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Node extends JPanel {
int xPos;
int yPos;
public Node(int x, int y){
this.xPos = x;
this.yPos = y;
}
@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.WHITE);
g2.drawRect(this.xPos,this.yPos, Board.WINDOW_WIDTH/200,Board.WINDOW_HEIGHT/ 160);
g2.setColor(Color.DARK_GRAY);
g2.fillRect(this.xPos,this.yPos,Board.WINDOW_WIDTH/200,Board.WINDOW_HEIGHT/ 160);
}
}
CodePudding user response:
After experimenting greatly, I decided to scrap that project and make a completely new version that in my opinion is much more organized and has 4 files in total, I would like to add that the game itself is not finished as that is not what my question was asking, rather it was asking how to make a proper grid layout for using JPanel JFrame (hence why you will see so many import statements that will be removed) and here is my solution:
Main.java:
package snakegame;
import java.awt.EventQueue;
public class Main {
public static void main(String arg[]){
EventQueue.invokeLater(() -> {
var gameFrame = new GameFrame();
gameFrame.window.setVisible(true);
});
}
}
GameFrame.java:
package snakegame;
import javax.swing.*;
import java.awt.*;
public class GameFrame {
JFrame window;
Game panel;
public GameFrame(){
window = new JFrame();
panel = new Game();
window.setUndecorated(false);
window.setLocationRelativeTo(null);
window.setTitle("JSnake");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setResizable(false);
window.add(panel);
window.pack();
window.setVisible(true);
}
}
Node.java:
package snakegame;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Node extends JPanel {
private final int SIZE = 20;
public Node(){
this.setBorder(BorderFactory.createLineBorder(Color.BLACK));
this.setPreferredSize(new Dimension(SIZE,SIZE));
}
@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(0,0, getWidth(), getHeight());
}
}
Game.java:
import java.awt.Color;
import java.awt.Image;
import java.awt.*;
import java.awt.event.*;
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.ImageIcon;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.JMenu;
public class Game extends JPanel implements ActionListener {
private final int DELAY = 75;
private Node[][] grid = new Node[40][40];
private char direction;
Timer timer;
public Game(){
this.setBackground(Color.black);
this.setFocusable(true);
startGame();
}
private void startGame(){
initNodes();
timer = new Timer(DELAY, this);
timer.start();
}
private JPanel initNodes(){
this.setLayout(new GridLayout(40,40,0,0));
for(int row = 0; row <= grid.length - 1; row ){
for(int col = 0; col <= grid[row].length - 1; col ){
grid[row][col] = new Node();
this.add(grid[row][col]);
}
}
return this;
}
//Create the game loop
@Override
public void actionPerformed(ActionEvent e) {
}
//Check for key presses to use in the moveSnake method
public class KeyListener extends KeyAdapter{
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT:
if (direction != 'R') {
direction = 'L';
}
break;
case KeyEvent.VK_RIGHT:
if (direction != 'L') {
direction = 'R';
}
break;
case KeyEvent.VK_UP:
if (direction != 'D') {
direction = 'U';
}
break;
case KeyEvent.VK_DOWN:
if (direction != 'U') {
direction = 'D';
}
break;
}
}
}
}