Hello guys , Im testing react-babylon package.
Currently im getting the “No Physics Engine available.” console message when integrating havok into the project.
First question.
Package documentation suggest to start the project using the CRA script.
Should it be change to other method like vite ? (in my case CRA does not work anymore for new latest versions).
In case of using vite, what is the proper way to integrate havok ?
Some time ago I was recommended to look to this repo as starting point , but it seem that nobody has updated this.
So in my case I just created a new vite project , install the react-babylon and havok packages and tryed adding this code into my App.tsx file but could not succed … im getting the above mentioned message.
Any advice/toughs would be welcome.
Leandro.
Package docs don’t (or shouldn’t) recommend using CRA. They do link to CRA examples that are a few years old. Vite would be much better. I’ll try to get a sample up on the docs site (gatsby)
1 Like
Yep … thats the example I mentioned.
I copied it and removed the bouncing balls.
Then, I got the “No physics engine available” message when trying to apply the physicsAggregate to the ground mesh.
I think it should be something related to vite config.
This is what I have on my vite.config.ts and package.json.
{
"name": "solid-path",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@babylonjs/core": "^7.39.0",
"@babylonjs/gui": "^7.39.0",
"@babylonjs/havok": "^1.3.10",
"babylonjs-hook": "^0.1.1",
"react": "^18.3.1",
"react-babylonjs": "^3.2.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@eslint/js": "^9.15.0",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.3.4",
"eslint": "^9.15.0",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.14",
"globals": "^15.12.0",
"typescript": "~5.6.2",
"typescript-eslint": "^8.15.0",
"vite": "^6.0.1"
}
}
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
server: {
fs: {
// Allow serving files outside of the root
allow: [
"../.."
]
}
},
optimizeDeps: { exclude: ["@babylonjs/havok"] },
})```
Could you share the .tsx where you load the havok library and also where you create your scene? Something is not happening there - maybe related to the async nature of loading havok.
The examples main snippets (which are missing error handling) are:
import { HavokPlugin } from '@babylonjs/core/Physics/v2/Plugins/havokPlugin'
import HavokPhysics, { HavokPhysicsWithBindings } from '@babylonjs/havok'
...
const [HK, setHK] = useState<HavokPhysicsWithBindings>()
(async () => {
setHK(await HavokPhysics())
})()
return <Engine ... >
{HK ? (
<Scene enablePhysics={[null, new HavokPlugin(false, HK)]}>
...
</Scene>
)}
</Engine>
You might not like holding off the scene until the physics is ready, but you could flow state through when the physics is loaded and load the aggregates. There is always an escape hatch to get scene access and apply the physics engine yourself. Can’t really tell unless you provided also that code. If it’s not obvious from your loading code then I could update that project to vite and havok to find the culprit.
edit: if you are using babylonjs-hook
then the code will be different. Not sure 100% - you’d never need both of those libraries at the same time. I’m going based on the title of this post.
Sure , I will push it to github.
please take a look here
I agree with you that , problem is related to async nature.
You will see that if code changes , the error disappear.
I tryed triggering havok loading and scene rendering from different button events but have no success.
thanks.
hi @Leandro_Roggerone thanks for the repo. I’m able to repro!! First of all, when I remove <StrictMode>..
in your main then it works. So, I looked more and I am calling enablePhysics
twice. I will fix that, but I don’t think that is causing the issue still (it’s a legacy thing before enablePhysics was part of automatically called functions).
Not sure how to proceed here. I’ll remove that I call it a second time for sure. It’s pretty hard to debug. This shows the second unnecessary call, but also that the second scene that is created has no physics engine.
<Scene enablePhysics={physicsPropsRef.current} onSceneMount={(s) => {
console.log('mounted');
const cur = s.scene.enablePhysics;
s.scene.enablePhysics = function (...args) {
console.log('calling enable physics', args);
return cur.apply(s.scene, args);
}
console.log(s.scene.uid);
console.log('physics engine', s.scene.getPhysicsEngine())
}} >
...
</Scene>
Ok , dont worry , I will continue playing around and investigating a little bit more also.
Anyway , would be great to review the api in order to work with vite script , there are other issues as well , for example when working with mesh/models , im getting similar issue with loader plugin , in that case with “No plugin or fallback for … glb” console message.
Leandro.
I’ve never seen any loader issues. Did you specify .glb, but maybe it was a networking/routing issue? Can you put that in your repro? I’m prepping a new release of react-babylonjs
now that doesn’t double call “enablePhysics” in case there are some re-entrancy issues and I’m adding a callback before it’s called the first time. I am seeing that “enablePhysics” is failing on the second scene being created - stepping through the debugger it’s when the Havok physics engine is being created. stay tuned.
ok. I dropped a new release. there is an onCreated
now and enablePhysics
isn’t double called. so, that removed two question marks that I had. I made a hook (do not use this in production):
const useAsyncWithStrict = (
effect: () => Promise<HavokPhysicsWithBindings>,
uniqueRef: React.MutableRefObject<Nullable<HavokPhysicsWithBindings>>,
dispatch: React.Dispatch<React.SetStateAction<boolean>>
) => {
const isUnmounted = useRef(false)
useEffect(() => {
(async () => {
const result = await effect();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
console.log('loaded HavokPhysics()', (result as any).InternalError());
if (isUnmounted.current !== true) {
console.log('setting ref:')
uniqueRef.current = result;
dispatch(true)
} else {
console.log('already unmounted - skipping');
isUnmounted.current = false;
}
// physicsPropsRef.current = [null, new HavokPlugin(false, result)];
// (physicsPropsRef.current![1] as unknown as {aa: number}).aa = Math.random()
})();
return () => {
console.log('marking unmounted')
isUnmounted.current = true
dispatch(false)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
}
This allows you to for hacky testing ignore the first mount/unmount from StrictMode to do something like this:
const YourComponent = () => {
const [physicsReady, setPhysicsReady] = useState(false);
const havokPhysicsRef = useRef<Nullable<HavokPhysicsWithBindings>>(null);
useAsyncWithStrict(async () => await HavokPhysics(), havokPhysicsRef, setPhysicsReady)
return (
<Engine ...>
{physicsReady && (
<Scene enablePhysics={[null, new HavokPlugin(undefined, havokPhysicsRef.current)]} onCreated={(scene) => {
console.log(` > scene created: ${scene.uid}`);
const cur = scene.enablePhysics;
scene.enablePhysics = function (...args) {
const wasInitialized = cur.apply(scene, args);
console.log(` > enablePhysics(..) called. Was initialized: ${wasInitialized}`, args[1]?.name);
return wasInitialized;
}
console.log('onCreated -> physics engine', scene.getPhysicsEngine())
}} onSceneMount={({ scene }) => {
console.log('onSceneMount -> physics engine:', scene.getPhysicsEngine());
}} >...</Scene>
</Engine>)
}
rendering (physicsReady: yes): with HK App.tsx:95:10
rendering (physicsReady: yes): with HK localhost:5173:1:596
> scene created: f7498488-7b9a-4396-b899-d47fa28b588e App.tsx:107:22
onCreated -> physics engine undefined App.tsx:115:22
> enablePhysics(..) called. Was initialized: true HavokPlugin App.tsx:111:24
onSceneMount -> physics engine:
Object { _physicsPlugin: {…}, _physicsBodies: [], _subTimeStep: 0, gravity: {…} }
App.tsx:117:22
> scene created: f7a0496a-7308-4022-bdac-42747b928b9a App.tsx:107:22
onCreated -> physics engine undefined App.tsx:115:22
BJS - [15:07:10]: o is undefined logger.ts:107:29
> enablePhysics(..) called. Was initialized: false HavokPlugin App.tsx:111:24
onSceneMount -> physics engine: undefined App.tsx:117:22
Uncaught Error: No Physics Engine available.
Anyway, it seems like you can’t re-use a HavokPhysics()
, but then you can in a PG:
re-use HavokPhysics | Babylon.js Playground
I tried to follow the o is undefined
- it’s pretty buried in the Havok Plugin. Works without StrictMode obviously still…
lol
Hi , @brianzinn , I really apreciate your effort and support.
unfortunately I didnt have any free time during this lasts weeks to try this out but I promise I will very soon.