Thread: I believe I've found an official Answer to my Problem (Object Factories)

  1. #31
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    Rob gave me this though, and it did give me hope...
    Code:
    class TrollMonster
    {
    public:
       virtual void Update()
       {
          if (daylight)
             TurnToStone(); // This function is ONLY specific to Trolls and doesn't exist in the base Monster class!
          else if (feel_like_dancing)
          {
             DoTrollDanceOfTrolls();
          }
          else
             DoSomeOtherTrollStuff();
       }
    
    protected:
       void TurnToStone()
       {
          // Code to turn trolls to stone 
       }
    
       void DoTrollDanceOfTrolls()
       {
          // Code to make troll dance
       }
    
       void DoSomeOtherTrollStuff()
       {
          // Troll stuff
       }
    };
    We virtualize a single Update function, along with a couple virtuals for rendering info, physics info, sound info and such...

    Basically, the AI is handled in the Update function, or you could add to the virtualizedupdate function based on an AI engine...

    We just throw an Update into a loop checking if the new Monster1 exists, if it doesnt, loop ends, no more updating for that monster and monster1 is unregistered and deleted...

    I believe this is it what we're trying to do.
    Last edited by Shamino; 12-17-2005 at 07:58 PM.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  2. #32
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    Quote Originally Posted by Shamino
    Read my edit, first of all this wouldn't work at all...
    I did, read my post.

    Quote Originally Posted by Shamino
    But, to answer your question, as if this would work...

    if something points to something, it always points to it, no matter where you put it or send it...

    if we pass bashyourheadoff pointer to the monster1 thingy..

    and then call monster1->bashyourheadoff
    That wasn't a question but yeah I understand that it points to it - duh.

    But how is Monster1 able to have a function called bashyourheadoff just because you passed it a function pointer? You would need to store that function pointer and call it in another function, and since Monster1 is unaware of what functions you are passing it, it would not have a bashyourheadoff function, but it might have something called function1 which calls the first function pointer. However you're still unable to get n amount of function pointers and functions for those function pointers in the class.

    I'm tired of rewriting that, read my old posts again if you still want to say you can call monster1->bashyourheadoff just because you passed its constructor a function pointer.
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

  3. #33
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    Monster1 is a mailman

    All he does is deliver letters, he needs an address, he doesn't need to know who lives there, or whats in the letter...(I love it when my programming teacher is right)

    Monster1 is an object, he has an address for bashyourheadin...

    he doesn't need to know what bashyourheadin does to execute it as long as he has an address for it
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  4. #34
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    Quote Originally Posted by Shamino
    I believe this is it what we're trying to do.
    I hope you're not talking about what I'm trying to do (and do know how to do), as I've known what I wanted to do for more than a page now and was just trying to undo what I did to your mind. I think I'm the one that got you hooked on this whole idea about render accepting a generic class without losing data and still remaining easily manageable. (even though I still think templated method is fine for that).

    Yeah that Update a nice way to go about it, which I said when you originally posted it. It allows for differences in how things are handled in subclasses with one general method.
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

  5. #35
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    I keep forgetting our problems are seperate...

    Lol, we're trying to solve them together... Bad mistake?

    lmao... thats funny....

    But anyways, I found my answer.... Rob's update function thingy...

    My problem was passing a generic object to every engine in my game, not passing everything that the object has, only the information that the engine needs, so it's okay if I lose some data..

    Just not what each specific engine needs...

    Virtual functions would be an easy solution, but with 100 different specific functions that would have to be put in the base class, not good....

    An update function is a solution to that, and hopefully, i'm thinking it is my final solution...
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  6. #36
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    Quote Originally Posted by Shamino
    Monster1 is a mailman

    All he does is deliver letters, he needs an address, he doesn't need to know who lives there, or whats in the letter...(I love it when my programming teacher is right)

    Monster1 is an object, he has an address for bashyourheadin...

    he doesn't need to know what bashyourheadin does to execute it as long as he has an address for it
    It doesn't matter.

    Monster1 does need to know how many variables it has, and what functions it has. The amount of functions you send to Monster1 also varies, so how can that be possible?

    Monster1 is unable to know the return type of bashyourheadin, or the name of the function its recieving so it cannot just up and create (or point) a function for itself called bashyourheadin.

    You could do this if the amount of function pointers you passed was constant and you knew their return type and name, and created all of that in Monster1, but thats completely against the point of what you wanted to do. Since that would be the same as virtual functions.

    Seriously, you can't just add functions to Monster1 because you pass 15 function pointers to its constructor. Nor could they use the same name as the functions you're passing.

    Gah, I'm so done with this thread.

    Edit: I dont have a problem to solve anymore, I've said that 10 times. I was replying to your problem for the last page and a half. Yeah, stick with the Update() function. Its good.
    Last edited by Dae; 12-17-2005 at 08:15 PM.
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

  7. #37
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    Okay, you're prolly right Dae (as I am more of a newbie than you, I gaurantee)

    Only reason I though that is because robert didn't challenge that Idea when I gave it to him...

    But it doesn't matter, I've solved my problem, yay...

    We're both happy now
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  8. #38
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    Defiently!

    Eh, we're about the same level, its just easier to see how insane one is when its not yourself.

    Theres no reason to be unhappy, its winter break damnit!

    Can't wait to impliment the stuff I've read the past couple days. A lot my ideas on how to go about things was iffy before you started all these topics Shamino.
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

  9. #39
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    Questions lead to answers, and answers lead to this


    IM FREAKIN ECSTATIC ABOUT THIS!!!!

    THIS IS SUCCESSSSSSSSSSSSSS

    http://img.photobucket.com/albums/v131/Shamino/OMG.jpg

    ONE CLIENT!!!!

    MULTIPLE ENGINE USAGE!!!

    I can't believe it, I programmed something INCREDIBLY OOP'd up and amazingly useful!
    Last edited by Shamino; 12-18-2005 at 02:23 AM.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  10. #40
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    Nice!

    P.S. I cant believe you're still using the class factory. You wont benefit from it the way you are using it. Its also slowing you down a little bit, and adding extra lines of code that aren't necessary.
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

  11. #41
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    Why is it slowing me down?

    Adding lines of code?

    What could be simpler?

    Creating a new object in two lines of code

    I can pass it as an *Object as well, which is the key issue here..

    I'm using the language the way it was ment to be used, object orientedly, with virtual functions...

    If it can realistically slow down and be noticeable just because of a few virtual functions, I'll blame that on the computer..

    I think I can pass it as an object....

    I hope.....

    EDIT:

    BTW, I added you to AIM, log on !
    Last edited by Shamino; 12-18-2005 at 03:55 AM.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  12. #42
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    What could be easier is just creating an object of Ship yourself. Why go through this sidestep of giving the class factory a function pointer to your class and an id, and then two lines later call a new object of that class?

    Its slowing you down a little bit because you're putting the pointers in a map which takes O(log n) to search. Whereas you could just instantiate it because you already have access to it. Just #include the header file and CGoblin SomeGoblin;.

    A few pages back, I mentioned why this class factory isn't what we thought it was on the first page. But if you have some reason to be assigning classes to id's when you already have access to them, alrighty.

    BTW, I could be wrong, but I reread Bubba's post a couple more times and I don't think you have it implimented the way he has it. Just so you know. If you reread it concentrating on the pool part and using id's part.
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

  13. #43
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    EDIT: I posted this before reading the last page. Mea culpa. Ignore if you feel like it.

    You're theorizing without keeping one foot on the ground. As a result, you think up "great ideas" - but they're actually quite useless.

    With your bashyourheadoff() method, it seems that you think it's necessary, but have you even tried to think up a concrete example of a situation where the PlayerEngine has to call it?

    Let's for a moment assume the game is a Gamboy Pokemon-style round-based fighting game. You're in a fight with the Ogre. What does the game really need to know?

    1) It needs to render an image of the ogre in the lower right corner. Character::getFightImage() is one virtual function that is required for this.
    2) It needs a list of attacks the ogre can do. Character::getAttacks() is a virtual function that returns a list of Attack objects. (Actually, both these functions would be non-virtual and read from data files, but let's go with your split objects here.)
    3) Each Attack object has attached a name that can be displayed to the user, perhaps an ID, perhaps an animation of the attack itself.
    4) In addition, there's a Character::getAttackSequence(Attack*) to get an animation of this monster executing this particular attack.
    5) Finally, you need Character::getAttackValue(), Attack::getBaseDamage() and Character::getDefenceValue() (for the player) to calculate the damage the attack did.

    Did you see bashyourheadoff() anywhere?



    On a side note, templates are done at compile time, so you can't step from runtime polymorphism to compile-time polymorphism. The moment you store the monsters together in a list, you've lost their type information.
    Last edited by CornedBee; 12-18-2005 at 04:12 AM.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  14. #44
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    To answer the question of IDs:

    An ID is simply the index of the object in the index which contains all of the game objects, or at least all of them for the current level, or the current map area that has been loaded in (say in a flight sim).

    You don't pass multiple objects to the renderer Shamino. In fact you don't pass any objects. The render function is composed of a frustrum culler that firsts trivially rejects all objects that are not in the frustrum. Once the trivial rejection is complete you could code another more accurate function but I did not for good reason. Given the complexity of objects and given that most objects will completely be inside of the frustrum or completely outside, it did not make sense to waste CPU cycles on figuring out how to split complex objects across frustrum planes. So I pretty much just let brute force hardware do it. It's not the best, but it is better than using complete brute force.

    Once the object passes the tests it's ID is then put into the final render list. So you are guaranteed that at the end of the cull, you are only computing physics and other information for those objects that are visible or could be visible. Now in a flight sim where physics are computed for every object, you only do that in memory so they still don't need to be in the render list. For FPS games there really is no need to compute physics info for monster A that is 500m away from your position, unless your engine supports real-time monster movement. If you notice, most games don't. Most game worlds are quite static and for good reason. They try to cover the static portion by making the monster act realistic 'when he is visible or near', but when he is out of bounds, he really doesn't exist.
    Derek Smart tried to create a fully functional real-time space sim with Battlecruiser 3000AD and had major problems. BCM actually comes quite close to doing it well, but still suffers. Don't get me wrong his engine actually does it very well, but I think that graphics suffer due to the load from the other systems updating the universe.

    The point is, if you cannot see it, don't render it. If you are not anywhere near it, don't update it.

    Ok, now you have the render list. Now transform, do the physics calcs, collision test, and render.

    See the render list is built every frame or in a really good system, it is cached and re-used. As objects leave the frustrum they are removed from the list. This is NOT easy to code but it is a good system. This is why I've been slamming my head against a wall trying to get this stuff working.

    I don't use Object factories, I use vectors and arrays or simply container classes. Objects are just that - objects. So treat them as such. It is a whole lot easier creating containers to manage the separate portions that make up the whole than creating several objects with identical functions. My system basically has resources that are out there in memory to use at any time. All you need is the index. The index or ID is a universally unique identifier for ALL vectors/arrays. So object 1 is at physics 1, vertex data 1, etc, etc.

    So this render list:
    2,10,400,10000,14000,23,40,55,6782

    Would mean that objects with these indexes are currently in the frame and need attention. But you still need to do some type of quadtree cull and then a frustrum cull to get the data size down to something the CPU could do in this lifetime. The quadtree or BSP would determine which objects are at least in proximity of the player. The frustrum cull would eliminate those objects close to the player that he cannot see. You would probably update physics information for all objects that passed the quadtree so that objects behind the player can still fire on him, move, etc.
    But you only draw the one's that pass the frustrum cull.

    Huge array of data
    - QuadTree test - close to the player, store and cache
    --- Frustrum Cull - visible - store and cache, and render

    Update all objects that pass QuadTree test - maintain cache and remove items that are no longer in proximity.

    Only draw those that pass the frustrum cull test. Cache these as well for quick reference. If an object fails the frustrum test - remove it from the list.

    Perhaps Bob and I should get something like this up and running.
    Don't get me wrong, it's not easy and it's not really fun programming, but it is extremely necessary.

    So you see that if your resource cache is in such a state as to be unusable or overly 'C++' then when it comes time to start using the data and objects you will have a huge mess.

    Keep it simple and straightforward. No one cares how you get it done, just that it's fast, usable, robust, and does the job well.
    Don't use OOP just for the sake of being OOP elite or something. It is a tool that can be used, but it can also be abused.

    In my system the container classes handle all accesses to the objects they contain. You do not create the objects but you do ask the container class to create them. So I guess it is a factory of sorts, but I avoid all the templates, pre-processor, and functor issues in C++. A member function pointer cannot be called w/o being called from an object. You cannot easily assign a member function pointer to point to a non-member function. Look up functors. A good topic for containers would be singletons as well.

    Final word. Use inheritance and virtual functions wisely.

    I'm not saying this is the only way to do it, but it works for me.
    Last edited by VirtualAce; 12-18-2005 at 06:07 AM.

  15. #45
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    This warrants another post.

    You also do not want to hard-code functions that perform actions per se. Your script system should be closely connected to the engine so that it can manipulate objects at will - again based on IDs.

    Your system should be message based. Instead of the system always querying for information you need to get to the point that the systems can communicate back and forth. If an object needs attention then the object should be sent a message through the message system.

    This changes the whole paradigm of games programming because once you get this working you can now create demos and testbeds for the game by simply writing a script. Instead of this:

    Code:
    if (Mouse.Pressed(Controls.dwFire)
    {
      Object->Fire();
    }
    You have this:

    Code:
    if (Mouse.Pressed(Controls.dwFire)
    {
      MessageSys->SendMessageToObject(MSG_FIRE,Object,TargetObject)
    }
    So now when you do the multiplayer, you just look at the incoming message and send it to the system and it will do what you want. For scripts you simply interpret the script and then relay the correct message and the action is performed.

    It's a lot like Win32 programming and the systems for it. Hopefully not as messy or slow, but you get my drift.

    Notice the sheer genius of the MSG structure in Windows. This one structure is applicable to all windows objects and every object relies on it. This is what you need for your game. That way you can use one function to send messages and based on the message, the parameters will have diff meanings.

    In Windows to repaint a window you can either call your Paint function or you can send a message to a window provided you have its handle. But Windows does not specifically call the Paint function for that object. It sends a message and the object(s)responds to it. This allows any implementation of the WM_PAINT message and allows any function name to be used. Much the same for bashyourheadoff(). If you hard-code it, you will code yourself into a corner.

    What does Windows do? It calls your WndProc() and the MSG is a parameter. You then act on the message and the Windows SDK tells you what that message is pertaining to and so you code your implementation of it.

    Get a message system up and running soon after your resource system. And when you design your resource system and all systems keep in mind the underlying message-based structure. There is more to talk about concerning documents and views, the document being the game data, and the view being the render. If you implement this right, switching cameras is a simple matter of switching views.
    Last edited by VirtualAce; 12-18-2005 at 06:28 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. using this as synchronization object
    By George2 in forum C# Programming
    Replies: 0
    Last Post: 03-22-2008, 07:49 AM
  2. problem with answer going to default?
    By Patrick1234 in forum C++ Programming
    Replies: 4
    Last Post: 10-02-2002, 09:11 AM
  3. slight problem just can't see the answer
    By anthonye in forum C++ Programming
    Replies: 1
    Last Post: 07-05-2002, 08:45 AM
  4. I've ran into a problem
    By Mike Jones in forum C Programming
    Replies: 1
    Last Post: 03-27-2002, 04:08 PM
  5. code help :)
    By Unregistered in forum C Programming
    Replies: 4
    Last Post: 02-28-2002, 01:12 PM