Programming C, C++, Java, PHP, Ruby, Turing, VB
Computer Science Canada 
Programming C, C++, Java, PHP, Ruby, Turing, VB  

Username:   Password: 
 RegisterRegister   
 [Tutorial] Using Java's libraries to create a simple game engine
Index -> Programming, Java -> Java Tutorials
View previous topic Printable versionDownload TopicRate TopicSubscribe to this topicPrivate MessagesRefresh page View next topic
Author Message
TerranceN




PostPosted: Sat Aug 21, 2010 10:06 pm   Post subject: [Tutorial] Using Java's libraries to create a simple game engine

Introduction
This tutorial was requested in the Request a Tutorial thread.

This tutorial is for people who know their way around java as a language but don't know the java libraries well enough to make a game. If you don't understand what an instance variable is, for example, you might not understand what is going on.

This tutorial will explain how to use java's libraries to make a simple game engine, it will not explain stuff that a quick look at java's documentation will explain.

This was the way I learned how to make a game in java from reading other's code and reading the java documentation, so there may be far easier ways to do this(if someone knows an easier way, I would love to know).

Starting The Game

First we need to make a window. There are a couple ways of doing this, I don't know if this is the proper or common way of doing it, its just how I've always done it. There is already a class that can handle creating a window, called the Frame (java.awt.Frame). There is also a class called JFrame (javax.swing.JFrame) that is just a frame with some extra methods that can help us, so lets use that instead. To use this class you have to create a class that inherits it, we can use this as our main class as well.

Java:

import java.awt.*;
import javax.swing.JFrame;

/**
 * Main class for the game
 */

public class GameTutorial extends JFrame
{
        public static void main(String[] args)
        {
               
        }
}


Next lets add some methods any game will need: run, initialize, update, and draw. Lets add the templates of these methods then fill them in one by one.

Java:

import java.awt.*;
import javax.swing.JFrame;

/**
 * Main class for the game
 */

public class GameTutorial extends JFrame
{       
        public static void main(String[] args)
        {
               
        }
       
        /**
         * This method starts the game and runs it in a loop
         */

        public void run()
        {
               
        }
       
        /**
         * This method will set up everything need for the game to run
         */

        void initialize()
        {
               
        }
       
        /**
         * This method will check for input, move things
         * around and check for win conditions, etc
         */

        void update()
        {
               
        }
       
        /**
         * This method will draw everything
         */

        void draw()
        {
               
        }
}


Run Method

First is the run method since it will be what starts the game. The first thing is to call the initialize method so everything will be set up, then we make the game loop.

The way a game runs is in a big loop of updating and drawing so fast it is impossible to see all the small little changes that happen. Since games don't go on forever we need a way to exit that loop, so create a boolean instance variable and call it something like isRunning. Now with that we can exit the loop from anywhere in the class. Inside that loop we obviously need to update and draw the game, so call those methods in there.

Java:

while(isRunning)
{              
        update();
        draw();
}


There is one problem with this though, we have no control over how fast the game will run. This means on different computers the game will run at different speeds. A simple way to control this is using a frame rate cap; the idea is to make each frame (each iteration of the loop) take the same amount of time. This works well for small games because this can compensate for the game running too fast, but not slow, which should not be a problem for small games. First of all create an fps instance variable so you can easily change the frames per second later. We can cap the framerate by delaying the game when it is going too fast, but we need to know how long the frame took, to know how long to delay for. Using System.currentTimeMillis we can find the difference between the time at the beginning of the frame and at the end of the frame to find how much time elapsed. Now to find the amount of time we need to delay, we just need to subtract the amount of time the frame took from the amount of time each frame should take (1000ms / fps). We end of with something like this

Java:

while(isRunning)
{
        long time = System.currentTimeMillis();
       
        update();
        draw();
       
        //  delay for each frame  -   time it took for one frame
        time = (1000 / fps) - (System.currentTimeMillis() - time);
}


Now the last thing is to delay the game. If the time we need to delay is not greater than 0 theres no need to delay, and we can delay using Thread.sleep which can throw an exception, but we don't need to worry about that exception.

Now that we're done with the game loop we should set the window to not be visible using the setVisible method. Once you are done with that your run method should look something like this

Java:

/**
 * This method starts the game and runs it in a loop
 */

public void run()
{
        initialize();
       
        while(isRunning)
        {
                long time = System.currentTimeMillis();
               
                update();
                draw();
               
                //  delay for each frame  -   time it took for one frame
                time = (1000 / fps) - (System.currentTimeMillis() - time);
               
                if (time > 0)
                {
                        try
                        {
                                Thread.sleep(time);
                        }
                        catch(Exception e){}
                }
        }
       
        setVisible(false);
}


