1

I am trying to make a Sprite move across a background image in swing, but every time I update the position and it repaints, it repaints with the previous position of the image as well. However I am just trying to make it so that it moves 10 pixels for every time the right arrow is pressed. Here is the Main class, which controls the movement.

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;

public class Main extends JFrame implements KeyListener, ActionListener{
    private static final long serialVersionUID = 1L;

    //Caitlan info
    Image caitlanImage = new ImageIcon("Caitlan.png").getImage();
    Person caitlan = new Person(caitlanImage, "Caitlan", 50, 200, true);

    //Jake info
    Image jakeImage = new ImageIcon("Jake.png").getImage();
    Person jake = new Person(jakeImage, "Jake", 0, 200, true);

    //Level objects
    Image granadaBackground = new ImageIcon("Granada Background.jpg").getImage();
    Level granada = new Level(granadaBackground, "Granada", new Point(600, 300));

    Image elevatorBackground = new ImageIcon("Elevator.png").getImage();
    Level elevator = new Level(elevatorBackground, "Elevator", new Point(0,0));



    public static void main(String[] args) throws InterruptedException{
        new Main();
    }
    public Main() throws InterruptedException{  //Constructor (only should be called once)
        setSize(700,300);
        setTitle("Project Anniversary");
        setVisible(true);   
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        addKeyListener(this);
    }
    public void paint(Graphics g){      //Overridden paint method.

        if(checkIfLevelDone(granada, caitlan)){
            granada.setDone();
        }
        if(!granada.isDone()){
            g.drawImage(granada.getImage(), 0, 0, granadaBackground.getWidth(null), granadaBackground.getHeight(null),null);
            g.drawImage(jake.getImage(), jake.getPosX(), jake.getPosY(), jake.getImage().getWidth(null), jake.getImage().getHeight(null),null);
            g.drawImage(caitlan.getImage(), caitlan.getPosX(), caitlan.getPosY(), caitlan.getImage().getWidth(null), caitlan.getImage().getHeight(null), null);
        }
        else if(granada.isDone()){
            setSize(300,300);
            g.drawImage(elevator.getImage(), 0, 0,   
    elevator.getImage().getWidth(null), elevator.getImage().getHeight(null),null);
            g.drawImage(jake.getImage(), jake.getPosX(), jake.getPosY(), 
    jake.getImage().getWidth(null), jake.getImage().getHeight(null),null);
            g.drawImage(caitlan.getImage(), caitlan.getPosX(), caitlan.getPosY(), 
     caitlan.getImage().getWidth(null), caitlan.getImage().getHeight(null), null);
        }
    }
    public void keyPressed(KeyEvent e) { //Method called whenever a key is pressed
        caitlan.printLocation();
        int code = e.getKeyCode();
        if(code == KeyEvent.VK_RIGHT){   //When the user presses the right arrow
            caitlan.setLocation(caitlan.getPosX() + 10, caitlan.getPosY());
            repaint();
        }
        if(code == KeyEvent.VK_LEFT){    //When the user presses the left arrow
            caitlan.setLocation(caitlan.getPosX() - 10, caitlan.getPosY());
            repaint();
        }
        if(code == KeyEvent.VK_UP){         //Implement jumping code here
            repaint();
        }
    }
    public boolean checkIfLevelDone(Level l, Person p){ 
    //Method to check if a given level is done
        if(l.getCompletionPoint().x <= p.getPosX()){
            return true;
        }
        return false;
    }
    public void followOtherPerson(Person a, Person b) throws InterruptedException{               
    //Method to follow the other character

    }
    public void jump(Person p) throws InterruptedException{     //Jump method
        caitlan.setLocation(caitlan.getPosX(), caitlan.getPosY() - 60);
        repaint();
    }
    public void keyReleased(KeyEvent e) {           //IGNORE

    }
    public void keyTyped(KeyEvent e) {              //IGNORE

    }
    public void actionPerformed(ActionEvent e) {    //IGNORE


    }

    }

