1
\$\begingroup\$

I've been working on a turn based tactics game on a grid. I've been trying to figure out how to store and relate the grid and the objects on it. Essentially, my question boils down to how to ask these two questions without violating the DRY(Don't Repeat Yourself) principle.

  • Given a object, how to get it's position? object.get_pos()
  • Given a cell, how to find out what object is in it? grid.get_cell(cell)

One particular thing I was thinking is that it doesn't make sense to talk about a object independently of the grid it is on. Therefore it seems like each object should have a reference to the grid. But having a grid doesn't make sense unless it has cells that contain objects. Is this just a place where things are tightly coupled enough that this kind of circular reference is acceptable?

\$\endgroup\$
  • \$\begingroup\$ When you say "position", are you referring to the object's grid position, or its position in 2D space? \$\endgroup\$ – driima Oct 13 '15 at 20:41
  • \$\begingroup\$ Grid position. As far as my game is concerned the two are interchangeable \$\endgroup\$ – mklauber Oct 13 '15 at 21:02
2
\$\begingroup\$

I think it makes sense for the two to know about each other. If you want to avoid tight coupling (and there are many good reasons to do so), you could have both the grid and the objects implement interfaces - IGrid and IGridObject, respectively. Then they can only refer to each other by interface, and that breaks the circular reference.

You may want to look into dependency injection (or some other inversion of control technique) and the factory pattern to help you on your way.

\$\endgroup\$
  • \$\begingroup\$ I'm working in python so no strict interfaces, but I'll keep that in mind. (turn based means speed is really not an issue). But I will also look into dependency injection. \$\endgroup\$ – mklauber Oct 13 '15 at 23:28
1
\$\begingroup\$

Circular referencing is usually not a good idea, and it's best to keep the flow in one direction - down. The grid and the objects have a parent-child relationship, whereby the grid is the parent, and the objects are its children. The question you should ask yourself is:

Does the child need to know about or access information about the parent?

Does the object need to know about or access the grid? Typically, only the grid should have knowledge of and be able to access its objects, so it should have functionality to achieve both results:

  • grid.get_object(cell) would return the object that is inside the specified cell.
  • grid.get_cell(object) would return the cell that the specified object is in.
\$\endgroup\$
  • \$\begingroup\$ If I'm inside a unit, how should I get a reference to the grid? For example, I've got code describing a unit's behavior that's attached to a unit, and it needs to know the unit's neighbors. \$\endgroup\$ – mklauber Oct 13 '15 at 23:25
  • \$\begingroup\$ If you need to know the unit's neighbors, you could retrieve the position / cell of the object using grid.get_cell(object), and increment / decrement the appropriate co-ordinates. I have never used python, so I'm speaking strictly in layman's terms as you hadn't specified a language in your question or tags. \$\endgroup\$ – driima Oct 13 '15 at 23:30
  • \$\begingroup\$ The issue I'm having is how to make grid available without making it global. But I think @tandersen's suggestion of dependency injection may solve that. \$\endgroup\$ – mklauber Oct 13 '15 at 23:33
  • \$\begingroup\$ Dependency injection would encourage circular referencing. Read up on Microsoft's documentation about this. \$\endgroup\$ – driima Oct 13 '15 at 23:40
  • \$\begingroup\$ Well, my units need to know what's in various locations on the grid, so they have to know about the grid somehow. What would you recommend? \$\endgroup\$ – mklauber Oct 13 '15 at 23:44
1
\$\begingroup\$

This is a perfect example of DRY being a concept that makes people afraid of making the right decision, in some cases. Here repeating yourself makes sense. Each cell should contain a list of objects in it and each object should contain the cell it is in. You will want both to correctly perform queries and operations. For example: given a list of common unit types, find all the cells they are in, or given a cell, find all the units in the surrounding grid cells. The key is to centralize the setting of these values in such a way that they are always synchronized. Using debug asserts in various places to confirm this is true is good engineering practices.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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