FRP and a set of pairwise interacting (colliding) objects

Hi, I want to simulate as set of 2D objects, which can collide pairs wise with each other. In an OOP language, I would do this: for (o1 in objects) { for (o2 in objets) { if (testCollision(o1, o2)) { CollData cd = getCollisionData(o1,o2); o1.reactToCollision(cd); o2.reactToCollision(cd): } } } Now I want to do the same thing in Haskell with FRP. Normally in FRP (correct me if I am wrong) I have for my objects a Signal (or whatever it is called in the specific library), which gets as input the collision events for this object (and probably more data, but let's assume collision events are enough): object :: Signal (Event CollData) ObjectState The CollData events themself are generated at another place: collisions :: Signal [ObjectState] (Event CollData) But now the collisions are generated at one place, and processed at another. This means that CollData must be somehow tagged to the objects it belongs to (an ID for example). This again means that some function must take the pool of all collision datas and distribute them to the "object" Signals. When I have a lot of objects, this means a significant overhead! Now I am wondering if there is a nicer approach which avoids this overhead. Thanks! Nathan

Nathan Hüsken
[...]
But now the collisions are generated at one place, and processed at another. This means that CollData must be somehow tagged to the objects it belongs to (an ID for example). This again means that some function must take the pool of all collision datas and distribute them to the "object" Signals.
When I have a lot of objects, this means a significant overhead!
Now I am wondering if there is a nicer approach which avoids this overhead.
You can get around the overhead by letting the objects do the collisions themselves, much like in your OOP variant. For instance in Netwire you could have this: planets :: MyWire [Planet] Planet This naive way still causes the overhead of lists and a planet distinguishing between others and itself. But now this is simply a matter of choosing proper data structures and starting to identify planets: type PlanetSet = Map PlanetId Planet planets :: MyWire PlanetSet (PlanetId, Planet) This looks more promising. Now the last thing is that this looks like a chicken/egg problem, but it's easy to resolve using ArrowLoop and one-instant delays. Greets, Ertugrul -- nightmare = unsafePerformIO (getWrongWife >>= sex) http://ertes.de/

On 06/29/2012 04:47 PM, Ertugrul Söylemez wrote:
Nathan Hüsken
wrote: [...]
But now the collisions are generated at one place, and processed at another. This means that CollData must be somehow tagged to the objects it belongs to (an ID for example). This again means that some function must take the pool of all collision datas and distribute them to the "object" Signals.
When I have a lot of objects, this means a significant overhead!
Now I am wondering if there is a nicer approach which avoids this overhead. You can get around the overhead by letting the objects do the collisions themselves, much like in your OOP variant. For instance in Netwire you could have this:
planets :: MyWire [Planet] Planet
This naive way still causes the overhead of lists and a planet distinguishing between others and itself. But now this is simply a matter of choosing proper data structures and starting to identify planets:
type PlanetSet = Map PlanetId Planet
planets :: MyWire PlanetSet (PlanetId, Planet)
This looks more promising. Now the last thing is that this looks like a chicken/egg problem, but it's easy to resolve using ArrowLoop and one-instant delays.
So I would have a main arrow like this (leaving out the Map for which I have to lookup the syntax): main = proc in -> do planet1 <- planets initPlanet1 -< allPlanets planet2 <- ... ... allPlanets <- delay [] -< [planet1,planet2 ...] (I would probably have some arrow managing all planets instead of listing them separately) Correct? Yes, that makes sense. There is still a little overhead. Assuming collisions are symmetric, the OOP approach would only test every pair of planets once ... not in the way I wrote it down, but it could easily be changed so that it does. But here they have to tested twice. Thats only factor 2 and probably acceptable. Still, is it avoidable? Thanks! Nathan

Nathan Hüsken
So I would have a main arrow like this (leaving out the Map for which I have to lookup the syntax):
main = proc in -> do planet1 <- planets initPlanet1 -< allPlanets planet2 <- ... ... allPlanets <- delay [] -< [planet1,planet2 ...]
(I would probably have some arrow managing all planets instead of listing them separately) Correct?
Yes, that's the basic idea. Just drop in a 'rec' somewhere for the feedback to work.
Yes, that makes sense. There is still a little overhead. Assuming collisions are symmetric, the OOP approach would only test every pair of planets once ... not in the way I wrote it down, but it could easily be changed so that it does. But here they have to tested twice. Thats only factor 2 and probably acceptable. Still, is it avoidable?
Yes, it is. You can write a managing wire transformer (along the lines of the ones from Control.Wire.Trans.Combine) specifically for colliding objects. It's really much easier than it sounds. Just have a look into the source code of that module. Greets, Ertugrul -- Not to be or to be and (not to be or to be and (not to be or to be and (not to be or to be and ... that is the list monad.
participants (2)
-
Ertugrul Söylemez
-
Nathan Hüsken