Here is the Level class:

 import java.awt.Image;
 import java.awt.Point;

 public class Level {

//Private attributes
private Image backgroundImage;           //Image
private String levelName;               //Name of level
private boolean levelComplete;      //Status that holds if the level is done
private Point completionPoint;      //Point at which the level is completed

public Level(Image i, String l, Point p){       //Constructor
    this.backgroundImage = i;
    this.levelName = l;
    this.completionPoint = p;
    levelComplete = false;
}
public void setDone(){
    levelComplete = true;
}
public boolean isDone(){        //Returns if the level is done or not
    return levelComplete;
}
public Image getImage(){            //Getters and setters
    return backgroundImage;
}
public String getLevelName(){
    return levelName;
}
public void setImage(Image i){
    this.backgroundImage = i;
}
public void setName(String name){
    this.levelName = name;
}
public Point getCompletionPoint(){
    return completionPoint;
}
public void setCompletionPoint(Point p){
    this.completionPoint = p;
}

 }

And finally, here is the Person class.

  import java.awt.*;

public class Person{

    //Attributes
    private Image image;
    private String name;
    private int xlocation;
    private int ylocation;

    /*Boolean that you can publically access to determine if the given Person object is a 
    player*/
    public boolean isPlayer;      

    public Person(Image i, String s){       //Really shouldn't be used
        this.image = i;
        this.name = s;
    }
    public Person(Image i){             //Really shouldn't be used
        this.image = i;
    }
    public Person(Image i, String s, int xloc, int yloc){       //Basic constructor
        this.name = s;
        this.image = i;
        this.xlocation = xloc;
        this.ylocation = yloc;
    }
    public Person(Image i, String s, int xloc, int yloc, boolean isPlayer){ //Detailed constructor
        this.name = s;
        this.image = i;
        this.xlocation = xloc;
        this.ylocation = yloc;
        this.isPlayer = isPlayer;
    }
    public void printLocation(){
        System.out.println("Person " + name + " is at location (" + xlocation +", " + ylocation +").");
    }
    public void incrementPositionX(){                       //Increase xlocation by 1
        xlocation++;
    }
    public void incrementPositionY(){                       //Increase ylocation by 1
        ylocation++;
    }
    public void setName(String name){                       //Method to change the name of a sprite
        this.name = name;
    }
    public void setImage(Image image){  //Method to change the image of a sprite
        this.image = image;
    }
    public Image getImage(){                //Get image
        return image;
    }
    public int getPosX(){                   //Get x position
        return xlocation;
    }
    public int getPosY(){                   //Get y position
        return ylocation;
    }
    public String getName(){                //Get name
        return name;
    }
    public void setLocation(int x, int y){  //Method to change the location of a sprite
        this.xlocation = x;
        this.ylocation = y;
    }
}
Jake Byman
  • 540
  • 12
  • 29

1 Answers1

4

You should not paint directly on top level container such as JFrame. Instead, use JComponent or JPanel. Override paintComponent() for painting rather than paint() and don't forget to call super.paintComponent(g)

Take a look at Performing Custom Painting tutorial for more information.

Also, key listener is a lower level interface. It is best to use Key Bindings instead. See How to Use Key Bindings for details and examples.

Also, there is no need to create ImageIcon to get Image. Look into ImageIO.read() methods.

tenorsax
  • 21,123
  • 9
  • 60
  • 107
  • Also see this good [example](http://stackoverflow.com/a/9772966/1048330) by @mKorbel that demonstrates how to move an icon around the panel using key bindings. – tenorsax Mar 19 '13 at 17:45
  • Thank you! I did that, and that was very helpful. But do you know why the image is still being repainted next to itself at its previous position? I'm trying to get the sprite to animate, by moving pixels over, but it doesn't seem to be working. Any thoughts? – Jake Byman Mar 19 '13 at 18:05
  • @JakeByman you're welcome! I could not repro the issue with painting artifacts in the posted code. Make sure you start the app with `invokeLater`, see [Initial Threads](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html). Try composing SSCCE so it is easier to run and reproduce the issue. – tenorsax Mar 19 '13 at 18:17