Java-Gaming.org    
Featured games (91)
games approved by the League of Dukes
Games in Showcase (577)
games submitted by our members
Games in WIP (498)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  LWJGL Tutorial Series - A Basic Game  (Read 5542 times)
0 Members and 1 Guest are viewing this topic.
Offline SHC
« Posted 2013-09-06 15:29:50 »

LWJGL Tutorial Series


Welcome to the first Tutorial in the LWJGL Tutorial Series. Throughout this series, I'll be showing you how to create Modern OpenGL (OpenGL 3.2 or newer) applications using LWJGL - a Java wrapper for OpenGL, OpenAL and OpenCL in Java.

In this tutorial, we will design a basic
Game
class which, we'll use as the super class for the other tutorials. We'll see how to create a window, selecting the core OpenGL profile and setup a basic working skeleton which will be used as a framework in the future tutorials.

If I'm doing anything wrong, or has a better way to do, please notify me with comments.

A Basic Game Class


Now that we are ready to get started, we need a simple framework that we'll be using throughout the tutorial. We want a framework with the following functions.

  • Handle the GameLoop for us.
  • Allow resizing events.
  • Utility method for getting current time.
  • Overridable methods for initializsing, updating, rendering and disposing.

Now that we've thought about a basic framework, we are going to implement it. Let's start by defining the methods as the skeleton.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
public class Game
{
    /**
     * Initialize the game
     */

    public void init()
    {
    }

    /**
     * Update the game
     */

    public void update(long elapsedTime)
    {
    }

    /**
     * Render the game
     */

    public void render()
    {
    }

    /**
     * Handle Display resizing
     */

    public void resized()
    {
    }

    /**
     * Dispose the game
     */

    public void dispose()
    {
    }
}

Now that we've our bare-bones, let's try to create the muscles, the variables of the class. Since we are thinking of having an
end
method which will be static so we can end the game from anywhere, we should have a static instance variable.

1  
private static Game instance;

The method
end()
is a static method for convenience and it calls
dispose()
on the game instance before exiting. Now let's code this.

1  
2  
3  
4  
5  
6  
public static void end()
{
    instance.dispose();
    Display.destroy();
    System.exit(0);
}

Then we make a constructor for our class which creates a
Display
with core OpenGL profile and start the gameloop. If you are wondering what a core profile is, it's simply an OpenGL context with no deprecated functions available and we will have access to all the modern OpenGL functions.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
/**
 * Create a new Game
 */

public Game()
{
    try
    {
        // Set the static reference
       instance = this;

        // Create the default PixelFormat
       PixelFormat pfmt = new PixelFormat();

        // We need a core context with atleast OpenGL 3.2
       ContextAttribs cattr = new ContextAttribs(3, 2).withForwardCompatible(true)
                                                       .withProfileCore(true);

        // Create the Display
       Display.create(pfmt, cattr);
        Display.setResizable(true);

        // Start the game
       gameLoop();
    }
    catch (LWJGLException e)
    {
        e.printStackTrace();
        System.exit(-1); // There is no point in running without hardware acceleration right?
   }
}

Remember that we thought of having an utility method for current time? We'll be using milliseconds as our unit of time and our function
getCurrentTime()
will do it.

1  
2  
3  
4  
public static long getCurrentTime()
{
    return Sys.getTime() * 1000 / Sys.getTimerResolution();
}

We'll be using this method for calculating the elapsed time in the game-loop. This method will also be helpful when we start dealing with animations. Now comes the game-loop. For this tutorial series, we'll be using a fixed-time step game-loop which updates at a steady rate of 60 fps, i.e., our game will update and render 60 times in a second.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
private void gameLoop()
{
    long lastFrame = getCurrentTime();
    long thisFrame = getCurrentTime();

    init();

    while (!Display.isCloseRequested())
    {
        thisFrame = getCurrentTime();
        update(thisFrame - lastFrame);
        render();

        lastFrame = thisFrame;
        Display.update();

        // Check the resize property
       if (Display.wasResized())
            resized();

        Display.sync(60);  // You can write this value to a variable to change it.
   }

    end();
}

