OOP and what solution you would use.

Started by
18 comments, last by Surg 14 years, 8 months ago
Quote:Original post by solinent
Hmmm alright, I guess you are correct. I just don't like passing objects in the constructor really (then I have to worry about copying objects, and since I'm using OpenGL handles, I do have nontrivial destructors in some cases).

Then pass by (const) reference instead.

Quote:I always thought that proper OOP design uses composition and inheritance in different places (inhertance for specifying "is a type of" and composition for "has a").

That's the rule of thumb, yeah. But things can be designed in different ways: a game entity can be seen as a renderable, updateable thing, but it can also be seen as an updateable object that owns (or can own) a renderable.

In this case, I'd probably write a separate class that contains both a physics object and a renderable object. This keeps physics and rendering code in their respective classes, and lets the third class deal with rendering a rigid body. That 'glue code' shouldn't clutter those two classes.


As for physical objects always being rendered (or always being rendered with the same orientation, or always as a mesh), that may not always be the case, depending on the situation. You could perhaps reuse that physical object class for trigger areas, or render it as a bunch of particles.
Create-ivity - a game development blog Mouseover for more information.
Advertisement
For what it's worth, in my project I have a position component. Game objects may include a position component. When rendering/performing collision detection/collision response/object picking/etc the position is read from the position component. This way I can have invisible objects that can interact physically, or visible objects that do not interact physically and all other combinations of components. There is a sort of component dependency here, but that's another topic.
Quote:Original post by solinent

I always thought that proper OOP design uses composition and inheritance in different places (inhertance for specifying "is a type of" and composition for "has a").


It is; the common problem is deciding on whether something contains another thing or it contains another thing. One common example is game objects, are all objects a type of object or are they all the same only containing different components? In my opinion and experience the more flexible approach is to say it contains components as it creates a greater level of reuse.

Although not always useful inheritance is very useful for subsystems and other things that offer different functionality for the same inputs without having to co-exist. I use inheritance for my rendering subsystem which allows for switching between OpenGL, Direct3d, or any other renderer able to supply outputs for the inputs the interface defines.
Quote:Original post by Zahlman
Quote:Original post by solinent
I was hoping for a inheritance solution.

I know how to get it to work, I just want to know what OOP provides me. I can do composition fairly well, but I have trouble thinking about inheritance patterns for some reason. I was just wondering if someone here found a nice pattern to use.


Here's the thing: OOP has at least as much to do with composition as it does with inheritance - much more, actually, according to some. After all, composition is how you specify objects - they consist of their data members and their methods/member functions, and bases are really just data members with a thick coating of syntactic sugar. It's been found in practice that overuse of inheritance is much more common than underuse; and anyway, inheritance is simply one way of getting at subtyping, which is the real underlying "OOP concept", if anything.

IOW, the "nice pattern to use" is called "composition". :)

Interfaces work, too, but they're tricky to get right in C++, and involve lots of boilerplace in Java. In Python, it's generally all ad-hoc anyway, to the point where there isn't even really a clear line between doing it the "composition way" and doing it the "interface way". (It's quite unusual for Python coders to go out of their way to hide part of the functionality of one class from another class. You might say that Pythonistas see encapsulation as more of an organizational tool rather than a security measure. I know that's the case for me, anyway.)


I actually take this to the extreme. I almost never inherit for purposes of implementation. And when I say almost never I really mean almost never. The past month or two there were 3 or 4 situations where I thought to myself "ok, now *this* actually makes sense to have it use implementation inheritance." couple weeks later when I needed to enhance it somehow I was like "/sigh, should have used containment".

The thing is, a lot of times inheritance does "make sense" from a conceptual point of view. It's also sometimes easy to implement. But it doesn't scale well, it's not flexible, and it's error-prone. For example, to obtain base class functionality you have to explicitly call the base class version of a function. Like say you implement some method foo() and you override that in a derived class. The derived class then has to remember to call the base foo() in order to gain its functionality. But where do you call it? At the beginning? Somewhere in the middle? At the end? The answer: it depends what you want to do. That answer sucks, because it leads to spaghetti code and bugs. Any time the client of something has to "remember" things it has the potential to lead to bugs and bad code.


So, what do you do? How about this:

struct IRenderable{   virtual ~IRenderable() {}   virtual void Render() = 0;};struct GeometryInfo{   Matrix4 transformation;   Mesh mesh;};struct MovementInfo{   Vector3 acceleration_;   Vector3 velocity_;};struct GeometricObject : public IRenderable{protected:   ObjectGeometry geometry_;   Vector3 position_;};class RigidBody : public GeometricObject{public:   virtual void Render()   {   }private:   MovementInfo linear_;   MovementInfo angular_;};
Quote:Original post by cache_hit
Quote:Original post by Zahlman
Quote:Original post by solinent
I was hoping for a inheritance solution.

I know how to get it to work, I just want to know what OOP provides me. I can do composition fairly well, but I have trouble thinking about inheritance patterns for some reason. I was just wondering if someone here found a nice pattern to use.


