[vc_row css_animation=”” row_type=”row” use_row_as_full_screen_section=”no” type=”full_width” angled_section=”no” text_align=”left” background_image_as_pattern=”without_pattern”][vc_column][vc_column_text]
[/vc_column_text][vc_separator type=”normal” up=”1″][vc_column_text css=”.vc_custom_1582221975753{background-color: #f6f6f6 !important;}”]
Now let’s put together our own game in Java! With object-oriented programming, we can easily create multiple classes with their own purpose that interact with each other.
[/vc_column_text][vc_empty_space height=”20px”][vc_column_text]In our game we will have a number of classes that interact with each other
It is recommended to read the chapter on Classes and Objects before you begin, to more easily understand how the different classes and objects interact with each other.[/vc_column_text][vc_empty_space height=”50px”][vc_column_text]
[/vc_column_text][vc_empty_space height=”20px”][vc_column_text]
[/vc_column_text][vc_empty_space height=”20px”][vc_separator type=”normal”][vc_empty_space height=”10px”][vc_column_text]
In the first class called GameObject, the x- and y-coordinates for each object are handled. Since all objects in the game need coordinates (so that you can place them in the desired place on the game screen), any class that requires coordinates will be able to inherit from this class.
public class GameObject {
public int x, y;
// The constructor declares the class variables
public GameObject(int x, int y) {
this.x = x;
this.y = y;
}
// Return the respective coordinate
public int getX() {
return x;
}
public int getY() {
return y;
}
// Set a new value to x and y
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public Rectangle getBounds(int x, int y){
return new Rectangle(x, y, 64, 64);
}
}
Let’s have a closer look on the last part of the code, line 28 and 29.
public Rectangle getBounds(int x, int y){
return new Rectangle(x, y, 64, 64);
}
This method returns the area that the object covers on the playing field, so that you can determine if two objects collide with each other or not.[/vc_column_text][vc_empty_space height=”20px”][vc_column_text]
[/vc_column_text][vc_empty_space height=”10px”][vc_separator type=”normal”][vc_empty_space height=”10px”][vc_column_text]
We then create an interface according to:
public interface Entity {
public void tick();
public void render(Graphics g);
}
Every class created with this interface should have two methods:
[/vc_column_text][vc_empty_space height=”20px”][vc_separator type=”normal”][vc_empty_space height=”10px”][vc_column_text]
The class named, BufferedImageLoader , creates an image-object from the images we want in the game:
public class BufferedImageLoader {
private BufferedImage image;
public BufferedImage loadImage(String path) throws IOException{
image = ImageIO.read(getClass().getResource(path));
return image;
}
}
Note: If there is no file present with the same name as the name sent into the constructor, an error message is thrown (IOException) and the program will then stop executing. (Remember Try Catch ? )[/vc_column_text][vc_empty_space height=”20px”][vc_column_text]
[/vc_column_text][vc_empty_space height=”10px”][vc_separator type=”normal”][vc_empty_space height=”10px”][vc_column_text]
The Classed called Player is the player that is to control the game with the arrow keys.
public class Player extends GameObject implements Entity {
private BufferedImage hero;
private double velX = 0;
private double velY = 0;
public Player(int x, int y) {
super(x, y);
BufferedImageLoader loader = new BufferedImageLoader();
try{
hero = loader.loadImage("/hero.png");
}
catch (IOException e){
e.printStackTrace();
}
}
@Override
public void tick() {
x+=velX;
y+=velY;
if(x <=0){
x=0;
}
if(x >=Game.WIDTH-64){
x=640-64;
}
if(y <=0){
y=0;
}
if(y >=Game.HEIGHT-64){
y=Game.HEIGHT-64;
}
}
@Override
public void render(Graphics g) {
g.drawImage(hero, x, y, null);
}
@Override
public Rectangle getBounds() {
return new Rectangle((int)x, (int)y, 64, 64);
}
public void setVelX(double velX){
this.velX = velX;
}
public void setVelY(double velY){
this.velY = velY;
}
}
[/vc_column_text][vc_empty_space height=”20px”][vc_column_text]
[/vc_column_text][vc_empty_space height=”10px”][vc_separator type=”normal”][vc_empty_space height=”10px”][vc_column_text]
The Wall Class handles the falling wall that the player should avoid. Like the Player class, this class inherits from GameObject and Entity. This class is handled even if there is a collision between the player and the wall. There will be a wall object (a box) printed a total of eight times on the playing field (two holes in the wall).
public class Wall extends GameObject implements Entity {
private BufferedImage wall;
private double velY = 1;
Random random;
int rand;
public Wall(int x, int y) {
super(x, y);
BufferedImageLoader loader = new BufferedImageLoader();
try{
wall = loader.loadImage("/wall.png");
}
catch (IOException e){
e.printStackTrace();
}
random = new Random();
rand = random.nextInt(10);
}
@Override
public void tick() {
y = y+(int)velY;
if(y>=Game.HEIGHT){
y=0;
rand = random.nextInt(10);
setVelY(velY+0.5);
Counter.count++;
}
}
@Override
public void render(Graphics g) {
for(int i = 0; i < Game.FACTOR; i++ ) {
if(i != rand && i != rand+1) {
g.drawImage(wall, x + 64 * i, y, null);
}
}
}
public void setVelY(double velY){
this.velY = velY;
}
/*
We create an ArrayList that we fill with rectangles. Each rectangle is a "part of the wall" (total 10 pieces - 2 holes) By creating margins we can easily see if a wall collides with the player = Game Over, using the built-in function "intersect" that investigates whether two rectangles intersect.
*/
private ArrayList<Rectangle> getRectangleWall(){
ArrayList<Rectangle> rectangles = new ArrayList<Rectangle>();
for(int i = 0; i < Game.FACTOR; i++ ) {
if(i != rand && i != rand+1) {
rectangles.add(getBounds(64*i, y));
}
}
return rectangles;
}
public boolean collision(Rectangle rectanglePlayer){
for(Rectangle rec : getRectangleWall()) {
if (rectanglePlayer.intersects(rec)) {
return true;
}
}
return false;
}
}
[/vc_column_text][vc_empty_space height=”20px”][vc_column_text]
[/vc_column_text][vc_empty_space height=”10px”][vc_separator type=”normal”][vc_empty_space height=”10px”][vc_column_text]
The Counter class keeps track of the number of turns/levels the player have passed
public class Counter {
// Creates a new font with a counter that all classes can access
Font fnt0 = new Font("Comics", Font.BOLD, 20);
public static int count = 0;
// Draws the value of count
public void render(Graphics g) {
g.setFont(fnt0);
g.setColor(Color.BLACK);
//Draw count on position (x=10, y=30)
g.drawString(Integer.toString(count), 10, 30);
}
//If methods reset is used --> reset counter
public void reset(){
this.count = 0;
}
}
[/vc_column_text][vc_empty_space height=”20px”][vc_separator type=”normal”][vc_empty_space height=”10px”][vc_column_text]
Furthermore, one of the last parts of our game is to create the Start Menu. The class Starter simply prints “press enter to start” to start the game. You could of course add more features to this menu, for example, leaderboard or playtime. But for now, let’s just focus on getting the Start menu in place and then we will leave the extra features to you to explore and try. This, of course, implies for all of the features of the game.
public class Starter {
Font fnt0 = new Font("Comics", Font.BOLD, 25);
public void render(Graphics g) {
g.setFont(fnt0);
g.setColor(Color.BLACK);
g.drawString("Press Enter to start", 205, 220);
}
}
[/vc_column_text][vc_empty_space height=”20px”][vc_column_text]
[/vc_column_text][vc_empty_space height=”30px”][vc_column_text]Finally, if you want to download the game and try it for yourself – Download the game[/vc_column_text][vc_empty_space height=”60px”][/vc_column][/vc_row][vc_row css_animation=”” row_type=”row” use_row_as_full_screen_section=”no” type=”full_width” angled_section=”no” text_align=”left” background_image_as_pattern=”without_pattern”][vc_column][vc_column_text]
[/vc_column_text][vc_empty_space][/vc_column][/vc_row]