Related
I don't really understand why this program draws three pawns instead of one and two of which seem to have a random(probably not so random) positions. enter image description here
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class GamePanel extends JPanel implements MouseListener {
static final int SCREEN_EDGE = 800;
static final int GAME_UNITS = 64;
static final int UNIT_SIZE = 100;
final int[] x = new int[GAME_UNITS];
final int[] y = new int[GAME_UNITS];
boolean running = false;
public GamePanel() {
this.setPreferredSize(new Dimension(SCREEN_EDGE, SCREEN_EDGE));
this.setFocusable(true);
this.addKeyListener(new MyKeyAdapter());
startGame();
int[] position = {0,0};
int[] position1 = {1, 0};
new Pawn(position,-1);
}
private void startGame() {
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
draw(g);
}
public void draw(Graphics g){
int counter = 1;
for (int y = 0; y < SCREEN_EDGE/UNIT_SIZE; y++) {
// 1 == "white" 2 == "black"
int color = (y % 2 == 0) ? 1 : 2;
for (int x = 0; x < SCREEN_EDGE/UNIT_SIZE; x++) {
g.setColor(color == 1 ? new Color(239,217, 181) : new Color(180, 136,98));
g.fillRect(x*UNIT_SIZE, y*UNIT_SIZE, UNIT_SIZE, UNIT_SIZE);
color = color == 1 ? 2 : 1;
}
}
for (int i = 0; i < Figure.figures.length; i++) {
JLabel figureSprite = new JLabel(Figure.figures[i].image, JLabel.CENTER);
figureSprite.setSize(90,90);
figureSprite.setLocation(Figure.figures[i].position[0] + 5,Figure.figures[i].position[1] + 5);
this.add(figureSprite);
}
}
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
public class MyKeyAdapter extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
}
}
}
import javax.swing.*;
public abstract class Figure{
protected int value;
protected ImageIcon image;
protected int[][] possibleMoves;
public int[] position;
// white = -1 black = 1
protected int whiteOrBlack;
protected static int figureCount = 1;
// int[figureCount][0 = x][1 = y][2 = color]
public static Figure[] figures = new Figure[figureCount];
public Figure(int value, int[] position, int[][] possibleMoves , int whiteOrBlack) {
this.value = value;
this.position = position;
this.possibleMoves = possibleMoves;
this.whiteOrBlack = whiteOrBlack;
Figure[] oldFigures = figures;
figures = new Figure[figureCount];
for (int i = 0; i < oldFigures.length; i++) {
figures[i] = oldFigures[i];
}
figures[figureCount - 1] = this;
figureCount++;
}
public abstract void move(int[] coordinates);
}
import javax.swing.*;
import java.awt.*;
import java.io.*;
public class Pawn extends Figure{
public Pawn(int[] position, int whiteOrBlack) {
super(1, position, new int[3][2], whiteOrBlack);
super.image = new ImageIcon(getClass().getClassLoader().getResource("graphics/" + (whiteOrBlack == -1 ? "whitePawn.png" : "blackPawn.png")));
Image newImage = super.image.getImage().getScaledInstance(90,90, Image.SCALE_AREA_AVERAGING);
super.image = new ImageIcon(newImage);
}
public void checkMoves(){
for (int i = 0; i < figures.length; i++) {
if((position[0] - 1) == figures[i].position[0] && (position[1] + this.whiteOrBlack) == figures[i].position[1] && figures[i].whiteOrBlack != this.whiteOrBlack) {
possibleMoves[0][0] = position[0] - 1;
possibleMoves[0][1] = position[1] + this.whiteOrBlack;
}else possibleMoves[0] = new int[2];
if((position[0]) != figures[i].position[0] && (position[1]) != figures[i].position[1]){
possibleMoves[1][0] = position[0];
possibleMoves[1][1] = position[1] + 1;
}else possibleMoves[1] = new int[2];
if((position[0] + 1) == figures[i].position[0] && (position[1] + this.whiteOrBlack) == figures[i].position[1] && figures[i].whiteOrBlack != this.whiteOrBlack) {
possibleMoves[2][0] = position[0] + 1;
possibleMoves[2][1] = position[1] + this.whiteOrBlack;
}else possibleMoves[2] = new int[2];
}
}
#Override
public void move(int[] coordinates) {
}
}
import javax.swing.*;
public class GameFrame extends JFrame {
public GameFrame(){
this.add(new GamePanel());
this.setTitle("Chess");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setResizable(false);
this.setVisible(true);
this.setLocationRelativeTo(null);
}
}
public class ChessGame {
public static void main(String[] args) {
new GameFrame();
}
}
I tried few thing like changing JLabel to BufferedImage but it would've generate other problems down the line like not being able to use MouseListener so i feel stuck. I would love to know why this code generates 3 textures too.
It looks like you are adding FigureSprites from within the drawComponent() method. The more often you draw the window, the more figures you have to draw.
Instead within drawComponent() just draw the current state but do not modify it. Adding figures has to come from somewhere else. For example, you could create the necessary pawns in the constructor. Or in extra methods that might get triggered based on user input.
In case you modify the GamePanel's state enough so that it should get painted freshly, just invoke repaint(). Swing will mark this component for repainting and decide on it's own when to run the paint() method, which in turn will run paintComponent().
I am writing a video game GUI and I want to firstly open a frame with a menu bar and when the user clicks on play in the menu a JPanel that is in a different class gets added to the current one and it ends up with a frame containing the menu bar and the JPanel. When I run the code bellow I don't get any errors and the console initiates the process. The problem is nothing shows on the screen?? Not the initial frame or anything else.
The code for the frame that calls the class with the JPanel is:
/*-----------------------------------------------------------------------------------------------------*/
package Testes;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Tetris extends JFrame{
private static final long serialVersionUID = 1L;
public static final int WIDTH = 250;
public static final int HEIGHT = 490;
public Tetris() {
JFrame frame = new JFrame();
TetrisBoard janela = new TetrisBoard();
JMenuBar menubar = new JMenuBar();
JMenu start = new JMenu("Start");
JMenuItem play = new JMenuItem("Play");
play.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
janela.startGame();
}
});
start.add(play);
JMenuItem exit = new JMenuItem("Exit");
exit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
});
start.add(exit);
JMenu help = new JMenu("Help");
JMenuItem manual = new JMenuItem("User Manual");
manual.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
JOptionPane.showMessageDialog(null, "The goal of Tetris is to eliminate \nas many lines as possible before\n the Tetrominoes reach the top.\nControls:\n\u2190 - Move Left\n\u2192 - Move Right\n\u2193 - Drop\n" +
"C - Rotate AntiClockwise\nV - Rotate Clockwise\nP - Pause\nEsc - Quit","Instructions", JOptionPane.OK_OPTION, new ImageIcon());
}
});
help.add(manual);
JMenuItem about = new JMenuItem("About");
about.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
JLabel label = new JLabel("<html><center>Tetris made by GG<br>MEEC<br>2020<html>");
label.setHorizontalAlignment(SwingConstants.CENTER);
JOptionPane.showMessageDialog(null, label, "About", JOptionPane.INFORMATION_MESSAGE);
}
});
help.add(about);
menubar.add(start);
menubar.add(help);
frame.add(janela,BorderLayout.CENTER);
frame.add(menubar,BorderLayout.NORTH);
janela.setFocusable(true);
frame.setTitle("Tetris");
frame.setLayout(new BorderLayout());
frame.setSize(250, 490);
//setPreferredSize(new Dimension(255, 495));
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.pack();
}
public static void main(String[] args) {
new Tetris();
}
}
/*-----------------------------------------------------------------------------------------------------*/
And the class with the JPanel is:
/*-----------------------------------------------------------------------------------------------------*/
package Testes;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
public class TetrisBoard extends JPanel implements KeyListener/*, ActionListener*/{
private static final long serialVersionUID = 1L;
public static final int COLOR_MIN = 35;
public static final int COLOR_MAX = 255 - COLOR_MIN;
public static final int BORDER_WIDTH = 5;
public static final int COL_COUNT = 10;
public static final int VISIBLE_ROW_COUNT = 20;
public static final int HIDDEN_ROW_COUNT = 2;
public static final int ROW_COUNT = VISIBLE_ROW_COUNT + HIDDEN_ROW_COUNT;
public static final int TILE_SIZE = 24;
public static final int SHADE_WIDTH = 4;
private static final int CENTER_X = COL_COUNT * TILE_SIZE / 2;
public static final int CENTER_Y = VISIBLE_ROW_COUNT * TILE_SIZE / 2;
public static final int PANEL_WIDTH = COL_COUNT * TILE_SIZE + BORDER_WIDTH * 2;
public static final int PANEL_HEIGHT = VISIBLE_ROW_COUNT * TILE_SIZE + BORDER_WIDTH * 2;
public static final Font LARGE_FONT = new Font("Tahoma", Font.BOLD, 16);
public static final Font SMALL_FONT = new Font("Tahoma", Font.BOLD, 12);
public static final long FRAME_TIME = 20L;
public static final int TYPE_COUNT = TileType.values().length;
public boolean isPaused;
public boolean isNewGame;
public boolean isGameOver;
public int level;
public int score;
public Random random;
public Clock logicTimer;
public TileType currentType;
public TileType nextType;
public int currentCol;
private int currentRow;
public int currentRotation;
public int dropCooldown;
public float gameSpeed;
public String difficulty = "Easy";
public int newLevel;
public int lines;
public int cleared;
public TileType[][] tiles;
public TetrisBoard() {
addKeyListener(this);
this.tiles = new TileType[ROW_COUNT][COL_COUNT];
setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
setBackground(Color.BLACK);
startGame();
}
public void clear() {
for(int i = 0; i < ROW_COUNT; i++) {
for(int j = 0; j < COL_COUNT; j++) {
tiles[i][j] = null;
}
}
}
public boolean isValidAndEmpty(TileType type, int x, int y, int rotation) {
if(x < -type.getLeftInset(rotation) || x + type.getDimension() - type.getRightInset(rotation) >= COL_COUNT) {
return false;
}
if(y < -type.getTopInset(rotation) || y + type.getDimension() - type.getBottomInset(rotation) >= ROW_COUNT) {
return false;
}
for(int col = 0; col < type.getDimension(); col++) {
for(int row = 0; row < type.getDimension(); row++) {
if(type.isTile(col, row, rotation) && isOccupied(x + col, y + row)) {
return false;
}
}
}
return true;
}
public void addPiece(TileType type, int x, int y, int rotation) {
for(int col = 0; col < type.getDimension(); col++) {
for(int row = 0; row < type.getDimension(); row++) {
if(type.isTile(col, row, rotation)) {
setTile(col + x, row + y, type);
}
}
}
}
public int checkLines() {
int completedLines = 0;
for(int row = 0; row < ROW_COUNT; row++) {
if(checkLine(row)) {
completedLines++;
}
}
return completedLines;
}
public boolean checkLine(int line) {
for(int col = 0; col < COL_COUNT; col++) {
if(!isOccupied(col, line)) {
return false;
}
}
for(int row = line - 1; row >= 0; row--) {
for(int col = 0; col < COL_COUNT; col++) {
setTile(col, row + 1, getTile(col, row));
}
}
return true;
}
public boolean isOccupied(int x, int y) {
return tiles[y][x] != null;
}
public void setTile(int x, int y, TileType type) {
tiles[y][x] = type;
}
public TileType getTile(int x, int y) {
return tiles[y][x];
}
//#Override
public void paintComponent(Graphics g) {
this.paintComponent(g);
g.translate(BORDER_WIDTH, BORDER_WIDTH);
if(isPaused()) {
g.setFont(LARGE_FONT);
g.setColor(Color.GREEN);
String msg = "PAUSED";
g.drawString(msg, CENTER_X - g.getFontMetrics().stringWidth(msg) / 2, CENTER_Y);
} else if(isNewGame() || isGameOver()) {
g.setFont(LARGE_FONT);
g.setColor(Color.WHITE);
g.setColor(Color.GREEN);
String msg = isNewGame() ? "TETRIS" : "GAME OVER";
g.drawString(msg, CENTER_X - g.getFontMetrics().stringWidth(msg) / 2, 150);
g.setFont(SMALL_FONT);
msg = "Press Enter to Play" + (isNewGame() ? "" : " Again");
g.drawString(msg, CENTER_X - g.getFontMetrics().stringWidth(msg) / 2, 300);
} else {
for(int x = 0; x < COL_COUNT; x++) {
for(int y = HIDDEN_ROW_COUNT; y < ROW_COUNT; y++) {
TileType tile = getTile(x, y);
if(tile != null) {
drawTile(tile, x * TILE_SIZE, (y - HIDDEN_ROW_COUNT) * TILE_SIZE, g);
}
}
}
TileType type = getPieceType();
int pieceCol = getPieceCol();
int pieceRow = getPieceRow();
int rotation = getPieceRotation();
for(int col = 0; col < type.getDimension(); col++) {
for(int row = 0; row < type.getDimension(); row++) {
if(pieceRow + row >= 2 && type.isTile(col, row, rotation)) {
drawTile(type, (pieceCol + col) * TILE_SIZE, (pieceRow + row - HIDDEN_ROW_COUNT) * TILE_SIZE, g);
}
}
}
g.setColor(Color.DARK_GRAY);
for(int x = 0; x < COL_COUNT; x++) {
for(int y = 0; y < VISIBLE_ROW_COUNT; y++) {
g.drawLine(0, y * TILE_SIZE, COL_COUNT * TILE_SIZE, y * TILE_SIZE);
g.drawLine(x * TILE_SIZE, 0, x * TILE_SIZE, VISIBLE_ROW_COUNT * TILE_SIZE);
}
}
}
g.setColor(Color.GREEN);
g.drawRect(0, 0, TILE_SIZE * COL_COUNT, TILE_SIZE * VISIBLE_ROW_COUNT);
}
public void drawTile(TileType type, int x, int y, Graphics g) {
drawTile(type.getBaseColor(), type.getLightColor(), type.getDarkColor(), x, y, g);
}
public void drawTile(Color base, Color light, Color dark, int x, int y, Graphics g) {
g.setColor(base);
g.fillRect(x, y, TILE_SIZE, TILE_SIZE);
g.setColor(dark);
g.fillRect(x, y + TILE_SIZE - SHADE_WIDTH, TILE_SIZE, SHADE_WIDTH);
g.fillRect(x + TILE_SIZE - SHADE_WIDTH, y, SHADE_WIDTH, TILE_SIZE);
g.setColor(light);
for(int i = 0; i < SHADE_WIDTH; i++) {
g.drawLine(x, y + i, x + TILE_SIZE - i - 1, y + i);
g.drawLine(x + i, y, x + i, y + TILE_SIZE - i - 1);
}
}
public void startGame() {
this.random = new Random();
this.isNewGame = true;
if(this.difficulty.equals("Easy")) {
this.gameSpeed=1.0f;
}else if(this.difficulty.equals("Intermediate")) {
this.gameSpeed=3.0f;
}else if(this.difficulty.equals("Hard")) {
this.gameSpeed=6.0f;
}
this.level=1;
this.cleared=0;
this.newLevel=0;
this.logicTimer = new Clock(gameSpeed);
logicTimer.setPaused(true);
while(true) {
long start = System.nanoTime();
logicTimer.update();
if(logicTimer.hasElapsedCycle()) {
updateGame();
}
//Decrement the drop cool down if necessary.
if(dropCooldown > 0) {
dropCooldown--;
}
renderGame();
long delta = (System.nanoTime() - start) / 1000000L; // delta in miliseconds
if(delta < FRAME_TIME) {
try {
Thread.sleep(FRAME_TIME - delta); // sleeps the difference between the fps and the time for the game to process (delta)
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
public void updateGame() {
if(isValidAndEmpty(currentType, currentCol, currentRow + 1, currentRotation)) {
currentRow++;
} else {
addPiece(currentType, currentCol, currentRow, currentRotation);
cleared = checkLines();
if(cleared > 0) {
lines += cleared;
score += 50 << cleared; // left bit shift - add the number of zeros on the right to the binary version of the number on the right
// score = score + 50 << cleared;
}
//newLevel+=cleared;
gameSpeed += 0.035f;
logicTimer.setCyclesPerSecond(gameSpeed);
logicTimer.reset();
dropCooldown = 25;
if(newLevel<10) {
newLevel+=cleared;
}else if(newLevel>=10) {
level+=1;
newLevel=0;
cleared=0;
}
spawnPiece();
}
}
public void renderGame() {
repaint();
}
public void resetGame() {
this.level = 1;
this.score = 0;
this.lines = 0;
this.newLevel = 0;
this.cleared = 0;
if(this.difficulty.equals("Easy")) {
this.gameSpeed=1.0f;
}else if(this.difficulty.equals("Intermediate")) {
this.gameSpeed=3.0f;
}else if(this.difficulty.equals("Hard")) {
this.gameSpeed=6.0f;
}
this.nextType = TileType.values()[random.nextInt(TYPE_COUNT)];
this.isNewGame = false;
this.isGameOver = false;
clear();
logicTimer.reset();
logicTimer.setCyclesPerSecond(gameSpeed);
spawnPiece();
}
public void spawnPiece() {
this.currentType = nextType;
this.currentCol = currentType.getSpawnColumn();
this.currentRow = currentType.getSpawnRow();
this.currentRotation = 0;
this.nextType = TileType.values()[random.nextInt(TYPE_COUNT)];
if(!isValidAndEmpty(currentType, currentCol, currentRow, currentRotation)) {
lose();
}
}
public void lose()
{
this.isGameOver = true;
logicTimer.setPaused(isPaused);
String info = "";
if (score>HighScore.getHighScores()[9].getScore())
{
info="You got a high score!\n<br>Please enter you name.\n<br>(Note: Only 10 characters will be saved)";
JLabel label = new JLabel("<html><center>GAME OVER\n<br>" + info);
label.setHorizontalAlignment(SwingConstants.CENTER);
String name=JOptionPane.showInputDialog(null, label,"Tetris", JOptionPane.INFORMATION_MESSAGE);
if (name!=null) {
HighScore.addHighScore(new HighScore(score,level,lines,(name.length()>10)?name.substring(0, 10):name,(difficulty.length()>12)?difficulty.substring(0, 12):difficulty));
}
}else {
info="You didn't get a high score:( \n<br>Keep trying you will get it next time!";
JLabel label = new JLabel("<html><center>GAME OVER\n<br>" + info);
label.setHorizontalAlignment(SwingConstants.CENTER);
JOptionPane.showMessageDialog(null, label, "Tetris", JOptionPane.PLAIN_MESSAGE);
}
if (JOptionPane.showConfirmDialog(null, "Do you want to play again?",
"Tetris", JOptionPane.YES_NO_OPTION)==JOptionPane.YES_OPTION) {
this.score=0;
this.level=0;
this.lines=0;
startGame();
}else
{
//If not, quit
System.exit(0);
}
}
public void rotatePiece(int newRotation) {
int newColumn = currentCol;
int newRow = currentRow;
int left = currentType.getLeftInset(newRotation);
int right = currentType.getRightInset(newRotation);
int top = currentType.getTopInset(newRotation);
int bottom = currentType.getBottomInset(newRotation);
if(currentCol < -left) {
newColumn -= currentCol - left;
} else if(currentCol + currentType.getDimension() - right >= COL_COUNT) {
newColumn -= (currentCol + currentType.getDimension() - right) - COL_COUNT + 1;
}
if(currentRow < -top) {
newRow -= currentRow - top;
} else if(currentRow + currentType.getDimension() - bottom >= ROW_COUNT) {
newRow -= (currentRow + currentType.getDimension() - bottom) - ROW_COUNT + 1;
}
if(isValidAndEmpty(currentType, newColumn, newRow, newRotation)) {
currentRotation = newRotation;
currentRow = newRow;
currentCol = newColumn;
}
}
public boolean isPaused() {
return isPaused;
}
public boolean isGameOver() {
return isGameOver;
}
public boolean isNewGame() {
return isNewGame;
}
public int getScore() {
return score;
}
public int getLevel() {
return level;
}
public String getDiff(){
return difficulty;
}
public int getLines() {
return lines;
}
public TileType getPieceType() {
return currentType;
}
public TileType getNextPieceType() {
return nextType;
}
public int getPieceCol() {
return currentCol;
}
public int getPieceRow() {
return currentRow;
}
public int getPieceRotation() {
return currentRotation;
}
//#Override
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_DOWN:
if(!isPaused && dropCooldown == 0) {
logicTimer.setCyclesPerSecond(25.0f);
}
break;
case KeyEvent.VK_LEFT:
if(!isPaused && isValidAndEmpty(currentType, currentCol - 1, currentRow, currentRotation)) {
currentCol--;
}
break;
case KeyEvent.VK_RIGHT:
if(!isPaused && isValidAndEmpty(currentType, currentCol + 1, currentRow, currentRotation)) {
currentCol++;
}
break;
case KeyEvent.VK_C:
if(!isPaused) {
rotatePiece((currentRotation == 0) ? 3 : currentRotation - 1);
}
break;
case KeyEvent.VK_V:
if(!isPaused) {
rotatePiece((currentRotation == 3) ? 0 : currentRotation + 1);
}
break;
case KeyEvent.VK_P:
if(!isGameOver && !isNewGame) {
isPaused = !isPaused;
logicTimer.setPaused(isPaused);
}
break;
case KeyEvent.VK_ENTER:
if(isGameOver || isNewGame) {
resetGame();
}
break;
case KeyEvent.VK_ESCAPE:
int ans = JOptionPane.showConfirmDialog(null, "Are you sure you want to quit?\n", "Tetris", JOptionPane.INFORMATION_MESSAGE);
if(ans==1 || ans==2) {
//isPaused = !isPaused;
//logicTimer.setPaused(isPaused);
return;
}else if(ans==0) {
System.exit(0);
}
}
}
}
//#Override
public void keyReleased(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_S:
logicTimer.setCyclesPerSecond(gameSpeed);
logicTimer.reset();
break;
}
}
#Override
public void keyTyped(KeyEvent e) {}
}
First of all, dont add a JMenuBar by frame.add(myJMenuBar,someConstraints). Do it by calling the method frame.setJMenuBar(myJMenuBar);
Secondly, you add the components into the frame (its content pane), and after that you frame.setLayout(new BorderLayout());, while you should first set the layout and AFTER add the components to it:
frame.setLayout(new BorderLayout());
frame.add(janela, BorderLayout.CENTER);
This works:
You might notice it replaces the ridiculously long & complicated TetrisBoard with a red panel with a preferred size of 400 x 200. This is how you should figure such things out. Post a minimal reproducible example in future.
import java.awt.*;
import javax.swing.*;
public class Tetris extends JFrame {
public Tetris() {
JFrame frame = new JFrame();
JPanel janela = new JPanel();
janela.setBackground(Color.RED);
janela.setPreferredSize(new Dimension(400,200));
JMenuBar menubar = new JMenuBar();
JMenu start = new JMenu("Start");
JMenuItem play = new JMenuItem("Play");
start.add(play);
JMenuItem exit = new JMenuItem("Exit");
start.add(exit);
JMenu help = new JMenu("Help");
JMenuItem manual = new JMenuItem("User Manual");
help.add(manual);
JMenuItem about = new JMenuItem("About");
help.add(about);
menubar.add(start);
menubar.add(help);
frame.add(janela, BorderLayout.CENTER);
frame.setJMenuBar(menubar);
janela.setFocusable(true);
frame.setTitle("Tetris");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
new Tetris();
}
}
I am kind of stuck on this issue.
Basically I have a car image that I need to have go back to the start point once it disappers off the screen on the x axis. I thought I had it fixed by my checkOFFscreen but it did not work so I am suck and asking for some guidance on how to solve this.
Mainpanel.java
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;
public class MainPanel extends JPanel {
Player myPlayer;
Player myOtherPlayer;
private int WIDTH = 1000;
private int HEIGHT = 1000;
private int WALLWIDTH = 100;
private int WALLHEIGHT = 100;
private ArrayList<Wall> walls = new ArrayList<Wall>();
Timer myTimer = new Timer(500, new timerListener());
JLabel myTimeLabel;
int time =1;
public MainPanel()
{
setPreferredSize(new Dimension(WIDTH,HEIGHT));
JLabel myLabel= new JLabel ("Game ends once 30 seconds is receahed:");
myLabel.setFont(new Font("Serif", Font.BOLD,32));
myLabel.setForeground(Color.WHITE);
myTimeLabel= new JLabel (Integer.toString(time));
myTimeLabel.setFont(new Font("Serif", Font.BOLD,32));
myTimer.start();
add(myLabel);
add(myTimeLabel);
myPlayer = new Player(0,100, "toad.png", KeyEvent.VK_UP, KeyEvent.VK_DOWN, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT,this, 50, 38);
myOtherPlayer = new Player(200,200, "toad.png", KeyEvent.VK_W, KeyEvent.VK_S, KeyEvent.VK_A, KeyEvent.VK_D,this, 50, 38);
createWalls();
}
public ArrayList<Wall> getWalls() {
return walls;
}
public void createWalls()
{
int j = 0;
for(int i = 0; i < HEIGHT/WALLHEIGHT; i++)
{
for(int k = 0; k < WIDTH/WALLWIDTH; k++)
{
if(i == 0 || i == (HEIGHT/WALLHEIGHT-1))
{
walls.add(new Wall(k*WALLWIDTH,j,"road.png", 100, 100));
}
}
j+=WALLHEIGHT;
}
}
private class timerListener implements ActionListener
{
public void actionPerformed(ActionEvent e) {
time++;
myTimeLabel.setText(Integer.toString(time));
myTimeLabel.setForeground(Color.WHITE);
if(time >= 30)
{
myTimer.stop();
}
repaint();
}
}
public void paintComponent(Graphics page)
{
super.paintComponent(page);
page.drawImage(myPlayer.getImageIcon().getImage(), myPlayer.getX(), myPlayer.getY(), null);
page.drawImage(myOtherPlayer.getImageIcon().getImage(), myOtherPlayer.getX(), myOtherPlayer.getY(), null);
for(int i = 0; i < walls.size(); i++)
{
page.drawImage(walls.get(i).getImageIcon().getImage(), walls.get(i).getX(), walls.get(i).getY(), null);
}
page.setFont(new Font("Arial", Font.PLAIN,32));
page.drawString("Player 1 Score: " + myPlayer.getScore(), 100, 800);
page.drawString("Player 2 Score: " + myOtherPlayer.getScore(), 100, 850);
if(time > 30)
{
page.drawString("GAME OVER", WIDTH/2-100, HEIGHT/2);
JOptionPane.showMessageDialog(null, "Please enter your email");
}
}
}
Player.java
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import javax.swing.ImageIcon;
public class Player extends GameObject implements KeyListener{
private int Up;
private int Down;
private int Left;
private int Right;
private MainPanel myPanel;
private Movement myMovement = new Movement();
private int score = 0;
public Player(int x, int y, String imagePath, int Up, int Down, int Left, int Right, MainPanel myPanel, int HEIGHT, int WIDTH)
{
super(x,y,imagePath, HEIGHT, WIDTH);
this.Up = Up;
this.Down = Down;
this.Left = Left;
this.Right = Right;
this.myPanel = myPanel;
myPanel.addKeyListener(this);
myPanel.setFocusable(true);
checkOffScreen();
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public void checkOffScreen(){
if (x >=1050){
x=0;
}
}
public int getScore()
{
return score;
}
#Override
public void keyPressed(KeyEvent arg0) {
// TODO Auto-generated method stub
int key = arg0.getKeyCode();
if(key == Left)
{
x-=myMovement.getDistanceLeft();
if(checkWalls())
{
x+=10;
}
}
else if(key == Right)
{
x+=myMovement.getDistanceRight();
if(checkWalls())
{
x-=10;
}
}
myPanel.repaint();
}
public boolean checkWalls()
{
ArrayList<Wall> walls = myPanel.getWalls();
for(int i = 0 ; i < walls.size(); i++)
{
if(areRectsColliding(x,x+HEIGHT,y,y+WIDTH,walls.get(i).getX(), walls.get(i).getX()+ walls.get(i).getHEIGHT(),
walls.get(i).getY(),walls.get(i).getY()+walls.get(i).getWIDTH()))
{
return true;
}
}
return false;
}
#Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
private boolean areRectsColliding(int r1TopLeftX, int r1BottomRightX,
int r1TopLeftY, int r1BottomRightY, int r2TopLeftX,
int r2BottomRightX, int r2TopLeftY, int r2BottomRightY) {
if (r1TopLeftX < r2BottomRightX && r1BottomRightX > r2TopLeftX
&& r1TopLeftY < r2BottomRightY && r1BottomRightY > r2TopLeftY) {
return true;
} else {
return false;
}
}
#Override
public ImageIcon getImageIcon() {
// TODO Auto-generated method stub
return new ImageIcon(imagePath);
}
}
checkOffScreen looks like it's in your initialization of the player, not the main loop of the game. You need to check the x when you repaint, just like when you're moving the image of the car, every time you call to move the image of the car, you need to check your x axis after it's been moved.
Pseudo code
Player.checkOffScreen();
myPanel.repaint();
This should move the car back to the beginning after it's reached the parameters given.
I just wrote some code to make my player move in my little maze game, but nothing happens. Also my maze is not drawn correct as in the matrix input. I don't figure out why is wrong this code...any help is well appeciated.
Thank you!
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import javax.swing.*;
public class Main extends JPanel {
private static Image white;
private static Image black;
private static Image finish;
private static Image player;
private static int x = 1;
private static int y = 1;
private String matrix[][];
public Main() {
addKeyListener(new Keys());
setFocusable(true);
}
public static String[][] load(String input) {
List<String[]> rows = new ArrayList<>();
try (Scanner scanner = new Scanner(input)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
String[] cols = new String[line.length()];
for (int i = 0; i < cols.length; i++) {
cols[i] = line.substring(i, i + 1);
}
rows.add(cols);
}
}
return rows.toArray(new String[rows.size()][]);
}
public static JFrame buildFrame() {
JFrame frame = new JFrame("Labyrinth Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(900, 950);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
return frame;
}
public void moveUp() {
x += 0;
y += -1;
}
public void moveLeft() {
x += -1;
y += 0;
}
public void moveDown() {
x += 0;
y += 1;
}
public void moveRight() {
x += 1;
y += 0;
}
public class Keys extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
int keycode = e.getKeyCode();
// repaint();
if (keycode == KeyEvent.VK_W) {
if (!matrix[getX()][getY() - 1].equals("1")) {
moveUp();
}
}
if (keycode == KeyEvent.VK_A) {
if (!matrix[getX() - 1][getY()].equals("1")) {
moveLeft();
}
}
if (keycode == KeyEvent.VK_S) {
if (!matrix[getX()][getY() + 1].equals("1")) {
moveDown();
}
}
if (keycode == KeyEvent.VK_D) {
if (!matrix[getX() + 1][getY()].equals("1")) {
moveRight();
}
}
}
#Override
public void keyReleased(KeyEvent event) {
}
}
public static void main(String[] args) {
String input = "1111111111111111111111111111111111111111111\n"
+ "1000000010001000001000000010000000100000001\n"
+ "1010111010101010101111101011111010111111101\n"
+ "1010001010100010100000001010000010000010001\n"
+ "1011101010111110101111111010111111111010111\n"
+ "1000101010100000101000001000100010000010001\n"
+ "1011101011101011111011101111111010111110101\n"
+ "1010001000001010000010100000001010000010101\n"
+ "1010111111111010111110111111101011111011101\n"
+ "1010100000100010100000000000101000000000101\n"
+ "1110101111101110111110111011101011111110101\n"
+ "1000100000000010000010100010001000100010001\n"
+ "1011111111111111111011101010111111101011101\n"
+ "1000000000000000100010001010000000001010001\n"
+ "1011111111111011101110111011111111111010111\n"
+ "1000100010001000001010001000100000001010101\n"
+ "1110101011101111111010101110111110111010101\n"
+ "1000101010001000100000101000100000100010001\n"
+ "1011101010111010101111101011101110101111111\n"
+ "1000001010000010000000101000001000100010001\n"
+ "1111111011111110111111101111111011111010101\n"
+ "1000001010000010100010001000000010000010101\n"
+ "1011111010111011101010111011111110101110101\n"
+ "1010000010001010001010001000100000101010101\n"
+ "1010111111101010111011101111101111101011101\n"
+ "1000100000001010101010001000100010101000101\n"
+ "1011111011111010101010111010111010101011101\n"
+ "1010000010001000101010000010001010001000001\n"
+ "1010101110101111101011101111101011111010101\n"
+ "1010101000101000001000101000001000000010101\n"
+ "1011101011111010111110111011101111111110111\n"
+ "1000001000000010000000000010000000000010021\n"
+ "1111111111111111111111111111111111111111111\n";
String[][] matrix = load(input);
JFrame frame = buildFrame();
ImageIcon img = new ImageIcon("C:/Users/Desktop/black20.png");
black = img.getImage();
img = new ImageIcon("C:/Users/Desktop/gri20.png");
white = img.getImage();
img = new ImageIcon("C:/Users/Desktop/finish20.png");
finish = img.getImage();
img = new ImageIcon("C:/Users/Desktop/smiley20.png");
player = img.getImage();
// frame.add(new Player());
JPanel pane = new JPanel() {
#Override
public void paint(Graphics g) {
super.paint(g);
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
if (matrix[i][j].equals("1")) {
g.drawImage(black, i * 20, j * 20, null);
}
if (matrix[i][j].equals("0")) {
g.drawImage(white, i * 20, j * 20, null);
}
if (matrix[i][j].equals("2")) {
g.drawImage(finish, i * 20, j * 20, null);
}
}
}
g.drawImage(player, x * 20, y * 20, null);
}
};
frame.add(pane);
frame.add(new Main());
}
}
It should look like:
Problems/Suggestions:
You're adding more than one component to the JFrame in a default fashion. Since the JFrame's contentPane uses BorderLayout, only one component will display, the last one added, and the other will be completely covered and will remain invisible.
Your Main JPanel is not being used as a true JPanel. Nothing is being added to it, and in fact it looks like it should be a logical class and not a component class.
Rather than using KeyListeners, which are very fidgety when it comes to focus problems, use Key Bindings which will allow you to get around focus issues in a clean and higher level way.
Don't override the JPanel's paint method but rather its paintComponent method as this will give you several advantages, including default use of double buffering for your animation.
Don't give component classes a public int getX() and public int getY() method without care since these override key methods that place the component within its container. Since the Main class shouldn't even extend JPanel, this will end up to be a non-issue for your code, but in the future, it would mess your program up.
When you run into similar problems, such as a KeyListener not working, remove the issue from your big program and try to reproduce it in a small separate program. This will give you a much cleaner environment for helping you to isolate and understand your problem and thereby help you fix it.
Your program is mis-using the static modifier. Your x and y fields should not be static and should not be accessed in a static way.
You've got way too much code within your main method, which is one of the reasons why you likely made x and y static, because you were forced to do so since you're trying to access them within main. The solution is not to make the fields static but to get all that code out of the static world and into the instance world.
Edit
For some reason the question intrigued me, and so I decided to try to M-V-C or Model-View-Controller it if possible and see what I could come up with. So here goes a bunch of classes that sort of work, beginning with a text file that holds the data.
The GUI looks like:
It must be in the same location as the class files since it is obtained as a resource and must have the file name "input.txt"
1111111111111111111111111111111111111111111
1000000010001000001000000010000000100000001
1010111010101010101111101011111010111111101
1010001010100010100000001010000010000010001
1011101010111110101111111010111111111010111
1000101010100000101000001000100010000010001
1011101011101011111011101111111010111110101
1010001000001010000010100000001010000010101
1010111111111010111110111111101011111011101
1010100000100010100000000000101000000000101
1110101111101110111110111011101011111110101
1000100000000010000010100010001000100010001
1011111111111111111011101010111111101011101
1000000000000000100010001010000000001010001
1011111111111011101110111011111111111010111
1000100010001000001010001000100000001010101
1110101011101111111010101110111110111010101
1000101010001000100000101000100000100010001
1011101010111010101111101011101110101111111
1000001010000010000000101000001000100010001
1111111011111110111111101111111011111010101
1000001010000010100010001000000010000010101
1011111010111011101010111011111110101110101
1010000010001010001010001000100000101010101
1010111111101010111011101111101111101011101
1000100000001010101010001000100010101000101
1011111011111010101010111010111010101011101
1010000010001000101010000010001010001000001
1010101110101111101011101111101011111010101
1010101000101000001000101000001000000010101
1011101011111010111110111011101111111110111
1000001000000010000000000010000000000010021
1111111111111111111111111111111111111111111
Next the main program, the one that creates the model, the view, and the controller, hooks them all together, and then displays the GUI:
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
/**
* link: http://stackoverflow.com/a/41418250/522444
*
* #author Pete
*
*/
#SuppressWarnings("serial")
public class Main2 extends JPanel {
private View mainPanel;
public Main2(MatrixModel matrixModel) {
mainPanel = new View(matrixModel);
new Controller(matrixModel, mainPanel);
setLayout(new BorderLayout());
add(mainPanel, BorderLayout.CENTER);
}
private static void createAndShowGui(MatrixModel model) {
Main2 mainPanel = new Main2(model);
JFrame frame = new JFrame("Main2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
final MatrixModel model = MatrixUtil.getInput(MatrixUtil.PATH_TO_RSC);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui(model);
}
});
}
}
Next a utility class with static methods for reading in the text file as a resource and converting it into a Model object:
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class MatrixUtil {
// again this text file must be in the jar file or the code base
// at the same location as the class / java files
public static final String PATH_TO_RSC = "input.txt";
public static MatrixModel getInput(String resourcePath) {
InputStream is = MatrixUtil.class.getResourceAsStream(resourcePath);
if (is == null) {
String text = "resourcePath is not found and not loading text: " + resourcePath;
throw new IllegalArgumentException(text);
}
return getInput(is);
}
public static MatrixModel getInput(InputStream is) {
MatrixModel model = null;
try (Scanner scan = new Scanner(is)) {
List<List<MatrixPosition>> listOfLists = new ArrayList<>();
while (scan.hasNextLine()) {
String line = scan.nextLine();
if (line.trim().isEmpty()) {
continue;
}
List<MatrixPosition> list = new ArrayList<>();
for (char c : line.toCharArray()) {
list.add(MatrixPosition.getMatrixPosition(String.valueOf(c)));
}
listOfLists.add(list);
}
MatrixPosition[][] grid = new MatrixPosition[listOfLists.size()][];
for (int i = 0; i < grid.length; i++) {
List<MatrixPosition> list = listOfLists.get(i);
grid[i] = list.toArray(new MatrixPosition[] {});
}
model = new MatrixModel(grid, new SpritePosition(1, 1));
}
return model;
}
}
Basic enum to represent direction:
public enum Direction {
UP, DOWN, LEFT, RIGHT
}
Another enum to represent a location point in the grid, and whether it is a wall, a coridor or the end as well as static methods to convert from number to MatrixPosition:
public enum MatrixPosition {
WALL(1), CORRIDOR(0), END(2);
private int value;
private MatrixPosition(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static MatrixPosition getMatrixPosition(int value) {
for (MatrixPosition position : MatrixPosition.values()) {
if (value == position.getValue()) {
return position;
}
}
String text = "value of " + value;
throw new IllegalArgumentException(text);
}
public static MatrixPosition getMatrixPosition(String strValue) {
int value = -1;
try {
value = Integer.parseInt(strValue);
} catch (NumberFormatException e) {
String text = "NumberFormatException for strValue " + strValue;
throw new IllegalAccessError(text);
}
return getMatrixPosition(value);
}
}
A class to represent a position of our sprite, similar to the java.awt.Point class but with row and column fields instead of x and y:
public class SpritePosition {
int row;
int column;
public SpritePosition(int row, int column) {
this.row = row;
this.column = column;
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getColumn() {
return column;
}
public void setColumn(int column) {
this.column = column;
}
public void setRowColumn(int row, int column) {
this.row = row;
this.column = column;
}
}
The model has property change support code so that it can notify any classes listening to it of any changes in its state. The controller will be the class listening to the model
import java.beans.PropertyChangeListener;
import javax.swing.event.SwingPropertyChangeSupport;
public class MatrixModel {
public static final String SPRITE_POINT = "sprite point";
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this);
private MatrixPosition[][] grid;
private SpritePosition spritePosition;
public MatrixModel(MatrixPosition[][] grid, SpritePosition spritePosition) {
this.grid = grid;
this.spritePosition = spritePosition;
}
public int getRows() {
return grid.length;
}
public int getColumns() {
return grid[0].length;
}
public MatrixPosition getPosition(SpritePosition p) {
return getPosition(p.row, p.column);
}
public MatrixPosition getPosition(int row, int col) {
return grid[row][col];
}
public void setSpritePoint(SpritePosition spritePosition) {
SpritePosition oldValue = this.spritePosition;
SpritePosition newValue = spritePosition;
this.spritePosition = spritePosition;
pcSupport.firePropertyChange(SPRITE_POINT, oldValue, newValue);
}
public boolean isPointValid(SpritePosition p) {
if (p.column < 0 || p.row < 0) {
return false;
}
if (p.column >= grid[0].length || p.row >= grid.length) {
return false;
}
return grid[p.row][p.column] == MatrixPosition.CORRIDOR;
}
public boolean isMoveValid(Direction direction) {
int row = spritePosition.row;
int column = spritePosition.column;
switch (direction) {
case UP:
return isPointValid(new SpritePosition(row - 1, column));
case DOWN:
return isPointValid(new SpritePosition(row + 1, column));
case LEFT:
return isPointValid(new SpritePosition(row, column - 1));
case RIGHT:
return isPointValid(new SpritePosition(row, column + 1));
default:
return false;
}
}
public void move(Direction direction) {
if (!isMoveValid(direction)) {
String text = "For move to " + direction + "spritePosition: " + spritePosition;
throw new IllegalArgumentException(text);
}
int row = spritePosition.row;
int column = spritePosition.column;
switch (direction) {
case UP:
setSpritePoint(new SpritePosition(row - 1, column));
break;
case DOWN:
setSpritePoint(new SpritePosition(row + 1, column));
break;
case LEFT:
setSpritePoint(new SpritePosition(row, column - 1));
break;
case RIGHT:
setSpritePoint(new SpritePosition(row, column + 1));
break;
default:
break;
}
}
public SpritePosition getSpritePosition() {
return spritePosition;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
public void addPropertyChangeListener(String name, PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(name, listener);
}
public void removePropertyChangeListener(String name, PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(name, listener);
}
}
Controller class, one that sets up key bindings on the view so that it can listen for key presses, checks if they represent a valid move, and if so then tells the model to make the move. It also adds a listener to the model so that when its state changes, it will tell the view to move the sprite
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EnumMap;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
public class Controller {
private MatrixModel model;
private View view;
private Map<Direction, KeyStroke> dirKeyMap = new EnumMap<>(Direction.class);
public Controller(MatrixModel model, View view) {
this.model = model;
this.view = view;
dirKeyMap.put(Direction.DOWN, KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0));
dirKeyMap.put(Direction.UP, KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0));
dirKeyMap.put(Direction.LEFT, KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0));
dirKeyMap.put(Direction.RIGHT, KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));
model.addPropertyChangeListener(new ModelListener());
setUpKeyBindings(view);
}
private void setUpKeyBindings(View view) {
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = view.getInputMap(condition);
ActionMap actionMap = view.getActionMap();
for (Direction dir : Direction.values()) {
KeyStroke keyStroke = dirKeyMap.get(dir);
hookUp(inputMap, actionMap, dir, keyStroke);
}
}
private void hookUp(InputMap inputMap, ActionMap actionMap, Direction dir, KeyStroke key) {
inputMap.put(key, key.toString());
actionMap.put(key.toString(), new MoveAction(dir, model));
}
public MatrixModel getModel() {
return model;
}
public View getView() {
return view;
}
class ModelListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (MatrixModel.SPRITE_POINT.equals(evt.getPropertyName())) {
SpritePosition p = model.getSpritePosition();
view.setSpritePoint(p);
}
}
}
}
#SuppressWarnings("serial")
class MoveAction extends AbstractAction {
private Direction dir;
private MatrixModel model;
public MoveAction(Direction dir, MatrixModel model) {
super(dir.toString());
this.dir = dir;
this.model = model;
}
public void actionPerformed(ActionEvent e) {
if (model.isMoveValid(dir)) {
model.move(dir);
}
}
}
Finally the View class, that extends JPanel, that displays the maze and the sprite:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class View extends JPanel {
private static final int CELL_WIDTH = 20;
private static final Color CORRIDOR_COLOR = Color.LIGHT_GRAY;
private static final Color WALL_COLOR = Color.DARK_GRAY;
private static final Color END_COLOR = Color.ORANGE;
private static final Color SPRITE_COLOR = Color.RED;
private static final int GAP = 1;
private BufferedImage gridImg = null;
private SpritePosition spritePosition;
private JPanel mainPanel = new JPanel();
public View(MatrixModel matrixModel) {
gridImg = createImg(matrixModel);
spritePosition = matrixModel.getSpritePosition();
}
public JPanel getMainPanel() {
return mainPanel;
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet() || gridImg == null) {
return super.getPreferredSize();
}
int prefW = gridImg.getWidth();
int prefH = gridImg.getHeight();
return new Dimension(prefW, prefH);
}
public void setSpritePoint(SpritePosition spritePosition) {
this.spritePosition = spritePosition;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (gridImg != null) {
g.drawImage(gridImg, 0, 0, this);
}
g.setColor(SPRITE_COLOR);
int y = spritePosition.row * CELL_WIDTH + GAP;
int x = spritePosition.column * CELL_WIDTH + GAP;
g.fillRect(x, y, CELL_WIDTH - 2 * GAP, CELL_WIDTH - 2 * GAP);
}
private BufferedImage createImg(MatrixModel matrixModel) {
BufferedImage img = null;
if (matrixModel != null && matrixModel.getRows() > 0) {
int w = matrixModel.getColumns() * CELL_WIDTH;
int h = matrixModel.getRows() * CELL_WIDTH;
img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
for (int row = 0; row < matrixModel.getRows(); row++) {
for (int col = 0; col < matrixModel.getColumns(); col++) {
MatrixPosition position = matrixModel.getPosition(row, col);
Color c = null;
switch (position) {
case CORRIDOR:
c = CORRIDOR_COLOR;
break;
case WALL:
c = WALL_COLOR;
break;
case END:
c = END_COLOR;
break;
}
g2.setColor(c);
int x = col * CELL_WIDTH;
int y = row * CELL_WIDTH;
g2.fillRect(x, y, CELL_WIDTH, CELL_WIDTH);
}
}
g2.dispose();
}
return img;
}
}
When I set X and Y values for my array of JButtons, I get back the correct values only multiplied by 93. I can solve the problem by dividing the value by 93 but I would rather find out where the bug was in the first place.
I have two classes in the code, one for the actual program, and one for the button object along with the coordinates.
Here's the code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.GridLayout;
import java.io.*;
public class ConnectFour implements ActionListener
{
JFrame frame = new JFrame();
Button [][] buttons = new Button[6][7];
public ConnectFour()
{
frame.setSize(700,600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(6,7));
frame.setLocationRelativeTo(null);
frame.setTitle("Connect Four");
for(int filler = 0; filler <= 5; filler++)
{
for(int filler2 = 0; filler2 <= 6; filler2++)
{
buttons[filler][filler2] = new Button();
buttons[filler][filler2].setX(filler2);
buttons[filler][filler2].setY(filler);
//System.out.println(buttons[filler][filler2].getX());
//System.out.print(buttons[filler][filler2].getY());
frame.add(buttons[filler][filler2].button);
buttons[filler][filler2].button.addActionListener(this);
}
}
frame.setVisible(true);
}
public void actionPerformed(ActionEvent a)
{
JButton pressedButton = (JButton)a.getSource();
System.out.print(pressedButton.getY() / 93);
System.out.print(pressedButton.getX() / 93);
}
public static void main(String args[])
{
ConnectFour gameplay = new ConnectFour();
}
}
Here's the Button class:
import javax.swing.JButton;
public class Button
{
JButton button;
private int x = 0;
private int y = 0;
public Button()
{
button = new JButton();
}
public int getX() {return x;}
public int getY() {return y;}
public void setX(int xIndex)
{
x = xIndex;
}
public void setY(int yIndex)
{
y = yIndex;
}
}
You're mixing your two Button classes.
In this line, you're adding an actionListener to Button.button:
buttons[filler][filler2].button.addActionListener(this);
because JButton also has methods getX and getY, you can call them. When you do:
pressedButton.getX()
you're getting the x position of the JButton, not of your Button.
What I think would be the easiest way to solve this problem is making your button extend JButton and rename x and y to row and column, for instance:
public class Button extends JButton {
private int row = 0;
private int column = 0;
public Button(int row, int column) {
super();
this.row = row;
this.column = column;
}
public int getRow() {return row;}
public int getColumn() {return column;}
}
You can create you buttons as
for(int filler = 0; filler <= 5; filler++) {
for(int filler2 = 0; filler2 <= 6; filler2++) {
buttons[filler][filler2] = new Button(filler2, filler);
frame.add(buttons[filler][filler2]);
buttons[filler][filler2].addActionListener(this);
}
}
And use them in the ActionListener as
public void actionPerformed(ActionEvent a) {
Button pressedButton = (Button)a.getSource();
System.out.print(pressedButton.getColumn());
System.out.print(pressedButton.getRow());
}
I could not figure how to do it using your composition example, but this one works as you might want.
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.GridLayout;
import java.io.*;
public class ConnectFour implements ActionListener
{
JFrame frame = new JFrame();
CustomButton [][] buttons = new CustomButton[6][7];
public ConnectFour()
{
frame.setSize(700,600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(6,7));
frame.setLocationRelativeTo(null);
frame.setTitle("Connect Four");
for(int filler = 0; filler <= 5; filler++)
{
for(int filler2 = 0; filler2 <= 6; filler2++)
{
buttons[filler][filler2] = new CustomButton(filler,filler2);
frame.add(buttons[filler][filler2]);
buttons[filler][filler2].addActionListener(this);
}
}
frame.setVisible(true);
}
public void actionPerformed(ActionEvent a)
{
CustomButton pressedButton = (CustomButton)a.getSource();
System.out.println(pressedButton.getRow() + "/" + pressedButton.getCol());
}
public static void main(String args[])
{
ConnectFour gameplay = new ConnectFour();
}
}
class CustomButton extends JButton
{
private int row = 0;
private int col = 0;
public CustomButton(int row, int col)
{
this.row = row;
this.col = col;
}
public int getRow() {return row;}
public int getCol() {return col;}
public void setRow(int row)
{
this.row = row;
}
public void setCol(int col)
{
this.col = col;
}
}
I think x and y are defined in the superclass, try changing the variable names to something else. e.g.
private int myX = 0;
private int myY = 0;