Here's the thing: OOP has at least as much to do with composition as it does with inheritance - much more, actually, according to some. After all, composition is how you specify objects - they consist of their data members and their methods/member functions, and bases are really just data members with a thick coating of syntactic sugar. It's been found in practice that overuse of inheritance is much more common than underuse; and anyway, inheritance is simply one way of getting at subtyping, which is the real underlying "OOP concept", if anything.

IOW, the "nice pattern to use" is called "composition". :)

Interfaces work, too, but they're tricky to get right in C++, and involve lots of boilerplace in Java. In Python, it's generally all ad-hoc anyway, to the point where there isn't even really a clear line between doing it the "composition way" and doing it the "interface way". (It's quite unusual for Python coders to go out of their way to hide part of the functionality of one class from another class. You might say that Pythonistas see encapsulation as more of an organizational tool rather than a security measure. I know that's the case for me, anyway.)


I actually take this to the extreme. I almost never inherit for purposes of implementation. And when I say almost never I really mean almost never. The past month or two there were 3 or 4 situations where I thought to myself "ok, now *this* actually makes sense to have it use implementation inheritance." couple weeks later when I needed to enhance it somehow I was like "/sigh, should have used containment".

The thing is, a lot of times inheritance does "make sense" from a conceptual point of view. It's also sometimes easy to implement. But it doesn't scale well, it's not flexible, and it's error-prone. For example, to obtain base class functionality you have to explicitly call the base class version of a function. Like say you implement some method foo() and you override that in a derived class. The derived class then has to remember to call the base foo() in order to gain its functionality. But where do you call it? At the beginning? Somewhere in the middle? At the end? The answer: it depends what you want to do. That answer sucks, because it leads to spaghetti code and bugs. Any time the client of something has to "remember" things it has the potential to lead to bugs and bad code.


So, what do you do? How about this:

*** Source Snippet Removed ***


Hmm, interesting.

I don't really like your solution though, since a rigid body isn't really a "type of" geometry, it has it's own physical definition (which could be some seperate geometry: so this is confusing).

I think I will just go with composition and not store the transformation matrix in the RigidBody definition.

That way I can use a quaternion or a seperate method of specifying orientation and its derivative, and then in the composing class have an update method which calls the rigid body's tick method and then calls a rigid body function to update the renderobject!

So something like this:

class RigidBody{public:  void update (const RenderObject&);  void integrate (float seconds);// etc.};class RenderObject{public:  void setTransform (const Matrix4&);private:  Matrix4 transform;  Mesh mesh;  std::vector<RenderObject*> children;};class PhysicalObject{public:  void integrate (float msec)  {    rigidBody->integrate(seconds);    rigidBody->update(*renderObject);  }private:  boost::shared_ptr<RenderObject> renderObject;  boost::shared_ptr<RigidBody> rigidBody;};


This doesn't use inhertance and uses composition like most have recommended here. I can always change the renderObject in this method, and I have more flexibility in terms of rigidBodies (can always swap them out).

This is what I don't like about C++ though. To me it feels like inheritance _should_ be used in this situation, but there's way too many ways and I think most people will end up with composition because its easier to think about or more flexible.

Note: I'm not that worried about code reuse since I will be constantly re-writing re-factoring as I go along as this project is for my own knowledge and only involves me. For example, it started as a 2d car game (which I actually finished to some extent), and now is approaching a 3d car game (because it seemed like a good idea at the time :P).
Quote:Original post by solinent

I don't really like your solution though, since a rigid body isn't really a "type of" geometry, it has it's own physical definition (which could be some seperate geometry: so this is confusing).


The solution I gave didn't imply that it was a "type of geomtry". That would have been expressed by inheriting from ObjectGeometry. It implied that it was an object which contained geometry (i.e. a geometric object). In any case, GeometricObject was just a very thin wrapper that contained no implementation, only data members. You could just as easily delete that entire class and manually contain those members inside of RigidBody, or just change the name from GeometricObject to something like ObjectWithPositionAndTransformation.

Regarding your proposed new class layout, consider the following:

1) What about the case where an object's geometry is not specified by a mesh at all? Do you have a need to handle that?

2) What about objects that can never contain children by definition? Do you want to waste space storing the vector object even though it will have 0 items 100% of the time?

This is why you need interfaces, they make no assumption at all about the final implementation.
Quote:Original post by cache_hit
Quote:Original post by solinent

I don't really like your solution though, since a rigid body isn't really a "type of" geometry, it has it's own physical definition (which could be some seperate geometry: so this is confusing).


The solution I gave didn't imply that it was a "type of geomtry". That would have been expressed by inheriting from ObjectGeometry. It implied that it was an object which contained geometry (i.e. a geometric object). In any case, GeometricObject was just a very thin wrapper that contained no implementation, only data members. You could just as easily delete that entire class and manually contain those members inside of RigidBody, or just change the name from GeometricObject to something like ObjectWithPositionAndTransformation.

