gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Beginners > Am I overengineering?

#34449 - Steve++ - Wed Jan 19, 2005 7:50 pm

I'm making a sprite collision messaging system with a client/server architecture. Just wondering if I'm going overboard (especially for a GBA project). Here's a code snippet (only a tiny piece of the system):
Code:
#ifndef SPRITECLIENT_H
#define SPRITECLIENT_H

#include "fixedmath.h"
#include "SpriteServer.h"
#include "Grid.h"
#include "LinkedList.h"

class cSpriteClient : public cPoolable<cSpriteClient>
{
    cSpriteServer* m_pServer;
   FIXED m_fxdX;
   FIXED m_fxdY;
   unsigned char m_nCategory;
   cLinkedList<cSpriteClient*>* m_plstCollisions;
   cLinkedList<cSpriteClient*>::cIterator* m_pitrHostCellList;
   cLinkedList<cSpriteClient*>::cIterator* m_pitrServerOffScreenActiveList;
   
public:
   bool m_bVisible;
   void (*m_pfncAction)(cSpriteClient*);

   cSpriteClient();
   void init(   cSpriteServer* pServer,
              unsigned char nCategory,
             cLinkedList<cSpriteClient*>* plstCollisions,
            void (*pfncAction)(cSpriteClient*));

   void setXY(FIXED fxdX, FIXED fxdY);
   unsigned char getCategory();
   void getCollisionIterator(cLinkedList<cSpriteClient*>::cIterator* pitrCollisions);
   
   friend class cSpriteServer;
   friend class cGrid::cCell;
};

#endif

#34452 - poslundc - Wed Jan 19, 2005 8:35 pm

Not sure what kind of game you're making, but... probably. Don't know why you'd need or want a client-server architecture since most games have just a single collision management routine.

Other stuff in your code like linked lists (unless they operate from a static pool), accessor methods that aren't inlined, templates (not necessarily bad, but iffy), and friend classes (which often defeat the point of encapsulation) make me wince a little.

Dan.

#34465 - sajiimori - Wed Jan 19, 2005 11:33 pm

On the other hand, I reserve my wincing until I actually find out if the code is good. My code is filled with linked lists (generally from STL which use dynamic pools), accessor methods that don't have their bodies declared in the header (but are inlined anyway by including a seperate .inl file), templates (which let me write fast code which is also safe and general), and friend declarations (which allow me to move irrelevant parts of an implementation to internal classes, and let me write manager classes that have special privilages over their managed objects).

#34467 - poslundc - Thu Jan 20, 2005 12:25 am

sajiimori wrote:
On the other hand, I reserve my wincing until I actually find out if the code is good. My code is filled with linked lists (generally from STL which use dynamic pools)


Interesting... do you use malloc or your own routine, and does it use EWRAM or IWRAM? Do you have to deal with exceptions and fragmentation? And does it affect matters for you that STL lists are dually-linked at all? Sorry for all the questions, but I don't often hear of people using STL in their GBA programming.

Quote:
accessor methods that don't have their bodies declared in the header (but are inlined anyway by including a seperate .inl file)


I've not seen that style before. Would you not want to #include the .inl file in the header file, though?

Quote:
templates (which let me write fast code which is also safe and general


I agree that templates are fine so long as they aren't applied lazily, which can both bloat code and cause the square-peg-round-hole syndrome.

Quote:
and friend declarations (which allow me to move irrelevant parts of an implementation to internal classes, and let me write manager classes that have special privilages over their managed objects).


Eh, I think there's a time and place for friend declarations, but a server/client architecture doesn't generally behoove this, in my opinion anyway. Especially since the clients are likely to be various subclasses of a base client class, and the server shouldn't have any reason to mess with the clients' private members.

Dan.

#34476 - tepples - Thu Jan 20, 2005 2:04 am

poslundc wrote:
Don't know why you'd need or want a client-server architecture

Client-server from the start scales up to multiplayer more easily. Q3A for example uses client-server even in single-player mode.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#34479 - sajiimori - Thu Jan 20, 2005 4:00 am

Quote:
Sorry for all the questions, but I don't often hear of people using STL in their GBA programming.
The code in question isn't technically for GBA, but given the chance I would have written things this way even on my previous project (which was for GBA).
Quote:
do you use malloc or your own routine
I would have overloaded the global new/delete (just as I am on my current platform) to use custom routines.
Quote:
and does it use EWRAM or IWRAM?
I probably would have used EWRAM for most or all dynamic lists.
Quote:
Do you have to deal with exceptions
STL doesn't throw exceptions.
Quote:
and fragmentation?
The memory waste from oversized static arrays usually outweighs the loss due to fragmentation in my experience.
Quote:
And does it affect matters for you that STL lists are dually-linked at all?
Sometimes I use std::list, but more often I use the singly-linked std::slist.
Quote:
Would you not want to #include the .inl file in the header file, though?
Yes. The point is to keep the .h file clean because it serves as interface documentation.
Quote:
I agree that templates are fine so long as they aren't applied lazily, which can both bloat code and cause the square-peg-round-hole syndrome.
a.k.a. the "crappy programmer" syndrome. We've had an 8 page conversation about this before, though.

#34497 - poslundc - Thu Jan 20, 2005 3:27 pm

tepples wrote:
poslundc wrote:
Don't know why you'd need or want a client-server architecture

Client-server from the start scales up to multiplayer more easily. Q3A for example uses client-server even in single-player mode.


I suppose that's true, and I can understand doing that for code that is meant to be portable... still seems a bit much considering the fairly narrow limitations on GBA multiplayer.

Dan.

#34498 - poslundc - Thu Jan 20, 2005 3:41 pm

sajiimori wrote:
The code in question isn't technically for GBA, but given the chance I would have written things this way even on my previous project (which was for GBA).


OK; I'd assumed it was.

Quote:
Quote:
Do you have to deal with exceptions
STL doesn't throw exceptions.


I know... I guess I meant was do you need to build an exceptions model into your code, or do you just rely on engineering constraints into the game as well as patterns in how you allocate/delete to prevent out of memory and fragmentation errors?

Quote:
Quote:
I agree that templates are fine so long as they aren't applied lazily, which can both bloat code and cause the square-peg-round-hole syndrome.
a.k.a. the "crappy programmer" syndrome. We've had an 8 page conversation about this before, though.


Fair enough. And like I said, the original post's use of templates was not necessarily (or even probably) ill-advised, especially since there are only two class instances being generated by it and they seem like they would be very narrow, functionality-oriented library classes. It just makes me wince a little in the midst of everything else going on. :|

Dan.

#34501 - Steve++ - Thu Jan 20, 2005 4:29 pm

I'm using my own linked list template. It allocates from a pool. That's what the cPoolable template is all about. For any class/template whose instances I want to be compatible with an object pool, I simply make it inherit from cPoolable<class-name>.

Each sprite is given a category (1 to 15 (or so)). The server has a table where each row represents which category to test for collision with which other category. Every frame, the server finds all the viewable sprites and those sprites marked as active when off-screen and puts them into active lists. If there are, say, 15 categories, then there will be 15 active lists - each sprite being in the list for its category. The server then works through the category comparison table and tells each sprite which relevant sprite(s) has/have collided with it. Then the server calls the action function of each sprite. The action function has access to its sprite's collision list so it can act accordingly. Then the server clears that sprite's collision list, ready for the next frame. Pretty neat, eh?

Using this sort of architecture, the sprites don't need collision detection in their behaviour-specific code.

#34522 - sajiimori - Thu Jan 20, 2005 10:14 pm

Quote:
I guess I meant was do you need to build an exceptions model into your code, or do you just rely on engineering constraints into the game as well as patterns in how you allocate/delete to prevent out of memory and fragmentation errors?
If there were an automated (and reasonably efficient) way to prevent out-of-memory errors (whether due to fragmentation or real memory usage), I'd be all over it. As it is, exceptions don't provide such a solution, so like everybody else, I rely on engineering constraints.

In particular, large contiguous allocations need special attention, usually in the form of an early allocation (perhaps even before the exact data size is known, which obviously requires overestimation). Static data is the most extreme form of preallocation.