-
Notifications
You must be signed in to change notification settings - Fork 0
Home
This is a brief introduction into more technical details for this library. If you want to follow a tutorial with java-desktop@pjgl adaptation look here: https://github.com/PanJohnny/PJGameLibrary/wiki/Tutorial
This project is structured to three separate parts:
- Core
- API
- Implementation
Core consists of the "Main class" which is PJGLCore. PJGLCore is what everything is built upon. It handles the loop, calls a few events and manages implementations.
Api is a large division of this project. These are the most important classes:
- PJGL - used to initialize the library, full docs
- PJGLEvents - contains a set of predefined events for PJGL Engine, these events can be listened, full docs
Contains implementations of this project, currently lwjgl and java-desktop.
First you will need to initialize the library using the static init method. For that you can create your own adapters or choose an implementation.
Examples will have LWGL used.
PJGL.init(new LWJGLInitializer("Hello, World!", 750, 750)); // creates window with the title Hello, World!, size 750x750
final PJGL pjgl = PJGL.getInstance(); // PJGL is singleton class, you can get the instance and keep it as a variable
When using LWJGL adaptation you need to register sprites and objects when PJGLEvents.VISIBLE is called. Add a listener to this event and then call start. This is in-place because of initialization of OpenGL context.
PJGLEvents.VISIBLE.listen(() -> {
SpriteRegistry.register...
manager.queueAddition... // addition needs to be queued
});
There are two types of sprites.
Image sprites are mainly for com.panjohnny.pjgl.adapt.desktop adaptation, when Image is used to render sprites.
Register them with registerImageSprite(String, String). This method supports loading from classpath and filesystem.
These sprites contain integer representing OpenGL texture.
Register them with registerTextureSprite(String, String). This method supports loading from filesystem.
You can also register texture sprite as a atlas and then assign regions of it to SpriteRenderer. (Only LWJGL)
TextureAtlas atlas = SpriteRegistry.registerTextureSpriteAsAtlas("juan", "./assets/atlas.png");
AtlasRegion region0 = atlas.defineRegion(0, 0, 16, 16);
NOTE: Objects are always registered synchronously. To prevent concurrent modifications there are special queue methods.
Game objects on their own are just listeners for the update event. When you provide a components you add other functions.
GameObject apple = new GameObject() {
public final Position position = addComponent(new Position(this, 10, 10));
public final Size size = addComponent(new Size(this, 100, 100));
public final SpriteRenderer renderer = addComponent(new SpriteRenderer(this, "apple"));
public final Animator animator = addComponent(new Animator(this, appleAnimation));
};
In this sample a GameObject apple is created with a few components - position, size, renderer and animator.
Below is game object update method schema, the order of adding components matter.
GAME OBJECT UPDATE SCHEMA
super.update() // code that GameObject has
| -> Components[0].update()
| -> ...
| -> Components[last].update()
-> #update() // your new code
Components are updated on GameObject#update() instances of GameObject update later.
Objects need to be registered to the manager.
GameObjectManager manager = pjgl.getManager();
manager.addObject(apple); // this could be done only before calling pjgl.start()
manager.queueAddition(apple); // better method for thread safety, apple will be added next update, can be called when pjgl is running
PJGL.init(new JDInitializer("Apple!", 750, 750));
PJGL pjgl = PJGL.getInstance();
SpriteRegistry.registerImageSprite("apple", "apple.png");
GameObject apple = new GameObject() {
public final Position position = addComponent(new Position(this, 10, 10));
public final Size size = addComponent(new Size(this, 100, 100));
public final SpriteRenderer renderer = addComponent(new SpriteRenderer(this, "apple"));
};
pjgl.getManager().addObject(apple); // notice that objects can be added safely because pjgl.start() was not called
pjgl.start();
PJGL.init(new LWJGLInitializer("Apple!", 750, 750));
PJGL pjgl = PJGL.getInstance();
PJGLEvents.VISIBLE.listen(() -> {
SpriteRegistry.registerTextureSprite("apple", "./assets/apple.png");
// Juan is sprite map
TextureAtlas atlas = SpriteRegistry.registerTextureSpriteAsAtlas("juan", "./assets/juan-map.png");
AtlasRegion j0 = atlas.defineRegion(0, 0, 16, 16);
GameObject apple = new GameObject() {
public final Position position = addComponent(new Position(this, 10, 10));
public final Size size = addComponent(new Size(this, 100, 100));
public final SpriteRenderer renderer = addComponent(new SpriteRenderer(this, "apple"));
public final Animator animator = addComponent(new Animator(this, a));
};
pjgl.getManager().queueAddition(apple);
});
GLFWKeyboard keyboard = pjgl.getKeyboard();
GLFWWindow window = pjgl.getWindow();
// Example of input handling with GLFW
PJGLEvents.TICK.listen(() -> {
if (keyboard.isKeyDown(GLFW.GLFW_KEY_ESCAPE)) {
window.close();
}
if (keyboard.isKeyDown(GLFW.GLFW_KEY_LEFT)) {
pjgl.getRenderer().getCamera().move(-1, 0);
}
if (keyboard.isKeyDown(GLFW.GLFW_KEY_RIGHT)) {
pjgl.getRenderer().getCamera().move(1, 0);
}
if (keyboard.isKeyDown(GLFW.GLFW_KEY_UP)) {
pjgl.getRenderer().getCamera().move(0, -1);
}
if (keyboard.isKeyDown(GLFW.GLFW_KEY_DOWN)) {
pjgl.getRenderer().getCamera().move(0, 1);
}
});
pjgl.start();