Skip to content
This repository has been archived by the owner on Nov 13, 2018. It is now read-only.

Elmish proof of concept #27

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

whitetigle
Copy link
Contributor

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

@whitetigle
Copy link
Contributor Author

@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
Copy link
Contributor Author

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

Copy link
Member

@MangelMaxime MangelMaxime left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only read the code for now. I will test it and review the implementation later during this weekend.

<head>
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdn.polyfill.io/v2/polyfill.js?features=default,fetch"></script>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove this scrip tag because we now include core-js by default. And we don't need fetch :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 👍

@@ -0,0 +1,428 @@
// ******************************************************* TODO ****************************************************
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there some cleanup need in this file. I guess you took it from you website for "casque noir"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well I really just use this file for importing bulma. So maybe I could just not use this file and import bulma css directly if that's possible?

open Fable.Helpers.React.Props

// Fulma css
importAll "../../public/sass/main.sass"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to use importSideEffect in general when importing file to create a side effect in webpack. (for info importSideEffect is "new")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 👍

@whitetigle
Copy link
Contributor Author

Thanks for taking time to review this PR @MangelMaxime!

@MangelMaxime
Copy link
Member

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
Copy link
Member

Just because, I forgot to conclude :)

I would probably wait a little before merging this PR.

@whitetigle
Copy link
Contributor Author

whitetigle commented Nov 4, 2017

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?

@MangelMaxime
Copy link
Member

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

@whitetigle
Copy link
Contributor Author

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

@alfonsogarciacaro
Copy link
Member

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 😅

@whitetigle
Copy link
Contributor Author

whitetigle commented Nov 8, 2017

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

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

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants