How to retain rectangles at the bottom in Tetris Game? - java
I have started developing Tetris Game. Everything is working fine but how to retain rectangles at the bottom?
This is the Comp1 class in which the random shape is retrieved and move down with the timer
package buildblock;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import buildblock.tetris;
public class Comp1 extends JPanel implements ActionListener {
int curx=10;
int cury=30;
int nx=0;
int ny=0;
int p=1;
Timer t;
boolean EndofLine=false;
JLabel l1=new JLabel("");
int value=0;
int coords[][][]=new int[3][3][2];
int shape[][][][]={
{{{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0}}},
{{{0,0},{100,20},{0,0}},{{0,0},{100,40},{0,0}},{{80,60},{100,60},{0,0}}},
{{{0,0},{100,20},{0,0}},{{80,40},{100,40},{120,40}},{{0,0},{0,0},{0,0}}},
{{{0,0},{100,20},{0,0}},{{0,0},{100,40},{0,0}},{{0,0},{100,60},{0,0}}},
{{{80,20},{100,20},{0,0}},{{0,0},{100,40},{0,0}},{{0,0},{100,60},{0,0}}},
{{{0,0},{100,20},{0,0}},{{80,40},{100,40},{0,0}},{{80,60},{0,0},{0,0}}},
{{{80,20},{0,0},{0,0}},{{80,40},{100,40},{0,0}},{{0,0},{100,60},{0,0}}},
{{{80,20},{100,20},{0,0}},{{80,40},{100,40},{0,0}},{{0,0},{0,0},{0,0}}},
};
Comp1(tetris Parent)
{
setVisible(true);
setSize(400,900);
curx=(400-curx)/2;
setLayout(new BorderLayout());
timer();
}
public void getShape(int a)
{
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
for(int k=0;k<2;k++)
{
coords[i][j][k]=shape[a][i][j][k];
repaint();
}
}
}
}
public void paint(Graphics g)
{
super.paint(g);
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
for(int k=0;k<2;k++)
{
if(coords[i][j][k]!=0)
{
if(k==0)
{
curx=coords[i][j][k]+nx;
}
else
{
cury=coords[i][j][k]+ny;
drawRec(g,curx,cury,20,20);
}
}
}
}
}
}
public void drawRec(Graphics g,int newx,int newy,int w,int h)
{
g.drawRect(newx, newy, 20, 20);
g.drawLine(curx+1,cury+20-1,curx+20-1,cury+20-1);
}
public void timer()
{
t=new Timer(150,this);
t.start();
}
public int Random()
{
Random r=new Random();
int n=Math.abs(r.nextInt()%7+1);
return n;
}
public void lineDown()
{
ny=ny+10;
repaint();
}
public void actionPerformed(ActionEvent e)
{
if(value!=250&&!EndofLine)
{
value=value+5;
if(p==0)
{
p=Random();
}
getShape(p);
lineDown();
}
else
{
p=Random();
ny=0;
EndofLine=false;
value=0;
}
}
}
The shape is a 4 dimensional array from which the width and height of particular rectangle is retrieved which collectively form a desired shape.Through random function we choose the particular shape with getShape() method and using drawRect function we draw the Rectangles.
Now the lineDown function move down the particular shape with increment of 10,and after reaching at the last line the repaint() method is called and new Random shape is falling down from top,The Problem is now how to retain the particular shape at bottom so that next operations can be carried out.
I would create a List of "shapes" that have already fallen down to the bottom of the Tetris board. This List would be held within your Tetris class and when the current falling item hits the bottom of the board or one of the already falled shapes then it should be stopped and added to the fallen list.
Other general tips:
From personal experience, try to stay away from arrays of size > 2 unless its necessary; they are bloated, confusing and hard to maintain. In your case there's a perfect interface to use called Shape. Check out this code
// java.awt.geom.Path2D implements java.awt.Shape
java.awt.geom.Path2D path = new Path2D.Double();
path.moveTo(0, 0);
path.lineTo(2, 0);
path.lineTo(2, 2);
path.lineTo(2, 0);
path.closePath();
path.transform(AffineTransform.getScaleInstance(20, 20));
This creates a Shape that is your basic square! You then have access to great features that you wont have to implement yourself.
PS: As Andrew suggests in the comments, "Also look at Shape based collision detection. It uses Java 2D Area objects to test for intersection."
Related
I am not sure what is incorrect
I am creating a small Java Jpanel game in which I am supposed to have a rocket that moves up and down via arrows and fires via space. The firing method should work like this: Space bar pressed, thing fires and moves across screen , and then when it hits a certain x, it disappears. Also, you can only fire once until the other bullet disappears. I do not know what I am doing wrong. For one, as soon as my code starts you can see a bullet flying across the screen. 2nd, the bullet is not disappearing. 3rd, even though the other bullet is still visible, it allows me to fire again. import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.io.File; import java.io.IOException; import java.util.Random; import javax.imageio.ImageIO; import javax.swing.*; #SuppressWarnings("serial") public class SpaceGame extends JPanel implements ActionListener{ Timer t = new Timer(2, this); private ImageIcon rocket,asteroid,bullet; private JLabel rocketlabel,ast1,ast2,ast3,bulletLabel; public static int y=90,dy=0,bulletX=110,bulletY,i=0,canFire; //public sound sound; static boolean bulletFired=false;; static JFrame f = new JFrame(); SpaceGame(){ this.setBackground(Color.black); rocket = new ImageIcon(getClass().getResource("rocketFinal.png")); rocketlabel= new JLabel(rocket); this.add(rocketlabel); asteroid = new ImageIcon(getClass().getResource("asteroid.png")); ast1=new JLabel(asteroid); ast2=new JLabel(asteroid); ast3=new JLabel(asteroid); bullet = new ImageIcon(getClass().getResource("bulletReal.png")); bulletLabel = new JLabel(bullet); canFire=1; bulletLabel.setVisible(false); this.add(ast1);this.add(ast2);this.add(ast3);this.add(bulletLabel); f.addKeyListener(new controller()); this.setLayout(null); this.setVisible(true); } public class controller implements KeyListener{ #Override public void keyPressed(KeyEvent e) { int keyCode = e.getKeyCode(); if(keyCode== KeyEvent.VK_UP) { dy=-1; } if(keyCode== KeyEvent.VK_DOWN) { dy=1; } if(keyCode== KeyEvent.VK_SPACE) { if(canFire==0) { System.out.println(String.valueOf(canFire)); bulletFired = true; bulletY = y; bulletX=110; }canFire=1; } } #Override public void keyReleased(KeyEvent e) { int key = e.getKeyCode(); switch(key) { case KeyEvent.VK_UP: dy=0; break; case KeyEvent.VK_DOWN: dy=0; break; } } #Override public void keyTyped(KeyEvent e) { // TODO Auto-generated method stub } } public void paintComponent(Graphics g) { super.paintComponent(g); rocketlabel.setBounds(45,y,rocket.getIconWidth(),80); fireBullet(); paintStars(g); t.start(); } public void paintStars(Graphics g) { g.setColor(Color.yellow); for(int i=0; i<5;i++) { Random rand = new Random(); int o = rand.nextInt(500); int p = rand.nextInt(300); g.fillOval(o, p, 3, 3); } } public void actionPerformed(ActionEvent e) { if(y==-20) y=249; if(y==250)y=-20; y+=dy; if(bulletFired=true) { bulletX++; if(bulletX==455)bulletFired=false;bulletLabel.setVisible(false);System.out.println(String.valueOf(bulletX)); canFire=0; } repaint(); } public void fireBullet(){ if(bulletFired=true) { bulletLabel.setVisible(true); bulletLabel.setBounds(bulletX,bulletY+25,bullet.getIconHeight(),bullet.getIconWidth()); } } public static void main(String[] args) { String filepath = "SpaceGameMusic.wav"; musicStuff musicPlayer = new musicStuff(); musicPlayer.playMusic(filepath); SpaceGame t = new SpaceGame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.getContentPane().add(t); f.setSize(500,335); f.setVisible(true); f.setResizable(false); } }
For one, as soon as my code starts you can see a bullet flying across the screen. The paintComponent() method is for painting only. You can't control when Swing will determine a component needs to be repainted. So, for example: t.start(); should NOT be in the painting method. As soon as the frame is made visible the panel will be painted and the Timer will be started. You application code should control when the Timer is started. Other issues: you should not be using static variables. The variable should simply be instances of your class. the paintStars() method should not generate random locations. Again. a painting method should only paint the current state of the class. So if you want to change the location of the stars you should have a method like randomizeStars(). In this method you would update an ArrayList of Point objects. Each Point instance would represent the location of a star. Then the paintStars() method would simply iterate through the ArrayList and paint each star. you should not be using a KeyListener. A KeyListener only works if a component has focus. You can't guarantee that your component will lose focus. Instead you should be using Key Bindings. Key bindings allow you to handle a KeyEvent even if the component doesn't have focus. See Motion Using the Keyboard for more information and a working example. you can only fire once until the other bullet disappears Your canFire variable should be a boolean variable so it only has true/false values. Again you have a method that sets the state. Your game logic will then check the state before firing the bullet again. if(y==-20) y=249; if(y==250)y=-20; Don't hardcode values. The number should be based on the size of your panel. So you use methods like getWidth() and getHeight() to determine the current size of the panel.
The problem was quite simply that I had forgotten to use == in my if(boolean) statements.
How can I get my score in an other class? JAVA
I'm making a game with multiple asteroids going down. The goal is to dodge as many asteroids for as long as you can. I made it so that as soon as an asteroid reaches the bottom of the screen it is send back up, now i want to count every time it gets to the bottom and add it to the score. My problem is that all the asteroids are the same class so if I use: if(y>700){ y=-50; // x= (int) (Math.random()*670); // To send the asteroid back up setLocation(x,y); // score++; // To add up the score System.out.println(score); // To print the score Every asteroid adds op his own amount of times it has reached the bottom, but I want to know how many asteroids have reached the bottom in total. So I figured I have to get the score out of the asteroid class and add it up in an other class but I don't know how. This is the code of the asteroid class: import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JPanel; import javax.swing.Timer; public class Astroid extends JPanel implements ActionListener { public int yVelocity = 1; public int x = (int) (Math.random()*650), y = (int) (Math.random()*-1000); public Timer timer; private int score; public Astroid(int x,int y) { this.setLocation(x, y); this.setSize(25, 25); this.setBackground(Color.WHITE); this.setVisible(true); } { this.timer = null; this.timer = new Timer(10,new ActionListener(){ #Override public void actionPerformed(ActionEvent arg0) { setLocation(x,(y+=yVelocity)); timer.setDelay(10); repaint(); if(y>700){ y=-50; x= (int) (Math.random()*670); setLocation(x,y); score++; System.out.println(score); } } }); timer.start(); } } This is the code of the class that creates the asteroids: import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Timer; import java.util.TimerTask; import javax.swing.JFrame; import javax.swing.JPanel; public class SterTest extends JFrame implements ActionListener { public int a; public SterTest() { this.setSize(700, 700); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setLocationRelativeTo(null); final JPanel p = new JPanel(); p.setBackground(Color.BLACK); p.setLayout(null); for(a=0;a<3;a++) { Astroid astroid = new Astroid(1,1); p.add(astroid); } //Creates 3 asteroids to start with Timer timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { #Override public void run() { Astroid astroid2 = new Astroid(1,1); p.add(astroid2); a++; System.out.println("Het aantal asteroids in game is:"+a); } }, 5000, 5000); // creates a new asteroid every 5 seconds or so this.add(p); this.setVisible(true); }
Keeping track of the score probably isn't the job of the Asteroid class, so that variable would be best kept in a more central class. Then you can add an instance of the central class to each asteroid, and call a method to increment the score. Something like this: public class ScoreKeeper { private AtomicInteger score; public void incrementScore (int points) { score.getAndAdd (points); } public int getScore () { return score.get (); } } In you class SterTest you would create a single instance of ScoreKeeper and pass it to each new Astroid instance you create. public class Astroid { private ScoreKeeper scoreKeeper; public Astroid(int x,int y, ScoreKeeper scoreKeeper) { //... existing code ... this.scoreKeeper = scoreKeeper; } // ... when you want to increment the score, do this: scoreKeeper.incrementScore (1); }
Note: There are better and more OO approaches to this. This answer is that fastest route to working code from your current solution. Declare score as static. private static int score This will give you a single copy of that variable. However I see you have some threads. In this case you're going to need a little bit of synchronization to keep score consistent. I recommend adding private static final Object scoreLock to your fields. And replace score++ with synchronized(scoreLock) { Asteroid.score++; }
If you're not interested in keeping score of an individual asteroid than there is no reason to add a score variable to that class. The score should be maintained at a higher level, perhaps in your SterTest() class. When you detect an asteroid has made it to the bottom, just increment that score. I don't want to tell you how to design your program, but the most obvious way would be to just have actionPerformed return the score.
Create an AsteroidListener interface. Maybe like this: public interface AsteroidListener { public void impact(Asteroid asteroid); } Make your SterTest class implement this interface. Add a new parameter to your Asteroid constructor, for the listener. public Asteroid(int x, int y, AsteroidListener listener) { } When you need to call the listener to notify it that there was an impact: listener.impact(this); Tally up the score in your SterTest class.
Use the Java Observer/Observable pattern: public class Score extends Observable { private AtomicInteger counter = new AtomicInteger(); public void increment() { setChanged(); notifyObservers(Integer.valueOf(counter.incrementAndGet())); } } This class is added to Astroid : public Astroid(Score score, int x,int y) { // ... #Override public void actionPerformed(ActionEvent event) { // ... score.increment(); } } StarTest implements the Observer interface: public class StarTest implements Observer { // ... #Override public void update(Observable o, Object arg) { Integer count = (Inter)arg; // do something with the score } } You connect Observer and Observable as follows: StarTest starTest = new StarTest(); Score score = new Score(); score.addObserver(starTest); Astroid astroid = new Astroid(score, x, y);
How to delete an JPanel Object?
Im on to create a little "game", something like an 2d AirForce Shooter. So, i have a problem with deleting unused enemys. An Enemy is an simple JPanel, which is saved in the main logic as an array List. public static ArrayList<Enemy> enemys = new ArrayList<Enemy>(); The Enemy run logic does the following: while(!destroyed){ if(Game.running){ x--; if(getBounds().intersects(Field.player.getBounding())){ Player.death = true; } if(x < 0){ Field.deleteEnemy(this); } setBounds((int) x, (int) y, 100, 50); try{Thread.sleep(10);}catch(InterruptedException e){} } } So you can seem there i already tried to call the method deleteEnemy, and just give it the unused Enemy. But it isnt possible - when i just do this: public static void deleteEnemy(Enemy e){ System.out.println("test"); enemys.remove(e); } It will be just removed from the list, but coninues existing on the Main JPanel. And i cannot say remove(e); Because then i try to call a non static function in a static. So, how could i delete an Enemy? Someone knows? Thanks for help! The hole code: (Game.java) And, Enemy.java: package Game; import java.awt.*; import java.awt.event.*; import java.util.ArrayList; import javax.swing.JOptionPane; import javax.swing.JPanel; public class Field extends JPanel implements Runnable{ public static Player player = new Player(); public static ArrayList<Enemy> enemys = new ArrayList<Enemy>(); private Thread moveBackground = new Thread(this); private boolean bgMoving = false; public static boolean addMob = false; private int x = 0; private int bgSpeed = -1; public Field(){ setBounds(0, 0, 800, 600); setFocusable(true); setLayout(null); addKeyListener(new Handler()); add(player); } public void paintComponent(Graphics g){ Field.super.paintComponent(g); g.drawImage(Images.images[0], x, 0, this); } public static void deleteEnemy(Enemy e){ System.out.println("test"); enemys.remove(e); } public void run(){ while(!Player.death){ if(bgMoving){ bgMoving = true; x += bgSpeed; if(x < -(Images.images[0].getWidth(this) - this.getWidth() - 20)){ bgMoving = false; } repaint(); try { Thread.sleep(20); } catch (InterruptedException e) {} } if(addMob){ enemys.add(new Enemy()); add(enemys.get(enemys.size() - 1)); addMob = false; } } JOptionPane.showMessageDialog(null, "DIED!"); } public class Handler extends KeyAdapter { public void keyPressed(KeyEvent e) { player.KeyPressed(e); if(!bgMoving){ if(Game.running){ bgMoving = true; if(moveBackground.getState().toString() == "NEW"){ moveBackground.start(); } } } } public void keyReleased(KeyEvent e) { player.KeyReleased(e); } } } And, Enemy.java: package Game; import java.awt.Color; import java.awt.Graphics; import javax.swing.JPanel; public class Enemy extends JPanel implements Runnable{ Thread t = new Thread(this); private double x = Game.width(); private double y = Math.random() * Game.height(); private double xF = 0, yF = 0; private boolean destroyed = false; public Enemy(){ setBounds((int) x, (int) y, 100, 50); setOpaque(false); t.start(); } public void paintComponent(Graphics g){ Enemy.super.paintComponent(g); g.setColor(Color.GREEN); g.drawImage(Images.images[2], 0, 0, this); } public void run() { while(!destroyed){ if(Game.running){ x--; if(getBounds().intersects(Field.player.getBounding())){ Player.death = true; } if(x < 0){ Field.deleteEnemy(this); } setBounds((int) x, (int) y, 100, 50); try{Thread.sleep(10);}catch(InterruptedException e){} } } } }
After removing you will need to call revalidate() and repaint()
[Too long for a comment] I think the problem is in your logic on removing an Enemy/JPanel: You are removing it from the ArrayList only, what about the containing JPanel/JFrame you added it to? You must remove the JPanel from its container (maybe another JPanel or the JFrame) not just the ArrayList via Component#remove(Component c). If you drew the Enemy images directly in paintComponent(...) of your container via iterating the ArrayList; removing it from the ArrayList would be sufficient, as it will no longer be in the Array and thus no longer drawn on the next repaint(). +1 to #Optional, you may need to call revalidate() and repaint() on the container for the affects of the removed JPanel/Enemy to be shown. Also as #darijan mentioned, the use of static variables along with instance is not really a great design (though for certain designs this may be fine). In your case if you need access to an instance method of another class, within another class, simply pass the instance of the class whos method you would like to access to the object which will access it. Here is some psuedo code expressing much of the above mentioned problems / solutions: public class Field extends JPanel { private ArrayList<Enemy> enemies; public Field() { ... enemies.add(new Enemy(this));//create a new enemy and pas it the JPanel instance so it may access instance methods of this class } //ONLY USED IF JPanel for Enemy is ommited and Enemy class created which represents Enemy object and not Enemy object and aJPanel #Override protected void paintComponent(Graphics g) { super.paintComponent(g); ArrayList<Enemy> enemiesClone = new ArrayList<>(enemies);//copy array into another so we don't get a ConcurrentModificaton exception if removeEnemy is called while iterating the list if(!enemiesClone.isEmpty()) for(Enemy e:enemiesClone) {//iterate through array of images draw(e.getImage(),e.getX(),e.getY(),this); } } public void removeEnemy(Enemy e) { enemies.remove(e);//remove from the array //ONLY USED IF JPanels are used as Enemy remove(e);//remove from the JPanel //so the changes of removed panel can be visible seen revalidate(); repaint(); } } class Enemy extends JPanel //extends JPanel should be ommited for paintComponent method of drawing an enemy onscreen { private int x,y; private BufferedImage image; private Field f; public Enemy(Field f) {//constructor accepts Field instance to access instance method for the class this.f=f; } public void update() { if(offscreen||dead) { f.removeEnemy(this);//call removeEnemy which is an instance method of Field } } //BELOW METHODS ONLY USED WHEN Enemy represents object and not a JPanel which can draw its image itself (and update position by simply changing co-ordinates) public BufferedImage getImage() { return image; } public int getX() { return x; } public int getY() { return y; } } For a more detailed look check Game Development Loop, Logic and Collision detection Java Swing 2D I made which will give you the basics needed for most 2D games. However I do not use JPanels rather draw directly to a container.
Where do you add an Enemy to JPanel? Basically, you should call remove on Field JPanel: public void deleteEnemy(Enemy e){ System.out.println("test"); enemys.remove(e); this.remove(e); } The method should not be static.
coordinates stored in a getPoint() object
I am having a problem with the following code. My intent is to store the coordinates of a mouse click into an arraylist using getPoint, and then draw a rectangle at each location that the user has clicked. I have searched high and low for how to extract the x and y coordinates individually from a getPoint object to no avail. I am new to java, the line that is giving me trouble at compile time is: g2.drawRect(coordinateList(j).getHeight(),coordinateList(j.getWidth(),3,3); I know that I am probably way off, but how can I extract the x and y coordinates of a point individually from an array list, one item of the array by one in order to repaint a rectangle at the new click point and also all the previous clicks as well? import java.awt.*; import javax.swing.*; import java.awt.event.*; import java.awt.geom.*; import java.awt.event.MouseListener; import java.awt.Point; import java.util.*; public class ClickCloud extends JPanel { private int pointxy; //private Rectangle2D.Double r1; private boolean mouseClick; private int count; //private Point[] points; private Point coordinates = new Point(0, 0); private ArrayList<Point> coordinateList = new ArrayList<Point>(); public ClickCloud() { this.setPreferredSize(new Dimension(500,500)); this.addMouseListener(new MyMouseListener()); } public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D)g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); for (int j = 0; j < count; j++) { g2.setStroke(new BasicStroke(1.0f)); g2.setPaint(Color.BLUE); g2.drawRect(coordinateList(j).getHeight(),coordinateList(j.getWidth(),3,3); } } private class MyMouseListener implements MouseListener { public void mouseClicked(MouseEvent me) { count++; coordinates.setLocation(me.getPoint()); coordinateList.add(coordinates.getLocation()); repaint(); } public void mousePressed(MouseEvent me) { } public void mouseReleased(MouseEvent me) { } public void mouseEntered(MouseEvent me) { } public void mouseExited(MouseEvent me) { } } public static void main(String[] args) { JFrame f = new JFrame("ClickCloud demo"); f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); f.setLayout(new FlowLayout()); f.add(new ClickCloud()); f.pack(); f.setVisible(true); } } Thanks, T
Forget all the getLocation and setLocation. It's redundant. Just store me.getPoint() in your coordinateList. Then you can get the x and y coordinates with point.getX() and point.getY() respectively. In paintComponent, there is an easier way to iterate over a list of points: for (Point coordinate : coordinateList) { //"for each coordinate in coordinateList" //do something with coordinate.getX() and coordinate.getY() }
You are not getting properly the points from the ArrayList. g2.drawRect(coordinateList(j).getHeight(),coordinateList(j.getWidth(),3,3); To get the item at index j with an ArrayList, you simply use the method get(): Point point = coordinateList.get(j); Then the problem is that pointonly represents, well, points... They only have X and Y coordinates, not width and height. If I try to guess what you want to do and assume that you want to draw 3x3 rectangles where the user has clicked, you would call drawRect() like this: g2.drawRect(point.getX(), point.getY(), 3, 3); Also: You don't need to handle a count variable to know the number of points you have in your ArrayList. Just use the size() method of coordinateList or even better, use an enhanced for loop. You can use MouseAdapter instead of MouseListener to only override the events you need. You don't need the coordinates member and the get/setLocation stuff. Just write coordinateList.add(me.getPoint());
Coin flip program
I tried making a program that flips a coin(shows image of heads first and later shows image of tails) and I encountered problems trying to have the image of the coin viewed when I ran the problem; only a blank screen would show. I don't know whether this is from an improper saving method of the jpg images or from an error in the code. I also came across an error before again coding the program where I had the heads image show and tails image not show. CoinTest.java runs coin runner and Coin.java is the class for the program. import java.awt.*; import java.awt.event.*; import javax.swing.*; public class CoinTest extends JPanel implements ActionListener { private Coin coin; public CoinTest () { Image heads = (new ImageIcon("quarter-coin-head.jpg")).getImage(); Image tails = (new ImageIcon("Indiana-quarter.jpg")).getImage(); coin = new Coin(heads, tails); Timer clock = new Timer(2000, this); clock.start(); } public void paintComponent(Graphics g) { super.paintComponent(g); int x = getWidth() / 2; int y = getHeight() / 2; coin.draw(g, x, y); } public void actionPerformed(ActionEvent e) { coin.flip(); repaint(); } public static void main(String[] args) { JFrame w = new JFrame("Flipping coin"); w.setSize(300, 300); w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); CoinTest panel = new CoinTest(); panel.setBackground(Color.WHITE); Container c = w.getContentPane(); c.add(panel); w.setVisible(true); } } Now the actual Coin class. import java.awt.Image; import java.awt.Graphics; public class Coin { private Image heads; private Image tails; private int side = 1; public Coin(Image h, Image t) { heads = h; tails = t; } //flips the coin public void flip() { if (side == 1) side = 0; else side = 1; } //draws the appropriate side of the coin - centered in the JFrame public void draw(Graphics g, int x, int y) { if (side == 1) g.drawImage(heads, heads.getWidth(null)/3, heads.getHeight(null)/3, null); else g.drawImage(heads, tails.getWidth(null)/3, tails.getHeight(null)/3, null); } }
Firstly, ensure that both images are in the correct location to load. Secondly, you have a typo here: if (side == 1) g.drawImage(heads, heads.getWidth(null)/3, heads.getHeight(null)/3, null); else g.drawImage(heads, tails.getWidth(null)/3, tails.getHeight(null)/3, null); ^^^^ should be tails...
The width and height of the applet are coded in the tag. The code that draws the applet uses the two methods to get these values at run time. So now, different tags can ask for the same applet to paint different sized rectangles. The source code does not need to be recompiled for different sizes.