2

Context

When implementing a class, there's a distinction between fields that are there because they are part of what the object is and fields that are there because they are needed to implement the object.

For example, if you are implementing an ArrayList, you will have an array that isn't part of what an ArrayList is but are required into the implementation. That's the whole point of having public properties and private fields.

The problematic case

However, I'm in a kind of weird situation were the implementation is outside the class because the algorithm is interacting with a collection of that Object.

My case is a physics engine. My Body class has public properties that make sense like Velocity, Position, Size etc. However, now it starts to have properties that only make sense when used by the class World, that interacts with a collection of bodies. I have fields like CollisionShifting (how much the body is shifted by collision), Collisions, Movement (velocity * delta, needed to check for collisions) etc. and the list is growing.

The problem is the more features I implement into World, the more unintuitive fields I have to add to Body. And that's bad because anyone who want to implement the Body interface will have to implement those fields and won't know what's their purpose. As someone who implements Body (and not World), all you care about is where is your Body and how fast does it does. You also want to get notified when collisions happen but you don't want to have details like how much the body was shifted by collisions in the last frame as a property.

Possible options

So what I would like to do is having private fields per Body for the implementation of the World into the class World but I do not like the first look of this option.

I could map every Body to a class that's only purpose is to complete body into World:

Map<Body, HiddenFieldsOutOfTheModel> extraInfos;

I could do that for every field. It would be a bit more logic because I wouldn't have a weird out-of-the-model class but I feel it's just like moving the problem:

Map<Body, Vector> collisionShiftings;
Map<Body, List<Collision>> collisionsPerBody;
//etc.

This option is a bit tedious because whenever the World wants to remove a body, it has to remove it from a variable amount of Maps. Plus, I need to encapsulate the add/remove operations while without the Maps I can just leave write access to the array.

Question

I have to say I prefer the second approach but is there something better ? What is the best solution to keep the model clear and confuse the less people possible?

In short, what is the best way to have per-object private fields in a class containing a collection of these objects?

Update

It's been a while since I asked this question but I still don't have a "perfect solution". (And I'm not sure I will ever find one) For now I've taken the Map<Body, HiddenFieldsOutOfTheModel> extraInfos; option and named my HiddenFieldsOutOfTheModel class BodyState.

  • You may want to consider working at a different granularity like in this answer to a rather different question. This would take these collision and velocity fields out of individual objects and let you work with them as a set, performing operations on arrays of primitives. This keeps you from having either tons of dumb objects that are manipulated by the system, or smart objects that entangle with each other too much. Instead the system can manage the interactions on primitives that it owns to limit scope to match the algorithm. – Mike Jul 17 '17 at 18:33
  • @Mike The object that would put all the properties I don't know what to do with together doesn't much sense, but the properties themselves have sense. Arrays would be just like a maps but would force me to index my collection of bodies and limit me in general. While I could separate my vectors into x and y float arrays (I don't really see the advantage) I couldn't do the same for a list of collisions. I need that list for logic inside the physics engine. No no, I can't put everything into primitive arrays but thank you for the suggestion and for the great reading. – Winter Jul 17 '17 at 19:54
  • This sort of thing is exactly the reason that Entity Component Systems were invented, which are what many/most games use for managing their objects and the collections of properties each object has which are relevant only to a particular system or set of systems... – Sean Burton Jun 14 '18 at 10:49
1

My body doesn't know where it is.

My body doesn't know how fast it is moving.

My body does know it's experiencing 1g of acceleration. But that's only because it's colliding with the chair I'm sitting on. This is ever so slightly compressing my spine and making my butt numb.

I very much like to remove from objects what they don't need to know. Sure, if I look around the room I see plenty of other objects at measurable distances and velocities from me but that's their problem.

The fancy name for where I am is called a reference frame. Every object is entitled to think of it self as being at rest. It's the reference frames that move about.

Here's an addictive little website that tries to teach this idea with a game called Relativistic Space Sheep. Not since Asteroids have I seen a better lesson about physics baked into a game.

You've already hit on the idea of separating these things but you're not sure where to put them. I like to use one reference frame to keep track of the rest. Everything is measured relative to it. Only it knows the positions and velocities. From it you can find everything else.

  • My physics engine has others unrealistic features that forces me to keep values somewhere for each object. The question is, how do I keep those extra values the World needs ? – Winter Jun 17 '17 at 14:05
  • 1
    Without a good description of these unrealistic features expecting me to give you a good design for them is unrealistic. – candied_orange Jun 17 '17 at 14:09
  • Whatever they do, all they need are extra fields on the Body class. For example I have something that when you are standing on something and its moving, you get moved too. To implement that I have to add a InfluenceMovement field to the Body class. The actual algorithm that will set this vector don't change anything to the question. The question is simply where should I place this extra field. I'm not asking you to give me any design for these features, I'm just trying to solve an organisation problem. The answerer doesn't have to know about physics engines at all to offer a solution. – Winter Jun 17 '17 at 14:13
  • 2
    Well, influence movement is just another way of saying collision. But, you need to get pretty metaphysical here. In real life, nothing other than an outside observer is aware of the number of collisions in an objects history. I think this is what @candiedorange is eluding to with a reference frame. I think another way to reframe your question is "what do I want to poll to find this information" you can't ask a rock how fast it is moving, so you ask a person (frame of reference) to give you a value that reflects its movement in relation to other objects. – NonSecwitter Jun 17 '17 at 17:29
0

Allow the caller to specify the fields he wants in a "template" object, then return a handle or reference to the real object. If this were c#, the caller's code would look like

class Rock : IGameObjectTemplate
{
    //Blah blah blah
}

var rock = new Rock
{
    Position = new Point(10,10),
    Mass = 100
};
var worldObject = motionEngine.CreateObject(rock);

Or if you want to make it easier, do away with the caller's object entirely, and put the necessary parameters in a factory method:

var worldObject = motionEngine.CreateRock(10, 10, 100);

This way, the engine still manages the creation and tracking of all the world objects, but the caller can also have a copy if (s)he wants. The instance that is returned can be a totally separate type with whatever fields you need, public, private, or internal.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.