I wanted to create a caterpillar game using Java Frame. It basically has two players trying to occupy a square to increase their scores. I've been using two classes:
the caterpillar class
package caterpillar;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
class Caterpillar {
private Color color;
private Point position;
private char direction;
private Queue<Point> body;
private Queue<Character> commands;
private int score;
public Caterpillar (Color c, Point p){
color = c;
direction = 'E';
body = new LinkedList<Point>();
score = 0;
commands = new LinkedList<Character>();
for (int i = 0; i < 10; i++){
position= new Point(p.x + i, p.y);
body.offer(position);
}
}
public void setDirection(char direction){
commands.offer(new Character(direction));
}
public void move(CaterpillarGame game){
if(commands.size()>0){
Character c = (Character)commands.peek();
commands.poll();
direction = c.charValue();
if(direction == 'Z')
return;
}
Point np = newPosition();
if(game.canMove(np)){
body.poll();
body.offer(np);
position = np;
}
score+=game.squareScore(np);
}
private Point newPosition(){
int x = position.x;
int y = position.y;
if(direction == 'E')
x++;
else if(direction == 'W')
x--;
else if(direction == 'N')
y--;
else if(direction == 'S')
y++;
return new Point(x, y);
}
public boolean inPosition(Point np){ //check if position has alredy been occupied
Iterator <Point>it = body.iterator();
while(it.hasNext()){
Point location = it.next();
if(np.equals(location))
return true;
}
return false;
}
public int getScore(){
return score;
}
public void paint(Graphics g){
g.setColor(color);
Iterator <Point>it = body.iterator();
while(it.hasNext()){
Point p = it.next();
g.fillOval(5 + CaterpillarGame.SegmentSize * p.x,
15 + CaterpillarGame.SegmentSize * p.y,
CaterpillarGame.SegmentSize,
CaterpillarGame.SegmentSize);
}
}
}
the game class:
package caterpillar;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Random;
import javax.swing.JLabel;
public class CaterpillarGame extends Frame{
final static int BoardWidth = 60;
final static int BoardHeight = 40;
final static int SegmentSize = 10;
private Caterpillar playerOne;
private Caterpillar playerTwo;
private Point square;
private int number; //points the players will get if occupy the square
private Random generator;
private JLabel score1, score2;// scores of two players
public static void main(String[] args){
CaterpillarGame game= new CaterpillarGame();
game.run();
}
public CaterpillarGame(){
setBackground(Color.GREEN);
setVisible(true);
setSize((BoardWidth+1)*SegmentSize, BoardHeight*SegmentSize + 30);
addKeyListener(new KeyReader());
playerOne = new Caterpillar(Color.blue, new Point(20, 10));
playerTwo = new Caterpillar(Color.red, new Point(20, 30));
addWindowListener(new CloseQuit());
generator = new Random();
number = 1;
score1 = new JLabel("Player One: "+playerOne.getScore());
score2 = new JLabel("Player Two: "+playerTwo.getScore());
this.add(score1);
this.add(score2);
square = new Point(newSquare());
}
public void run(){
while(true){
movePieces();
repaint();
try{
Thread.sleep(100);
}catch(Exception e){}
}
}
public void paint(Graphics g){
playerOne.paint(g);
playerTwo.paint(g);
g.setColor(Color.white);
g.fillRect(square.x, square.y, 10,10); //line 62, exception thrown
g.setColor(Color.BLACK);
g.drawString(Integer.toString(number), 10, 10);
}
public void movePieces(){
playerOne.move(this);
playerTwo.move(this);
}
public boolean canMove(Point np){
int x = np.x;
int y = np.y;
if((x<=0)||(y<=0))
return false;
if((x>=BoardWidth)||(y>=BoardHeight))
return false;
if(playerOne.inPosition(np))
return false;
if(playerTwo.inPosition(np))
return false;
return true;
}
private class KeyReader extends KeyAdapter{
public void keyPressed(KeyEvent e){
char c = e.getKeyChar();
switch(c){
case 'q': playerOne.setDirection('Z');
break;
case 'a': playerOne.setDirection('W');
break;
case 'd': playerOne.setDirection('E');
break;
case 'w': playerOne.setDirection('N');
break;
case 's': playerOne.setDirection('S');
break;
case 'p': playerTwo.setDirection('Z');
break;
case 'j': playerTwo.setDirection('W');
break;
case 'l': playerTwo.setDirection('E');
break;
case 'i': playerTwo.setDirection('N');
break;
case 'k': playerTwo.setDirection('S');
break;
}
}
}
public Point newSquare(){
Point p = new Point(generator.nextInt(51), generator.nextInt(31));
while(playerOne.inPosition(p)||playerTwo.inPosition(p)){
p = new Point(generator.nextInt(51), generator.nextInt(31));
}
number++;
return square = p;
}
public int squareScore(Point p){
if(p.equals(square)){
newSquare();
return number;
}
return 0;
}
private class CloseQuit extends WindowAdapter{
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
}
this is what i have so far, but i got several problems when i ran the program:
the JLabels, square, and string didn't show up
it kept throwing java.lang.NullPointerException
how do i have the program stopped when the score of one player reaches a certain number?
how to check if a caterpillar touches the square?
Thanks in advance.
the JLabels, square, and string didn't show up
They are, you're just screwing with the paint process so badly that you're preventing them from been painted. Also, I "believe" that java.awt.Frame uses a BorderLayout.
This is one of the reasons we generally discourage people from overriding paint, it's far to easy to break the paint chain
Add a call to super.paint before you perform any custom painting.
#Override
public void paint(Graphics g) {
super.paint(g);
I'd prefer that you used paintComponent from a JComponent based class and add that object to your frame, but you seem to have restrictions from doing so...
Also, change the layout manager to something like FlowLayout to get both labels on the screen.
See Painting in AWT and Swing and Laying Out Components Within a Container for more details
it kept throwing java.lang.NullPointerException
This seems to be a race condition. Essentially, you are calling setVisible on the frame BEFORE you've finished initialising the requirements of the UI, which is causing paint to be called BEFORE the frame is fully initialized.
Call setVisible last. Better yet, don't call setVisible from within the constructor...
how do i have the program stopped when the score of one player reaches a certain number?
... In your "game loop" you need to be checking that state of the score and breaking out of the "game loop" when the required state is meet...
how to check if a caterpillar touches the square?
That's a much more complicated question. Essentially you could use the interests or contains method of a Rectangle (or other Shape object). You know where the Point of the square and "segments" of the Caterpillar are. You know the size of the square and the "segments".
You need to compare each of the segments to see if they intersect the are of the square. Take a closer look at java.awt.Rectangle for more details
Related
My restart button of the game does not work and it multiples when it is clicked. I do not understand Java perfectly I am considering myself good.
Main of the game
package snake_game;
public class snake {
public static void main(String arg[]) {
new GameFrame();
// is exacly the same as frame f = new frame();
// this is shorter and does the same job
}
}
GamePanel
package snake_game;
// import java.awt.event.ActionEvent;
// import java.awt.event.ActionListener;
// import java.awt.Graphics;
// import java.awt.event.KeyAdapter;
// import java.awt.event.KeyEvent;
// or I could write simply
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements ActionListener {
// panal dimentions
static final int SCREEN_WIDTH = 600;
static final int SCREEN_HEIGHT = 600;
// panal dimentions
// size
static final int UNIT_SIZE = 25;
// size to make 600 * 600 = 1200 px equel between 25 px
static final int GAME_UNITS = (SCREEN_WIDTH * SCREEN_HEIGHT) / UNIT_SIZE;
// size
// delay how fast the game will be
static final int DELAY = 75;
// delay
// dimentions
final int x[] = new int[GAME_UNITS];
final int y[] = new int[GAME_UNITS];
// dimentions
// snake
int bodyParts = 6;
// snake
// apple
int appleEaten;
int appleX;
int appleY;
// apple
char direction = 'R';
boolean running = false;
Timer timer;
Random random;
GamePanel game;
JButton resetButton;
GamePanel() {
random = new Random();
this.setPreferredSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT));
this.setBackground(Color.black);
this.setFocusable(true);
this.addKeyListener(new MyKeyAdapter());
startGame();
// when we want to make the program to continie we must say what the programm
// must execute next
}
public void startGame() {
newApple();
running = true;
timer = new Timer(DELAY, this);
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
draw(g);
}
public void draw(Graphics g) {
if (running) {
for (int i = 0; i < SCREEN_HEIGHT / UNIT_SIZE; i++) {
g.drawLine(i * UNIT_SIZE, 0, i * UNIT_SIZE, SCREEN_HEIGHT);
g.drawLine(0, i * UNIT_SIZE, i * SCREEN_WIDTH, i * UNIT_SIZE);
}
g.setColor(Color.red);
g.fillOval(appleX, appleY, UNIT_SIZE, UNIT_SIZE);
for (int i = 0; i < bodyParts; i++) {
if (i == 0) {
g.setColor(Color.green);
g.fillRect(x[i], y[i], UNIT_SIZE, UNIT_SIZE);
} else {
g.setColor(new Color(45, 180, 0));
// random color
g.setColor(new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255)));
// random color
g.fillRect(x[i], y[i], UNIT_SIZE, UNIT_SIZE);
}
}
g.setColor(Color.red);
g.setFont(new Font("Ink Free", Font.BOLD, 30));
FontMetrics metrics = getFontMetrics(g.getFont());
g.drawString("SCORE:" + appleEaten, (SCREEN_WIDTH - metrics.stringWidth("SCORE:" + appleEaten)) / 2,
g.getFont().getSize());
} else {
gameOver(g);
}
}
public void newApple() {
appleX = random.nextInt((int) (SCREEN_WIDTH / UNIT_SIZE)) * UNIT_SIZE;
appleY = random.nextInt((int) (SCREEN_HEIGHT / UNIT_SIZE)) * UNIT_SIZE;
}
public void move() {
for (int i = bodyParts; i > 0; i--) {
x[i] = x[i - 1];
y[i] = y[i - 1];
}
switch (direction) {
case 'U':
y[0] = y[0] - UNIT_SIZE;
break;
case 'D':
y[0] = y[0] + UNIT_SIZE;
break;
case 'L':
x[0] = x[0] - UNIT_SIZE;
break;
case 'R':
x[0] = x[0] + UNIT_SIZE;
break;
}
}
public void checkApple() {
if ((x[0] == appleX) && (y[0] == appleY)) {
bodyParts++;
appleEaten++;
newApple();
}
}
public void checkCollisions() {
// check if head collides with body
for (int i = bodyParts; i > 0; i--) {
if ((x[0] == x[i]) && (y[0] == y[i])) {
running = false;
}
}
// check if head touches left border
if (x[0] < 0) {
running = false;
}
// check if head touches right border
if (x[0] > SCREEN_WIDTH) {
running = false;
}
// check if head touches top border
if (y[0] < 0) {
running = false;
}
// check if head touches bottom border
if (y[0] > SCREEN_HEIGHT) {
running = false;
}
if (!running) {
timer.stop();
}
}
public void gameOver(Graphics g) {
// score
g.setColor(Color.red);
g.setFont(new Font("Ink Free", Font.BOLD, 30));
FontMetrics metrics1 = getFontMetrics(g.getFont());
g.drawString("SCORE:" + appleEaten, (SCREEN_WIDTH - metrics1.stringWidth("SCORE:" + appleEaten)) / 2,
g.getFont().getSize());
// game over text
g.setColor(Color.red);
g.setFont(new Font("Ink Free", Font.BOLD, 75));
FontMetrics metrics2 = getFontMetrics(g.getFont());
g.drawString("Game Over", (SCREEN_WIDTH - metrics2.stringWidth("Game Over")) / 2, SCREEN_HEIGHT / 2);
// restart button
resetButton = new JButton();
resetButton.setText("Restart");
resetButton.setSize(100, 50);
resetButton.setLocation(150, 150);
resetButton.addActionListener(this);
game = new GamePanel();
this.add(resetButton);
this.add(game);
this.setVisible(true);
// restart button
}
#Override
public void actionPerformed(ActionEvent e) {
if (running) {
move();
checkApple();
checkCollisions();
}
repaint();
// restart button
if (e.getSource() == resetButton) {
this.remove(game);
game = new GamePanel();
this.add(game);
resetButton.setVisible(false);
SwingUtilities.updateComponentTreeUI(this);
// restart button
}
}
public class MyKeyAdapter 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;
}
}
}
}
GameFrame
package snake_game;
import javax.swing.JFrame;
public class GameFrame extends JFrame {
GameFrame() {
GamePanel panel = new GamePanel();
this.add(panel);
this.setTitle("Snake");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.pack();
this.setVisible(true);
this.setLocationRelativeTo(null);
this.setUndecorated(false);
}
}
Introduction
I copied your code into my Eclipse IDE and ran it as is. I received the following runtime error.
Exception in thread "main" java.awt.IllegalComponentStateException: The frame is displayable.
at java.desktop/java.awt.Frame.setUndecorated(Frame.java:926)
at com.ggl.testing.SnakeGame$GameFrame.<init>(SnakeGame.java:41)
at com.ggl.testing.SnakeGame.main(SnakeGame.java:24)
Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section. Pay close attention to the Concurrency in Swing section.
I've been writing Swing code for over 10 years, and I have the Oracle website bookmarked in my browser. I still look up how to use certain components to make sure I'm using them correctly.
The first thing I did was to slow down your snake so I could test the game. I changed the delay of 75 to a delay of 750. Here's a screenshot of your current GUI.
Looking over your code, you extend a JFrame. You don't need to extend a JFrame. You're not changing any JFrame functionality. It's much simpler to use a JFrame. This leads to one of my Java rules.
Don't extend a Swing component, or any Java class, unless you intend
to override one or more of the class methods.
You do extend a JPanel. That's fine because you override the paintComponent method.
Finally, your JPanel class is doing too much work. You also make heavy use of static fields. Even though you'll only create one JPanel, it's a good habit to treat every class as if you will create multiple instances of the class. This creates fewer problems for yourself down the road.
You have the right idea, creating three classes.
So let's rework your code, using some basic patterns and Swing best practices. At this time, I don't know how many classes we'll wind up creating.
Explanation
When I write a Swing GUI, I use the model–view–controller (MVC) pattern. The name implies that you create a model first, then the view, then the controller(s).
An application model consists of one or more plain Java getter/setter classes.
A view consists of a JFrame, one or more JPanels, and any other necessary Swing components.
The controller consists of one or more Actions or ActionListeners. In Swing, there's usually not one controller to "rule them all".
To summarize:
The view reads information from the model
The view does not update the model
The controllers update the model and repaint/revalidate your view.
Model
I created two model classes, SnakeModel and Snake.
The SnakeModel class is a plain Java getter/setter class that holds one Snake instance, the apple eaten count, the apple location, the size of the game area, and a couple of booleans. One boolean indicates whether or not the game loop is running and the other boolean indicates whether or not the game is over.
The game area uses a java.awt.Dimension to hold the width and height of the game area. The width and the height do not have to have the same value. The game area can be rectangular.
The game area is measured in units. In the view, I convert the units into pixels. That's the opposite of what you did. If you want to change the game area, all you have to do is change the dimensions in the SnakeModel class. Everything in the view is based on the game area dimension.
The Snake class holds a java.util.List of java.awt.Point objects and a char direction. A java.awt.Point object holds an X and Y value. Since we're dealing with objects, rather than int values, we have to be careful to clone the object when we want a new Point.
View
All Swing applications must start with a call to the SwingUtilities invokeLater method. This method ensures that the Swing components are created and executed on the Event Dispatch Thread.
I created a JFrame, a drawing JPanel, and a separate button JPanel. Generally, it's not a good idea to add Swing components to a drawing JPanel. By creating a separate button JPanel, I get the added feature of a "Start Game" button at almost no extra cost. The button is disabled while the game is running.
The JFrame methods must be called in a specific order. The setVisible method must be called last.
I made the drawing JPanel more complicated by adding a separate area for the score.
I made the drawing JPanel less complicated by only drawing the state of the game, based on the application model. Period. Nothing else.
I limited the random colors to the white end of the color spectrum to maintain the contrast between the snake and the drawing JPanel background.
I used key bindings instead of a key listener. One advantage is that the drawing JPanel doesn't have to be in focus. Since I have a separate button JPanel, the drawing JPanel doesn't have focus.
Another advantage is that I can add the WASD keys with four lines of additional code.
One disadvantage is that the key bindings code looks more complicated than a key listener. Once you've coded a few key bindings, you'll appreciate the advantages.
Controller
I created three controller classes, ButtonListener, TimerListener, and MovementAction.
The ButtonListener class implements ActionListener. The ButtonListener class initializes the game model and restarts the timer.
The TimerListener class implements ActionListener. The TimerListener class is the game loop. This class moves the snake, checks to see if the apple is eaten, checks to see if the snake has moved outside the game area or touched itself, and repaints the drawing JPanel. I used your code as a model for the code in this class.
The MovementAction class extends AbstractAction. The AbstractAction class implements Action. This class changes the direction of the snake, based on the key presses.
I create four instances of the MovementAction class, one for each direction. This makes the actionPerformed method of the class much simpler.
Images
Here's what the revised GUI looks like when you start the game.
Here's the revised GUI during the game.
Here's the revised GUI when the game is over.
Code
Here's the complete runnable code. I made all the additional classes inner classes so I could post this code as one block.
You should put the separate classes in separate files.
When setting up a Swing GUI project, I create separate packages for the model, view, and controller. This helps me keep the code organized.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class SnakeGame implements Runnable {
public static void main(String arg[]) {
SwingUtilities.invokeLater(new SnakeGame());
}
private final GamePanel gamePanel;
private final JButton restartButton;
private final SnakeModel model;
public SnakeGame() {
this.model = new SnakeModel();
this.restartButton = new JButton("Start Game");
this.gamePanel = new GamePanel(model);
}
#Override
public void run() {
JFrame frame = new JFrame("Snake");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(gamePanel, BorderLayout.CENTER);
frame.add(createButtonPanel(), BorderLayout.SOUTH);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel();
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
panel.setBackground(Color.black);
restartButton.addActionListener(new ButtonListener(this, model));
panel.add(restartButton);
return panel;
}
public JButton getRestartButton() {
return restartButton;
}
public void repaint() {
gamePanel.repaint();
}
public class GamePanel extends JPanel {
private static final long serialVersionUID = 1L;
private final int margin, scoreAreaHeight, unitSize;
private final Random random;
private final SnakeModel model;
public GamePanel(SnakeModel model) {
this.model = model;
this.margin = 10;
this.unitSize = 25;
this.scoreAreaHeight = 36 + margin;
this.random = new Random();
this.setBackground(Color.black);
Dimension gameArea = model.getGameArea();
int width = gameArea.width * unitSize + 2 * margin;
int height = gameArea.height * unitSize + 2 * margin + scoreAreaHeight;
this.setPreferredSize(new Dimension(width, height));
setKeyBindings();
}
private void setKeyBindings() {
InputMap inputMap = this.getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = this.getActionMap();
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "down");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "left");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "right");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "up");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), "down");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "left");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "right");
actionMap.put("up", new MovementAction(model, 'U', 'D'));
actionMap.put("down", new MovementAction(model, 'D', 'U'));
actionMap.put("left", new MovementAction(model, 'L', 'R'));
actionMap.put("right", new MovementAction(model, 'R', 'L'));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension gameArea = model.getGameArea();
drawHorizontalGridLines(g, gameArea);
drawVerticalGridLines(g, gameArea);
drawSnake(g);
drawScore(g, gameArea);
if (model.isGameOver) {
drawGameOver(g, gameArea);
} else {
drawApple(g);
}
}
private void drawHorizontalGridLines(Graphics g, Dimension gameArea) {
int y1 = scoreAreaHeight + margin;
int y2 = y1 + gameArea.height * unitSize;
int x = margin;
for (int index = 0; index <= gameArea.width; index++) {
g.drawLine(x, y1, x, y2);
x += unitSize;
}
}
private void drawVerticalGridLines(Graphics g, Dimension gameArea) {
int x1 = margin;
int x2 = x1 + gameArea.width * unitSize;
int y = margin + scoreAreaHeight;
for (int index = 0; index <= gameArea.height; index++) {
g.drawLine(x1, y, x2, y);
y += unitSize;
}
}
private void drawApple(Graphics g) {
// Draw apple
g.setColor(Color.red);
Point point = model.getAppleLocation();
if (point != null) {
int a = point.x * unitSize + margin + 1;
int b = point.y * unitSize + margin + scoreAreaHeight + 1;
g.fillOval(a, b, unitSize - 2, unitSize - 2);
}
}
private void drawScore(Graphics g, Dimension gameArea) {
g.setColor(Color.red);
g.setFont(new Font("Ink Free", Font.BOLD, 36));
FontMetrics metrics = getFontMetrics(g.getFont());
int width = 2 * margin + gameArea.width * unitSize;
String text = "SCORE: " + model.getApplesEaten();
int textWidth = metrics.stringWidth(text);
g.drawString(text, (width - textWidth) / 2, g.getFont().getSize());
}
private void drawSnake(Graphics g) {
// Draw snake
Snake snake = model.getSnake();
List<Point> cells = snake.getCells();
Point cell = cells.get(0);
drawSnakeCell(g, cell, Color.green);
for (int index = 1; index < cells.size(); index++) {
// Color color = new Color(45, 180, 0);
// random color
Color color = new Color(getColorValue(), getColorValue(),
getColorValue());
cell = cells.get(index);
drawSnakeCell(g, cell, color);
}
}
private void drawSnakeCell(Graphics g, Point point, Color color) {
int x = margin + point.x * unitSize;
int y = margin + scoreAreaHeight + point.y * unitSize;
if (point.y >= 0) {
g.setColor(color);
g.fillRect(x, y, unitSize, unitSize);
}
}
private int getColorValue() {
// White has color values of 255
return random.nextInt(64) + 191;
}
private void drawGameOver(Graphics g, Dimension gameArea) {
g.setColor(Color.red);
g.setFont(new Font("Ink Free", Font.BOLD, 72));
FontMetrics metrics = getFontMetrics(g.getFont());
String text = "Game Over";
int textWidth = metrics.stringWidth(text);
g.drawString(text, (getWidth() - textWidth) / 2, getHeight() / 2);
}
}
public class ButtonListener implements ActionListener {
private final int delay;
private final SnakeGame view;
private final SnakeModel model;
private final Timer timer;
public ButtonListener(SnakeGame view, SnakeModel model) {
this.view = view;
this.model = model;
this.delay = 750;
this.timer = new Timer(delay, new TimerListener(view, model));
}
#Override
public void actionPerformed(ActionEvent event) {
JButton button = (JButton) event.getSource();
String text = button.getText();
if (text.equals("Start Game")) {
button.setText("Restart Game");
}
button.setEnabled(false);
model.initialize();
timer.restart();
}
}
public class TimerListener implements ActionListener {
private final SnakeGame view;
private final SnakeModel model;
public TimerListener(SnakeGame view, SnakeModel model) {
this.view = view;
this.model = model;
}
#Override
public void actionPerformed(ActionEvent event) {
moveSnake();
checkApple();
model.checkCollisions();
if (model.isGameOver()) {
Timer timer = (Timer) event.getSource();
timer.stop();
model.setRunning(false);
view.getRestartButton().setEnabled(true);
}
view.repaint();
}
private void moveSnake() {
Snake snake = model.getSnake();
Point head = (Point) snake.getHead().clone();
switch (snake.getDirection()) {
case 'U':
head.y--;
break;
case 'D':
head.y++;
break;
case 'L':
head.x--;
break;
case 'R':
head.x++;
break;
}
snake.removeTail();
snake.addHead(head);
// System.out.println(Arrays.toString(cells.toArray()));
}
private void checkApple() {
Point appleLocation = model.getAppleLocation();
Snake snake = model.getSnake();
Point head = snake.getHead();
Point tail = (Point) snake.getTail().clone();
if (head.x == appleLocation.x && head.y == appleLocation.y) {
model.incrementApplesEaten();
snake.addTail(tail);
model.generateRandomAppleLocation();
}
}
}
public class MovementAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private final char newDirection, oppositeDirection;
private final SnakeModel model;
public MovementAction(SnakeModel model, char newDirection,
char oppositeDirection) {
this.model = model;
this.newDirection = newDirection;
this.oppositeDirection = oppositeDirection;
}
#Override
public void actionPerformed(ActionEvent event) {
if (model.isRunning()) {
Snake snake = model.getSnake();
char direction = snake.getDirection();
if (direction != oppositeDirection && direction != newDirection) {
snake.setDirection(newDirection);
// System.out.println("New direction: " + newDirection);
}
}
}
}
public class SnakeModel {
private boolean isGameOver, isRunning;
private int applesEaten;
private Dimension gameArea;
private Point appleLocation;
private Random random;
private Snake snake;
public SnakeModel() {
this.random = new Random();
this.snake = new Snake();
this.gameArea = new Dimension(24, 24);
}
public void initialize() {
this.isRunning = true;
this.isGameOver = false;
this.snake.initialize();
this.applesEaten = 0;
Point point = generateRandomAppleLocation();
// Make sure first apple isn't under snake
int y = (point.y == 0) ? 1 : point.y;
this.appleLocation = new Point(point.x, y);
}
public void checkCollisions() {
Point head = snake.getHead();
// Check for snake going out of the game area
if (head.x < 0 || head.x > gameArea.width) {
isGameOver = true;
return;
}
if (head.y < 0 || head.y > gameArea.height) {
isGameOver = true;
return;
}
// Check for snake touching itself
List<Point> cells = snake.getCells();
for (int index = 1; index < cells.size(); index++) {
Point cell = cells.get(index);
if (head.x == cell.x && head.y == cell.y) {
isGameOver = true;
return;
}
}
}
public Point generateRandomAppleLocation() {
int x = random.nextInt(gameArea.width);
int y = random.nextInt(gameArea.height);
this.appleLocation = new Point(x, y);
return getAppleLocation();
}
public void incrementApplesEaten() {
this.applesEaten++;
}
public boolean isRunning() {
return isRunning;
}
public void setRunning(boolean isRunning) {
this.isRunning = isRunning;
}
public boolean isGameOver() {
return isGameOver;
}
public void setGameOver(boolean isGameOver) {
this.isGameOver = isGameOver;
}
public Dimension getGameArea() {
return gameArea;
}
public int getApplesEaten() {
return applesEaten;
}
public Point getAppleLocation() {
return appleLocation;
}
public Snake getSnake() {
return snake;
}
}
public class Snake {
private char direction;
private List<Point> cells;
public Snake() {
this.cells = new ArrayList<>();
initialize();
}
public void initialize() {
this.direction = 'R';
cells.clear();
for (int x = 5; x >= 0; x--) {
cells.add(new Point(x, 0));
}
}
public void addHead(Point head) {
cells.add(0, head);
}
public void addTail(Point tail) {
cells.add(tail);
}
public void removeTail() {
cells.remove(cells.size() - 1);
}
public Point getHead() {
return cells.get(0);
}
public Point getTail() {
return cells.get(cells.size() - 1);
}
public char getDirection() {
return direction;
}
public void setDirection(char direction) {
this.direction = direction;
}
public List<Point> getCells() {
return cells;
}
}
}
I've been looking for answers in similar threads here but I can't find out what's wrong with my code.
I'm trying to make an agar.io simulator and the agar object doesn't draw. Food draws but agar doesn't draw regardless of what I do.
Agar class code:
import java.awt.*;
import java.awt.event.*;
public class Agar {
//instance field
public static final int DEFAULT_SIZE = 1000, DEFAULT_X =
ArenaPanel.PANEL_WIDTH/2, DEFAULT_Y = ArenaPanel.PANEL_HEIGHT/2;
private int x, y, size;
private Color clr;
public Agar(Color c) {
x = DEFAULT_X;
y = DEFAULT_Y;
clr = c;
}
public void move() {
//blank for now, not used yet
}
//grows by 10% width
public void grow() {
size += 10;
}
public void draw(Graphics fred) {
fred.setColor(clr);
fred.fillOval(0,0,size,size);
fred.setColor(Color.black);
fred.drawOval(0,0,size,size);
}
}
Panel class code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.ArrayList;
public class ArenaPanel extends JPanel {
//instance field
public static final int PANEL_WIDTH = 1000, PANEL_HEIGHT = 500;
private ArrayList<Food> food;
private Timer foodAdder;
private Agar agar;
public ArenaPanel() {
//agar stuff
agar = new Agar(getRandomColor());
//food stuff
food = new ArrayList<Food>();
//add some initial food
for (int i = 0; i < 50; i++)
addRandomFood();
//"this will last a while"
foodAdder = new Timer(3000, new FoodAdder());
foodAdder.start();
//listeners
addComponentListener(new ResizeListener());
//more basic stuff
setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
setBackground(Color.white);
}
public void paintComponent(Graphics fred) {
super.paintComponent(fred);
agar.draw(fred);
for (int i = 0; i < food.size(); i++)
food.get(i).draw(fred);
}
//put it here so I can use it for both agar and food
private Color getRandomColor() {
int rand = (int)(Math.random()*7);
Color c;
switch (rand) {
case 0:
c = Color.red;
break;
case 1:
c = Color.orange;
break;
case 2:
c = Color.yellow;
break;
case 3:
c = Color.green;
break;
case 4:
c = Color.cyan;
break;
case 5:
c = Color.blue;
break;
default:
c = Color.pink;
}
return c;
}
private void addRandomFood() {
int x = (int)(Math.random()*PANEL_WIDTH);
int y = (int)(Math.random()*PANEL_HEIGHT);
food.add(new Food(x,y,getRandomColor()));
}
private class FoodAdder implements ActionListener {
public void actionPerformed(ActionEvent e) {
addRandomFood();
repaint();
}
}
private class ResizeListener extends ComponentAdapter {
public void componentResized(ComponentEvent e) {
setPreferredSize(getSize());
}
}
}
I tried debugging (placing System.out.println command into draw(), paintComponent(), agar's constructor) and all methods are in fact running properly. So I thought maybe it was just not showing up, but even when I tried changing agar's colour to black square (which should contrast a lot to colourful circular food) located at 0,0 but it still doesn't show.
What could be the problem here?
It has zero size. Call method grow at leas once.
I got this really annoying error. It's really hard to explain, but basically whenever my snake tiles (I'm coding the game "Snake") leaves the screen, I set it so it returns to the same y, but the x as 0, as the x = 0 is the leftmost part of the screen...
So yeah, hard to explain. Here's the full code:
Main Class:
package com.Code0.Snake.Main;
import java.applet.Applet;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.util.LinkedList;
import java.util.Random;
import com.Code0.Snake.Listeners.KeyListenerS;
import com.Code0.Snake.Threads.EventS;
public class MainS extends Applet{
//Defining vars.
public final int BOX_HEIGHT = 15;
public final int BOX_WIDTH = 15;
public final int GRID_HEIGHT = 30;
public final int GRID_WIDTH = 30;
public static final int NORTH = 1;
public static final int SOUTH = 2;
public static final int EAST = 3;
public static final int WEST = 4;
public static final int NONE = 0;
public static int direction;
public LinkedList<Point> snakeParts = new LinkedList<Point>();
public Point itemLocation = new Point();
public Graphics graphics;
int randomX;
int randomY;
int runCount = 0;
EventS events = new EventS(this);
KeyListenerS keylistener = new KeyListenerS(this);
//On Initialization
public void init(){
//Adding "Snakeparts" to the linked list.
snakeParts.add(new Point(10, 10));
snakeParts.add(new Point(10, 11));
snakeParts.add(new Point(10, 12));
this.addKeyListener(keylistener);
}
//Startup paint method.
public void paint(Graphics paramGraphics){
graphics = paramGraphics.create();
this.customInit();
this.setBackground(Color.WHITE);
this.drawAll();
}
public void customInit(){
this.runCount++;
this.setSize(new Dimension(451,451));
if(this.runCount == 2){
Thread eventThread = new Thread(events);
eventThread.start();
}
}
//Used to call all draw methods.
public void drawAll(){
Random random = new Random();
//Calling all draw methods.
this.drawGrid(graphics);
this.drawFruit(graphics,random.nextInt(GRID_WIDTH),random.nextInt(GRID_HEIGHT));
this.drawSnake(graphics);
}
public void drawGrid(Graphics paramGraphics){
paramGraphics.drawRect(0,0,BOX_WIDTH * GRID_WIDTH,BOX_HEIGHT * GRID_HEIGHT);
//Drawing horizontal lines.
for(int x = BOX_WIDTH; x < BOX_WIDTH * GRID_WIDTH; x+=BOX_WIDTH){
paramGraphics.drawLine(x,0,x,BOX_HEIGHT * GRID_HEIGHT);
}
//Drawing vertical lines.
for(int y = BOX_HEIGHT; y < BOX_HEIGHT * GRID_HEIGHT; y+=BOX_HEIGHT){
paramGraphics.drawLine(0, y, GRID_WIDTH * BOX_WIDTH,y);
}
}
public void drawSnake(Graphics paramGraphics){
paramGraphics.setColor(Color.GREEN);
for(Point point : this.snakeParts){
paramGraphics.fillRect(point.x * 15, point.y * 15, BOX_WIDTH, BOX_HEIGHT);
}
paramGraphics.setColor(Color.BLACK);
}
public void drawFruit(Graphics paramGraphics, int paramX, int paramY){
paramGraphics.setColor(Color.RED);
int tempX = paramX * 15;
int tempY = paramY * 15;
paramGraphics.fillOval(tempX, tempY, BOX_WIDTH,BOX_HEIGHT);
paramGraphics.setColor(Color.BLACK);
}
public void drawEmpty(Graphics paramGraphics, int x, int y){
paramGraphics.clearRect(x * 15, y * 15, 15, 15);
this.drawGrid(graphics);
}
}
Event Class (run on seperate thread):
package com.Code0.Snake.Threads;
import java.awt.Point;
import com.Code0.Snake.Main.MainS;
public class EventS implements Runnable{
MainS main;
int CURRENT_DIRECTION;
public EventS(MainS paramMain){
this.main = paramMain;
}
#Override
public void run() {
//Infinite loop checking the game and updating it.
while(true){
main.drawGrid(main.graphics);
Point head;
Point tail;
Point finalPoint = new Point();
switch(MainS.direction){
//If direction = north
case(MainS.NORTH):
head = main.snakeParts.getFirst();
finalPoint = new Point(head.x, head.y - 1);
main.snakeParts.push(finalPoint);
tail = main.snakeParts.getLast();
main.snakeParts.remove(tail);
main.drawSnake(main.graphics);
main.drawEmpty(main.graphics, tail.x, tail.y);
break;
//If direction = south
case(MainS.SOUTH):
head = main.snakeParts.getFirst();
finalPoint = new Point(head.x, head.y + 1);
main.snakeParts.push(finalPoint);
tail = main.snakeParts.getLast();
main.snakeParts.remove(tail);
main.drawSnake(main.graphics);
main.drawEmpty(main.graphics, tail.x , tail.y);
break;
case(MainS.WEST):
head = main.snakeParts.getFirst();
finalPoint = new Point(head.x - 1, head.y);
main.snakeParts.push(finalPoint);
tail = main.snakeParts.getLast();
main.snakeParts.remove(tail);
main.drawSnake(main.graphics);
main.drawEmpty(main.graphics, tail.x , tail.y);
break;
case(MainS.EAST):
head = main.snakeParts.getFirst();
finalPoint = new Point(head.x + 1, head.y);
main.snakeParts.push(finalPoint);
tail = main.snakeParts.getLast();
main.snakeParts.remove(tail);
main.drawSnake(main.graphics);
main.drawEmpty(main.graphics, tail.x , tail.y);
break;
case(MainS.NONE):
break;
}
if(finalPoint.x > main.GRID_WIDTH){
int totalSnakeParts = main.snakeParts.size();
main.snakeParts.clear();
for(int i = totalSnakeParts; i > 0; i--){
Point tempPoint = new Point(i - 2, finalPoint.y);
main.snakeParts.add(tempPoint);
main.drawGrid(main.graphics);
System.out.println(tempPoint);
}
main.drawSnake(main.graphics);
}
try {
Thread.currentThread().sleep((long)100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
KeyListener Class:
package com.Code0.Snake.Listeners;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import com.Code0.Snake.Main.MainS;
public class KeyListenerS implements KeyListener{
MainS main;
public KeyListenerS(MainS paramMain){
this.main = paramMain;
}
#Override
public void keyPressed(KeyEvent event) {
if(event.getKeyCode() == KeyEvent.VK_UP){
if(main.direction == main.SOUTH){
return;
}
main.direction = main.NORTH;
}
if(event.getKeyCode() == KeyEvent.VK_DOWN){
if(main.direction == main.NORTH){
return;
}
main.direction = main.SOUTH;
}
if(event.getKeyCode() == KeyEvent.VK_LEFT){
if(main.direction == main.EAST){
return;
}
main.direction = main.WEST;
}
if(event.getKeyCode() == KeyEvent.VK_RIGHT){
if(main.direction == main.WEST){
return;
}
main.direction = main.EAST;
}
}
#Override
public void keyReleased(KeyEvent arg0) {
}
#Override
public void keyTyped(KeyEvent arg0) {
}
}
EDIT
Here's the link to what it looks like (the bug):
http://s15.postimg.org/8z62dy7az/Bildschirmfoto_2014_06_03_um_16_47_48.png
OK, I'll try to go through your mistakes one-by-one, but really, this is a huge mess.
You save the graphics state and call paint from a separate Thread. Now, I'm not sure about applets and AWT, but in Swing that is a huge no-no. There is a convenient repaint() method available...
You do not have any synchronization on direction. This means the model can ignore the users commands if it feels like it. Try volatile. In fact, having both all variables and your drawing code in one class is fairly bad. MVC is the way to go.
You suffer from a large amount of off-by-1 errors. If you don't know what it is - google will help you. Just to name a few places where you have them: finalPoint.x > main.GRID_WIDTH will fire one cell too late since the grid starts with 0, for(int i = totalSnakeParts; i > 0; i--){Point tempPoint = new Point(i - 2, finalPoint.y); means the first point is in a negative coordinate (when i == 1).
In your border checking logic you reset the position of all the snake points, yet you do not paint empty squares on the previous positions. You do that when processing a move, why aren't you doing it now? That is the residual squares you have left on the right.
Your border checks are doing something strange anyway. What they do is straighten out the snake and teleport it to the left edge completely instead of just moving the head there. It looks the same while the snake is only 3 squares long because of a combination of bugs in number 3, but will be apparent with a longer one (Try it!). A classic approach would be to simply set the x coordinate of the head to 0, instead of resetting everything. That will also make number 4 obsolete, since you won't have to repaint the remainders at all (there won't be any, snake doesn't teleport).
I am fairly new to Java and LWJGL. I am trying to make a 2d sprite change appearance so it faces in the direction that you are holding, how would I go about this?
So far I have this-
package keyboardinputdb;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class KeyboardInputDB extends JFrame{
//Variables
int x, y, scoreCount;
private Image dbImage;
private Graphics dbg;
Image littleAdventurer;
boolean faceLeft;
boolean faceRight;
boolean faceUp;
Font font = new Font("Arial", Font.BOLD, 18);
//Action Listener
public class AL extends KeyAdapter {
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_LEFT){
x-=3;
if(x <= 0){
x = 0;
}
}
if(keyCode == e.VK_RIGHT){
x+=3;
if(x >= 235){
x = 235;
}
}
if(keyCode == e.VK_UP){
y-=3;
if(y <= 20){
y = 20;
}
}
if(keyCode == e.VK_DOWN){
y+=3;
if(y >= 235){
y = 235;
}
}
}
public void keyReleased(KeyEvent e){
}
}
public KeyboardInputDB(){
//Load Images
ImageIcon i = new ImageIcon("C:/Users/Clive/Documents/NetBeansProjects/KeyboardInput with DB/src/keyboardinputdb/littleAdventurer.gif");
littleAdventurer = i.getImage();
//Game Properties
addKeyListener(new KeyboardInputDB.AL());
setTitle("Java Game");
setSize(600, 500);
setResizable(false);
setVisible(true);
setBackground(Color.black);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
x = 150;
y = 150;
scoreCount = 0;
}
public void paint(Graphics g){
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
public void paintComponent(Graphics g){
g.setFont(font);
g.setColor(Color.white);
g.drawString("Score: " + scoreCount, 450, 70);
if(faceLeft = true){
g.drawImage(littleAdventurer, x, y, this);
}
else{
g.setColor(Color.white);
g.fillOval(x, y, 15, 15);
}
repaint();
}
public static void main(String[] args) {
KeyboardInputDB javagame = new KeyboardInputDB();
}
}
Any help with this would be appreciated.
First of all, your main problem is that you're using jFrame instead of LWJGL. I would recommend that you change to LWJGL first. You're also using three boolean variables for which direction your sprite is facing. What happens when both faceLeft and faceRight are true? You should use enums instead.
I assume you're new to Java, so I'll give you a little tutorial in enums...
1st, add this to the top of your class where you declare your varaibles:
public static enum Direction{
UP, DOWN, LEFT, RIGHT
}
public static Direction direction = Direction.DOWN;
You can now use this code to check if an enum is a certain value:
if(direction == Direction.LEFT){
//Do something.
}
You can also set an enum simply by calling:
direction = Direction.RIGHT;
And even easier way to check an enum's vause is by using a switch statement:
switch(direction){
case UP:
//Do something when up.
break;
case DOWN:
//Do something when down.
break;
case LEFT:
//Do something when left.
break;
case RIGHT:
//Do something when right.
break;
}
This best way that I can describe an enum to beginners is similar to a boolean (where it has a limited amount of options) but you can make as many options as you want.
Your current system also isn't using LWJGL, so I recommend changing to that if that's what you would like to use. Making a game is much easier with LWJGL than jFrame once you learn how to use OpenGL.
This page will prove useful: http://lwjgl.org/wiki/index.php?title=Main_Page#Getting_started
Just made quads first, then you can easily learn how to add a sprite in and rotate it using glRotatef()
*Note: * I'm new here. If you're going to downvote please tell me why.
I'm writing a java chess program using swing. I'm able to display the board, initialize pieces, and store them in a two dimensional array. However, I can't figure out how to display the pieces on my canvas. I keep getting a null pointer error on line 65 of class Piece.
*Update: * I've included some of the suggested changes. The null pointer error has cleared up, but I'm still having trouble getting the pieces to display. I don't think I've correctly pointed them at the canvas I created in class Chess.
My program is broken into three classes as follows:
Class Chess
import java.util.Scanner;
import javax.swing.*;
//import java.awt.*;
public class Chess {
public static final int WINDOW_WIDTH=600;
public static final int WINDOW_HEIGHT=600;
public static final int SQUARE_WIDTH = (WINDOW_WIDTH-10)/8;
public static final int SQUARE_HEIGHT = (WINDOW_HEIGHT-40)/8;
public static int position[][] = {};
public BoardComponent mycanvas= new BoardComponent(this);
public Chess()
{
JFrame mywindow;
mywindow=new JFrame("ChessMaster 2012");
mywindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mywindow.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
//BoardComponent mycanvas= new BoardComponent(this);
mywindow.add(mycanvas);
mywindow.setVisible(true); //window appears here
}
public static void main(String[] args) {
position = new int [8][8];
new Chess();
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferStrategy;
import javax.swing.ImageIcon;
public class Piece extends JPanel{
Piece[] mypiece;
public ImageIcon piece;
int nextID = 0;
BoardComponent board;
Chess chess;
public int locx, locy;
public void setCanvas(BoardComponent board)
{
this.board=board;
}
public Piece(char color, char Type, int posX, int posY){
// each piece assigned a PK on creation, beginning sequentially from top left
// and looping back to the beginning of each row
int pieceID = nextID;
char pieceColor = color;
char pieceType = Type;
posX = locx;
posY = locy;
// P = pawn, K = knight, R = Rook, B = Bishop, Q = Queen,
//S = king (can't reuse K, so we use S instead)
if (pieceType == 'P'){
new Pawn(pieceColor);
}
else if (pieceType == 'K'){
new Knight(pieceColor);
}
else if (pieceType == 'R'){
new Rook(pieceColor);
}
else if (pieceType == 'B'){
new Bishop(pieceColor);
}
else if (pieceType == 'Q'){
new Queen(pieceColor);
}
else if (pieceType == 'S'){
new King(pieceColor);
}
nextID ++;
Chess.position[posX][posY] = pieceID;
setCanvas(board);
repaint();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
drawPiece(g);
}
public void drawPiece(Graphics g){
g.drawImage(piece.getImage(),(locx*Chess.SQUARE_WIDTH),(locy*Chess.SQUARE_HEIGHT),null);
}
public class Pawn{
public Pawn(char color){
if(color == 'w'){
piece = new ImageIcon("src/gfx/wpawn.gif");
}
else{
piece = new ImageIcon("src/gfx/bpawn.gif");
}
}
}
public class Knight{
public Knight(char color){
if(color == 'w'){
piece = new ImageIcon("src/gfx/wknight.gif");
}
else{
piece = new ImageIcon("src/gfx/bknight.gif");
}
}
}
public class Rook{
public Rook(char color){
if(color == 'w'){
piece = new ImageIcon("src/gfx/wrook.gif");
}
else{
piece = new ImageIcon("src/gfx/brook.gif");
}
}
}
public class Bishop{
public Bishop(char color){
if(color == 'w'){
piece = new ImageIcon("src/gfx/wbishop.gif");
}
else{
piece = new ImageIcon("src/gfx/bbishop.gif");
}
}
}
public class Queen{
public Queen(char color){
if(color == 'w'){
piece = new ImageIcon("src/gfx/wqueen.gif");
}
else{
piece = new ImageIcon("src/gfx/bqueen.gif");
}
}
}
public class King{
public King(char color){
if(color == 'w'){
piece = new ImageIcon("src/gfx/wking.gif");
}
else{
piece = new ImageIcon("src/gfx/bking.gif");
}
}
}
}
Class BoardComponent:
import java.awt.*;
import javax.swing.*;
//This class draws the board and places the initial pieces
public class BoardComponent extends JComponent{
Chess chess;
public BoardComponent(Chess chessobject)
{
super();
chess=chessobject;
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
int rowCount = 0;
int highCount = 0;
int wideCount = 0;
int squareCount = 0;
ImageIcon piece;
for(rowCount = 0; rowCount<8;rowCount++){
for(int i = 0; i < 8; i++){
if(squareCount%2==1){
g.setColor(Color.ORANGE);
}
else{
g.setColor(Color.darkGray);
}
g.fillRect(wideCount,highCount, Chess.SQUARE_WIDTH-5, Chess.SQUARE_HEIGHT-5);
squareCount = squareCount + 1;
wideCount = wideCount + Chess.SQUARE_WIDTH;
g.setColor(Color.RED);
}
squareCount +=1;
wideCount = 0;
highCount = highCount + Chess.SQUARE_HEIGHT;
}
}
}
Class Piece:
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferStrategy;
import javax.swing.ImageIcon;
public class Piece extends JPanel{
Piece[] mypiece;
public ImageIcon piece;
int nextID = 0;
BoardComponent board;
Chess chess;
public int locx, locy;
public void setCanvas(BoardComponent board)
{
this.board=board;
}
public Piece(char color, char Type, int posX, int posY){
// each piece assigned a PK on creation, beginning sequentially from top left
// and looping back to the beginning of each row
int pieceID = nextID;
char pieceColor = color;
char pieceType = Type;
posX = locx;
posY = locy;
// P = pawn, K = knight, R = Rook, B = Bishop, Q = Queen,
//S = king (can't reuse K, so we use S instead)
if (pieceType == 'P'){
new Pawn(pieceColor);
}
else if (pieceType == 'K'){
new Knight(pieceColor);
}
else if (pieceType == 'R'){
new Rook(pieceColor);
}
else if (pieceType == 'B'){
new Bishop(pieceColor);
}
else if (pieceType == 'Q'){
new Queen(pieceColor);
}
else if (pieceType == 'S'){
new King(pieceColor);
}
nextID ++;
Chess.position[posX][posY] = pieceID;
setCanvas(board);
repaint();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
drawPiece(g);
}
public void drawPiece(Graphics g){
g.drawImage(piece.getImage(),(locx*Chess.SQUARE_WIDTH),(locy*Chess.SQUARE_HEIGHT),null);
}
public class Pawn{
public Pawn(char color){
if(color == 'w'){
piece = new ImageIcon("src/gfx/wpawn.gif");
}
else{
piece = new ImageIcon("src/gfx/bpawn.gif");
}
}
}
public class Knight{
public Knight(char color){
if(color == 'w'){
piece = new ImageIcon("src/gfx/wknight.gif");
}
else{
piece = new ImageIcon("src/gfx/bknight.gif");
}
}
}
public class Rook{
public Rook(char color){
if(color == 'w'){
piece = new ImageIcon("src/gfx/wrook.gif");
}
else{
piece = new ImageIcon("src/gfx/brook.gif");
}
}
}
public class Bishop{
public Bishop(char color){
if(color == 'w'){
piece = new ImageIcon("src/gfx/wbishop.gif");
}
else{
piece = new ImageIcon("src/gfx/bbishop.gif");
}
}
}
public class Queen{
public Queen(char color){
if(color == 'w'){
piece = new ImageIcon("src/gfx/wqueen.gif");
}
else{
piece = new ImageIcon("src/gfx/bqueen.gif");
}
}
}
public class King{
public King(char color){
if(color == 'w'){
piece = new ImageIcon("src/gfx/wking.gif");
}
else{
piece = new ImageIcon("src/gfx/bking.gif");
}
}
}
}
I'm fairly new to java, and this is really throwing me for a loop. Can anyone help?
Thanks!
Dont call drawPiece() from your constructor for what reason? I think repaint() might be what you need.
dont use getGraphics() as it wont be initialized yet until the panel is added and first repaint is done if im not mistaken.
Also never forget to honor paint chain and have super.paintComponent(..) as your first call in your overridden paintComponent(..) method of panel.
Rather extend JPanel and not JComponent
I think you meant to call drawPiece() in paintComponent(..) in which place you should just pass the Graphics object to drawPiece() from paintComponent(..) like so:
public class Piece extends JPanel{
public Piece(char color, char Type, int posX, int posY){
// each piece assigned a PK on creation, beginning sequentially from top left
// and looping back to the beginning of each row
....
// P = pawn, K = knight, R = Rook, B = Bishop, Q = Queen,
//S = king (can't reuse K, so we use S instead (from Shah, the historical name))
....
nextID ++;
Chess.position[posX][posY] = pieceID;
repaint();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
drawPiece(g);
}
public void drawPiece(Graphics g){
g.drawImage(piece.getImage(),(locx*Chess.SQUARE_WIDTH),(locy*Chess.SQUARE_HEIGHT),null);
}
}
Other suggestions:
Create JFrame and other Swing components on EDT by wrapping UI creation code in
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
//create ui here
}
});
Dont call setSize(...) on JFrame
rather override JPanel getPreferredSize() and return an appropriate size which fits components etc than you can remove setSize call on JFrame and call pack() on JFrame instance before setting visible
It seems like your variable board is not initialized yet. You need to call setCanvas() first to initialize it, then you can call drawPiece().