Jump to content

  • Log In with Google      Sign In   
  • Create Account


#ActualCygon

Posted 18 July 2012 - 03:17 AM

@Matias Goldberg: I got that. I didn't want to imply you recommended copy&paste programming. When you wrote "...rather than having to refactor everything or resort to copy-pasting the constructor into a reinit() function, then debug why reinit is failing (because you pasted more code than you should, or forgot to copy something).", in my opinion reinit() is a) just another form of two-stage initialization and b) can avoid code duplication just the same (it's not like reinit() would somehow force it).

I would still strongly prefer one-stage initialization in all 4 cases you listed. But instead of just criticizing your design, let me explain how I would have done it and you can criticize mine Posted Image)

Object reloading for memory & performance: I have a logical game object which maintains the persistent state (eg. class ScarySpider with int health, Item loot, int xp). Add AI, physics etc. via composition. This thing gets loaded and saved with a level and in savegames. With a client/server model, the server would only work with this logical game object. To actually render it, there is a class ScarySpiderPresenter which creates and maintains the visual and audible representation of the logical game object in the game's scene graph. If I wanted to reclaim memory this way, I'd destroy the ScarySpiderPresenter but leave the ScarySpider.

Reloading for in-place editing: Kill ScarySpiderPresenter, create ScarySpiderEditorPresenter. The latter could derive from the former or both could derive from a common base class as appropriate if there is shared functionality. This presenter could draw bounding boxes, overlay the AI's current patrol path / attack target or display scale and rotate widgets or whatever you like. Normal gameplay is not burdened with dragging the editor-specific state variables along as dead code.

Level reloading: Either be very clever and mutate the active world's state into the state loaded from the saved game / level (this is how I understood your approach) which will neatly cause the presenter hierarchy to create/destroy presenters as needed, all without requiring the save/load code to get clogged dealing out references to graphics devices, input managers and audio managers to the newly created objects. Or alternatively go ahead and kill the world with its presenters, then recreate it, taking into account that long loading times primarily result from needlessly reloading resources from disk - which can be solved by a resource manager with a LRU list and a memory budget.

So in short, whenever two-stage initialization is used, there are actually two classes being glued together. Yes, design gets more complicated as a project's scope grows and the effort to change late in the process becomes ever larger. All the more reason to pay attention to it, especially if one is not just coding Tetris of Pac Man!

#1Cygon

Posted 18 July 2012 - 03:16 AM

@Matias Goldberg: I got that. I didn't want to imply you recommended copy&paste programming. When you wrote "...rather than having to refactor everything or resort to copy-pasting the constructor into a reinit() function, then debug why reinit is failing (because you pasted more code than you should, or forgot to copy something).", in my opinion reinit() is a) just another form of two-stage initialization and b) can avoid code duplication just the same (it's not like reinit() would somehow force it).

I would still strongly prefer one-stage initialization in all 4 cases you listed. But instead of just criticizing your design, let me explain how I would have done it and you can criticize mine :o)

Object reloading for memory & performance: I have a logical game object which maintains the persistent state (eg. class ScarySpider with int health, Item loot, int xp). Add AI, physics etc. via composition. This thing gets loaded and saved with a level and in savegames. With a client/server model, the server would only work with this logical game object. To actually render it, there is a class ScarySpiderPresenter which creates and maintains the visual and audible representation of the logical game object in the game's scene graph. If I wanted to reclaim memory this way, I'd destroy the ScarySpiderPresenter but leave the ScarySpider.

Reloading for in-place editing: Kill ScarySpiderPresenter, create ScarySpiderEditorPresenter. The latter could derive from the former or both could derive from a common base class as appropriate if there is shared functionality. This presenter could draw bounding boxes, overlay the AI's current patrol path / attack target or display scale and rotate widgets or whatever you like. Normal gameplay is not burdened with dragging the editor-specific state variables along as dead code.

Level reloading: Either be very clever and mutate the active world's state into the state loaded from the saved game / level (this is how I understood your approach) which will neatly cause the presenter hierarchy to create/destroy presenters as needed, all without requiring the save/load code to get clogged dealing out references to graphics devices, input managers and audio managers to the newly created objects. Or alternatively go ahead and kill the world with its presenters, then recreate it, taking into account that long loading times primarily result from needlessly reloading resources from disk - which can be solved by a resource manager with a LRU list and a memory budget.

So in short, whenever two-stage initialization is used, there are actually two classes being glued together. Yes, design gets more complicated as a project's scope grows and the effort to change late in the process becomes ever larger. All the more reason to pay attention to it, especially if one is not just coding Tetris of Pac Man!

PARTNERS