Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

Dark GDK / Questions about managing my code.

Author
Message
Aldur
16
Years of Service
User Offline
Joined: 8th Oct 2007
Location: Melbourne, Australia
Posted: 9th Feb 2010 19:03
Hey,
I was just thinking and I needed some help on some sort of organized structure for my code.

What is the best way to split code between multiple files? I've read a small amount about it but not enough to know what to include in a source file and it's accompanying header file for a game.

Also, what should and shouldn't be hard coded into a project, except for the obvious things.

Any help that someone can give me would be much appreciated.

Cheers,
Aldur.

Matty H
15
Years of Service
User Offline
Joined: 7th Oct 2008
Location: England
Posted: 9th Feb 2010 19:50
In an ideal world you would wrap everything into re-usable functions or even better, classes.

This may take longer initialy, but you will end up with your own library of re-usable classes for your current and future projects.
Its all a matter of choice and preference, if you show some code, people here may tell you how they may do it as there will be lots of ways and all of them may be right.

Amnzero
15
Years of Service
User Offline
Joined: 1st Aug 2009
Location:
Posted: 10th Feb 2010 00:20
Yeah. I am starting with base classes, and wapping DGDK functions into classes derived from them. Its a lot of work really, and a little complicated, but worth it. So now instead of making a bunch of function calls to set up a terrain I can just make a terrain object like so:

TerrainObj* myTerrain = new TerrainObj("map.bmp");

Then I could optionally change some default settings.

myTerrain->Scale.X = 10;
myTerrain->Scale.Y = 10;
myTerrain->Texture = new ImageObj("terradesert.bmp");


Then to get my terrain up and on screen I just make a call to the objects build function:

myTerrain->Build();

Just turning the GDK into an OO library of your own design can be pretty rewarding lol.

if(enemy == Amnzero) runAway();
Amnzero->WebSite = L"http://neovance.com/";
Matty H
15
Years of Service
User Offline
Joined: 7th Oct 2008
Location: England
Posted: 10th Feb 2010 00:38
The real advantage of what Amnzero is doing is the fact that he can now add functions to his class that do not currently exist, eg raise the terrain at a certain point, this may take alot of working out but it will be there for him for every game he ever makes.

Aldur
16
Years of Service
User Offline
Joined: 8th Oct 2007
Location: Melbourne, Australia
Posted: 11th Feb 2010 12:01
Thanks for the replies guys.

I am going to look into writing my own lib and wrapping dgdk and native dx.
I'll post back when I make some decent progress, so if I encounter any problems, be ready for some questions

Cheers again!

dark coder
21
Years of Service
User Offline
Joined: 6th Oct 2002
Location: Japan
Posted: 11th Feb 2010 14:44
If you go the full OO route then you'll probably want more or less one header+source combo per class and to make the lib not a complete mess you'd ideally use namespaces(at the very least, put everything in one). Make sure it's const correct, try to not use global variables or functions unless you have to, and most importantly, be consistent!

One thing to keep in mind though, wrapping GDK properly requires a lot of thinking ahead, so make sure you're very good at C++ and know how to do most parts before you begin otherwise you'll end up rewriting everything several times. If you haven't decided on a style to use yet then I recommend THIS one for the most part, some of their suggestions I ignore because they're stupid(who wants to use American/wrong spelling? ) but most are very good.

Amnzero
15
Years of Service
User Offline
Joined: 1st Aug 2009
Location:
Posted: 11th Feb 2010 14:58
Geh...Seriously...?

if(enemy == Amnzero) runAway();
Amnzero->WebSite = L"http://neovance.com/";
dark coder
21
Years of Service
User Offline
Joined: 6th Oct 2002
Location: Japan
Posted: 11th Feb 2010 15:14
Yep, as well as not breaking encapsulation by doing things like:



