Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvement: Make manual creation of Mappers obsolete #64

Closed
Marty opened this issue Dec 29, 2022 · 1 comment
Closed

Improvement: Make manual creation of Mappers obsolete #64

Marty opened this issue Dec 29, 2022 · 1 comment

Comments

@Marty
Copy link

Marty commented Dec 29, 2022

I made the manual creation of Mappers in my project obsolete.
It works nicely for me that way but it would be better suited in the library itself.

The MapperSystem holds a Map with the mappers by type.
This does not need to be a system and could be integrated in World.

class MapperSystem extends VoidEntitySystem  {
  final Map<Type, Mapper> _mappers = {};

  Mapper<T> mapper<T extends Component>() {
    return _mappers.putIfAbsent(T, () => Mapper<T>(world)) as Mapper<T>;
  }

  @override
  void initialize() {
  }

  @override
  void processSystem() {
  }
}

To access this conveniently, I have two extensions:

extension MapperSystemExtension on EntitySystem {
  T? getComponent<T extends Component>(int entity) {
    return world.mapper<T>().getSafe(entity);
  }

  bool hasComponent<T extends Component>(int entity) {
    return world.mapper<T>().has(entity);
  }
}

extension MapperWorldExtension on World {
  Mapper<T> mapper<T extends Component>() {
    return getSystem<MapperSystem>().mapper<T>();
  }

  T? getComponent<T extends Component>(int entity) {
    return mapper<T>().getSafe(entity);
  }
}

It can then be used like this:

var position = getComponent<Position>(entity)!;

A nice sideeffect that I did not think of prior is, that you can easily navigate to the Component in question (in this case Position) without jumping to the definition of the mapper first. I find myself using that quite often.

Do you see any downsides to this?
I'd be happy to create a PR :)

@denniskaselow
Copy link
Owner

denniskaselow commented Dec 29, 2022

Hot damn. That looks great.

If you can get the tests to work despite #60 then go ahead with your PR.

Though I would prefer it if the getComponent method returns a T instead of a T? and used the [] operator instead of getSafe. And return T? with a getOptionalComponent that uses OptionalMapper. Or is there a reason you are doing it your way?

The only downsides I can think of at the moment (but they are negligible because you can still use the manual/generated way depending on your personal preferences):

  • it could be a (very low key) performance issue in EntityComponentSystems when iterating over a lot of entities and each time getting all required mappers by accessing a map, especially in systems that don't do much else (but overall it should be very minuscule and ignorable because you usually do a lot more)
  • it's a bit more typing when accessing a component (with IDE and content assist) pos ctrl+space enter [entity]; vs getC ctrl+space enter <Position>(entity); but that's just lazy me and I've removed that part for me a different way.

I am so used to dartemis_builder I never create my mappers manually anyway. I don't know if you have looked at it, but with it a MovementSystem would look like this, and there would be no need to create or access mappers:

@Generate(
  EntityProcessingSystem,
  allOf: [
    Position,
    Velocity,
  ],
)
class SimpleMovementSystem extends _$SimpleMovementSystem {
  @override
  void processEntity(int entity, Position position, Velocity velocity) {    
    position
      ..x += velocity.x * world.delta
      ..y += velocity.y * world.delta;
  }
}

EDIT: Oh, I see I need to update the dartemis readme with this example.

@denniskaselow denniskaselow closed this as not planned Won't fix, can't repro, duplicate, stale Mar 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants