Preliminary Engine Architecture

General discussion pertaining to Elysian Shadows, ESTk, ESGamma, and the Adventures in Game Development series.

Moderators: News Mods, Elysian Shadows Team

Preliminary Engine Architecture

Postby dandymcgee on Wed Aug 01, 2012 8:22 pm

Falco Girgis wrote:It is imperative that I can broadcast my narcissistic commit strings to the Twitter! Tweet Tweet, bitches! :twisted:
User avatar
dandymcgee
ES Beta Backer
ES Beta Backer
 
Posts: 4911
Joined: Tue Apr 29, 2008 4:24 pm
Location: New Hampshire

Re: Preliminary Engine Architecture

Postby Falco Girgis on Thu Aug 02, 2012 12:52 pm

Believe it or not, most of this Engine design is still very much in use today...

The debugging mechanism has become quite a bit more developed, as it now provides a uniform logging mechanism for Lua, Engine/Toolkit AssetIO, and Engine-specific debugging...

The "Engine" and "System" relationship is a design that has always been central for us... It is literally our far less reested Singleton solution. So you have a bunch of classes that need access to a single class/data structure? Instead abusing the living shit out of OO and allowing these classes to pull references to the shared class out of their asshole at any given point in the program's execution, you are forced to make these classes subclass a parent "Manager" class that gives them access to a pointer to this joint class...

In this way you are creating a compile-time contract as to who can and can't access this joint class. In Elysian Shadows, "Level" and "Area" are classes central to the Engine. They store all assets. Then each Subsystem needs access to these assets to do their job (WarpSystem needs to check for warp collision, AnimationSystem needs to update animations, etc). Rather than simply making Level and Area reesty ass singletons, we create a parent "System" class that acts as a "Manager" and facilitates access to this joint data... Then ONLY CLASSES THAT SUBCLASS THE PARENT MANAGE CLASS (Subsystems) can become "Managers" with access to the joint data. Tell me that isn't more elegant than a singleton...
"So what happens if the Elysian Shadows Kickstarter fails?"
Image
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
 
Posts: 10693
Joined: Thu May 20, 2004 3:04 pm
Location: Studio Vorbis, AL

Re: Preliminary Engine Architecture

Postby short on Sat Aug 04, 2012 5:00 am

Hey, this is awesome! Thanks for sharing, I'm extremely interested in different ways of solving this exact issue, and I like to approach you've explained.

I'd like you to clarify if I'm understanding this correctly, if you don't mind :).

Instead abusing the living shit out of OO and allowing these classes to pull references to the shared class out of their asshole at any given point in the program's execution, you are forced to make these classes subclass a parent "Manager" class that gives them access to a pointer to this joint class...


So if I'm understanding correctly, an example would like something like:

Code: Select all
struct SpriteCollection{
  static vector<int> sprites_;
  //...etc
};

class SpriteManager :
  public SpriteCollection {

protected:
  SpriteCollection SpriteCollection_; 
};

class ClassThatNeedsAccessToSpriteDS :
    public SpriteManager {
   
  void DoesStuffWithSpriteCollection(void) {
    // we can now use SpriteCollection_ here...
  }
};


Am I understanding what I read correctly?

edit:

I took a look again at your post, and it seems my example is in a similar direction, I hope you don't mind but I'm going to steal this approach next time I get the chance, it's definitely an approach to solving this problem I haven't seen yet. When did you come up with the idea, whiteboard phase or implementing phase?
My github repository contains the project I am currently working on,
link: https://github.com/bjadamson
User avatar
short
ES Beta Backer
ES Beta Backer
 
Posts: 571
Joined: Thu Apr 30, 2009 3:22 am
Location: Oregon, US

Re: Preliminary Engine Architecture

Postby Falco Girgis on Sat Aug 04, 2012 1:43 pm

Oh shit! Our first victim!

It would look like this:
Code: Select all
struct SpriteCollection {
    std::vector<int> sprites;
};

class SpriteManager {
protected:
    static SpriteCollection _sharedCollection;
};

