diff --git a/docs/01-main_class_width_user_input.md b/docs/01-main_class_width_user_input.md
index 1de0d71..3e9c5bc 100644
--- a/docs/01-main_class_width_user_input.md
+++ b/docs/01-main_class_width_user_input.md
@@ -1,44 +1,35 @@
# Main class and user input
-Building a game can be a game itself; or a nightmare. Depending on the tools, the team, the skills, … a lot of thing can
-interact badly with the process of creating a game. And this is exactly what we won't talk about!:)
+Building a game can be a game itself; or a nightmare. Depending on the tools, the team, the skills, … a lot of thing can interact badly with the process of creating a game. And this is exactly what we won't talk about!:)
-Here I will talk about creating a A-B-AB game with the only weapons provided by the nice Java JDK 19:) And no, I won't
-use JavaFX (beuarrk:)) I'll use the good old AWT and Swing (yes, I am maybe a 50 years old man…).
+Here I will talk about creating a A-B-AB game with the only weapons provided by the nice Java JDK 19:) And no, I won't use JavaFX (beuarrk:)) I'll use the good old AWT and Swing (yes, I am maybe a 50 years old man…).
Anyway let's try it through a series of posts to design some code.
## Creating a simple class
The basic Main class will support the famous "triptic" of the game loop: manage input, update objects, and draw
-everything on screen!
-But do you know why this is the basic default pattern for a game ?
+everything on screen! But do you know why this is the basic default pattern for a game ?
## A bit of video game history
-Why the game loop exists ? This is a very good question and the reason why is a historically based answer. Everything
-starts from the first ever video game: PONG.
+Why the game loop exists ? This is a very good question and the reason why is a historically based answer. Everything starts from the first ever video game: PONG.

