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 simple moving rectangle  (Read 3488 times)
0 Members and 1 Guest are viewing this topic.
Online SHC
« Posted 2013-09-06 16:45:11 »

LWJGL Tutorial Series


This is a continuation to part one, Creating a Simple Game class. In this tutorial, we're going to draw a moving rectangle with keyboard input. In the next part, we're going with colors.

Tutorial 1 - A simple moving rectangle


So, let's create a simple tutorial subclass of the Game class we created in part one.

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  
public class Tutorial1 extends Game
{
    public void init()
    {
        // Initialize here
   }

    public void update(long elapsedTime)
    {
        // Update logic here
   }

    public void render()
    {
        // Render to the screen here
   }

    public void resized()
    {
        // We reset the viewport here.
   }

    public static void main(String[] args)
    {
        new Tutorial1();
    }
}

Importing and configuring OpenGL


Let's start by writing imports. All the OpenGL functions we are going to use like
glXXX()
are defined in
org.lwjgl.opengl.GL11
class. So we statically import them.

1  
import static org.lwjgl.opengl.GL11.*;

Now that we've added the import, we can start using the OpenGL functions. First we need to configure it to our needs and then we can perform actual rendering. We're going to configure in the
init()
method. I'll list that method first and explain the code line by line.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
public void init()
{
    Display.setTitle("Tutorial 1: A simple moving rectangle");

    // Setup OpenGL
   glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glMatrixMode(GL_MODELVIEW);
    glOrtho(0, 800, 600, 0, 1, -1);
    glViewport(0, 0, Display.getWidth(), Display.getHeight());
}

We've seen four functions
glMatrixMode()
,
glLoadIdentity()
,
glOrtho()
and
glViewport()
Let's see them in detail.

Matrix Modes


OpenGL operates on matrices. The method
glMatrixMode()
is used to set the matrix to be used for a series of commands. The valid matrix modes are

  • GL_PROJECTION
    - Projection matrix
  • GL_MODELVIEW
    - View matrix
  • GL_TEXTURE
    - Texture matrix and
  • GL_COLOR
    - Color matrix

So the line
setMatrixMode(GL_PROJECTION);
sets the current matrix mode to projection matrix.

Next comes the call to
glLoadIdentity()
which does nothing more than replacing the current matrix with identity matrix. Next we change matrix mode to
GL_MODELVIEW
and call
glOrtho()

Setting an Orthographic Camera


The function
glOrtho()
is used to setup an orthographic camera. It's syntax is as follows.

1  
void glOrtho(double left, double right, double bottom, double top, double zNear, double zFar)

Here are the parameters.

1  
2  
3  
4  
5  
6  
7  
8  
9  
left, right
    // Specify the coordinates for the left and right vertical clipping planes.

bottom, top
    // Specify the coordinates for the bottom and top horizontal clipping planes.

zNear, zFar
    // Specify the distances to the nearer and farther depth clipping planes.
   // These values are negative if the plane is to be behind the viewer.

So calling
glOrtho(0, 800, 600, 0, 1, -1)
sets the coordinate system to the following.



This makes it easier to draw 2d graphics since we're used to the Java2D system till now. This coordinate system will be changed once we enter 3D mode.

And now, I set the viewport so that we display what we want at accurate positions.

Viewport


A viewport is like a window between you and the screen allowing you to peek through it. It's a rectangle on the screen and only the part underneath that rectangle is rendered on to the display stretching the visible region with the display. For the code,

1  
glViewport(0, 0, Display.getWidth(), Display.getHeight());

stretches our drawing area of 600, 800 onto the whole display.

Now we handle resizing with the resized method. In this, we simply reset the viewport to the current display size.

1  
2  
3  
4  
public void resized()
{
    glViewport(0, 0, Display.getWidth(), Display.getHeight());
}

Clearing the Screen


For clearing the color data, we use
glClear(GL_COLOR_BUFFER_BIT)


OpenGL stores it's data in buffers. There are mainly two types of buffers. They are
GL_COLOR_BUFFER_BIT
and
GL_DEPTH_BUFFER_BIT


OpenGL stores it's pixel data of screen in the color buffer bit and depth information in depth buffer bit. We just want to clear the color buffer since we are doing 2D graphics and there will be no depth for them.

Rendering with QUADS


OpenGL renders all the shapes with primitives and we supply vertices to it. QUADS stand for quadrilateral. At first we should say to OpenGL that we want to draw a QUAD. This can be done by using

1  
glBegin(GL_QUADS);

Then we supply the vertices of that shape with the
glVertex{numCoords}{type}()
function. You can change
{numCoords}
with the number of coordinates and
{type}
with the type of values you are passing in. After the rendering, we have to notify it by calling

1  
glEnd();

Now, let's make the render method.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
public void render()
{
    glBegin(GL_QUADS);
    {
        // We render by specifying vertices. In 2D, we can use the glVertex2f function

        glVertex2f(0, 0);      // Top left corner
       glVertex2f(0, 100);    // Top right corner
       glVertex2f(100, 100);  // Bottom right corner
       glVertex2f(100, 0);    // Bottom left corner
   }
    glEnd();
}

This draws a basic white rectangle on a black screen.

Keyboard Input


Now to make it move, we take the top left coordinates of it as variables x and y and change them with keyboard input.

I'm importing the members of the
org.lwjgl.input.Keyboard
class statically for convenience. The input is checked in the update method.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
public void update(long elapsedTime)
{
    if (isKeyDown(KEY_LEFT))
        x -= 4;

    if (isKeyDown(KEY_RIGHT))
        x += 4;

    if (isKeyDown(KEY_UP))
        y -= 4;

    if (isKeyDown(KEY_DOWN))
        y += 4;

    if (isKeyDown(KEY_ESCAPE))
        end();
}