And I also like to write 'manager' classes for all major aspects to avoid things like 'new ImageObj("terradesert.bmp");' because that will instance that class every time you need an image, what if the image you need is already loaded? That's a waste of memory. Plus, if there's an issue with the arguments passed to the constructor you can only jump out using an exception, if you use a function like createImage() then it can always return '0' if the image isn't found or something.

Amnzero
15
Years of Service
User Offline
Joined: 1st Aug 2009
Location:
Posted: 11th Feb 2010 16:03
Yeah. I like to live dangerously, and spell like crap. Thats how I roll. I also use manager classes, that pretty much take care of everything behind the scenes. I use mostly static functions, and variables in my base classes.

Im actually in the process of working my management functions to run on a seperate thread.

if(enemy == Amnzero) runAway();
Amnzero->WebSite = L"http://neovance.com/";
Aldur
16
Years of Service
User Offline
Joined: 8th Oct 2007
Location: Melbourne, Australia
Posted: 11th Feb 2010 16:14
@ Dark Coder:
Thanks for the reply and the link. I was hoping you would post because I have seen a lot of your work and like the way you manage your projects (one header + one source per class) like in your WIP 'Let's make: A game based around Earth' project.

I wouldn't say I am "very good" at C++, as I have only been using it for a short while, but what are the main things I should be cautious of, in your opinion?

@ Amnzero:
How far have you gotten with your lib? Any tips you could give me on starting out would be greatly appreciated!

Amnzero
15
Years of Service
User Offline
Joined: 1st Aug 2009
Location:
Posted: 11th Feb 2010 16:35 Edited at: 11th Feb 2010 16:39
Actually, my lib has a little ways to go yet, but I have most of the GDK wrapped at this point.

The main thing is to start off small. Start with a base class which all other classes will be derived from, and then start building the derivitives adding complexity, and functionality as you move up. I started with a class that had a constructor, a copy contructor, a couple of virtual functions, and a couple of variables. You could go two ways with it. If you have everything planned out well you could opt to build your management code right into the lowest base classes. For instance my base object class, which my terrain class is dirived from, helps my base manager class with assigning IDs and keeping track of memory for my terrain on the fly. Same with my image class.

Then of course you could opt for building your manager class on top of your framework. Its probably a lot simpler to do it that way, but personally I was looking to emulate a managed C++ like CLR with my library. EIther way I have not tested my libraries proformance yet, and the basic principal is the same. You have collections to keep track of objects, and the IDs assigned to them, and you have your functions to navigate, and maintain those collections.

if(enemy == Amnzero) runAway();
Amnzero->WebSite = L"http://neovance.com/";
dark coder
21
Years of Service
User Offline
Joined: 6th Oct 2002
Location: Japan
Posted: 11th Feb 2010 17:10
Quote: "but what are the main things I should be cautious of, in your opinion?"


For me it's changing style, I've written about 3 GDK wrappers from scratch now because I've changed my coding style. While refactoring the code was an option, it would have been too time consuming, and I always thought up better ways to implement certain things so it was better to recode it anyway.

So make sure you really think about each section when you go to write it, changing it down the line is a waste of time when you could have thought up the better method before you wrote the not so good one.

Quote: "Start with a base class which all other classes will be derived from"


What kind of class would you want to inherit from every other class? The most used classes in any of my code tends to be the reference counter.

entomophobiac
21
Years of Service
User Offline
Joined: 1st Nov 2002
Location: United States
Posted: 11th Feb 2010 17:54
dark coder: Could you possibly bother to write some pseudo code on the whole "manager" concept? I find it extremely interesting. My first thought would be some kind of utility class with a private constructor and a set of public methods, implementing everything "behind the scenes," as it were. I don't know.

Would you care to share some of this knowledge?
dark coder
21
Years of Service
User Offline
Joined: 6th Oct 2002
Location: Japan
Posted: 11th Feb 2010 18:46
Sure, though it's easier to just paste existing code.



This class manages all planets in my game, you may notice I privatise the constructor/destructor, as well as hide the copy constructor and assignment operator(by declaring but not defining them). This is because all of my managers follow the basic(non-thread safe) singleton design pattern, that is, only one instance of this class can exist at any time. The implementation of this is otherwise simply:



You'll notice you can create a planet using 'Planet& createPlanet( const std::string& name );' this returns a reference because I'm quite anal about having things be references unless their value can be NULL during standard(correct) execution, or if they're arguments using any of the basic types. If they're pointers then I get an overwhelming urge to do 'if ( whateverPtr )' before its use.

The actual code for the above method is pretty basic and is almost identical to all of the other managers:



The 'gdk:ynamicIdHandler' class essentially returns an unused index, much like the object/image/whatever IDs GDK uses, except this is used to efficiently find holes in the vector I store my planets in, if there are no holes then it returns an index higher than the vector size, this is where 'gdk::autoResizeVector' comes in use because that just automatically resizes the vector and zeros the new indices if the target size is larger than the current.

So the Planet constructor takes an index to where it's stored in the Planets Vector, and its name, the name itself is used to reference the 'PlanetTemplate' instance this planet is based off of. I then write the planet instance to the vector.

The Planet class inherits from my 'gdk::RefCounter' class(well not directly, it actually inherits Entity) which begins with 1 reference and can only be destroyed from 'void destroyPlanet( Planet& );'. How do I achieve that? Using more fun code:



THROW_IF is a bit of a misnomer, it's pretty much assert(), except it writes to my log system first and I couldn't exactly call it ASSERT, and I also have THROW for when I don't need a condition check first. Anyway, the first line makes sure the ref count is 1 before you destroy it, this makes it very hard for me to make my code leak memory and slightly harder to mess up the ref counting. You'll then notice I set 'currentlyDestroying_' to the instance passed, I blank out the planet's entry in my vector, put the now unused vector index back into my IDHandler class and finally release the last reference to my Planet, this invokes the virtual destructor in my gdk::RefCounter.

The Planet destructor looks like this:



It throws an assertion if this wasn't previously called by PlanetManager, and yes I'm aware there are different/better ways to do this, but this made the most sense at the time.

As far as managers go, this one is pretty tame because it only handles my planets, my gdk:bjectManager is a bit more complex:



You'll notice I have overloads and methods that do the same thing but handle pointers and references, with the case of the ones that return references those will throw errors if they can't find what you search for, the pointer version will just return NULL. I also like to organize my class declarations by grouping everything , and at least in VS with my 4 space tabs, these groups are mostly aligned.

Amnzero
15
Years of Service
User Offline
Joined: 1st Aug 2009
Location:
Posted: 11th Feb 2010 19:17
@ Dark Coder -

I am not exactly done with everything, but this is the makeup of my base class at the moment. It would be exagerating to say 'All' of my other classes derive from this one, but it is pretty close. I only have two classes that don't.



if(enemy == Amnzero) runAway();
Amnzero->WebSite = L"http://neovance.com/";
entomophobiac
21
Years of Service
User Offline
Joined: 1st Nov 2002
Location: United States
Posted: 11th Feb 2010 20:37
Amnzero: your class could as easily have been a struct, actually. As all the members are public, it's not really benefiting from anything specific to C++.

My suggestion would be:



...or at least something along those lines.
Amnzero
15
Years of Service
User Offline
Joined: 1st Aug 2009
Location:
Posted: 11th Feb 2010 21:31
Right. At the moment I am not exactly worried about getting everything perfect in the base classes...as I expand the library the base classes are not concrete. I may go back, to change, remove, or add to it still. Some of the stuff I am doing is a little experamental. I just have not bothered to type out a private: specifier yet lol

[url="http://neovance.com/"][/url]
Aldur
16
Years of Service
User Offline
Joined: 8th Oct 2007
Location: Melbourne, Australia
Posted: 14th Feb 2010 14:02 Edited at: 14th Feb 2010 16:55
I am still a bit lost on classes. I was hoping for a bit more help, if it is possible.

