I’m looking for advice on how to couple a React UI with a game built with babylon in TypeScript.
As an example, I want to be able to retrieve some text from an input field in React, from a typescript class, do some processing on it, then send it back to React to show the change.
My current attempt has been to export a function in TypeScript, which the React UI calls when submitted. The TypeScript function then does the needed processing, then sends it back to a React function - however, this seems messy.
I’m completely new to React, and relatively new to TypeScript - I come from a C++ and C# game dev background, where in this situation, I would decouple the logic from UI via events; however, I can’t find an example of this, and I have no idea what this would look like or if this would even be considered good practice.
Any pointers on the best way to do this would be really helpful - thank you!
I’ve had a look at the Babylon and React documentation; in the examples I’ve seen, everything is very tightly coupled?
In my current project, the game logic (babylon / typescript, game dev), and UI (react, web dev) are being developed independently of one another (as though two separate projects). In this case, how would you handle communication between the two?
I’m not using React but Svelte in my personal projects, and the way I handle it there is loosely coupled but using Svelte stores (global state) to communicate between the UI and 3D - the UI mutates the state, and the 3D subscribes and responds to those global state changes. In a work project we use loosely coupled Babylon Native and React Native with custom observables to communicate between the two. In React I imagine Redux or Recoil would allow something similar.
Even more loosely coupled would be a client/server architecture using something like Colyseus, where the React UI just sends player command requests to the authoritative server, which validates the requests and mutates game state for all clients.
Sorry my answer is a bit lengthy, but it’s a very interesting topic to me.
I would try to stick with a more event based model - I prefer that way of thinking. Lots of react libraries allow this kind of state management - you could consider a state management like Zustand, jotai, mobx, etc. There are so many libraries it can be hard to choose. I’ve been working full time for 2 years in vue, so I also want that reactivity in React.
I like more event driven models and come from a mostly c# and multi-threading background where UI concerns were always separated from logic (ie: MVVM in .net world). I have done some experimentation with state machines to match my mental model with events using a library I made loosely based off a .net one called stateless - here is a basic React project using it with a live babylon demo. brianzinn/xmachina-semaforo: babylon react semáforo traffic light xmachina state machine (github.com)
I’ve experimented with React + redux-saga and that works well to integrate with babylon.js in turn-based games. I ended up finding that the state library needs prop drilling or it can get messy to pass around event handlers or trigger events if you are accustomed to a single source of truth and clean decoupling then your word “messy” comes to mind!
Here is a react hook that I made to handle the above events and push the events and state from that state machine into React (the “manual” demo above shows the sync can be from React), while the babylon scene listens to same events and synchronized automatically. xmachina-semaforo/useMachina.ts at main · brianzinn/xmachina-semaforo (github.com)
it’s a pretty interesting topic. You can look also at some message buses that abstract away a lot of that, but you likely still want the state to propagate to not need to manage the logic in more than one place. I wrote a middleware for redux that eavesdropped on the actions and that was the first time I learned it can be messy to synchronize babylon <–> React. Would be happy to hear where you land on this as it’s a very interesting topic.
Lastly, another interesting thing in this space is the difference between a React render and a babylon render (in FPS) and how those can be managed independently, but need to work together and I use events typically to connect those as well (ie: at end of animation to notify/signal).
Just want to +1 @brianzinn’s thoughts. I have been down the rabbit-hole of having Redux in a Babylon app together and I think it’s a bad idea as well as excessive prop passing. Event based like asked about is the way to go. It also makes it SO much easier to move things around later. Each UI component wether react or not subscribing/unsubscribing to events. Keeping a state on the eventBus and the Babylon side utilizing the same events.
I think one difficulty this approach is keeping track of the flow of events from one to the other. I think we are up to 45 and would love to hear how some people tackle that
Thanks for all your feedback, it’s been really helpful.
@brianzinn after hearing everything here, I did decide to go event based; I really appreciate you sharing your approach to this. For my implementation, I’m using react-native-event-listeners - it’s allowed for a light implementation, and something we can build off easily as we go, both for react and typescript.