Jump to content
  • Advertisement
Sign in to follow this  
Storyyeller

c++ dividing up the interface

This topic is 3256 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

One thing I've been really confused about lately is figuring out what to put where in the interface. Often times, some members need to be accessed only be certain other classes or functions. For example, suppose I have a class Bullet that wants to give itself a Move behavior. The move behavior needs a pointer to an object with a move function in its interface in order to move its owner. But if I make the move function part of Bullet's public interface, then anything can move it, not just the behaviors. The only options I can think of are sticking everything in the public interface (a seeming violation of encapsulation), or abuse of Friend functors for everything, which seems unnecessarily complicated and prone to mistakes.

Share this post


Link to post
Share on other sites
Advertisement
Your terminology is a bit confusing. It's not clear what you mean by a "behavior," nor why it would need a pointer to an object, nor why a class function being public is a problem.

You are the programmer. If you want the Bullet class to have a move function, add one. As the programmer, you'll determine when that function gets called and you needn't worry about "anything" calling it.

Do I misunderstand your concern?

Share this post


Link to post
Share on other sites
People often overuse inheritance and code-reuse because they're taught from the beginning that it's pretty much the holy grail of software development. Problem is, in my experience, your first few attempts at creating a technology are not going to be good enough to merit reuse.

What's worse is that you spend 8 months trying to figure out if you should create a hierarchy that stipulates Base->Renderable->Dynamic->Bullet or just Base->Object->Bullet or however and forget that all you're trying to do is make a handful of pixels zip across the screen which will probably only be visible for a quarter of a second anyway, and then clean up the memory used for it. One of the most intelligent things I've ever heard was, "A good engineer can estimate the difficulty of a problem and choose the correct set of approaches to consider as solutions..." That was Jay Stelly from Valve, discussing one of the technical problems they had when creating Half-Life. His point was they found a good middle ground devoting just enough time to solve the problem in a way that would be acceptable but they didn't spend 3 years working out how to solve something that most players wouldn't notice. MY very long point is this: will your player notice a difference if your bullet that flashes across the screen is inherited from 8 base classes or just 1 base class?

If you're trying to create a reusable engine and this is your first attempt at such a project, I'd say drop the "reusable" part and the "engine" part for that matter and focus on the end-result. Once you can complete a whole project it makes it much easier to break down how you want objects to interact in the code.

Share this post


Link to post
Share on other sites
More like my second attempt. My first attempt wasn't planned out at all, and ended up duplicating a fair amount of code. I thought that I needed to redesign and rewrite my game, or else it would grow unmanageable once I expanded it to a larger game with more features etc.

I suppose I am going overboard in terms of worrying about design though.


Anyway, here's an example of what I've got so far

class Behavior: public GenericInterface, public ActiveInterface
{
bool active;

protected:
virtual void UpdateMe(){}
virtual void drawMe(SDL_Surface *screen, Sint16 screenx, Sint16 screeny) const{}
void Deactivate() {active=false;} //Call the callback if there is one

public:
Behavior() :active(true) {}
virtual ~Behavior() {if(active){Deactivate();}} //Make sure the Deactivation, and possible callback is always
//called prior to destruction, but don't call it twice (check if it is already not active)

void Update() {if(active){UpdateMe();}}
void draw(SDL_Surface *screen, Sint16 screenx, Sint16 screeny) const
{
if(active){drawMe(screen,screenx,screeny);}
}

void Kill() {Deactivate();}

bool IsActive() const {return active;}
};

class Mover: public Behavior
{
//We are using a regular pointer, rather then a shared pointer, because behaviors do not own their parent
MoveableInterface* target;
double vx,vy;

void UpdateMe()
{
if (target)
{
target->Move(vx,vy); //defined in MoveableInterface
}
else
{
Deactivate(); //If the parent doesn't exist, there's no use for us anymore
}
}

public:
Mover(MoveableInterface* parent, double vx0, double vy0)
: target(parent), vx(vx0), vy(vy0) {}
};

Share this post


Link to post
Share on other sites
Hey, look, he's using multiple inheritance.
A wise man once said that once you find yourself using multiple inheritance for the simplest of tasks and objects, you know your design is flawed. I wouldn't be surprised if you end up with a PolyObject class that looks like this:

class PolyObject : public IMovable, public IRotatable, public IScalable, public IPhysicsable, public IStorable, public IGPUResourceUser, public IRenderable, public IRobot
{
//...
};

Share this post


Link to post
Share on other sites
It could go either way really. I could argue that Dink Smallwood turned out to be a great game despite having an 11,000 line header file and a single source file for the whole game, or I could argue that Unreal Tournament (the original) defined every object, even redefining objects like classes. It all depends on your experience level and style. Carmack accomplished the same thing Sweeney did using a mash-up-hack C method of coding while Sweeney used design patterns and object-orientation. Both games turned out to look, feel, and play about the same. This is what makes me argue that it really doesn't matter.

When I say you're overdoing it I just mean that someone with less experience should be focusing on the core game itself, not complex design patterns and object-oriented programming. They're just weapons in a coder's arsenal, and like weapons, you should probably learn to use the basics before moving onto the complex. Things generally get ugly if someone thinks that because they can use a knife they can use a gun. And I'm definitely running this analogy straight into the ground so I'm gonna stop myself here.

So for now, just keep in mind what you're trying to do and how it will affect the end-result. Keep It Simple, Stupid (KISS), is another practice that many famous programmers have religiously advocated.

Its hard to tell you how you SHOULD do it because based on the code you've shown, I doubt the Bullet class is the only one being over-complicated. I personally just create an array during initialization, drop a projectile in it when needed, then set it's state variable to DEAD when I'm done with it. I do a little more than that but it's not much more complicated than a simple array.

Share this post


Link to post
Share on other sites
I'm thinking about just starting over again, hopefully achieving a middle way between too much focus on patterns, and not enough focus. Hopefully I can just combine lot of the code from my first two attempts a simple, but scalable hybrid design.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!