I have a class to manage my game settings which is currently incomplete and I noticed that no DarkGDK commands were called from inside the any of the classes posted here.

Being new to this doesn't help, but is the point of classes just to hold data and perform non-gdk functions/commands?

Cheers again for all of your input!

EDIT:
I have worked out the best way for me to manage my code, given my current level of knowledge with C++.

Thanks all.

Amnzero
15
Years of Service
User Offline
Joined: 1st Aug 2009
Location:
Posted: 15th Feb 2010 01:26 Edited at: 15th Feb 2010 01:31
Well I can't speak for dark coder, but a lot of the DarkGDK functions are wrapped into the class functions. Based on the type of classes and the functionality you want...there are a bunch of different ways to go about it. Here is the Build() function definition for my Terrain Object. The Make() function is included in this segment because it is used in Build(), but is private.



So basicly my Terrain::Make() is my replacement for dbMakeObjectTarrain() and my Terrain::Build() is my replacement for dbBuildTerrain for my Terrain objects.

[url="http://neovance.com/"][/url]
Aldur
16
Years of Service
User Offline
Joined: 8th Oct 2007
Location: Melbourne, Australia
Posted: 20th Feb 2010 14:12
Thanks Amn.

I didn't want to start a new thread, but if someone reads this, maybe Dark Coder:

What is the best way to handle media when using OOP? I know you spoke of DynamicIdHandler and also not to load it for every instance of a class.

Cheers!

Amnzero
15
Years of Service
User Offline
Joined: 1st Aug 2009
Location:
Posted: 21st Feb 2010 04:30 Edited at: 21st Feb 2010 04:33
Personally...I have three static vectors which I use kind of like a dictionary. One holds ID numbers for that type of media, another holds file names, and another holds a pointer to the class that loaded it.

So when I initialize say, a new Image, I will check to see if the filename is already in the collection. If it is I will Set the class ID to the ID assigned to that image file. At that point, I just insert the info for that class into the collection.

Otherwise I find the next available ID number to assign the new image, and load the image file at that point.

I also use the collection to keep track of multiple classes that use the same files, so if a class gets deleted that is using an Image that another class is also using, the image wont get marked for deletion (or the ID number will not be freed for use)

[url="http://neovance.com/"][/url]
Aldur
16
Years of Service
User Offline
Joined: 8th Oct 2007
Location: Melbourne, Australia
Posted: 21st Feb 2010 23:46
Any chance of a bit of source code for your static vectors?
Would be helpful

dark coder
21
Years of Service
User Offline
Joined: 6th Oct 2002
Location: Japan
Posted: 22nd Feb 2010 08:12
Quote: "What is the best way to handle media when using OOP?"


Well I don't know about the best method, but my media manager classes all have a findWhatever() method that takes a handle, the handle is either a custom handle or a path, but they're both handled as handles in my code. The function then searches(using a std::map) all instances of that media type against this handle, if it exists then it just returns a ref to it. If not then it checks if it's a path, if so then it loads the media and returns a new instance of whatever class. If not then I check if this handle has been assigned to a cached media template, because images for example can be loaded with several flags that you can't alter once loaded, so a file path alone isn't enough to load all things, such as cube maps. That would then load the media using these specific flags I've already assigned to the handle and return a ref to the new media, if that fails then this is an invalid handle and I throw an assertion.


Quote: "I know you spoke of DynamicIdHandler"


That's just an efficient way to return free(null) indices in my vector, it's called 'Dynamic' because it reallocates the deleted ID list when it becomes full, the StaticIdHandler uses a fixed deletion list size, which is slightly faster as it doesn't have to check its size.


Quote: "and also not to load it for every instance of a class."


I was talking about the media classes, like Image/Object/Whatever, there's not point in creating 10 instances of an image class that point to the same image if none of them operate on it.

Login to post a reply

Server time is: 2024-10-05 16:18:02
Your offset time is: 2024-10-05 16:18:02