Initialize Method

All we're going to do here (for now) is add some method calls to set up and display our window, they are all really self explanatory. windowWidth and windowHeight are just instance variables so you can easily modify the size.

Java:

/**
 * This method will set up everything need for the game to run
 */

void initialize()
{
        setTitle("Game Tutorial");
        setSize(windowWidth, windowHeight);
        setResizable(false);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
}


Main Method
The last thing is to create an instance of the game, call the run method and make sure all the threads are ended (this is because JFrame uses a separate thread). Still pretty self-explanatory

Java:

public static void main(String[] args)
{
        GameTutorial game = new GameTutorial();
        game.run();
        System.exit(0);
}


Now run it and marvel at the window that has been created! What do you mean a blank window is boring? Ok...

Drawing and Moving stuff

Lets make a simple animation to test that everything is working. Create an instance variable called x, and in the update method add x++; In the draw method we need to clear the screen and draw something using x as part of its location, to give the illusion of motion

Java:

Graphics g = getGraphics();

g.setColor(Color.WHITE);
g.fillRect(0, 0, windowWidth, windowHeight);

g.setColor(Color.BLACK);
g.drawOval(x, 10, 20, 20);


Run it.

Hooray, we got something moving in a controlled way, but when you run this you should notice two problems. First the image flickers as it move across the screen, and second, the circle appears in the title bar even though we told it to be drawn below it.

Double-Buffering
The reason this flickers is because when we clear the screen there is nothing there for a split second. To get around this we instead store all the data of what we are going to draw into memory, like creating a picture file, then we draw that picture to the screen. How is this any better? Since the drawn image will only be a slight change from what is already there, it is far less noticeable than the image dissappearing and reappearing. In order to do this we will create a BufferedImage (java.awt.image.BufferedImage) instance variable, which I will call backBuffer (the common name for this), which is just like a picture file in memory. In order to use this we need to first set it up in the initialize method

Java:

backBuffer = new BufferedImage(windowWidth, windowHeight, BufferedImage.TYPE_INT_RGB);


