How to "paint" a grid of JLabels with mouseDragged event? - java

I'm currently trying to reproduce the Game of Life. The implementation is done, but I want to add a painting mode. If this mode is activated the user should be able to turn every dead cell the mouse is currently on into a living one by dragging their mouse over them (dragging, not clicking, just like drawing something in Paint). Each JLabel-object on the grid represents one cell. The state of the cell is determined by its color. I got the paint-mode to work, but it only works when I start dragging the mouse on the background of the JPanel, if I start doing it on a JLabel, it does nothing. Should I perhaps use something else than a JPanel? Here is my code so far (CellLabel inherits from JLabel):
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.Random;
public class CellLabelGrid extends JPanel {
private final CellGrid cellGrid;
private final CellLabel[][] cellLabels;
private Color aliveColor;
private Color deadColor;
public CellLabelGrid(Game game, int rows, int cols) {
initializeColors();
this.cellGrid = new CellGrid(rows, cols);
this.cellLabels = new CellLabel[rows][cols];
this.setLayout(new GridLayout(rows, cols));
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
CellLabel cellLabel = new CellLabel(game, cellGrid.getCellAtIndex(i, j), aliveColor, deadColor);
cellLabels[i][j] = cellLabel;
this.add(cellLabel);
}
}
this.setBackground(Color.WHITE);
this.setPreferredSize(new Dimension(rows * 50, cols * 50));
MouseMotionListener mouseMotionListener = new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent e) {
int mouseX = e.getX();
int mouseY = e.getY();
if (game.getGameMode().equals(Mode.PAINT)) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (mouseX >= cellLabels[i][j].getX() && mouseX <= cellLabels[i][j].getX() + cellLabels[i][j].getWidth() && mouseY >= cellLabels[i][j].getY() && mouseY <= cellLabels[i][j].getY() + cellLabels[i][j].getHeight()) {
if (cellLabels[i][j].getBackground().equals(deadColor)) {
cellLabels[i][j].setBackground(aliveColor);
cellLabels[i][j].getCell().setState(CellState.ALIVE);
}
}
}
}
}
}
#Override
public void mouseMoved(MouseEvent e) {
}
};
this.addMouseMotionListener(mouseMotionListener);
this.setVisible(true);
}
public CellGrid getCellGrid() {
return cellGrid;
}
public CellLabel[][] getCellLabels() {
return cellLabels;
}
private void initializeColors() {
Random rand = new Random();
float r = rand.nextFloat();
float g = rand.nextFloat();
float b = rand.nextFloat();
aliveColor = new Color(r, g, b);
float r2 = rand.nextFloat();
float g2 = rand.nextFloat();
float b2 = rand.nextFloat();
deadColor = new Color(r2, g2, b2);
}
public Color getAliveColor() {
return aliveColor;
}
public Color getDeadColor() {
return deadColor;
}
}

Related

Java why does cell keep changing colors

Hello sorry I'm very weak in programming.
I'm trying to make my Box each a different shade of green. However, when I implement my code it keeps changing colors even when my box loop is finished.
The finished product is suppose to be a tetris with boxes that have different color of green.
So tetris class creates a lot of boxes in a array .
The method for the tetris is to create each box having its unique position of i and j
import javax.swing.*;
import java.awt.*;
class Main extends JFrame {
class App extends JPanel {
Grid grid;
public App() {
setPreferredSize(new Dimension(900, 720));
grid = new Grid();
}
#Override
public void paint(Graphics g) {
grid.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.*;
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);
}
}
}
}
import java.awt.*;
import java.util.Random;
class Cell extends Rectangle {
// fields
int random_int;
int minyellow = 50;
int maxyellow = 100;
static int size = 35;
//constructors
public Cell(int x, int y){
super(x,y,size,size);
}
//methods
void paint(Graphics g, Point mousePos){
int random_int = (int)(Math.random() * (maxyellow - minyellow + 1) + minyellow);
this.random_int=random_int;
if(contains(mousePos)){
g.setColor(Color.GRAY);
}
else {
g.setColor(Color.getHSBColor(255, random_int, 60));
}
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;
}
}
}
A problem in your code is that you pick the random number for your colour inside Cell's paint method, so every time it is painted, it gets a new random colour.
For a cell to have a stable colour, the simplest fix is to set random_int once, in the constructor, and not update it.
public Cell(int x, int y) {
super(x, y, size, size);
random_int = (int) (Math.random() * (maxyellow - minyellow + 1) + minyellow);
}
void paint(Graphics g, Point mousePos) {
if (contains(mousePos)) {
g.setColor(Color.GRAY);
}
else {
g.setColor(Color.getHSBColor(255, random_int, 60));
}
g.fillRect(x,y,size,size);
g.setColor(Color.BLACK);
g.drawRect(x,y,size,size);
}

