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.
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;
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.