2

I've got a 2D map, on which entities interact.

Should an entity's position be kept on the map object, or on the entity object itself, or both? Why? What does decide where a property is kept? What questions am I supposed to ask myself when deciding that?

Some use cases are:

  • checking what entities are on a given tile (performant if the entities are kept inside, say, an array on the map object, unperformant if the position is kept on the entity)
  • checking where a given entity is (easy if the position is on the entity instead - the above reversed)

My current thoughts are:

  • the position 'logically' should be kept on the map, because a position is something that just exists within an entity. An entity needs to live in some kind of a spatial space to have a position, and map is such a space.
  • there should be multiple data structures to ease various operations. For example, if entities are kept inside a 2D array, finding where a given entity is would be a linear operation (all cells must be iterated), and, say, a hashmap would bring it down to const time.

2 Answers 2

1

What does decide where a property is kept?

If you're talking about a "property" in a sense that it would be accessible from the outside (via getters or in other ways), then the object-oriented answer is nowhere. Properties are antithetical to object-orientation, specifically to encapsulation.

I will assume you're just talking about internal fields though.

What questions am I supposed to ask myself when deciding that?

The behavior decides, i.e. the use-cases and where those are. Data should always be where the functionality is that uses it, and vice versa.

[...] there should be multiple data structures to ease various operations [...]

I agree, and this is consistent with the above. Seems to me you have a functionality in the map and a functionality in the entities that both require the position, but in their own specialized format.

Therefore, knowing nothing else of your context, I would think having this information on both is reasonable.

Note also, that object-orientation does not require normalized data. Data can (and should) be redundant / denormalized if needed.

3
  • So an Entity might have its move method (let's say, Entities have some 'abilities', and one of them is "jump 2 tiles forward"), as well as the Map might have a move method to move Entities around if needed? This will require every Entity have a reference to the Map, and the Map to refence all the Entities somehow (to update the position in both places). Is this correct? Aren't cyclic references a bad pattern?
    – Sun
    Commented Apr 9, 2021 at 15:58
  • 1
    Yes, cyclic references are bad. However, I didn't say you should have the same behavior on both. You probably want to have one move() only, it doesn't matter on which one. If you absolutely must have it on both, that would mean they are actually both the same "unit". There are ways to do this too, like having the entity be an inner class of the map. Commented Apr 10, 2021 at 10:11
  • It's not strictly the same behavior, but both include changing an entity's position data. Say, the Entity wants to move itself around, while the Map might want to have a behavior that randomly rearranges all Entities that are on it. However, this (I think) requires the Entity to keep a reference to the Map (it needs to know, for example, if the tile it wants to move onto is empty), while the Map must keep a reference to all Entities to be able to call their move method and reorder them - thus we have a cyclic reference, which makes me think my idea is wrong somewhere.
    – Sun
    Commented Apr 10, 2021 at 10:47
0

Rather than store position as x,y values consider a 2D array of references to your entities. Now things are wherever their reference is.

When it's time to blow up whatever's at 2,2 you write code like this:

grid[2,2].blowup(2,2);

Done this way it's polymorphic. The code that knows where neither knows nor cares what's at 2,2. Whatever's there isn't trying to remember where it is. It's getting told. And if it's highly explosive it now knows all it needs to know to blow up everything nearby. And if nothing is there the nothing can quietly do nothing as it's told to blow up.

This also allow things to be immutable even if moved. Moving is just coping a reference. And things can be changed just by writing down a different reference.

Of course you don't have to solve the problem this way. Heck you don't have to use Object Oriented Programming. But since I used this technique to win a chess tournament I feel it's worth mentioning. It's powerful, fast, and easy to read. Made testing easy.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.