Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
Tags

Finally had some time to work on this again (Christmas is busy when you and your GF have big families :D )!

I've read numerous times that using entity systems when programming a game leads to a better code than e.g. object oriented design more often that not. I know the "rules for jamming" say to not clean up / optimize your code during the jam because of the tight time frame but I'm here to learn something and try out stuff and hopefully create a small fun game in the process so I decided to try out Ashley. In this devlog entry I will shortly discribe what it took me to use Ashley to do the physics simulation in its systems (while still using Box2D).


At first a small look how the code for the physics worked before:

There were two arrays with Box2D Fixtures: one for stationary planets and one for moving bodies. The Fixtures were created like this:

private Fixture createPlanet(float x, float y, float radius) {
  BodyDef bodyDef = new BodyDef();
  bodyDef.position.set(scaleDown(x), scaleDown(y));
  bodyDef.type = BodyDef.BodyType.StaticBody;
  Body body = world.createBody(bodyDef);
  FixtureDef fixtureDef = new FixtureDef();
  CircleShape shape = new CircleShape();
  shape.setRadius(scaleDown(radius));
  fixtureDef.shape = shape;
  fixtureDef.restitution = 0;
  fixtureDef.friction = 0;
  fixtureDef.filter.maskBits = 0;
  return body.createFixture(fixtureDef);
}

The moving bodies had almost the same code, but using

bodyDef.type = BodyDef.BodyType.DynamicBody;

and a fixed radius.

Planets could be created with

planets.add(createPlanet(320, 360, 20));

and the moving bodies could be created with

bodies.add(createBody(640, 360));

The growing of the planets was handled in the render() method like this:

if (Gdx.input.isTouched()) {
   int x = Gdx.input.getX();
   int y = 720 - Gdx.input.getY();
   for (Fixture f : planets) {
      Vector2 position = f.getBody().getPosition();
      float radius = f.getShape().getRadius();
      if (x > scaleUp(position.x) - scaleUp(radius) && x < scaleUp(position.x) + scaleUp(radius)  && 
          y > scaleUp(position.y) - scaleUp(radius) && y < scaleUp(position.y) + scaleUp(radius)) {
         f.getShape().setRadius(radius + scaleDown(1));
      }
   }
}

The physics calculation was done in the applyForces() method that also was called from render(). It applied a linear impules from every planet to every body based on a constant force (here 50), the planet's radius and the delta time:

private void applyForces(float delta) {
   for (Fixture body : bodies) {
      for (Fixture planet : planets) {
         Body bodyBody = body.getBody();
         Body planetBody = planet.getBody();
         Vector2 distance = new Vector2(planetBody.getPosition()).sub(bodyBody.getPosition());
         distance.nor();
         float force = 50;
         distance.x = distance.x * planet.getShape().getRadius() * force * delta;
         distance.y = distance.y * planet.getShape().getRadius() * force * delta;
         bodyBody.applyLinearImpulse(distance, bodyBody.getLocalCenter(), true);
      }
   }
}

The full source file can be found here.

That's a small and little proof of concept for something based around orbital physics. Now let's "port" it to Ashley :)


At first Ashley is needed as dependency, I ticked the Ashley checkbox in the libGDX setup tool so it's automatically there for me, but adding Ashley to the project afterwards is very easy and described here.

At first I needed to think about which entities, components and systems I would need. The entities are easy: One entity for a (stationary) planet that has gravity and one entity for the dynamic body that the planets play with. as for the components I went with the same approach - one DynamicBodyComponent that has a dynamic Box2D Fixture and one PlanetComponent that has a static Box2D Fixture. The body entity will have the DynamicBodyComponent and the planet Entity will have the PlanetComponent.

Components are just value classes without any logic and Entities are just bags with components - for behavoir I needed Systems. The first system is the GravitySystem that takes the logic that was in applyForces() and applies it to the Correct components. It has an array of all DynamicBodyComponents and another array with all PlanetComponents that are registered to the engine. In the update() method it does exaclty the same thing that was done in applyForces() - the code is even copy pasted, the only thing I needed to change was instead of getting the Fixture from the Fixture array I needed to get the Entity from the EntityArray, get the correct Component from the Entity and then get the Fixture from the Component. That's how the method looks now:

@Override
public void update(float deltaTime) {
   for (Entity body : dynamicEntities) {
      for (Entity planet : planets) {
         Body bodyBody = body.getComponent(DynamicComponent.class).fixture.getBody();
         Body planetBody = planet.getComponent(PlanetComponent.class).fixture.getBody();
         Vector2 distance = new Vector2(planetBody.getPosition()).sub(bodyBody.getPosition());
         distance.nor();
         float force = 50;
         distance.x = distance.x * planet.getComponent(PlanetComponent.class).fixture.getShape().getRadius() * force * deltaTime;
         distance.y = distance.y * planet.getComponent(PlanetComponent.class).fixture.getShape().getRadius() * force * deltaTime;
         bodyBody.applyLinearImpulse(distance, bodyBody.getLocalCenter(), true);
      }
   }
}

I also needed to override addedToEngine() and update the Entity arrays in the system every time a new entity was added. That's how the whole class looks now.

I created another System to move expanding the planets away from the render() method, the code is basically copy-pasted without any changes, you can find it here.

So I have Components and I have Systems that do stuff with the components now - what next?

  1. Setup the Ashley-Engine
  2. Register the Systems
  3. Create Entities with the components!

The first and second steps are veeeery easy:

engine = new Engine();
engine.addSystem(new GravitySystem());
engine.addSystem(new InputSystem());

The third step is also pretty easy: I went into createPlanet() and createBody(), changed the signature from Fixture to void (since we don't need to put the Fixtures into arrays anymore) and instead of returning the created fixture I now create a new Entity, put the Fixture into its Component and register the Entity to the System:

Fixture fixture = body.createFixture(fixtureDef);
Entity entity = new Entity();
PlanetComponent component = new PlanetComponent(); //for planets, DynamicComponent for bodies
component.fixture = fixture;
entity.add(component);
engine.addEntity(entity);

The very last step is to add

engine.update(delta)

to render() and it works! Technically everything works exactly like before but now I have nice separation of concerns thanks to Entities, Components and Systems!

If you would like to look at the source at GitHub:

If any of you has any questions, feel free to contact me. Also if there is something I am doing really wrong (except for messy code, I know about that :D) feel free to point it out (as in "constructive criticism")!