跳到主要内容

与网页通信

PlayCanvas 和 WebGL 的一个主要优势是应用可以直接与周围网页交互。本页介绍 PlayCanvas 应用与网页或 Web 应用之间常见的接口设计方法。

通常有两种情况:将应用通过 iframe 嵌入网页,或使用自己提供的 HTML 页面加载 PlayCanvas。两者需要不同的通信方式。

定义 API​

无论采用哪种托管方式,都应先明确向网页开放哪些应用功能。例如,通过按钮或滑块修改物体颜色,或将输入文本传入应用并渲染到纹理。提前确定所需功能,在 PlayCanvas 中编写显式 API 或函数集合,网页只调用这些接口。

以下简单示例展示了两种向网页暴露应用 API 的方式。

// method one: define a global function to set the score
window.setScore = function (score) {
const app = pc.Application.getApplication();
const entity = app.root.findByName("Score Keeper");
entity.script.scoreKeeper.setScore(score);
}

var ScoreKeeper = pc.createScript("scoreKeeper");

ScoreKeeper.prototype.initialize = function (entity) {
// method two: define an application event to set the score
this.app.on("score:set", function (score) {
this.setScore(score);
}, this);
};

ScoreKeeper.prototype.setScore = function (score) {
// do the score setting here.
};

// how to use the API:

// method one:
window.setScore(10);

// method two:
const app = pc.Application.getApplication();
app.fire("score:set", 10);

第一种定义全局函数,供页面任意位置调用;第二种定义应用事件,由页面触发,应用监听后执行操作。两者都是有效的 API 设计方式。

嵌入 iframe​

通过 iframe 可以快速将 PlayCanvas 内容放入网页,并继续使用经过优化的官方托管服务,无需自行提供全部内容。但宿主页无法直接调用另一个页面中运行的应用 JavaScript 函数。

父页面与 iframe 之间需要使用 JavaScript 的 postMessage API 传递数据。

宿主页中请为 iframe 使用不带额外 iframe 包装的 URL。默认发布链接会再用一个 iframe 包含构建,以显示底部社交分享栏;这样会形成两层 iframe,给 postMessage 通信带来问题。

在 URL 的 https://playcanv.as 后添加 /e,即可获得不含外层 iframe 和社交分享栏的构建版本。

<iframe id="app-frame" src="https://playcanv.as/e/p/example/">
<script>
const iframe = document.getElementById("app-frame");
iframe.contentWindow.postMessage({
score: 10,
}, "https://playcanv.as");
</script>

在应用中:

window.addEventListener("message", function (event) {
if (event.origin === "http://example.com") { // always check message came from your website
const score = event.data.score;

// call API method one:
window.setScore(score);

// call API method two:
const app = pc.Application.getApplication();
app.fire("score:set", score);
}
}, false);

提供自己的 HTML​

下载 PlayCanvas 应用以自行托管时,会包含用于运行应用的 index.html,内容如下。

<!doctype html>
<html>
<head>
<meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no'>
<meta charset='utf-8'>
<link rel="stylesheet" type="text/css" href="styles.css">
<title>Application Title</title>
<script src="playcanvas-stable.min.js"></script>
<script>
SCENE_PATH = "12346.json";
CONTEXT_OPTIONS = {
'alpha': false,
'preserveDrawingBuffer': false
};
</script>
</head>
<body>
<script src="__start__.js"></script>
<script src="__loading__.js"></script>
</body>
</html>

完全可以,也推荐以此页面为基础,修改并加入所需的额外网页内容。

例如,响应按钮点击时,可以直接从页面脚本调用前面定义的应用 API,无需使用 postMessage。

自定义代码应在 __start__.js 之后执行,因为该脚本负责创建 PlayCanvas 应用。很多时候还需要等待资源全部加载,但在应用开始运行前执行,可以监听 start 事件。

例如:

<!doctype html>
<html>
<head>
<meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no'>
<meta charset='utf-8'>
<link rel="stylesheet" type="text/css" href="styles.css">
<title>Application Title</title>
<script src="playcanvas-stable.min.js"></script>
<script>
SCENE_PATH = "12346.json";
CONTEXT_OPTIONS = {
'alpha': false,
'preserveDrawingBuffer': false
};
</script>
</head>
<body>
<script src="__start__.js"></script>
<script src="__loading__.js"></script>
<script>
const app = pc.Application.getApplication();
app.on("start", function () {
// get the root of the scene.
const hierarchy = app.root.children[0];

// do other stuff here
});
</script>
</body>
</html>