In this way, I record the values and translate the coordinates before drawing with
glTranslatef(x, y, 0)

Complete Render Code


Let's see the final render code now.

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  
public void render()
{
    // Clear the color information.
   glClear(GL_COLOR_BUFFER_BIT);

    // Set the color to white.
   glColor3f(1, 1, 1);

    // Create a new draw matrix for custom settings.
   glPushMatrix();
    {
        // Translate to the location.
       glTranslatef(x, y, 0);

        // Begin drawing with QUADS. A QUAD is a polygon with four vertices.
       glBegin(GL_QUADS);
        {
            glVertex2f(0, 0);
            glVertex2f(0, 100);
            glVertex2f(100, 100);
            glVertex2f(100, 0);
        }
        glEnd(); // End the drawing.
   }
    glPopMatrix(); // Restore original settings.
}

And when you run this, you should be able to move the rectangle with arrow keys. And it looks like this.



And it's the end of the first tutorial.

Source Code


Tutorial1.java

Offline quew8

JGO Coder


Medals: 23



« Reply #1 - Posted 2013-09-06 18:04:56 »

Firstly, I don't think you really explained what the viewport is and I think its quite an important concept. Also, "clears the colour data" I think is a bit vague. Maybe a brief explanation of the various buffers is in order.

Otherwise nice.
Online SHC
« Reply #2 - Posted 2013-09-06 18:10:10 »

@quew8

Thanks. I'll add that tomorrow morning.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Online SHC
« Reply #3 - Posted 2013-09-07 05:13:30 »

I've updated this article. If any changes are needed, please notify me.

Offline ylvakiller

Junior Newbie





« Reply #4 - Posted 2013-09-08 13:55:56 »

Hi there,

something was unclear for me, maybe you can explain why. in the rendering code you do
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
        // Create a new draw matrix for custom settings.
       glPushMatrix();
        {
            // Translate to the location.
           glTranslatef(x, y, 0);
           
            // Begin drawing with QUADS. A QUAD is a polygon with four vertices.
           glBegin(GL_QUADS);
            {
                glVertex2f(0, 0);
                glVertex2f(0, 100);
                glVertex2f(100, 100);
                glVertex2f(100, 0);
            }
            glEnd();  // End the drawing.
       }
        glPopMatrix();  // Restore original settings.


but why the glPopMatrix? as fas I understand it the glPushMatrix() creates a new drawing matrix for custom settings yet the glPopMatrix restores the original settings...
doesnt that conflict with each other? making new settings and then restoring them again? or are those settings just for the white square in the middle?

hope you can help with this question, I got the code working and understand the different aspects but do not understand this specific part completely...


greetings,

Ylva



part 2:

Also I tried to add borders to the white box so it can only go as far as the corners of the screen, not further.
I thought I could do that in the update method where the key movements are put to the x and y coords.
the first ones are fairly obvious:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
if (isKeyDown(KEY_LEFT))
        {
           
            x -= 4;
           
            if (x<=0)
            {
                x = 0;      //left border
           }
        }


this will work for the 0,0 borders (top and left)

however for the right this wont work, I tried using the coords that we have set (800 and 600) and even Display.getWidth() & Display.getHeight() which we also use when defining the viewport.
Now if I understand it right the Display.getHeight() and getWidth() will not work since they look at the size of the actual window, which if you have a large screen will be way more then 800 and 600 right?
The viewport method that we called is going to take that 800 and 600 and distribute that along the size of the actual window if I'm right.
the 800 and 600 then should work, however this also does not work, the x and y coords can still get quite a bit bigger than the 800 and 600...
I don't see why that doesn't work so perhaps I am missing something very basic when it comes to coding a graphical plane...

greetings again,

Ylva
Online SHC
« Reply #5 - Posted 2013-09-08 15:19:27 »

@ylvakiller

What you understood about
glPushMatrix()
and
glPopMatrix()
was right. To better understand why they were used, try commenting those lines and you'll understand. Removing them causes our rendering code to translate the axis and doesn't revert the translation. So if once it is translated to (4, 0) assuming you only pressed right, this will not be reversed. So in the next loop, even if you haven't pressed keys, the axis will be translated to (8, 0) since x will be 4 still since it's coordinate. If you didn't like using them, you can also negative translate. Add
glTranslatef(-x, -y, 0);
after rendering and remove the matrix calls.

For your second question, you are doing the left part right but you forgot one thing that
x + width
will be the right. In this case the width is 100 so test
if (x + 100 >= 800)
will succeed for what you are trying. Note that 800 is the largest value on x axis we set with
glOrtho()
function. Similarly you can test for top and bottom as well. I'll show this in one of my up-coming tutorials 'LWJGL Pong'.

Offline ylvakiller

Junior Newbie





« Reply #6 - Posted 2013-09-08 16:23:26 »

aaa thanks for clarifying the Pushmatrices,

and I knew I was forgetting something basic... you where right, adding the size of the object (the white square) works perfectly thanks! Smiley


greetings,


Ylva
Offline MaxMeijer

Innocent Bystander





« Reply #7 - Posted 2014-02-02 15:16:16 »

Why do you call glOrtho when the current matrix is GL_MODELVIEW instead of GL_PROJECTION? On other websites they say it should be called on GL_PROJECTION.
Online SHC
« Reply #8 - Posted 2014-02-02 15:37:35 »

@MaxMeijer

There is no special reason for that. It just changes the current matrix. I just used there because, I'm not going to call
glLoadIdentity()
anywhere in my code to reset the identity matrix. But most recommend to use it because it won't be affected even if you load the identity matrix.

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 (24 views)
2014-04-15 18:08:23

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

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

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

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

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

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

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

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

CJLetsGame (191 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!