*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().
Related
PS : Here is the GitHub for those intrested https://github.com/Yasakidev/AnimalRescueUP/tree/master
I'm developing a "Pet Rescue Saga" Java game in Swing. I'm kind of new to Swing and fell into a problem.
I want my pieces to fall when they are removed. Here I've managed to "remove them" by changing their color but then I want them to fall like a tetris.
Here's my code :
GRID (Which is the JFrame and a singleton class)
import javax.swing.*;
import java.awt.*;
public class Grid extends JFrame {
private static Grid main;
private Case[][] cases;
public Grid() {
this.cases = new Case[8][8];
for (int i = 0; i < cases.length; i++) {
for (int j = 0; j < cases[i].length; j++) {
this.cases[i][j] = new Case(i, j);
this.add(cases[i][j]);
}
}
this.setSize(800, 800);
this.setLayout(new GridLayout(8,8));
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
public Case getCase(int i, int j) {
return this.cases[i][j];
}
public static Grid getGrid() {
if(main == null) main = new Grid();
return main;
}
public void swap(int x1, int y1, int x2, int y2) {
Case temp = this.cases[x1][y1];
cases[x1][y1] = cases[x2][y2];
cases[x2][y2] = temp;
}
public void rebuild() {
for(int i = cases.length-1-1; i > 0; i--) {
for (int j = cases[i].length-1-1; j > 0; j--) {
int k = i;
while(!cases[k+1][j].isActive()) {
this.swap(i, j, i+1, j);
k++;
}
}
}
//swap(5,5,5,6);
}
}
CASE (Which defines the blocks inside the Grid, on click, they run clicked() and remove all adjacent Blocks of the same color recursively)
import utils.RandomGen;
import javax.swing.*;
import javax.swing.border.LineBorder;
import java.awt.*;
public class Case extends JPanel {
private JButton btn;
private Color color;
private final int posX;
private final int posY;
private boolean isActive;
public Case(int x, int y) {
//Init Members
this.posX = x;
this.posY = y;
//Init Components
this.initColor();
this.initButton();
this.initPanel();
}
public void clicked() {
this.setVisible(false);
this.isActive = false;
checkAdjacent();
Grid.getGrid().rebuild;
}
private void initColor() {
int i = RandomGen.get(0,4);
switch(i) {
case 0 -> this.color = new Color(255,0,0);
case 1 -> this.color = new Color(0,0, 255);
case 2 -> this.color = new Color(136, 0, 255);
case 3 -> this.color = new Color(27, 255, 0);
default -> this.color = new Color(0, 0, 0);
}
}
private void initButton() {
this.btn = new JButton();
this.btn.setOpaque(false);
this.btn.setContentAreaFilled(false);
this.btn.setBorderPainted(false);
this.btn.addActionListener(new ClickEventHandler(this));
}
private void initPanel() {
this.setBorder(new LineBorder(new Color(0,0,0)));
this.setBackground(this.color);
this.add(btn);
this.setLayout(new CardLayout());
this.isActive = true;
this.setVisible(true);
}
private void checkAdjacent() {
//CLEAR DOWN
if(this.posX != 7 && Grid.getGrid().getCase(this.posX+1, this.posY).isActive && Grid.getGrid().getCase(this.posX+1, this.posY).getColor().getRGB() == this.color.getRGB()) Grid.getGrid().getCase(this.posX+1, this.posY).clicked();
//CLEAR UP
if(this.posX != 0 && Grid.getGrid().getCase(this.posX-1, this.posY).isActive && Grid.getGrid().getCase(this.posX-1, this.posY).getColor().getRGB() == this.color.getRGB()) Grid.getGrid().getCase(this.posX-1, this.posY).clicked();
//CLEAR RIGHT
if(this.posY != 7 && Grid.getGrid().getCase(this.posX, this.posY+1).isActive && Grid.getGrid().getCase(this.posX, this.posY+1).getColor().getRGB() == this.color.getRGB()) Grid.getGrid().getCase(this.posX, this.posY+1).clicked();
//CLEAR LEFT
if(this.posY != 0 && Grid.getGrid().getCase(this.posX, this.posY-1).isActive && Grid.getGrid().getCase(this.posX, this.posY-1).getColor().getRGB() == this.color.getRGB()) Grid.getGrid().getCase(this.posX, this.posY-1).clicked();
}
public Color getColor() {
return color;
}
public int getPosX() {
return posX;
}
public int getPosY() {
return posY;
}
public boolean isActive() {
return isActive;
}
}
Here's two screenshots of the problem
Randomly generated grid
When clicking on the red pattern for example, i want the rest of the blocks to fall
I tried the Grid.rebuild() to make the blocks fall, but nothing changes on the display.
Also if you spot bad habits or mistakes please point them to me.
Thanks for your help !
I am currently working on a tic tac toe program for an assignment. The issue I am having is when I count my player (either the 'X' player or the 'Y' player), it seems to be counting both players as the same. For instance, after the third play, it sees three plays and counts it as a winner, even though only two plays of one player and one play of the other have been completed.
public class TicTacToeApp
{
public static void main(String[] args)
{
TicTacToeView view = new TicTacToeView();
TicTacToeModel model = new TicTacToeModel();
TicTacToeViewController controller = new
TicTacToeViewController(view,model);
view.setVisible(true);
}
}
public class TicTacToeModel
{
double xpos,ypos,xr,yr;
char[][] position = {{' ',' ',' '},
{' ',' ',' '},
{' ',' ',' '}};
public void computePos(int row, int col, int h, int w)
{
xpos=(col+0.5)*w/3.0;
ypos=(row+0.5)*h/3.0;
xr=w/8.0;
yr=h/8.0;
}
public boolean isEmpty(int xpos, int ypos)
{
if(position[xpos][ypos]==' ')
return true;
return false;
}
public void placeO(int xpos, int ypos)
{
position[xpos][ypos]='O';
}
public int putX(){
for(int i=0; i<3;i++){
for(int j = 0;j<3;j++) {
if(position[i][j]==' ') {
position[i][j]='X';
return 0;
}
}
}
return -1; //some error occurred. This is odd. No cells were free.
}
public void printBoard(){
for(int i=0;i<3;i++)
System.out.println(position[i][0]+"|"+position[i][1]+"|"+position[i][2]);
}
}
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.ArrayList;
public class TicTacToeView extends JFrame{
private JButton oButton, xButton;
public JPanel board;
public ArrayList<Shape> shapes;
public TicTacToeView(){
shapes = new ArrayList<Shape>();
JPanel topPanel=new JPanel();
topPanel.setLayout(new FlowLayout());
add(topPanel, BorderLayout.NORTH);
add(board=new Board(), BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 500);
}
private class Board extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
int w=getWidth();
int h=getHeight();
Graphics2D g2d = (Graphics2D) g;
// Draw the grid
g2d.setPaint(Color.WHITE);
g2d.fill(new Rectangle2D.Double(0, 0, w, h));
g2d.setPaint(Color.BLACK);
g2d.setStroke(new BasicStroke(4));
g2d.draw(new Line2D.Double(0, h/3, w, h/3));
g2d.draw(new Line2D.Double(0, h*2/3, w, h*2/3));
g2d.draw(new Line2D.Double(w/3, 0, w/3, h));
g2d.draw(new Line2D.Double(w*2/3, 0, w*2/3, h));
//draw circles and xs by visiting elements in the array List.
for(Shape shape : shapes){
g2d.setPaint(Color.BLUE);
g2d.draw(shape);
}
}
}
public void addMouseListener(MouseListener ml){
board.addMouseListener(ml);
}
public static void main(String[] args) {
TicTacToeView ttv = new TicTacToeView();
ttv.setVisible(true);
}
}
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.Graphics2D;
import java.awt.Color;
import javax.swing.JOptionPane;
public class TicTacToeViewController implements MouseListener{
TicTacToeView view;
TicTacToeModel model;
Color oColor=Color.BLUE, xColor=Color.RED;
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public TicTacToeViewController(TicTacToeView view, TicTacToeModel model) {
this.view = view;
this.model = model;
view.addMouseListener(this);
}
public void play(int xpos, int ypos) {
if (model.isEmpty(xpos,ypos)) {
model.placeO(xpos, ypos);
drawBoard();
view.repaint();
model.putX();
if(didWin("X")){
JOptionPane.showMessageDialog(null,"X Wins","Winner", JOptionPane.INFORMATION_MESSAGE);
}
if(didWin("O"))
JOptionPane.showMessageDialog(null,"O Wins","Winner",JOptionPane.INFORMATION_MESSAGE);
}
}
public void drawBoard() {
Graphics2D g2d = (Graphics2D)view.board.getGraphics();
for (int i=0; i<3; i++)
for(int j=0; j<3;j++) {
model.computePos(i,j,view.board.getHeight(),view.board.getWidth());
double xpos = model.xpos;
double xr = model.xr;
double ypos = model.ypos;
double yr = model.yr;
if (model.position[i][j]=='O') {
view.shapes.add(new Ellipse2D.Double(xpos-xr, ypos-yr, xr*2, yr*2));
}
else if (model.position[i][j]=='X') {
view.shapes.add(new Line2D.Double(xpos-xr, ypos-yr, xpos+xr, ypos+yr));
view.shapes.add(new Line2D.Double(xpos-xr, ypos+yr, xpos+xr, ypos-yr));
}
System.out.println("Coords: xpos:"+xpos+", ypos:"+ypos+", xr"+xr+", yr"+yr);
}
}
public void mouseClicked(MouseEvent e) {
int ypos=e.getX()*3/view.getWidth();
int xpos=e.getY()*3/view.getHeight();
//System.out.println("Play "+xpos+","+ypos);
play(xpos,ypos);
}
public boolean didWin(char player) {
int count = 0;
int count2 = 0;
for(int i = 0; i<3; i++)
{
for(int j= 0; j<3; j++)
{
if(model.position[i][j]==player)
{
count++;
if(count ==2)
return true;
}
}
count=0;
}
for(int k = 0; k<3; k++)
{
for(int l= 0; l<3; l++)
{
if(model.position[l][k]==player)
{
count2++;
if(count2 ==2)
return true;
}
}
count2=0;
}
if(model.position[0][0]==player && model.position[1][1]==player && model.position[2][2]==player)
return true;
if(model.position[0][2]==player && model.position[1][1]==player && model.position[2][0]==player)
return true;
return false;
}
}
My question is if someone can look over my logic and see why the game only allows three moves. In other words, the O goes, the X goes, then the O goes, and the game announces a winner. Also, I am not looking for a code answer, but rather which part I should inspect to fix my code.
It sounds like the error is in the didWin () method if everything else works.
I think when you call the didWin I only used one ' ' don't think it really changes anything tho
For starters, you want your count to see if it's == 3 or at least > 2, not == 2.
I just start learning Java. I write a program like this:
Bacteria.class
import java.awt.*;
public class Bacteria extends Creature{
public static final int COLOR_STEP = 256/MAX_AGE;
Bacteria(Board board, int _x, int _y){
super.board = board;
//initialize age, x, y
super.age = 1;
super.x = _x;
super.y = _y;
}
//Draw a circle representing the creature at its position
//This function is done.
public void draw(Graphics g) {
g.setColor(new Color(0, COLOR_STEP * age, 0));
g.fillOval(x * board.CELL_SIZE, y * board.CELL_SIZE, board.CELL_SIZE, board.CELL_SIZE);
}
public void tick() {
//your code
// this is how the creature lives in one tick
// make the creature get older if it is not dead.
// if it's got older than MAX_AGE then it should die
// ...call board.addDead() to register the dead creature
// if it can have baby then try reproduce()
age++;
if (this.canHaveBaby()) {
this.reproduce();
}
//this.reproduce();
if (age > MAX_AGE) {
board.addDead(this);
}
}
}
Creature.class
import java.awt.*;
public class Creature {
public static final int MAX_AGE = 5;
public Board board;
public int age; // age of the creature measures in ticks
public int x; // (x,y) is the position of the creature
public int y;
Creature(Board board, int _x, int _y) {
this.board = board;
//initialize age, x, y
age = 1;
x = _x;
y = _y;
}
public Creature() {
}
//Draw a circle representing the creature at its position
//This function is done.
public void draw(Graphics g){}
public void tick(){}
public void reproduce() {
//your code
// if it can have a baby then produce a baby
// ...in an empty cell next to its cell.
// board.emptyCell() should be used
// ....to check whether a cell in the board is empty
// and call board.addBaby() to place the baby to the board
//int x_current = x, y_current = y;
if(board.emptyCell(x, y+1)){
Creature baby = new Creature(board,x, y+1);
//System.out.println("1");
board.addBaby( baby);
}
else if(board.emptyCell(x+1,y)){
Creature baby = new Creature(board,x+1, y);
board.addBaby(baby);
}
else if(board.emptyCell(x+1,y+1)){
Creature baby = new Creature(board,x+1, y+1);
board.addBaby(baby);
}
else if(board.emptyCell(x-1,y)){
Creature baby = new Creature(board,x-1, y);
board.addBaby(baby);
}
else if(board.emptyCell(x,y-1)){
Creature baby = new Creature(board,x, y-1);
board.addBaby(baby);
}
else if(board.emptyCell(x-1,y-1)){
Creature baby = new Creature(board,x-1, y-1);
board.addBaby(baby);
}
else if(board.emptyCell(x-1,y+1)){
Creature baby = new Creature(board,x-1, y+1);
board.addBaby(baby);
}
else if(board.emptyCell(x+1,y-1)){
Creature baby = new Creature(board,x+1, y-1);
board.addBaby(baby);
}
}
public boolean canHaveBaby() {
//your code
// if the creature is dead or it is too young
// then it cannot have a baby
if(age == 0 || age > MAX_AGE){
return false;
}
return true;
}
public boolean atPosition(int _x, int _y) {
//your code
// return true if the creature is at the position (_x,_y)
// you need this function for board.empty to function correctly
if(_x == x && _y == y){
return true;
}
return false;
}
}
Board.class
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
public class Board extends JPanel {
public static final int CELL_SIZE = 10;
private final int rows = 10;
private final int cols = 20;
ArrayList<Creature> creatureList;
ArrayList<Creature> babies, dead;
// ArrayList<Bacteria> bacteriaList;
// ArrayList<Bacteria> babies_bac, dead_bac;
Board() {
super();
setBackground(Color.white);
creatureList = new ArrayList<Creature>();
//creatureList.size();
babies = new ArrayList<Creature>();
dead = new ArrayList<Creature>();
setPreferredSize(new Dimension(cols * CELL_SIZE, rows * CELL_SIZE));
creatureList.add(new Bacteria(this, 1, 1));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Creature creature: creatureList) {
creature.draw(g);
}
}
public void tick() {
dead = new ArrayList<Creature>();
babies = new ArrayList<Creature>();
for (Creature creature: creatureList) {
creature.tick();
}
creatureList.addAll(babies);
creatureList.removeAll(dead);
}
public void addBaby(Creature baby) {
if (baby != null) babies.add(baby);
}
public void addDead(Creature deadCreature) {
if (deadCreature != null) dead.add(deadCreature);
}
public boolean emptyCell(int x, int y) {
if (x < 0 || y < 0 || x >= cols || y >= rows) return false;
for (Creature creature : creatureList) {
if (creature.atPosition(x, y)) {
return false;
}
}
for (Creature creature : creatureList) {
if (creature.atPosition(x, y)) {
return false;
}
}
return true;
}
public String getPopulation() {
return String.format("%d", creatureList.size());
}
}
and BacteriaSimulator.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class BacteriaSimulator extends JFrame {
private Board board;
private JLabel label;
public BacteriaSimulator() {
initUI();
setTitle("Bacteria Simulator");
setSize(350, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private void initUI() {
JPanel panel = new JPanel();
board = new Board();
panel.add(board);
label = new JLabel(board.getPopulation());
panel.add(label);
JButton button = new JButton("Tick");
button.addActionListener(new ButtonNextListener());
panel.add(button);
add(panel);
pack();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
BacteriaSimulator ex = new BacteriaSimulator();
ex.setVisible(true);
}
});
}
private class ButtonNextListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
board.tick();
label.setText(board.getPopulation());
repaint();
}
}
}
I want Board.class work with creatureList. However, Board is still initialized with a bacteria (creatureList.add(new Bacteria(this, 1, 1));). I got a problem that is Board.class can not run draw() and tick() method which I want. How to draw objects bacteria and make the right method of tick ()? Can you help me! Thank you!
Your draw() and tick() functions are part of Bacteria.java. They cannot be used from Board.java unless you create an instance of Bacteria and then invoke the methods using that.
basically i have been following a Java tutorial to make a basic maze game where i generate a random maze which is saved to a file then i print it out using Jpanel however i keep getting this error when i compile.
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at maze.Map.getMap(Map.java:43)
at maze.Board.paint(Board.java:40)
However i am not sure why, i believe it is something to do with my Y integer but if i set it to 0 it causes my program to print out wrong(just prints the same column instead of changing rows).
I need the Y value in Map.java:43 to increase like my x value does however it provides me with the Exception error.
Code:
Map Class
package maze;
import java.awt.Image;
import java.io.File;
import java.util.*;
import javax.swing.ImageIcon;
public class Map {
private Scanner m;
private Image wall, ground;
//number of columns
private String Map[] = new String[20];
public Map() {
//sets ground to a texture
ImageIcon img = new ImageIcon("C:\\MazeGraphics\\ground.png");
ground = img.getImage();
//sets wall texture
img = new ImageIcon("C:\\MazeGraphics\\wall.png");
wall = img.getImage();
openFile();
readFile();
closeFile();
}
public Image getGround() {
// gives grass texture for screen
return ground;
}
public Image getWall() {
// gives wall texture for screen
return wall;
}
public String getMap(int x, int y) {
//compares string to find graphic to use
String index= Map[y].substring(x, x+1);
return index;
}
public void openFile() {
try {
m = new Scanner(new File("C:\\MazeGraphics\\Maze.txt"));
} catch (Exception e) {
System.out.println("Error Loading Map");
}
}
public void readFile() {
for(int i = 0; i < 20; i++)
{
while(m.hasNext()){
Map[i] = m.next();
}
}
}
public void closeFile() {
m.close();
}
}
Board Class:
package maze;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Board extends JPanel implements ActionListener {
private Timer timer;
private Map m;
private Player p;
public Board()
{
MazeGeneration maz=new MazeGeneration();
//runs Map class
m = new Map();
p = new Player();
//listens for key presses
addKeyListener(new Al());
//knows to add key listener to the frame
setFocusable(true);
timer = new Timer(25, this);
timer.start();
}
public void actionPerformed(ActionEvent e) {
repaint();
}
public void paint(Graphics g) {
super.paint(g);
//paints the board row by row
for (int y = 0; y < 20; y++)
{
for (int x = 0; x < 20; x++)
{
//places graphic depending on the letter.
if (m.getMap(x, y).equals("g"))
{
g.drawImage(m.getGround(), y * 32, x * 32, null);
}
if (m.getMap(x, y).equals("w"))
{
g.drawImage(m.getWall(), y * 32,x * 32, null);
}
}
}
g.drawImage(p.getPlayer(), p.gettileX() * 32, p.gettileY() * 32, null);
}
public class Al extends KeyAdapter {
//moving the player
public void keyPressed(KeyEvent e, char maz[][], int r, int c) {
int keycode = e.getKeyCode();
if (keycode == KeyEvent.VK_W) {
//if not a wall can move
if (!m.getMap(p.gettileX(), p.gettileY() - 1).equals("w")) {
p.move(0, -1);
}
}
if (keycode == KeyEvent.VK_S) {
if (!m.getMap(p.gettileX(), p.gettileY() + 1).equals("w")) {
p.move(0, 1);
}
}
if (keycode == KeyEvent.VK_A) {
if (!m.getMap(p.gettileX() - 1, p.gettileY()).equals("w")) {
p.move(-1, 0);
}
}
if (keycode == KeyEvent.VK_D) {
if (!m.getMap(p.gettileX() + 1, p.gettileY() ).equals("w")) {
p.move(1, 0);
}
}
}
}
}
The issue is in this code: In your readFile() method, your issue arises during reading your file:
for(int i = 0; i < 20; i++)
{
while(m.hasNext()){
Map[i] = m.next();
}
}
You are assigning the value only to the 0'th index. To explain, for the first for loop, the index i is at zero. The inner loop "iterates" through the Scanner m until there is no element next. Therefore, Map[0] contains the last element on the file.
Your solution is as follows:
int i = 0;
while (m.hasNext()) {
Map[i++] = m.next();
}
I hope this helps.
Hi, I'm developing a snake game. To create the snake I'm using ArrayList. While moving the snake I'm getting the following error: "java.lang.IndexOutOfBoundsException: Index: 3, Size: 3". Below is my program. In Snake.update() method I have problem.
Game.java:
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class Game extends JFrame {
public Game(){
add(new GamePanel());
setTitle("Game Test3");
setVisible(true);
setAlwaysOnTop(true);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
}
public static void main(String[] args) {
new Game();
}
}
GamePanel.java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class GamePanel extends JPanel implements Runnable, KeyListener {
public static int width = 300;
public static int height = 400;
private Thread thread;
private Image image;
private Graphics2D g;
private Food food;
private Snake snake;
public GamePanel() {
setPreferredSize(new Dimension(width, height));
setFocusable(true);
}
public void addNotify() {
super.addNotify();
if (thread == null) {
thread = new Thread(this);
thread.start();
}
addKeyListener(this);
}
public void run() {
image = createImage(width, height);
g = (Graphics2D) image.getGraphics();
RenderingHints reneringHints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHints(reneringHints);
food = new Food();
snake = new Snake();
while (true) {
gameRender();
gameUpdate();
gameDraw();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void gameDraw() {
Graphics2D g2 = (Graphics2D) getGraphics();
g2.drawImage(image, 0, 0, this);
g2.dispose();
}
private void gameRender() {
g.setColor(Color.black);
g.fillRect(0, 0, width, height);
// food drawing
food.draw(g);
// snake drawing
snake.draw(g);
}
private void gameUpdate() {
food.update();
snake.update();
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
snake.setLeft(true);
}
if (key == KeyEvent.VK_RIGHT) {
snake.setRight(true);
}
if (key == KeyEvent.VK_UP) {
snake.setUp(true);
}
if (key == KeyEvent.VK_DOWN) {
snake.setDown(true);
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
snake.setLeft(false);
}
if (key == KeyEvent.VK_RIGHT) {
snake.setRight(false);
}
if (key == KeyEvent.VK_UP) {
snake.setUp(false);
}
if (key == KeyEvent.VK_DOWN) {
snake.setDown(false);
}
}
public void keyTyped(KeyEvent e) {
}
}
//snake body
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.ArrayList;
public class Snake {
private int x;
private int y;
private int r;
int body;
Rectangle rectangle;
ArrayList<Rectangle> rc = new ArrayList<Rectangle>();
private boolean left;
private boolean right;
private boolean up;
private boolean down;
public Snake() {
x = 150;
y = 150;
r = 4;
body = 3;
for (int i = 0; i < body; i++) {
rc.add(new Rectangle(x - i * r * 3, y, r * 3, r * 3));
}
}
public void draw(Graphics2D g) {
for (int i = 0; i < body; i++) {
if (i == 0) {
g.setColor(Color.red);
} else {
g.setColor(Color.green);
}
g.fillOval(rc.get(i).x, rc.get(i).y, rc.get(i).width,
rc.get(i).height);
}
}
public void update() {
for (int i = body; i > 0; i--) {
rc.set(i, rc.get(i - 1));
}
if (left) {
rc.get(0).x -= 1;
System.out.println("vbnv");
}
if (right) {
rc.get(0).x += 1;
}
if (up) {
rc.get(0).y -= 1;
}
if (down) {
rc.get(0).y += 1;
}
}
public void setLeft(boolean b) {
left = b;
}
public void setRight(boolean b) {
right = b;
}
public void setUp(boolean b) {
up = b;
}
public void setDown(boolean b) {
down = b;
}
}
Without reading the code I can tell that somewhere you are trying to get non-existent element. Read the message of exception, it tells you that your ArrayList consist of three elements (which means that the last element has index of 2) while you try to get the element with index of 3.
Update: yes, the problem is here:
for (int i = body; i > 0; i--) {
rc.set(i, rc.get(i - 1));
}
body equals to 3, and rc after the constructor invocation has the size of 3. set method replaces already existing element with the specified index (see the documentation), but element with index of 3 doesn't exist. That's the cause of an exception.
Your problem is in this loop:
for (int i = body; i > 0; i--) {
rc.set(i, rc.get(i - 1));
}
During the first iteration around this loop, you will be calling:
rc.set(3, <someValue>);
3 is not a valid index in a list of length 3. The largest valid index is 2.
for (int i = body; i > 0; i--)
In this for, i is assigned with the value of body(which is 3) and it looks like your ArrayList rc has only 3 elements in it. Therefore, when you try to access the index 3 using rc.set(3, something), its giving the IndexOutOfBoundsException.
Always remember, whether it is Arrays or ArrayList, the max possible index accessible in them is always array.length - 1 and ArrayList.size() - 1.