I've been working on a several simple games, and I've always come to a decision point where I have to choose whether to have the Level object as an attribute of the Player class or the Player as an attribute of the Level class.

I can see arguments for both:

The Level should contain the player because it also contains every other entity. In fact it just makes sense this way: "John is in the room." It makes it a bit more difficult to move the player to a new level, however, because then each level has to pass its player object to an upcoming level.

On the other hand, it makes programming sense to me to leave the player as the top-level object that is persistent between levels, and the environment changes because the player decides to change his level and location. It becomes very easy to change levels, because all I have to do is replace the level variable on the player.

What's the most common practice here? Or better yet, is there a "right" way to architecture this relationship?

  • \$\begingroup\$ Create something like a "player character" on every level. State you want to copy from one level to another, e.g. score, probably shouldn't be inside the player in the first place. \$\endgroup\$ – Markus von Broady Oct 11 '12 at 18:09
  • \$\begingroup\$ What if I wanted to maintain player state, eg. HP? \$\endgroup\$ – Thane Brimhall Oct 11 '12 at 19:17
  • \$\begingroup\$ You're right, in the end you would probably end moving everything outside the level listening to my above advice. \$\endgroup\$ – Markus von Broady Oct 11 '12 at 19:50
  • \$\begingroup\$ How would you support multi-player functionality, if you assume that a single 'Player' owns all the important game details? \$\endgroup\$ – Kylotan Oct 11 '12 at 20:10
  • 1
    \$\begingroup\$ It was more of a hypothetical situation to show that Level data is not part of a single player in any sense. But given your comment here, I no longer know what you're trying to ask! \$\endgroup\$ – Kylotan Oct 11 '12 at 22:51

There is another option. The player and the level are both members of the game object.

However, I think the most common practice is to make the player an object inside the level. This has numerous benefits. For example, the level will process collisions between objects. Adding all the objects into the same level pool allows you to reuse the collision code with the player object too. It allows the player object to more easily interact with other objects in the level. The code you use for moving the player from one level to another could also be used for moving other game objects from one level to another. And so on and so on.

I don't think "because it's a little more difficult" is a good enough reason to break the common object oriented structure.

It's good to follow the standard structure even when you're the only one working on the code. Easy to understand and expected code structure is crucial if you were to ever have someone else work on your code. Keep in mind, that "someone else" could be you a few years from now when you're looking back at your code and wondering what the heck you were doing.

  • 1
    \$\begingroup\$ Excellent answer, clear and concise. +1 especially because you mention to do what's expected, even if it's a little more difficult; maintainable code is really important! \$\endgroup\$ – Thane Brimhall Oct 11 '12 at 19:32

There's certainly no "right" way to approach this problem, but there are better ways based on software engineering guidelines and principles. From what you've described, I'd approach the problem this way:

A level contains a set of agent objects that exist within the level. Agents could be any kind of character or other entity, player-controlled or not.

The player object deals with the actual human player sitting at the keyboard, things like score, name, lives left, et cetera. It might also (directly or indirectly via another interface) manage the transformation of keyboard or controller input into in-game responses, and it can accomplish this by maintaining a reference to the currently-controlled agent in a level.

In this fashion the level object and the player object don't actually know about each other directly at all; the level just knows it deals with a bunch of agents, and the player knows it deals with one particular agent that is the one the player is directly controlling right now.

There are three key principles at work here:

  1. Minimizing the responsibilities of an interface. In an ideal world, an interface would have but one task.
  2. Aggregation of functionality rather than inheritance. Instead of having the player be an agent, the player contains a reference to an agent it controls. This tends to also help you adhere to the idea that an inherited interface should be substitutable with its base interfaces, because a player probably does a lot more things, and a lot differently, than any other actor in the game.
  3. Logical lifetime separation. As you note, the player should persist outside the lifetime of the actual level, so while it would be okay for a player to refer to a "current level" much like the player could refer to the "currently controlled agent," you don't want the opposite where the player is potentially destroyed when the level is, thus requiring a complicated process of serializing and deserializing transferrable state between levels.
  • \$\begingroup\$ So, if I understand correctly, you suggest separation of the player object (persistent) and the player's entity (created on creation of level), correct? \$\endgroup\$ – Thane Brimhall Oct 11 '12 at 19:26
  • 1
    \$\begingroup\$ Yes. You can include metadata of some sort in the level to tag an entity as "default player" if you want. One of the interesting advantages this approach is that it lets you easily take control of any other entity on the map. \$\endgroup\$ – user1430 Oct 11 '12 at 19:50

I want to emphasize that there are many ways to solve this and that you shouldn't fool yourself into believing that one size fits all with this problem.

This is a little subjective and anecdotal from my own game, but here's how I view it. The world (level) and the beings that populate it (entities) are separate "things". That is, entities still exist even if the world doesn't and vice versa (ignoring realism for the sake of argument).

That said, I tend to structure my object "ownership" in terms of a hierarchy of what populates what. For example, while the world doesn't own the player (or any other entity), the player does populate the world and is subject to its rules. A player (and other entities) in my game are managed by a third party. This third party extracts necessary data from both the level and the player when they need to interact (collisions, events, etc...).

So really that was a long winded way of saying that another option is to do neither of your suggestions.


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.