I am trying within exercise to put into ArrayList a set of Picture objects, then shuffle them randomly and display them as a grid of 3x3. However, the shuffle method does not work correctly for me. Or perhaps I am doing anything wrong within draw or drawImage methods, I don't know.
I am always getting picture displayed from 9 pieces in their original order, not randomly shuffled.
See below my PicturePiece class as well as the main class.
package lab;
import java.awt.Graphics2D;
import java.awt.Image;
import java.io.File;
import javax.imageio.ImageIO;
public class PicturePiece {
private int IMAGE_X = 266;
private int IMAGE_Y = 224;
private final int row;
private final int col;
private Image img;
private static int count = 0;
private int id = 0;
public PicturePiece(int row, int col, File f) {
try {
this.img = ImageIO.read(f);
} catch (Exception e) {
e.printStackTrace();
}
this.row = this.IMAGE_X * row;
this.col = this.IMAGE_Y * col;
PicturePiece.count++;
this.id = PicturePiece.count;
}
public void draw(Graphics2D g2) {
g2.drawImage(this.img, this.row, this.col, null);
}
public void setPosition(int row, int col) {
this.IMAGE_X = row;
this.IMAGE_Y = col;
}
public int getXposition() {
return this.IMAGE_X;
}
public int getYposition() {
return this.IMAGE_Y;
}
public int getRow() {
return this.row;
}
public int getCol() {
return this.col;
}
public String getImage() {
return this.img.toString();
}
public static int getPictureCount() {
return PicturePiece.count;
}
public int getId() {
return this.id;
}
}
And here is my main class:
/*
Find a pretty image from the Internet and use an image editor to break it down
into 9 pieces (for example, you can use the application Paint in Windows).
Display the 9 images in a 3×3 grid in a random order. Add a mouse listener.
Allow the user to swap two images by clicking on them.
The goal of the game is to re-create the original image.
Display an appropriate message when the user wins.
*/
package lab;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.util.*;
public class Puzzle {
public static void main(String[] args) throws Exception {
MyFrame frame = new MyFrame();
frame.setSize(1000, 1000);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class MyFrame extends JFrame {
MyPanel p;
public MyFrame() {
p = new MyPanel();
add(p);
setVisible(true);
}
}
class MyPanel extends JPanel {
private ArrayList<PicturePiece> images = new ArrayList<PicturePiece>();
public MyPanel() {
this.setFocusable(true);
try {
int j = 0, k = 0, pocet = 0;
for (int i = 1; i <= 9; i++) {
//g2.drawImage(images.get(i), (IMAGE_X * (j)), (IMAGE_Y * (k)), null);
images.add(new PicturePiece(j, k, new File(("/home/ivo/Pictures/domcek/domcek" + i + ".jpg"))));
pocet++;
//System.out.println("j = " + (j - 1) + "; k = " + (k - 1) + "; i = " + i + "; pocet = " + pocet);
if ((pocet % 3) == 0) {
j = 0;
k++;
} else {
j = j + 1;
}
}
} catch (Exception e) {
}
//Random rnd = new Random();
//rnd.setSeed(400);
//Collections.shuffle(images, rnd);
Collections.shuffle(images);
}
public void draw(Graphics2D g2) {
try {
for (int i = 0; i <= images.size(); i++) {
images.get(i).draw(g2);
}
} catch (Exception my) {
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
draw(g2);
}
}
Your error arises because you are setting the row/column (j and k) in the MyPanel function.
So the shuffle only changes the order of the PicturePiece in the list, not the j/k that you use for the position.
In order to achieve the behavior you would like I would generate the row/column from the order in the list.
the problem is that you draw the image based in init coordinates, even if you suffle them, the coordinates remain the same in the PicturePiece objects.
short solution:
change in PicturePiece:
public void draw(Graphics2D g2, int i, int j) {
g2.drawImage(this.img, this.IMAGE_X *i, this.IMAGE_Y * j, null);
}
change in Puzzle:
public void draw(Graphics2D g2) {
try {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
System.out.println(i*3+j);
images.get(i*3+j).draw(g2, i ,j);
}
}
} catch (Exception my) {
}
}
this way you will get images in the same order from the array, but if they are shuffled inside the array, the image will be different at each execution.
Note: this is a hardcoded version (ok only for 3x3 matrix) but I hope you got the ideea. There are many other solutions to this but this is the shortest one I could think of.
Instead of drawing, on to the JPanel/JComponent, it would be wise to use a JLabelfor this purpose, which will make your work a bit easier, as you only have to worry about the index positions.
Here is one example:
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.util.*;
import javax.imageio.ImageIO;
import javax.swing.*;
public class TestingImages {
private static final String IMAGE_HEADER = "/images/windowicon/windowicon";
private GUIView guiView;
private void performTask () {
try {
guiView = new GUIView (IMAGE_HEADER);
} catch (Exception exp) {
exp.printStackTrace ();
}
Runnable runnable = new Runnable () {
#Override
public void run () {
guiView.displayGUI ();
}
};
EventQueue.invokeLater (runnable);
}
public static void main (String[] args) {
new TestingImages ().performTask ();
}
}
class GUIView {
private static final int ROWS = 3;
private static final int COLUMNS = 3;
private static final int GAP = 5;
private static final int TOTAL_IMAGES = 9;
private JLabel originalImageLabel;
private JLabel[] splitImageLabel;
private int counter;
private int[] imageMap;
private int previousIndex;
private int currentIndex;
private MouseAdapter labelAdapter = new MouseAdapter () {
private int counter = 0;
#Override
public void mouseClicked (MouseEvent me) {
JLabel label = (JLabel) me.getSource ();
if (counter == 0) {
/*
* On first click, we simply keeping track of on which label
* the user clicked in the first place
*/
previousIndex = findLabelIndex (label);
System.out.println("Previous Index: " + previousIndex);
counter = 1;
} else if (counter == 1) {
/*
* On second click, firstly we will get the location of the JLabel
* on which the user clicked, then we will simply swap the icon as
* well as the Name of this JLabel with the JLabel at previousIndex
*/
currentIndex = findLabelIndex (label);
System.out.println("Current Index: " + currentIndex);
ImageIcon tempIcon = (ImageIcon) splitImageLabel[previousIndex].getIcon ();
splitImageLabel[previousIndex].setIcon (splitImageLabel[currentIndex].getIcon ());
splitImageLabel[currentIndex].setIcon (tempIcon);
String labelName = splitImageLabel[previousIndex].getName ();
splitImageLabel[previousIndex].setName (splitImageLabel[currentIndex].getName ());
splitImageLabel[currentIndex].setName (labelName);
prepareModel ();
counter = 0;
}
if (hasWon()) {
System.out.println("CONGRATULATIONS you won :-)");
}
}
};
public GUIView (String imageHeader) throws IOException {
imageMap = new int[TOTAL_IMAGES];
counter = 0;
originalImageLabel = new JLabel ();
originalImageLabel.setIcon (new ImageIcon (
ImageIO.read (GUIView.class.getResource (
imageHeader + ".jpg"))));
splitImageLabel = new JLabel[TOTAL_IMAGES];
for (int i = 0; i < ROWS; ++i) {
for (int j = 0; j < COLUMNS; ++j) {
splitImageLabel[counter] = new JLabel ();
String indexValue = "" + counter;
/*
* Since JLabel[] is a 1-D Array, hence we simply giving
* each JLabel, at each index a name, as 0 1 2 3 and so on
*/
splitImageLabel[counter].setName (indexValue);
splitImageLabel[counter].setIcon (new ImageIcon (ImageIO.read (
GUIView.class.getResource (imageHeader + i + "-" + j + ".png"))));
splitImageLabel[counter].addMouseListener (labelAdapter);
++counter;
}
}
}
public void displayGUI () {
JFrame frame = new JFrame("Testing Images");
frame.setDefaultCloseOperation (JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel ();
contentPane.setBorder (BorderFactory.createEmptyBorder (GAP, GAP, GAP, GAP));
contentPane.setLayout (new GridLayout (2, 1, GAP, GAP));
JPanel headerPanel = new JPanel ();
headerPanel.setBorder (BorderFactory.createEmptyBorder (GAP, GAP, GAP, GAP));
headerPanel.add (originalImageLabel);
contentPane.add (headerPanel);
JPanel footerPanel = new JPanel ();
footerPanel.setBorder (BorderFactory.createEmptyBorder (GAP, GAP, GAP, GAP));
footerPanel.setLayout (new GridLayout (ROWS, COLUMNS, GAP, GAP));
/*
* This will Shuffle the JLable[] array
*/
Collections.shuffle (Arrays.asList (splitImageLabel));
prepareModel ();
for (int i = 0; i < TOTAL_IMAGES; ++i) {
footerPanel.add (splitImageLabel[i]);
}
contentPane.add (footerPanel);
frame.setContentPane (contentPane);
frame.pack ();
frame.setLocationByPlatform (true);
frame.setVisible (true);
}
private int findLabelIndex (JLabel label) {
int index = 0;
for (int i = 0; i < TOTAL_IMAGES; ++i) {
if (label.getName ().equals(splitImageLabel[i].getName ())) {
index = i;
break;
}
}
return index;
}
/*
* hasWon() is used to simply check, if the array has values
* 0 1 2 3 4 till TOTAL_IMAGES, i.e. in increasing order, then it
* means, that the image has been rightly placed, by the user.
* Hence, the GAME is OVER
*/
private boolean hasWon () {
boolean flag = true;
for (int i = 0; i < TOTAL_IMAGES; ++i) {
if (imageMap[i] != i) {
flag = false;
}
}
return flag;
}
/*
* PrepareModel() is used to assign values to imageMap[] array,
* in the same sequence, in which the JLabel is placed inside
* JLabel[] array. Say JLabel[] array has JLabels with names in
* this order 1 5 4 3 and so on, thus imageMap[] will contain
* values 1 5 4 3 and so on, once they are in sorted order, then
* we can easily check for winning condition
*/
private void prepareModel () {
System.out.println("Preparing MODEL");
for (int i = 0; i < TOTAL_IMAGES; ++i) {
imageMap[i] = getIntValue(splitImageLabel[i].getName ());
System.out.println("i: " + i + " Name: " + splitImageLabel[i].getName ());
}
System.out.println("Exiting MODEL");
}
private int getIntValue (String text) {
int value = 0;
try {
value = Integer.parseInt (text);
} catch (Exception exp) {
exp.printStackTrace ();
}
return value;
}
}
OUTPUT:
IMAGES USED:
ORIGINAL IMAGE: http://i.imgur.com/GNIZRQy.jpg
To SPLIT, I used this site: http://imagesplitter.net/
let me first thank you for your time and effort.
I wrote my application/lab this way:
package lab;
import java.awt.Graphics2D;
import java.awt.Image;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class PicturePiece extends JPanel {
private Image img;
private int id = 0;
public PicturePiece(int id) {
this.id = id;
}
public void setImage(File f) {
try {
this.img = ImageIO.read(f);
} catch (Exception e) {
}
}
public String getImage() {
return this.img.toString();
}
public int getId() {
return this.id;
}
public void draw(Graphics2D g2, int row, int col) {
g2.drawImage(this.img, row, col, null);
}
}
/**
* Find a pretty image from the Internet and use an image editor to break it
* down into 9 pieces (for example, you can use the application Paint in
* Windows). Display the 9 images in a 3×3 grid in a random order. Add a mouse
* listener. Allow the user to swap two images by clicking on them. The goal of
* the game is to re-create the original image. Display an appropriate message
* when the user wins.
*/
package lab;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D;
import java.io.File;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.util.*;
public class Puzzle {
public static void main(String[] args) throws Exception {
MyFrame frame = new MyFrame();
frame.setSize((266 * 3) + 10, (224 * 3) + 10);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class MyFrame extends JFrame {
MyPanel p;
public MyFrame() {
p = new MyPanel();
add(p);
setVisible(true);
}
}
class MyPanel extends JPanel implements MouseListener {
public static final int IMAGE_X = 266;
public static final int IMAGE_Y = 224;
public static final int PAD = 5;
private int counter = 0;
private int previouspicture = -1;
private int currentpicture = -1;
private boolean won = false;
private ArrayList<PicturePiece> images = new ArrayList<PicturePiece>();
public MyPanel() {
this.setFocusable(true);
for (int i = 0; i < 9; i++) {
images.add(new PicturePiece(i));
}
Random rnd = new Random();
rnd.setSeed(40000);
Collections.shuffle(images, rnd);
try {
for (int i = 0; i < images.size(); i++) {
images.get(i).setImage(new File(("src/chapter/domcek/domcek" + (images.get(i).getId() + 1) + ".jpg")));
}
} catch (Exception e) {
}
addMouseListener(this);
}
public void draw(Graphics2D g2) {
int j = 0, k = 0, pocet = 0;
for (int i = 0; i < 9; i++) {
images.get(i).draw(g2, j * (IMAGE_X + PAD), k * (IMAGE_Y + PAD));
pocet++;
if ((pocet % 3) == 0) {
j = 0;
k++;
} else {
j = j + 1;
}
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
validate();
draw(g2);
if (won == true) {
showMessage("You won!!!", g2);
}
}
/**
* checks whether user clicked on two different pictures and if yes, changes
* their order
*
* #param e - event object
*/
#Override
public void mouseClicked(MouseEvent e) {
int picturepiece_id;
if (counter == 0) {
previouspicture = getPicturePiece(e.getX(), e.getY());
counter = 1;
} else if (counter == 1) {
counter = 0;
currentpicture = getPicturePiece(e.getX(), e.getY());
if ((previouspicture != currentpicture) && (previouspicture != -1) && (currentpicture != -1)) {
swap(previouspicture, currentpicture);
repaint();
int j = 0;
int i = 0;
i = 0;
while ((j == i) && (i < images.size()) && (j < images.size())) {
i++;
j = images.get(i).getId();
if ((j == 8) && (i == 8)) {
won = true;
removeMouseListener(this);
repaint();
break;
}
}
}
}
}
/**
* prints message on winning
*
* #param s - message to print
* #param g2 - graphical context
*/
public void showMessage(String s, Graphics2D g2) {
Font myFont = new Font(" SansSerif ", Font.BOLD, 100);
g2.setFont(myFont);
g2.setColor(Color.BLUE);
Rectangle2D textBox = myFont.getStringBounds(s, g2.getFontRenderContext());
g2.drawString(s, (int) (getWidth() / 2 - textBox.getWidth() / 2), (int) (getHeight() / 2 - textBox.getHeight()));
}
/**
* returns order number of picture within 3x3 grid where user clicked
*
* #param x - X coordinate
* #param y - Y coordinate
* #return
*/
private int getPicturePiece(int x, int y) {
if ((x <= IMAGE_X) && (y <= IMAGE_Y)) {
return 0;
} else if (((x > IMAGE_X) && (x <= IMAGE_X * 2)) && (y <= IMAGE_Y)) {
return 1;
} else if (((x > IMAGE_X) && (x <= IMAGE_X * 3)) && (y <= IMAGE_Y)) {
return 2;
} else if ((x <= IMAGE_X) && ((y > IMAGE_Y) && (y <= (IMAGE_Y * 2)))) {
return 3;
} else if (((x > IMAGE_X) && (x <= (IMAGE_X * 2))) && ((y > IMAGE_Y) && (y <= (IMAGE_Y * 2)))) {
return 4;
} else if (((x > IMAGE_X) && (x <= (IMAGE_X * 3))) && ((y > IMAGE_Y) && (y <= (IMAGE_Y * 2)))) {
return 5;
} else if ((x <= IMAGE_X) && ((y > IMAGE_Y) && (y <= (IMAGE_Y * 3)))) {
return 6;
} else if (((x > IMAGE_X) && (x <= (IMAGE_X * 2))) && ((y > IMAGE_Y) && (y <= (IMAGE_Y * 3)))) {
return 7;
} else if (((x > IMAGE_X) && (x <= (IMAGE_X * 3))) && ((y > IMAGE_Y) && (y <= (IMAGE_Y * 3)))) {
return 8;
} else {
return -1;
}
}
/**
* swaps two clicked different pictures
*
* #param previouspic - first picture
* #param currentpic - second picture
*/
public void swap(int previouspic, int currentpic) {
int temp = 0;
int a = previouspic;
int b = currentpic;
PicturePiece p = images.get(a);
PicturePiece p2 = images.get(b);
images.set(a, p2);
images.set(b, p);
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
Related
I created a very simple shooting game utilizing JPanel as shown in the code below. I also wanted to experiment with rotating the game and trying it out. I have one issue, where the game I was able to successfully rotate the game but the dimension seems to cut out, and I have to set each position of the enemy and myself to the rotated position.
I was wondering if there was a way to rotate the result as a whole, instead of simply rotating the shape so that the position of the ship and the missiles would also rotate all at once.
Edited code: added three lives to the player and tried implementing heart image with BufferedImage.
public class game extends JFrame{
public game(){
}
public static void main(String[] args){
new game();
}
public class MyJPanel extends JPanel implements ActionListener, MouseListener,
MouseMotionListener,KeyListener
{
//variables for player
int my_x;
int player_width,player_height;
private int lives = 3;
int heart_width, heart_height;
//variables for player's missiles
int my_missile_x, my_missile_y;
int missile_flag;
public static final int MY_Y = 600;
//variables for enemies' missiles
int e_missile_flag[];
int e_missile_x[];
int e_missile_y[];
int e_missile_move[];
Image image,image2;
Timer timer;
private BufferedImage heart;
public MyJPanel(){
missile_flag = 0;
/*** initialize enemies' info ***/
ImageIcon icon2 = new ImageIcon("enemy.jpg");
image2 = icon2.getImage();
enemy_width = image2.getWidth(this);
enemy_height = image2.getHeight(this);
try {
heart = ImageIO.read(getClass().getResource("heart.jpg"));
}catch(IOException e) {
}
heart_width = heart.getWidth(this);
heart_height = heart.getHeight(this);
n = 14; //number of enemies
enemy_x = new int[n];
enemy_y = new int[n];
enemy_move = new int[n];
enemy_alive = new int[n];
int distance = 40;
e_missile_flag = new int[n];
e_missile_x = new int[n];
e_missile_y = new int[n];
e_missile_move = new int[n];
// place enemies in 7x2
for (int i = 0; i < 7; i++) {
enemy_x[i] = (enemy_width + distance) * i + 50;
enemy_y[i] = 50;
}
for (int i = 7; i < n; i++) {
enemy_x[i] = (enemy_width + distance) * (i - 5) + 50;
enemy_y[i] = 100;
}
for (int i = 0; i < n; i++) {
enemy_alive[i] = 1; //all alive
enemy_move[i] = -10; //moves to left
}
for (int i = 0; i < n; i++) {
e_missile_flag[i] = 0;
e_missile_x[i] = 0;
e_missile_y[i] = 0;
e_missile_move[i] = 7 + n%3;
}
/*** setup system ***/
setBackground(Color.black);
setFocusable(true);
addMouseListener(this);
addMouseMotionListener(this);
addKeyListener(this);
timer = new Timer(50, this);
timer.start();
}
private void updateEnemiesPosition(){
//update enemies' position
Dimension dim = getSize();
for (int i = 0; i < n; i++) {
enemy_x[i] += enemy_move[i];
if ((enemy_x[i] < 0) || (enemy_x[i] > (dim.width - enemy_width))) {
enemy_move[i] = -enemy_move[i];
}
}
}
private void updateMyPosition() {
if(my_x < 0) {
my_x = 800;
}
if(my_x > 800) {
my_x = 0;
}
}
private void activateMyMissile(){
//shoot a missile
if(missile_flag == 0){
my_missile_x = my_x + player_width / 2;
my_missile_y = MY_Y; //MY_Y=400
missile_flag = 1;
}
}
private void updateMyMissile(){
//update missile position if alive
if (missile_flag == 1) {
my_missile_y -= 15;
if (0 > my_missile_y) {
missile_flag = 0;
}
}
}
private void activateEnemiesMissile(){
//activate enemies' missile if enemy is alive and its missile is not alive
for(int i = 0; i < n; i++){
if (enemy_alive[i] == 1 && e_missile_flag[i] == 0) {
e_missile_x[i] = enemy_x[i] + enemy_width/2;
e_missile_y[i] = enemy_y[i];
e_missile_flag[i] = 1;
}
}
}
private void updateEnemiesMissile(){
//update enemies' missile position if alive
Dimension dim = getSize();
for(int i = 0; i < n; i++){
if (e_missile_flag[i] == 1) {
e_missile_y[i] += e_missile_move[i];
if (e_missile_y[i] > dim.height) {
e_missile_flag[i] = 0;
}
}
}
}
private void checkHitToEnemy(){
for(int i = 0; i < n; i++){
if(missile_flag == 1 && enemy_alive[i] == 1){
if(
my_missile_x > enemy_x[i] &&
my_missile_x < (enemy_x[i] + enemy_width) &&
my_missile_y > enemy_y[i] &&
my_missile_y < (enemy_y[i] + enemy_height)
){
//hit
missile_flag = 0;
enemy_alive[i] = 0;
}
}
}
}
private boolean checkClear(){
int cnt = 0;
for(int i = 0; i < n; i++){
if(enemy_alive[i] == 0) cnt++;
}
return (n == cnt);
}
if(lives>0) {
int x = 0;
int y = getHeight()- heart.getHeight();
for(int index = 0; index < lives; index++) {
g.drawImage(heart, x, y, this);
x += heart.getWidth();
}
}
g2d.dispose();
}
public void actionPerformed(ActionEvent e){
if (e.getSource() == timer) {
updateEnemiesPosition();
updateMyPosition();
updateMyMissile();
updateEnemiesMissile();
activateEnemiesMissile();
if(checkHitToPlayer()){
System.out.println("===== Game Over =====");
System.exit(0);
}
checkHitToEnemy();
if(checkClear()){
System.out.println("===== Game Clear =====");
System.exit(0);
}
repaint();
}
}
public void mouseClicked(MouseEvent me)
{ }
public void mousePressed(MouseEvent me)
{
activateMyMissile();
}
public void mouseReleased(MouseEvent me)
{ }
public void mouseExited(MouseEvent me)
{ }
public void mouseEntered(MouseEvent me)
{ }
public void mouseMoved(MouseEvent me)
{ }
public void mouseDragged(MouseEvent me)
{ }
public void keyReleased(KeyEvent e){
}
public void keyTyped(KeyEvent e){
}
}
}
The original size of the component is going to be less then 800x500 (I say less then, because the actual size will be 800x500 - the frame decorations - this is why you should be setting the size of the window directly).
When you rotate it 90 degrees, it becomes (less then) 500x800. So, no, there's no "easy" way to resolve this, without making the game square.
I added...
g2d.setColor(Color.DARK_GRAY);
g2d.fillRect(0, 0, getWidth(), getHeight());
after the rotation, which highlights the issue.
To do this, you should override getPreferredSize of the JPanel and the call pack on the frame. This will ensure that that game canvas is sized to it's preferred size and the window decorations are then packed around it.
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Lec12 extends JFrame {
public Lec12() {
setTitle("Game Example");
setDefaultCloseOperation(EXIT_ON_CLOSE);
MyJPanel myJPanel = new MyJPanel();
Container c = getContentPane();
c.add(myJPanel);
pack();
setVisible(true);
}
public static void main(String[] args) {
new Lec12();
}
public class MyJPanel extends JPanel implements ActionListener, MouseListener,
MouseMotionListener, KeyListener {
//variables for player
int my_x;
int player_width, player_height;
//variables for enemies
int enemy_width, enemy_height;
int n;
int enemy_x[];
int enemy_y[];
int enemy_move[];
int enemy_alive[];
//variables for player's missiles
int my_missile_x, my_missile_y;
int missile_flag;
public static final int MY_Y = 400;
//variables for enemies' missiles
int e_missile_flag[];
int e_missile_x[];
int e_missile_y[];
int e_missile_move[];
Image image, image2;
Timer timer;
public MyJPanel() {
/**
* * initialize player's info **
*/
my_x = 250;
ImageIcon icon = new ImageIcon("player.jpg");
image = icon.getImage();
player_width = image.getWidth(this);
player_height = image.getHeight(this);
missile_flag = 0;
/**
* * initialize enemies' info **
*/
ImageIcon icon2 = new ImageIcon("enemy.jpg");
image2 = icon2.getImage();
enemy_width = image2.getWidth(this);
enemy_height = image2.getHeight(this);
n = 14; //number of enemies
enemy_x = new int[n];
enemy_y = new int[n];
enemy_move = new int[n];
enemy_alive = new int[n];
int distance = 40;
e_missile_flag = new int[n];
e_missile_x = new int[n];
e_missile_y = new int[n];
e_missile_move = new int[n];
// place enemies in 7x2
for (int i = 0; i < 7; i++) {
enemy_x[i] = (enemy_width + distance) * i + 50;
enemy_y[i] = 50;
}
for (int i = 7; i < n; i++) {
enemy_x[i] = (enemy_width + distance) * (i - 5) + 50;
enemy_y[i] = 100;
}
for (int i = 0; i < n; i++) {
enemy_alive[i] = 1; //all alive
enemy_move[i] = -10; //moves to left
}
for (int i = 0; i < n; i++) {
e_missile_flag[i] = 0;
e_missile_x[i] = 0;
e_missile_y[i] = 0;
e_missile_move[i] = 7 + n % 3;
}
/**
* * setup system **
*/
setBackground(Color.black);
setFocusable(true);
addMouseListener(this);
addMouseMotionListener(this);
addKeyListener(this);
timer = new Timer(50, this);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 800);
}
private void updateEnemiesPosition() {
//update enemies' position
Dimension dim = getSize();
for (int i = 0; i < n; i++) {
enemy_x[i] += enemy_move[i];
if ((enemy_x[i] < 0) || (enemy_x[i] > (dim.width - enemy_width))) {
enemy_move[i] = -enemy_move[i];
}
}
}
private void updateMyPosition() {
if (my_x < 0) {
my_x = 800;
}
if (my_x > 800) {
my_x = 0;
}
}
private void activateMyMissile() {
//shoot a missile
if (missile_flag == 0) {
my_missile_x = my_x + player_width / 2;
my_missile_y = MY_Y; //MY_Y=400
missile_flag = 1;
}
}
private void updateMyMissile() {
//update missile position if alive
if (missile_flag == 1) {
my_missile_y -= 15;
if (0 > my_missile_y) {
missile_flag = 0;
}
}
}
private void activateEnemiesMissile() {
//activate enemies' missile if enemy is alive and its missile is not alive
for (int i = 0; i < n; i++) {
if (enemy_alive[i] == 1 && e_missile_flag[i] == 0) {
e_missile_x[i] = enemy_x[i] + enemy_width / 2;
e_missile_y[i] = enemy_y[i];
e_missile_flag[i] = 1;
}
}
}
private void updateEnemiesMissile() {
//update enemies' missile position if alive
Dimension dim = getSize();
for (int i = 0; i < n; i++) {
if (e_missile_flag[i] == 1) {
e_missile_y[i] += e_missile_move[i];
if (e_missile_y[i] > dim.height) {
e_missile_flag[i] = 0;
}
}
}
}
private void checkHitToEnemy() {
for (int i = 0; i < n; i++) {
if (missile_flag == 1 && enemy_alive[i] == 1) {
if (my_missile_x > enemy_x[i]
&& my_missile_x < (enemy_x[i] + enemy_width)
&& my_missile_y > enemy_y[i]
&& my_missile_y < (enemy_y[i] + enemy_height)) {
//hit
missile_flag = 0;
enemy_alive[i] = 0;
}
}
}
}
private boolean checkHitToPlayer() {
for (int i = 0; i < n; i++) {
if (e_missile_flag[i] == 1) {
if (e_missile_x[i] > my_x
&& e_missile_x[i] < (my_x + player_width)
&& e_missile_y[i] > MY_Y
&& e_missile_y[i] < (MY_Y + player_height)) {
e_missile_flag[i] = 0;
return true;
}
}
}
return false;
}
private boolean checkClear() {
int cnt = 0;
for (int i = 0; i < n; i++) {
if (enemy_alive[i] == 0) {
cnt++;
}
}
return (n == cnt);
}
public void paintComponent(Graphics g) {
super.paintComponent(g); //reset graphics
Graphics2D g2d = (Graphics2D) g.create();
System.out.println(getWidth() + "x" + getHeight());
int w2 = getWidth() / 2;
int h2 = getHeight() / 2;
g2d.rotate(-Math.PI / 2, w2, h2);
g2d.setColor(Color.DARK_GRAY);
g2d.fillRect(0, 0, getWidth(), getHeight());
//draw player
g2d.setColor(Color.BLUE);
g2d.fillRect(my_x, 400, 10, 10);
// g.drawImage(image, my_x, 400, this);
//draw enemies
for (int i = 0; i < n; i++) {
if (enemy_alive[i] == 1) {
g2d.setColor(Color.RED);
g2d.fillRect(enemy_x[i], enemy_y[i], 10, 10);
// g.drawImage(image2, enemy_x[i], enemy_y[i], this);
}
}
//draw players missiles
if (missile_flag == 1) {
g2d.setColor(Color.white);
g2d.fillRect(my_missile_x, my_missile_y, 2, 5);
}
//draw enemies' missiles
for (int i = 0; i < n; i++) {
if (e_missile_flag[i] == 1) {
g2d.setColor(Color.white);
g2d.fillRect(e_missile_x[i], e_missile_y[i], 2, 5);
}
}
g2d.dispose();
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == timer) {
updateEnemiesPosition();
updateMyPosition();
updateMyMissile();
updateEnemiesMissile();
activateEnemiesMissile();
if (checkHitToPlayer()) {
System.out.println("===== Game Over =====");
System.exit(0);
}
checkHitToEnemy();
if (checkClear()) {
System.out.println("===== Game Clear =====");
System.exit(0);
}
repaint();
}
}
public void mouseClicked(MouseEvent me) {
}
public void mousePressed(MouseEvent me) {
activateMyMissile();
}
public void mouseReleased(MouseEvent me) {
}
public void mouseExited(MouseEvent me) {
}
public void mouseEntered(MouseEvent me) {
}
public void mouseMoved(MouseEvent me) {
}
public void mouseDragged(MouseEvent me) {
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_S:
my_x = my_x + 10;
break;
case KeyEvent.VK_W:
my_x = my_x - 10;
break;
case KeyEvent.VK_DOWN:
my_x = my_x + 10;
break;
case KeyEvent.VK_UP:
my_x = my_x - 10;
break;
case KeyEvent.VK_X:
if (missile_flag == 0) {
my_missile_x = my_x + player_width / 2;
my_missile_y = MY_Y;// MY_Y=400
missile_flag = 1;
}
break;
}
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
}
}
Also, beware, transformations of this nature are accumulative. You should, instead, take a snapshot of the Graphics context and dispose of it once you're done (see the above for an example).
Also, have look at How to Use Key Bindings as it will help resolve the focus issues related to KeyListener
Within my program, I have the following code:
package io.github.AdmiralSbs.DiceWars;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Scanner;
public class HexDisplay extends JPanel {
private static final long serialVersionUID = 1L;
public static final int SIZE = 200;
private int height;
private int width;
private Hex[][] hex;
private BufferedImage myImage;
private Graphics drawer;
public HexDisplay(File f) throws IOException {
Scanner key = new Scanner(f);
int[] temp = commaSplit(key.nextLine());
height = temp[0];
width = temp[1];
hex = new Hex[width][height];
for (int w = 0; w < width; w++) {
for (int h = 0; h < height; h++) {
//temp = commaSplit(key.nextLine());
if (h % 2 == 0)
hex[w][h] = new Hex((int) (SIZE * (w + 0.5)),
(int) (SIZE * (h + 0.5)), SIZE);
else
hex[w][h] = new Hex((int) (SIZE * (w + 1.5)),
(int) (SIZE * (h + 0.5)), SIZE);
System.out.println(hex[w][h].getX() + " " + hex[w][h].getY());
}
}
key.close();
starting();
ImageIO.write(myImage, "jpg", new File("outPic.jpg"));
}
public void starting() {
setPreferredSize(new Dimension(400,400));
setLayout(new FlowLayout());
myImage = new BufferedImage(400, 400, BufferedImage.TYPE_INT_RGB);
drawer = myImage.getGraphics();
drawer.setColor(Color.BLUE);
drawer.fillRect(0, 0, 400, 400);
drawStuff(drawer);
repaint();
}
public int[] commaSplit(String s) {
String[] str = s.split(",");
int[] ret = new int[str.length];
for (int i = 0; i < str.length; i++) {
ret[i] = Integer.parseInt(str[i]);
}
return ret;
}
public void paintComponents(Graphics g) {
g.drawImage(myImage, 0, 0, this);
System.out.println("Painted");
}
public void drawStuff(Graphics g) {
for (int w = 0; w < width; w++) {
for (int h = 0; h < height; h++) {
hex[w][h].draw(g);
}
}
System.out.println("Drew");
revalidate();
repaint();
paintComponents(g);
}
}
What I would expect to happen is for the frame that contains this JPanel to display the image, but it does not. All System.out.println() methods are called as expected, and I am able to save the image as a .jpg file. However, the image is not displayed in the GUI. What can be done?
You have a typo:
// v
public void paintComponents(Graphics g) {
It should be paintComponent.
And should contain a call to super method:
super.paintComponent(g);
as the first line in the method
I'm hoping someone could help me understand my code probs. I'm trying to create a Reversi board game in Java but my game board will only stick to white pieces and refuse to do anything. Any suggestions would be great.
This is the part I have to do (hence marked TO DO). Honestly it should be 1 or 2 lines for each of them but I'm just not catching on. I'm definitely having trouble with my get() and flip() methods.
public class Simple2DArray implements Simple2DInterface
{
// TO DO: Your instance variables
private int[][] simpleArray = new int[8][8];
private int row = simpleArray.length;
private int column = simpleArray[0].length;
private int none = -1, white = 1, black = 0, value;
/**
* Constructor: Once a two dimensional array is constructed
* set all elements in the array to -1.
* #param aRow the number of rows of this Simple2DArray.
* #param aColumn the number of columns of this Simple2DArray.
*/
public Simple2DArray(int aRow, int aColumn)
{
// TO DO: Constructor
this.row = aRow;
this.column = aColumn;
for (int i = 1; i < simpleArray.length; i++)
{
for (int j = 1; j < simpleArray[i].length; j++)
{
simpleArray[i][j] = none;
}
}
}
/**
* Gets the number of rows of this Simple 2D Array.
* #return the number of rows of this Simple 2D array.
*/
public int getNumberOfRows()
{
// TO DO
return simpleArray.length;
}
/**
* Gets the number of columns of this Simple 2D Array.
* #return the number of columns of this Simple 2D array.
*/
public int getNumberOfColumns()
{
// TO DO
return simpleArray[1].length;
}
/**
* Reset every element to -1
*/
public void clear()
{
// TO DO
for (int i = 1; i < simpleArray.length; i++)
{
for (int j = 1; j < simpleArray[i].length; j++)
{
simpleArray[i][j] = none;
}
}
}
/**
* Sets the value at location row and column to 1.
* #param row the row number (start at 1).
* #param column the column number (start at 1).
*/
public void setToOne(int row, int column)
{
// TO DO
for (int i = 1; i < simpleArray.length; i++)
{
for (int j = 1; j < simpleArray[i].length; j++)
{
simpleArray[i][j] = white;
}
}
}
/**
* Sets the value at location row and column to 0.
* #param row the row number (start at 1).
* #param column the column number (start at 1).
*/
public void setToZero(int row, int column)
{
// TO DO
for (int i = 1; i < simpleArray.length; i++)
{
for (int j = 1; j < simpleArray[i].length; j++)
{
simpleArray[i][j] = black;
}
}
}
/**
* Reverse the value at row and column. If the value
* at row and column is 1, reverse it to 0. If the value
* at row and column is 0, reverse it to 1. If the value
* at row and column is -1, do nothing.
* #param row the row number (start at 1).
* #param column the column number (start at 1).
*/
public void flip(int row, int column)
{
// TO DO
value = simpleArray[row][column];
if (value == white)
{
value = black;
}
if(value == black)
{
value = white;
}
}
/**
* Gets the value at row and column.
* #param row the row number (start at 1).
* #param column the column number (start at 1).
* #return the value at row and column.
*/
public int get(int row, int column)
{
// TO DO
for (int i = 1; i < simpleArray.length; i++)
{
for (int j = 1; j < simpleArray[i].length; j++)
{
row = i;
column = j;
value = simpleArray[row][column];
}
}
return value;
}
}
And the rest of my files/interfaces/etc.:
public interface Simple2DInterface
{
/**
* Gets the number of rows of this Simple 2D Array.
* #return the number of rows of this Simple 2D array.
*/
public int getNumberOfRows();
/**
* Gets the number of columns of this Simple 2D Array.
* #return the number of columns of this Simple 2D array.
*/
public int getNumberOfColumns();
/**
* Reset every element to -1
*/
public void clear();
/**
* Sets the value at location row and column to 1.
* #param row the row number (start at 1).
* #param column the column number (start at 1).
*/
public void setToOne(int row, int column);
/**
* Sets the value at location row and column to 0.
* #param row the row number (start at 1).
* #param column the column number (start at 1).
*/
public void setToZero(int row, int column);
/**
* Reverse the value at row and column. If the value
* at row and column is 1, reverse it to 0. If the value
* at row and column is 0, reverse it to 1. If the value
* at row and column is -1, do nothing.
* #param row the row number (start at 1).
* #param column the column number (start at 1).
*/
public void flip(int row, int column);
/**
* Gets the value at row and column.
* #param row the row number (start at 1).
* #param column the column number (start at 1).
* #return the value at row and column.
*/
public int get(int row, int column);
}
public class Simple2DArrayTester
{
public static void main(String[] args)
{
int point = 0;
int numRows = 10;
int numColumns = 15;
boolean notEqualMinusOne = false;
Simple2DInterface s2d1 = new Simple2DArray(numRows,numColumns);
// Check that all locations are -1.
System.out.print("Testing that all locations must be -1: ");
for(int i = 1; i <= numRows; i++)
{
for(int j = 1; j <= numColumns; j++)
{
if(s2d1.get(i, j) != -1)
{
notEqualMinusOne = true;
}
}
}
if(notEqualMinusOne)
{
System.out.println("FAIL");
System.out.println("Not all locations contain -1.\n");
}
else
{
System.out.println("PASS");
point++;
}
System.out.println("Your current point is " + point + ".\n");
// Testing the method getNumberOfRows()
System.out.print("Testing the method getNumberOfRows: ");
if(s2d1.getNumberOfRows() != numRows)
{
System.out.println("FAIL");
System.out.println("The number of from your method getNumberOfRows should be " + numRows + ".");
System.out.println("But your method getNumberOfRows returns " + s2d1.getNumberOfRows() + ".\n");
}
else
{
System.out.println("PASS");
point++;
}
System.out.println("Your current point is " + point + ".\n");
// Testing the method getNumberOfColumns()
System.out.print("Testing the method getNumberOfColumns: ");
if(s2d1.getNumberOfColumns() != numColumns)
{
System.out.println("FAIL");
System.out.println("The number of from your method getNumberOfColumns should be " + numColumns + ".");
System.out.println("But your method getNumberOfColumns returns " + s2d1.getNumberOfColumns() + ".\n");
}
else
{
System.out.println("PASS");
point++;
}
System.out.println("Your current point is " + point + ".\n");
// Testing the method setToOne()
System.out.print("Testing the method setToOne(): ");
s2d1.setToOne(5, 9);
if(s2d1.get(5, 9) != 1)
{
System.out.println("FAIL");
System.out.println("After calling the method setToOne(5,9) the value at row 5 column 9 should be 1.");
System.out.println("But your method get(5,9) returns " + s2d1.get(5,9) + ".\n");
}
else
{
System.out.println("PASS");
point++;
}
System.out.println("Your current point is " + point + ".\n");
// setToZero()
System.out.print("Testing the method setToZero(): ");
s2d1.setToZero(9, 5);
if(s2d1.get(9, 5) != 0)
{
System.out.println("FAIL");
System.out.println("After calling the method setToZero(9,5) the value at row 9 column 5 should be 0.");
System.out.println("But your method get(9,5) returns " + s2d1.get(9,5) + ".\n");
}
else
{
System.out.println("PASS");
point++;
}
System.out.println("Your current point is " + point + ".\n");
// flip()
System.out.print("Testing flip from one to zero: ");
s2d1.flip(5, 9);
if(s2d1.get(5, 9) != 0)
{
System.out.println("FAIL");
System.out.println("After flipping by calling flip(5,9) the value at row 5 column 9 should be 0.");
System.out.println("But your method get(5,9) returns " + s2d1.get(5,9) + "\n.");
}
else
{
System.out.println("PASS");
point++;
}
System.out.println("Your current point is " + point + ".\n");
System.out.print("Testing flip from zero to one: ");
s2d1.flip(9, 5);
if(s2d1.get(9, 5) != 1)
{
System.out.println("FAIL");
System.out.println("After flipping by calling flip(9,5) the value at row 9 column 5 should be 1.");
System.out.println("But your method get(9,5) returns " + s2d1.get(9,5) + "\n.");
}
else
{
System.out.println("PASS");
point++;
}
System.out.println("Your current point is " + point + ".\n");
System.out.print("Testing flip -1: ");
s2d1.flip(1, 1);
if(s2d1.get(1, 1) != -1)
{
System.out.println("FAIL");
System.out.println("After flipping by calling flip(1,1), the value at row 1 column 1 should be -1.");
System.out.println("But your method get(1,1) returns " + s2d1.get(1,1) + ".\n");
}
else
{
System.out.println("PASS");
point++;
}
System.out.println("Your current point is " + point + ".\n");
// clear()
System.out.print("Testing the method clear(): ");
s2d1.clear();
notEqualMinusOne = false;
for(int i = 1; i <= numRows; i++)
{
for(int j = 1; j <= numColumns; j++)
{
if(s2d1.get(i, j) != -1)
{
notEqualMinusOne = true;
}
}
}
if(notEqualMinusOne)
{
System.out.println("FAIL");
System.out.println("After calling the method clear. Not all locations contain -1.\n");
}
else
{
System.out.println("PASS");
point++;
}
System.out.println("Your current point is " + point + ".\n");
if(point == 9)
{
System.out.println("Everything looks good one extra point :)");
point++;
}
System.out.println("Your final point is " + point + ".");
if(point == 10)
{
System.out.println("Contratulation! Your class Simple2DArray works perfectly (I guess).");
System.out.println("You can run OthelloFrame to see how Simple2DArray can be used in a program.");
}
else
{
System.out.println("There is one or more errors in your class.");
System.out.println("Fix your bugs to get more points.");
}
}
}
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;
#SuppressWarnings("serial")
public class OthelloFrame extends JFrame
{
private int frameWidth = 600;
private int frameHeight = 600;
private JLabel msg;
private JButton switchPlayer;
private JPanel msgPanel;
private JPanel controlPanel;
private Simple2DInterface sa;
private OthelloComponent oc;
private boolean isWhite = false;
public static void main(String[] args)
{
JFrame frame = new OthelloFrame();
frame.setVisible(true);
}
public OthelloFrame()
{
sa = new Simple2DArray(8,8);
sa.setToOne(4, 4);
sa.setToZero(4, 5);
sa.setToZero(5, 4);
sa.setToOne(5, 5);
msg = new JLabel("Click on an empty space to put a disk or click on a disk to change color.");
oc = new OthelloComponent(sa);
controlPanel = new JPanel();
controlPanel.setLayout(new GridLayout(2,1));
switchPlayer = new JButton("Switch Color to White");
class SwitchButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent arg0)
{
oc.switchColor();
isWhite = !isWhite;
if(isWhite)
{
switchPlayer.setText("Switch Color to Black");
}
else
{
switchPlayer.setText("Switch Color to White");
}
}
}
ActionListener sp = new SwitchButtonListener();
switchPlayer.addActionListener(sp);
controlPanel.add(switchPlayer);
msgPanel = new JPanel();
msgPanel.setBorder(new TitledBorder("Message"));
msgPanel.add(msg);
controlPanel.add(msgPanel);
setSize(frameWidth, frameHeight);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Wanna be Othello");
add(oc);
add(controlPanel, BorderLayout.SOUTH);
setVisible(true);
}
}
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import javax.swing.JComponent;
#SuppressWarnings("serial")
public class OthelloComponent extends JComponent implements MouseListener
{
private Simple2DInterface grid;
private int numRows;
private int numColumns;
private int leftMargin = 10;
private int rightMargin = 10;
private int topMargin = 10;
private int bottomMargin = 10;
private int circleMargin = 5;
private double circleSize;
private int width;
private int height;
private int topLeftX;
private int topLeftY;
private int bottomRightX;
private int bottomRightY;
private double cellWidth;
private double cellHeight;
private double boardWidth;
private double boardHeight;
private boolean isWhite;
public OthelloComponent(Simple2DInterface a2DArray)
{
grid = a2DArray;
numRows = grid.getNumberOfRows();
numColumns = grid.getNumberOfColumns();
isWhite = false;
this.addMouseListener(this);
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
width = this.getWidth();
height = this.getHeight();
cellWidth = (double) (width - (leftMargin + rightMargin)) / numColumns;
cellHeight = (double) (height - (topMargin + bottomMargin)) / numRows;
if(cellWidth > cellHeight)
{
cellWidth = cellHeight;
}
else
{
cellHeight = cellWidth;
}
circleSize = cellWidth - (2 * circleMargin);
boardWidth = cellWidth * numColumns;
boardHeight = cellHeight * numRows;
topLeftX = (width - (int) boardWidth) / 2;
topLeftY = (height - (int) boardHeight) / 2;
bottomRightX = topLeftX + (int) boardWidth;
bottomRightY = topLeftY + (int) boardHeight;
Line2D.Double line = new Line2D.Double(0,0,0,0);
// Draw the Board
g2.setColor(Color.BLACK);
for(int i = 0; i <= numRows; i++)
{
line.setLine(topLeftX, topLeftY + (i * cellHeight), bottomRightX, topLeftY + (i * cellHeight));
g2.draw(line);
}
for(int i = 0; i <= numColumns; i++)
{
line.setLine(topLeftX + (i * cellWidth), topLeftY, topLeftX + (i * cellWidth), bottomRightY);
g2.draw(line);
}
// Draw circles
Ellipse2D.Double circle = new Ellipse2D.Double();
for(int row = 1; row <= numRows; row++)
{
for(int column = 1; column <= numColumns; column++)
{
if(grid.get(row, column) == 0)
{
g2.setColor(Color.BLACK);
int x = topLeftX + circleMargin + (int) ((column - 1) * cellWidth);
int y = topLeftY + circleMargin + (int) ((row - 1) * cellHeight);
circle.setFrame(x,y,circleSize,circleSize);
g2.fill(circle);
}
else if(grid.get(row, column) == 1)
{
int x = topLeftX + circleMargin + (int) ((column - 1) * cellWidth);
int y = topLeftY + circleMargin + (int) ((row - 1) * cellHeight);
circle.setFrame(x,y,circleSize,circleSize);
g2.setColor(Color.WHITE);
g2.fill(circle);
g2.setColor(Color.BLACK);
g2.draw(circle);
}
}
}
}
public void mouseClicked(MouseEvent arg0)
{
int column = getColumn(arg0.getX());
int row = getRow(arg0.getY());
if(row != 0 && column != 0)
{
if(grid.get(row, column) == -1)
{
if(isWhite)
{
grid.setToOne(row, column);
}
else
{
grid.setToZero(row, column);
}
}
else
{
if(isWhite && grid.get(row, column) == 0)
{
grid.flip(row, column);
}
else if(!isWhite && grid.get(row, column) == 1)
{
grid.flip(row, column);
}
}
}
repaint();
}
public void switchColor()
{
isWhite = !isWhite;
}
public int getColumn(int x)
{
int result = 0;
for(int column = 1; column <= numColumns; column++)
{
if(x > topLeftX + ((column - 1) * cellWidth) && x < topLeftX + (column * cellWidth))
{
result = column;
break;
}
}
return result;
}
public int getRow(int y)
{
int result = 0;
for(int row = 1; row <= numRows; row++)
{
if(y > topLeftY + ((row - 1) * cellHeight) && y < topLeftY + (row * cellHeight))
{
result = row;
break;
}
}
return result;
}
public void mouseEntered(MouseEvent arg0)
{
}
public void mouseExited(MouseEvent arg0)
{
}
public void mousePressed(MouseEvent arg0)
{
}
public void mouseReleased(MouseEvent arg0)
{
}
}
Looking through the code there were a lot of things that I would change unrelated to the question so I just refactored your classes:
OthelloFrame.java:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;
#SuppressWarnings("serial")
public class OthelloFrame extends JFrame {
private static final int FRAME_WIDTH = 600;
private static final int FRAME_HEIGHT = FRAME_WIDTH;
private OthelloComponent gridComponent;
private JButton switchPlayerButton;
public OthelloFrame() {
// create grid and add to frame
Simple2DInterface grid =
new Simple2DArray(Simple2DArray.DEFAULT_BOARD_DIMENSION, Simple2DArray.DEFAULT_BOARD_DIMENSION);
int halfWidth = grid.getNumberOfColumns() / 2;
int halfHeight = grid.getNumberOfRows() / 2;
grid.set(halfHeight - 1, halfWidth - 1, Simple2DArray.WHITE);
grid.set(halfHeight - 1, halfWidth, Simple2DArray.BLACK);
grid.set(halfHeight, halfWidth - 1, Simple2DArray.BLACK);
grid.set(halfHeight, halfWidth, Simple2DArray.WHITE);
gridComponent = new OthelloComponent(grid);
add(gridComponent);
// create control panel
JPanel controlPanel = new JPanel();
controlPanel.setLayout(new GridLayout(2,1));
// create and add switch player button to control panel
switchPlayerButton = new JButton("Switch Color to White");
ActionListener sp = new SwitchButtonListener();
switchPlayerButton.addActionListener(sp);
controlPanel.add(switchPlayerButton);
// create and add instructions to control panel
JPanel msgPanel = new JPanel();
msgPanel.setBorder(new TitledBorder("Message"));
msgPanel.add(new JLabel("Click on an empty space to put a disk or click on a disk to change color."));
controlPanel.add(msgPanel);
// add control panel to frame
add(controlPanel, BorderLayout.SOUTH);
// final setup
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(FRAME_WIDTH, FRAME_HEIGHT);
setTitle("Wanna be Othello");
setVisible(true);
}
public static void main(String[] args) {
JFrame frame = new OthelloFrame();
frame.setVisible(true);
}
private class SwitchButtonListener implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
gridComponent.switchColor();
switchPlayerButton.setText("Switch Color to " + (gridComponent.whiteToPlay() ? "Black" : "White"));
}
}
}
OthelloComponent.java:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import javax.swing.JComponent;
#SuppressWarnings("serial")
public class OthelloComponent extends JComponent implements MouseListener {
private static final int MARGIN = 10;
private static final int CIRCLE_MARGIN = MARGIN / 2;
private static final int BOTTOM_MARGIN = MARGIN;
private static final int TOP_MARGIN = MARGIN;
private static final int LEFT_MARGIN = MARGIN;
private static final int RIGHT_MARGIN = MARGIN;
private Simple2DInterface grid;
private int numRows;
private int numColumns;
private double circleDiameter;
private double topLeftX;
private double topLeftY;
private double cellHeight;
private double cellWidth;
private double boardHeight;
private double boardWidth;
private int turn;
public OthelloComponent(Simple2DInterface a2DArray) {
grid = a2DArray;
numRows = grid.getNumberOfRows();
numColumns = grid.getNumberOfColumns();
turn = Simple2DArray.BLACK;
this.addMouseListener(this);
}
public int getColumn(int x) {
return (int) (Math.ceil((x - topLeftX) / cellWidth) - 1);
}
public int getRow(int y) {
return (int) (Math.ceil((y - topLeftY) / cellHeight) - 1);
}
public void mouseClicked(MouseEvent arg0) {
int column = getColumn(arg0.getX());
int row = getRow(arg0.getY());
// you can take this out if you want
System.out.println("r: " + row + ", c: " + column);
if (row >= 0 && column >= 0 && row < numRows && column < numColumns) {
grid.set(row, column, turn);
}
repaint();
}
public void mouseEntered(MouseEvent arg0) {}
public void mouseExited(MouseEvent arg0) {}
public void mousePressed(MouseEvent arg0) {}
public void mouseReleased(MouseEvent arg0) {}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
cellHeight = ((double) getHeight() - (TOP_MARGIN + BOTTOM_MARGIN)) / numRows;
cellWidth = ((double) getWidth() - (LEFT_MARGIN + RIGHT_MARGIN)) / numColumns;
// make cells the largest possible squares
if (cellWidth > cellHeight) {
cellWidth = cellHeight;
} else {
cellHeight = cellWidth;
}
circleDiameter = cellWidth - (2 * CIRCLE_MARGIN);
boardHeight = cellHeight * numRows;
boardWidth = cellWidth * numColumns;
topLeftX = (getWidth() - boardWidth) / 2;
topLeftY = (getHeight() - boardHeight) / 2;
double bottomRightX = topLeftX + boardWidth;
double bottomRightY = topLeftY + boardHeight;
Line2D.Double line = new Line2D.Double(0,0,0,0);
// draw the lines on the board
g2.setColor(Color.BLACK);
for (int i = 0; i <= numRows; i++) {
line.setLine(topLeftX, topLeftY + i * cellHeight, bottomRightX, topLeftY + i * cellHeight);
g2.draw(line);
}
for (int i = 0; i <= numColumns; i++) {
line.setLine(topLeftX + i * cellWidth, topLeftY, topLeftX + i * cellWidth, bottomRightY);
g2.draw(line);
}
// draw circles
for (int row = 0; row < numRows; row++) {
for (int column = 0; column < numColumns; column++) {
if (grid.get(row, column) != Simple2DArray.NONE) {
Color fill = grid.get(row, column) == Simple2DArray.BLACK ? Color.BLACK : Color.WHITE;
drawCircle(row, column, fill, Color.BLACK, g2);
}
}
}
}
public void switchColor() {
turn = -turn;
}
public boolean whiteToPlay() {
return turn == Simple2DArray.WHITE;
}
private void drawCircle(int row, int column, Color fill, Color border, Graphics2D g2) {
Ellipse2D.Double circle = new Ellipse2D.Double();
double x = topLeftX + CIRCLE_MARGIN + column * cellWidth;
double y = topLeftY + CIRCLE_MARGIN + row * cellHeight;
circle.setFrame(x,y,circleDiameter,circleDiameter);
g2.setColor(fill);
g2.fill(circle);
g2.setColor(border);
g2.draw(circle);
}
}
Simple2DInterface.java:
public interface Simple2DInterface {
/** Reset every element to 0. */
public void clear();
/** Gets the value at row and column. */
public int get(int row, int column);
/** Gets the number of columns of this Simple2DInterface. */
public int getNumberOfColumns();
/** Gets the number of rows of this Simple2DInterface. */
public int getNumberOfRows();
/** Sets the value at location row and column to a certain color. */
public void set(int row, int column, int color);
}
Simple2DArray.java:
public class Simple2DArray implements Simple2DInterface {
public static final int DEFAULT_BOARD_DIMENSION = 8;
static final int BLACK = -1;
static final int NONE = 0;
static final int WHITE = 1;
private int[][] simpleArray;
/** Creates a blank Simple2DArray with the specified number of rows and columns. */
public Simple2DArray(int rows, int columns) {
simpleArray = new int[rows][columns];
}
/** Reset every element to 0 */
public void clear() {
simpleArray = new int[getNumberOfRows()][getNumberOfColumns()];
}
/** Gets the value at row and column. */
public int get(int row, int column) {
return simpleArray[row][column];
}
/** Gets the number of columns of this Simple 2D Array. */
public int getNumberOfColumns() {
return simpleArray.length != 0 ? simpleArray[0].length : 0;
}
/** Gets the number of rows of this Simple 2D Array. */
public int getNumberOfRows() {
return simpleArray.length;
}
/** Sets the value at location row and column to a certain color. */
public void set(int row, int column, int color) {
simpleArray[row][column] = color;
}
}
Next steps: tighten the bound checks a bit, signal the end of the game, clear button, automatically change all the opponents coins on each move, move validation.
I am working on a program that I can use to present topics in front of my class. While MS Powerpoint and similar programs are nice, I feel like they are lacking in some areas. I am not trying to re-create these programs, I am only trying to make a program where I can type text into String arrays, add images, and position them all on the screen.
Currently my program opens a fullscreen dark window with a little X in the top left, which when clicked will close the program.
Here is the class file:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Scanner;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main {
static JFrame frame;
static MyPanel panel;
static MouseListener listener;
static final int letterWidth = 6;
static final int letterHeight = 9;
static final int letterRow = 10;
static final int letterCol = 11;
static final int letterNum = 110;
static String[] textA = {"Hello World,",
"Here is a test",
"of what I can do.",
"Isn't it neat?!"
};
static int textX = 100;
static int textY = 100;
public static void main(String[] args){
System.out.println("Welcome to Presenter");
System.out.println("Beginning loading");
frame = new JFrame();
panel = new MyPanel();
listener = new MouseListener(){
public void mouseClicked(MouseEvent arg0) {
if(arg0.getButton() ==MouseEvent.BUTTON1){
//Close button
int x = (int) MouseInfo.getPointerInfo().getLocation().getX();
int y = (int) MouseInfo.getPointerInfo().getLocation().getY();
if(x>20 && x<48 && y>20 && y<56){
frame.dispose();
System.exit(0);
}
}
}
public void mouseEntered(MouseEvent arg0) {}
public void mouseExited(MouseEvent arg0) {}
public void mousePressed(MouseEvent arg0) {}
public void mouseReleased(MouseEvent arg0) {}
};
frame.setUndecorated(true);
frame.setVisible(true);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setFocusable(true);
frame.add(panel);
frame.addMouseListener(listener);
System.out.println("");
System.out.println("Loading Complete");
}
public static class MyPanel extends JPanel{
private static final long serialVersionUID = 1L;
HashMap<String, BufferedImage> iLetters;
static BufferedImage exitButton = new BufferedImage(28, 36, BufferedImage.TYPE_INT_ARGB);
static BufferedImage letters = new BufferedImage(120, 198, BufferedImage.TYPE_INT_ARGB);
Scanner lightbulb;
static boolean point = false;
int x;
int y;
BufferedImage textBox;
int boxW, boxH;
public MyPanel(){
//pictures
File a = new File("Exit.png");
try { exitButton = ImageIO.read(a); } catch (IOException e) {e.printStackTrace();}
a = new File("Letters.png");
try { letters = ImageIO.read(a); } catch (IOException e) {e.printStackTrace();}
//letter index
try { lightbulb = new Scanner(new File("letters.txt")); } catch (FileNotFoundException e) {e.printStackTrace();}
System.out.println("Files Read");
//create letters
System.out.println("Beginning tiling");
iLetters = new HashMap<String, BufferedImage>();
BufferedImage[] pics = new BufferedImage[letterNum];
int count = 0;
for(int x=0; x<letterCol; x++){
for(int y=0; y<letterRow; y++){
pics[count] = new BufferedImage(letterWidth, letterHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D gr = pics[count++].createGraphics();
gr.drawImage(letters, 0, 0, letterWidth, letterHeight, letterWidth * y, letterHeight * x, letterWidth * y + letterWidth, letterHeight * x + letterHeight, null);
gr.dispose();
}
System.out.println("Row " + x + " tiled.");
}
System.out.println("Completed Tiling");
System.out.println("Beginning indexing");
int loc = 0;
String key = "";
while(lightbulb.hasNext()){
loc = lightbulb.nextInt()-1;
key = lightbulb.next();
iLetters.put(key, pics[loc]);
}
System.out.println("Indexing Complete");
System.out.println("Making Text Boxes");
makeTextBox(textA);
System.out.println("Text Boxes Made");
}
public void paintComponent(Graphics g){
super.paintComponent(g);
this.setBackground(new Color(0, 0, 10));
g.drawImage(exitButton, 20, 20, null);
// g.drawImage(iLetters.get("A"), 100, 100, null);
drawTexts(g);
}
public void drawTexts(Graphics g){
g.drawImage(textBox, textX, textY, textX+(boxW*2), textY+(boxH*2), null);
}
public int findLongest(String[] text){
int longest = 0;
for(int i=0; i<text.length; i++){
if(text[i].length() > longest)
longest = text[i].length();
}
return longest;
}
public void makeTextBox(String[] text){
int longest = findLongest(text);
boxW = (longest*6)+(longest-1);
boxH = (text.length*9)+(text.length-1);
textBox = new BufferedImage(boxW, boxH, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = textBox.createGraphics();
char[] line;
int drawX = 0;
int drawY = 0;
for(int i=0; i<text.length; i++){
line = text[i].toCharArray();
for(int j=0; j<line.length; j++){
if(j<line.length-1){
g2d.drawImage(iLetters.get(line[j]), drawX, drawY, null);
drawX += letterWidth + 1;
}
else{
g2d.drawImage(iLetters.get(line[j]), drawX, drawY, null);
}
}
if(i<text.length-1){
drawY += letterHeight + 1;
}
else{
drawY += letterHeight;
}
}
g2d.dispose();
}
}
}
The rest of the files needed for it to run are here http://www.mediafire.com/?jq8vi4dm3t4b6
2 PNGs and 1 text file.
The program runs fine with no errors. The only problem is the drawTexts() method. When the method is called, the lines of text do not appear anywhere on screen, when they should be appearing at (100, 100) at 2x the size of the letters in the file.
It's been a while since I did graphics. I remember needing to call repaint() somewhere, but I cannot remember if I need it here, and if I do, where it goes.
Okay, this might take some time...
There are 10 columns and 11 rows, these are around the wrong way...
static final int letterRow = 10;
static final int letterCol = 11;
I don't think you understand what gr.drawImage(letters, 0, 0, letterWidth, letterHeight, letterWidth * y, letterHeight * x, letterWidth * y + letterWidth, letterHeight * x + letterHeight, null); is actually doing, what you really want is BufferedImage#getSubImage...
BufferedImage subimage = letters.getSubimage(letterWidth * x, letterHeight * y, letterWidth, letterHeight);
You're reading the Letters.png file in row/column order, but building the mapping as if it was in column/row order...
Instead of...
for (int x = 0; x < letterCol; x++) {
for (int y = 0; y < letterRow; y++) {
You should be using...
for (int y = 0; y < letterRow; y++) {
for (int x = 0; x < letterCol; x++) {
The lightbulb Scanner is not reading the file...I'm don't use Scanner that often, but when I changed it to lightbulb = new Scanner(new BufferedReader(new FileReader("letters.txt"))); it worked...
In your makeTextBox method you are trying to retrieve the image using a char instead of String, this means the lookup fails as the two keys are incompatible. You need to use something more like...
BufferedImage img = iLetters.get(Character.toString(line[j]));
Also, on each new line, you are not resting the drawX variable, so the text just keeps running off...In fact, I just re-wrote the loop to look more like...
for (int i = 0; i < text.length; i++) {
line = text[i].toCharArray();
for (int j = 0; j < line.length; j++) {
BufferedImage img = iLetters.get(Character.toString(line[j]));
g2d.drawImage(img, drawX, drawY, null);
if (j < line.length - 1) {
drawX += letterWidth + 1;
}
}
drawX = 0;
if (i < text.length - 1) {
drawY += letterHeight + 1;
} else {
drawY += letterHeight;
}
}
And yes, it could be simplified more, but little steps...
There might be a bunch of other things, but that should get you a step closer...
Hi guys i'm trying to create a draughts game in Java and am using JPanels to represent the squares, if I were to change the size of the panels how would I do so ? if I use a layout manager the squares are not big enough. At the moment i'm not using a layout manager to try and change the size, but the size doesnt seem to change - just stays at 1,1 pixel.
private void createSquares(){
for(int i = 0; i < 65; i++){
squares[i] = new JPanel();
squares[i].setLayout(null);
squares[i].setSize(20,20);
board.add(squares[i]);
}
}
You could always "borrow" an image or two online, and put that into your program. For example this code:
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import javax.imageio.ImageIO;
import javax.swing.*;
public class GetChessSquareImages {
public static final String PATH_TO_SQUARES = "http://www.colourbox.com/preview/" +
"4578561-622234-seamless-oak-square-chess-like-parquet-texture.jpg";
private static final int IMG_SIDE_COUNT = 4;
private static final double SCALE = 0.8;
private Map<SquareColor, List<Icon>> squareColorMap = new HashMap<SquareColor, List<Icon>>();
private Random random = new Random();
public void downloadImages() throws IOException {
URL lrgImgUrl = new URL(PATH_TO_SQUARES);
BufferedImage largeImg = ImageIO.read(lrgImgUrl);
int w = largeImg.getWidth() / IMG_SIDE_COUNT;
int h = largeImg.getHeight() / IMG_SIDE_COUNT;
for (int i = 0; i < IMG_SIDE_COUNT; i++) {
int x = (i * largeImg.getWidth()) / IMG_SIDE_COUNT;
for (int j = 0; j < IMG_SIDE_COUNT; j++) {
if (j != 1 && j != 2) {
int y = (j * largeImg.getHeight()) / IMG_SIDE_COUNT;
extractSubImg(largeImg, i, j, x, y, w, h);
}
}
}
}
private void extractSubImg(BufferedImage largeImg,
int i, int j, int x, int y, int w, int h) {
Image subImg = largeImg.getSubimage(x, y, w, h);
int width = (int) (w * SCALE);
int height = (int) (h * SCALE);
subImg = subImg.getScaledInstance(width, height, Image.SCALE_SMOOTH);
List<Icon> iconList = null;
if (i % 2 == j % 2) {
iconList = squareColorMap.get(SquareColor.LIGHT);
if (iconList == null) {
iconList = new ArrayList<Icon>();
squareColorMap.put(SquareColor.LIGHT, iconList);
}
} else {
iconList = squareColorMap.get(SquareColor.DARK);
if (iconList == null) {
iconList = new ArrayList<Icon>();
squareColorMap.put(SquareColor.DARK, iconList);
}
}
iconList.add(new ImageIcon(subImg));
}
public Icon getRandomIcon(SquareColor sqrColor) {
List<Icon> iconList = squareColorMap.get(sqrColor);
if (iconList == null) {
return null;
} else {
return iconList.get(random.nextInt(iconList.size()));
}
}
public static void main(String[] args) {
GetChessSquareImages getImages = new GetChessSquareImages();
try {
getImages.downloadImages();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
int side = 8;;
JPanel panel = new JPanel(new GridLayout(side , side));
for (int i = 0; i < side; i++) {
for (int j = 0; j < side; j++) {
SquareColor sqrColor = (i % 2 == j % 2) ? SquareColor.LIGHT : SquareColor.DARK;
Icon icon = getImages.getRandomIcon(sqrColor);
panel.add(new JLabel(icon));
}
}
JOptionPane.showMessageDialog(null, panel);
}
}
enum SquareColor {
DARK, LIGHT
}
returns this JPanel:
Then your square size will be based on the sizes of your ImageIcons. For example, I have scaled my squares back with a scale factor of 0.8 (the SCALE constant above) to make the grid a more reasonable size.