class SomethingThatNeedsAccessToSprites: public SpriteManager {
public:
    void fuckWithSprites(void) { _sharedCollection.sprites[4]; //I can now access the shares sprite collection }
};


Now anything that needs to access this common "SpriteCollection" must be a "SpriteManager" (to inherit access to a the static SpriteCollection instance).

short wrote:I hope you don't mind but I'm going to steal this approach next time I get the chance, it's definitely an approach to solving this problem I haven't seen yet. When did you come up with the idea, whiteboard phase or implementing phase?
Go for it. We wouldn't be making this code public if we didn't think you guys would be using it. I came up with this very early on at the whiteboard. The issue of facilitating access to common data like this is really central to any game Engine. Unfortunately too many people (including us with the first iteration of the engine) opt for the easy way out and just pollute their code with singletons... It's unfortunate.

This is yet another reason that I think starting with C over C++ is actually beneficial. In C, everything is essentially global. You never have to spend hours or days agonizing over object-oriented designs like this that you can't fully comprehend until after you have made mistakes... What is absolute shitty design in C++ can be pristine design in C... Then that allows you to focus on learning actual game logic without the guilt and hindrance of also trying to adhere to an OO paradigm that you don't fully understand. Once you have fully experienced C, I think you will have a better grasp on what OO is, why it is beneficial, and what it can offer your project (as opposed to adhering to an OO paradigm "just because" without actually understanding its benefits). </rant>

We use the exact same paradigm in the Toolkit as well.
"So what happens if the Elysian Shadows Kickstarter fails?"
Image
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
 
Posts: 10693
Joined: Thu May 20, 2004 3:04 pm
Location: Studio Vorbis, AL

Re: Preliminary Engine Architecture

Postby dandymcgee on Sun Aug 12, 2012 5:16 pm

Gotta love the good ol' pencil on paper design tactic. Definitely more fun to come up with class definitions for your engine than pay attention during Calculus lectures.
Falco Girgis wrote:It is imperative that I can broadcast my narcissistic commit strings to the Twitter! Tweet Tweet, bitches! :twisted:
User avatar
dandymcgee
ES Beta Backer
ES Beta Backer
 
Posts: 4911
Joined: Tue Apr 29, 2008 4:24 pm
Location: New Hampshire

Re: Preliminary Engine Architecture

Postby Jevi on Wed Feb 06, 2013 7:09 pm

How do you manage the deallocation of that memory during process termination? From what I can see multiple classes inherit the same static members; how do you determine who is responsible for cleaning up?
Jevi
Chaos Rift Newbie
Chaos Rift Newbie
 
Posts: 2
Joined: Tue Feb 05, 2013 3:09 pm

Re: Preliminary Engine Architecture

Postby Falco Girgis on Thu Feb 07, 2013 10:56 am

Jevi wrote:How do you manage the deallocation of that memory during process termination? From what I can see multiple classes inherit the same static members; how do you determine who is responsible for cleaning up?
We have a single class that manages the pointer itself (rather than just the contents).

LevelSystem is responsible for allocating, deallocating, and setting the current level and area.
"So what happens if the Elysian Shadows Kickstarter fails?"
Image
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
 
Posts: 10693
Joined: Thu May 20, 2004 3:04 pm
Location: Studio Vorbis, AL

Re: Preliminary Engine Architecture

Postby Jevi on Thu Feb 07, 2013 8:22 pm

We have a single class that manages the pointer itself (rather than just the contents).

LevelSystem is responsible for allocating, deallocating, and setting the current level and area.


Does that class which manages the pointer happen to be something like a smart pointer? A shared pointer of some sort with reference counting?
Jevi
Chaos Rift Newbie
Chaos Rift Newbie
 
Posts: 2
Joined: Tue Feb 05, 2013 3:09 pm

Re: Preliminary Engine Architecture

Postby Falco Girgis on Sun Feb 10, 2013 1:42 pm

Jevi wrote:
We have a single class that manages the pointer itself (rather than just the contents).

LevelSystem is responsible for allocating, deallocating, and setting the current level and area.


Does that class which manages the pointer happen to be something like a smart pointer? A shared pointer of some sort with reference counting?
Nope. Since every "manager" class is inheriting the exact same static pointer, there is only ever one reference in use technically.

That LevelSystem class is a subsystem just like everything else. It inherits the same static pointer. It is just the only class that ever changes what the pointer points to or calls new/delete on it.

It also holds on to adjacent areas in RAM so you can simply point to a new level/area that has already been sitting in RAM to swap levels and areas without having to load. We don't stream or preload new areas, but we do cache a certain number of previously visited areas and levels, so returning back where you came from wouldn't be a load time and would also have movable objects and enemy placement the way you left them.

The number of cached levels and areas depends on your platform. The Dreamcast doesn't cache like this (it only ever holds 1 area and 1 level since it only has 16MB of RAM), the iOS builds hold on to at least a couple areas and 1 level, then the x86 platforms hold onto even more areas and multiple levels.
"So what happens if the Elysian Shadows Kickstarter fails?"
Image
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
 
Posts: 10693
Joined: Thu May 20, 2004 3:04 pm
Location: Studio Vorbis, AL


Return to Elysian Shadows Discussion

Who is online

Users browsing this forum: No registered users and 1 guest