JavaFX Canvas not showing drawings - java

I would first like to say that I have extensively looked into this over the past day and I haven't found anything that fits this particular case. I'm in the midst of trying to create a simply Conway's Game of Life Application, and I seem to be having trouble with drawing to a JavaFX Canvas. Everything seems to be configurerd correctly (Canvas added to a layout container, said container added to a scene, and the stage is started) but even after trying different ways of encapsultating the code the Canvas remains to be empty
Here is my code:
public class Life extends Application implements Runnable {
private Grid grid;
private boolean running;
private boolean paused;
private int stepsPerMinute;
#Override
public void start(Stage stage) {
this.grid = new Grid(60, 40);
this.running = true;
this.paused = false;
this.stepsPerMinute = 60;
StackPane root = new StackPane();
root.getChildren().add(grid);
Scene scene = new Scene(root, 1080, 720);
stage.setTitle("Conway's Game of Life");
stage.setScene(scene);
stage.setResizable(false);
stage.setOnCloseRequest(e -> stop());
stage.show();
}
public void run() {
while (running) {
if (!paused) {
try {
Thread.sleep(1000 / stepsPerMinute);
} catch (InterruptedException e) { e.printStackTrace(); }
grid.step();
grid.draw();
}
}
}
#Override
public void stop() {
this.running = false;
// TODO: Dump Stats at end
System.exit(0);
}
public static void main(String[] args) { launch(args); }
public class Grid extends Canvas {
private final int WIDTH = 1080, HEIGHT = 720;
private boolean[][] cellStates;
private int rows, cols;
private int stepNum;
public Grid(int rows, int cols) {
this.rows = rows;
this.cols = cols;
this.stepNum = 0;
randomize();
minWidth(WIDTH);
maxWidth(WIDTH);
prefWidth(WIDTH);
minHeight(HEIGHT);
maxHeight(HEIGHT);
prefHeight(HEIGHT);
}
public Grid(boolean[][] cellStates) {
this.cellStates = cellStates;
this.rows = cellStates.length;
this.cols = cellStates[0].length;
this.stepNum = 0;
}
public void step() {
boolean[][] updatedStates = new boolean[rows][cols];
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++) {
int aliveNeighbors = countAliveNeighbors(i, j);
if (cellStates[i][j]) {
if (aliveNeighbors == 2 || aliveNeighbors == 3)
updatedStates[i][j] = true;
}
else if (aliveNeighbors == 3)
updatedStates[i][j] = true;
}
this.cellStates = updatedStates;
stepNum++;
}
private int countAliveNeighbors(int r, int c) {
int result = 0;
for (int i = -1; i <= 1; i++)
for (int j = -1; j <= 1; j++) {
if (cellStates[ (rows + r + i) % rows ][ (cols + c + j) % cols ])
result++;
}
return result;
}
public void randomize() {
boolean[][] updatedStates = new boolean[rows][cols];
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++) {
if (Math.random() < 0.08)
updatedStates[i][j] = true;
}
this.cellStates = updatedStates;
}
public void glider(){
this.cellStates = new boolean[rows][cols];
this.cellStates[1][2] = true;
this.cellStates[2][3] = true;
this.cellStates[3][1] = true;
this.cellStates[3][2] = true;
this.cellStates[3][3] = true;
}
public void draw() {
GraphicsContext g = this.getGraphicsContext2D();
int cellWidth = WIDTH / cols, cellHeight = HEIGHT / rows;
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++) {
if (cellStates[i][j])
g.setFill(Color.color(0.0078, 0, 1));
else
g.setFill(Color.color(0.9961, 1, 0.8431));
g.fillRect(j * cellWidth, i * cellHeight, cellWidth, cellHeight);
g.strokeLine(j * cellWidth, 0, j * cellWidth, HEIGHT);
g.strokeLine(0, i * cellHeight, WIDTH, i * cellHeight);
}
}
}
}
I left the imports out of the code for sake of brevity.
Thank you!

Related

How to update the position of snakes and ladders in an 2D array code?