windowWidth, windowHeight is the size and BufferedImage.TYPE_INT_RGB is the type of image (you don't need to worry about this). Next, instead of doing all our drawing to the screen we want to do it to our buffer by getting its graphics object then drawing to it instead

Java:

Graphics g = getGraphics();

Graphics bbg = backBuffer.getGraphics();

bbg.setColor(Color.WHITE);
bbg.fillRect(0, 0, 500, 500);

bbg.setColor(Color.BLACK);
bbg.drawOval(x, 10, 20, 20);


Now that we are finished drawing on the buffer, we need to draw it to the screen like so

Java:

g.drawImage(backBuffer, 0, 0, this);


backBuffer is the image, (0, 0) is the location to draw it at, and this (because it inherits JFrame) is the ImageObserver required to draw the image.

Now there should be no more flickering (that a human can see at least).

Insets
Insets are the titlebar and frame around a window, it is because of these that our drawing is drawing in the titlebar. The problem is that when we set our window to be windowWidth by windowHeight those sizes include the insets, what we actually want is windowWidth by windowHeight of drawing space. In order to do this we need an Insets instance variable I just called insets, get the insets of the JFrame, and resize the window so it is windowWidth + left and right insets by windowHeight + top and bottom insets

Java:

insets = getInsets();
setSize(insets.left + windowWidth + insets.right,
                insets.top + windowHeight + insets.bottom);


This must be placed after the first bit of code we added to initialize. This is because setVisible determines what the insets are, otherwise they will be zero (thereby having no effect). Right now the backBuffer is still being drawn in the top left corner of the titlebar, but now that we know what the insets are, we can draw the backBuffer in the correct location

Java:

g.drawImage(backBuffer, insets.left, insets.top, this);


Now everything is drawing correctly!

Input
Input for JFrames is event based, meaning that the application waits for the user to do something, then triggers a function. Unfortunately that not how a game works, the game should run regardless of whether the user decided to input anything. Since the JFrame runs has separate thread, when getting input we can save the state of the keys then access them in the game thread like polled input (we can know which keys are up or down at any time).

For this lets make a new class and call it InputHandler. Leys get keyboard input working. For this the class needs to implement the KeyListener interface, this means it has to have the following methods: keyPressed, keyReleased and keyTyped which all have a KeyEvent as a parameter. We are also going to add our own method isKeyDown, and a constructor that takes a component, so we can assign the input handler to that component.

Java:

import java.awt.Component;
import java.awt.event.*;

/**
 * Makes handling input a lot simpler
 */

public class InputHandler implements KeyListener
{       
        /**
         * Assigns the newly created InputHandler to a Component
         * @param c Component to get input from
         */

        public InputHandler(Component c)
        {
                c.addKeyListener(this);
        }
       
        /**
         * Checks whether a specific key is down
         * @param keyCode The key to check
         * @return Whether the key is pressed or not
         */

        public boolean isKeyDown(int keyCode)
        {
               
        }
       
        /**
         * Called when a key is pressed while the component is focused
         * @param e KeyEvent sent by the component
         */

        public void keyPressed(KeyEvent e)
        {
               
        }

        /**
         * Called when a key is released while the component is focused
         * @param e KeyEvent sent by the component
         */

        public void keyReleased(KeyEvent e)
        {
               
        }

        /**
         * Not used
         */

        public void keyTyped(KeyEvent e){}
}


Since we want to be able to know whether all keys are up or down, lets make an array of 256 booleans called keys, this will store our key data. When a key is pressed we turn that key to true, and when released we turn it to false. And for isKeyDown simply return the boolean at that location in the array. Also, lets add an if statement to make sure the key is within the bounds of the array.

Java:

import java.awt.Component;
import java.awt.event.*;

/**
 * Makes handling input a lot simpler
 */

public class InputHandler implements KeyListener
{       
        /**
         * Assigns the newly created InputHandler to a Component
         * @param c Component to get input from
         */

        public InputHandler(Component c)
        {
                c.addKeyListener(this);
        }
       
        /**
         * Checks whether a specific key is down
         * @param keyCode The key to check
         * @return Whether the key is pressed or not
         */

        public boolean isKeyDown(int keyCode)
        {
                if (keyCode > 0 && keyCode < 256)
                {
                        return keys[keyCode];
                }
               
                return false;
        }
       
        /**
         * Called when a key is pressed while the component is focused
         * @param e KeyEvent sent by the component
         */

        public void keyPressed(KeyEvent e)
        {
                if (e.getKeyCode() > 0 && e.getKeyCode() < 256)
                {
                        keys[e.getKeyCode()] = true;
                }
        }

        /**
         * Called when a key is released while the component is focused
         * @param e KeyEvent sent by the component
         */

        public void keyReleased(KeyEvent e)
        {
                if (e.getKeyCode() > 0 && e.getKeyCode() < 256)
                {
                        keys[e.getKeyCode()] = false;
                }
        }

        /**
         * Not used
         */

        public void keyTyped(KeyEvent e){}
}


Now in our game class create an InputHandler instance variable, I called mine input, and instantiate it in the initialize method (with 'this' as the Component, because deep in JFrame's inheritance it is a Component). Now in the update method replace x++ with this

Java:

if (input.isKeyDown(KeyEvent.VK_RIGHT))
{
        x += 5;
}
if (input.isKeyDown(KeyEvent.VK_LEFT))
{
        x -= 5;
}


You can now control whats going on on the screen, and you should now know enough to make a simple game.

Finished Game Class

Java:

import input.InputHandler;

import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;

/**
 * Main class for the game
 */

public class GameTutorial extends JFrame
{       
        boolean isRunning = true;
        int fps = 30;
        int windowWidth = 500;
        int windowHeight = 500;
       
        BufferedImage backBuffer;
        Insets insets;
        InputHandler input;
       
        int x = 0;
       
        public static void main(String[] args)
        {
                GameTutorial game = new GameTutorial();
                game.run();
                System.exit(0);
        }
       
        /**
         * This method starts the game and runs it in a loop
         */

        public void run()
        {
                initialize();
               
                while(isRunning)
                {
                        long time = System.currentTimeMillis();
                       
                        update();
                        draw();
                       
                        //  delay for each frame  -   time it took for one frame
                        time = (1000 / fps) - (System.currentTimeMillis() - time);
                       
                        if (time > 0)
                        {
                                try
                                {
                                        Thread.sleep(time);
                                }
                                catch(Exception e){}
                        }
                }
               
                setVisible(false);
        }
       
        /**
         * This method will set up everything need for the game to run
         */

        void initialize()
        {
                setTitle("Game Tutorial");
                setSize(windowWidth, windowHeight);
                setResizable(false);
                setDefaultCloseOperation(EXIT_ON_CLOSE);
                setVisible(true);
               
                insets = getInsets();
                setSize(insets.left + windowWidth + insets.right,
                                insets.top + windowHeight + insets.bottom);
               
                backBuffer = new BufferedImage(windowWidth, windowHeight, BufferedImage.TYPE_INT_RGB);
                input = new InputHandler(this);
        }
       
        /**
         * This method will check for input, move things
         * around and check for win conditions, etc
         */

        void update()
        {
                if (input.isKeyDown(KeyEvent.VK_RIGHT))
                {
                        x += 5;
                }
                if (input.isKeyDown(KeyEvent.VK_LEFT))
                {
                        x -= 5;
                }
        }
       
        /**
         * This method will draw everything
         */

        void draw()
        {              
                Graphics g = getGraphics();
               
                Graphics bbg = backBuffer.getGraphics();
               
                bbg.setColor(Color.WHITE);
                bbg.fillRect(0, 0, windowWidth, windowHeight);
               
                bbg.setColor(Color.BLACK);
                bbg.drawOval(x, 10, 20, 20);
               
                g.drawImage(backBuffer, insets.left, insets.top, this);
        }
}


Some Things To Try Yourself

Make a small game like pong.

Expand the InputHandler to include mouse motion, and mouse buttons.
Hint: Look up the interfaces MouseMotionListener and MouseListener in the java documentation.

For keys and buttons, make methods that will only return true once, until the key or button is released (I call these isKeyHit/isMouseHit).

Create a better game engine that does not cap the frame rate but still has smooth motion.

Conclusion

Thanks for reading this and I hope this helps someone.

If you have any suggestions/comments/errors please let me know below.
Sponsor
Sponsor
Sponsor
sponsor
Nai




PostPosted: Mon Aug 23, 2010 5:03 pm   Post subject: RE:[Tutorial] Using Java\'s libraries to create a simple game engine

Awesome tutorial! This really helped to get me started making my own games. Thanks!
Entity1037




PostPosted: Fri Mar 07, 2014 2:07 pm   Post subject: RE:[Tutorial] Using Java\'s libraries to create a simple game engine

You skipped some steps, like how to set up the java packages (which you named input here).

I tried making a package, but it doens't seem to access any of the methods (or even create an instance of InputHandler) from InputHandler, although it DOES import the package. Could you please explain how you did the packages?
Panphobia




PostPosted: Fri Mar 07, 2014 4:37 pm   Post subject: RE:[Tutorial] Using Java\'s libraries to create a simple game engine

You don't need to make a package, have you learned about Object Oriented programming yet? Well that is all you need.
Entity1037




PostPosted: Sat Mar 08, 2014 12:08 am   Post subject: RE:[Tutorial] Using Java\'s libraries to create a simple game engine

OK, OK, I had a stupid mistake. I didn't realize that a package was unnessesary for some unapparent reason...

One more thing: it keeps saying that the variable "keys" was never declared. It's not initialized in the code given above. Help?
AlanD




PostPosted: Tue Apr 15, 2014 8:31 pm   Post subject: Re: [Tutorial] Using Java's libraries to create a simple game engine

"Keys" is a boolean array, and you can declare it in the constructor.

(e.g. keys = new boolean [256])

The tutorial was amazing, thank you!
Lkullez




PostPosted: Thu May 21, 2015 8:48 am   Post subject: RE:[Tutorial] Using Java\'s libraries to create a simple game engine

Giving me a variable "keys" was never declared error and can't declear it. Could someone post a pic or a pice of code that explains this and helps me do this?
Insectoid




PostPosted: Thu May 21, 2015 7:15 pm   Post subject: RE:[Tutorial] Using Java\'s libraries to create a simple game engine

This is explained in the comment before yours.
aldman123




PostPosted: Sat Nov 19, 2016 9:49 pm   Post subject: RE:[Tutorial] Using Java\'s libraries to create a simple game engine

I know that this is an old post, but how would I draw a .png instead of an oval?
Insectoid




PostPosted: Sun Nov 20, 2016 9:32 am   Post subject: RE:[Tutorial] Using Java\'s libraries to create a simple game engine

Turing can't load png files, only bmp, jpg and gif.
Display posts from previous:   
   Index -> Programming, Java -> Java Tutorials
View previous topic Tell A FriendPrintable versionDownload TopicRate TopicSubscribe to this topicPrivate MessagesRefresh page View next topic

Page 1 of 1  [ 10 Posts ]
Jump to:   


Style:  
Search: