Compare commits
6
Commits
02aa0891cb
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2405f1fb53 | ||
|
|
5a3e3a33fc | ||
|
|
0bc67fe87b | ||
|
|
e00558937a | ||
|
|
6aab0ee986 | ||
|
|
2bc53528d0 |
@@ -4,63 +4,66 @@
|
||||
### [View the Documentation](./docs/overview.md)
|
||||
|
||||
## *About Entity-Component-Systems*
|
||||
An Enity-Component-System comprises of four main parts
|
||||
1. The [entity](./docs/entity/Entity.md) which is essentially just a unique ID *i.e. an integer value*
|
||||
2. The [component](./docs/entity/Component.md) which is a `struct` (`class` in Java). Typically contains data, but can be empty (to be used as a flag for certain systems) or contain function definitions.
|
||||
3. The [system](./docs/system/System.md) which defines two main functions: `init()` and `update()`. Systems define a filter that is used to maintain a current and relevant list of entities that the system will act on.
|
||||
4. The [engine](./docs/Engine.md), which ties everything together. It exposes the functions that should be called, and methods for retrieving data correctly. The initialisation of everything required also takes place here
|
||||
|
||||
Traditional game-engine designs typically follow the standard functional or object-oriented design paradigms.
|
||||
This choice of paradigm is as important as it is in typical applications.
|
||||
## About the implementation
|
||||
The JavaECS project is a Maven project targeting Java SE 1.8.
|
||||
It is released under the MIT licence.
|
||||
It is intended to be compiled and packed into a `.jar` and referenced and imported into a project.
|
||||
The Maven build script will produce a `javadoc` `.jar` with the library.
|
||||
|
||||
A functional-paradigm game usually focuses on a 'this-then-that' model, e.g.:
|
||||
## Getting started with JavaECS
|
||||
Initialise the library like so:
|
||||
``` java
|
||||
Engine gameEngine = new Engine(/* desired number of entities */);
|
||||
```
|
||||
Next, the known components should be added.
|
||||
|
||||
***Simple Driving Game***
|
||||
|
||||
``` py
|
||||
turn = GetTurn()
|
||||
TurnCar(turn)
|
||||
if IsCollided(): # and other checks
|
||||
GameOver()
|
||||
else:
|
||||
DrawNextFrame()
|
||||
turn = GetTurn()
|
||||
Use the reflective component type:
|
||||
``` java
|
||||
gameEngine.registerComponent(ExampleComponent.class);
|
||||
```
|
||||
|
||||
Such a system works well for some game-designs; it is simplistic and follows a deterministic sequence of steps. But it lacks scalability and extensibility.
|
||||
|
||||
An Object-Oriented approach could be used instead:
|
||||
``` py
|
||||
# Create a base-class that is a vehicle, with basic properties:
|
||||
class Vehicle:
|
||||
position = [x,y]
|
||||
IsCrashed = False
|
||||
def CalcTurn():
|
||||
pass
|
||||
def IsCollided():
|
||||
pass
|
||||
|
||||
# Create the PlayerVehicle class which extends Vehicle to include the player input method
|
||||
class PlayerVehicle(Vehicle):
|
||||
def GetPlayerInput():
|
||||
pass
|
||||
|
||||
def GameLoop():
|
||||
vehicles[] = GetAllVehichles()
|
||||
allCollided = False
|
||||
while not allCollided:
|
||||
for v in vehicles:
|
||||
turnAmount
|
||||
if v is PlayerVehicle:
|
||||
turnAmount = v.GetPlayerInput()
|
||||
else:
|
||||
turnAmount = v.CalcTurn()
|
||||
v.TurnVehicle()
|
||||
if v.IsCollided():
|
||||
v.IsCrashed = True
|
||||
anyNotCollided = False
|
||||
for v in vehicles:
|
||||
if v.IsCrashed = False:
|
||||
anyNotCollided = True
|
||||
break
|
||||
Next, register the systems that are required.
|
||||
Each system must be constructed, and passed as a parameter to the Engine.
|
||||
- *If the system shall be invoked elsewhere, then you can petition the engine for the instance of the system.*
|
||||
``` java
|
||||
ExampleSystem exampleSystem = new ExampleSystem(gameEngine);
|
||||
gameEngine.registerSystem(ExampleSystem.class, exampleSystem);
|
||||
```
|
||||
|
||||
Which allows the instancing of objects. Each action also results in an objective state, which can be simply compared to determine the result.
|
||||
Next, create the entities that are needed as required.
|
||||
``` java
|
||||
Entity newEntity = gameEngine.createEntity();
|
||||
```
|
||||
|
||||
ECS are typically built on object-oriented ideas, but make specfic attempts to reduce overheads that come from object-oriented ideas.
|
||||
The primary reduction made in ECS is to eliminate or otherwise minimise inhertance cycles to reduce the amount of virtual calls required.
|
||||
Assign the components to the entity:
|
||||
``` java
|
||||
gameEngine.addComponent(newEntity, ExampleComponent.class, new ExampleComponent());
|
||||
```
|
||||
|
||||
Be sure to call `init()` on each system, before the logical loop of the program
|
||||
``` java
|
||||
exampleSystem.init();
|
||||
```
|
||||
|
||||
Finally, the engine is ready to enter the logical loop, e.g.:
|
||||
``` java
|
||||
while (true){
|
||||
exampleSystem.update();
|
||||
}
|
||||
```
|
||||
* note systems are *not* required to perform their `update()` in the normal logical loop.
|
||||
* the update can also be performed at a factored rate. E.g. physics can be performed at a different rate to the renderer, in order to improve physics accuracy
|
||||
* when using your own implmentation of a system, you may leave `init()` empty. Therefore, it isn't necessary to call `init()` before the game loop. **However**, It is recommended that you call `init()` to maintain consistency with all systems in the engine.
|
||||
* Entities, components, and systems can be created at any time in the program lifecycle.
|
||||
* Entities can be destroyed.
|
||||
* Components and systems cannot be destroyed.
|
||||
* Be aware that component registrations are contained via [BitSet](https://docs.oracle.com/javase/8/docs/api/java/util/BitSet.html). As the array is extended as bits are needed, note that the order of the set bits may impact performance with a large number of component types.
|
||||
|
||||
### Example:
|
||||
[App.java](/BrychanD/JavaECS-Examples/src/branch/master/demo1/src/main/java/nz/ac/massey/javaecs/examples/App.java#line=12-128)
|
||||
|
||||
+18
-3
@@ -7,14 +7,19 @@
|
||||
background-color: #383c4a;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/css/index.css">
|
||||
<link rel="stylesheet" href="/css/theme-night-sky.css">
|
||||
|
||||
<script>
|
||||
const queryString = window.location.search;
|
||||
const queryLoc = window.location.origin;
|
||||
const queryRequest = window.location.href.split('?')[0];
|
||||
const windowLoc = window.location.toString();
|
||||
console.log(queryString);
|
||||
const urlParams = new URLSearchParams(queryString);
|
||||
const requestURL = urlParams.get('url')
|
||||
const selector = urlParams.get('selector')
|
||||
var pageLink;
|
||||
// Fetch the content
|
||||
fetch(queryLoc + requestURL)
|
||||
.then(function (data) {
|
||||
@@ -27,20 +32,30 @@
|
||||
// Select the correct container
|
||||
var htmlTrimmed = doc.querySelector(selector);
|
||||
if (htmlTrimmed) {
|
||||
htmlTrimmed = htmlTrimmed.parentElement;
|
||||
/*
|
||||
var styleSheets = doc.querySelectorAll("link");
|
||||
for (var i = 0; i < styleSheets.length; i++) {
|
||||
document.head.appendChild(styleSheets[i]);
|
||||
}
|
||||
} */
|
||||
// Fetch and refactor links, to use this html doc where appropriate
|
||||
document.title = doc.title;
|
||||
var hlinks = htmlTrimmed.querySelectorAll("a");
|
||||
for (var i = 0; i < hlinks.length; i++) {
|
||||
if (hlinks[i].href.replace(queryLoc, "").startsWith("/")) {
|
||||
// Replace either http://<somehost>/<somedoc> or http://<somehost> with "" so that:
|
||||
// 1.) links to elements on the same page work
|
||||
// 2.) disable cross-origin requests
|
||||
var fixedURL = hlinks[i].href.replace(window.location, "").replace(queryLoc, "")
|
||||
var fixedURL = hlinks[i].href.replace(windowLoc.split('#')[0], "").replace(queryLoc, "")
|
||||
// If the remaining character is the hash, this is a same-page section link
|
||||
if (fixedURL.startsWith("#")) {
|
||||
// There are two cases here;
|
||||
// 1.) The hash-url is just a typical page-link
|
||||
// 2.) The hash-url is a page content reference
|
||||
if (fixedURL.contains("#page=")) {
|
||||
pageLink.add(fixedURL);
|
||||
|
||||
}
|
||||
else if (fixedURL.startsWith("#")){
|
||||
fixedURL = requestURL + fixedURL;
|
||||
}
|
||||
// selector is the selector used to select the element. Use body if the whole page is required
|
||||
|
||||
@@ -18,7 +18,7 @@ Before attempting to use a system, it must be registered.
|
||||
|
||||
Registration requires a call to `registerSystem(String systemName, ECSSystem system)`, with params of the `String name` and a object reference of the [ECSSystem](./ECSSystem.md). Using the object reference, a system can be invoked at any time.
|
||||
|
||||
See [EntityManager.java](/BrychanD/JaveECS/src/branch/master/javaecs/src/main/java/nz/ac/massey/programming_project_159333_s1_2021/EntityManager.java)
|
||||
See [EntityManager.java](/BrychanD/JaveECS/src/branch/master/javaecs/src/main/java/nz/ac/massey/javaecs/EntityManager.java)
|
||||
|
||||
## Constructors
|
||||
``` java
|
||||
|
||||
Reference in New Issue
Block a user