public class ChutesAndLadders2d {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[][] numbersOnBoard = new int [6][6];
boardSetUpA (numbersOnBoard);
printTwoD(numbersOnBoard);
}
public static void boardSetUpA (int[][]twoD) {
//Square with even size
//even rows
for (int row = 0;row<twoD.length; row ++) {
if (row %2 ==0) {
int num = twoD.length*(twoD.length-row);
for (int col = 0; col<twoD[row].length; col ++ ) {
twoD[row][col] = num;
num--;
}
}//
else {
int num = twoD.length*(twoD.length-(row + 1))+ 1;
for (int col = 0; col<twoD[row].length; col ++ ) {
twoD[row][col] = num;
num++;
}
}
}//for row
}//
public static void printTwoD(int [][] array){
for (int row = 0; row < array.length; row++){
for (int column = 0; column < array[row].length; column++){
System.out.print(array[row][column] + "\t");
}
System.out.println();
}
}
public static void boardDetails(String[][]board) {
for (int row = 0;row<board.length; row++){
for (int col = 0;col<board[row].length; col++){
if( col+2 == row||col+1 == row*2 ){
board[row][col] = "Lad"; // Append value
}
else if (col*2 == row|| row*2 == col){
board[row][col] = "Cht";// Append value
}
else {
board[row][col] = " ";
}
}
board[board.length-1][0] = "Start";
if (board.length%2 ==0) {
board[0][0] = "End";}
else {
board[0][board.length-1]="End";
}
}
}
public static void printBoard (int[][]twoD, String[][]strTwoD) {
//Printing
for (int row = 0;row<twoD.length;row++) {
for (int col = 0;col<twoD[row].length;col++) {
System.out.print(twoD[row][col] + " "+strTwoD[row][col]+"\t\t");
}
System.out.println("\n");
}
}
}
This is the starter code I have for setting up the snakes and ladders game. I also tried to set the chutes/snakes and ladders on the board but it is not printing. How should I fix it and how do I develop this code to have three methods: update the moves of a player once he reaches a snake, a ladder, and once he rolls his die, from one place to another?
Is it possible to implement a Shutes & Ladders game using a 2D Array? For sure! Does that make sense in an object-oriented language such as Java? I dont know ....
What do you need for that?
A square board with e.g. 36 playing fields.
Connections between two playing fields. (shutes and ladders)
Pawns and a dice.
A renderer that outputs the playing field (as text or graphics).
A program that allows input and connects everything to a functioning game.
Here is an example that works with a List instead of an Array. That can certainly be changed if it is necessary for your purposes.
I hope this is of some help to you.
P.S .: After the start, the board is displayed with field numbers. Shutes are shown as red lines. Ladders as green lines. Keys 1-6 on the keyboard simulate rolling the dice..
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyAdapter;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.*;
public class ChutesAndLadders2d {
public static void main(String[] args) {
JFrame frame = new JFrame("Chutes and Ladders 2D");
Game game = new ChutesAndLadders2d().new Game();
game.setPreferredSize(new Dimension(400, 400));
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setContentPane(game);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
#SuppressWarnings("serial")
class Game extends JPanel{
private final Font defaultFont = new Font("Arial", Font.PLAIN, 16);
private final BasicStroke stroke = new BasicStroke(4f);
private static final int SCALE = 64;
// board and pawns
private final Board board = new Board(6);
private final List<Pawn> pawns = new ArrayList<>();
public Game(){
setFocusable(true); // receive Keyboard-Events
addKeyListener(new KeyAdapter(){
#Override
public void keyTyped(KeyEvent e) {
char c = e.getKeyChar();
if(c >= '1' && c <= '6'){
int steps = Integer.parseInt(Character.toString(c));
Pawn pawn = pawns.get(0);
pawn.move(steps);
Field field = board.get(pawn.fieldIndex);
if(field.targetKind() != Kind.NONE){
pawn.move(field.getTarget().index - field.index);
}
repaint();
}
}
});
board.connect(5, 12); // Ladder 5 -> 12
board.connect(8, 4); // Shute 8 -> 4
board.connect(15, 32); // Ladder 15 -> 32
board.connect(35, 17); // Shute 35 -> 17
board.connect(23, 30); // Ladder 23 -> 30
pawns.add(new Pawn(Color.BLUE, board.size() - 1));
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
setFont(defaultFont);
for(Field field : board){
Point p = field.getLocation();
g2d.drawRect(p.x * SCALE, p.y * SCALE, SCALE, SCALE);
g2d.drawString(field.text, p.x * SCALE + 24, p.y * SCALE + 40);
}
for(Field field : board){
if(field.targetKind() != Kind.NONE){
g2d.setColor(field.targetKind() == Kind.LADDER ? Color.GREEN : Color.RED);
g2d.setStroke(stroke);
Point source = field.getLocation();
Point target = field.getTarget().getLocation();
g2d.drawLine(source.x * SCALE + 40, source.y * SCALE + 24, target.x * SCALE + 40, target.y * SCALE + 24);
}
}
for(Pawn pawn : pawns){
Point loc = board.get(pawn.fieldIndex).getLocation();
g2d.setColor(pawn.color);
g2d.fillOval(loc.x * SCALE + 32, loc.y * SCALE + 32, 16, 16);
}
}
}
class Board implements Iterable<Field>{
private final List<Field> fields = new ArrayList<>();
public Board(int size){
for(int index = 0; index < size * size; index++)
fields.add(new Field(index, size));
}
public Field get(int index){
return fields.get(index);
}
public void connect(int startFieldnumber, int targetFieldnumber){
get(startFieldnumber - 1).setTarget(get(targetFieldnumber - 1));
}
#Override
public Iterator<Field> iterator() {
return fields.iterator();
}
public int size(){
return fields.size();
}
}
class Field{
final int index;
final String text;
final int size;
private Field target;
public Field(int index, int size){
this.index = index;
this.size = size;
text = "" + (index + 1);
}
public void setTarget(Field target){
if(target == this) return;
this.target = target;
}
public Field getTarget(){
return target;
}
public Kind targetKind(){
if(target == null) return Kind.NONE;
return index < target.index ? Kind.LADDER : Kind.SHUTE;
}
public Point getLocation(){
int x = index % size;
int y = index / size;
if(y % 2 != 0) x = size - x - 1;
return new Point(x, size - y - 1);
}
}
class Pawn{
int fieldIndex = 0;
int maxIndex;
Color color;
public Pawn(Color color, int maxIndex){
this.color = color;
this.maxIndex = maxIndex;
}
public void move(int steps){
fieldIndex += steps;
if(fieldIndex < 0) fieldIndex = 0;
if(fieldIndex > maxIndex) fieldIndex = maxIndex;
}
}
enum Kind{
NONE, SHUTE, LADDER
}
}

Why do i get an an error on paint method when the parameters are correct? [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I am facing an issue with the paint method in the below program. The error "void Stage.paint(Graphic g, Point mouseloc)" and the error "paint cannot be resolved to a type". I have inputted the correct parameters and have set the fields and constructors properly. The error are in italics.Sorry i am new to coding and hopefully you can help me
import javax.swing.*;
import java.awt.*;
class Main extends JFrame {
class App extends JPanel {
Stage stage;
public App() {
setPreferredSize(new Dimension(900, 720));
stage = new Stage();
}
#Override
public void paint(Graphics g) {
*stage.paint(g, getMousePosition());*
}
}
public static void main(String[] args) throws Exception {
Main window = new Main();
window.run();
}
private Main() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
App canvas = new App();
this.setContentPane(canvas);
this.pack();
this.setVisible(true);
}
public void run() {
while (true) {
this.repaint();
}
}
}
import java.awt.*;
import java.util.Random;
public class Stage {
Grid grid;
Terrain sand;
Terrain oasis;
Terrain palm_tree;
Terrain wall;
Random RandomNo = new Random();
int number;
public Stage() {
grid = new Grid();
for(int i = 0;i<20;i++)
{
for (int j = 0; j < 20; j++) {
number = 1 + RandomNo.nextInt(10);
if (number <= 4) {
sand = new Sand(grid.cellAtColRow(i, j));
} else if (number == 1) {
oasis = new Oasis(grid.cellAtColRow(i, j));
} else if (number == 2) {
wall = new Wall(grid.cellAtColRow(i, j));
} else if (number == 3) {
palm_tree = new PalmTree(grid.cellAtColRow(i, j));
}
}
}
*public paint(Graphics g, Point mouseLoc){*
grid.paint(g, mouseLoc);
sand.paint(g);
oasis.paint(g);
wall.paint(g);
palm_tree.paint(g);
}
}
}
import java.awt.*;
class Grid {
//fields
Cell[][] cells = new Cell[20][20];
// constructor
public Grid(){
for(int i = 0; i < cells.length; i++){
for(int j = 0; j < cells[i].length; j++){
cells[i][j] = new Cell(10+35*i,10+35*j);
}
}
}
// methods
public void paint(Graphics g, Point mousePos){
for(int i = 0; i < cells.length; i++){
for(int j = 0; j < cells[i].length; j++){
cells[i][j].paint(g, mousePos);
}
}
}
public Cell cellAtColRow(int c, int r){
return cells[c][r];
}
}
import java.awt.*;
class Cell extends Rectangle {
// fields
static int size = 35;
//constructors
public Cell(int x, int y){
super(x,y,size,size);
}
//methods
void paint(Graphics g, Point mousePos){
if(contains(mousePos)){
g.setColor(Color.GRAY);
}
else {
g.setColor(Color.WHITE);
}
g.fillRect(x,y,size,size);
g.setColor(Color.BLACK);
g.drawRect(x,y,size,size);
}
public boolean contains(Point p){
if (p != null){
return super.contains(p);
} else {
return false;
}
}
}
Two problems...
First public paint(Graphics g, Point mouseLoc){ is not a valid declaration, you're missing the return type.
It should be public void paint(Graphics g, Point mouseLoc) {
Second, you have a misplaced }, which means that paint is actually been declared inside the constructor...
public Stage() {
grid = new Grid();
for(int i = 0;i<20;i++)
{
for (int j = 0; j < 20; j++) {
number = 1 + RandomNo.nextInt(10);
if (number <= 4) {
sand = new Sand(grid.cellAtColRow(i, j));
} else if (number == 1) {
oasis = new Oasis(grid.cellAtColRow(i, j));
} else if (number == 2) {
wall = new Wall(grid.cellAtColRow(i, j));
} else if (number == 3) {
palm_tree = new PalmTree(grid.cellAtColRow(i, j));
}
}
}
public paint(Graphics g, Point mouseLoc){
grid.paint(g, mouseLoc);
sand.paint(g);
oasis.paint(g);
wall.paint(g);
palm_tree.paint(g);
}
}
It should be more like...
public Stage() {
grid = new Grid();
for(int i = 0;i<20;i++)
{
for (int j = 0; j < 20; j++) {
number = 1 + RandomNo.nextInt(10);
if (number <= 4) {
sand = new Sand(grid.cellAtColRow(i, j));
} else if (number == 1) {
oasis = new Oasis(grid.cellAtColRow(i, j));
} else if (number == 2) {
wall = new Wall(grid.cellAtColRow(i, j));
} else if (number == 3) {
palm_tree = new PalmTree(grid.cellAtColRow(i, j));
}
}
}
}
public void paint(Graphics g, Point mouseLoc){
grid.paint(g, mouseLoc);
sand.paint(g);
oasis.paint(g);
wall.paint(g);
palm_tree.paint(g);
}

Java - why is the mouseClicked method not permanently resetting variables when it's done being executed?

I have a 2D array of cell objects which contain a String variable for its "tileCode", when I set the active tile code with the keyboard and then click on the desired cell in the 2D array, it should change that cells tileCode to the current active tile. But after I click on the tile, it immediately switches back to its previous tile code and image.
By default, each tile is set to a floor.
public static JFrame frame = new JFrame("Tool");
public static Panel panel;
public Image wall, floor;
public int rows = 50;
public int cols = 50;
public int xCoor = 20;
public int yCoor = 20;
String activeKey = "f";
Image activeImage = floor;
//Arrays
Rectangle[][] recs = new Rectangle[rows][cols];
Cell[][] cells = new Cell[rows][cols];
public Set <Integer> keysDown = new HashSet<>();
public LevelDesignTool() {
loadImages();
panel = new Panel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1400, 1100);
frame.setFocusable(true);
frame.requestFocus();
frame.setVisible(true);
frame.getContentPane().add(panel);
KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.addKeyEventDispatcher(this);
addMouseListener(this);
myThread thread = new myThread();
thread.start();
}
class Panel extends JPanel {
public void paintComponent(Graphics g) {
Graphics2D g2D = (Graphics2D)g;
//Loading array of Tile Types
ArrayList<String> TileTypes = new ArrayList<>();
try {
Scanner TileFileScanner = new Scanner(new File("TileTypes"));
while(TileFileScanner.hasNext()) {
TileTypes.add(TileFileScanner.nextLine());
}
}
catch(FileNotFoundException e) {
System.err.println("Tile Type file not found.");
}
g.setFont(new Font("Italic",Font.PLAIN, 25));
g.drawString("Press Enter to save to file.", 1050, 50);
//Tile Type key on the rigt side of the screen
int y = 550;
for(int i = 0; i < TileTypes.size(); i++) {
g.drawString(TileTypes.get(i), 1050, y);
y += 30;
}
//Creating 2D array of Rectangles
xCoor = 20;
for(int r = 0; r < rows; r++) {
yCoor = 20;
for(int c = 0; c < cols; c++) {
recs[r][c] = new Rectangle(xCoor, yCoor, 18, 18);
yCoor += 19;
}
xCoor += 19;
}
//Creating 2D array of cells
for(int r = 0; r < rows; r++) {
for(int c = 0; c < cols; c++) {
cells[r][c] = new Cell(recs[r][c], "f", activeImage);
xCoor += 21;
}
xCoor = 0;
yCoor += 21;
}
//Drawing cells
for(int r = 0; r < rows; r++) {
for(int c = 0; c < cols; c++) {
g.fillRect((int)cells[r][c].r.getX(), (int)cells[r][c].r.getY(), (int)cells[r][c].r.getWidth(), (int)cells[r][c].r.getHeight());
g.setColor(Color.BLACK);
}
}
//Drawing the images stored in each cell object
for(int r = 0; r < rows; r++) {
for(int c = 0; c < cols; c++) {
cells[r][c].image = floor;
g.drawImage(cells[r][c].getImage(), cells[r][c].getX(), cells[r][c].getY(), this);
}
}
addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
for(int r = 0; r < rows; r++) {
for(int c = 0; c < cols; c++) {
if (cells[r][c].getRect().contains(e.getX(), e.getY())) {
cells[r][c].tileCode = activeKey;
cells[r][c].image = activeImage;
//System.out.println("click registered");
}
}
}
}
});
}
}
//Must have these implemeted because they are from an interface
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
#Override
public void mousePressed(MouseEvent e) {}
#Override
public void mouseReleased(MouseEvent e) {}
public void update() throws Exception {
//System.out.println(cells[0][0].getTileCode());
//System.out.println(activeKey);
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if(event.getID() == KeyEvent.KEY_PRESSED){
keysDown.add(event.getKeyCode());
if(event.getKeyCode() == KeyEvent.VK_F) {
activeKey = "f";
activeImage = floor;
}
if(event.getKeyCode() == KeyEvent.VK_E) {
activeKey = "e";
}
if(event.getKeyCode() == KeyEvent.VK_W) {
activeKey = "w";
activeImage = wall;
}
}
if(event.getID() == KeyEvent.KEY_RELEASED)
keysDown.remove(event.getKeyCode());
return false;
}
class myThread extends Thread {
public void run() {
while(true) {
try {
Thread.sleep(15);
frame.repaint();
update(); //update any game state changes for the next frame
}
catch(Exception e) {
System.out.println(e);
}
}
}
}
private void loadImages() {
floor = new ImageIcon("images/Floor.png").getImage();
wall = new ImageIcon("images/Wall.png").getImage();
}
//Runs code
public static void main(String[] args) {
new LevelDesignTool();
}
}
once I click on a cell, its image should change to the active image and the tile code should change to the active tile code.
problem is that you are initializing your data (and adding a new mouseListener) on every call to paintComponent. That resets all the data to "floor" every time it repaints, which overrides any change you made in the mouse listener. Also, notice that in your "Drawing cells" loop, you reset the image to floor (cells[r][c].image = floor;) just before you draw it. This again resets the data you set in your mouse listener.
The solution is to move your mouseListener and your initialization code into a constructor for Panel, like this:
class Panel extends JPanel {
ArrayList<String> TileTypes = new ArrayList<String>();
public Panel() {
//Loading array of Tile Types
try {
Scanner TileFileScanner = new Scanner(new File("TileTypes"));
while(TileFileScanner.hasNext()) {
TileTypes.add(TileFileScanner.nextLine());
}
} catch(FileNotFoundException e) {
System.err.println("Tile Type file not found.");
}
//Creating 2D array of Rectangles
xCoor = 20;
for(int r = 0; r < rows; r++) {
yCoor = 20;
for(int c = 0; c < cols; c++) {
recs[r][c] = new Rectangle(xCoor, yCoor, 18, 18);
yCoor += 19;
}
xCoor += 19;
}
//Creating 2D array of cells
for(int r = 0; r < rows; r++) {
for(int c = 0; c < cols; c++) {
cells[r][c] = new Cell(recs[r][c], "f", activeImage);
cells[r][c].image = floor;
xCoor += 21;
}
xCoor = 0;
yCoor += 21;
}
addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
for(int r = 0; r < rows; r++) {
for(int c = 0; c < cols; c++) {
if (cells[r][c].getRect().contains(e.getX(), e.getY())) {
cells[r][c].tileCode = activeKey;
cells[r][c].image = activeImage;
//System.out.println("click registered");
}
}
}
}
});
}
public void paintComponent(Graphics g) {
Graphics2D g2D = (Graphics2D)g;
g.setFont(new Font("Italic",Font.PLAIN, 25));
g.drawString("Press Enter to save to file.", 1050, 50);
//Tile Type key on the rigt side of the screen
int y = 550;
for(int i = 0; i < TileTypes.size(); i++) {
g.drawString(TileTypes.get(i), 1050, y);
y += 30;
}
//Drawing cells
for(int r = 0; r < rows; r++) {
for(int c = 0; c < cols; c++) {
g.fillRect((int)cells[r][c].r.getX(), (int)cells[r][c].r.getY(),
(int)cells[r][c].r.getWidth(), (int)cells[r][c].r.getHeight());
g.setColor(Color.BLACK);
}
}
//Drawing the images stored in each cell object
for(int r = 0; r < rows; r++) {
for(int c = 0; c < cols; c++) {
g.drawImage(cells[r][c].getImage(), cells[r][c].getX(), cells[r][c].getY(), this);
}
}
}
}
Also, not part of your question, but you are discarding the interrupted exception in your thread. Do this instead:
public void run() {
while (!Thread.interrupted()) {
try {
Thread.sleep(15);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}

Game Of Life Java MouseAdapter doesn't always work

Sometimes the mousePressed event gets executed , but at other times it won't. It also seems to depend on the time you press it. How do I get it to ALWAYS work?
I'm not sure which part of the code is faulty, so here's the whole class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Board extends JPanel implements ActionListener {
Timer timer = new Timer(500, this);
private boolean[][] board;
private boolean isActive = false;
private int height;
private int width;
private int multiplier = 20;
private JButton btnRun;
private JButton btnRand;
private JButton btnClear;
public Board() {
this(new boolean[20][20]);
}
public Board(final boolean[][] board) {
this.board = board;
height = board.length;
width = board[0].length;
setBackground(Color.black);
btnRun = new JButton("Run");
add(btnRun);
btnRun.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
isActive = !isActive;
btnRun.setText(isActive ? "Pause" : "Run");
}
});
btnRand = new JButton("Random");
add(btnRand);
btnRand.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setBoard(randomBoard());
}
});
btnClear = new JButton("Clear");
add(btnClear);
btnClear.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setBoard(clearBoard());
}
});
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
getBoard()[e.getY() / multiplier][e.getX() / multiplier] = !getBoard()[e.getY() / multiplier][e.getX() / multiplier];
}
});
timer.start();
}
public int getMultiplier() {
return multiplier;
}
public boolean[][] getBoard() {
return board;
}
public void setBoard(boolean[][] boardToSet) {
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
board[i][j] = boardToSet[i][j];
}
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
g.setColor(board[i][j] ? Color.green : Color.gray);
g.fillRect(j * multiplier, i * multiplier, multiplier - 1, multiplier - 1);
}
}
if (isActive) {
timer.start();
}
else {
timer.stop();
repaint();
}
}
public void actionPerformed(ActionEvent e) {
board = nextGeneration();
repaint();
}
public boolean[][] randomBoard() {
Random rand = new Random();
boolean[][] randBoard = new boolean[height][width];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
randBoard[i][j] = rand.nextBoolean();
}
}
return randBoard;
}
public boolean[][] clearBoard() {
boolean[][] emptyBoard = new boolean[height][width];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
emptyBoard[i][j] = false;
}
}
return emptyBoard;
}
public int countSurrounding(int a, int b) {
int count = 0;
int[][] surrounding = {{a - 1, b - 1},
{a - 1, b },
{a - 1, b + 1},
{a , b - 1},
{a , b + 1},
{a + 1, b - 1},
{a + 1, b },
{a + 1, b + 1}};
for (int[] i: surrounding) {
try {
if (board[i[0]][i[1]]) {
count++;
}
}
catch (ArrayIndexOutOfBoundsException e) {}
}
return count;
}
public boolean[][] nextGeneration() {
boolean[][] nextBoard = new boolean[height][width];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
nextBoard[i][j] = board[i][j];
}
}
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
if (board[i][j] && !(countSurrounding(i, j) == 2 || countSurrounding(i, j) == 3)) {
nextBoard[i][j] = false;
}
else if (!board[i][j] && countSurrounding(i, j) == 3) {
nextBoard[i][j] = true;
}
}
}
return nextBoard;
}
}
Add a System.out statement in mousePressed() and you will see that it is always called:
public void mousePressed(MouseEvent e) {
System.out.println("mousePressed");
getBoard()[e.getY() / multiplier][e.getX() / multiplier] = !getBoard()[e.getY() / multiplier][e.getX() / multiplier];
repaint();
}
Like others suggested in your other very similar question, the problem stems from your use of timers in your paint method.
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
g.setColor(board[i][j] ? Color.green : Color.gray);
g.fillRect(j * multiplier, i * multiplier, multiplier - 1, multiplier - 1);
}
}
//if (isActive) { // take this stuff out...
// timer.start();
//}
//else {
// timer.stop();
// repaint();
//}
}
The paintComponent() method should be used to draw your components only. Do not use it to start/stop timers, make additional calls to repaint(), or otherwise call any other kind of program logic. Rethink your design, especially in paintComponent().
In addition to what whiskeyspider said, if you click on a cell while it's running, you won't see the cell light up until the next generation, and only if that position is considered alive, after processing, in the next generation.

