The main Application class
The main Application class
The KarmaPlatform
class is the main class for our game. It will manage the game loop, and also the display through a
windows and the buffered strategy to render this display.
A JFrame
component from the Swing java API is used to create a Window. The KarmaPlatform
will inherit from a JPanel
component to facilitate the window sizing accordingly to the defined size in the configuration properties file.
To render the game objects, we will use a buffer strategy to first draw all game objects onto an image buffer, and then
copy this buffer to a 3-layer JFrame
buffer. At rendering time, we first draw then swap one of the three buffers.
@startuml
!theme plain
hide methods
hide attributes
class KarmaPlatform extends JPanel implements KeyListener{
+createScene()
+input()
+update(d:long)
+draw()
-init(args:String[])
-dispose()
-loop()
}
show KarmaPlatform methods
KarmaPlatform --> BufferedImage:buffer
KarmaPlatform --> JFrame:frame
@enduml
figure 1.1 - the KarmaPlatform main class
The init(String[])
method is loading a default configuration from a properties file (config.properties) and overload
it with possible matching arguments from the java command line
Configuration loading
seeloadConfiguration()
, parseCLI(String[]) andparseArguments(List<String>)
for implementation details.
Then, createScene()
creates the game object composing the game scene, populating the entities
list.
And finally, the loop()
method will sustain the game loop, calling step by step:
input()
, to manage keyboard inputupdate(long)
to update all entities, sorted on their priority value,draw()
to draw every active Entity on the rendering buffer, sorted on their priority value,
and looping.
Applying physic and mechanic laws
The update
method processing is the most complex, because this is where all the physic computation are performed.
@startuml
KarmaPlatform -> KarmaPlatform:loop()
KarmaPlatform -> KarmaPlatform:input()
KarmaPlatform -> KarmaPlatform:update()
group "apply Physic"
KarmaPlatform -> KarmaPlatform:applyPhysics()
KarmaPlatform --> KarmaPlatform:keepInPlayArea()
KarmaPlatform --> KarmaPlatform:detectCollision()
KarmaPlatform --> Behavior:onUpdate()
end
KarmaPlatform -> KarmaPlatform:draw()
@enduml
figure 1.2 - The physic computation process
the applyPhysics()
first executes the first Newton law about speed on each Entity.
entity position = entity position + entity velocity * elapsed time
then update the bounding box for the concerned entity
And then apply some material concerned factors:
entity velocity = entity velocity * entity friction
keeps the Entity constrained into the play area defined in the World
object
with the keepInPlayArea(World, Entity)
, and update again the bounding box (if required).
On some border collision, apply an elasticity material factor to compute the resulting velocity:
private void keepInPlayArea(World w, Entity e) {
Rectangle2D playArea = w.getPlayArea();
if (!playArea.contains(e.box)) {
if (e.x < playArea.getX()) {
e.dx = e.dx * -e.getElasticity();
e.x = playArea.getX();
}
// doing the same test on all other sides...
e.updateBox();
}
}
And finally, try and detect collision between the concerned Entity and all others, and compute resulting velocity:
entity velocity = max (entity velocity and other entity velocity)
* -max(entity elasticity and other entity elasticity)
private void detectCollision(World w, Entity e) {
entities.values().stream().filter(o -> e.isActive() && o.isActive() && !o.equals(e)).forEach(o -> {
if (e.box.intersects(o.box) || e.box.contains(o.box)) {
e.dx = Math.max(o.dx, e.dx) * -Math.max(e.getElasticity(), o.getElasticity());
e.dy = Math.max(o.dy, e.dy) * -Math.max(e.getElasticity(), o.getElasticity());
}
});
}