// Psuedoriffic
class Direct3DObject {
interface;
device;
vertex buffer;
IDirect3DTexture9 *LoadTexture(char *fileName); // actual code
}
class Texture {
init(zFilename);
//(*LoadTexture access needed!!!)
}
class Kernel {
Direct3DObject D3D;
Texture tl;
)
Well after trying to implement it, I've discovered I need to re-design. I've obviously discovered I shouldn't have the LoadTexture funtion in the Direct3DObject interface. I'm just thinking I'm going to need a directx object that only holds the pointers, and no methods. I'm really confused on how to do this while making sure everything that needs to remain static, remains static. Are there any tutorials/resources out there that show common ways for constructing (OO) game engines? Please don't lead me to "Enginuity" because I don't like his server/client methods. I want something straight to the point.
🔒 Locked
Designing the ENGINE
Advertisement
Original Post
This is an engine design issue, NOT a Direct3D issue. Many people have just said "Oh sorry, I don't know DirectX." I don't have a problem with DirectX, as I've written programs with it before. I'm just trying to get the engine to be OO. I've been trying to design my engine, and am running into problems. First major problem was getting objects to work together, and still have only once instance of the DirectX object present to pull pointers from. I tried to design a KERNEL that has a TEXTURE object (loading and listing). Within the KERNEL, I create an instance of a TEXTURELIST and an instance of Direct3DObject. Everything's fine and stuff is starting to click. Well, then the problem is that I can't use the Direct3DObject in KERNEL in the TEXTURELIST implementation.
tbh, i'd have said this problem was trival to solve;
- Assume the Direct3DObject exists for the life time of Kernel
- Assume the Texture object exists only for the life of the Kernel
- Object pointers are wrapped in reference counting smart pointers
- Apon construction of a TextureList it is passed a reference to the Direct3DObject and makes its own copy
The object is then free to make use of the Direct3DObject for its life time, once everything goes out of scope you get everything cleaned up.
Job done.
There are probably numberous other ways of doing it, using different methods, but this is pretty much the K.I.S.S method :)
This is nothing more than normal Software OOP, games arent really anything magical in that respect. Just apply OO programming rules and ideas and work from there
- Assume the Direct3DObject exists for the life time of Kernel
- Assume the Texture object exists only for the life of the Kernel
- Object pointers are wrapped in reference counting smart pointers
- Apon construction of a TextureList it is passed a reference to the Direct3DObject and makes its own copy
The object is then free to make use of the Direct3DObject for its life time, once everything goes out of scope you get everything cleaned up.
Job done.
There are probably numberous other ways of doing it, using different methods, but this is pretty much the K.I.S.S method :)
This is nothing more than normal Software OOP, games arent really anything magical in that respect. Just apply OO programming rules and ideas and work from there
If you don't want to use smart pointers, try something like this.
Of course you'll probably want to throw in a few asserts to make sure everything is clean on program exit. To further simplify, you could make ms_pD3DO an object instead of a pointer (no reference counting required), but would then have very little control over when the D3DO object was created or destroyed.
// header fileclass Direct3DObject{...};class CTexture{ CTexture(); ~CTexture(); static int ms_iRefs; static Direct3DObject * ms_pD3DO; ...};// source fileint CTexture::ms_iRefs = 0;Direct3DObject CTexture::ms_pD3DO = NULL;CTexture(){ if (!ms_iRefs) ms_pD3DO = new Direct3DObject; ms_iRefs++;}~CTexture(){ ms_iRefs--; if (!ms_iRefs) delete ms_pD3DO;}Of course you'll probably want to throw in a few asserts to make sure everything is clean on program exit. To further simplify, you could make ms_pD3DO an object instead of a pointer (no reference counting required), but would then have very little control over when the D3DO object was created or destroyed.
Quote:
Original post by DesCr
I've been trying to design my engine, and am running into problems. First major problem was getting objects to work together, and still have only once instance of the DirectX object present to pull pointers from.
I tried to design a KERNEL that has a TEXTURE object (loading and listing). Within the KERNEL, I create an instance of a TEXTURELIST and an instance of Direct3DObject. Everything's fine and stuff is starting to click. Well, then the problem is that I can't use the Direct3DObject in KERNEL in the TEXTURELIST implementation.// Psuedorifficclass Direct3DObject { interface; device; vertex buffer; IDirect3DTexture9 *LoadTexture(char *fileName); // actual code}class Texture { init(zFilename); //(*LoadTexture access needed!!!)}class Kernel { Direct3DObject D3D; Texture tl;)
If you're having access problems, try:
Remember that method and member access to classes is private by default.
|
Remember that method and member access to classes is private by default.
I've worked through a lot of design issues. I'm not sure what I was smoking when I decided to give the D3DO methods like Render(), when CRender should be taking care of that kind of thing. Some things you can't figure out until implementation :)
Time to learn about singletons!
Time to learn about singletons!
having had my flirt with singletons i'm not so inclinded to recomend them, when i first learnt about them like most ppl i guess they seemed like 'the answer to everything', but having created a complex bit of software with singletons i feel they hindered the system more than then helpped and infact caused me to use some horrible hacks in places to solve problems :|
the only thing in the end which was logical to have as a singleton was the logging system which I did truely need to get at everywhere without restriction, everything else would probably have worked better with a passed down smart pointer or normal pointer in initalisation.
but hey, we live and learn :)
the only thing in the end which was logical to have as a singleton was the logging system which I did truely need to get at everywhere without restriction, everything else would probably have worked better with a passed down smart pointer or normal pointer in initalisation.
but hey, we live and learn :)
Quote:
Original post by _the_phantom_
having had my flirt with singletons i'm not so inclinded to recomend them, when i first learnt about them like most ppl i guess they seemed like 'the answer to everything', but having created a complex bit of software with singletons i feel they hindered the system more than then helpped and infact caused me to use some horrible hacks in places to solve problems :|
the only thing in the end which was logical to have as a singleton was the logging system which I did truely need to get at everywhere without restriction, everything else would probably have worked better with a passed down smart pointer or normal pointer in initalisation.
but hey, we live and learn :)
Singeltons can help with getting access to systems from "anywhere".
I think it's a lot nicer to use singletons than to pass pointers around in the code.
What kind of 'hacks' did you have to do?
In my opinion, design of complex systems can almost always have several singletons, and their use usually make the design a bit better as well...
But I am very interrested in hearing what kind of problems you had with them.. (maybe I can learn something ;-)
yeah, they can help with getting access to things anywhere, but if you step back and think about that for a second it does mean that you can get access to it ANYWHERE.
Passing a pointer to something on the other hand means you can limit the access to only the systems which require it, with the initalisation of the internal pointer to something being done at subsystem construction.
I currently dont have access to the source, its stuck on my other machine which is currently 351million LBAs throught a 490Million LBA zero format with about 12 more hours togo, but if memory serves I had 4 singletons which were :
- Network connection allocator
- Logging System
- Output system
- System Kernel (the program was based on the Enginuity for functional design)
The systems purpose was to query and pass the return of game servers as fast as possible and output the data into a series of files, it was also multithreaded just to add to the fun ;)
As I pointed out earlier, the singletons could be accessed from anywhere, however the question arises why would i need access to say the Kernel or network system from a parser? Which i didnt, instead it became apprent that I probably would have been better off passing down smart pointers to the sections that required access to those subsytems thus keeping everything encapsulatd and clean, the only exception i would have made would have been with the loggin system as I did need access to that anywhere (from parser objects to the networking subsystem).
I think the main issue i had with singletons was the fact that having assigned certain tasks to being singletons I didnt consider the access to those parts of the system as well as i could have, as well as going maybe a little singleton crazy. However i'm also inclinded to put that down to inexperance of designing and building a system of that complexity in the space of time I was initaly given to do it (management dropped a dead line on me of about 2months iirc to have it designed, coded and tested as well as some other things, needless to say i wasnt happy and we missed the deadline by quite a few months), having finished the program I can see all the flaws in it and started work on the next version which was shaping up to be alot better until I lost my job [wink] (not related to my coding btw, its coz an invester pulled out of the company, just thought i'd clear that up [grin])
The program works, and does its job very well but when i go back to the code to perform little updates every now and then I cant help thinking at times 'what was I smoking when I did this?' or 'dear god, why did I do that?', often relating to the singletons and the badly thought out access system around them simple because they were global.
So, while they arent bad, I'd say be VERY carefull with your useage of them, there is often a better way to do things, and this is coming from a converted fan of singletons [smile]
Passing a pointer to something on the other hand means you can limit the access to only the systems which require it, with the initalisation of the internal pointer to something being done at subsystem construction.
I currently dont have access to the source, its stuck on my other machine which is currently 351million LBAs throught a 490Million LBA zero format with about 12 more hours togo, but if memory serves I had 4 singletons which were :
- Network connection allocator
- Logging System
- Output system
- System Kernel (the program was based on the Enginuity for functional design)
The systems purpose was to query and pass the return of game servers as fast as possible and output the data into a series of files, it was also multithreaded just to add to the fun ;)
As I pointed out earlier, the singletons could be accessed from anywhere, however the question arises why would i need access to say the Kernel or network system from a parser? Which i didnt, instead it became apprent that I probably would have been better off passing down smart pointers to the sections that required access to those subsytems thus keeping everything encapsulatd and clean, the only exception i would have made would have been with the loggin system as I did need access to that anywhere (from parser objects to the networking subsystem).
I think the main issue i had with singletons was the fact that having assigned certain tasks to being singletons I didnt consider the access to those parts of the system as well as i could have, as well as going maybe a little singleton crazy. However i'm also inclinded to put that down to inexperance of designing and building a system of that complexity in the space of time I was initaly given to do it (management dropped a dead line on me of about 2months iirc to have it designed, coded and tested as well as some other things, needless to say i wasnt happy and we missed the deadline by quite a few months), having finished the program I can see all the flaws in it and started work on the next version which was shaping up to be alot better until I lost my job [wink] (not related to my coding btw, its coz an invester pulled out of the company, just thought i'd clear that up [grin])
The program works, and does its job very well but when i go back to the code to perform little updates every now and then I cant help thinking at times 'what was I smoking when I did this?' or 'dear god, why did I do that?', often relating to the singletons and the badly thought out access system around them simple because they were global.
So, while they arent bad, I'd say be VERY carefull with your useage of them, there is often a better way to do things, and this is coming from a converted fan of singletons [smile]
Quote:
Original post by _the_phantom_
So, while they arent bad, I'd say be VERY carefull with your useage of them, there is often a better way to do things, and this is coming from a converted fan of singletons [smile]
Yep.. I agree...
This leads us to:
"Singletons is a great tool, when used correctly"
"Use the right tool for the job"
etc...
(Just like everything else)
I also used to be a Singleton fan, I threw all my major systems into singletons and it was nice because they could all access each other. Of course, because they could all call methods from one another it introduced complete dependence on each component. Portability was completely shot, I couldn't replace any systems because they were all so tied in.
Singletons are useful if you use them sparingly.
Singletons are useful if you use them sparingly.
Quote:
Original post by DesCr
Thanks for the tips! They will definately play into my re-designing today. I guess it's time I brush up on my operator overloading, and learn smart pointers :)
Some nice easy-to-use smart pointers can be found in the boost libraries at www.boost.org. The smart pointers keep track of how many times an object is referenced. If an object isn't referenced any more, the smart pointer code will free the memory for you.
It's all internal to the smart pointers library, so you don't have to know anything about the implementation. It's very nice that way. shared_pointer looks the most useful to me, as it behaves like references in C# or Java.
yes, boost::shared_ptr is very usefull, probably the most used one of the group, i've used them extensivly myself and for the majority of things prefer them to normal pointers just for the shear 'dont care' factor they bring as you know everything will get cleaned up in the end [smile]
I used to use singletons for a while. In a library I still would. But in making a game itself, and on my own, I find they add extra awkwardness to your code in order to ... I'm sorry, but I just use global variables now :}
A singleton prevents you accidently making two. In an API, even one you are only using for yourself, this is a good thing. In a self contained program, how many people here really think it's worth it? I don't often need a specific order of initialisation, but if I do they will be global pointers and the objects will be created on startup.
A singleton prevents you accidently making two. In an API, even one you are only using for yourself, this is a good thing. In a self contained program, how many people here really think it's worth it? I don't often need a specific order of initialisation, but if I do they will be global pointers and the objects will be created on startup.
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement