samples-pixi icon indicating copy to clipboard operation
samples-pixi copied to clipboard

Elmish proof of concept

Open whitetigle opened this issue 8 years ago • 10 comments

This is a proof of concept of bi-directional communication between a Pixi application and an Elmish application. original discussion

whitetigle avatar Nov 03 '17 08:11 whitetigle

@MangelMaxime I added Elmish, React and Fulma to the project. In order to it all work I added some packages like style-loader, css-loader etc... But I am neither sure all the packages I added are needed there nor am I am confident about the webpack config update.

Since I have no other documentation than source code I think there are changes that may not be relevant to the configuration.

Could you check on your side please? Thanks!

whitetigle avatar Nov 03 '17 08:11 whitetigle

For the note, it's a little bit more than an Elmish-Pixi app. It's more a Elmish-React-Fulma+Pixi app.

whitetigle avatar Nov 03 '17 09:11 whitetigle

Thanks for taking time to review this PR @MangelMaxime!

whitetigle avatar Nov 03 '17 17:11 whitetigle

Ok this seems to works, I made some really little improvements.

I thinks we could improve the comments and also explain more how everything is wired. This minimal prototype works but I am not sure if this is viable for a real case.

My problems, is the GameModel is using mutable and so I believe we can be out of sync between the Elmish app and the Pixi rendering state.

This week-end I am planning to work on Elmish eco-system and Fulma. And then, I want to create a "real case" game using Fable and Pixi so we can use it to test this architecture or any future proposition. (Should be something equivalent to what fulma-demo is for Elmish + Fulma)).

MangelMaxime avatar Nov 03 '17 21:11 MangelMaxime

Just because, I forgot to conclude :)

I would probably wait a little before merging this PR.

MangelMaxime avatar Nov 03 '17 21:11 MangelMaxime

Well I've been thinking about the dependency between Elmish and Pixi.

I think that using an immutable field for updating the game state is just a matter of trust. The kind of trust we would need for instance when getting an update from a Suave server and vice-versa.

Regarding the Model managed by Elmish and shared with the pixi rendering loop, there I think is a dangerous thing. It's not its mutability which is dangerous, but the fact that elmish and pixi somehow try to share a reference to the same model. And there, yes, out of sync can be a problem.

Now, all things considered, Since Pixi now manages its rendering loop - no need to call RAF - I think we should let pixi manage its own model, sprites, an all but use Elmish as a Controller.

What I mean, is that I have been trying to model a real life sample where the out-of-sync could be a problem. Here it is: a GameOver Rule.

Let's say that when we have more than 50 dragons displayed on screen it triggers a GameOver. Who's in charge there? Elmish or Pixi?

I think that Pixi does only need to 1 - manage it's graphical stuff 2 - tell Elmish what's happening: user clicked, user dragged something, sprite collision happened, etc..

In this scenario, Pixi does not have any idea of the current state of Elmish model. It's not its business anymore.

Then Elmish, acting as a controller, will get messages from Pixi, updates its model and eventually tell pixi what to do by updating its state. So in the end the only dirty call we'd get would be: game.state <- newState: the update would happen in the next frame and would be fast as hell.

So with our dragons, it's Elmish who would be in Charge of testing the GameOver case and tell pixi to play the GameOver animation.

No more shared model. Only Pixi sending messages to Elmish and Elmish updating pixi state.

Maybe I'm missing something, but I think it could be a very simple somehow cleaner compromise. What do you think?

whitetigle avatar Nov 04 '17 07:11 whitetigle

Seems like a good idea indeed. Would you like to try it in this PR?

MangelMaxime avatar Nov 04 '17 07:11 MangelMaxime

Ok I'll make the changes. 👍 (Not exactly sure when though 😉 )

whitetigle avatar Nov 04 '17 07:11 whitetigle

I need to look this into more detail. Quick thoughts:

Goal: Adapt Elmish to a Game with Pix as Renderer

For this let's check how a productivity app works and how it differentiates with a game:

  1. Events happen (and dispatch a message)
  2. An update function updates the app state with the received message
  3. At one point, Elmish uses the current state to render the app

While in a game

  1. Events happen (and dispatch a message)
  2. An update function updates the app state with the received message
  3. The ticker, well, ticks. This can be considered an event so we dispatch a message with the elapsed time, and the state is updated again (an asynchronous action must be called in between, for example we can call a physics library which can be or not in a web worker)
  4. Elmish must ensure the render function is called after that

I think this is very similar to what the Elmish.Worker helper does, so I will try to adapt it. The key is to let Elmish control when render is called. This seems to be possible as per PIXI documentation:

ticker.autoStart = false;
ticker.stop();
function animate(time) {
    ticker.update(time);
    renderer.render(stage);
    requestAnimationFrame(animate);
}
animate(performance.now());

Another idea to increase performance could be not to call update when events are raised, just collect them and call update just once per frame with the time delta and the collected events 🤔

About mutable fields, ideally there should be none, but this is difficult in a game with too many updates (there would be too many memory allocations that would drop performance) and also using Pixi sprites, because at the . Anyways, the only thing we have to ensure is the model is not touched outside the update function, for this we could expose an interface of the model only with immutable fields. I didn't do it in the game workshop because of some problems with serialization... and also because there seemed to be a bug in Fable when interfaces clash with the class member names that I need to fix 😅

alfonsogarciacaro avatar Nov 07 '17 14:11 alfonsogarciacaro

for this we could expose an interface of the model only with immutable fields

I'm not sure to understand what it is :)

whitetigle avatar Nov 08 '17 16:11 whitetigle