Author Topic: pedantic object oriented question  (Read 68021 times)

naughty

  • Rogueliker
  • ***
  • Posts: 59
  • Karma: +0/-0
    • View Profile
Re: pedantic object oriented question
« Reply #45 on: April 13, 2013, 09:25:55 PM »
I have entities with move as a member function, and it basically delegates to the map to do the physical moving, but then the entity can override the virtual move function to do something before or after the move, while if you have a monolithic move function for the map, handling pre-post ops on a type by type basis gets nuts.

I don't think having 'move' owned by the map is wrong per se but I think you can make a stronger argument for something like eclectocrat's design here.

The sky won't fall down whichever way you do it, unless the codebase or the game gets a lot more complicated.

First off why do you need lots of different pre and post steps for movement? I would be quite worried if that happened because it means you derive a new critter class just to get a new kind of movement. If your game does have a lot of very different forms of movement you should be abstracting that out of the critter anyway, e.g. into a hierarchy of movement objects. (I'm assuming that like in most games critters are not uniquely determined by their style of movement.)

If you don't factor it out and you have another method/behaviour on the critter that can vary, an attack() method say, then you could be for a right pain in arse. You only need 3 types of movement and 3 types of attack to lead to 9 different classes you could have to write. Of course you could make a faustian pact and use multiple inheritance but possibly reduce the amount of code you write at the cost of you sanity.

It would be easier to factor both movement and attacking out into their own objects or hierarchies (thereby turning a N*M problem into an N+M problem). This also has the nice side effect of being far easier to make data driven (so new critter types can be added without writing code).

The oft quoted slogan of 'favour composition over inheritance' essentially means that the ideal number of critter classes is one. It's also motivated by very similar arguments to those presented above.

So if you have a small numbers of methods/verbs you won't really feel the pain but I've worked on RTSs where the number of combinations got quite large and the 'critter move' solution writ large led to loads of issues. Once we changed to the compositional system (and put 'move in the map') for the subsequent game it all went a lot more smoothly.

george

  • Rogueliker
  • ***
  • Posts: 201
  • Karma: +1/-1
    • View Profile
    • Email
Re: pedantic object oriented question
« Reply #46 on: April 13, 2013, 09:49:56 PM »
A components system does the same work here as a virtual move method on the thing, the point is you specialize the behavior on the thing and not in the map's move function.

naughty

  • Rogueliker
  • ***
  • Posts: 59
  • Karma: +0/-0
    • View Profile
Re: pedantic object oriented question
« Reply #47 on: April 13, 2013, 10:23:07 PM »
A components system does the same work here as a virtual move method on the thing, the point is you specialize the behavior on the thing and not in the map's move function.

No one's saying you should specialise in the map move method based on critter type. The point is that there's either only one move method on the critter or it would most likely be abstracted out and therefore not be 'in' the critter.

You're going to need a move method on the map anyway (unless the critter is allowed to access private state of the map) and the critters (or one of it components or otherwise associated objects) will end up having to call it.

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: pedantic object oriented question
« Reply #48 on: April 14, 2013, 07:18:29 PM »
I think using the word 'Map' is kind of naive. What you're talking about are game states.

  • Critter polls game state to determine which of its behaviors is ideal.
  • Critter informs game state of its behavior, game state provides available moves and heuristic weights.
  • Critter tells state where it wants to move and state updates to a new state.

Doesn't matter where 'move' is located, so long as information is passed and evaluated accordingly.

I think this gets silly though. I prefer that neither my entities nor my states have any methods at all- they're really just tables of data that get worked on by different systems. A system is just a procedure that reads and updates the state based upon a specific subset of salient properties among entities. A system can look at the game state and the state of an entity and evaluate which state it should be in without any silly messaging schemes.

Ex

  • IRC Communications Delegate
  • Rogueliker
  • ***
  • Posts: 313
  • Karma: +0/-0
    • View Profile
Re: pedantic object oriented question
« Reply #49 on: April 14, 2013, 08:12:34 PM »
I think using the word 'Map' is kind of naive.
Have you looked at the source for many video games? Try Crawl, Nethack, Angband, Doom, Wolfenstein, or Quake some time.

eclectocrat

  • Rogueliker
  • ***
  • Posts: 81
  • Karma: +0/-0
  • Most of your personality is unconscious.
    • View Profile
    • Mysterious Castle
    • Email
Re: pedantic object oriented question
« Reply #50 on: April 14, 2013, 08:20:06 PM »
I have entities with move as a member function, and it basically delegates to the map to do the physical moving, but then the entity can override the virtual move function to do something before or after the move, while if you have a monolithic move function for the map, handling pre-post ops on a type by type basis gets nuts.

I don't think having 'move' owned by the map is wrong per se but I think you can make a stronger argument for something like eclectocrat's design here.

The sky won't fall down whichever way you do it, unless the codebase or the game gets a lot more complicated.

First off why do you need lots of different pre and post steps for movement? ...

Sorry I kind of stopped taking it seriously there, questions such as these raise major red flags for me. This is why I never ask python questions on stack overflow. The whole "why would anyone ever want to...?" thing is just anathema to making positive progress, imho. No offence dude, the rest of your post contained good engineering points.

Slightly OT, I remember discussing boost::shared_ptr when it was being migrated to tr1 and they were not sure what to do with the thread safety/locking template parameter that came after the primary pointer type. The apparent problem was that the combinations of template parameters would create a combinatorial explosion of complexity that would make it very hard to assign pointer to each-other in safe ways. My question was why even force them to be compatible? Why not just say that any pointer can only be compatible with other pointers with the same thread-safety/locking policy? I never really got an answer to that. I usually like to avoid complexity, because the problem space will provide enough without you adding in heaps of your own.

Anyways, I agree with the sky not falling regardless of which method you ultimately use. In my experience, the surest way to have clean code is to review regularly and take the time to care after corner cases. If you do that, then either way is just fine... (unless you are writing nuclear reactor controllers, cmon this is a roguelike board!)

naughty

  • Rogueliker
  • ***
  • Posts: 59
  • Karma: +0/-0
    • View Profile
Re: pedantic object oriented question
« Reply #51 on: April 14, 2013, 09:20:46 PM »
...

First off why do you need lots of different pre and post steps for movement? ...

Sorry I kind of stopped taking it seriously there, questions such as these raise major red flags for me. This is why I never ask python questions on stack overflow. The whole "why would anyone ever want to...?" thing is just anathema to making positive progress, imho. No offence dude, the rest of your post contained good engineering points.

Looking back over the post that sentence does seem more abrasive than I'd like in hindsight. It would be wrong to back and edit it but if I could I'd probably write something like "What kind of things are you doing in the pre and post operations?"

I am genuinely interested in the possible use-cases of lots of different pre and post operations to movement though. It's  possible that it could be something not covered by the text succeeding the offending sentence.

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: pedantic object oriented question
« Reply #52 on: April 14, 2013, 10:01:03 PM »
I think using the word 'Map' is kind of naive.
Have you looked at the source for many video games? Try Crawl, Nethack, Angband, Doom, Wolfenstein, or Quake some time.

Old games used naive nomenclature. So what? Are we talking about topology, game states, the systems that manages the relationships between entities, or just an arrangement of entities? A monolithic 'Map' object for doing all of those things is naive.

naughty

  • Rogueliker
  • ***
  • Posts: 59
  • Karma: +0/-0
    • View Profile
Re: pedantic object oriented question
« Reply #53 on: April 15, 2013, 07:52:24 AM »
requerent: by game-state do you mean something roughly like the 'model' in something like MVC? For example:

Code: [Select]
struct GameState {
    Entity entities[...];
    Terrain cells[...][...];
    Gas gasLayer[...][...]; // For area of effect spells or gases like in Brogue.
};

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: pedantic object oriented question
« Reply #54 on: April 15, 2013, 05:16:05 PM »
A game state is just a discrete representation of all salient data within the game. It's very useful to have these as separate data structures so that you can easily generate trees and search them, save them, or hash and mask them for networking.

requerent: by game-state do you mean something roughly like the 'model' in something like MVC? For example:

Code: [Select]
struct GameState {
    Entity entities[...];
    Terrain cells[...][...];
    Gas gasLayer[...][...]; // For area of effect spells or gases like in Brogue.
};

That's incomplete. You'll need the Tick number and you need the seed in there to accurately replicate the state in Brogue. We also need to know whose turn it is- since we may be using states to search the state space to analyze what the best moves for a group of enemies may be.


It is an MVC model so long as each entity has a controller.

naughty

  • Rogueliker
  • ***
  • Posts: 59
  • Karma: +0/-0
    • View Profile
Re: pedantic object oriented question
« Reply #55 on: April 15, 2013, 09:50:55 PM »
Aye I've seen that in Quake3 (much cleaner in concept than implementation) and pretty much all games written in functional languages. Must admit it is a lot nicer to do the networking for that kind of structure.

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: pedantic object oriented question
« Reply #56 on: April 16, 2013, 01:00:44 AM »
Aye I've seen that in Quake3 (much cleaner in concept than implementation) and pretty much all games written in functional languages. Must admit it is a lot nicer to do the networking for that kind of structure.

Many of the modern game engines use a Controller-Pawn relationship to make a distinction between the AI/Player and how they interact with the state/model. This is conceptually simple to understand, but it's usually implemented within a complex hierarchy of entangling Objects, none of which are necessary to the logic in the game with the exception of a few with native hooks (typically for cameras and player input-- and in a general way collision detection, though not necessarily resolution).


That's why I like Component-based Entity-Systems. Your state is a database. Each key is an entity (or a state of an entity) that points to a table of components. Each component is a specialized set of data to be worked on by Systems, which are just state-less procedures that analyze a subset of the components and updates the data accordingly. Saving games, state space search, and networking is then super-trivial. Adding components or states dynamically to entities is trivial, as is creating new systems and components to expand the scope of your game. Easy to test and debug also.

Lua is especially well-engineered for this sort of design scheme (tables and local variable speed-ups are great), though you can accomplish it in any language.

ekolis

  • 7DRL Reviewer
  • Rogueliker
  • *
  • Posts: 186
  • Karma: +0/-0
  • get ye dennis
    • View Profile
    • Ed's home page
    • Email
Re: pedantic object oriented question
« Reply #57 on: April 16, 2013, 07:09:43 AM »
It is an MVC model so long as each entity has a controller.

That's one thing I've never understood about MVC. If there's a one-to-one mapping between models and controllers, why even make the distinction between the two? Why should I have to call a controller method to create a new monster or whatever when I can just call a constructor? OK, if there's a lot of logic and parameters involved, then it might be best to use a factory, but isn't it just premature optimization to mandate that all object initialization be done via a controller? And what of regular methods? Why can't Attack(Creature target) be a method of the Creature class, instead of of the CreatureController class? Doesn't moving everything into a controller actually *break* the founding principle of OOP that data and the methods to manipulate it should be kept together?
The Ed draws near! What dost thou deaux?

>EAT SANDVICH

naughty

  • Rogueliker
  • ***
  • Posts: 59
  • Karma: +0/-0
    • View Profile
Re: pedantic object oriented question
« Reply #58 on: April 16, 2013, 08:23:48 AM »
requerent: to be honest the games companies (I'm looking at you Epic) that have the complicated hierarchies for their entities are stuck with mid-90s ideas of how to use OO and design game engines.

While I like component systems I wouldn't go as far as to make all components methodless structs. Then again I was first exposed to a design similar to modern day component systems many years ago by a Smalltalk coder who considered it a good OO design and I agree.

The OOP that the component and 'Data Oriented Programing' guys are attacking is over two decades old, it's just a shame it's what is still being taught to undergrads.

ekolis MVC is a minefield, there are so many subtle variants and architecture astronauts that have muddied the waters over the years. The irony is that is was created by Smalltalk coders to handle GUI apps but they hardly use it any more, they use libraries based on Morphic written for the Self language which is quite radically different.

The original idea was to separate rendering code (the View) from the application's 'database' (the Model or the game-state as requerent mentioned above). The Controller is the main point of contention that causes so many different variants of the pattern to exist (MVP, MVVM and so on).

From a game programming PoV the Controller is worth abstracting out because entities can be 'controlled' by multiple things, a player with an input device, an AI, a networked player or AI on another machine or even totally scripted in a cut-scene. If they all use the same interface to change the Model your life is a lot simpler. If they all have a similar interface themselves, they can be interchanged freely. Component systems achieve the same results by slightly different means.

The guideline (that has become dogma) that controllers should be the only place where new model objects are created is due to the intuition that the input to the system as a whole comes through the Controllers. For some MVC designs this is fine but for others it is pointless or counter-productive.

I'm not sure why Attack() should be a method on the Controller, do you have a link to who would have said that?


requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: pedantic object oriented question
« Reply #59 on: April 16, 2013, 11:50:57 PM »
Quote
The OOP that the component and 'Data Oriented Programing' guys are attacking is over two decades old, it's just a shame it's what is still being taught to undergrads.

Please elucidate. I need schooling >_<.  A game is really just a database with a UI. Any OOP we do just feels like fluff. You can, of course, program DOP-style in OOP paradigm, but is it not just extra work? If it's all you know- sure, go for it- but are there any strict advantages?

Quote
I'm not sure why Attack() should be a method on the Controller, do you have a link to who would have said that?

It's pretty standard nomenclature. Controller.Verb() queues a call to Actor.doVerb(). That's how Unreal does it anyway.