![]() |
|
OOP Design and Resource Management |
_Kronk_
Member #12,347
November 2010
|
Hey people. I just recently got C++ The Language, and it's really helping me see how amazingly bad my code is and is giving me some great ideas on how to make my game engine API more manageable and stable. So, I have to have a resource manager in my design; it just makes sense. The way I ahve been doing this is to have a single class, ResourceManager, that loads all the datafiles, etc, and also contains all the drawing functions so that anything that needs to be drawn also has indirect access to the data; in this case a user might have an Animation class that contains a list of unsigned ints that are frame indices from the datafile, these are sent to the ResourceManager's draw functions as arguments, etc. TL;DR Should I use a Singleton(which means Resource::f() syntax) or do what Stroustrup seems to like in C++TL, which would be something like this: 1
2// ResourceInterface.h
3
4namespace Resources {
5
6void FlipBuffer();
7void Draw(int x, int y, unsigned frame, unsigned a);
8...
9
10}
11
12// ResourceImplementation.cpp
13
14namespace Resources {
15
16 BITMAP * buffer;
17 DATAFILE * data;
18
19}
20
21void Resources::Draw(int x, int y, unsigned frame, unsigned a) {
22
23 set_trans_blender(0, 0, 0, a);
24 draw_trans_sprite(buffer, (BITMAP*)data[frame].dat, x, y);
25
26}
27
28// etc...
So, users of the Resource code can just using Resources; Draw(myX, myY, anim->CurrentFrame(), anim->A()); instead of (a) exposing the Resource interface directly and (b) having to use verbose syntax. Personally, I prefer using the namespace. Which is better? -------------------------------------------------- My blog: http://joshuadover.tumblr.com |
bamccaig
Member #7,536
July 2006
![]() |
Neither. The "best" is to use a non-static (non-Singleton) instance of your resource manager object. Also, your resource manager probably shouldn't know how to draw anything. That's mixing up concerns. Your resource manager should manage resources well. Nothing more. _Kronk_ said:
namespace Resources { // ... } void Draw(//...
Draw is supposed to be inside of the namespace. -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
_Kronk_
Member #12,347
November 2010
|
bamccaig said: Neither. The "best" is to use a non-static (non-Singleton) instance of your resource manager object. Also, your resource manager probably shouldn't know how to draw anything. That's mixing up concerns. Your resource manager should manage resources well. Nothing more. The reason I have it doing the drawing is that it keeps the allegro backend from users; any code relating to DATAFILEs or BITMAPs is completely contained in the Resource Manager. I suppose I could rename it "GraphicsManager" or something similar to show the relationship better. I'm actually planning on writing an RAII wrapper class for BITMAPs and DATAFILEs, so that a ResourceManager might end up being obselete anyway. If I were to use a single instance of ResourceManager somewhere and then pass around references/pointers to it, that changes the user's relationship to it; you go from 1
2// Drawing_Thingy.h
3
4class Thing {
5
6 protected:
7
8 int x, int y, unsigned frame, unsigned a;
9
10 public:
11
12 void Draw();
13}
14
15// Drawing_Thingy.cpp
16
17#include "Drawing_Thingy.h"
18#include "Resources.h"
19using Resources;
20
21void Thing::Draw() {
22
23 DrawImage(x, y, frame, a);
24
25}
which has an understood the ResourceManager relationship to 1
2// Drawing_Thingy2.h
3
4class Thing {
5
6 protected:
7
8 int x, int y, unsigned frame, unsigned a;
9
10 public:
11
12 void Draw(ResourceManager& r);
13}
14
15// Drawing_Thingy2.cpp
16
17void Thing::Draw(ResourceManager& r) {
18
19 r.DrawImage(x, y, frame, a);
20
21}
which has an understood a ResourceManager relationship, when in reality there is only one ResourceManager. Another question is where would the ResourceManager live? If it were made a member of the Game class, you would have to use syntax like things[i]->Draw(Game->Resources); which isn't nearly as clean or easy to read as the namespace option.
Well, I'll have to go for a regular instance-centric design anyway. Just realized that I can't have an RAII wrapper construct/destruct in a semi-global scope like a namespace when I'm using allegro -------------------------------------------------- My blog: http://joshuadover.tumblr.com |
bamccaig
Member #7,536
July 2006
![]() |
_Kronk_ said: The reason I have it doing the drawing is that it keeps the allegro backend from users; any code relating to DATAFILEs or BITMAPs is completely contained in the Resource Manager. ... ...there is only one ResourceManager. Another question is where would the ResourceManager live? If it were made a member of the Game class, you would have to use syntax like things[i]->Draw(Game->Resources); which isn't nearly as clean or easy to read as the namespace option.
You asked for good practices and I'm giving them to you. I wouldn't pass the resource manager into a thing and have it draw itself with the resource manager though. From the sound of it all of your things are going to have very similar Draw methods. I would try to implement a common interface (abstract base class) for all things drawable and have a renderer object draw those. Your things will implement this drawable interface. The one renderer object can know about the one resource manager and then it's just a matter of saying... for(<each drawable thing>) { renderer.render(<thing>); } The renderer can worry about figuring out which resource to draw for which thing and how based on the interface(s) (you can have multiple drawable interfaces, if you need them, and therefore many overloads of Renderer::render, but you probably won't need this unless you do something beyond drawing a sprite per thing). -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
_Kronk_
Member #12,347
November 2010
|
bamccaig said: You asked for good practices and I'm giving them to you. Don't shoot the messenger.
Sorry, didn't mean to come across that way. I was just kind of frustrated trying to find the best solution. It seems like I've been working on this forever So where would the Renderer be? It wouldn't be global, so maybe a member of the game class? -------------------------------------------------- My blog: http://joshuadover.tumblr.com |
Mark Oates
Member #1,146
March 2001
![]() |
Don't put the cart before the horse. The most important thing to think about is how you want to use the interface. First ask yourself "What would make it the most reasonable and usable?" For example, I hide all my image managing behind the following functions: ALLEGRO_BITMAP *get_image(const char *filename); bool preload_image(const char *filename); bool reload_image(const char *filename); void set_image_path(const char *filename); The above functions include several convience behaviors, including that get_image will never return a null pointer and crash my program. If you haven't preloaded an image yet, no big deal, it will be loaded on first call to get_image and is ready from that point on. Whenever I draw, I draw with the image filename, which acts as the identifier: al_draw_bitmap(get_image("monkey.png"), 50, 20, NULL); This way I don't have to remember indexes or variable names. Everything is consistent. There are a multitude of ways that these functions could be "solved" under the hood, but in the end, it doesn't matter. The important thing is that you should think about how you want to use it first. Then solve for that. Passing around pointers and instances, and juggling namespaces and whatnots is only going to make things worse. -- |
axilmar
Member #1,204
April 2001
|
_Kronk_ said: Personally, I prefer using the namespace. Which is better? Neither. Remember that object-oriented design is about objects. You shouldn't have any manager classes, it's a mistake. You should have objects that represent the actual entities of your program. So, from the text you posted, I can infer the following objects:
|
jmasterx
Member #11,410
October 2009
|
You always want to think, things might change, I might need more than 1 of something. In fact ideally (but not likely) your game should be able to be instanced multiple times and run separate instances of itself on multiple threads happily. I realize the underlying graphics or audio apis might not allow this but you want to think with this idea in mind; anything is bound to change, and singletons are bad. Namespaces are a bit like packages in Java, or folders in a file system. Because C++ relies heavily on libraries you want to know where classes come from. Internally it can be used to organize though: gui::widget::TextBox* textBox = new gui::widget::TextBox(); base::Entity* hunter = new character::enemy::Hunter(); That's overkill but you get the idea. They are used to organize your classes, not to be your classes. Agui GUI API -> https://github.com/jmasterx/Agui |
bamccaig
Member #7,536
July 2006
![]() |
_Kronk_ said:
Sorry, didn't mean to come across that way. I was just kind of frustrated trying to find the best solution. It seems like I've been working on this forever
I hope you didn't take me too seriously. _Kronk_ said: So where would the Renderer be? It wouldn't be global, so maybe a member of the game class? That is an option. It could just be a local variable in whatever function/method the main game loop is in. Where it is depends on your design. It really doesn't need to be known to much of the program though. Mostly only the part that renders the game, which is hopefully only done in one part of the program. It can probably be a local variable somewhere, but it might make sense to make it a member of an object instead. axilmar said: Remember that object-oriented design is about objects. Yes. axilmar said: You shouldn't have any manager classes, it's a mistake. Not really. Managing/manipulating/organizing objects is a necessary thing and in a truly object-oriented world it would be objects that do these things also. axilmar said: You should have objects that represent the actual entities of your program. Yes. axilmar said: When created, it should be setup with the appropriate resources loaded by the above classes. It's debatable whether a bitmap object should know how to load itself from a file. It's especially awkward in C++ where throwing exceptions from a constructor is not so simple. I've found that it's often useful to have a separate class do this. The bitmap object itself becomes just a dumb data object and then you have higher-level objects that manipulate them. -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
AMCerasoli
Member #11,955
May 2010
![]() |
axilmar said: Remember that object-oriented design is about objects. You shouldn't have any manager classes, it's a mistake. I don't know about classes manager (I don't use them when doing OOP), but resource managers it's also a very good idea in OOP. A lot of objects may use the same resources like sounds or images, if you create 50 instances of the same object obviously you're not going to load an image per each object. I use to send a pointer to the resource manager to each of my objects, and if the objects needs an image or sound etc... talks with the resource manager, and the resource managers do all that it needs to do to find that file: search in the .exe directory, sear on internet etc...
|
axilmar
Member #1,204
April 2001
|
bamccaig said: Not really. Managing/manipulating/organizing objects is a necessary thing and in a truly object-oriented world it would be objects that do these things also. Truly object-oriented worlds do not have manager objects. Look around you; do you see any manager object? you don't. Quote: It's debatable whether a bitmap object should know how to load itself from a file. Not debatable at all, for me. The bitmap knows its internal organization of information, and so the bitmap should be able to load itself from a file. Quote: It's especially awkward in C++ where throwing exceptions from a constructor is not so simple. There is no problem in throwing exceptions from constructors. If an exception is thrown from a constructor, the destructor of all up to that point constructed objects will be invoked, as if the object was deleted. Quote: I've found that it's often useful to have a separate class do this. The bitmap object itself becomes just a dumb data object and then you have higher-level objects that manipulate them. And throw simplicity out of the window, for no benefit? AMCerasoli said: A lot of objects may use the same resources like sounds or images, if you create 50 instances of the same object obviously you're not going to load an image per each object.I use to send a pointer to the resource manager to each of my objects, and if the objects needs an image or sound etc... talks with the resource manager, and the resource managers do all that it needs to do to find that file: search in the .exe directory, sear on internet etc... You can always create the resource once and then share it amongst all parts of your code. You don't need a resource manager for that. |
AMCerasoli
Member #11,955
May 2010
![]() |
axilmar said: You can always create the resource once and then share it amongst all parts of your code. You don't need a resource manager for that. If you want and unorganized code, and repetitive code all the time, you can do what you say. isn't the same: std::list<C_bullet*> bullets; bullets.push_back(new Fast(&Res_manager)); bullets.push_back(new Blow(&Res_manager)); bullets.push_back(new Vola(&Res_manager)); Than: 1ALLEGRO_BITMAP *bullet_img = al_loa...
2ALLEGRO_BITMAP *exp_img = al_loa...
3ALLEGRO_BITMAP *air1_bmp = al_loa...
4ALLEGRO_SAMPLE *snd_blow1 = al_load...
5ALLEGRO_SAMPLE *snd_blow2= al_load...
6ALLEGRO_SAMPLE *snd_fall1= al_load...
7ALLEGRO_SAMPLE *snd_fall3= al_load...
8
9std::list<C_bullet*> bullets;
10bullets.push_back(new Fast(bullet_img, sound_touch, sound_roll, snd_fall3));
11bullets.push_back(new Blow(bullet_img, exp_img, air1_bmp, snd_blow1, snd_blow2));
12bullets.push_back(new Vola(air1_bmp, air2_bmp, snd_fall1, snd_fall3));
13
14al_destroy_bit...
15al_destroy_bit...
16al_destroy_bit...
17al_destroy_sam...
18al_destroy_sam...
19etc...
And those are just ~3 arguments per objects... if they where more would be worse.
|
Audric
Member #907
January 2001
|
axilmar said: Truly object-oriented worlds do not have manager objects. Look around you; do you see any manager object? you don't. It's a proof that we don't live in an object-oriented world;) |
axilmar
Member #1,204
April 2001
|
AMCerasoli said: If you want and unorganized code, and repetitive code all the time, you can do what you say. Your example isn't fair. When you are using the resource manager, you are forgetting to tell the resource manager which resources will be needed. Your code should have been like this: Res_manager.load_bitmap("bullet"); Res_manager.load_bitmap("exp"); Res_manager.load_bitmap("air1"); Res_manager.load_sample("blow1"); Res_manager.load_sample("blow2"); Res_manager.load_sample("fall1"); Res_manager.load_sample("fall2"); Res_manager.load_sample("fall3"); std::list<C_bullet*> bullets; bullets.push_back(new Fast(&Res_manager, "bullet", "touch", "roll", "fall3")); bullets.push_back(new Blow(&Res_manager, "bullet", "exp", "air1", "blow1", "blow2")); bullets.push_back(new Vola(&Res_manager, "air1", "air2", "fall1", "fall3")); There is little difference between your approach and mine. Audric said: It's a proof that we don't live in an object-oriented world;) But objects is what exists around us. |
AMCerasoli
Member #11,955
May 2010
![]() |
... Are you crazy? why would I tell the object which resource to load from outside?. The object already know that... 1
2class bullet : public C_bullet{
3 private:
4 ALLEGRO_BITMAP* bm1;
5 ALLEGRO_SAMPLE* sn1;
6 public:
7 bullet(RES_MANAGER *res_manager):
8 bm1 (res_manager->bm_loader("bullet.png")),
9 sn1 (res_manager->sn_loader("sound1.ogg"))
10 {}
11
12 ~bullet(){
13 res_manager->unneeded_res("bullet.png");
14 res_manager->unneeded_res("sound1.ogg");
15 }
16};
And that way all I have to do is just: bullets.push_back(new bullet(&Res_manager));
|
axilmar
Member #1,204
April 2001
|
AMCerasoli said: ... Are you crazy? why would I tell the object which resource to load from outside?. The object already know that... How would you reuse the code then? your bullet example is not reusable code. |
Audric
Member #907
January 2001
|
Sharing code between bullet and another class is irrelevant. The point of a resource manager is to get a kind of cache, where the first demander of a resource causes the load, and any other demander will be given a reference to the same resource, avoiding a second disk access and uncompress. (The second demander may be a second instance of "Bullet", or a very different class like the HUD if it uses the same sprites to display ammo) |
AMCerasoli
Member #11,955
May 2010
![]() |
In the real world objects aren't reusable, at least not this kind of objects. This is the end of the chain, a bullet. A bullet has its purposes, if you want a big bullet then you would do: big_bullet : public C_bullet{.. All the rest would be the same, so the reusable code here is C_bullet which has physics functions and variables that are going to be needed by all the kind of bullets... Well at least that's how I see it. If you want to change just the images used by your big_bullet I would create another object... After all it's another object. big_black_bullet : public C_bullet{.. // this makes more damage so I change that here big_red_bullet : public C_bullet{.. // this makes less damage How to change the physics?, simple: 1
2class big_black_bullet : public C_bullet{
3 private:
4 ALLEGRO_BITMAP* bm1;
5 ALLEGRO_SAMPLE* sn1;
6 public:
7 bullet(RES_MANAGER *res_manager):
8 bm1 (res_manager->bm_loader("bullet.png")),
9 sn1 (res_manager->sn_loader("sound1.ogg"))
10 {
11
12 set_damage(30); // change the damage.
13
14 }
15
16 ~bullet(){
17 res_manager->unneeded_res("bullet.png");
18 res_manager->unneeded_res("sound1.ogg");
19 }
20};
|
bamccaig
Member #7,536
July 2006
![]() |
axilmar said: Truly object-oriented worlds do not have manager objects. Look around you; do you see any manager object? you don't. Our world isn't a purely object-oriented world. An object is something "tangible and relatively stable." There are a ton of things in our world that don't fit that description. This post isn't an object in the real world. There still are "managers" though. The laws of the universe, for example, manage much (everything?) of what happens. We can't actually move in space. We can only operate muscles inside of us that interact with our limbs that interact with our surroundings; our surroundings then push us around. axilmar said: Not debatable at all, for me. The bitmap knows its internal organization of information, and so the bitmap should be able to load itself from a file. A bitmap and an image file (even a bitmap file) are two different things. They're very closely related (especially the bitmap file), but they are still distinct. axilmar said: There is no problem in throwing exceptions from constructors. If an exception is thrown from a constructor, the destructor of all up to that point constructed objects will be invoked, as if the object was deleted. Yes, but you are still responsible for cleaning up any non-RAII state that the constructor has done so far. I didn't say that it wasn't possible. I just said it was awkward. axilmar said: And throw simplicity out of the window, for no benefit? There is benefit. It makes more sense. In the real world, an image doesn't do anything. It's a static object. It can be manipulated, but it needs something external to manipulate it. The same is true of most other objects. There are things that the objects themselves can do, but there are also things that can be done with the objects. The latter is usually the one that we're dealing with. A hammer doesn't pound in nails. A person, for example, pounds in a nail with a hammer. The hammer has attributes that make it good for pounding in nails, but the hammer itself doesn't do anything. axilmar said: You can always create the resource once and then share it amongst all parts of your code. You don't need a resource manager for that.
That's what a resource manager does for you. A bullet should not have functions on it to describe its physics, IMHO. A bullet should just describe the attributes of the bullet itself (and since it does nothing, doesn't really need any functionality). It's a dumb object. It might have a mass, maybe it has a shape, but how it interacts with the world is up to the particular world that its in. -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
AMCerasoli
Member #11,955
May 2010
![]() |
bamccaig said: A bullet should not have functions on it to describe its physics, IMHO. A bullet should just describe the attributes of the bullet itself (and since it does nothing, doesn't really need any functionality). It's a dumb object. It might have a mass, maybe it has a shape, but how it interacts with the world is up to the particular world that its in. Yes bamccaig, and we're going to spend the rest of our life creating a perfect and completely similar world in which we live on. At the end with 80 years old axilmar is going to have a library of 50.000.000 files, which actually don't do anything, you would need to join 30 classes to make a ball move in the screen... ahahahahaha. I think you went too far body. class ball : public texture, public material, public molecules, public atoms{..
|
bamccaig
Member #7,536
July 2006
![]() |
You don't have to model every last detail. You only need to model what exists in your world. That doesn't change how they should be manipulated. Usually objects interact with other objects. Sometimes they interact in weird ways with the entire world. If you try to store that in each object then the entire world is going to have to know about the entire world. If you use higher-level managers or service objects then you can centralize this functionality much easier, IMHO. Ultimately, the language doesn't put any restrictions on you. A method is just a dumb function that gets an implicit argument passed to it. It's up to the programmer to figure out what is appropriate where. Bullet::shoot(Player &) could just as easily be Player::shootWith(Bullet &). So which is it? Both? It could instead be, World::shoot(Player &, Bullet &). The Player doesn't need to know about the Bullet and visa-versa. -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
_Kronk_
Member #12,347
November 2010
|
I think I'm finally starting to see the light on all this A rough outline of my new design: 1
2int main() {
3
4 init_allegro();
5
6 try {
7
8 Game game;
9 game.Run();
10
11 }
12
13 catch(MyException& e) {
14
15 cout << "Exception: " << e.name << endl << "Cause: " << e.cause << endl;
16
17 }
18
19}
20
21void Game::Run() {
22
23 try {
24
25 ResourceManager resources(cfg file name);
26 ObjectManager objects(cfg file name);
27 Map map(cfg file name);
28 Renderer renderer();
29
30 if(NeedUpdate()) {
31
32 objects.Update();
33
34 map.Draw(renderer);
35 objects.Draw(renderer);
36 renderer.FlipBuffer();
37
38 }
39
40 }
41
42 catch(MyException& e) {
43
44 cout << blah;
45
46 }
47
48}
I'm also going to be working from a RAII standpoint in code as well. I'm kind of stoked. This is going to be much less of a beast to work with than my previous design -------------------------------------------------- My blog: http://joshuadover.tumblr.com |
axilmar
Member #1,204
April 2001
|
Audric said: Sharing code between bullet and another class is irrelevant Reuse is irrelevant? since when? Quote: The point of a resource manager is to get a kind of cache, where the first demander of a resource causes the load, and any other demander will be given a reference to the same resource, avoiding a second disk access and uncompress. A variable is good enough for this purpose. No need for a cache. AMCerasoli said: In the real world objects aren't reusable, at least not this kind of objects. This is the end of the chain, a bullet. In the real world, we should reuse as much code as possible. Quote: If you want to change just the images used by your big_bullet I would create another object... After all it's another object. So if all a class does is change the images, why not have one class and load the images to the object externally using a function? it makes more sense. bamccaig said: There still are "managers" though. The laws of the universe, for example, manage much (everything?) of what happens. We can't actually move in space. We can only operate muscles inside of us that interact with our limbs that interact with our surroundings; our surroundings then push us around. That's not management, that's interactions based on rules. Quote: A bitmap and an image file (even a bitmap file) are two different things. They're very closely related (especially the bitmap file), but they are still distinct. I didn't say otherwise. Still, a bitmap should use the image file internally to load itself from disk. That's proper OO. Quote: Yes, but you are still responsible for cleaning up any non-RAII state that the constructor has done so far. I didn't say that it wasn't possible. I just said it was awkward. That's what smart pointers are for. There is nothing awkward to it. Quote: The latter is usually the one that we're dealing with. A hammer doesn't pound in nails. A person, for example, pounds in a nail with a hammer. The hammer has attributes that make it good for pounding in nails, but the hammer itself doesn't do anything. Then you would need a person object that knows everything. Not good OOP. Quote: That's what a resource manager does for you. And therefore a resource manager is redundant. Quote: It can potentially do it much easier. I've yet to see an example of how a resource manager makes it easier. Anyone care to post one? Quote: A bullet should not have functions on it to describe its physics, IMHO. A bullet should just describe the attributes of the bullet itself (and since it does nothing, doesn't really need any functionality). It's a dumb object. It might have a mass, maybe it has a shape, but how it interacts with the world is up to the particular world that its in. No, that's part of the Bullet subclass, not an external object. The common attributes of bullets belong to the Bullet class, and the particular physics of the world belong to the Bullet subclass. AMCerasoli said: Yes bamccaig, and we're going to spend the rest of our life creating a perfect and completely similar world in which we live on. At the end with 80 years old axilmar is going to have a library of 50.000.000 files, which actually don't do anything, you would need to join 30 classes to make a ball move in the screen... ahahahahaha. I think you went too far body. On the contrary, I'd have one Bullet class. |
Oscar Giner
Member #2,207
April 2002
![]() |
axilmar said: I've yet to see an example of how a resource manager makes it easier. Anyone care to post one? Not needing to keep track of duplicate bitmaps accross all yout program manually. Also, the example posted earlier assumes that the resources needed are known at compile time (they're hardcoded). It's also nice that, when entering a new level, the resource manager automatically frees any resource that will not be used by the new map, but keeping the ones that will be used (a lot of games fail at this though, and always unload everything and reload again the needed resources at each map change). How do you do this without a resource manager? -- |
jmasterx
Member #11,410
October 2009
|
A resource manager can do reference counting on expensive resources like bitmaps. This way each class that might need a Bitmap just requests it from the RM and the class calls releaseBitmap() once it is destroyed and so resources are never duplicated and only freed when they are no longer needed. Agui GUI API -> https://github.com/jmasterx/Agui |
|
|