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 / Design Issues

Author
Message
Jna99
19
Years of Service
User Offline
Joined: 3rd Nov 2005
Location: Portugal
Posted: 18th Oct 2007 18:11
Hi I've got an unusual doubt to clear, it's not GDK specific it's more a design question! I've a main.cpp file where the main loop is located, in that file I've got instanced all the object controller that I need, like the camera, mouse ,tree list controllers, problem is that I've made some functions where I can control the LOD of the trees, since I'm using Object I need to get acess to both the mouse position and the tree controller! So my question is what's the best choice...to create an object where the mouse and tree controller are passed by parameter, or should the function be placed on tree controller object and the mouse object passed by parameter...or any other hypothesis?

jason p sage
17
Years of Service
User Offline
Joined: 10th Jun 2007
Location: Ellington, CT USA
Posted: 18th Oct 2007 19:46
I think one could argue what is better - and who knows the perfect scenario - but I would try to be conigsant of what is easier for you to remember - and what call ultimately causes the least number of clock cycles. i.e. Passing Two Parameters is more work that passing one - but whats a few byte on the stack - you're just passing pointers likely.

The other option is exploring the friend class (or just make it all public if you're lazy - which isn't always a bad thing) and then having (Must be careful with this design - not good if you want multiple "Tree Controller" objects.... But you make a "Pointer" to the Mouse controller IN the TREE Control, and vice versa. Caution must be used to prevent either one from "accessing" the other until its instantiated. Like:



This technique assumes you will not try to instantiate TreeCtlRef, as that would make a NEW object yada yada.

I often do things like this - sometimes just to save typing.

MyShortHand=ThisClass->ThatClass->ThisClass->ThatClass;
MyShortHand->Value=1;
MyShortHane->Execute();

etc etc


just my opinion - I hope me or others can help get you you happily coding along.

Jna99
19
Years of Service
User Offline
Joined: 3rd Nov 2005
Location: Portugal
Posted: 18th Oct 2007 21:15
jason p sage thanks for your input,I believe I'm gonna try my first suggestion 'cause at college I learned that We should always try to separate functionalities, that way if there's a problem in a object that problem stays confined to that object and the object related to that one!

jason p sage
17
Years of Service
User Offline
Joined: 10th Jun 2007
Location: Ellington, CT USA
Posted: 18th Oct 2007 22:29
Understood and I don't blame you - (now for tiny soapbox) but there is a difference between real world and game programming. I'm a professional software engineer - and I work on various customer relationship management systems - customizations, integrations, and straight up "Add-ons".

Follow the rule they teach you in school - is good - especially if/when your code will/could be used and improved by others. but this is a game - clock cycles are paramount.

If you logically set up your objects - during design:

TMOUSECTL{
float X(void);
float Y(void);
float Z(void);
};

TTREECTL{
void UpdateAll(float p_CamX, float p_CamY, float p_CamZ);
};


It DEFINATELY makes sense they should stick to thier own functionality - like they said to you in school.

However.. with business apps - one approach - simply inheritance - for tying those two together would 1: make them Friend Classes, and 2: Make a new class with both of them in it.

Not a great inhertitance example - but made "Business dumb" kinda to keep it obvious.

TTREEMOUSECTL{
TTREECTL *TreeCtl;
TMOUSECTL *MouseCtl;
};
TTREEMOUSECTL::TTREEMOUSECTL(){
public TreeCtl=new TTREECTL();
public MouseCTL=new TMOUSECTL();
Public SpecialFuunction();
};

Where SpecialFunction acts as the "Logic" to marry the two - doing whatever it is you need them to be integrated as. This approach is kind of for making self documenting code (dumbed down for business. Rather have logical Hierarchy, and easy to see levels for most coders - don't want them learning more than actually coding etc.

What I suggested with the pointers - Really if written correctly is much neater and if developed so it checks for null pointers - can be made very secure/safe/maintainable.

The main benefit is less calls. You could get even tighter if you just passed the pointer to the mousectl to tree when you call a tree ufnction that needs mouse, and vice versa - for a more "School friendly" version of what I said. That way you stick to Single entry - single Exit without funky (possibly stray) pointers. Easier to manage - maybe you should go this route to get the bes tof both worlds.

Jna99
19
Years of Service
User Offline
Joined: 3rd Nov 2005
Location: Portugal
Posted: 19th Oct 2007 00:01
jason p sage thanks again for the input I'll study the design more closely to see what's the best choice, I believe this last one structures my code a little more which is always good!

P.S Always good to find another engineer, but my specialty is Systems Architectures and Computer Networks

jason p sage
17
Years of Service
User Offline
Joined: 10th Jun 2007
Location: Ellington, CT USA
Posted: 19th Oct 2007 01:43
You're Welcome - I'm pretty sure you've helped me along the way as WELL!

Jna99
19
Years of Service
User Offline
Joined: 3rd Nov 2005
Location: Portugal
Posted: 20th Oct 2007 00:18
Hi again since our last conversation I implemented one of the ways we talked about and it worked fine! Currently I'm having another problem, well not really a problem more like a dilemma ...since I've got trees and plants both are extensions of the object forest, now if I want to create a list of forests can I add to that list, plants and trees? I believe I can since they both descend from the same parent (forest), but I also know they have more information that the forest object..(I should have gone to more hierarchy classes on college lol)

jason p sage
17
Years of Service
User Offline
Joined: 10th Jun 2007
Location: Ellington, CT USA
Posted: 20th Oct 2007 02:48
Quote: "since our last conversation I implemented one of the ways we talked about and it worked fine! "
EXCELLENT!

You're having better luck than me currently. Ted6 is HOSED Alpha Dbo Export Doesn't work as advertised.

What you are saying reminds me of something IanM knows more about then me - only because (I admit it) I don't really "like" the idea even though I see its uses. This is Class Templates.

To my knowledge this allows you to make a "Pseudo class" that can be applied to multiple classes. In short - It "Writes the same code functionality" for different underlying data types. (I personally heard this and was like WOW - that IS SO AWESOME...(and I mean it still but...) but I'd never touch that with a ten foot pole! )

I do something IanM says is closer to old School C - I don't totally agree - but I see his point - nad it has merit. (You need to know these things before I sugest design idea that might not be ideal )

The important thing to know "low level" about classes, and inherited classes - (REAL inherited classes - not the dumbed down business example I gave which was more about "business structure" then proper ocde design for systems... but I digress... (They aren't mutually exclusive I must add though - business logic and proper "school" coding) anyway....

If you have a root class... The BEAUTY of object oriented code is that the variable members are created when you instantiate the class but the code exists once. ONCE! If you "Override" and "Inherit" (c++ default I think), in C++ the Override is called first, then the original code is called. Like Wise, due to there design - They literally work like a pile of paper - neatly stacked. A book is a good example. If you original class has a variable named "MyAge", it is written at page one (remember using book as parable). If you inherit a million times, making a "Novel size" class. From a pointer point of view, An instance of your "Novel Class" STILL has that same "MyAge" variable on page 1... or:

// not real values - but to prove a point

TORIGINALCALSS *Daddy=NEW TORIGINALCLASS();

Then mem address pointed to by "Daddy" PLUS Page 1 = Address of MyAge Variable for that instance.

TCHILDOFORIGINAL *ChildClass = NEW TCHILDOFORIGINAL();

Then mem address pointed to by "ChildClass" PLUS Page 1 = Address of MyAge Variable for that instance also!

The point is - I personally use linked lists (You could make your own or learn STDLIB ones) .. I made my own - silly - but I know it intimately.

Anyways - My BASE classes all have "BASE" variables needed so I can store "Lists" of them (that work like a database, "MoveFirst, MoveNext, Append, Insert etc.) And regardless of what I put in the child classes, plants or trees, I can maintain my list the same way. To access the members of "TREE" class though - I TypeCast the void pointer in my "Linked List" that is pointing to the current "Item" we are working on.

Also - for speed sake, I save "BookMarks" in my linked list because sometimes - for reasons of either convienance and raw CPU speed - I'll directly reference an "Item" Via the saved "BookMArk pointer" versus using the Linked list to navigate to it. This does make for some ugly type casts - but lightning code - if not dereferencing to deep when you try to get fancy.

There are STDLIB "Lists" and "Dynamic array" that are well tested, use templates as mentioned above - and allow the same functyionality - possibly more readable - defaintely more industry standard - but then again - Microsoft makes many industry standards and they aren't always a good thing - but usually pretty trustworthy

This allows throwing forrest and tree objects in same list.

One thing I do if I decide I must mix dirreferent "Classes" in same list (I usually don't do that) You proably would add a variable to the ITEM base class that you build on that has some sort of "TYPE" # in it so you only perform execute code for a given class when you know your pointer is defiantely pointing to the class you want.

TRUE Hierarchy's - that are of a dynamic nature tend to be a sginle list of items - with references to itself - - this translates to a "ParentID", where ParentID=0 is the ROOT or top directory. then you have however many kinds of data stored in a "DIR" but then you have special entries that are indeed "DIR" references which point to a "Sub Root"... and it takes recursive routines to properly read the whole heirarchy without missing a beat. This kind of code is not overly complex but can get dicey trying to debug because as you stare at the code you have to think how its calling itself, and how many levels deep you are, and what the variable are "NOW" and if you call yourself again, or exit - how will i be.. etc. when its working - Its awesome - getting it working - sometimes can be a long stare at your screen - complete silence - no keys being pressed - then finally you see the flaw - AAHHH HA!!! click click click...


Note - all this typing is because you said "Lists". there is a lot to be said for what you can do with straight inheritance if alot of the functionality between forrest, trees, plants are the same in your application. If not... Well.. you always can simplyfy by just having three lists or something versus trying to force them into one. (This is what I typically do)

I'll have a list of ALL OBJECTS.
A list if "TRees" (Stores bookmarks to ALL-OBJECTS LIST)
A list of "Plants" (Stores bookmarks to ALL-OBJECTS LIST)

this way I can loop through EVERYTHING, Or just plants, or just trees. the rule I follow is the MAIN "OBJECT" (DarkGDK Class I wrote generic) is the master of the ACTUAL OBJECTS.

In this example, My Tree list "ITEM CLASS" would have all my TREE methods, variables as well as a pointer to the ALL-OBJECTS LIST for the tree in question.

I could do this various ways - Like make it totally wrapped - so its as easy as "Delete Tree" and it cascades and does all - but I don't like being that rigid in a game. I might Want to remove a tree from the tree list, but not kill the object in DarkGDK... Why? Let's say tree got chopped down and is falling into a river... now it isn't a tree - is my FloatingLog "Thing" I have a separate class for. See?

There are many ways to skin a cat - I hope I tossed some ideas at least your way!


If this all sounded like nonsense I apoligize

Good Luck!

Jna99
19
Years of Service
User Offline
Joined: 3rd Nov 2005
Location: Portugal
Posted: 20th Oct 2007 15:23
jason p sage I didn't understand , but I've made some tests and it worked fine, I created a list of objects (type A) then I added 2 object (type B :: A and C::A), my current problem is the cast I'm controlling the cast with a int var on the A object, since I can't find an "instance of" method! So can do you know any other way of controlling the cast?

jason p sage
17
Years of Service
User Offline
Joined: 10th Jun 2007
Location: Ellington, CT USA
Posted: 20th Oct 2007 16:56
Quote: "jason p sage I didn't understand"
I'm sorry - It was a lot of information I was trying to convey and I'm probably not as good a writer as I would like to think I Am.

No but this sounds kinda like what I said above - where "Page 1" has a variable - that can always "Work" on descendant classes.

class base{ int MyType;};

class childtree(base){int treeBranches;};

class childplant(base){bool poisonous;};


you can always do:

(base*)MyTree->MyType=CONSTANT_TREETYPE;

and

(base*)MyPlant->MyType=CONSTANT_PLANTTYPE;


and this seems to be what you're doing - I did touch on this above - hidden in my bad explainations.

Like waise - the Answer to your Dilema is most likely CLASS TEMPLATES - like I also buried references to above as well.

The other thing I tried to mention above is a way to make bookmarks - let's try calling them simply what they are - pointers.


Than you could have a MAJOR LIST of "THINGS" with a simplified Base class. This is your master list, and this list only contains ONE TYPE stored in it, multiple copies of say GDK3DOBJECT. One is a tree, another a plant - (Behind the scenes the GDK objectID is a tree or plant) but this list is just a master list of 3d things.


Then have a TREELIST that only has trees, also a PLANT list that only has trees.

The Simple method of doing this - would mean having your treelist "Item" have a pointer to the MASTERLIST item (GDK3dOBJECT).

As you load stuff into GDK3dObject, you add a ITEM to your TREELIST if its a tree, and store the GDK3dOBJECT pointer in that Tree Object. Same for plants.


You end up with

GDK3dOBJECT <- MASTER LIST of GDK 3d stuff

TREELIST <- List of Trees Only - Each Item has pointer to its "GDK3dOBJECT item"

PLANTLIST <- List of plants only. - Each Item has pointer to its "GDK3dOBJECT item"



Now you don't have to worry about typecasting unless you get really fancy.

The more complicated method I described yto you originally - is exactly like above - but 1: Requires Type Casting, 2: is messy according to college recommended techniques, 3: Gives full bi-directional flexibility and is very fast.


This is where EACH GDK3dOBJECT item has both the INTEGER you use now, PLUS a Void pointer - that if its a TREE, has a pointer to the TREE OBJECT item it represents and if a plant has a poitner to the PLANTITEM it represents. then you need to do the whole typecast based on ID type.... Though You MIGHT get "TABOO" and try using SIZEOF - because USUALLY classes are the same size - but this is VERY RISKY technique - (useful in assembly where you sometimes need to do strange things under strange circumstances) I don't recommend it. Much safer to use the Integer for your class type thing so you know how to cast.

I REALLY THINK you should check out Templates because they MIGHT ALLOW doing this sort of thing without the tricky

switch (MyInt){
case 1:{((TPLANT*)MyObject)->Whatever) exit;};
case 2:{((TTREE*)Mybject)->Whatever) exit;};
}; etc



does this help a little? Sounds like you are totally ripping up this concept - and that is good - I hope I can at least help steer you toward the direction where you go on and find out a perfect solution.

Jna99
19
Years of Service
User Offline
Joined: 3rd Nov 2005
Location: Portugal
Posted: 20th Oct 2007 20:55
jason p sage thanks again for the help, it helped clear some doubt, even if the implementation was already done.. Now I present you with another question if you a have a method like the following:

int forestHandler::getForestStuff(forestStuff *stuff,int id);

and want the method to return the stuff object and the int value what should I do?

I believe I have to access the address of the object but I can't seam to do it..this is what I´m doing

forestStuff * stuff;
int var = getForestStuff(&stuff,3);

jason p sage
17
Years of Service
User Offline
Joined: 10th Jun 2007
Location: Ellington, CT USA
Posted: 20th Oct 2007 23:02
I don't THINK it needs to be that complex. I'm pretty sure C++ passes variables by reference so in theory - if your routine sets the Stuff Parameter:



I think you'll find Stuff parameter will point to the stuff you told it when it returns from getForstStuff.

(Gosh the forums are quiet today)

Jna99
19
Years of Service
User Offline
Joined: 3rd Nov 2005
Location: Portugal
Posted: 22nd Oct 2007 01:28 Edited at: 22nd Oct 2007 01:30
jason p sage I've made the following:

Method in forestHandler class


The call


It breaks the program...

EDIT: I will repost this in the programming section

jason p sage
17
Years of Service
User Offline
Joined: 10th Jun 2007
Location: Ellington, CT USA
Posted: 22nd Oct 2007 02:56
You have to be careful you aren't passing back a value that was instantiated on the stack. You aren't doing that are you?

In short - when you instantiate a class - the thing is in your heapspace - the pointers if handled right always point to that area. That should be valid until you destroy the class - freeing it from the heap - rendering the pointer dangerous - which is why people usually set the pointer to zero after they destroy a class.

This is what it looks like might be happening - I dunno.

Jna99
19
Years of Service
User Offline
Joined: 3rd Nov 2005
Location: Portugal
Posted: 22nd Oct 2007 11:54 Edited at: 22nd Oct 2007 12:20
jason p sage then what should I do to make this work? I believe I should make this but I gives me an error (it says it cannot cast forestHandler ** to forestHandler*)..




EDIT: I believe I found the solution



jason p sage
17
Years of Service
User Offline
Joined: 10th Jun 2007
Location: Ellington, CT USA
Posted: 22nd Oct 2007 14:19
Let me know if that does it for good. The theory is sound - we've all been passing by reference for years I rememebr when I first saw the benefit - trackign a bug down and then someone told me WHY it was messing up and I was like THAT is cOOL!

Login to post a reply

Server time is: 2024-11-16 20:38:24
Your offset time is: 2024-11-16 20:38:24