This almost completes our
Game
class, but we want to be able to deal with DisplayModes and fullscreen. To be able to switch the DisplayModes, we're going to use a method called
setDisplayMode()
which was actually from the official LWJGL wiki with some modifications by me like it now returns a boolean to indicate success.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
/**
 * Sets a DisplayMode after selecting for a better one.
 * @param width The width of the display.
 * @param height The height of the display.
 * @param fullscreen The fullscreen mode.
 *
 * @return True if switching is successful. Else false.
 */

public static boolean setDisplayMode(int width, int height, boolean fullscreen)
{
    // return if requested DisplayMode is already set
   if ((Display.getDisplayMode().getWidth() == width) &&
        (Display.getDisplayMode().getHeight() == height) &&
        (Display.isFullscreen() == fullscreen))
        return true;

    try
    {
        // The target DisplayMode
       DisplayMode targetDisplayMode = null;

        if (fullscreen)
        {
            // Gather all the DisplayModes available at fullscreen
           DisplayMode[] modes = Display.getAvailableDisplayModes();
            int freq = 0;

            // Iterate through all of them
           for (DisplayMode current: modes)
            {
                // Make sure that the width and height matches
               if ((current.getWidth() == width) && (current.getHeight() == height))
                {
                    // Select the one with greater frequency
                   if ((targetDisplayMode == null) || (current.getFrequency() >= freq))
                    {
                        // Select the one with greater bits per pixel
                       if ((targetDisplayMode == null) || (current.getBitsPerPixel() > targetDisplayMode.getBitsPerPixel()))
                        {
                            targetDisplayMode = current;
                            freq = targetDisplayMode.getFrequency();
                        }
                    }

                    // if we've found a match for bpp and frequency against the
                   // original display mode then it's probably best to go for this one
                   // since it's most likely compatible with the monitor
                   if ((current.getBitsPerPixel() == Display.getDesktopDisplayMode().getBitsPerPixel()) &&
                        (current.getFrequency() == Display.getDesktopDisplayMode().getFrequency()))
                    {
                        targetDisplayMode = current;
                        break;
                    }
                }
            }
        }
        else
        {
            // No need to query for windowed mode
           targetDisplayMode = new DisplayMode(width, height);
        }

        if (targetDisplayMode == null)
        {
            System.out.println("Failed to find value mode: " + width + "x" + height + " fs=" + fullscreen);
            return false;
        }

        // Set the DisplayMode we've found
       Display.setDisplayMode(targetDisplayMode);
        Display.setFullscreen(fullscreen);

        System.out.println("Selected DisplayMode: " + targetDisplayMode.toString());

        // Generate a resized event
       instance.resized();

        return true;
    }
    catch (LWJGLException e)
    {
        System.out.println("Unable to setup mode " + width + "x" + height + " fullscreen=" + fullscreen + e);
    }

    return false;
}

We're not complete yet, we need to set the initial DisplayMode. We are going to create the initial display with a 800x600 window so add this call to the above function just after we create our Display in the constructor.

1  
setDisplayMode(800, 600, false);

That's all to it, we've made our basic
Game
class which is ready to serve our needs in future tutorials. In the next tutorial, I'll be showing you how to draw a simple rectangle and move it with the arrow keys.

Source Code


The source code is available in my GitHub repository.

Game.java

Offline quew8

JGO Coder


Medals: 23



« Reply #1 - Posted 2013-09-06 18:02:24 »

Generally, I think you should choose a Display Mode from the list of available DisplayMode s. You can iterate through them to choose the best one in terms of dimensions, fullscreen etc.
Offline Troncoso

JGO Coder


Medals: 20



« Reply #2 - Posted 2013-09-06 18:11:35 »

I agree, and if generally, if you use a custom display mode, you won't be able to use full screen.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline SHC
« Reply #3 - Posted 2013-09-06 18:13:25 »