Regarding your proposed new class layout, consider the following:

1) What about the case where an object's geometry is not specified by a mesh at all? Do you have a need to handle that?

2) What about objects that can never contain children by definition? Do you want to waste space storing the vector object even though it will have 0 items 100% of the time?

This is why you need interfaces, they make no assumption at all about the final implementation.


Well in RigidBody you inherited from GeometricObject. (edit: and a RigidBody has no idea that there is such thing as graphics! I want to seperate physics and graphics entirely.)

1. I only support triangle meshes in rendering, since I'm interfacing OpenGL. It's true that I could make an interface, but it's not required by me now and in the forseeable future, and it's fairly simple to add after the fact. (ie. I'll add it if I use it, I'm not afraid of changing the object's definition).

2. Really an empty vector doesn't take up very much space, and a "RenderObject" is more of a node in my scenegraph. The additional overhead of virtual methods is probably more, but this is then a microoptimization (unless I add millions of renderobjects, then it becomes a valid speedup).

However, I'm unlikely to do that, and I think your idea is a good one. In this way I could also pass untransformable geometry into the whole mess (ie. a plain mesh). But the way I conceptually organized it is that a RenderObject is the main renderer's interface to the Mesh.
Quote:Original post by solinent
I always thought that proper OOP design uses composition and inheritance in different places (inhertance for specifying "is a type of" and composition for "has a").


Thenk think to it in terms of 'attributes': your object has the attribute to own a physical behaviour and has the attribute to be renderable.
Quote:Original post by cache_hitFor example, to obtain base class functionality you have to explicitly call the base class version of a function. Like say you implement some method foo() and you override that in a derived class. The derived class then has to remember to call the base foo() in order to gain its functionality. But where do you call it? At the beginning? Somewhere in the middle? At the end? The answer: it depends what you want to do.

Well that is not the way to use function overloading in my opinion. If you need to reimplement a function in a derived class then you either want to replace the whole implementation or your base implementation lacks things. If you only need added functionality and still rely on the base implementation you would something like this:
class Base{public:   Base();   virtual ~Base();   void Foo ()   {      // do something      FooInternal();   }protected:   virtual void FooInternal()   {      // empty base implementation   }};

Now each derived class can use the base functionality of Foo and still adding functionality in FooInternal which gets called automatically. If you think there are reasons some classes need to call their own stuff before or after Foo executes extend this scheme to:
class Base{public:   Base();   virtual ~Base();   void Foo ()   {      FooBeginInternal();      // do something      FooEndInternal();   }protected:   virtual void FooBeginInternal()   {      // empty base implementation   }   virtual void FooEndInternal()   {      // empty base implementation   }};


@original poster
There is no single valid answer to that, as always it depends on your coding style and the remainder of your code an interfaces. But without knowing the design in depth I would suggest (as most others did above) to use the physics and the renderable class as attributes of the entity class. Philosophers might argue that an enty is a renderable while others would say the entity from the interface point of view has a renderable. To avoid nasty multiple inheritance I would always opt for the has a way of doing things.

Another classical example is a rag doll class. Its a skinned mesh as well as a physics object. No go one step ahead and think of an instanced skinned mesh class. This is a skinned mesh as well as an instanced mesh as well as a physics object. There is no easy way of reflecting this by using interfaces. The only valid C++ solution in such a case would be to have abstract classes where you can use multiple inheritance savely. But then you would either have to provide duplicated code because the implementing classes must not use multiple inheritance or you have to write helper classes to perform various tasks which are used by the implementing classes.

Anyway, in this way I would use a design like that:

class Transform; // stores access to the transformation attributesclass Renderable; // represents a tri mesh for example, doesn't care about transformations thoughclass PhysicsObject{public:   const Transformation& GetTransformation() const;private:   Transform m_trans;};class Entity{public:   void Update()   {      if (m_po != 0)      {         m_po->Update();         m_trans = m_po->getTransformation();      }      else      {         // update transformation by AI or whatever      }   }   const Transformation& GetTransformation() const;   const Renderable* getRenderable () const;private:   PhysicsObject* m_po;   Renderable*    m_r;   Transformation m_trans;};

In this design you would have a scene graph or a similar structure that stores all of your entites, updates them each frame, and then get their transformation and renderable to render the visual representation of the entity.
------------------------------------I always enjoy being rated up by you ...
Quote:Original post by cignox1
Quote:Original post by solinent
I always thought that proper OOP design uses composition and inheritance in different places (inhertance for specifying "is a type of" and composition for "has a").


Thenk think to it in terms of 'attributes': your object has the attribute to own a physical behaviour and has the attribute to be renderable.


These sort of guidelines are ambiguous and can be molded to fit into eachother.

The problem with this is that it entangles the two when they shouldn't be brought together in such a way. Component design, I think, utilizes the most basic OOP principle of reuse more in their simplicity. The last post showed this well in it's entity class with sub objects as components.

This topic is closed to new replies.

Advertisement