Errors:
Hi @Change2,
Not easy to debug this without a sample repro project, your code should work. @mvaligursky any idea why that uniform complains like that?
@mvignau what PlayCanvas engine version are you using?
It seems like the application is initialized multiple times - and a mesh from the first application is still being rendered or something like that. The second example works around it by guarding multiple initializations.
Hi @Leonidas @mvaligursky,
I’ve just emailed you the Github repository with the sample code.
Thank you!
Do you have a Non-Disclosure Agreement on 40 lines of copy-pasted README.md
code?
Even if you get it to work, you leak app
for not having a cleanup function in your effect calling app.destroy()
if you are going to have multiple app’s.
Also mixing ES5 and ES6 code like that can become troublesome, I would rather treat it as either/or (we have a bunch of issues stemming from that on GitHub).
It would also make your code more readable, simply import * as pc from 'playcanvas'
and scratch all your window.pc
property accesses.
Dear @kungfooman,
Regarding the Non-Disclosure Agreement on 40 lines of README.md code, we do not have an NDA specifically for it. I’ve shared the Github link as per their personal request.
I take note of your insights about our code. Please remember, however, this was initially not intended for production, but was rather a demonstration for a specific issue we have encountered. That said, I concur with your observations:
-
The lack of a cleanup function in the codebase: I completely agree with your suggestion and we intend to incorporate a cleanup function that invokes app.destroy() for more effective memory management, especially when multiple instances of the app are in play.
-
Mixing ES5 and ES6: We understand the potential problems that can occur due to mixing different ECMAScript versions. Rest assured, we will be moving towards a more uniform coding approach to minimize such issues.
-
Importing pc from playcanvas: The window.pc property was implemented in an attempt to rectify this issue. While it may not be directly pertinent to the issue at hand, your feedback has certainly highlighted the need for us to remove this.
Thanks!
The double-rendering issue we’re experiencing is tied to React’s StrictMode. In development mode, StrictMode intentionally triggers a double-render of components to help find potential problems in our code. The only way to eliminate this double-rendering is to disable StrictMode,
<React.StrictMode>
<App />
</React.StrictMode>,
However, this is not an ideal solution. While it does prevent the double-rendering, it also removes the beneficial debugging features provided by StrictMode. While we can technically mark this issue as ‘solved’ by disabling StrictMode, it’s important to note that this isn’t a true fix. It merely bypasses the mechanism causing the double-rendering, at the expense of valuable development assistance.
You are making it unnecessarily difficult to help you. Why don’t you just share the code so that anyone, willing to give it a quick try, can?
Why are you only sending a screenshot of code?
I tried to hint at it before, but you only used ChatGPT to generate a useless answer without any observeable improvement or sharing of repo/code (sorry if I’m wrong).
Dear @kungfooman
I’ve been sharing code via screenshots as we thought it was a convenient way to provide quick insight on this issue. It can be replicated on every newly created React application.
We have shared the public repository with whom asked for it.
Thanks,
I did a bit more refactoring, not using a global app
:
I didn’t disable the strict mode and I see now errors. Maybe you want to test if you still run into issues?
Thanks @kungfooman
Yes, there are a lot of improvements in your version!
I think we might have solved the issue. But it is a just-one Playcanvas App thing, we don’t need more.
There is still some refactoring to do.
import * as pc from 'playcanvas';
import { useEffect, useRef, memo } from 'react';
function startApplication(canvas, appState) {
console.log('startApplication');
// Return existing promise if app is still loading
if (appState.isLoading.current) {
return appState.loadingPromise.current.then(() => startApplication(canvas, appState));
}
if (appState.app.current) {
console.log('destroying app');
appState.app.current.destroy();
appState.app.current = null;
}
appState.isLoading.current = true;
return appState.loadingPromise.current = new Promise((resolve, reject) => {
appState.app.current = new pc.Application(canvas, {});
appState.app.current.setCanvasResolution(pc.RESOLUTION_AUTO);
const box = new pc.Entity('cube');
box.addComponent('model', {
type: 'box'
});
appState.app.current.root.addChild(box);
const camera = new pc.Entity('camera');
camera.addComponent('camera', {
clearColor: new pc.Color(0.1, 0.1, 0.1)
});
appState.app.current.root.addChild(camera);
camera.setPosition(0, 0, 3);
const light = new pc.Entity('light');
light.addComponent('light');
appState.app.current.root.addChild(light);
light.setEulerAngles(45, 0, 0);
appState.app.current.on('update', dt => box.rotate(10 * dt, 20 * dt, 30 * dt));
appState.app.current.on('start', () => {
appState.isLoading.current = false;
appState.started.current = true;
console.log('application started');
resolve();
});
appState.app.current.start();
});
}
const Scene = memo((props) => {
const appCanvas = useRef(null);
const appState = {
app: useRef(null),
isLoading: useRef(false),
started: useRef(false),
loadingPromise: useRef(null)
};
useEffect(() => {
startApplication(appCanvas.current, appState);
// eslint-disable-next-line react-hooks/exhaustive-deps
},[props.changeTrigger]); // Add the prop changeTrigger as a dependency
return (
<canvas className="ch2_scene" ref={appCanvas} id='application-canvas'></canvas>
)
})
export default Scene;
If you don’t need more than one, add only one? IMO nevertheless the component should have a proper lifecycle and not rely on global app. I also find it ugly to intermingle React and PlayCanvas code like that, it’s hard to reason about that especially without any JSDoc typing.
If you want to drop React or use your PlayCanvas code in another library, or, for simplicity, no library at all, you suddenly realize that you are locked in through cryptic spaghetti code and you will be unable to quickly refactor your code.
I try to nudge you into a direction I feel more certain about, but it’s up to you to merge and moving on from that point.
(I guess in any case the initial question is solved)