I'm thinking on making another tutorial for fullscreen and how to select displaymodes. Thanks anyway.

Offline SHC
« Reply #4 - Posted 2013-09-07 04:47:46 »

I've added the code to change DisplayMode by querying the available modes.

Offline davidc

Senior Member


Medals: 5
Projects: 2



« Reply #5 - Posted 2013-09-07 06:59:05 »

I'm not a fan of using return value (ie. true of false) to indicate if something succeeds or not, especially when you already have a mechanism in place that achieves exactly the same and actually requires additional effort to turn off. For example, your setDisplayMode() should just declare "throws LWJGLException". Nowhere in your code is there any point in catching this. There is no way to recover. Just let it get thrown. You don't even have to call printStackTrace() or System.exit(1) - this is done for you by the JVM's exception handling model.
Offline SHC
« Reply #6 - Posted 2013-09-07 07:08:15 »

@davidc

Yes that can be done but I actually don't like using the
throws
keyword. It's a personal preference.

Offline davidc

Senior Member


Medals: 5
Projects: 2



« Reply #7 - Posted 2013-09-07 08:00:37 »

Why the heck not? They are there to allow exceptions to work. Ineffective use of them takes more effort.

If you are going to go down the path of using return codes, you'll need to make sure your code is checking them. You don't in your example.
Offline quew8

JGO Coder


Medals: 23



« Reply #8 - Posted 2013-09-07 09:58:40 »

Well actually, I think it can be recovered from, otherwise it wouldn't be a checked exception. If nothing else just to show an error message in a dialogue for end users. But it is as one or both (can't see previous posts in the articles & tutorials post reply apparently) said, it is just personal preferences and this is not a tutorial on coding styles.
Offline ylvakiller

Junior Newbie





« Reply #9 - Posted 2013-09-07 13:45:41 »

Hi there,

I am just starting game programming so this tutorial series help em quite a lot.

I have just one remark, is it possible to do a code recap, or a code file at the end of every part of the tutorial so we can check the code we've written with the code you wrote so we can be sure we are putting the correct code in the correct places?
That will help understanding people who are new at coding with OpenGL like me.

greetings,

Ylva
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline SHC
« Reply #10 - Posted 2013-09-07 13:47:10 »

@ylvakiller

It's a nice idea. I'll upload the source files.

Offline ylvakiller

Junior Newbie





« Reply #11 - Posted 2013-09-07 13:47:55 »

Awesome thanks!  Smiley
Online Riven
« League of Dukes »

JGO Overlord


Medals: 605
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #12 - Posted 2014-03-30 18:09:14 »

Unlocked by request Pointing

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline SHC
« Reply #13 - Posted 2014-03-30 18:10:05 »

@Riven

Thanks you very much for unlocking.

Pages: [1]
  ignore  |  Print  
 
 

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

xsi3rr4x (23 views)
2014-04-15 18:08:23

BurntPizza (18 views)
2014-04-15 03:46:01

UprightPath (32 views)
2014-04-14 17:39:50

UprightPath (16 views)
2014-04-14 17:35:47

Porlus (32 views)
2014-04-14 15:48:38

tom_mai78101 (58 views)
2014-04-10 04:04:31

BurntPizza (116 views)
2014-04-08 23:06:04

tom_mai78101 (216 views)
2014-04-05 13:34:39

trollwarrior1 (183 views)
2014-04-04 12:06:45

CJLetsGame (190 views)
2014-04-01 02:16:10
List of Learning Resources
by Longarmx
2014-04-08 03:14:44

Good Examples
by matheus23
2014-04-05 13:51:37

Good Examples
by Grunnt
2014-04-03 15:48:46

Good Examples
by Grunnt
2014-04-03 15:48:37

Good Examples
by matheus23
2014-04-01 18:40:51

Good Examples
by matheus23
2014-04-01 18:40:34

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:22:30

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:05:20
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!