i am trying to create a game similar to jetpack joyride in which the user can hold the spacebar to go up and let go to travel downward. I am using timers to simulate the gravity and using keyPressed and keyReleased to check if the user is holding the spacebar. I am using print statements to know for sure that both keyPressed and keyReleased are working, but i dont know why the physics arent running. I dont know whether the problem is my if statements not updating, if it is the new timers being created inside of the if statement. Either way, the gravity is not changing, and im stuck. Help is appreciated.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Calendar;
public class Game implements KeyListener {
JFrame frame;
JLabel player;
public boolean grounded = false;
public int velocity = 0;
public int finalY = 0;
public boolean spaceHeld = false;
Action spaceAction;
Game() {
frame = new JFrame("Nicholas Seow-Xi Crouse");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1920, 1080);
frame.setLayout(null);
frame.setFocusable(true);
frame.addKeyListener(this);
player = new JLabel();
player.setBackground(Color.red);
player.setBounds(10, 1800, 50, 50);
player.setOpaque(true);
frame.add(player);
frame.setVisible(true);
Timer flightTime = new Timer();
TimerTask flight = new TimerTask() {
public void run() {
if(velocity > -5) {
velocity -= 1;
}
else{
velocity = -5;
}
if (finalY < -61) {
finalY = finalY + velocity;
}
else{
finalY = -61;
}
player.setLocation(player.getX(), player.getY() + finalY);
if (player.getY() <= 0){
cancel();
velocity = 0;
finalY = 0;
player.setLocation(player.getX(), 0);
}
}
};
Timer gravityTime = new Timer();
TimerTask gravity = new TimerTask() {
//creates a timer run method that simulates the falling gravity when not grounded
public void run() {
if(velocity < 5){
velocity += 1;
}
else{
velocity = 5;
}
//creates the variable the tells where the player is located
if (finalY < 61) {
finalY = finalY + velocity;
}
else{
finalY = 61;
}
player.setLocation(player.getX(), player.getY() + finalY);
if (player.getY() >= 1000){
cancel();
velocity = 0;
finalY = 0;
player.setLocation(player.getX(), 990);
}
}
};
if (spaceHeld == false ) {
gravityTime.scheduleAtFixedRate(gravity, 0, 33);
}
if (spaceHeld == true ) {
flightTime.scheduleAtFixedRate(flight, 0 ,33);
}
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_SPACE){
spaceHeld = true;
//debug
System.out.println(spaceHeld);
}
}
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_SPACE){
spaceHeld = false;
//debug
System.out.println(spaceHeld);
}
}
}
Code is event based, and currently nothing triggers your timers to start. To do this you can simply move the timer schedule/start actions inside the key events:
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_SPACE){
//Cancel the other timer here so that they don't overlap
gravity.cancel();
gravityTime.cancel();
//Create a new instance of the timer
flightTime = new Timer();
flight = new TimerTask() {
public void run() {
if(velocity > -5) {
velocity -= 1;
}
else{
velocity = -5;
}
if (finalY < -61) {
finalY = finalY + velocity;
}
else{
finalY = -61;
}
player.setLocation(player.getX(), player.getY() + finalY);
if (player.getY() <= 0){
cancel();
velocity = 0;
finalY = 0;
player.setLocation(player.getX(), 0);
}
}
};
//Now start the timer
flightTime.scheduleAtFixedRate(flight, 0 ,33);
}
}
//Do the same for the gravity method
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_SPACE){
......
}
}
}
Note above that you should also cancel the other scheduled task with the opposing key events so that they do not overlap each other and value strange results.
And to make flightTime and gravityTime accessible to the keyPressed method simply declare them as class variables:
public class Game implements KeyListener {
JFrame frame;
JLabel player;
public boolean grounded = false;
public int velocity = 0;
public int finalY = 0;
public boolean spaceHeld = false;
//Move them here but don't assign a value:
public Timer flightTime;
public TimerTask flight;
public Timer gravityTime;
public TimerTask gravity;
You can still create the object later in the Game method:
flightTime = new Timer();
flight = new TimerTask() {
....
};
Related
noob here trying to make a simple snake game. followed along with tutorial on youtube and my code mayches the working code as best i can tell...snake not responding to commands, seems KeyListener not working. printed out requestFocusInWindow in jpanel constructor to make sure it was in focus and got back false, even though i entered setFocusable(true) asfirst arg in panel constructor.
please help me figure out why snake not responding to movement commands
package otherSnake;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JPanel;
public class Panel extends JPanel implements Runnable {
public static final int width = 800, height = 800;
private boolean running = false;
private Thread thread;
private Bodypart b;
private ArrayList<Bodypart> snake;
private Apple apple;
private ArrayList<Apple> apples;
private Random r;
private int size = 5;
private int x = 10, y = 10;
private boolean right = true, left = false, up = false, down = false;
private int ticks = 0;
private Key key;
public Panel() {
setFocusable(true);
key = new Key();
addKeyListener(key);
setPreferredSize(new Dimension(width, height));
r = new Random();
snake = new ArrayList<Bodypart>();
apples = new ArrayList<Apple>();
start();
}
public void tick() {
if (snake.size() == 0) {
b = new Bodypart(x, y, 10);
snake.add(b);
}
if (apples.size() == 0) {
int xCord = r.nextInt(79);
int yCord = r.nextInt(79);
apple = new Apple(xCord, yCord, 10);
apples.add(apple);
}
ticks++;
if (ticks > 250000) {
if (right)
x++;
if (left)
x--;
if (up)
y--;
if (down)
y++;
ticks = 0;
b = new Bodypart(x, y, 10);
snake.add(b);
if (snake.size() > size) {
snake.remove(0);
}
}
}
public void paint(Graphics g) {
g.clearRect(0, 0, width, height);
g.setColor(Color.BLACK);
for (int i = 0; i < width / 10; i++) {
g.drawLine(i * 10, 0, i * 10, height);
}
for (int i = 0; i < height / 10; i++) {
g.drawLine(0, i * 10, width, i * 10);
}
for (int i = 0; i < snake.size(); i++) {
snake.get(i).draw(g);
}
for (int i = 0; i < apples.size(); i++) {
apples.get(i).draw(g);
}
}
public void start() {
running = true;
thread = new Thread(this, "Game Loop");
thread.start();
}
public void stop() {
running = false;
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void run() {
while (running) {
tick();
repaint();
}
}
private class Key implements KeyListener {
#Override
public void keyTyped(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_RIGHT ) {
up = false;
down = false;
right = true;
//left=false;
}
if (key == KeyEvent.VK_LEFT ) {
up = false;
down = false;
left = true;
//right=false;
}
if (key == KeyEvent.VK_UP ) {
up = true;
down = false;
left = false;
right = false;
}
if (key == KeyEvent.VK_DOWN ) {
up = false;
down = true;
left = false;
right = false;
}
}
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
}
I have this small project that upon running the program it will automatically animate. In this case an oval shape should continuously animate using a thread. However in my program it will stop for the fifth direction - meaning following a certain path. Can anyone suggest me a better solution or help me let the oval shape continuously move until the user closes the program.
package movingball;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MovingBall extends JPanel{
private int ballX = 30;
private int ballY = 30;
private int pattern = 1;
private int limitHeight;
private int limitWidth;
boolean horizontalBoundary = true;
boolean verticalBoundary = true;
public MovingBall(){
setBackground(Color.BLACK);
}
public MovingBall(int x, int y){
x = this.ballX;
y = this.ballY;
repaint();
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500,700);
MovingBall movingBall = new MovingBall();
frame.add(movingBall);
frame.setVisible(true);
BallUsingThread ball = new BallUsingThread(movingBall);
Thread first = new Thread(ball);
first.start();
}
#Override
public void paintComponent(Graphics canvas){
super.paintComponent(canvas);
canvas.setColor(Color.BLUE);
canvas.fillOval(ballX, ballY, 100, 100);
}
public void animateBall(){
if(horizontalBoundary && verticalBoundary){
if(pattern == 1){
diagonalDown(getWidth()-100,365);
}else if(pattern == 2){
diagonalDown(getWidth(),150);
}
}
if(!horizontalBoundary && !verticalBoundary){
diagonalDownLeft(150, getHeight());
pattern = 4;
}
if(horizontalBoundary && !verticalBoundary){
if(pattern == 4){
diagonalUp(0, 490);
}
if(pattern == 5){
System.out.print("helo");
diagonalUp(500,10);
}
System.out.print("last move" + pattern);
}
if(!horizontalBoundary && verticalBoundary){
diagonalUpRight(getWidth(),100);
pattern = 5;
System.out.print(pattern);
}
repaint();
}
public void diagonalDown(int limitWidth, int limitHeight){
this.limitWidth = limitWidth;
this.limitHeight = limitHeight;
if((ballX += 30) >= limitWidth){
horizontalBoundary = false;
}
if((ballY += 30) >= limitHeight){
verticalBoundary = false;
}
}
public void diagonalUp(int limitWidth, int limitHeight){
this.limitWidth = limitWidth;
this.limitHeight = limitHeight;
if((ballX -= 30) <= limitWidth) {
horizontalBoundary = false;
}
if((ballY -= 30) <= limitHeight){
verticalBoundary = true;
}
}
public void diagonalUpRight(int limitWidth, int limitHeight){
this.limitWidth = limitWidth;
this.limitHeight = limitHeight;
if((ballX += 30) >= limitWidth) {
horizontalBoundary = true;
}
if((ballY -= 30) <= limitHeight){
verticalBoundary = false;
}
}
public void diagonalDownLeft(int limitWidth, int limitHeight){
this.limitWidth = limitWidth;
this.limitHeight = limitHeight;
if((ballX -= 30) <= limitWidth){
horizontalBoundary = true;
}
if((ballY += 30) >= limitHeight){
verticalBoundary = false;
}
//System.out.print("downleft");
}
}
class BallUsingThread implements Runnable{
private final MovingBall movingBall;
public BallUsingThread(MovingBall mb){
movingBall = mb;
}
#Override
public void run() {
for(;;){
movingBall.animateBall();
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
System.out.printf("Error",ex);
}
}
}
}
It is not the problem with loop, if you System.out.println("loop running"); you will see that the loop is running, but that there is the problem with your draw ball logic that in this part of your code
if(!horizontalBoundary && verticalBoundary){
diagonalUpRight(getWidth(),100);
pattern = 5;
System.out.print(pattern);
}
You are trying to diagonalUpRight() so after some calling to this method, then the none of the if clause will executed, because the conditions are not satisfied, so the ball remains in the same place at every loop, and seems that the loop stopped working.
A small suggestion: It is better to use while(tru /*some condition*/) loop instead of for(;;) in such cases.
Solution: If you carefully check the logic you will see that there is no an if clause which is used for the condition below:
horizontalBoundary = true
verticalBoundary = true
When pattern = 5 So when these two variables become true andpattern = 5 then nothing will happen to the ball position, so you can write a condition which is used to check these two variables for true value.
Eidt Eidt the below part of you code and you will see the result which loop is not stopping, I just initialized the position of ball the values become true and the pattern = 5.
if(horizontalBoundary && verticalBoundary){
if(pattern == 1){
diagonalDown(getWidth()-100,365);
}else if(pattern == 2){
diagonalDown(getWidth(),150);
} else { // added this else block
ballX = 30;
ballY = 30;
pattern = 1;
}
}
Override paintComponent(Graphics) and implement all painting inside this method (but not animations).
Then use Swing timer to schedule periodic events each 100 ms, implement everything that changes the picture in the handler of this event and call repaint() from there at the end to refresh the picture.
I'm trying to make a small app that bounces balls around the frame of the window. When I add more than 1 ball to the list; it doesn't loop through them as expected.
Here's my code:
The Main Class:
public class Main extends JFrame {
private static final long serialVersionUID = 1L;
private List<Ball> balls = new ArrayList<Ball>();
private List<Ball> tempballs = new ArrayList<Ball>();
private static Timer t;
public void addBall(Ball b) {
tempballs.add(b);
}
public void initUI() {
this.setSize(500, 500);
this.setDefaultCloseOperation(3);
this.setVisible(true);
}
private BufferStrategy bs;
private Random r = new Random();
public void paint() {
if (!tempballs.isEmpty()) {
balls.addAll(tempballs);
tempballs = new ArrayList<Ball>();
}
int i = 0;
System.out.println(balls.size());
for (Ball b : new ArrayList<Ball>(balls)) {
i++;
System.out.println(i);
if ((bs = this.getBufferStrategy()) == null) {
this.createBufferStrategy(2);
return;
}
if (bs.contentsLost() || bs.contentsRestored()) {
return;
}
if (b.y >= this.getHeight() - 100) {
b.ydirection = -r.nextDouble() * 5;
}
if (b.y < 20) {
b.ydirection = r.nextDouble() * 5;
}
if (b.x >= this.getWidth() - 100) {
b.xdirection = -r.nextDouble() * 5;
}
if (b.x < 0) {
b.xdirection = r.nextDouble() * 5;
}
b.x += b.xdirection;
b.y += b.ydirection;
if (b.xdirection > 0)
b.xdirection += 0.1;
else
b.xdirection += -0.1;
if (b.ydirection > 0)
b.ydirection += 0.1;
else
b.ydirection += -0.1;
Graphics g = bs.getDrawGraphics();
g.fillOval((int) b.x, (int) b.y, 100, 100);
bs.show();
g.dispose();
bs.dispose();
}
i = 0;
}
public static void main(String[] args) {
try {
final Main m = new Main();
m.addMouseListener(new Mouse(m));
m.initUI();
t = new Timer();
TimerTask tt = new TimerTask() {
#Override
public void run() {
m.paint();
}
};
t.schedule(tt, Calendar.getInstance().getTime(), 20);
} catch (ConcurrentModificationException e) {
e.printStackTrace();
}
}
}
Here's the Ball class:
public class Ball {
private Random r = new Random();
public double y, x, ydirection, xdirection;
public Ball(int x, int y) {
this.y = y;
this.x = x;
ydirection = r.nextGaussian() * 5;
xdirection = r.nextGaussian() * 5;
}
}
and the mouse listener:
public class Mouse implements MouseListener {
Main m;
public Mouse(Main m) {
this.m = m;
}
#Override
public void mouseClicked(MouseEvent e) {
m.addBall(new Ball(e.getX(), e.getY()));
System.out.println("cl");
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
}
Additional details:
It only loops through the first item in the list, but the list size grows.
I'm using java 6, but I will change versions if needed.
If your loop does not behave as intended, try to find out why it is cancelled. You have two return statements in your loop which could cause this behavior. Make sysouts before those returns to figure out which one is the cause. Then find out why your if around the return is true. To digg deeper you can use your IDE's debugging mode and place breakpoints at interesting lines or use the step mode to run one line of code at a time.
Besides this you can place both if before the loop, the values they are checking should not change while you are in the paint() function (you are using the UI thread which might change them).
You have below return statements inside the loop. If the execution reaches any of the return statements, the loop ends.
Figure out, if you are entering these conditions and returning for the first value in the list.
if ((bs = this.getBufferStrategy()) == null) {
this.createBufferStrategy(2);
return;
}
if (bs.contentsLost() || bs.contentsRestored()) {
return;
}
I am trying to get a ball to bounce up and down when you press the up arrow key. I can get the ball to move up but it will not stop moving up. I have written the code for the ball movement in my update method. I am trying to get the ball to stop at y coordinate 400, but it just passes it up.
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
public class Game extends Canvas implements Runnable {
int x,y;
public static int width = 300;
public static int height = width / 16 * 9;
public static int scale = 3;
private boolean running = false;
public Thread thread;
public JFrame frame;
public Keyboard key;
private BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
private int[] pixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();
public Game() {
Dimension size = new Dimension(width * scale, height * scale);
setPreferredSize(size);
frame = new JFrame();
key = new Keyboard();
addKeyListener(key);
}
public synchronized void start() {
running = true;
thread = new Thread(this, "Display");
thread.start();
}
public synchronized void stop(){
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void run() {
long lastTime = System.nanoTime();
final double nanoSeconds = 1000000000.0 / 60.0;
double delta = 0;
int frames = 0;
int gameUpdates = 0;
long timer = System.currentTimeMillis();
requestFocus();
while(running){
long now = System.nanoTime();
delta += (now - lastTime) / nanoSeconds;
lastTime = now;
//this ensures that delta only updates the screen 60 times each second
while (delta >= 1){
update();
gameUpdates++;
delta--;
}
render();
frames++;
//this if statement happens once a second
if (System.currentTimeMillis() - timer > 1000){
timer += 1000;
frame.setTitle("Bouncy Ball! ~ ~ ~ Updates per second: " + gameUpdates + ". Frames per second: " + frames + ".");
gameUpdates = 0;
frames = 0;
}
}
stop();
}
int yy;
public void update() {
key.update();
y = y + yy;
if(key.up){
yy = -5;
if(y == 400){
yy = 0;}
}
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null){
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.drawImage(image,0,0,getWidth(),getHeight(),null);
g.setColor(Color.DARK_GRAY);
g.fillRect(0,0,getWidth(),getHeight());
g.setColor(Color.MAGENTA);
g.fillOval(300,y+435,50,50);
g.dispose();
bs.show();
}
public static void main(String[] args) {
Game game = new Game();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setResizable(false);
game.frame.setVisible(true);
game.frame.add(game);
game.frame.pack();
game.frame.setTitle("Bouncy Ball");
game.start();
}
}
This is my keylisener class
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Keyboard implements KeyListener{
private boolean[] keys = new boolean[120];
public boolean up, down, left, right;
public void update(){
up = keys[KeyEvent.VK_UP];
down = keys[KeyEvent.VK_DOWN];
left = keys[KeyEvent.VK_LEFT];
right = keys[KeyEvent.VK_RIGHT];
}
#Override
public void keyPressed(KeyEvent e) {
keys[e.getKeyCode()] = true;
}
#Override
public void keyReleased(KeyEvent e) {
keys[e.getKeyCode()] = false;
}
#Override
public void keyTyped(KeyEvent e) {
}
}
Your issue is in the key.update() method. key.up will only be true while you're holding the up key, not just if you press the up key once. If, for now, you only care about a single button press, change it to:
public void update() {
if (keys[KeyEvent.VK_UP]) {
up = true;
}
}
Which will only update once, once you press up, and keys.up will stay true.
Also, y is decreasing, not increasing (you're subtracting 5 from it), so you want to change
== 400 to == 400, or even better, <= 400, in case you don't increment with whole numbers (as per the other answer).
As a general debugging idea: At that if statement, I printed out the value of y, and noticed it only printed out 3 or 4 values (corresponding to how long I was holding it down), which meant that the if statement wasn't being checked, or wasn't returning true (which was the case here).
Instead of:
if(key.up){
yy = -5;
if(y == 400){
yy = 0;}
}
try:
if(key.up){
yy = -5;
if(y >= 400){
yy = 0;}
}
If your ball is moving at 5px per update then it may pass 400px without actually
equaling 400px, this is why you check if it is greater than 400px.
So I am trying to make a game like Snake, but I am running into some issues.
I want to repeat the if statement inside of of the moveup class using a while loop, but
when I try to use the KeyListener to listen for the key press of the up arrow key to break the while loop it acts like it only looped once (moved up 5 pixels). The loop is supposed to make the snake continue going up without having to click multiple times, but it just moves five (the value I set it to do) pixels. Here is the code:
public class Snake extends JFrame implements KeyListener {
int ballX = 50;
int ballY = 50;
int playerX = 250;
int playerY = 250;
boolean up = false;
boolean right = false;
boolean down = false;
boolean left = true;
class DrawPane extends JPanel {
public void paintComponent(Graphics gc) {
Random rand = new Random();
int dotsX = rand.nextInt(500) + 1;
int dotsY = rand.nextInt(500) + 1;
Graphics g = this.getGraphics();
setVisible(true);
super.paintComponents(gc);
gc.setColor(Color.BLUE);
gc.fillRect(ballX, ballY, 10, 10);
gc.setColor(Color.RED);
gc.fillRect(playerX, playerY, 10, 10);
}
}
public Snake(String title) {
super(title);
JFrame frame = new JFrame();
setContentPane(new DrawPane());
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setSize(500, 500);
this.setBackground(Color.YELLOW);
this.setResizable(false);
this.addKeyListener(this);
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
if (e.getKeyCode() == KeyEvent.VK_UP) {
up = true;
right = false;
down = false;
left = false;
moveup(e);
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
up = false;
right = false;
down = true;
left = false;
movedown(e);
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
up = false;
right = true;
down = false;
left = false;
moveright(e);
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
up = false;
right = false;
down = false;
left = true;
moveleft(e);
}
}
public void moveup(KeyEvent e) {
while (up) {
if (playerX < 500 || playerX > 0) {
playerX = playerX + 5;
repaint();
if (e.getKeyChar() == KeyEvent.VK_UP)
break;
}
}
}
public void moveright(KeyEvent e) {
if (playerX < 500 || playerX > 0) {
playerX = playerX + 5;
repaint();
// moveright();
}
}
public void movedown(KeyEvent e) {
if (playerY < 500 || playerY > 0) {
playerY = playerY + 5;
repaint();
// movedown();
}
}
public void moveleft(KeyEvent e) {
if (playerX < 500 || playerX > 0) {
playerX = playerX - 5;
repaint();
// moveleft();
}
}
public void snakePanel() {
JPanel panel1 = new JPanel();
panel1.setBackground(Color.red);
}
public void ActionListener() {
}
public static void main(String[] args) {
Snake r = new Snake("Snake");
}
}
It never loops because of the break. Effectively you're saying:
if keycode is up
loop
move up
break if keycode is up // Will always be true
More so, you shouldn't be looping in an event handler like that. Event handlers should execute and return quickly else you'll block the event thread. Should be using a timer to act as a heartbeat and update the position/repaint periodically.
Keep in mind that you DON'T want to use Swing for more advanced games in the future.
--- Quick solution:
Just remove your while(). The KeyListener interface lets you abstract the concept of "while this key is pressed, do this". Instead, when you implement the interface, you say: "whenever this key is pressed, do this". It's an event.
Here's your working code:
http://pastebin.com/b0CZDxpD