Change color of rectangle in grid

I need help changing the color of a rectangle in a grid. So far, I have the rectangles and the grid (which are lines drawn separating the rectangles), and I want to change the color of a single rectangle when it's clicked.
I added the line "System.out.println("Something")" in the loop where the color is supposed to change, and it always returns "Something." That's why I'm confused. Thanks for any and all help!
Class Grid:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import javax.swing.Timer;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Grid extends JPanel{
private int a = 50;
private int b = 50;
private Lifeform[][] Life;
private boolean[][]life = new boolean[a][b];
private Timer t;
Grid(){
//creates grid of rectangles
Life = new Lifeform[a][b];
int ypos = 0;
for(int i = 0; i < Life.length; i++){
int xpos = 0;
for(int j = 0; j < Life[0].length; j++){
Rectangle r = new Lifeform();
r.setBounds(xpos, ypos, 50, 50);
Life[i][j] = (Lifeform) r;
xpos += 50;
}
ypos += 50;
}
t = new Timer(64, new Movement());
this.addMouseListener(new mouse());
}
public void paintComponent(Graphics g){
for(Lifeform[] n : Life){
//makes rectangles white
g.fillRect(this.getX(), this.getY(), this.getWidth(), this.getHeight());
g.setColor(Color.white);
}
for (int i = 0; i <= 25; i++){
g.drawLine(0, 50*i, 1500, 50*i);
g.setColor(Color.black);
}
for (int i = 0; i <= 25; i++){
g.drawLine(50*i, 0, 50*i, 750);
g.setColor(Color.black);
}
}
private JFrame createGrid(){
JFrame frame = new JFrame("Alveolate");
frame.add(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(700,700);
frame.setVisible(true);
return frame;
}
public class mouse implements MouseListener{
//colors rectangles (it doesn't work)
public void mouseClicked(MouseEvent e) {
Point p = new Point(e.getX(),e.getY());
for(int i = 0; i < Life.length; i++){
for(int j = 0; j < Life[i].length; j++){
Lifeform spot = Life[i][j];
if (spot.contains(p)){
spot.setColor(Color.red);
System.out.println("Something");
}
}
}
}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}
public class Movement implements ActionListener{
public void actionPerformed ( ActionEvent e ){
for (int i = 0; i < Life.length; i++){
for (int j = 0; j < Life[i].length; j++){
if(Life[i][j].getColor().equals(Color.black)){
life[i][j] = true;
}
else{
life[i][j] = false;
}
}
}
repaint();
}
}
public void startTimer(){
t.start();
}
public void stopTimer(){
t.stop();
}
public static void main(String[] args) {
Grid ABC = new Grid();
ABC.createGrid();
ABC.startTimer();
}
}
Class Lifeform:
import java.awt.Color;
import java.awt.Rectangle;
public class Lifeform extends Rectangle {
private Color c;
public Lifeform() {
c = Color.WHITE;
}
public Color getColor() {
return c;
}
public boolean setColor( Color c ) {
boolean rtn = false;
if( c != null ) {
this.c = c;
rtn = true;
}
return rtn;
}
}
try
for(Lifeform[] n : Life){
for(Lifeform lf : n){
g.setColor(lf.getColor());
g.fillRect((int)lf.getX(), (int)lf.getY(), (int)lf.getWidth(), (int)lf.getHeight());
}
}
in your paintComponent method
try this:
for(int i = 0; i < 50; i++){
for(int j = 0; j < 50; j++){
....
}
}
Didn't read all you code but it seems like you definitely set the color of your Lifeform to red. This means that your rendering code never actually uses this fact to display that Lifeform. It seems like the only time you draw your rectangles is in paintComponent. This paint needs to be called each time you want a redraw to happen. You can use repaint on your JFrame or JPanel to get this to happen. Also, the render code you have there seems to only ever display white rectangles
g.fillRect(this.getX(), this.getY(), this.getWidth(), this.getHeight());
g.setColor(Color.white);
This is in a loop through your Lifeform[][]. Instead you should probably have a double for loop to get every Lifeform and use the x and y and color from that to draw. Something like:
g.fillRect(Life[i][j].getX(), Life[i][j].getY(), ..., ..., Life[i][j].getColor())
Also, Life should be named life with a lowercase 'l'. It's way confusing seeing names without conventions.

JPanel creates twice

I am trying to make a GUI for a battleship game. One class is for creating the GUI itself and a second class is on top of it to manage the board in the game. My problem is that the JPanel creates twice once a mouse click happens (the mouse click is supposed to be where one is firing in the game and then marks that as a hit/miss). I'm not sure why it is creating twice. Is it because of the passing of a panel? Code below and a photo of what the code generates.
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class BattleshipApplet extends JApplet implements MouseListener {
private final JButton playButton = new JButton("Play");
private final JLabel msgBar = new JLabel("Click Play to start game");
private BoardPanel panel;
public BattleshipApplet(){
playButton.addActionListener(this::playButtonClicked);
addMouseListener(this);
}
public void init(){
configureGui();
}
private void configureGui(){
setLayout(new BorderLayout());
JPanel buttons = new JPanel(new FlowLayout(FlowLayout.LEFT));
buttons.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
buttons.add(playButton);
add(buttons, BorderLayout.NORTH);
msgBar.setBorder(BorderFactory.createEmptyBorder(10,10,5,5));
add(createBoardPanel(), BorderLayout.CENTER);
add(msgBar, BorderLayout.SOUTH);
}
private BoardPanel createBoardPanel(){
panel = new BoardPanel();
return panel;
}
private void displayMessage(String msg){
msgBar.setText(msg);
}
private void playButtonClicked(ActionEvent event){
displayMessage("Play button clicked!");
}
public void mouseClicked(MouseEvent e) {
panel.mouseClickedAt(e.getX(), e.getY());
e.consume();
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
}
The board class using JPanel
[![import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class BoardPanel extends JPanel {
int mx, my;
boolean rect1Clicked;
//gamePlay a;
public void init(){
rect1Clicked = false;
}
/***Your applet shall show the status of the board before and after
each shot, including the number of shots made and the status of
each place (no shot or hit/miss shot). ***/
public void paint(Graphics g){
boolean miss = false;
for (int i=0; i<11; i++){
g.setColor(Color.blue);
g.drawLine(20,20+i*28, 300, 20+i*28);
}
for (int i=0; i<11; i++)
g.drawLine(20+i*28,20,20+i*28,300);
//if inside board
if(rect1Clicked == true){
g.setColor(Color.green);
//aligns to square to check in computer board for hit/miss
int bx =(my-20)/28;
int by =(mx-20)/28;
//check hit on board
//if shot was a miss
if(miss == true ){
//update to white
g.setColor(Color.white);
}
//if shot was a hit
if(miss == false){
//update to red
g.setColor(Color.red);
}
//compare to line for fill
int fillx = mx/2;
int filly = my/2 ;
if(mx<=47){
fillx = 20;
}
if(mx>47 && mx<=75){
fillx = 48;
}
if(mx>75 && mx<=103){
fillx = 76;
}
if(mx>103 && mx <=131){
fillx = 104;
}
if(mx>131 && mx<=159){
fillx = 132;
}
if(mx>159 && mx<=187){
fillx = 160;
}
if(mx>187 && mx <=215){
fillx = 188;
}
if(mx>215 && mx <=243){
fillx = 216;
}
if(mx>243 && mx <=271){
fillx = 244;
}
if(mx>271 && mx<=299){
fillx = 272;
}
if(mx>299){
fillx = 300;
}
//y comparisons
if(my<=47){
filly = 20;
}
if(my>47 && my<=75){
filly = 48;
}
if(my>75 && my<=103){
filly = 76;
}
if(my>103 && my <=131){
filly = 104;
}
if(my>131 && my<=159){
filly = 132;
}
if(my>159 && my<=187){
filly = 160;
}
if(my>187 && my <=215){
filly = 188;
}
if(my>215 && my <=243){
filly = 216;
}
if(my>243 && my <=271){
filly = 244;
}
if(my>271 && my<=299){
filly = 272;
}
if(my>299){
filly = 300;
}
g.drawString("("+mx+","+my+")",mx,my);
//25 describes size of square
g.fillOval(fillx, filly, 25, 25);
}
}
public void game(BoardPanel p){
//while game plays
}
public void mouseClickedAt(int x, int y){
mx = x;
my = y;
//user clicked inside of board space
if(mx>20 && mx<300 && my>20 && my<300){
//send to board in MainBattleship
rect1Clicked = true;
}
//updates board
repaint();
}
}][1]][1]
I am so lost, thank you for any help!
Suggestions:
Don't override a JPanel's paint method but rather its paintComponent method as this is safer, and later when you want to do animation, will result in smoother animation.
Most important you almost always need to call the super's painting method within your own, else the JPanel will not remove previous image artifacts that need to be cleaned up. So if you continue to override paint (although I recommend against, this) the first line of your override should be super.paint(g);, or if you override paintComponent then the first line should be super.paintComponent(g);, of course assuming that you're methods use a Graphics parameter named g.
Also, add the MouseListener to the JPanel, not to the applet, since it is the mouse click location on the panel that matters to you.
Also, use a grid of components or some math to greatly simplify your code -- that ugly list of if blocks should be replaced by a much simpler for loop, one using basic math.
Consider extracting that logic discussed in the point above out of your painting method and into a model of some kind, perhaps a 2D array of boolean.
You're using a lot of "magic" numbers in your code, numbers that should be changed to a combination of constants and mathematically derived numbers.
Notice what happens if you click on your GUI, and then resize it, or if you minimize and then restore it -- you lose all red circles except for the last one pressed. This is another reason to use a grid of boolean or other model to hold state of the game, and then use this model when drawing your GUI.
On further thinking, you might want a 2D array of an enum or an int array, since the grid cell state will likely be more than 2 values (true or false), but rather will be three values -- untested, hit, and miss, and you'll likely want to fill your oval with red if a hit or white if a miss.
For example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import javax.swing.*;
public class GridExample {
private static void createAndShowGui() {
final GridPanel gridPanel = new GridPanel();
JButton resetBtn = new JButton(new AbstractAction("Reset") {
#Override
public void actionPerformed(ActionEvent e) {
gridPanel.reset();
}
});
JPanel btnPanel = new JPanel();
btnPanel.add(resetBtn);
JFrame frame = new JFrame("GridExample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(gridPanel);
frame.getContentPane().add(btnPanel, BorderLayout.PAGE_END);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class GridPanel extends JPanel {
private static final int ROWS = 10;
private static final int CELL_WIDTH = 28;
private static final int PAD = 20;
private static final int PREF_W = ROWS * CELL_WIDTH + 2 * PAD;
private static final int PREF_H = PREF_W;
private static final Color GRID_COLOR = Color.blue;
private static final Color CIRCLE_COLOR = Color.red;
private static final int SML_GAP = 2;
private boolean[][] grid = new boolean[ROWS][ROWS];
public GridPanel() {
addMouseListener(new MyMouse());
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
public void reset() {
grid = new boolean[ROWS][ROWS]; // fills grid with false
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// draw grid:
g2.setColor(GRID_COLOR);
for (int i = 0; i <= ROWS; i++) {
int x1 = PAD + i * CELL_WIDTH;
int y1 = PAD;
int x2 = x1;
int y2 = PAD + CELL_WIDTH * ROWS;
g2.drawLine(x1, y1, x2, y2);
g2.drawLine(y1, x1, y2, x2);
}
// iterate through the grid boolean array
// draw red circles if the grid value is true.
g2.setColor(CIRCLE_COLOR);
int w = CELL_WIDTH - 2 * SML_GAP; // width of the circle to draw
int h = w;
// nested for loop to go through the grid array
for (int r = 0; r < grid.length; r++) {
for (int c = 0; c < grid[r].length; c++) {
if (grid[r][c]) {
int x = PAD + c * CELL_WIDTH + SML_GAP;
int y = PAD + r * CELL_WIDTH + SML_GAP;
g2.fillOval(x, y, w, h);
}
}
}
}
private class MyMouse extends MouseAdapter {
public void mousePressed(MouseEvent e) {
int x = e.getPoint().x;
int y = e.getPoint().y;
if (x < PAD || y < PAD) {
// clicked above or to right of grid
return;
}
int r = (y - PAD) / CELL_WIDTH;
int c = (x - PAD) / CELL_WIDTH;
// if clicked to right or below grid.
// the < 0 part is likely unnecessary, but why not be extra safe?
if (r >= ROWS || c >= ROWS || r < 0 || c < 0) {
return;
}
grid[r][c] = true;
repaint();
}
}
}

repaint() doesn't repaint on call?

I'm trying to make a match 3 game. I am trying to create some visual aid to what is actually happening by first marking the gems that need to be deleted "black", and after that letting gravity do it's job. I'm struggling to do this, I called repaint(); after I marked them "black", but it doesn't seem to work. I also tried adding in revalidate(); as suggested in another question but that doesn't seem to fix the problem either. Here's the piece of code that's troubling me.
Trouble code:
public void deletePattern(Set<Gem> gemsToDelete){
for(Gem gem : gemsToDelete)
gem.setType(7);
repaint(); //This doesn't seem to work
doGravity();
switchedBack = true;
checkPattern();
}
I want to repaint the board before doGravity() and after the enhanced for loop. Could it be that I'm not using the thread correctly in the doGravity() method?
Here's the full code:
Board.java
package Game;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.LinkedHashSet;
import java.util.Set;
public class Board extends JPanel{
final int BOARDWIDTH = 8;
final int BOARDHEIGHT = 8;
private static final Color COLORS[] = { new Color(255, 0, 0), new Color(255, 128, 0), new Color(255, 255, 0), new Color(0, 255, 0), new Color(0, 255, 255), new Color(0, 0, 255), new Color(127, 0, 255), new Color(0, 0, 0), new Color(0, 0, 0), new Color(255, 255, 255)};
boolean isAlive, isPattern, switchedBack;
boolean isFirstSelected = false;
Gem[][] gems;
int fromX, fromY, toX, toY;
public Board() {
gems = new Gem[BOARDWIDTH][BOARDHEIGHT];
addMouseListener(new MouseInputAdapter());
}
int cellWidth() { return (int) getSize().getWidth() / BOARDWIDTH; }
int cellHeight() { return (int) getSize().getHeight() / BOARDHEIGHT; }
public void start(){
isPattern = switchedBack = false;
isAlive = true;
fillBoard();
checkPattern();
switchedBack = false;
}
public void paint(Graphics g) {
super.paint(g);
for (int x = 0; x < BOARDWIDTH; x++) {
for (int y = 0; y < BOARDHEIGHT; y++)
drawCell(g, x, y, gems[x][y]);
}
}
public void fillBoard(){
for (int x = 0; x < BOARDWIDTH; x++) {
for (int y = 0; y < BOARDHEIGHT; y++)
gems[x][y] = new Gem();
}
}
public void drawCell(Graphics g, int x, int y, Gem gem) {
x = x * cellWidth();
y = y * cellHeight();
g.setColor(COLORS[gem.getType()]);
g.fillRect(x, y, x + cellWidth(), y + cellHeight());
}
class MouseInputAdapter extends MouseAdapter { #Override public void mouseClicked(MouseEvent e) { selectGems(e); } }
public void selectGems(MouseEvent e){
int x = e.getX() / cellWidth();
int y = e.getY() / cellHeight();
if(!isFirstSelected) {
fromX = x;
fromY = y;
isFirstSelected = true;
}else{
toX = x;
toY = y;
if((Math.abs(fromX - toX) == 1 ^ Math.abs(fromY - toY) == 1) & (gems[fromX][fromY].getType() != gems[toX][toY].getType())) {
switchGems();
isFirstSelected = false;
}
}
}
public void switchGems(){
int tempType = gems[fromX][fromY].getType();
gems[fromX][fromY].setType(gems[toX][toY].getType());
gems[toX][toY].setType(tempType);
checkPattern();
switchedBack = false;
repaint();
}
public void checkPattern() {
Set<Gem> gemsToDelete = new LinkedHashSet<>();
isPattern = false;
for (int x = 0; x < BOARDWIDTH; x++) {
for (int y = 0; y < BOARDHEIGHT; y++) {
if (x + 2 < BOARDWIDTH && (gems[x][y].getType() == gems[x + 1][y].getType()) && (gems[x + 1][y].getType() == gems[x + 2][y].getType())) { //Checks for 3 horizontal gems in a row
isPattern = true;
gemsToDelete.add(gems[x][y]);
gemsToDelete.add(gems[x + 1][y]);
gemsToDelete.add(gems[x + 2][y]);
}
if (y + 2 < BOARDHEIGHT && (gems[x][y].getType() == gems[x][y + 1].getType()) && (gems[x][y + 1].getType() == gems[x][y + 2].getType())) { //Check for 3 vertical gems in a row
isPattern = true;
gemsToDelete.add(gems[x][y]);
gemsToDelete.add(gems[x][y + 1]);
gemsToDelete.add(gems[x][y + 2]);
}
}
}
if(!gemsToDelete.isEmpty())
deletePattern(gemsToDelete);
if(!isPattern && !switchedBack){
switchedBack = true;
switchGems();
}
}
public void deletePattern(Set<Gem> gemsToDelete){
for(Gem gem : gemsToDelete)
gem.setType(7);
repaint(); //This doesn't seem to work
doGravity();
switchedBack = true;
checkPattern();
}
public void doGravity(){
try{
Thread.sleep(1000);
}catch(InterruptedException e){e.printStackTrace();}
for (int y = 0; y < BOARDHEIGHT; y++) {
for (int x = 0; x < BOARDWIDTH; x++) {
if(gems[x][y].getType() == 7){
for (int i = y; i >= 0; i--) {
if(i == 0)
gems[x][i].setType(gems[x][i].genType());
else
gems[x][i].setType(gems[x][i-1].getType());
}
}
}
}
}
}
Gem.java
package Game;
public class Gem {
private int type;
public Gem(){
this.type = genType();
}
public int genType(){
return (int) (Math.random() * 7);
}
public void setType(int type){
this.type = type;
}
public int getType(){
return type;
}
}
Game.java
package Game;
import javax.swing.*;
public class Game extends JFrame{
public Game(){
Board board = new Board();
getContentPane().add(board);
board.start();
setTitle("Game");
setSize(600, 600);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
public static void main(String[] args){
Game game = new Game();
game.setLocationRelativeTo(null);
game.setVisible(true);
}
}
Your code is initiated via a mouse click. Code invoked from a Swing listener is executed on the Event Dispatch Thread (EDT), which is also responsible for painting the GUI
The Thread.sleep() in your doGravaity() method causes the EDT to sleep, therefore the GUI can't repaint() itself until the whole looping code is finished, at which point it will just paint the final state of your animation.
Instead of sleeping, you need to use a Swing Timer to schedule animation. So basically, in the deletePattern() method you would start the Timer to do the gravity animation. This will free up the EDT to repaint itself and when the Timer fires you would animate your components one move and then do repaint() again. When the components are finished moving you stop the timer.
Read the section from the Swing tutorial on Concurrency for more information about the EDT.
Call this.invalidate() or this.postInvalidate() which then forces a repaint.

how can i use an array to make random circles

I have been working on a school assignment and the teacher wants us to make 7 circles appear on a JPanel and move downwards. Once a circle reaches the bottom a new circle should be made to replace the circle that reached the bottom of the JPanel. I decided to use an array to continue to make random circles but I cant get it to work right. I used a for loop to populate the array with circles that have a random radius and color. The code compiles but when I run it I get an exception. I am having a hard time getting the array to work properly. The other thing that I am not sure about is how to draw the circles so that they are space out across the JPanel.
The Code
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.Random;
public class keyExample extends JPanel implements ActionListener, KeyListener {
private Circle[] circles = new Circle[7];
Timer t = new Timer(5, this);
//current x and y
double x = 150, y = 200;
double changeX = 0, changeY = 0;
private Circle;
private int circlex = 0, circley = 0; // makes initial starting point of circles 0
private javax.swing.Timer timer2;
public keyExample() {
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
timer2 = new javax.swing.Timer(33, new MoveListener());
timer2.start();
}
public void NewCircle() {
Random colors = new Random();
Color color = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));
Random num = new Random();
int radius = num.nextInt(45);
for (int i = 0; i < circles.length; i++) {
circles[i] = new Circle(circlex, circley, radius, color);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLUE);
g2.fill(new Rectangle2D.Double(x, y, 40, 40));
NewCircle();
for (int i = 0; i < circles.length; i++)
circles[i].fill(g);
}
public void actionPerformed(ActionEvent e) {
repaint();
x += changeX;
y += changeY;
changeX = 0;
changeY = 0;
}
public void up() {
if (y != 0) {
changeY = -3.5;
changeX = 0;
}
}
public void down() {
if (y <= 350) {
changeY = 3.5;
changeX = 0;
}
}
public void left() {
if (x >= 0) {
changeX = -3.5;
changeY = 0;
}
}
public void right() {
if (x <= 550) {
changeX = 3.5;
changeY = 0;
}
}
private class MoveListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
repaint();
Random speed = new Random();
int s = speed.nextInt(8);
circle.move(0, s);
}
}
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if (code == KeyEvent.VK_UP) {
up();
}
if (code == KeyEvent.VK_DOWN) {
down();
}
if (code == KeyEvent.VK_RIGHT) {
right();
}
if (code == KeyEvent.VK_LEFT) {
left();
}
}
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
}
Your problem is that you're trying to paint with the circle variable, a variable that you never assign a valid reference to.
One solution is to give it a valid reference via circle = new Circle(...), but having said that, I'll tell you to ignore it since you shouldn't even be using the variable circle. Just get rid of it. What you want to do is to use your circles array -- that's what you should be painting in your paintComponent method. Use a for loop inside of paintComponent and iterate through the array painting each circle item that the array holds.

Categories

Resources