Processing. Even though the array content has changed, what is being drawn with draw() method doesn't change

constants
public final int DIMENSIONS = 4;
public final int MOVE_RIGHT = 1;
public final int MOVE_LEFT = 2;
public final int MOVE_UP = 3;
public final int MOVE_DOWN = 4;
main
PuzzleFrame board;
void setup(){
size(401,401);
board = new PuzzleFrame();
background(100);
}
void draw(){
background(100);
board.draw();
}
void keyPressed()
{
if(key == CODED)
{
if(keyCode == RIGHT) board.moveTile(MOVE_RIGHT);
if(keyCode == LEFT) board.moveTile(MOVE_LEFT);
if(keyCode == UP) board.moveTile(MOVE_UP);
if(keyCode == DOWN) board.moveTile(MOVE_DOWN);
}
}
class that creates puzzle frame
class PuzzleFrame{
private Tile[][] puzzleFrame;
private Tile[][] solvedPuzzleFrame;
public PuzzleFrame()
{
puzzleFrame = new Tile[DIMENSIONS][DIMENSIONS];
solvedPuzzleFrame = new Tile[DIMENSIONS][DIMENSIONS];
int tileNumber = 1;
for(int i = 0; i < DIMENSIONS; i++)
{
for(int j = 0; j < DIMENSIONS; j++)
{
puzzleFrame[i][j] = new Tile(tileNumber, j*100, i*100);
solvedPuzzleFrame[i][j] = new Tile(tileNumber, j*100, i*100);
tileNumber++;
}
}
}
public void draw()
{
for(int i = 0; i < DIMENSIONS; i++)
{
for(int j = 0; j < DIMENSIONS; j++)
{
puzzleFrame[i][j].draw();
}
}
}
public void moveTile(int side)
{
if(isMoveAllowed(side))
{
switch(side)
{
case MOVE_RIGHT:
{
for(int i = 0; i < DIMENSIONS; i++)
{
for(int j = 0; j < DIMENSIONS; j++)
{
if(puzzleFrame[i][j].getTileNumber() == DIMENSIONS*DIMENSIONS)
{
Tile tempTile = puzzleFrame[i][j];
puzzleFrame[i][j] = puzzleFrame[i][j-1];
puzzleFrame[i][j-1] = tempTile;
System.out.println("right");
break;
}
}
}
break;
}
}
}
}
private boolean isMoveAllowed(int side)
{
switch(side)
{
case MOVE_RIGHT:
{
for(int i = 0; i < DIMENSIONS; i++)
{
for(int j = 0; j < DIMENSIONS; j++)
{
if(puzzleFrame[i][j].getTileNumber() == DIMENSIONS*DIMENSIONS)
{
if(j > 0) return true;
}
}
}
break;
}
}
return false;
}
}
tile class which is used for to create puzzle Frame
class Tile{
private final int mTileNumber;
private final int width = 100;
private final int height = 100;
private String number = "";
private int xpos;
private int ypos;
private int xOffSet;
private int yOffSet;
public Tile(int tileNumber, int xpos, int ypos)
{
mTileNumber = tileNumber;
number += tileNumber;
textSize(64);
this.xpos = xpos; this.ypos = ypos;
xOffSet = 30;
yOffSet = 70;
if(mTileNumber >= 10)
{
xOffSet = 10;
}
}
public void draw()
{
if(mTileNumber == DIMENSIONS*DIMENSIONS)
{
}
else
{
strokeWeight(2);
fill(255);
rect(xpos, ypos, width, height);
fill(0);
text(number, xpos+xOffSet, ypos+yOffSet);
}
}
public int getTileNumber()
{
return mTileNumber;
}
}
I'm trying to make 15 puzzle game but the problem that I came across is that when I press arrow key RIGHT, contents of the puzzleFrame array change (I checked it in Eclipse via debugger) but in processing the image drawn remains the same. For now my code only consists of a function that allows to slide tile to the right. I honestly don't understand why the image remains the same even though the contents of the array have changed.
I know this doesn't answer your question but how are you avoiding a compiler error in your Tile class during the assignment: mTileNumber = tileNumber
You declared mTileNumber as a final variable so you shouldn't be able to reassign it to anything.

Categories