By the end of this tutorial you will have learned how to leverage the power of object-oriented programming to create a game engine containing game entities.
The story behind LWJGL entities
Instead of looking at the scene as a bunch of shapes, look at the scene as a bunch of objects. Each object has material properties, a bounding box for collision and an amount of transparency for instance. Furthermore, each object can be classified into more abstract groups or categories. For example: a football (or soccer ball), a basketball, and a tennis ball are all balls. They all share the same properties of a ball, being round, but they also differ. Utilising this approach makes managing an object pool straightforward.
LWJGL Entity interface
This is the parent interface for the entity.
public interface Entity2D { public float getX(); public float getY(); public void setX(float x); public void setY(float y); public void setLocation(float x, float y); public void setUp(); public void destroy(); public void draw(); } |
It is still very basic and generic. Collision detection would be too specific to add here. It would be better to add a CollidableEntity2D down the line.
Abstract classes – being lazy
When a lazy approach is desired, create an abstract class for the aforementioned interface and implement the position methods and leave the remaining methods abstract.
public abstract class AbstractEntity2D implements Entity2D { protected float x; protected float y; public float getX() { return x; } public float getY() { return y; } public void setX(float x) { this.x = x; } public void setY(float y) { this.y = y; } public void setLocation(float x, float y) { this.x = x; this.y = y; } public abstract void setUp(); public abstract void destroy(); public abstract void draw(); } |
Implementing the interface fully
It is now possible to easily create a class derived from the ‘Entity2D’ interface.
public class Box2D extends AbstractEntity2D { protected float size; public Box2D(float x, float y, float size) { this.x = x; this.y = y; this.size = size; } public Box2D() { this.x = this.y = this.size = 0; } @Override public void setUp() { // We don't need anything here for a box } @Override public void destroy() { // We don't need anything here for a box } @Override public void draw() { glBegin(GL_TRIANGLES); glVertex2f(x + size/2, y + size/2); glVertex2f(x + size/2, y - size/2); glVertex2f(x - size/2, y - size/2); glVertex2f(x - size/2, y - size/2); glVertex2f(x - size/2, y + size/2); glVertex2f(x + size/2, y + size/2); glEnd(); } } |
Using the classes for the LWJGL Entities in code
To create an instance of ‘Entity2D’, write the following code.
// Before game loop Entity2D box = new Box2D(30.0f, 50.0f, 25.0f); box.setUp(); // In game loop box.draw(); // After game loop box.destroy(); |
Note that even though the ‘setUp()’ and ‘destroy()’ methods do not appear necessary, they are still called. The reason is that in the future resource handling might be put there.
Conclusion
This concludes this tutorial. Should you have any questions or remarks, I would love to see them in the comments section below.
How do you do this with textures?
and collision detection too
I susoppe that sounds and smells just about right.
Why is using abstract classes over interfaces lazy? I don’t see a problem with it!
In programming, “lazy” is not always a negative thing, it often means writing cleaner code that takes less time to run.
Can you procedurally generate these entities at the games will or do you have manually type the constructor for each entity. Eg. Naturally spawning animals that have another entity created when the random class picks 1/10.
Yes. For instance, you can decide at run-time whether to add entities to a List
How would I implement this.
Griffin, you would implement it something like this:
// All the randomly added entities in your game.
private static final ArrayList entities = new ArrayList();
// How many entities should be present at once?
private static final int numEntities = 60;
// Initialize your game.
// Run in another thread, as usual.
private void gameLoop() {
while(running) {
// Loop through entities, moving them and drawing them, and remove an entity if it’s no longer used–call addEntities().
}
}
private void addEntities() {
while(entities.size() < numEntities) {
if(Math.random() < 70) // 70% chance.
entities.add(new Zombie());
else // Other 30%.
entities.add(new Pig());
// And so forth.
}
}
Can the same principles be applied to the position of a 3D object, such as a point?
What would the draw method look like if you were using vertex array objects?
Technically, you could use vertex array objects in conjunction with this method of rendering. Normally though, you would use vertex buffer objects to render the primitive shapes. Here is an example of using vertex buffer objects: https://github.com/OskarVeerhoek/YouTube-tutorials/blob/master/src/episode_18/VertexBufferObjectDemo.java.
Is there a way to create infinite entities using this?
I’m quite new to LWJGL, any tips?
If you are asking for a way to create and control a potentially infinite amount of objects, I think you must use a Data Structure to store and iterate through them. For example:
HashTable() allows quick reference to specific objects using a key.
ArrayList() is great to iterate through same-class objects when you need to update all of them in some way.
BinaryHeap() is an useful asset when you wish to iterate orderly through some property common to a series of objects.
I’m sure you can think of some Data Structure that comes handy in your case.
Thanks for the comment.
In this case, the lazy way is the best way. This is the foundation of object oriented programming.
What’s the non-lazy way to do this?
When you implement an interface you have to declare all the methods,but with an abstractclass you only have to subclass and override the desired methods. Lazyness ftw!
Sounds more like “work smarter, not harder” than lazy to me 😀
When he said lazy, he did not mean for it to be taken so seriously. In general, the rule is that a lazy programmer creates the simplest and thus most efficient programs. Abstract classes (think “Ball”) define a set of characteristics common to all subclasses (like “Football”, “Baseball”, and “Basketball”). Thus, you don’t have to rewrite all the variables in each individual class (the hard way). Technically, neither of the two ways is any faster than the other, simply because the compiler breaks the code down the same as the hard way if you do it the easier, smarter way. HOWEVER–abstract classes are very important for things such as lists of randomly generated entities. In the comments above, you can find my example, where you might add multiple types of entities to a list. If you have an ArrayList, you can’t add Baseballs lot it–same as the other way around. But if you make an ArrayList, you can randomly add Footballs, Baseballs, Etc. to the same list.