I'm trying to move the boat on the x-axis (without the keyboard yet). How can I relate the movement/ animation to the boat.png
and not to any other image?
public class Mama extends Applet implements Runnable {
int width, height;
int x = 200;
int y = 200;
int dx = 1;
Image img1, img2, img3, img4;
@Override
public void init(){
setSize(627, 373);
Thread t = new Thread(this);
img1 = getImage(getCodeBase(),"Background.png");
img2 = getImage(getCodeBase(), "boat.png");
img3 = getImage(getCodeBase(), "LeftPalm.png");
img4 = getImage(getCodeBase(), "RightPalm.png");
}
@Override
public void paint(Graphics g){
g.drawImage(img1, 0, 0, this);
g.drawImage(img2, 200, 200, this);
g.drawImage(img3, 40, 100, this);
g.drawImage(img4, 450, 130, this);
}
@Override
public void run() {
while(true){
x += dx;
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
System.out.println("Thread generates an error.");
}
}
}
}
There are a few things that stand out...
The "Problem"
As has already been stated, you need to supply variable arguments to the image drawing process. g.drawImage(img2, x, y, this);
, this will allow you define where the image should be painted.
While you've implemented Runnable
, you've actually not started any threads to call it. This means, nothing is actually changing the variables.
In you start
method, you should be calling something like new Thread(this).start()
.
Recommendations
Although you've tagged the question as Swing, you're using AWT components. This isn't recommended (in fact applets are generally discouraged as they are troublesome - IMHO). The other problem, as you are bound to find out shortly, is they are not double buffered, this generally leads to flickering when performing animation, which isn't desirable.
As a side note, it is also discouraged to override the paint
method of top level containers like Applet
. Top level containers tend to contain a number additional components, by overriding the paint
method like this, you destroy this setup. Also, top level containers don't tend to be double buffered either.
The example below uses a JFrame
, but it wouldn't take much to convert it to use a JApplet
(just drop the AnimationPanel
on to it. This is another reason why extending from top level containers is generally discouraged ;)
public class AnimatedBoat {
public static void main(String[] args) {
new AnimatedBoat();
}
public AnimatedBoat() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new AnimationPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class AnimationPane extends JPanel {
private BufferedImage boat;
private int xPos = 0;
private int direction = 1;
public AnimationPane() {
try {
boat = ImageIO.read(new File("boat.png"));
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
xPos += direction;
if (xPos + boat.getWidth() > getWidth()) {
xPos = getWidth() - boat.getWidth();
direction *= -1;
} else if (xPos < 0) {
xPos = 0;
direction *= -1;
}
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public Dimension getPreferredSize() {
return boat == null ? super.getPreferredSize() : new Dimension(boat.getWidth() * 4, boat.getHeight());
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int y = getHeight() - boat.getHeight();
g.drawImage(boat, xPos, y, this);
}
}
}
You need to replace g.drawImage(img2, 200, 200, this);
with g.drawImage(img2, x, y, this);