As mentioned above, I am trying to embed playcanvas into the Vue program. I have retrieved some examples that integrate Vue into Playcanvas. Is there any good way to reverse it? I heard that we can consider using the source version, can anyone give me some guidance? thank.
Hi @kprimo,
I donāt have much experience with Vue.js but I know it should be similar with react and angular.
If you search the forums for react you will find some insightful posts:
Hi @kprimo
As @Leonidas linked, you can either embed an iframe and run an app through the public folder, or use the more direct approach with NPM.
It is very similar to the webpack template (https://github.com/playcanvas/playcanvas-webpack)
You can simply npm install playcanvas
and then import * as pc from 'playcanvas';
.
I modified the HelloWorld component from Vue to contain a Playcanvas app;
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<canvas id="game" style="width: 50em; height: 25em"></canvas>
</div>
</template>
<script>
import * as pc from 'playcanvas';
export default {
name: 'HelloWorld',
props: {
msg: String
},
data: function() {
return {
app: undefined
}
},
mounted(){
this.app = new pc.Application(document.getElementById('game'));
this.app.setCanvasResolution(pc.RESOLUTION_AUTO);
// create box entity
const box = new pc.Entity('cube');
box.addComponent('model', {
type: 'box'
});
this.app.root.addChild(box);
// create camera entity
const camera = new pc.Entity('camera');
camera.addComponent('camera', {
clearColor: new pc.Color(0.1, 0.1, 0.1)
});
this.app.root.addChild(camera);
camera.setPosition(0, 0, 3);
// create directional light entity
const light = new pc.Entity('light');
light.addComponent('light');
this.app.root.addChild(light);
light.setEulerAngles(45, 0, 0);
// rotate the box according to the delta time since the last frame
this.app.on('update', dt => box.rotate(10 * dt, 20 * dt, 30 * dt));
this.app.start();
}
}
</script>
Hope it helps.
Thank you for sharing, @Ivolutio!
Iām actually working on a project that uses Vue.JS right now. Ended up going with a little more unconventional way of integrating by forgoing PlayCanvas NPM package entirely. However, it only takes me a second to export a new version of the project from PlayCanvas and have it working in Vue, so Iāve found that convenient. If you stick the exported files right in the āpublicā folder, and use a slightly modified index.html then it should work.
If it helps, this is what my public/index.html
looks like:
<body>
<!-- Vue.JS app root -->
<div id="app"></div>
<!-- PlayCanvas -->
<link rel="manifest" href="./playcanvas/manifest.json">
<script src="./playcanvas/playcanvas-stable.min.js"></script>
<script src="./playcanvas/settings.js"></script>
<script>
// PlayCanvas project location settings
var PREFIX = '/playcanvas/';
var CONFIG_FILENAME = PREFIX + 'config.json';
var ASSET_PREFIX = PREFIX;
var SCRIPT_PREFIX = PREFIX;
</script>
<script src="./playcanvas/start.js" defer></script>
<script src="./playcanvas/loading.js" defer></script>
</body>
When I export the lastest project from PlayCanvas, I unzip everything into the ./public/playcanvas
folder.
This method is a little less flexible though. I end up moving the <canvas>
DOM element into a Vue component on load.
thank you for your sharing. I think Iāll adopt your plan.
Hello, do you have any more examplesļ¼
Thanks for your help!
Iāve got it to work with your instructions, however Iāve tried to load a model file in json format via loadFromUrl()
and I only get html response headers. Iām fairly new to vue and not sure if I configured it (or webpack) correctly.
Here is exactly what I did:
-
npm install -g @vue/cli
(newest version) vue create projectname
cd projectname
vue add router
npm install playcanvas
- edit main.js:
add lines:
import * as pc from 'playcanvas';
Vue.prototype.$pc = pc
- Vue router created two pages (Home.vue & About.vue) with routes for me, I edited About.vue and added the following code:
<template>
<div class="about">
<canvas id="game" style="width: 50em; height: 25em"></canvas>
</div>
</template>
<script>
export default {
name: 'About',
data() {
return {
app: undefined
}
},
mounted() {
this.app = new this.$pc.Application(document.getElementById('game'));
this.app.setCanvasResolution(this.$pc.RESOLUTION_AUTO);
const url = "../assets/models/s01.json";
const environment = new this.$pc.Entity('Environment');
// load model file
this.app.assets.loadFromUrl(url, "model", function (err, asset) {
environment.addComponent("model");
environment.model.model = asset.resource;
environment.setLocalPosition(0, 0, 0);
this.app.root.addChild(environment);
});
// create camera entity
const camera = new this.$pc.Entity('camera');
camera.addComponent('camera', {
clearColor: new this.$pc.Color(0.1, 0.1, 0.1)
});
this.app.root.addChild(camera);
camera.setPosition(0, 0, 6);
// create directional light entity
const light = new this.$pc.Entity('light');
light.addComponent('light');
this.app.root.addChild(light);
light.setEulerAngles(45, 0, 0);
this.app.start();
}
}
</script>
Then when I use npm run serve
and check it in the browser, I get the console error:
āError loading model: s01.json [SyntaxError: Unexpected token < in JSON at position 0]ā
When checking the headers in chrome dev-tools the response headers are:
Content-Type: text/html; charset=UTF-8
Those should be application/json
as far as I know, but I donāt know how to make that happen
Any help is greatly appreciated.
Cheers
Hi @patriboz
Where is your assets/models/s01.json
located? If you put it in the src
folder, try moving it to the public
folder where your index.html is.
You were right, it was located in /src/, but after copying the assets to the public folder, I still get the same error and same html response header.
In that case, I think you should be able to see the request url for that file in the network tab of chrome. Can you share that, as well as your folder structure of your Vue project?
Sure. The request url is: http://localhost:8080/public/models/s01.json
And the folderstructure is:
project
+.git
+node_modules
+public
+models
s01.json
+src
+assets
+components
+pages
About.vue
Home.vue
+router
App.vue
main.js
package.json
package-lock.json
README.md
In the code I used this url after copying the model to public: ../../public/models/s01.json
Remove public from the url. I think it should be relative from the public folder, as the siteās index.html is located there.
So the correct path: ./models/s01.json
Oh yes, that did the trick. Thank you so much!
Iāve got some other errors now, but I think I can fix them myself. If not, Iāll get back to you
EDIT: All fixed. Works like a charm now. Thank you!
Hi, this works good. Only thing I discovered is that the MiniStats from the playcanvas-extras do not work. It seems that the āpcā directive cannot be accessed Does anyone have an Idea? I got the error that pc is undefined inside the playcanvas-extras.js script.
Thanks!
Is the order of the scripts correct? (Ie is playcanvas included before extras)
It might be because āpcā isnt registered on the āwindowā. So when you have created your app, try this: window.pc = pc;
Great, that was the cause @Ivolutio ! Thanks a lot - silly me
Hi I wonder, how you structure your Vue.js projects and how you use components.
Most components are renderless I guess. I found a project which combines Vue and Babylon.js https://github.com/Beg-in/vue-babylonjs
Would it be a good approach if it work similar like this or I guess it es enough to structure components as .js files and import themā¦
That is an interesting way to structure your apps, thanks for sharing.
I am personally only using JavaScript to add entities and components to my playcanvas app, but if that other kind of structure makes sense for you I donāt see why it wouldnāt work. It probably depends on what app youāre creating and why youāre using Vue in the first place.