I am working on a 2D game as a learning project and I have hit a bump. I cannot figure out how to move a Polygon object using the KeyListener within a JPanel (which is added to a JFrame). I've tried the frog.translate(int x, int y) method, which does not update the location. I've also tried changing the array coordinates manually. A sample of my code is below:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Board extends JPanel implements KeyListener {
private Frog frog;
public Board() {
setBackground(Color.GREEN);
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
frog = new Frog();
// Frog graphics
g2.setColor(Color.BLACK);
g2.drawPolygon(frog);
g2.setColor(new Color(0,150,15));
g2.fillPolygon(frog);
}
@Override
public void keyTyped(KeyEvent ke) {
}
@Override
public void keyPressed(KeyEvent ke) {
int c = ke.getKeyCode();
if(c == KeyEvent.VK_LEFT){
frog.moveFrogLeft(25);
//frog.translate(-25,0);
}
if(c == KeyEvent.VK_RIGHT){
frog.moveFrogRight(25);
//frog.translate(25,0);
}
if(c == KeyEvent.VK_UP){
frog.moveFrogUp(25);
//frog.translate(0,-25);
}
if(c == KeyEvent.VK_DOWN){
frog.moveFrogDown(25);
//frog.translate(0,25);
}
repaint();
}
@Override
public void keyReleased(KeyEvent ke) {
}
}
///////////////////////
import java.awt.Polygon;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Frog extends Polygon {
private Integer[] xcoord;
private Integer[] ycoord;
public Frog(){
xcoord = new Integer[] {5,10,10,15,15,20,
20,30,30,35,35,40,40,
45,45,40,40,30,30,40,
40,45,45,40,40,35,35,
30,30,20,20,15,15,10,
10,5,5,10,10,20,20,
10,10,5,5};
ycoord = new Integer[] {10,10,5,5,20,20,
10,10,20,20,5,5,10,10,
15,15,25,25,30,30,35,35,
40,40,45,45,35,35,40,40,
35,35,45,45,40,40,35,35,
30,30,25,25,15,15,10};
for(int i = 0; i < xcoord.length; i++){
this.addPoint(xcoord[i],ycoord[i]);
}
}
public void moveFrogLeft(int x) {
if(xcoord[0] - x < 0){
//do nothing
} else {
for(int i = 0; i < xcoord.length; i++){
xcoord[i] = xcoord[i] - x;
}
}
}
public void moveFrogRight(int x){
if(xcoord[0] + x > 600){
//do nothing
} else {
for(int i = 0; i < xcoord.length; i++){
xcoord[i] = xcoord[i] + x;
}
}
}
public void moveFrogUp(int y){
if(ycoord[0] - y < 0){
//do nothing
} else {
for(int i = 0; i < ycoord.length; i++){
ycoord[i] = ycoord[i] - y;
}
}
}
public void moveFrogDown(int y){
if(ycoord[0] + y > 600){
//do nothing
} else {
for(int i = 0; i < ycoord.length; i++){
ycoord[i] = ycoord[i] + y;
}
}
}
}
This code has a simple issue:
The marked line overwrites the frog with a new instance, every time the frog is painted, thus reseting it to the original point. Apart from the obvious issue that this is the reason for the unexpected behaviour, never do any unnecessary calculations in the
paintComponent(...)
-method. Any precomputation, Object-generation, etc. should be done outside ofpaintComponent
!!!Don't create a Frog in your paintComponent() method! That is throwing away the existing frog and creating a new one with default position. You should create all of your Frog instances when you initialize your panel, or possibly in response to a b button click to "create a new frog".
First of all, I would strongly discourage you from using
KeyListener
, it's troublesome at the best, a better choice would be to make use of the Key Bindings API which was desgiend to fix the short commings of theKeyListener
API.Second, you shouldn't be modifying the points of the polygon, the 2D Graphics API is actually capable of some really neat tricks which makes it much easier and faster to change the location (and rotation and scale) of what you are drawing.
Take a look closer look at 2D Graphics for more details.
Instead of changing the points of the polygon, which isn't taking into consideration the viewable bounds, you could simply use an
AffineTransform
...This just simply changes the origin point of the
Graphics
context to the location where you want to paint the polygon (yes, there's another reason why I'm usingAffineTransform
Now, you're probably wondering why I would use
AffineTransform
instead ofGraphcis2D#translate
, the main reason is, it's easy to apply other transformations, like rotation...All this does is apply a compound transformation, moving the
Graphics
context's origin and rotation matrixAnd for a complete example...
Look ma, no maths!