-_figure 1 - Pong where all begins (ref:[https://fr.wikipedia.org/wiki/Pong](https://fr.wikipedia.org/wiki/Pong))_
+_figure 1 - Pong where all begins (
+ref:[Pong on wikipedia](https://fr.wikipedia.org/wiki/Pong))_
-The original Pong video game from wikipediaAt this very beginning time, the processor to execute tasks is a very a slow
-on, almost some hundreds of Khz as CPU frequency. To understand the scale we are talking about, current processor are
-running at 2 to 4 GHz!
-So processor are very slow, each cycle of CPU is a precious one. So every line of code is very optimized and clearly
-dedicated to some precise tasks.
+The original Pong video game from wikipediaAt this very beginning time, the processor to execute tasks is a very a slow on, almost some hundreds of Khz as CPU frequency. To understand the scale we are talking about, current processor are running at 2 to 4 GHz!
+So processor are very slow, each cycle of CPU is a precious one. So every line of code is very optimized and clearly dedicated to some precise tasks.
-And another element must be taken in account: the display process. At this time, screen where not flat one with a bunch
-of LCD, but CRT ones. CRT display screen are based on ionic flow started from a cathode (electronic gun) and moving to
-the anode (the screen grid) to excite fluorescent layer in the intern face of the glass bulb.
+And another element must be taken in account: the display process. At this time, screen where not flat one with a bunch of LCD, but CRT ones. CRT display screen are based on ionic flow started from a cathode (electronic gun) and moving to the anode (the screen grid) to excite fluorescent layer in the
+intern face of the glass bulb.
-And swiping the all surface of the screen has a time cost: to display 25 frame per seconds, we need 16ms to swipe a
-frame.
-A CRT tube with its ions gun!The CRT Tube is nothing more than a big bubble light. (3) the cathode emits ions (1) and
-(2) are anodes, deflecting ion ray to screen, lighting a fluorescent dot.
+And swiping the all surface of the screen has a time cost: to display 25 frame per seconds, we need 16ms to swipe a frame. A CRT tube with its ions gun!The CRT Tube is nothing more than a big bubble light. (3) the cathode emits ions (1) and (2) are anodes, deflecting ion ray to screen, lighting a fluorescent dot.
- myself with my own hands !")
+ myself with my own hands !")
_figure 2 - A CRT diagram with ions gun and anodes deflectors_
@@ -48,20 +39,22 @@ So capturing input, moving things and displaying things must be done in 16ms. An
So the game process is a LOOP. that's why we talk about a Main Loop:
- myself with my own hands !")
+ myself with my own hands !")
_figure 3 - The basic Main loop explained with a pencil: the method to keep a fixed frame rate !_
-There is also some advanced version of the Main Loop, where multiple update can be performed between each rendering
-phase, the timer is around the update methods only:
+There is also some advanced version of the Main Loop, where multiple update can be performed between each rendering phase, the timer is around the update methods only:
- myself with my own hands !")
+ myself with my own hands !")
_figure 4 - The advanced method to keep a fixed update rate_
-I can only invite you to read the fantastic book from Robert Nystrom for details about the Main loop.
+I can only invite you to read the fantastic book "Game Programming Pattern" from Robert Nystrom[¹] for details about the Main loop.
-> **Note:** diagram are largely inspired by the Robert Nystrom book, thanks to him to had shared his own knowledge!
+> **Note:** diagram are largely inspired by the Robert Nystrom book, thanks to
+> him to had shared his own knowledge!
Anyway, I need to implement my own. As a good diagram is better than word:
@@ -92,10 +85,12 @@ public class Main {
public void loop() {
while (!isExit()) {
+ // --- simplified version
input();
update();
render();
waitUntilNextFrame();
+ // ---
}
}
@@ -110,45 +105,72 @@ public class Main {
}
```
-So, what do you think of my (too?) basic class ? nothing fancy, nothing "bling bling". only useful and mandatory.
+So, what do you think of my (too?) basic class ? nothing fancy, nothing "bling-bling". only useful and mandatory.
+
+So yes, as you may be now, the game loop is the heart of any old school game, and even some Big game engine keep running such old loop.
-So yes, as you maybe now, the gameloop is the heart of any old school game. and even some Big game engine keep running
-such old loop.
Let's dive into some details.
The Loop is certainly the most important one, so let get some code:
```java
public class Main {
- //...
- public void loop() {
- int frames = 0;
- int fps = getTargetFps();
- double internalTime = 0;
- double previousTime = System.currentTimeMillis();
- double currentTime = System.currentTimeMillis();
- double elapsed = currentTime - previousTime;
- create(this);
- while (!isExitRequested()) {
- currentTime = System.currentTimeMillis();
- input(this);
- elapsed = currentTime - previousTime;
- if (!isPaused()) {
- update(this, elapsed);
- }
- render(this, fps);
- frames += 1;
- internalTime += elapsed;
- if (internalTime > 1000.0) {
- fps = frames;
- frames = 0;
- internalTime = 0;
- }
- waitUntilNextFrame(elapsed);
- previousTime = currentTime;
- }
+ //...
+ public void loop() {
+ int frames = 0;
+ int fps = getTargetFps();
+ double internalTime = 0;
+ double previousTime = System.currentTimeMillis();
+ double currentTime = System.currentTimeMillis();
+ double elapsed = currentTime - previousTime;
+ create(this);
+ while (!isExitRequested()) {
+ currentTime = System.currentTimeMillis();
+ input(this);
+ elapsed = currentTime - previousTime;
+ if (!isPaused()) {
+ update(this, elapsed);
+ }
+ render(this, fps);
+ frames += 1;
+ internalTime += elapsed;
+ if (internalTime > 1000.0) {
+ fps = frames;
+ frames = 0;
+ internalTime = 0;
+ }
+ waitUntilNextFrame(elapsed);
+ previousTime = currentTime;
}
+ }
+
+ default void waitUntilNextFrame(double elapsed) {
+ try {
+ double timeFrame = 1000.0 / getTargetFps();
+ int wait = (int) (elapsed < timeFrame ? timeFrame - elapsed : 1);
+ Thread.sleep(wait);
+ } catch (InterruptedException ie) {
+ System.err.println("error while trying to wait for sometime");
+ }
+ }
+ //...
+}
+```
+
+This implementation of the game-loop is named "Fixed Frame game loop". To maintain a sustainable frequency for that loop, I use the default current traditional FPS: 60 frames per second, this is now an internal configuration:
+```java
+double timeFrame=1000.0/getTargetFps();
+```
+
+> **INFO**
We will discover the configuration mechanism on the 3rd
+> chapter.
+
+So starting with that , defining the waiting time is a simple calculus int the wait method to compute the rest of the timeframe minus elapsed time:
+
+```java
+public class Main {
+ //...
default void waitUntilNextFrame(double elapsed) {
try {
double timeFrame = 1000.0 / getTargetFps();
@@ -157,32 +179,55 @@ public class Main {
} catch (InterruptedException ie) {
System.err.println("error while trying to wait for sometime");
}
- }}
+ }
//...
}
```
-So to maintain a sustainable frequency for that loop, I use the default current traditional FPS: 60 frames per second.
-
-So starting with that , defining the waiting time is a simple calculus.
+and the rest of the loop process is list of calls:
```java
-int timeFrame=1000/60;
- int wait=timeFrame-elapsed;
-```
-
-and the rest of the loop process is simple calls:
+public class Main {
+ //...
+ public void loop() {
+ currentTime = System.currentTimeMillis();
+
+ // (1)
+ input(this);
+ elapsed = currentTime - previousTime;
+ // (2)
+ if (!isPaused()) {
+ update(this, elapsed);
+ }
+ // (3)
+ render(this, fps);
+
+ // compute next wait time until
+ // FPS time frame is reach.
+ frames += 1;
+ internalTime += elapsed;
+ if (internalTime > 1000.0) {
+ fps = frames;
+ frames = 0;
+ internalTime = 0;
+ }
+ waitUntilNextFrame(elapsed);
-```java
-elapsed=currentTime-previousTime;
- input();
- update(elapsed);
- render();
+ previousTime = currentTime;
+ }
+ //...
+}
```
-- input() will manage all the player's device input like keyboard, mouse or joystick,
-- update(elapsed) will compute all the moves and animations for all the game objects,
-- render() will draw the resulting objects and display that on screen.
+1. `input()` will manage all the player's device input like keyboard, mouse or
+ joystick,
+2. `update(long)` will compute all the moves and animations for all the game
+ objects,
+3. `render(Game, long)` will draw the resulting objects and display that on
+ screen.
And when you execute this incredible class… nothing will happen.
-BUT… we now have the framework of our future game. I'm not joking, this is a fact ;)
+BUT… we now have the framework of our future game. I'm not joking, this is a
+fact ;)
+
+[^1]: Game programming Patterns, Robert Nystrom, 2014, Genever Benning, 520 pages - http://gameprogrammingpatterns.com/
\ No newline at end of file
diff --git a/docs/02-adding_entity_and_entitytype.md b/docs/02-adding_entity_and_entitytype.md
index 82f9d80..ee05ccc 100644
--- a/docs/02-adding_entity_and_entitytype.md
+++ b/docs/02-adding_entity_and_entitytype.md
@@ -1,13 +1,26 @@
# Adding Entity and EntityType
-The `Entity` is a class to define all the moving (or not) object on screen.
+The `Entity` is the basics for every object in the game. From the simple spark of fire to the full animated main
+character, all are `Entity`. A `Node` hierarchical tree definition will structure all the Entity in the game.
+
The `EntityType` define the type of rendering and management.
+here is an illustration of the required classes, detailed in the bellow sections.
+
```plantuml
@startuml
!theme plain
+hide Node attributes
+interface Node<>{
+ + getName():String
+ + long getId():long
+ + setParent(T p):T
+ + getParent():T
+ + addChild(T c):T
+ + getChild():List
+}
hide Entity methods
-class Entity{
+class Entity implements Node{
- id:long
- name:String
- x:double
@@ -19,6 +32,8 @@ class Entity{
}
hide EntityType methods
enum EntityType{
+ - DOT,
+ - LINE,
- RECTANGLE,
- ELLIPSE,
- IMAGE
@@ -27,10 +42,91 @@ Entity --> EntityType:type
@enduml
```
-## the EntityType enumeration
+## The Entity class
+
+These entities are defined through a class, grouping all the required attributes to make it movable, drawable as some
+basic geometric shapes or image, and displayed at the right place.
+
+An entity must be identifiable with a unique ID, and for a more common access and retrievable, with a name.
+This ID is auto-generated by an incremental counter, and default name is generated based on this counter, to be sure
+that every Entity is uniquely identified.
+
+```java
+public class Entity {
+ private static long index = 0;
+ private long id = ++index;
+ private String name = "default_" + id;
+
+ EntityType type = EntityType.RECTANGLE;
+ Vector2D position;
+ Vector2D velocity;
+
+ double width = 16, height = 16;
+
+ BufferedImage image = null;
+ Color borderColor = Color.WHITE;
+ Color fillColor = Color.BLUE;
+ int direction = 0;
+
+ private Entity parent;
+ private List child = new ArrayList<>();
+
+ Map attributes = new HashMap<>();
+
+}
+```
+
+The 3 first attributes are managing identifier:
+
+- `index` is the internal static counter of entity generated in the game,
+- `id` is the unique identifier for that new entity, initialized based on the next value of the counter,
+- `name` is the human-readable name, set by default to "default_" + id value;
+
+The 5 next attributes are dedicated to geometric and physic computation:
+
+- `type` is defining the global shape of this entity, (see `EntityType`),
+- `position` a 2D vector defining the position of the entity in the play area,
+- `velocity` a 2D vector to define current velocity on the play area of this entity,
+- `width` and `height` define the size (as a rectangular box) of that entity.
+
+And the next attributes are used for rendering purpose:
+
+- `image` define a `BufferedImage` to be drawn as entity at `position`,
+- `borderColor` is the color used to draw edge of this Entity's shape,
+- `fillColor` is the color defined to fill this shape.
+- `direction` is used to draw image left (<0) or right (=>0) oriented.
+
+As `Entity` can be hierarchically grouped, we need some `Node` management capability.
+The 2 next attributes a dedicated to manage this entity's tree:
+
+- `parent` the parent entity if exists, else null,
+- `child` a list of child Entity linked to this one.
+
+## The Node Interface
+
+A mentioned on the Entity description, a hierarchical tree is used to organize the game entities.
+
+This tree is composed of node. here is the interface to be implemented in the tree nodes:
+
+```java
+public interface Node {
+ String getName();
+
+ long getId();
+
+ T setParent(T p);
+
+ T getParent();
+
+ T addChild(T c);
+
+ List getChild();
+}
+```
-TODO
+These Entity methods are defined to match this interface, based on the 2 attributes `parent` and `child`.
+it will also use `id` and `name`.
-## the Entity class
+## The EntityType enumeration
-TODO
+TODO
\ No newline at end of file
diff --git a/docs/03-configuration.md b/docs/03-configuration.md
index df72fef..2a2febb 100644
--- a/docs/03-configuration.md
+++ b/docs/03-configuration.md
@@ -2,42 +2,46 @@
## Goals
-The COnfiguration principle consists in loading values from a properties file into a map wich keys are enumeratioin entries, and typed values the conversion of properties values into some required objects.
+The `Configuration` principle consists in loading values from a properties file into a map which keys are enumeration
+entries, and typed values the conversion of properties values into some required objects.
## Proposed design
-The enumration entry will be of type :
+The enumeration entry will be of type :
```java
public enum ConfigAttribute {
MY_VALUE(
- "game.phusic.gravity", // the property key entry
- "gravity,g", // the possible CLI arguments (long and short)
- "The gravity value used by physic engine computation and affects every Entity in the World game, defaut is set to no gravity." , // all is in the text ;)
- 0.0, // the default value if no entry provided
- v->Double:valueOf), // the way to parse the string value and convert it to the a required type (thanks to the Java Function interface).
+ "game.physic.gravity", // the property key entry
+ "gravity,g", // the possible CLI arguments (long and short)
+ "The gravity value used by physic engine computation and affects every Entity in the World game, defaut is set to no gravity.", // all is in the text ;)
+ 0.0, // the default value if no entry provided
+ v -> Double::valueOf), // the way to parse the string value and convert it to the required type (thanks to the Java Function interface).
//...
;
}
```
-You can add any other entry in the enum to define new confguration key/values.
+
+You can add any other entry in the enum to define new configuration key/values.
Anatomy of a `ConfigAttribute` enum entry:
-- a `String` fo rthe configuration attribute entry,
+- a `String` for the configuration attribute entry,
- a `coma separated list of String` to define the possible CLI arguments (long and short)
-- a clear and understandable description as a `String` for this configuration entry. this text will be displayed as help when requested.
-- an `Object` instance as a default value (eg.0.0 for a double, "blabla" for a String, ttc...)
-- a Java `Function` implementation to convert the loaded String form an entry in the properties file or the argument value from the command line to the required data type.
+- a clear and understandable description as a `String` for this configuration entry. this text will be displayed as help
+ when requested.
+- an `Object` instance as a default value (eg.0.0 for a double, "blablabla" for a String, ttc...)
+- a Java `Function` implementation to convert the loaded String form an entry in the properties file or the
+ argument value from the command line to the required data type.
-And from the config.propeties file, the corresponding entry :
+And from the `config.propeties` file, the corresponding entry :
```properties
# this configuration key is a double value
game.physic.gravity=0.981
```
-This property value can be overriden through java command line argument:`
+This property value can be overridden through java command line argument:`
```bash
$> java -jar simplegameclass-1.0.jar gravity=0.981
@@ -46,15 +50,19 @@ $> java -jar simplegameclass-1.0.jar gravity=0.981
## File Rules
1. The `config.properties` file is provided as default values for the full game framework in the jar itself.
-2. if a `my-config.properties` is provided in the same location as the JAR file itself, all entries in this properties file will be used to override already defined values by the new provided ones.
-3. As soon a value has been modified through a command line argument a `backup.properties` is saved in the same root path os the jar itself.
+2. if a `my-config.properties` is provided in the same location as the JAR file itself, all entries in this properties
+ file will be used to override already defined values by the new provided ones.
+3. As soon a value has been modified through a command line argument a `backup.properties` is saved in the same root
+ path os the jar itself.
## The `Configuration` service
-The service will provide
-4. all the required default behavior to satisfy the File rules.
+The service will provide
+
+4. all the required default behavior to satisfy the File rules.
5. the required API to let a specific configuration file to be loaded (to be used for unit test purpose)
-6. an entry point to intiialize the internal configuration value object from the file and from the arguments passed from the common Java main method.
+6. an entry point to initialize the internal configuration value object from the file and from the arguments passed from
+ the common Java main method.
### The Configuration class design
@@ -73,31 +81,43 @@ class Configuration {
@enduml
```
-From the command line,
+From the command line,
-7. if an unknown attribute is used, the program exit without execution, but with a clear message giving an error message.
+7. if an unknown attribute is used, the program exit without execution, but with a clear message giving an error
+ message.
8. the user can request to display help for the game arguments with the 'help' or '?' first argument
```bash
$> java -jar simplegameclass-1.0.jar help
```
-9. when the Configuraton properties file is read and parsed, some clear INFO level messages output the detected values for each entry.
-10. If an unkown values is used, the program properly exits without execution, but with a help message giving the error message about the unknown attribute.
+9. when the Configuration properties file is read and parsed, some clear INFO level messages output the detected values
+ for each entry.
+10. If an unknown values is used, the program properly exits without execution, but with a help message giving the error
+ message about the unknown attribute.
-To use an initiazed configruation value :
+To use an initialized configuration value :
```java
-Configuration config = new Configuration(
- "/config.properties",
- new String[]{} );
-
-String windowTitle = config.get(
- ConfigAttribute.WINDOW_TITLE);
+public class Main {
+ public void main(String[] args) {
+ Configuration config = new Configuration(
+ "/config.properties",
+ args);
+ String windowTitle = config.get(ConfigAttribute.WINDOW_TITLE);
+ System.out.printf("title:%s%n", windowTitle);
+ }
+}
```
-for a properties entry like :
+And the default value is set in a properties file entry like :
```properties
game.window.title="My title window"
```
+
+Ok, we now have a very good configuration utility to manage all the future configuration values fo our game framework
+development and its service initialization.
+
+It is now time to move to the [next chapter](04-physic_with_world_and_material.md "Physic with World and Material")
+about Adding some moves and physics computation laws.
\ No newline at end of file
diff --git a/docs/images/figure-crt.jpg b/docs/images/figure-crt.jpg
new file mode 100644
index 0000000..1770fa1
Binary files /dev/null and b/docs/images/figure-crt.jpg differ
diff --git a/docs/images/figure-game-loop-fixed.jpg b/docs/images/figure-game-loop-fixed.jpg
new file mode 100644
index 0000000..f9daa46
Binary files /dev/null and b/docs/images/figure-game-loop-fixed.jpg differ
diff --git a/docs/images/figure-game-loop.jpg b/docs/images/figure-game-loop.jpg
new file mode 100644
index 0000000..79fbbb0
Binary files /dev/null and b/docs/images/figure-game-loop.jpg differ