Lesson #2-9: Creating the Main Character
Welcome to the fourth day! Now that we got the basic frameworks set up, we will be adding our main character.
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:
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
package kiloboltgame;
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;
}
}
}
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?
A brief description of the variables (there will be more a in depth discussion further down):
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.
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.
3. Recall the meaning of += :
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:
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!
public void update() {
// 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.
}
}
// 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:
First, let's discuss the section labeled:
// 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:
// 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:
In Metal Slug, the character freely moves in the left half of the screen, but once he starts moving to the right, the character stays at the same location while the background scrolls. This is what we are doing here. If speed is zero, then we will not scroll the background. If the character's centerX coordinate is less than 150, he can move freely. Else, we will scroll the background and stop moving the character.
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, 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.
Lesson #2-10: Graphics 101
To make sense of those speed values, we need to talk about some basic graphical stuff.
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.
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.
Creating a Robot named robot.
With the Robot class created, we can now create a Robot object inside StartingClass.
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).
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).
Lesson #2-11: Drawing the Main Character from StartingClass.java
There's lots of code to cover here, and I will try to keep the explanations as simple as possible; however, some of the concepts here are a bit elusive and you might wonder how you would come up with such a solution when programming by yourself in the future. This is one of those cases where you are not required to memorize or fully understand how something works, because it is so easy to implement and difficult to fully understand.
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:
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
@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);
}
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);
}
The individual statements of this segment of code is easy to understand. What is difficult is discerning how each of these pieces fit together as a whole to create a double buffering system. Feel free to look at this in detail, but my advice to you: ignore it, accept it, and move on. :)
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:
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
@Override
public void paint(Graphics g) {
g.drawImage(character, robot.getCenterX() - 61, robot.getCenterY() - 63, this);
}
public void paint(Graphics g) {
g.drawImage(character, robot.getCenterX() - 61, robot.getCenterY() - 63, this);
}
The g.drawImage() method takes in the following parameters:
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.
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
1. The character variable is undefined, so we must first define it.
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:
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
@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");
}
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");
}
4. Finally, we must create a data folder by right clicking on src and creating a folder named data.
Inside it, download, drag, and drop this image:
Inside it, download, drag, and drop this image:

character.png |
That should solve the character errors. The StartingClass.java will look like this now:
(If you have errors, try Rebuilding by doing the following: On the toolbar above, click on Project > Clean > OK).
(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
package kiloboltgame;
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
}
}
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
We still have these errors in our StartingClass:
In my previous description of the Robot class, I mentioned that we would be creating:
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.
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.
3. Select all, sort by getters then setters, and then press OK.
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:
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
package kiloboltgame;
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
}
}
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
}
}
Lesson #2-12: Character Movement
At this point, you should be able to draw your character to the screen without any flickering:
Now we will make our final set of changes to make this character move.
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();
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
@Override
public void run() {
while (true) {
robot.update();
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run() {
while (true) {
robot.update();
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Now you should finally have the end result:
Figure 2-20: StartingClass.java, End of Day 4
package kiloboltgame;
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
}
}
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
package kiloboltgame;
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;
}
}
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;
}
}
That's it for Day 4. This was a tough lesson. Please let me know in the comments section if you need me to clarify anything at all.
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!
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 |
Instructions on importing projects can be found here.
