我在网上找到了这些代码,但它们最初是在JFrame中。现在我想做的是我想把这个JFrame变成一个面板。我想我已经为添加面板做了正确的更改。但是当我运行它时会出现"java.lang.NullPointerException"
错误,而我的eclipse会说SnakeGamePanel.java:339
处的错误是repaint()
方法中的Startgame()
错误。以下代码是我的3个面板,SnakeGamePanel,BoardPanel,SidePanel。如果我错误地添加了面板,请指导我如何将BoardPanel和SidePanel添加到SnakeGamePanel中。
游戏来源:http://psnbtech.blogspot.sg/2012/10/tutorial-java-snake-game-remake.html
SnakeGamePanel:
package gamesUI;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Point;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Random;
public class SnakeGamePanel extends JPanel {
/**
* Create the panel.
*/
/**
* The Serial Version UID.
*/
private static final long serialVersionUID = 6678292058307426314L;
/**
* The number of milliseconds that should pass between each frame.
*/
private static final long FRAME_TIME = 1000L / 50L;
/**
* The minimum length of the snake. This allows the snake to grow
* right when the game starts, so that we're not just a head moving
* around on the board.
*/
private static final int MIN_SNAKE_LENGTH = 5;
/**
* The maximum number of directions that we can have polled in the
* direction list.
*/
private static final int MAX_DIRECTIONS = 3;
/**
* The BoardPanel instance.
*/
private BoardPanel board;
/**
* The SidePanel instance.
*/
private SidePanel side;
/**
* The random number generator (used for spawning fruits).
*/
private Random random;
/**
* The Clock instance for handling the game logic.
*/
private Clock logicTimer;
/**
* Whether or not we're running a new game.
*/
private boolean isNewGame;
/**
* Whether or not the game is over.
*/
private boolean isGameOver;
/**
* Whether or not the game is paused.
*/
private boolean isPaused;
/**
* The list that contains the points for the snake.
*/
private LinkedList<Point> snake;
/**
* The list that contains the queued directions.
*/
private LinkedList<Direction> directions;
/**
* The current score.
*/
private int score;
/**
* The number of fruits that we've eaten.
*/
private int fruitsEaten;
/**
* The number of points that the next fruit will award us.
*/
private int nextFruitScore;
/**
* Creates a new SnakeGame instance. Creates a new window,
* and sets up the controller input.
*/
private int highscore = 0;
private String saveDataPath;
private String FileName = "SaveData";
protected static JFrame myFrame = null;
public SnakeGamePanel(JFrame mf){
myFrame = mf;
//this is for the highscore system
try {
saveDataPath = SnakeGamePanel.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath();
}
catch (Exception e){
}
setLayout(new BorderLayout());
//adding the panels to snakegamepanel
BoardPanel board = new BoardPanel(this);//this is the left panel
SidePanel side = new SidePanel(this);//this is the right panel
add(board, BorderLayout.CENTER);
add(side, BorderLayout.EAST);
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
/*
* If the game is not paused, and the game is not over...
*
* Ensure that the direction list is not full, and that the most
* recent direction is adjacent to North before adding the
* direction to the list.
*/
case KeyEvent.VK_W:
case KeyEvent.VK_UP:
if(!isPaused && !isGameOver) {
if(directions.size() < MAX_DIRECTIONS) {
Direction last = directions.peekLast();
if(last != Direction.South && last != Direction.North) {
directions.addLast(Direction.North);
}
}
}
break;
/*
* If the game is not paused, and the game is not over...
*
* Ensure that the direction list is not full, and that the most
* recent direction is adjacent to South before adding the
* direction to the list.
*/
case KeyEvent.VK_S:
case KeyEvent.VK_DOWN:
if(!isPaused && !isGameOver) {
if(directions.size() < MAX_DIRECTIONS) {
Direction last = directions.peekLast();
if(last != Direction.North && last != Direction.South) {
directions.addLast(Direction.South);
}
}
}
break;
/*
* If the game is not paused, and the game is not over...
*
* Ensure that the direction list is not full, and that the most
* recent direction is adjacent to West before adding the
* direction to the list.
*/
case KeyEvent.VK_A:
case KeyEvent.VK_LEFT:
if(!isPaused && !isGameOver) {
if(directions.size() < MAX_DIRECTIONS) {
Direction last = directions.peekLast();
if(last != Direction.East && last != Direction.West) {
directions.addLast(Direction.West);
}
}
}
break;
/*
* If the game is not paused, and the game is not over...
*
* Ensure that the direction list is not full, and that the most
* recent direction is adjacent to East before adding the
* direction to the list.
*/
case KeyEvent.VK_D:
case KeyEvent.VK_RIGHT:
if(!isPaused && !isGameOver) {
if(directions.size() < MAX_DIRECTIONS) {
Direction last = directions.peekLast();
if(last != Direction.West && last != Direction.East) {
directions.addLast(Direction.East);
}
}
}
break;
/*
* If the game is not over, toggle the paused flag and update
* the logicTimer's pause flag accordingly.
*/
case KeyEvent.VK_SPACE:
if(!isGameOver) {
isPaused = !isPaused;
logicTimer.setPaused(isPaused);
}
break;
/*
* Reset the game if one is not currently in progress.
*/
case KeyEvent.VK_ENTER:
if(isNewGame || isGameOver) {
resetGame();
}
break;
}
}
});
board.setSize(500, 500);
side.setSize(300, 500);
setVisible(true);
}
//this is to save the highscore in a file
private void createSaveData(){
try{
File file = new File (saveDataPath, FileName);
FileWriter output = new FileWriter(file);
BufferedWriter writer = new BufferedWriter(output);
writer.write("" + 0);
writer.close();
}
catch (Exception e){
e.printStackTrace();
}
}
//this is to load the highscore when the game starts
private void loadHighScore(){
try{
File f = new File (saveDataPath, FileName);
if (!f.isFile()){
createSaveData();
}
BufferedReader reader = new BufferedReader (new InputStreamReader(new FileInputStream(f)));
highscore = Integer.parseInt(reader.readLine());
reader.close();
}
catch (Exception e){
e.printStackTrace();
}
}
//this is to set the new highscore in the file if theres any
private void setHighScore(){
FileWriter output = null;
try{
File f = new File(saveDataPath, FileName);
output = new FileWriter(f);
BufferedWriter writer = new BufferedWriter (output);
writer.write("" + highscore);
writer.close();
}
catch (Exception e){
e.printStackTrace();
}
}
/**
* Starts the game running.
*/
public void startGame() {
/*
* Initialize everything we're going to be using.
*/
loadHighScore();
this.random = new Random();
this.snake = new LinkedList<>();
this.directions = new LinkedList<>();
this.logicTimer = new Clock(9.0f);
this.isNewGame = true;
//Set the timer to paused initially.
logicTimer.setPaused(true);
/*
* This is the game loop. It will update and render the game and will
* continue to run until the game window is closed.
*/
while(true) {
//Get the current frame's start time.
long start = System.nanoTime();
//Update the logic timer.
logicTimer.update();
/*
* If a cycle has elapsed on the logic timer, then update the game.
*/
if(logicTimer.hasElapsedCycle()) {
updateGame();
}
//Repaint the board and side panel with the new content.
board.repaint();
side.repaint();
/*
* Calculate the delta time between since the start of the frame
* and sleep for the excess time to cap the frame rate. While not
* incredibly accurate, it is sufficient for our purposes.
*/
long delta = (System.nanoTime() - start) / 1000000L;
if(delta < FRAME_TIME) {
try {
Thread.sleep(FRAME_TIME - delta);
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
/**
* Updates the game's logic.
*/
private void updateGame() {
/*
* Gets the type of tile that the head of the snake collided with. If
* the snake hit a wall, SnakeBody will be returned, as both conditions
* are handled identically.
*/
TileType collision = updateSnake();
/*
* Here we handle the different possible collisions.
*
* Fruit: If we collided with a fruit, we increment the number of
* fruits that we've eaten, update the score, and spawn a new fruit.
*
* SnakeBody: If we collided with our tail (or a wall), we flag that
* the game is over and pause the game.
*
* If no collision occurred, we simply decrement the number of points
* that the next fruit will give us if it's high enough. This adds a
* bit of skill to the game as collecting fruits more quickly will
* yield a higher score.
*/
if(collision == TileType.Fruit) {
fruitsEaten++;
score += nextFruitScore;
spawnFruit();
} else if(collision == TileType.SnakeBody) {
isGameOver = true;
logicTimer.setPaused(true);
} else if(nextFruitScore > 10) {
nextFruitScore--;
}
if ( score >= highscore){
highscore = score;
setHighScore();
}
}
/**
* Updates the snake's position and size.
* @return Tile tile that the head moved into.
*/
private TileType updateSnake() {
/*
* Here we peek at the next direction rather than polling it. While
* not game breaking, polling the direction here causes a small bug
* where the snake's direction will change after a game over (though
* it will not move).
*/
Direction direction = directions.peekFirst();
/*
* Here we calculate the new point that the snake's head will be at
* after the update.
*/
Point head = new Point(snake.peekFirst());
switch(direction) {
case North:
head.y--;
break;
case South:
head.y++;
break;
case West:
head.x--;
break;
case East:
head.x++;
break;
}
/*
* If the snake has moved out of bounds ('hit' a wall), we can just
* return that it's collided with itself, as both cases are handled
* identically.
*/
if(head.x < 0 || head.x >= BoardPanel.COL_COUNT || head.y < 0 || head.y >= BoardPanel.ROW_COUNT) {
return TileType.SnakeBody; //Pretend we collided with our body.
}
/*
* Here we get the tile that was located at the new head position and
* remove the tail from of the snake and the board if the snake is
* long enough, and the tile it moved onto is not a fruit.
*
* If the tail was removed, we need to retrieve the old tile again
* incase the tile we hit was the tail piece that was just removed
* to prevent a false game over.
*/
TileType old = board.getTile(head.x, head.y);
if(old != TileType.Fruit && snake.size() > MIN_SNAKE_LENGTH) {
Point tail = snake.removeLast();
board.setTile(tail, null);
old = board.getTile(head.x, head.y);
}
/*
* Update the snake's position on the board if we didn't collide with
* our tail:
*
* 1. Set the old head position to a body tile.
* 2. Add the new head to the snake.
* 3. Set the new head position to a head tile.
*
* If more than one direction is in the queue, poll it to read new
* input.
*/
if(old != TileType.SnakeBody) {
board.setTile(snake.peekFirst(), TileType.SnakeBody);
snake.push(head);
board.setTile(head, TileType.SnakeHead);
if(directions.size() > 1) {
directions.poll();
}
}
return old;
}
/**
* Resets the game's variables to their default states and starts a new game.
*/
private void resetGame() {
/*
* Reset the score statistics. (Note that nextFruitPoints is reset in
* the spawnFruit function later on).
*/
this.score = 0;
this.fruitsEaten = 0;
/*
* Reset both the new game and game over flags.
*/
this.isNewGame = false;
this.isGameOver = false;
/*
* Create the head at the center of the board.
*/
Point head = new Point(BoardPanel.COL_COUNT / 2, BoardPanel.ROW_COUNT / 2);
/*
* Clear the snake list and add the head.
*/
snake.clear();
snake.add(head);
/*
* Clear the board and add the head.
*/
board.clearBoard();
board.setTile(head, TileType.SnakeHead);
/*
* Clear the directions and add north as the
* default direction.
*/
directions.clear();
directions.add(Direction.North);
/*
* Reset the logic timer.
*/
logicTimer.reset();
/*
* Spawn a new fruit.
*/
spawnFruit();
}
/**
* Gets the flag that indicates whether or not we're playing a new game.
* @return The new game flag.
*/
public boolean isNewGame() {
return isNewGame;
}
/**
* Gets the flag that indicates whether or not the game is over.
* @return The game over flag.
*/
public boolean isGameOver() {
return isGameOver;
}
/**
* Gets the flag that indicates whether or not the game is paused.
* @return The paused flag.
*/
public boolean isPaused() {
return isPaused;
}
/**
* Spawns a new fruit onto the board.
*/
private void spawnFruit() {
//Reset the score for this fruit to 100.
this.nextFruitScore = 100;
/*
* Get a random index based on the number of free spaces left on the board.
*/
int index = random.nextInt(BoardPanel.COL_COUNT * BoardPanel.ROW_COUNT - snake.size());
/*
* While we could just as easily choose a random index on the board
* and check it if it's free until we find an empty one, that method
* tends to hang if the snake becomes very large.
*
* This method simply loops through until it finds the nth free index
* and selects uses that. This means that the game will be able to
* locate an index at a relatively constant rate regardless of the
* size of the snake.
*/
int freeFound = -1;
for(int x = 0; x < BoardPanel.COL_COUNT; x++) {
for(int y = 0; y < BoardPanel.ROW_COUNT; y++) {
TileType type = board.getTile(x, y);
if(type == null || type == TileType.Fruit) {
if(++freeFound == index) {
board.setTile(x, y, TileType.Fruit);
break;
}
}
}
}
}
/**
* Gets the current score.
* @return The score.
*/
public int getScore() {
return score;
}
/**
* Gets the number of fruits eaten.
* @return The fruits eaten.
*/
public int getFruitsEaten() {
return fruitsEaten;
}
/**
* Gets the next fruit score.
* @return The next fruit score.
*/
public int getNextFruitScore() {
return nextFruitScore;
}
/**
* Gets the current direction of the snake.
* @return The current direction.
*/
public Direction getDirection() {
return directions.peek();
}
public int getHighScore(){
return highscore;
}
/**
* Entry point of the program.
* @param args Unused.
*/
public static void main(String[] args) {
SnakeGamePanel Snake = new SnakeGamePanel(myFrame);
Snake.startGame();
}
}
BoardPanel:
package gamesUI;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import javax.swing.JPanel;
/**
* The {@code BoardPanel} class is responsible for managing and displaying the
* contents of the game board.
* @author Brendan Jones
*
*/
public class BoardPanel extends JPanel {
/**
* Serial Version UID.
*/
private static final long serialVersionUID = -1102632585936750607L;
/**
* The number of columns on the board. (Should be odd so we can start in
* the center).
*/
public static final int COL_COUNT = 25;
/**
* The number of rows on the board. (Should be odd so we can start in
* the center).
*/
public static final int ROW_COUNT = 25;
/**
* The size of each tile in pixels.
*/
public static final int TILE_SIZE = 20;
/**
* The number of pixels to offset the eyes from the sides.
*/
private static final int EYE_LARGE_INSET = TILE_SIZE / 3;
/**
* The number of pixels to offset the eyes from the front.
*/
private static final int EYE_SMALL_INSET = TILE_SIZE / 6;
/**
* The length of the eyes from the base (small inset).
*/
private static final int EYE_LENGTH = TILE_SIZE / 5;
/**
* The font to draw the text with.
*/
private static final Font FONT = new Font("Tahoma", Font.BOLD, 25);
/**
* The SnakeGame instance.
*/
private SnakeGamePanel game;
/**
* The array of tiles that make up this board.
*/
private TileType[] tiles;
/**
* Creates a new BoardPanel instance.
* @param game The SnakeGame instance.
*/
public BoardPanel(SnakeGamePanel game) {
this.game = game;
this.tiles = new TileType[ROW_COUNT * COL_COUNT];
setPreferredSize(new Dimension(COL_COUNT * TILE_SIZE, ROW_COUNT * TILE_SIZE));
setBackground(Color.BLACK);
setLayout(null);
}
/**
* Clears all of the tiles on the board and sets their values to null.
*/
public void clearBoard() {
for(int i = 0; i < tiles.length; i++) {
tiles[i] = null;
}
}
/**
* Sets the tile at the desired coordinate.
* @param point The coordinate of the tile.
* @param type The type to set the tile to.
*/
public void setTile(Point point, TileType type) {
setTile(point.x, point.y, type);
}
/**
* Sets the tile at the desired coordinate.
* @param x The x coordinate of the tile.
* @param y The y coordinate of the tile.
* @param type The type to set the tile to.
*/
public void setTile(int x, int y, TileType type) {
tiles[y * ROW_COUNT + x] = type;
}
/**
* Gets the tile at the desired coordinate.
* @param x The x coordinate of the tile.
* @param y The y coordinate of the tile.
* @return
*/
public TileType getTile(int x, int y) {
return tiles[y * ROW_COUNT + x];
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
/*
* Loop through each tile on the board and draw it if it
* is not null.
*/
for(int x = 0; x < COL_COUNT; x++) {
for(int y = 0; y < ROW_COUNT; y++) {
TileType type = getTile(x, y);
if(type != null) {
drawTile(x * TILE_SIZE, y * TILE_SIZE, type, g);
}
}
}
/*
* Draw the grid on the board. This makes it easier to see exactly
* where we in relation to the fruit.
*
* The panel is one pixel too small to draw the bottom and right
* outlines, so we outline the board with a rectangle separately.
*/
g.setColor(Color.DARK_GRAY);
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
for(int x = 0; x < COL_COUNT; x++) {
for(int y = 0; y < ROW_COUNT; y++) {
g.drawLine(x * TILE_SIZE, 0, x * TILE_SIZE, getHeight());
g.drawLine(0, y * TILE_SIZE, getWidth(), y * TILE_SIZE);
}
}
/*
* Show a message on the screen based on the current game state.
*/
if(game.isGameOver() || game.isNewGame() || game.isPaused()) {
g.setColor(Color.WHITE);
/*
* Get the center coordinates of the board.
*/
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
/*
* Allocate the messages for and set their values based on the game
* state.
*/
String largeMessage = null;
String smallMessage = null;
if(game.isNewGame()) {
largeMessage = "Snake Game!";
smallMessage = "Press Enter to Start";
} else if(game.isGameOver()) {
largeMessage = "Game Over! BOOHOOO";
smallMessage = "Press Enter to Restart";
} else if(game.isPaused()) {
largeMessage = "Paused";
smallMessage = "Press P to Resume";
}
/*
* Set the message font and draw the messages in the center of the board.
*/
g.setFont(FONT);
g.drawString(largeMessage, centerX - g.getFontMetrics().stringWidth(largeMessage) / 2, centerY - 50);
g.drawString(smallMessage, centerX - g.getFontMetrics().stringWidth(smallMessage) / 2, centerY + 50);
}
}
/**
* Draws a tile onto the board.
* @param x The x coordinate of the tile (in pixels).
* @param y The y coordinate of the tile (in pixels).
* @param type The type of tile to draw.
* @param g The graphics object to draw to.
*/
private void drawTile(int x, int y, TileType type, Graphics g) {
/*
* Because each type of tile is drawn differently, it's easiest
* to just run through a switch statement rather than come up with some
* overly complex code to handle everything.
*/
switch(type) {
/*
* A fruit is depicted as a small red circle that with a bit of padding
* on each side.
*/
case Fruit:
g.setColor(Color.RED);
g.fillOval(x + 2, y + 2, TILE_SIZE - 4, TILE_SIZE - 4);
break;
/*
* The snake body is depicted as a green square that takes up the
* entire tile.
*/
case SnakeBody:
g.setColor(Color.GREEN);
g.fillRect(x, y, TILE_SIZE, TILE_SIZE);
break;
/*
* The snake head is depicted similarly to the body, but with two
* lines (representing eyes) that indicate it's direction.
*/
case SnakeHead:
//Fill the tile in with green.
g.setColor(Color.GREEN);
g.fillRect(x, y, TILE_SIZE, TILE_SIZE);
//Set the color to black so that we can start drawing the eyes.
g.setColor(Color.BLACK);
/*
* The eyes will always 'face' the direction that the snake is
* moving.
*
* Vertical lines indicate that it's facing North or South, and
* Horizontal lines indicate that it's facing East or West.
*
* Additionally, the eyes will be closer to whichever edge it's
* facing.
*
* Drawing the eyes is fairly simple, but is a bit difficult to
* explain. The basic process is this:
*
* First, we add (or subtract) EYE_SMALL_INSET to or from the
* side of the tile representing the direction we're facing. This
* will be constant for both eyes, and is represented by the
* variable 'baseX' or 'baseY' (depending on orientation).
*
* Next, we add (or subtract) EYE_LARGE_INSET to and from the two
* neighboring directions (Example; East and West if we're facing
* north).
*
* Finally, we draw a line from the base offset that is EYE_LENGTH
* pixels in length at whatever the offset is from the neighboring
* directions.
*
*/
switch(game.getDirection()) {
case North: {
int baseY = y + EYE_SMALL_INSET;
g.drawLine(x + EYE_LARGE_INSET, baseY, x + EYE_LARGE_INSET, baseY + EYE_LENGTH);
g.drawLine(x + TILE_SIZE - EYE_LARGE_INSET, baseY, x + TILE_SIZE - EYE_LARGE_INSET, baseY + EYE_LENGTH);
break;
}
case South: {
int baseY = y + TILE_SIZE - EYE_SMALL_INSET;
g.drawLine(x + EYE_LARGE_INSET, baseY, x + EYE_LARGE_INSET, baseY - EYE_LENGTH);
g.drawLine(x + TILE_SIZE - EYE_LARGE_INSET, baseY, x + TILE_SIZE - EYE_LARGE_INSET, baseY - EYE_LENGTH);
break;
}
case West: {
int baseX = x + EYE_SMALL_INSET;
g.drawLine(baseX, y + EYE_LARGE_INSET, baseX + EYE_LENGTH, y + EYE_LARGE_INSET);
g.drawLine(baseX, y + TILE_SIZE - EYE_LARGE_INSET, baseX + EYE_LENGTH, y + TILE_SIZE - EYE_LARGE_INSET);
break;
}
case East: {
int baseX = x + TILE_SIZE - EYE_SMALL_INSET;
g.drawLine(baseX, y + EYE_LARGE_INSET, baseX - EYE_LENGTH, y + EYE_LARGE_INSET);
g.drawLine(baseX, y + TILE_SIZE - EYE_LARGE_INSET, baseX - EYE_LENGTH, y + TILE_SIZE - EYE_LARGE_INSET);
break;
}
}
break;
}
}
}
侧面板:
package Original;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JPanel;
/**
* The {@code SidePanel} class is responsible for displaying statistics and
* controls to the player.
* @author Brendan Jones
*
*/
public class SidePanel extends JPanel {
/**
* Serial Version UID.
*/
private static final long serialVersionUID = -40557434900946408L;
/**
* The large font to draw with.
*/
private static final Font LARGE_FONT = new Font("Tahoma", Font.BOLD, 20);
/**
* The medium font to draw with.
*/
private static final Font MEDIUM_FONT = new Font("Tahoma", Font.BOLD, 16);
/**
* The small font to draw with.
*/
private static final Font SMALL_FONT = new Font("Tahoma", Font.BOLD, 12);
/**
* The SnakeGame instance.
*/
private SnakeGame game;
/**
* Creates a new SidePanel instance.
* @param game The SnakeGame instance.
*/
public SidePanel(SnakeGame game) {
this.game = game;
setPreferredSize(new Dimension(300, BoardPanel.ROW_COUNT * BoardPanel.TILE_SIZE));
setBackground(Color.BLACK);
}
private static final int STATISTICS_OFFSET = 150;
private static final int CONTROLS_OFFSET = 320;
private static final int MESSAGE_STRIDE = 30;
private static final int SMALL_OFFSET = 30;
private static final int LARGE_OFFSET = 50;
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
/*
* Set the color to draw the font in to white.
*/
g.setColor(Color.WHITE);
/*
* Draw the game name onto the window.
*/
g.setFont(LARGE_FONT);
g.drawString("Snake Game", getWidth() / 2 - g.getFontMetrics().stringWidth("Snake Game") / 2, 50);
/*
* Draw the categories onto the window.
*/
g.setFont(MEDIUM_FONT);
g.drawString("Statistics", SMALL_OFFSET, STATISTICS_OFFSET);
g.drawString("Controls", SMALL_OFFSET, CONTROLS_OFFSET);
/*
* Draw the category content onto the window.
*/
g.setFont(SMALL_FONT);
//Draw the content for the statistics category.
int drawY = STATISTICS_OFFSET;
g.drawString("Total Score: " + game.getScore(), LARGE_OFFSET, drawY += MESSAGE_STRIDE);
g.drawString("Fruit Eaten: " + game.getFruitsEaten(), LARGE_OFFSET, drawY += MESSAGE_STRIDE);
g.drawString("Fruit Score: " + game.getNextFruitScore(), LARGE_OFFSET, drawY += MESSAGE_STRIDE);
//Draw the content for the controls category.
drawY = CONTROLS_OFFSET;
g.drawString("Move Up: W / Up Arrowkey", LARGE_OFFSET, drawY += MESSAGE_STRIDE);
g.drawString("Move Down: S / Down Arrowkey", LARGE_OFFSET, drawY += MESSAGE_STRIDE);
g.drawString("Move Left: A / Left Arrowkey", LARGE_OFFSET, drawY += MESSAGE_STRIDE);
g.drawString("Move Right: D / Right Arrowkey", LARGE_OFFSET, drawY += MESSAGE_STRIDE);
g.drawString("Pause Game: P", LARGE_OFFSET, drawY += MESSAGE_STRIDE);
}
}