To do so, we will be creating a new class. Within this class, we will do the following:
1. Manage x, y coordinates and speed.
2. Make updates to speed and position.
3. Allow other classes to retrieve its x, y related variables.
Therefore, the methods of this class will be divided into these categories:
1. Constantly updated methods that are called on each iteration of the game loop.
2. Methods that are only called upon player input.
3. Helper methods that retrieve and change the value of variables in the class.
Let's get started.
We begin by creating a new class called Robot.java in the kiloboltgame package (or whatever you named your package).
Copy and paste the following:
Figure 2-13: Robot.java
import java.awt.Graphics;
public class Robot {
//In Java, Class Variables should be private so that only its methods can change them.
private int centerX = 100;
private int centerY = 382;
private boolean jumped = false;
private int speedX = 0;
private int speedY = 1;
public void update() {
// Moves Character or Scrolls Background accordingly.
if (speedX < 0) {
centerX += speedX;
} else if (speedX == 0) {
System.out.println("Do not scroll the background.");
} else {
if (centerX <= 150) {
centerX += speedX;
} else {
System.out.println("Scroll Background Here");
}
}
// Updates Y Position
if (centerY + speedY >= 382) {
centerY = 382;
}else{
centerY += speedY;
}
// Handles Jumping
if (jumped == true) {
speedY += 1;
if (centerY + speedY >= 382) {
centerY = 382;
speedY = 0;
jumped = false;
}
}
// Prevents going beyond X coordinate of 0
if (centerX + speedX <= 60) {
centerX = 61;
}
}
public void moveRight() {
speedX = 6;
}
public void moveLeft() {
speedX = -6;
}
public void stop() {
speedX = 0;
}
public void jump() {
if (jumped == false) {
speedY = -15;
jumped = true;
}
}
}
What do those variables mean?
1. centerX, centerY are the x, y coordinates of our robot character's center.
2. speedX, speed Y are the rate at which these x and y positions change.
3. jumped changes to true if the character is in the air, and reverts to false when grounded.
Now let's talk about each of the methods above.
1. Always called methods:
update() : this method will be called on each iteration of the for loop. This is a very important method, so let's spend time taking about it. But before we do that, PLEASE look through it one more time and try to make sense of the if statements.
*When examining the update() method again, Keep the following in mind.
1. Speed can be negative, which means that a character with negative speedX would move to the left.
2. The Origin (0,0) pixel is at the TOP LEFT. I will talk about this below. This means that if a character has a positive speedY, he is FALLING, not RISING.
x += 1;
is equivalent to:
x = x + 1;
4. We are arbitrarily defining the ground at about 440 pixels. That means if the character's centerY is at about 382, his feet would reach the ground at ~440 pixels.
5. If the character's centerX is lesser than 60, his left hand will be outside the left edge of the screen.
Now have a look at a diagram:
Examine this update() method once more before moving on!
// Moves Character or Scrolls Background accordingly.
if (speedX < 0) {
centerX += speedX; //This changes centerX by adding speedX.
} else if (speedX == 0) {
System.out.println("Do not scroll the background.");
} else {
if (centerX <= 150) { //If the character's centerX is in the left 150 pixels
centerX += speedX; //Change centerX by adding speedX.
} else {
System.out.println("Scroll Background Here"); /
}
}
// Updates Y Position
if (centerY + speedY >= 382) {
//382 is where the character's centerY would be if he were standing on the ground.
centerY = 382;
}else{
centerY += speedY; //Add speedY to centerY to determine its new position
}
// Handles Jumping
if (jumped == true) {
speedY += 1; //While the character is in the air, add 1 to his speedY.
//NOTE: This will bring the character downwards!
if (centerY + speedY >= 382) {
centerY = 382;
speedY = 0;
jumped = false;
}
}
// Prevents going beyond X coordinate of 0
if (centerX + speedX <= 60) { //If speedX plus centerX would bring the character //outside the screen,
centerX = 61;
//Fix the character's centerX at 60 pixels.
}
}
Dissecting the update() method:
// Moves Character or Scrolls Background accordingly.
1. Our first if statement:
For our game to draw the character in the proper location, centerX must constantly be updated; however, if the character is not moving (speedX == 0), then there is no need to update centerX by adding speed to it.
2. Watch a few seconds of this video:
Now, let's discuss the sections labeled:
//Updates Y Position and //Handles Jumping.
Since gravity is always present, the character is constantly being pushed to the ground. We assume that the ground is located at about 440 pixels down from the top, and if the character's Y position plus his Y speed will bring him below the ground, we use the statement: centerY = 382; to manually set the character at a height that will stop him from moving.
The Handles jumping section will check the current speed and position to test whether the character is in mid-jump or on the ground.
Finally, let's discuss the section labeled:// Prevents going beyond X coordinate of 0
This section just checks if the character is moving beyond the left edge of the screen and fixes his centerX coordinate at 61 if he tries to move off the screen.
Now that we have discussed the update() method, we will move on to the other methods:
2. Methods called upon input:
moveRight(), which sets the character's horizontal speed (speedX) as 6.
moveLeft(), which sets the character's speedX as -6.
stop(), which sets the speedX as zero.
jump(), which sets the vertical speed as -15.
3. Helper Methods
We will be adding these later in today's lesson.
Pixels are the tiny squares on your display. They are the smallest unit of change in your display, and are either on or off and have a single color.
Screen resolution is a representation of your horizontal and vertical pixel counts. For example, a resolution of 1920 by 1080 tells you that a display has 1920 horizontal pixels and 1080 vertical pixels.
Individual pixel coordinates are given in (x,y); however, by convention and technological limitations, we choose the top left corner as (0,0). On a screen with resolution 1920 x 1080, then, the bottom right pixel has coordinates (1919, 1079) NOT (1920, 1080). This is because we begin counting from zero, not one.
I will now apply this to describe how we create an illusion of motion in games.
Within the StartingClass's paint method, we will write a statement that will look something like this:
drawRobot(centerX, centerY). This will draw the Robot at the coordinate (centerX, centerY).
With each iteration of the paint method, which is called roughly 60 times per second, the Robot will appear to move as its centerX and centerY values change. To change the centerX and centerY, we use the speedX and speedY variables, which represent the rate at which centerX and centerY will change with each update of the game (60 times per second).
So when I say that moveRight() sets the character's horizontal speed as 6, I am saying that each time that moveRight() is called, the character's speed will be given a value of 6 pixels. In the case of the robot, the update() method, will add this speed of 6 to the centerX value. Changing the centerX value will mean that the drawRobot(centerX, centerY) statement above will now "move" the robot to a new location with its new centerX. If this happens on a speed that is fast enough, we get the illusion of smooth motion.
Locate:
public class StartingClass extends Applet implements Runnable, KeyListener {
and below it, declare:
private Robot robot;
to create a private Robot object called robot.
Now, let us initialize this value by writing:
robot = new Robot(); in the start() method.
Now that we have created an instance of the Robot class, we can take Robot's methods and call them by writing:
robot.methodName(); (methodName() is just a generic name for any method in the Robot class).
We will be working in the StartingClass.java
1. First make sure that you have imported : java.awt.Graphics;
2. Then we will begin by going below the run method (it does not matter where, but I like grouping related methods together) and create the following methods: update(Graphics g) and paint(Graphics g). It is easy to do create these methods by typing update and then pressing Ctrl+Space, and choosing the first option. Do the same thing with paint.
The update() method is implicitly called automatically, and will loop over and over again. The paint() will similarly be always called, with the repaint() statement within the run() method.
I. Defining the update() Method:
Let's first deal with the update() method. We will use this method for double buffering - a technique that is used to prevent tearing and flickering. Feel free to read up more on this subject, as I am not an expert in this topic. The basic concept is that it works by retaining the previous position of the screen's current image for a short amount of time, so that the movement of the image looks smooth and natural.
1. Begin by declaring (below private Robot robot):
private Image image;
private Graphics second;
As class variables (accessible by all methods within the StartingClass).
2. If you receive an error on either Graphics or Images, press Ctrl+Shift+O to auto-import them.
3. Now go down the the update() method and add the following:
Figure 2-14: update() method within StartingClass.java
public void update(Graphics g) {
if (image == null) {
image = createImage(this.getWidth(), this.getHeight());
second = image.getGraphics();
}
second.setColor(getBackground());
second.fillRect(0, 0, getWidth(), getHeight());
second.setColor(getForeground());
paint(second);
g.drawImage(image, 0, 0, this);
}
II. Defining the paint() Method:
The paint() method will be used to draw our graphics to the screen. For now, we only need to draw the robot, so it will have one statement inside:
Figure 2-15: paint() method within StartingClass.java
public void paint(Graphics g) {
g.drawImage(character, robot.getCenterX() - 61, robot.getCenterY() - 63, this);
}
g.drawImage(img, x, y, observer)
An Image variable, the x and y coordinates where you want to draw the Image, and an ImageObserver (which is slightly beyond the scope of this lesson).
In our example, we will use the character variable to represent our robot image, and then draw the top left corner of the robot 61 pixels to the left, and 63 pixels above the (centerX, centerY), and then use the "this" keyword as our ImageObserver.
At this point, you will have a lot of errors. We will address them each one at a time.
I. Addressing the character variable error
Find the statement: private Image image;
and add , character like so:
private Image image, character;
2. Now we must assign a value to it. We will assign an image to the variable character. To do so, we must create a URL object that will allow us to use addresses (such as C:\Images\image.jpg) to refer to images.
So, below private Image image, character; add:
private URL base;
(As mentioned before, private variables are only accessible from within the class - it is common practice to create class-wide variables as private).
Remember to import URL.
3. Within the init() method, we will define the URL base and the assign value to character.
Make these changes:
Figure 2-16: init() method within StartingClass.java
public void init() {
setSize(800, 480);
setBackground(Color.BLACK);
setFocusable(true);
addKeyListener(this);
Frame frame = (Frame) this.getParent().getParent();
frame.setTitle("Q-Bot Alpha");
try {
base = getDocumentBase();
} catch (Exception e) {
// TODO: handle exception
}
// Image Setups
character = getImage(base, "data/character.png");
}
Inside it, download, drag, and drop this image:

character.png |
(If you have errors, try Rebuilding by doing the following: On the toolbar above, click on Project > Clean > OK).
Figure 2-17: StartingClass.java, After Fixing character Errors
import java.applet.Applet;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.net.URL;
public class StartingClass extends Applet implements Runnable, KeyListener {
private Image image, character;
private Graphics second;
private URL base;
@Override
public void init() {
setSize(800, 480);
setBackground(Color.BLACK);
setFocusable(true);
addKeyListener(this);
Frame frame = (Frame) this.getParent().getParent();
frame.setTitle("Q-Bot Alpha");
try {
base = getDocumentBase();
} catch (Exception e) {
// TODO: handle exception
}
// Image Setups
character = getImage(base, "data/character.png");
}
@Override
public void start() {
robot = new Robot();
Thread thread = new Thread(this);
thread.start();
}
@Override
public void stop() {
// TODO Auto-generated method stub
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void run() {
while (true) {
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void update(Graphics g) {
if (image == null) {
image = createImage(this.getWidth(), this.getHeight());
second = image.getGraphics();
}
second.setColor(getBackground());
second.fillRect(0, 0, getWidth(), getHeight());
second.setColor(getForeground());
paint(second);
g.drawImage(image, 0, 0, this);
}
@Override
public void paint(Graphics g) {
g.drawImage(character, robot.getCenterX() - 61, robot.getCenterY() - 63, this);
}
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
System.out.println("Move up");
break;
case KeyEvent.VK_DOWN:
System.out.println("Move down");
break;
case KeyEvent.VK_LEFT:
System.out.println("Move left");
break;
case KeyEvent.VK_RIGHT:
System.out.println("Move right");
break;
case KeyEvent.VK_SPACE:
System.out.println("Jump");
break;
}
}
@Override
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
System.out.println("Stop moving up");
break;
case KeyEvent.VK_DOWN:
System.out.println("Stop moving down");
break;
case KeyEvent.VK_LEFT:
System.out.println("Stop moving left");
break;
case KeyEvent.VK_RIGHT:
System.out.println("Stop moving right");
break;
case KeyEvent.VK_SPACE:
System.out.println("Stop jumping");
break;
}
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
II. Addressing the get... errors
1. Constantly updated methods that are called on each iteration of the game loop.
2. Methods that are only called upon player input.
3. Helper methods that retrieve and change the value of variables in the class.
We never did create the helper methods. So here we do that.
1. Open Robot.java again.
2. Right click anywhere on the white space, click Source >> and select Generate Getters and Setters.
What are getters and setters?
Again, in Java, it is common practice to set class-wide variables as private. For other classes to access these private variables, they must use helper functions known as getters and setters.
Let's have a look at a pair:
public int getSpeedX() {
return speedX;
}
and
public void setSpeedX(int speedX) {
this.height = speedX;
}
Whenever a getter method is called, it returns the value that you "get." When I say:
myNewVariable = getSpeedX(), my new variable will get the value of speedX.
If I say: setSpeed(10); then my speedX will now have a value of 10.
With these three things finished, the result is:
Figure 2-18: StartingClass.java After Fixing the get... Errors
import java.applet.Applet;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.net.URL;
public class StartingClass extends Applet implements Runnable, KeyListener {
private Robot robot;
private Image image, character;
private Graphics second;
private URL base;
@Override
public void init() {
setSize(800, 480);
setBackground(Color.BLACK);
setFocusable(true);
addKeyListener(this);
Frame frame = (Frame) this.getParent().getParent();
frame.setTitle("Q-Bot Alpha");
try {
base = getDocumentBase();
} catch (Exception e) {
// TODO: handle exception
}
// Image Setups
character = getImage(base, "data/character.png");
}
@Override
public void start() {
robot = new Robot();
Thread thread = new Thread(this);
thread.start();
}
@Override
public void stop() {
// TODO Auto-generated method stub
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void run() {
while (true) {
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void update(Graphics g) {
if (image == null) {
image = createImage(this.getWidth(), this.getHeight());
second = image.getGraphics();
}
second.setColor(getBackground());
second.fillRect(0, 0, getWidth(), getHeight());
second.setColor(getForeground());
paint(second);
g.drawImage(image, 0, 0, this);
}
@Override
public void paint(Graphics g) {
g.drawImage(character, robot.getCenterX() - 61, robot.getCenterY() - 63, this);
}
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
System.out.println("Move up");
break;
case KeyEvent.VK_DOWN:
System.out.println("Move down");
break;
case KeyEvent.VK_LEFT:
System.out.println("Move left");
break;
case KeyEvent.VK_RIGHT:
System.out.println("Move right");
break;
case KeyEvent.VK_SPACE:
System.out.println("Jump");
break;
}
}
@Override
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
System.out.println("Stop moving up");
break;
case KeyEvent.VK_DOWN:
System.out.println("Stop moving down");
break;
case KeyEvent.VK_LEFT:
System.out.println("Stop moving left");
break;
case KeyEvent.VK_RIGHT:
System.out.println("Stop moving right");
break;
case KeyEvent.VK_SPACE:
System.out.println("Stop jumping");
break;
}
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
First: In StartingClass go down to the keyPressed() method, and replace:
1. System.out.println("Move left"); with robot.moveLeft();
2. System.out.println("Move right"); with robot.moveRight();
3. System.out.println("Jump"); with robot.jump();
And in the keyReleased() method, replace:
1. System.out.println("Stop moving left");
and
2. System.out.println("Stop moving right");
with
robot.stop();
Second: Within the run() method, we need to call robot.update();
Figure 2-19: run() method within StartingClass.java
public void run() {
while (true) {
robot.update();
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Figure 2-20: StartingClass.java, End of Day 4
import java.applet.Applet;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.net.URL;
public class StartingClass extends Applet implements Runnable, KeyListener {
private Robot robot;
private Image image, character;
private Graphics second;
private URL base;
@Override
public void init() {
setSize(800, 480);
setBackground(Color.BLACK);
setFocusable(true);
addKeyListener(this);
Frame frame = (Frame) this.getParent().getParent();
frame.setTitle("Q-Bot Alpha");
try {
base = getDocumentBase();
} catch (Exception e) {
// TODO: handle exception
}
// Image Setups
character = getImage(base, "data/character.png");
}
@Override
public void start() {
robot = new Robot();
Thread thread = new Thread(this);
thread.start();
}
@Override
public void stop() {
// TODO Auto-generated method stub
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void run() {
while (true) {
robot.update();
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void update(Graphics g) {
if (image == null) {
image = createImage(this.getWidth(), this.getHeight());
second = image.getGraphics();
}
second.setColor(getBackground());
second.fillRect(0, 0, getWidth(), getHeight());
second.setColor(getForeground());
paint(second);
g.drawImage(image, 0, 0, this);
}
@Override
public void paint(Graphics g) {
g.drawImage(character, robot.getCenterX() - 61, robot.getCenterY() - 63, this);
}
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
System.out.println("Move up");
break;
case KeyEvent.VK_DOWN:
System.out.println("Move down");
break;
case KeyEvent.VK_LEFT:
robot.moveLeft();
break;
case KeyEvent.VK_RIGHT:
robot.moveRight();
break;
case KeyEvent.VK_SPACE:
robot.jump();
break;
}
}
@Override
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
System.out.println("Stop moving up");
break;
case KeyEvent.VK_DOWN:
System.out.println("Stop moving down");
break;
case KeyEvent.VK_LEFT:
robot.stop();
break;
case KeyEvent.VK_RIGHT:
robot.stop();
break;
case KeyEvent.VK_SPACE:
System.out.println("Stop jumping");
break;
}
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
Figure 2-21: Robot.java, End of Day 4
import java.awt.Graphics;
public class Robot {
private int centerX = 100;
private int centerY = 382;
private boolean jumped = false;
private int speedX = 0;
private int speedY = 1;
public void update() {
// Moves Character or Scrolls Background accordingly.
if (speedX < 0) {
centerX += speedX;
} else if (speedX == 0) {
System.out.println("Do not scroll the background.");
} else {
if (centerX <= 150) {
centerX += speedX;
} else {
System.out.println("Scroll Background Here");
}
}
// Updates Y Position
if (centerY + speedY >= 382) {
centerY = 382;
}else{
centerY += speedY;
}
// Handles Jumping
if (jumped == true) {
speedY += 1;
if (centerY + speedY >= 382) {
centerY = 382;
speedY = 0;
jumped = false;
}
}
// Prevents going beyond X coordinate of 0
if (centerX + speedX <= 60) {
centerX = 61;
}
}
public void moveRight() {
speedX = 6;
}
public void moveLeft() {
speedX = -6;
}
public void stop() {
speedX = 0;
}
public void jump() {
if (jumped == false) {
speedY = -15;
jumped = true;
}
}
public int getCenterX() {
return centerX;
}
public int getCenterY() {
return centerY;
}
public boolean isJumped() {
return jumped;
}
public int getSpeedX() {
return speedX;
}
public int getSpeedY() {
return speedY;
}
public void setCenterX(int centerX) {
this.centerX = centerX;
}
public void setCenterY(int centerY) {
this.centerY = centerY;
}
public void setJumped(boolean jumped) {
this.jumped = jumped;
}
public void setSpeedX(int speedX) {
this.speedX = speedX;
}
public void setSpeedY(int speedY) {
this.speedY = speedY;
}
}
If your code is not working for any reason, try Rebuilding by doing the following:
On the toolbar above, click on Project > Clean > OK.
As a general rule, if your code does not work and you cannot find any errors, your first step should be to rebuild the project!
Thanks for reading and please support us if you are learning! Every dollar helps us out tremendously!

kiloboltgame4.zip |
