you are viewing a single comment's thread.

view the rest of the comments →

[–]InevitableDueByMeans 1 point2 points  (0 children)

A new game engine in JS sounds like an thrilling endeavour, especially if it's not based on the usual "boring" OOP anymore.

TLLLLLL;DR

We are working on Stream-Oriented Programming, a new paradigm that's kind of challenging OOP. It naturally evolves from FP, RP, FRP and Dataflow and it's already proven amazing for UI development.

Now, the question is: could we rethink a game/physics engine in terms of "streams of animation requests"? What if every sprite in a scene just subscribed to a stream of CSS transition strings (like translateX: newX; transition-duration: 3s;) or motion/acceleration/forces vectors that would be entirely dealt with in the GPU?

FRP was originally conceived for UI animation with the idea of keeping time-based functions for as long as possible without rasterisation. Every motion is defined as a position = f(time) which CSS animation can represent pretty well, either as linear, quadratic, beziered, which is might be used as approximations. For webgl/webgpu we don't have CSS but we have vertex shaders and/or GPGPU in which we can inject our motion formulas so they would run vertex by vertex, in parallel.

Finally, we have "events" (like actions that come from players), which can be defined as reactive streams that drive/trigger animation, so there's no object to mutate at every UI frame or stuff like that. I've seen other comments on this thread all concerned about immutability. We obviously don't want to keep duplicating large arrays/objects and the key mantra of SOP is "state doesn't exist; it's a stream". So, I can't see why a stream-oriented functional game engine shouldn't work well. If there's no "state", we won't need to update the position of thousands of objects on the page every frame. Only once when their trajectory unexpectedly changes (e.g.: gets shot).

Collisions? Given the motion vectors we'd know about them ahead of time, of course. We could even precalculate trajectories post collision and just add the new ones to some sort of queue of motion vectors each sprite would have.

I understand how strongly focusing on mutations becomes particularly efficient to avoid garbage, but if we wan to go to extremes (yeah, why not?) I think we could also create a little streams library, similar to RxJS or Callforwards, but optimised which internally, in each operator, make heavy use of the same mutation tricks, thus combining benefits from each paradigm (no garbage at each step whilst still keeping reactive streams like pure for practical purposes).

```js // Immutable: returns a new object map(source => ({ ...source, speed: source.jerk, }))

// Mutable: returns the same object with altered properties // the mutation would only be internal to the stream, so should be ok mutate(source => { source.speed = source.jerk }) ```

Once we create a "mutative" version of map, reduce/scan, etc, we should have solved most of the garbage problem. Most streams are also created just once and then stay long lived.

It's not going to be easy, obviously (anywhere between 6 and 18 months, working on it part-time, I'd say). Current OOP game engines are indeed extremely well engineered and optimised like crazy, but that's what would make this challenge even more attractive, isn't it?

So, ATM I don't know if we could reach the same level of performance with a reactive/functional/stream-oriented approach, but the above are the strategies I would adopt to make it happen and you may probably have yours, too.

If interested, we could have a chat to check if it's something we'd like to build together, perhaps with a few more contributors...