The first thing we will do in this tutorial is get our ball data into it's own class (unlike the previous article).
public class Ball {
private int px;
private int py;
private int speed;
private int width;
public Ball(int px, int py, int speed) {
this.px = px;
this.py = py;
this.speed = speed;
this.width = 50;
}
public int getPx(){
return this.px;
}
public int getPy(){
return this.py;
}
public void moveUp(){
if((py-speed) > 0){
py-=speed;
}
else if(py > 0){
py-=py;
}
}
public void moveDown(){
if((py+width+speed) < 250){
py+=speed;
}
else if((py+width) < 250){
py+=(250-(py+width));
}
}
public void moveLeft(){
if((px-speed) > 0){
px-=speed;
}
else if(px > 0){
px-=(px);
}
}
public void moveRight(){
if((px+width+speed) < 250){
px+=speed;
}
else if((px+width) < 250){
px+=(250-(px+width));
}
}
}
The ball's x and y position, as well as it's speed, are initialized in the class constructor. We have 2 methods that return the value of the x and y position, and 4 methods that are in charge of moving the ball while making sure it stays onscreen.
MoveBall.java
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class MoveBall extends Applet{
public static final int WIDTH = 250;
public static final int HEIGHT = 250;
Graphics backBuffer;
Image frontBuffer;
Image background;
Image ball;
Ball myBall = new Ball(50,50,5);
Dimension appletSize;
boolean leftKey = false;
boolean rightKey = false;
boolean upKey = false;
boolean downKey = false;
public void init(){
this.setSize(WIDTH, HEIGHT);
appletSize = getSize();
addKeyListener(new MyKeyListener());
frontBuffer = createImage(appletSize.width,appletSize.height);
backBuffer = frontBuffer.getGraphics();
background = getImage(getDocumentBase(), "wood.png");
ball = getImage(getDocumentBase(),"ball.png");
Thread t = new Thread(new MainLoop());
t.start();
}
private class MyKeyListener extends KeyAdapter{
public void keyPressed(KeyEvent e){
switch (e.getKeyCode()){
case KeyEvent.VK_LEFT:
leftKey = true;
break;
case KeyEvent.VK_RIGHT:
rightKey = true;
break;
case KeyEvent.VK_UP:
upKey = true;
break;
case KeyEvent.VK_DOWN:
downKey = true;
break;
}
}
public void keyReleased(KeyEvent e){
switch (e.getKeyCode()){
case KeyEvent.VK_LEFT:
leftKey = false;
break;
case KeyEvent.VK_RIGHT:
rightKey = false;
break;
case KeyEvent.VK_UP:
upKey = false;
break;
case KeyEvent.VK_DOWN:
downKey = false;
break;
}
}
}
public class MainLoop implements Runnable{
public MainLoop(){
}
public void run(){
while(true){
if(upKey){ myBall.moveUp(); }
if(downKey){ myBall.moveDown(); }
if(leftKey){ myBall.moveLeft(); }
if(rightKey){ myBall.moveRight(); }
repaint();
try {
Thread.sleep(20);
}
catch (InterruptedException ex){
}
}
}
}
public void drawScreen(Graphics display){
backBuffer.drawImage(background,0,0,null);
backBuffer.drawImage(ball, myBall.getPx(), myBall.getPy(), null);
backBuffer.drawString("CLICK ON SCREEN TO GAIN FOCUS THEN...",0,230);
backBuffer.drawString("press arrow keys to move ball",0,245);
display.drawImage(frontBuffer,0,0,this);
}
public void update(Graphics display){
drawScreen(display);
}
}
Notice the Keylistener. When one of the arrow keys is pressed a corresponding boolean is set to true, when the key is released, the boolean is set to false. The main loop of our program is constantly checking to see if these booleans are active. If they are, then an appropriate call to the ball class's movement methods is made. You may be wondering why we don't just call the ball's movement methods inside of the KeyListener methods and eliminate the boolean middle man. We could do that, but the ball's movement would lag for about 2 seconds before it started moving smoothly. The same thing happens when a character key is pressed and held in a word processor. The character prints to the screen, there is a 2 second lag, and then the character prints to the screen rapidly, multiple times. By using booleans we can make sure that the movement is instantaneous and in sync with the frame rate.





