EntityFactory - GameDevWeek/CodeBase GitHub Wiki

A big problem with so many different people trying to create game content is separation. Usually we had a huge MapLoader class where everybody was contributing to. This was a huge bottleneck and caused lots of problems.

The following helper classes were created to solve this in a generic way.

The concept of this idea

The idea is to have a json file that contains all information needed to create entities using a string identifier. This file will be parsed and when an entity is created that information will be used to call factories to create the entities and components required.

The JSON file

The JSON is a simple map from key to object:

{
	"cookie": {
		"meta": {
			"frequency": 5
		},
		"components": {
			"Position": {},
			"Eatable" : {
				"energy": 10,
				"sound": "eatable_generic"
			},
			"RenderTexture": {
				"image": "eatable_cookie"
			},
			"PhysixBody": { "type": "item", "scale": 18 }
		}
	},
	"muffin": {
...
	}
}

Think of these entity definitions as blueprints for your entities.

Check out a fully featured JSON file here

As you can see, each entity definition object has two members:

  • meta
    • This is a map from key to (int, float, boolean or string)
    • Use it to store information about the entity that does not belong to any component, like spawn-frequency or maybe a description.
  • components
    • This is a map from key to object, where object can contain exactly the same values as meta.
    • Each component to be added can define its construction parameters here.
    • If a component does not need parameters, the object still needs to exist.

The code

Check out fully featured factories here

The EntityFactory parameters

First of all, your component factories might need some parameters to create an entity. These should be inside of a class like this:

public class EntityFactoryParam {
	public float x;
	public float y;
	public Game game;
}

There will be only one class like this, which is passed to every component factory. Some might call this a "context". You can think of it as the parameters you need to create components, like the position where the entity should be spawned or a reference to the game instance.

The EntityFactory

Create these members in your Game class:

private final EntityFactoryParam factoryParam = new EntityFactoryParam();
private final EntityFactory<EntityFactoryParam> entityFactory = new EntityFactory("data/json/entities.json", Game.class);

The second parameter is a class that can be used as a reference to find factories in subpackages. This is done to avoid hardcoded string literals.

Initialize the factory like this:

entityFactory.init(engine, assetManager);

Component Factories

A simple ComponentFactory might look like this: (Remember: This must be publicly available in the same package or a subpackage as the second parameter to the EntityFactory)

public class RenderTextureComponentFactory extends ComponentFactory<EntityFactoryParam> {

	// Return the same string as used in the "components" json map
	@Override
	public String getType() {
		return "RenderTexture";
	}

	// This is called whenever an entity needs a component of this type.
	// @param meta contains the meta properties from the json entity definition
	// @param properties contains the properties from the json component definition
	@Override
	public void run(Entity entity, SafeProperties meta, SafeProperties properties, EntityFactoryParam param) {
		// engine and assetManager are already stored in the super class
		RenderTextureComponent component = engine.createComponent(RenderTextureComponent.class);
		component.texture = assetManager.getTexture(properties.getString("image"));
		assert (component.texture != null);
		entity.add(component);
	}
}

Creating an entity

An entity creation method could look like this:

public Entity createEntity(String name, float x, float y) {
	factoryParam.game = this;
	factoryParam.x = x;
	factoryParam.y = y;
	Entity entity = entityFactory.createEntity(name, factoryParam);

	engine.addEntity(entity);
	return entity;
}