Compare commits
No commits in common. "master" and "release" have entirely different histories.
17
README.md
17
README.md
@ -1,12 +1,10 @@
|
||||
# JavaECS
|
||||
An implementation of an Entity-Component-System written in Java.
|
||||
An implementation of a conceptually simple Entity-Component-System written in Java.
|
||||
|
||||
## Introduction to ECS
|
||||
The primary goal of an ECS is to provide fast access to many entities; especially where those entities share many of the same properties. It also solves issues regarding adaptability in an inheritance-based engine.
|
||||
ECS is more of a conceptual idea rather than an actual engine structure. There exists many variations of the concept, each adding in different features and models as required.
|
||||
|
||||
The primary example of an ECS is [EnTT](https://github.com/skypjack/entt), which is used in Mojang's Minecraft.
|
||||
|
||||
There are four key elements to an ECS:
|
||||
1. The **entity**, which is a simple ID, usually an index.
|
||||
2. The **component**, which is a struct or class that stores data
|
||||
@ -16,13 +14,14 @@ There are four key elements to an ECS:
|
||||
## About JavaECS
|
||||
The focus of JavaECS is more about the structure rather than raw performance. It remains performant, but there may be multiple areas where improvements can be made.
|
||||
|
||||
In a quick port of Alex Beimler's [ECS Benchmark](https://github.com/abeimler/ecs_benchmark), JavaECS performs at about the same speed as [ECS](https://github.com/redxdev/ECS) (~90 ms). The results aren't normalised between test environments, so take them with a grain of salt; but it tends to suggest that the project has decent performance.
|
||||
|
||||
This project is inspired by:
|
||||
* [C++ implementation](https://austinmorlan.com/posts/entity_component_system/) by Austin Morlan.
|
||||
* [Nomad Game Engine](https://medium.com/@savas/nomad-game-engine-part-2-ecs-9132829188e5) by Niko Savas
|
||||
* [EntityX](https://github.com/alecthomas/entityx) by Alec Thomas.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
This project is inspired by a C++ implementation by [Austin Morlan](https://austinmorlan.com/posts/entity_component_system/).
|
||||
|
||||
|
||||
## Implementation
|
||||
See the [documentation](https://git.software.kauripeak.co.nz/BrychanD/JavaECS-Docs/wiki) for implementation details
|
||||
See the [documentation](https://git.software.kauripeak.co.nz/BrychanD/JavaECS-Docs/wiki) for implmentation details
|
||||
|
@ -2,7 +2,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>nz.ac.massey.javaecs</groupId>
|
||||
<artifactId>javaecs</artifactId>
|
||||
<version>1.0.1</version>
|
||||
<version>1.0.0</version>
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
|
@ -16,21 +16,22 @@ import java.util.HashMap;
|
||||
/**
|
||||
* Manages the addition, sorting and retrieving of components and component data
|
||||
*/
|
||||
public class ComponentManager{
|
||||
public Map<Type, Map<Entity, Object>> componentArrays = new HashMap<>();
|
||||
class ComponentManager{
|
||||
private Map<Type, Map<Entity, Object>> componentArrays = new HashMap<>();
|
||||
// Need to be able to map bit indices and component types
|
||||
public Map<Integer, Type> indexComponentType = new HashMap<>();
|
||||
public Map<Type, Integer> componentTypeIndex = new HashMap<>();
|
||||
private Map<Integer, Type> indexComponentType = new HashMap<>();
|
||||
private Map<Type, Integer> componentTypeIndex = new HashMap<>();
|
||||
//
|
||||
|
||||
/**
|
||||
* Adds the specified component to the provided entity.
|
||||
* Does not ensure synchronisation with the other managers; ensure this is done!
|
||||
* <p>
|
||||
* Providing a null Object defaults the value to boolean false
|
||||
* @param componentType the class type of the component to add
|
||||
* @param componentData the component data to associate
|
||||
* @param entity the entity to associate data to
|
||||
*/
|
||||
public boolean addComponentToEntity(Type componentType, Object componentData, Entity entity){
|
||||
protected boolean addComponentToEntity(Type componentType, Object componentData, Entity entity){
|
||||
componentArrays.get(componentType).put(entity, componentData);
|
||||
return true;
|
||||
}
|
||||
|
@ -29,8 +29,8 @@ import java.util.HashSet;
|
||||
* Additional functions can be implemented as required.
|
||||
*/
|
||||
public abstract class ECSSystem{
|
||||
public Set<Entity> entities = new HashSet<>();
|
||||
public BitSet registrationSet;
|
||||
protected Set<Entity> entities = new HashSet<>();
|
||||
protected BitSet registrationSet;
|
||||
|
||||
public ECSSystem(){
|
||||
registrationSet = new BitSet();
|
||||
|
@ -151,6 +151,7 @@ public class Engine {
|
||||
int componentIndex = componentManager.getComponentIndex(componentType);
|
||||
if (entityManager.registerComponent(componentIndex, entity))
|
||||
{
|
||||
//systemManager.entityRegistrationAdded(entity, componentIndex);
|
||||
systemManager.entityRegistrationsChanged(entity, entityManager.getRegistrations(entity));
|
||||
componentManager.addComponentToEntity(componentType, component, entity);
|
||||
return true;
|
||||
|
@ -19,17 +19,15 @@ import java.util.ArrayList;
|
||||
* Manages data from the perspective of the entity.
|
||||
* <p>
|
||||
* I.e. Controls adding and removing entities, and registration and deregistration of components.
|
||||
* <p>
|
||||
* Do not update values in this class unless you have reviewed the JavaECS source!
|
||||
*/
|
||||
public class EntityManager{
|
||||
class EntityManager{
|
||||
// According to https://stackoverflow.com/questions/12524826/why-should-i-use-deque-over-stack
|
||||
// ArrayDeque is likely faster than a LinkedList, when used in place of one.
|
||||
// We can also supply a size to the constructor of ArrayDeque, which avoids resizing the collection
|
||||
// at initialisation time (took 1.4s vs 1.8s for 1M)
|
||||
public Deque<Entity> unusedEntities;
|
||||
public List<BitSet> entityRegistrations;
|
||||
public int maxSize = 1024;
|
||||
private Deque<Entity> unusedEntities;
|
||||
private List<BitSet> entityRegistrations;
|
||||
private int maxSize = 1024;
|
||||
|
||||
/**
|
||||
* Initialise the EntityManager with the default max size of 1024
|
||||
@ -65,7 +63,7 @@ public class EntityManager{
|
||||
* @return the index of the new entity
|
||||
* @throws NoSuchElementException an exception if there are no more unused entities
|
||||
*/
|
||||
public Entity addEntity() throws NoSuchElementException{
|
||||
protected Entity addEntity() throws NoSuchElementException{
|
||||
Entity result = unusedEntities.remove();
|
||||
entityRegistrations.set(result.getValue(), new BitSet());
|
||||
return result;
|
||||
@ -107,7 +105,7 @@ public class EntityManager{
|
||||
* @param entity the entity to register
|
||||
* @return true if the operation was successful
|
||||
*/
|
||||
public boolean registerComponent(int component, Entity entity){
|
||||
protected boolean registerComponent(int component, Entity entity){
|
||||
if (entity.getValue() >= maxSize){
|
||||
Engine.writeErr("Attempted to assign a component to non-existent entity: " + entity.getValue());
|
||||
return false;
|
||||
@ -126,36 +124,32 @@ public class EntityManager{
|
||||
/**
|
||||
* Adds the entity index back into unusedEntities, and sets the registrations to null
|
||||
* <p>
|
||||
* <b>Does not handle associated data</b> Use the method in ECS to remove entities cleanly,
|
||||
* or otherwise ensure the component data and systems are updated!
|
||||
* <b>Does not handle associated data</b> Use the method in ECS to remove entities cleanly
|
||||
* @param entity the entity to remove
|
||||
*/
|
||||
public void removeEntity(Entity entity){
|
||||
protected void removeEntity(Entity entity){
|
||||
unusedEntities.add(entity);
|
||||
entityRegistrations.set(entity.getValue(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the entity's registrations to the provided BitSet.
|
||||
* <p>
|
||||
* Does <b>not</b> ensure the systems registrations are updated.
|
||||
* Sets the entity's registrations to the provided BitSet
|
||||
* @param entity the entity to set
|
||||
* @param registrations the preset registrations
|
||||
*/
|
||||
public void setRegistrations(Entity entity, BitSet registrations){
|
||||
protected void setRegistrations(Entity entity, BitSet registrations){
|
||||
entityRegistrations.set(entity.getValue(), registrations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters the specified component from the entity
|
||||
* <p>
|
||||
* <b>Does not handle component data</b> Use the method in ECS to remove components cleanly,
|
||||
* or otherwise ensure the component data and systems are updated!
|
||||
* <b>Does not handle component data</b> Use the method in ECS to remove components cleanly
|
||||
* @param component the component index to remove
|
||||
* @param entity the entity to remove
|
||||
* @return true if successful
|
||||
*/
|
||||
public boolean unregisterComponent(int component, Entity entity){
|
||||
protected boolean unregisterComponent(int component, Entity entity){
|
||||
try{
|
||||
entityRegistrations.get(entity.getValue()).clear(component);
|
||||
return true;
|
||||
|
@ -17,18 +17,16 @@ import java.util.HashMap;
|
||||
/**
|
||||
* Manages system-focused aspects, such as ensuring a system has the correct list of current entities.
|
||||
* Manages registration of new systems
|
||||
* <p>
|
||||
* Do not update data in this class unless you have reviewed the JavaECS source.
|
||||
*/
|
||||
public class SystemManager{
|
||||
public Map<Type, ECSSystem> systems = new HashMap<>();
|
||||
class SystemManager{
|
||||
private Map<Type, ECSSystem> systems = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Signals the SystemManager that an entity was destroyed.
|
||||
* Removes the entity from each system's tracked entities
|
||||
* @param entity the destroyed entity
|
||||
*/
|
||||
public void entityDestroyed(Entity entity){
|
||||
protected void entityDestroyed(Entity entity){
|
||||
// Unlike components, this isn't simply indexed.
|
||||
for (Type key : systems.keySet()) {
|
||||
systems.get(key).entities.remove(entity);
|
||||
|
Loading…
x
Reference in New Issue
Block a user