So I'm trying to write a tile-grid based game and came up with a quite unusual solution. I filled a 2D JPanel Array with JLabels with an ImageIcon as tile. Everything works so far but I did not find any way to render this activly.
I've tryied some methods for active rendering I found on the Internet, but they did not work on my idea. Do you have some ideas how to realize this without rewrite everything to Canvas or something similar?
Here's my code:
Window
public class Win extends JFrame {
private static final long serialVersionUID = 1L;
private BufferStrategy bs;
public Win(int x, int y) {
this.setSize(x, y);
this.setVisible(true);
this.setResizable(false);
this.setIgnoreRepaint(true);
this.createBufferStrategy(2);
setBs(getBufferStrategy());
}
public BufferStrategy getBs() {
return bs;
}
public void setBs(BufferStrategy bs) {
this.bs = bs;
}
}
"Draw"
public class Field extends JPanel {
private static final long serialVersionUID = 5257799495742189076L;
private int x = 0;
private int y = 0;
private JPanel backPanel[][] = new JPanel[19][19];
private BufferedImage images[] = new BufferedImage[100];
private JLabel image[][] = new JLabel[19][19];
public Field() {
this.setLayout(new GridLayout(20, 20));
this.setIgnoreRepaint(true);
}
// Creates Panel Grid & Draws floor
public void setPanels() {
for (int h = 0; h < 19; h++) {
for (int w = 0; w < 19; w++) {
backPanel[h][w] = new JPanel();
backPanel[h][w].setLayout(new GridLayout(1, 1));
image[h][w] = new JLabel(new ImageIcon(images[0]));
backPanel[h][w].add(image[h][w]);
this.add(backPanel[h][w]);
}
}
}
// Loads the Textures
public void getTextures() throws IOException {
for (int i = 0; i < 1; i++) {
images[i] = ImageIO.read(new File("texture.png"));
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(images[1], 0, 0, null);
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
}
Game Loop
public class GameLoop implements Runnable {
private boolean runFlag = true;
#Override
public void run() {
Field field = new Field();
Win window = new Win(640, 640);
window.add(field);
try {
field.getTextures();
} catch (IOException e) {
e.printStackTrace();
}
while (runFlag) {
try {
field.setPanels();
window.getBs().show();
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void stop() {
runFlag = false;
}
}
Some alternatives:
Shuffle the components and do removeAll(), add(), and validate() as shown here.
Shuffle the contents and do setIcon(), as shown here.
In either case,
Use javax.swing.Timer to pace the animation, as shown here and here.
Consider TexturePaint to fill the icons, as shown here.
Related
When I use normal JPanel initialized inside main instead of extended class. The button is added to a panel without problem and after launch is displayed in a center of a frame (default layout).
I would like to be able to add buttons inside an extended class. This problem occurs in Screen class aswell, where I need a Play Again button or Next Level button. The Screen is class extended by a JPanel too and JButtons are initialized inside the constructor aswell.
I'm not sure if the wrong part is in way of adding the components or in writing a code for a JPanel.
Here is the code:
Main:
public static void main(String[] args) {
// window - class JFrame
theFrame = new JFrame("Brick Breaker");
// game panel initialization
GamePanel gamePanel = new GamePanel(1);
theFrame.getContentPane().add(gamePanel);
// base settings
theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
theFrame.setLocationRelativeTo(null);
theFrame.setResizable(false);
theFrame.setSize(WIDTH, HEIGHT);
theFrame.setVisible(true);
}
GamePanel Class:
public class GamePanel extends JPanel {
// Fields
boolean running;
boolean clicked = false;
private int rows = 8, colms = 11, N = rows * colms, level; // numbers of rows and columns
private int colmsC, rowsC;
private BufferedImage image;
private Graphics2D g;
private MyMouseMotionListener theMouseListener;
private MouseListener mouseListener;
private int counter = 0;
// entities
Ball theBall;
Paddle thePaddle;
Bricle[] theBricks;
Screen finalScreen;
public GamePanel(int level) {
// buttons
JButton pause = new JButton(" P ");
add(pause);
this.level = level;
init(level);
}
public void init(int level) {
// level logic
this.rowsC = level + rows;
this.colmsC = level + colms;
int count = rowsC * colmsC;
thePaddle = new Paddle();
theBall = new Ball();
theBall.setY(thePaddle.YPOS - thePaddle.getHeight() + 2);
theBall.setX(thePaddle.getX() + thePaddle.getWidth() / 2 - 5);
theBricks = new Bricle[count];
theMouseListener = new MyMouseMotionListener();
addMouseMotionListener(theMouseListener);
mouseListener = new MyMouseListener();
addMouseListener(mouseListener);
// make a canvas
image = new BufferedImage(BBMain.WIDTH, BBMain.HEIGHT, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) image.getGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// specific Bricks initialized
int k = 0;
for (int row = 0; row < rowsC; row++) {
for (int col = 0; col < colmsC; col++) {
theBricks[k] = new Bricle(row, col);
k++;
}
}
running = true;
}
public void playGame() {
while (running) {
//update
if (clicked) {
update();
}
// draw
draw();
// display
repaint();
// sleep
try {
Thread.sleep(20);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// update loop ( like playGame )
public void update() {
// ball moving
checkCollisions();
theBall.update();
}
public void draw() {
// background
g.setColor(Color.WHITE);
g.fillRect(0,0, BBMain.WIDTH, BBMain.HEIGHT-20);
// the bricks
int k = 0;
for (int row = 0; row < rowsC; row++) {
for (int col = 0; col < colmsC; col++) {
theBricks[k].draw(g, row, col);
k++;
}
}
// the ball and the paddle
theBall.draw(g);
thePaddle.draw(g);
// counter
String countString = new Integer(this.counter).toString();
g.drawString(countString, 20, 20);
// WIN / LOOSE SCREEN
if (this.counter == this.N * 20) {
win();
}
if (theBall.getRect().getY() + theBall.getRect().getHeight() >= BBMain.HEIGHT) {
loose();
}
}
public void paintComponent(Graphics g) {
// retype
Graphics2D g2 = (Graphics2D) g;
// draw image
g2.drawImage(image, 0, 0, BBMain.WIDTH, BBMain.HEIGHT, null);
// dispose
g2.dispose();
}
public void pause() {
this.running = false;
finalScreen = new Screen(this.level, counter);
finalScreen.draw(g,"GAME PAUSED");
}
public void win() {
this.running = false;
finalScreen = new Screen(this.level, counter);
finalScreen.draw(g,"YOU WIN");
}
public void loose () {
this.running = false;
finalScreen = new Screen(this.level, counter);
finalScreen.draw(g,"YOU LOOSE");
}
public void addScore() {
this.counter += 20;
theBall.setDY(theBall.getDY() - 0.001);
}
// Mouse Listeners
private class MyMouseListener implements MouseListener {
#Override
public void mouseClicked(MouseEvent e) {
clicked = true;
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
private class MyMouseMotionListener implements MouseMotionListener {
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
if (clicked)
thePaddle.mouseMoved(e.getX());
}
}
}
I'm making a game in Swing and I'm running into an error where randomly, when opening the program, nothing displays. There's seemingly nothing that triggers it, but I have no idea what could possibly be causing it. And also this is everything in my program that seems to be the problem, Since when i tested the source of the problem, it seems to be that the problem is that it is not rendering anything. My update method is working, but the paint method is not running.
Here is the gameHandler class that loads everything and where I believe the problem could be occurring, if this isn't enough to locate the error, please ask me to add whatever it is you would like to see.
public class GameHandler
{
private GamePanel gp;
private Player p;
private StarManager sm;
private EnemyManager em;
private UI ui;
private BulletManager bm;
private PANEL state;
private MenuPanel mp;
public GameHandler(GamePanel gp, Core c)
{
this.gp = gp;
p = new Player(c.getWidth()/2 - 50/2, c.getHeight() - c.getHeight()/4, 25, 50, c);
sm = new StarManager(50, c.getWidth(), c.getHeight(), 15);
em = new EnemyManager(gp, c, p);
bm = new BulletManager(4, p, em);
new GameInput(c, p, bm);
ui = new UI(p);
mp = new MenuPanel(c);
}
public void update()
{
state = gp.getState();
sm.update();
if(state == PANEL.GAME)
{
p.update();
em.update();
bm.update();
}
}
public void render(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
sm.render(g);
if(state == PANEL.GAME)
{
p.render(g);
bm.render(g);
em.render(g);
ui.render(g);
}
else if(state == PANEL.MENU)
{
mp.render(g);
}
}
}
public class Core extends JComponent implements Runnable
{
private static final long serialVersionUID = 1L;
private int
WIDTH = 800,
HEIGHT = 800;
public boolean running;
public GamePanel gp;
public Core()
{
new Display(WIDTH, HEIGHT, "Geometric Space Invasion", this);
init();
}
public void init()
{
gp = new GamePanel(this);
setLayout(new BorderLayout());
add(gp, BorderLayout.CENTER);
Thread t = new Thread(this);
running = true;
t.start();
}
public static void main(String[] args)
{
new Core();
}
#Override
public void run()
{
while(running)
{
try
{
Thread.sleep(7);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
gp.update();
gp.repaint();
}
}
public int getWidth()
{ return WIDTH; }
public int getHeight()
{ return HEIGHT; }
}
public class GamePanel extends JPanel
{
private static final long serialVersionUID = 1L;
private GameHandler gh;
private PANEL state = PANEL.MENU;
private boolean gameOver;
public GamePanel(Core c)
{
setBackground(Color.BLACK);
gameOver = false;
gh = new GameHandler(this, c);
}
public void update()
{
if(gameOver)
state = PANEL.MENU;
gh.update();
}
public enum PANEL
{
MENU,
GAME
/* THIS IS HOW TO CREATE A PANEL VAIRABLE AND CHECK
private PANEL test = PANEL.MENU;
if(test == PANEL.MENU)
//Do whatever.
*/
}
public enum DIFFICULTY
{
EASY,
MEDIUM,
HARD
}
public DIFFICULTY diff = DIFFICULTY.MEDIUM; //TODO : REMOVE
public void paintComponent(Graphics g)
{
super.paintComponent(g);
gh.render(g);
}
public DIFFICULTY getDifficulty()
{
return diff;
}
public PANEL getState()
{
return state;
}
public void setGameOver(boolean gameOver)
{
this.gameOver = gameOver;
}
}
EDIT: FIXED. I fixed it by switching the two lines in the constructor for the Core class.
public Core()
{
new Display(WIDTH, HEIGHT, "Geometric Space Invasion", this);
init();
}
became
public Core()
{
init();
new Display(WIDTH, HEIGHT, "Geometric Space Invasion", this);
}
I have a large program that I will post some classes of and hopefully you guys can find the problem. Basically, sometimes when I start it, it creates the game just fine, and others the background is up a few pixels to the north and west directions leaving very unsightly whitespace. I cannot seem to find the missing piece of code that decides whether not it does this. It honestly feel like some kind of rendering glitch on my machine. At any rate, I have put a background getX and getY method in for debugging and have noticed that whether the background is fully stretched to the screen(its a custom background so the pixel height and width match perfectly), or its up and to the left, the background still reads that it is displaying at (0,0). I will post all the methods from the main thread to the creating of the background in the menu. I will leave notes indicating the path it takes through this code that gets it to creating the background. Thank you for your help and I will check in regularly for edits and more information.
EDIT: added background.java
EDIT2: added pictures explaining problem
Menu.java *ignore the FileIO code, the main point is the creation of a new GamePanel()
public class Menu {
private static File file;
public static void main(String[] args) throws IOException {
file = new File("saves.txt");
if(file.exists()){
FileIO.run();
FileIO.profileChoose();
}
else{
FileIO.profileCreate();
FileIO.run();
}
JFrame window = new JFrame("Jolly Jackpot Land");
window.setContentPane(new GamePanel());
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setResizable(false);
window.pack();
window.setLocationRelativeTo(null);
window.setVisible(true);
}
}
Next is the GamePanel.java
public class GamePanel extends JPanel implements Runnable, KeyListener {
// ID
private static final long serialVersionUID = 1L;
// Dimensions
public static final int WIDTH = 320;
public static final int HEIGHT = 240;
public static final int SCALE = 2;
// Thread
private Thread thread;
private boolean running;
private int FPS = 30;
private long targetTime = 1000 / FPS;
// Image
private BufferedImage image;
private Graphics2D g;
// Game State Manager
private GameStateManager gsm;
public GamePanel() {
super();
setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
setFocusable(true);
requestFocus();
}
public void addNotify() {
super.addNotify();
if (thread == null) {
thread = new Thread(this);
addKeyListener(this);
thread.start();
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
}
private void init() {
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) image.getGraphics();
running = true;
gsm = new GameStateManager();
}
#Override
public void run() {
init();
long start;
long elapsed;
long wait;
// Game Loop
while (running) {
start = System.nanoTime();
update();
draw();
drawToScreen();
elapsed = System.nanoTime() - start;
wait = targetTime - (elapsed / 1000000);
if (wait < 0) {
wait = 5;
}
try {
Thread.sleep(wait);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void update() {
gsm.update();
}
private void draw() {
gsm.draw(g);
}
private void drawToScreen() {
Graphics g2 = getGraphics();
g2.drawImage(image, 0, 0, WIDTH * SCALE, HEIGHT * SCALE, null);
g2.dispose();
}
#Override
public void keyPressed(KeyEvent k) {
gsm.keyPressed(k.getKeyCode());
}
#Override
public void keyReleased(KeyEvent k) {
}
#Override
public void keyTyped(KeyEvent arg0) {
}
}
This calls for the creation of a new GameStateManager object in its init() method and the class for that is here.
GameStateManager.java
public class GameStateManager {
private ArrayList<GameState> gameStates;
private int currentState;
public static final int MENUSTATE = 0;
public static final int SLOTGAMESTATE = 1;
public static final int DICEGAMESTATE = 2;
public static final int ROULETTEGAMESTATE = 3;
public static final int LEADERBOARDSTATE = 4;
public static final int SETTINGSSTATE = 5;
public static final int HELPSTATE = 6;
public GameStateManager() {
gameStates = new ArrayList<GameState>();
currentState = 0;
gameStates.add(new MenuState(this));
gameStates.add(new SlotGameState(this));
gameStates.add(new DiceGameState(this));
gameStates.add(new RouletteGameState(this));
gameStates.add(new LeaderboardState(this));
gameStates.add(new SettingsState(this));
gameStates.add(new HelpState(this));
}
public void setState(int state){
currentState = state;
gameStates.get(currentState).init();
currentState = 0;
}
public int getState() {
return currentState;
}
public void update() {
gameStates.get(currentState).init();
}
public void draw(java.awt.Graphics2D g){
gameStates.get(currentState).draw(g);
}
public void keyPressed(int k){
gameStates.get(currentState).keyPressed(k);
}
public void keyReleased(int k) {
gameStates.get(currentState).keyReleased(k);
}
}
GameState is an abstract class I have so its not worth posting, it only contains init(), draw(), etc. This next class is the last and final class and is called because GameStateMananger starts at MENUSTATE or 0, and when GSM is initialized it initializes its current state, thus taking us to the class MenuState
MenuState.java
public class MenuState extends GameState {
private Background bg;
public FontMetrics fontMetrics;
private int choice = 0;
private String[] options = { "Slot Machine", "Dice Toss", "Roulette Wheel", "Leaderboards", "Settings", "Help",
"Quit" };
private Color titleColor;
private Font titleFont;
private Font font;
public MenuState(GameStateManager gsm) {
this.gsm = gsm;
try {
bg = new Background("/Backgrounds/happybg.png");
titleColor = Color.WHITE;
titleFont = new Font("Georgia", Font.PLAIN, 28);
} catch (Exception e) {
e.printStackTrace();
}
font = new Font("Arial", Font.PLAIN, 12);
}
#Override
public void init() {
}
#Override
public void update() {
}
#Override
public void draw(Graphics2D g) {
Canvas c = new Canvas();
fontMetrics = c.getFontMetrics(font);
// Draw BG
bg.draw(g);
// Draw title
g.setColor(titleColor);
g.setFont(titleFont);
String title = "Jolly Jackpot Land!";
g.drawString(title, 36, 60);
g.setFont(font);
for (int i = 0; i < options.length; i++) {
if (i == choice)
g.setColor(Color.RED);
else
g.setColor(Color.WHITE);
g.drawString(options[i], 30, 120 + i * 15);
}
g.setColor(Color.WHITE);
g.setFont(new Font("Arial", Font.PLAIN, 10));
g.drawString("v1.1", 165, 235);
Object[] a = { ("Name: " + Player.getName()), ("Gil: " + Player.getGil()),
("Personal Best: " + Player.getPersonalBest()), ("Winnings: " + Player.getWinnings()),
("Wins: " + Player.getWins()), ("Losses: " + Player.getLosses()),
("Win/Loss Ratio: " + String.format("%.2f", Player.getRatio()) + "%") };
g.setFont(font);
if (Player.getName() != null) {
for (int x = 0; x < a.length; x++) {
g.drawString(a[x].toString(), GamePanel.WIDTH - fontMetrics.stringWidth(a[x].toString()) - 30,
120 + x * 15);
}
}
}
private void select() {
if (choice == 0) {
// Slots
gsm.setState(GameStateManager.SLOTGAMESTATE);
}
if (choice == 1) {
// Dice
gsm.setState(GameStateManager.DICEGAMESTATE);
}
if (choice == 2) {
// Roulette
gsm.setState(GameStateManager.ROULETTEGAMESTATE);
}
if (choice == 3) {
// Leaderboards
gsm.setState(GameStateManager.LEADERBOARDSTATE);
}
if (choice == 4) {
// Settings
gsm.setState(GameStateManager.SETTINGSSTATE);
}
if (choice == 5) {
// Help
gsm.setState(GameStateManager.HELPSTATE);
}
if (choice == 6) {
// Quit
System.exit(0);
}
}
#Override
public void keyPressed(int k) {
if (k == KeyEvent.VK_ENTER) {
select();
}
if (k == KeyEvent.VK_UP) {
choice--;
if (choice == -1) {
choice = options.length - 1;
}
}
if (k == KeyEvent.VK_DOWN) {
choice++;
if (choice == options.length) {
choice = 0;
}
}
}
#Override
public void keyReleased(int k) {
}
}
Background.java
public class Background {
private BufferedImage image;
private double x;
private double y;
public Background(String s) {
try {
image = ImageIO.read(getClass().getResourceAsStream(s));
} catch (Exception e) {
e.printStackTrace();
}
}
public void setPosition(double x, double y) {
this.setX(x);
this.setY(y);
}
public void draw(Graphics2D g) {
g.drawImage(image, 0, 0, null);
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
}
This is where it waits for input in the game loop basically. I know this is a lot of code, but a lot of it is skimming till a method call takes you to the next class. I just can't figure out why it only happens sometimes, if it was consistent I could debug it. Any help would be extremely appreciated.
These are both from clicking the .jar of the above program, exact same .jar, exact same source code, different result. I am bewildered.
This is my slider puzzle game. So far it can only do 3x3 games. When I try and pass the variables l and w (length and width) of the board it doesn't work. It only works when i set the variables ROWS and COLS as finals. When I try and change it I get errors. I'm not sure what to do, any help would be appreciated.
Currently the user can input values that can't do anything at the moment. When the game is started, a 3x3 board is generated. The user can restart the game with a different scrambled board but the buttons that solve the board and the buttons that reset the board to the original state do not work yet.
public class SlidePuzzle {
public static void main(String[] args)
{
JFrame window = new JFrame("Slide Puzzle");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String length = JOptionPane.showInputDialog("Length");
String width = JOptionPane.showInputDialog("Width");
int l = Integer.parseInt(length);
int w = Integer.parseInt(width);
window.setContentPane(new SlidePuzzleGUI());
window.pack();
window.show();
window.setResizable(false);
}
}
public class SlidePuzzleGUI extends JPanel
{
private GraphicsPanel _puzzleGraphics;
private SlidePuzzleModel _puzzleModel = new SlidePuzzleModel();
This class contains the GUI for the Slider Puzzle
public SlidePuzzleGUI() {
JButton newGameButton = new JButton("New Game");
JButton resetButton = new JButton("Reset");
JButton solveButton = new JButton("I GIVE UP :(");
resetButton.addActionListener(new ResetAction());
newGameButton.addActionListener(new NewGameAction());
JPanel controlPanel = new JPanel();
controlPanel.setLayout(new FlowLayout());
controlPanel.add(newGameButton);
controlPanel.add(resetButton);
controlPanel.add(solveButton);
_puzzleGraphics = new GraphicsPanel();
this.setLayout(new BorderLayout());
this.add(controlPanel, BorderLayout.NORTH);
this.add(_puzzleGraphics, BorderLayout.CENTER);
}
This is the graphics panel
class GraphicsPanel extends JPanel implements MouseListener {
private static final int ROWS = 3;
private static final int COLS = 3;
private static final int CELL_SIZE = 80;
private Font _biggerFont;
public GraphicsPanel() {
_biggerFont = new Font("SansSerif", Font.BOLD, CELL_SIZE/2);
this.setPreferredSize(
new Dimension(CELL_SIZE * COLS, CELL_SIZE*ROWS));
this.setBackground(Color.black);
this.addMouseListener(this);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int r=0; r<ROWS; r++) {
for (int c=0; c<COLS; c++) {
int x = c * CELL_SIZE;
int y = r * CELL_SIZE;
String text = _puzzleModel.getFace(r, c);
if (text != null) {
g.setColor(Color.gray);
g.fillRect(x+2, y+2, CELL_SIZE-4, CELL_SIZE-4);
g.setColor(Color.black);
g.setFont(_biggerFont);
g.drawString(text, x+20, y+(3*CELL_SIZE)/4);
}
}
}
}
public void mousePressed(MouseEvent e) {
int col = e.getX()/CELL_SIZE;
int row = e.getY()/CELL_SIZE;
if (!_puzzleModel.moveTile(row, col)) {
Toolkit.getDefaultToolkit().beep();
}
this.repaint();
}
public void mouseClicked (MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered (MouseEvent e) {}
public void mouseExited (MouseEvent e) {}
}
public class NewGameAction implements ActionListener {
public void actionPerformed(ActionEvent e) {
_puzzleModel.reset();
_puzzleGraphics.repaint();
}
}
public class ResetAction implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
_puzzleModel.tryAgain();
_puzzleGraphics.repaint();
}
}
public class solveAction implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
_puzzleModel.solve();
_puzzleGraphics.repaint();
}
}
}
public class SlidePuzzleModel {
private static final int ROWS = 3;
private static final int COLS = 3;
private Tile[][] _contents;
private Tile[][] _solved;
private Tile _emptyTile;
public SlidePuzzleModel() {
_contents = new Tile[ROWS][COLS];
reset();
}
String getFace(int row, int col) {
return _contents[row][col].getFace();
}
public void reset() {
for (int r=0; r<ROWS; r++) {
for (int c=0; c<COLS; c++) {
_contents[r][c] = new Tile(r, c, "" + (r*COLS+c+1));
}
}
_emptyTile = _contents[ROWS-1][COLS-1];
_emptyTile.setFace(null);
for (int r=0; r<ROWS; r++) {
for (int c=0; c<COLS; c++) {
exchangeTiles(r, c, (int)(Math.random()*ROWS)
, (int)(Math.random()*COLS));
}
}
}
public void tryAgain()
{
}
public void solve()
{
for (int i = 1; i < ROWS+1;i++)
{
for(int j = 1; j < COLS+1;j++)
{
exchangeTiles(i, j, i, j);
}
}
}
public boolean moveTile(int r, int c) {
return checkEmpty(r, c, -1, 0) || checkEmpty(r, c, 1, 0)
|| checkEmpty(r, c, 0, -1) || checkEmpty(r, c, 0, 1);
}
private boolean checkEmpty(int r, int c, int rdelta, int cdelta) {
int rNeighbor = r + rdelta;
int cNeighbor = c + cdelta;
if (isLegalRowCol(rNeighbor, cNeighbor)
&& _contents[rNeighbor][cNeighbor] == _emptyTile) {
exchangeTiles(r, c, rNeighbor, cNeighbor);
return true;
}
return false;
}
public boolean isLegalRowCol(int r, int c) {
return r>=0 && r<ROWS && c>=0 && c<COLS;
}
private void exchangeTiles(int r1, int c1, int r2, int c2) {
Tile temp = _contents[r1][c1];
_contents[r1][c1] = _contents[r2][c2];
_contents[r2][c2] = temp;
}
public boolean isGameOver() {
for (int r=0; r<ROWS; r++) {
for (int c=0; c<ROWS; c++) {
Tile trc = _contents[r][c];
return trc.isInFinalPosition(r, c);
}
}
return true;
}
}
class Tile {
private int _row;
private int _col;
private String _face;
public Tile(int row, int col, String face) {
_row = row;
_col = col;
_face = face;
}
public void setFace(String newFace) {
_face = newFace;
}
public String getFace() {
return _face;
}
public boolean isInFinalPosition(int r, int c) {
return r==_row && c==_col;
}
}
How would I make it so that the user can specify dimensions of the game board?
EDIT
public class SlidePuzzle {
public static void main(String[] args)
{
JFrame window = new JFrame("Slide Puzzle");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String length = JOptionPane.showInputDialog("Length");
String width = JOptionPane.showInputDialog("Width");
int l = Integer.parseInt(length);
int w = Integer.parseInt(width);
window.setContentPane(new SlidePuzzleGUI());
window.pack();
window.show();
window.setResizable(false);
}
}
public class SlidePuzzleGUI extends JPanel
{
private GraphicsPanel _puzzleGraphics;
private SlidePuzzleModel _puzzleModel = new SlidePuzzleModel();
public SlidePuzzleGUI(int l, int w) {
JButton newGameButton = new JButton("New Game");
JButton resetButton = new JButton("Reset");
JButton solveButton = new JButton("I GIVE UP :(");
resetButton.addActionListener(new ResetAction());
newGameButton.addActionListener(new NewGameAction());
JPanel controlPanel = new JPanel();
controlPanel.setLayout(new FlowLayout());
controlPanel.add(newGameButton);
controlPanel.add(resetButton);
controlPanel.add(solveButton);
_puzzleGraphics = new GraphicsPanel(l,w);
this.setLayout(new BorderLayout());
this.add(controlPanel, BorderLayout.NORTH);
this.add(_puzzleGraphics, BorderLayout.CENTER);
}
class GraphicsPanel extends JPanel implements MouseListener {
private int ROWS;
private int COLS;
private static final int CELL_SIZE = 80;
private Font _biggerFont;
public GraphicsPanel(int l, int w) {
_biggerFont = new Font("SansSerif", Font.BOLD, CELL_SIZE/2);
this.setPreferredSize(
new Dimension(CELL_SIZE * COLS, CELL_SIZE*ROWS));
this.setBackground(Color.black);
this.addMouseListener(this);
ROWS = l;
COLS = w;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int r=0; r<ROWS; r++) {
for (int c=0; c<COLS; c++) {
int x = c * CELL_SIZE;
int y = r * CELL_SIZE;
String text = _puzzleModel.getFace(r, c);
if (text != null) {
g.setColor(Color.gray);
g.fillRect(x+2, y+2, CELL_SIZE-4, CELL_SIZE-4);
g.setColor(Color.black);
g.setFont(_biggerFont);
g.drawString(text, x+20, y+(3*CELL_SIZE)/4);
}
}
}
}
public void mousePressed(MouseEvent e) {
int col = e.getX()/CELL_SIZE;
int row = e.getY()/CELL_SIZE;
if (!_puzzleModel.moveTile(row, col)) {
Toolkit.getDefaultToolkit().beep();
}
this.repaint();
}
public void mouseClicked (MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered (MouseEvent e) {}
public void mouseExited (MouseEvent e) {}
}
public class NewGameAction implements ActionListener {
public void actionPerformed(ActionEvent e) {
_puzzleModel.reset();
_puzzleGraphics.repaint();
}
}
public class ResetAction implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
_puzzleModel.tryAgain();
_puzzleGraphics.repaint();
}
}
public class solveAction implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
_puzzleModel.solve();
_puzzleGraphics.repaint();
}
}
}
Your key classes have no setter methods or constructor parameters that allow you to pass the length and width to them. If you want to change this aspect of their states, then they have to have a mechanism to do this. Currently your GraphicsPanel is hard-coded to use the ROWS and COLS constants, and this will be very hard to change. Instead replace all those hard-codings to variables, and sure have them default to the ROWS and COLS constants in your default constructor, but also provide a non-default constructor that will allow the programmer to pass in a different row and col setting.
Edit
You've got to
Use the constructor parameters to set class fields so that the entire class can use these values, not just the constructor.
Call the proper constructor, the one that requires the parameters!
i.e.,
public MyConstructor(int x, int y) {
this.x = x;
this.y = y;
}
I want to display many animation at the same time with thread.
But It doesn't work, the second animation start when the first end.
I'm using thread but probably the wrong way because i'm beginner
Here is my code :
public class Board extends JPanel{
Mouse mouse;
ArrayList<Explosion> explosions;
public Board() {
mouse = new Mouse(this);
explosions = new ArrayList();
setDoubleBuffered(true);
this.addMouseListener(mouse);
}
public void addExplosion(Explosion e) {
explosions.add(e);
new Thread(explosions.get(explosions.indexOf(e))).start();
}
public void removeExplosion(Explosion e) {
explosions.remove(e);
}
public void paint(Graphics g) {
super.paint(g);
for(int i=0; i<explosions.size(); i++) {
explosions.get(i).paintComponent(g);
}
Graphics2D g2d = (Graphics2D)g;
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
}
public class Explosion extends JPanel implements Runnable{
private BufferedImage img;
final int width = 320;
final int height = 320;
final int rows = 5;
final int cols = 5;
private int x,y;
private int cursor;
BufferedImage[] sprites = new BufferedImage[rows * cols];
Board board;
public Explosion(Board board,int x, int y) {
this.board = board;
this.x = x;
this.y = y;
try {
try {
this.img = ImageIO.read(new File((this.getClass().getResource("files/explosion2.png")).toURI()));
} catch (URISyntaxException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
cursor = 0;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
sprites[(i * cols) + j] = img.getSubimage(
j * (width/rows),
i * (height/cols),
width/rows,
height/cols
);
}
}
}
public void run() {
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
cursor++;
}
};
Timer timer = new Timer(50, taskPerformer);
while(cursor < ((rows*cols)-1)) {
timer.start();
board.repaint();
}
timer.stop();
board.removeExplosion(this);
}
public void paintComponent(Graphics g){
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(sprites[cursor], x, y, this);
g.dispose();
}
}
Thanks for helping
Any code that updates the GUI should be run on the thread associated with the GUI. To do so from a different thread, like in your case, you will need to use SwingUtilities.InvokeLater:
SwingUtilities.InvokeLater(new Runnable() {
public void run() {
// code to update the GUI goes here
}
});