跳到主要内容

入门

画布内界面是一棵实体树,根节点带有屏幕组件,定义界面所在空间。其下带元素组件的实体构成图像、文本和容纳其他元素的不可见组。按钮和滚动视图等组件进一步提供行为。本页介绍不同开发方式的配置,并构建一个包含标签和点击计数按钮的小面板。

屏幕中央的深色面板,上方是 Hello, PlayCanvas! 文本,下方是橙色 Click me 按钮

配置​

只要应用包含相应组件系统,就能绘制屏幕与元素。要响应输入,还需 ElementInput,将鼠标、触摸和 XR 输入转换为元素事件。

创建应用时,注册界面组件系统、字体与纹理处理器,以及 ElementInput:

const canvas = document.getElementById('application');
const device = await pc.createGraphicsDevice(canvas, {
deviceTypes: [pc.DEVICETYPE_WEBGPU]
});

const options = new pc.AppOptions();
options.graphicsDevice = device;

// Create the ElementInput before the mouse and touch devices, so that calling
// stopPropagation() in a UI event handler also hides the event from them
options.elementInput = new pc.ElementInput(canvas);
options.mouse = new pc.Mouse(canvas);
options.touch = new pc.TouchDevice(canvas);

options.componentSystems = [
pc.CameraComponentSystem,
pc.ScreenComponentSystem,
pc.ElementComponentSystem,
pc.ButtonComponentSystem
];
options.resourceHandlers = [
pc.FontHandler,
pc.TextureHandler
];

const app = new pc.AppBase(canvas);
app.init(options);
app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
app.setCanvasResolution(pc.RESOLUTION_AUTO);
app.start();

window.addEventListener('resize', () => app.resizeCanvas());

使用其他界面组件时,再添加 pc.ScrollViewComponentSystem、pc.ScrollbarComponentSystem、pc.LayoutGroupComponentSystem 和 pc.LayoutChildComponentSystem。精灵还需要 pc.SpriteHandler 与 pc.TextureAtlasHandler。pc.Application 会注册所有系统和处理器,但同样不会自动创建 ElementInput,需要通过选项传入。其余配置详见独立使用引擎。

第一个界面​

上图的界面由屏幕和面板组成,面板包含标签和按钮,按钮包含自己的文本。文本需要字体资源;本页代码加载名为 arial.json 的字体,可由任意字体文件生成。

按前述方法配置应用后:

// Load a font for the text
const font = new pc.Asset('arial', 'font', { url: 'fonts/arial.json' });
app.assets.add(font);
await new Promise((resolve) => {
font.ready(resolve);
app.assets.load(font);
});

const camera = new pc.Entity('camera');
camera.addComponent('camera', { clearColor: new pc.Color(0.1, 0.11, 0.13) });
app.root.addChild(camera);

// A screen-space screen that scales with the canvas
const screen = new pc.Entity('screen');
screen.addComponent('screen', {
screenSpace: true,
referenceResolution: [1280, 720],
scaleMode: pc.SCALEMODE_BLEND,
scaleBlend: 0.5
});
app.root.addChild(screen);

// A panel in the middle of the screen
const panel = new pc.Entity('panel');
panel.addComponent('element', {
type: pc.ELEMENTTYPE_IMAGE,
anchor: [0.5, 0.5, 0.5, 0.5],
pivot: [0.5, 0.5],
width: 420,
height: 240,
color: new pc.Color(0.16, 0.18, 0.23),
opacity: 0.9
});
screen.addChild(panel);

// A label near the top of the panel
const label = new pc.Entity('label');
label.addComponent('element', {
type: pc.ELEMENTTYPE_TEXT,
fontAsset: font.id,
text: 'Hello, PlayCanvas!',
fontSize: 36,
anchor: [0.5, 1, 0.5, 1],
pivot: [0.5, 1]
});
label.setLocalPosition(0, -40, 0);
panel.addChild(label);

// A button near the bottom: an image element that receives input, and a
// button component that tints the image when it is hovered and pressed
const button = new pc.Entity('button');
button.addComponent('element', {
type: pc.ELEMENTTYPE_IMAGE,
anchor: [0.5, 0, 0.5, 0],
pivot: [0.5, 0],
width: 200,
height: 60,
color: new pc.Color(1, 0.55, 0.2),
useInput: true
});
button.addComponent('button', {
imageEntity: button,
hoverTint: new pc.Color(1, 0.7, 0.45),
pressedTint: new pc.Color(0.8, 0.4, 0.1)
});
button.setLocalPosition(0, 40, 0);
panel.addChild(button);

const buttonText = new pc.Entity('text');
buttonText.addComponent('element', {
type: pc.ELEMENTTYPE_TEXT,
fontAsset: font.id,
text: 'Click me',
fontSize: 28,
color: new pc.Color(0.1, 0.1, 0.1),
anchor: [0.5, 0.5, 0.5, 0.5],
pivot: [0.5, 0.5]
});
button.addChild(buttonText);

// Count the clicks
let clicks = 0;
button.button.on('click', () => {
clicks++;
label.element.text = `Clicked ${clicks} times`;
});
按钮

组合关系​

上述界面的实体树如下:

screen 屏幕组件:根节点,定义界面所在空间
└── panel 图像元素
├── label 文本元素
└── button 接收输入的图像元素,并带按钮组件
└── text 文本元素

由此可得以下规则,本章其余内容都建立在这些规则之上:

  • 元素按屏幕单位布局。 对于本例这种会缩放的屏幕空间界面,一个单位对应 1280 × 720 参考分辨率下的一个像素,全部内容随画布缩放。详见屏幕。
  • 子项相对父项定位。 锚点选择父项上的点或边,轴心选择元素自身放在该位置的点。标签锚定面板顶部,因此面板移动或改尺寸时,标签也随之变化。Y 轴向上,详见元素。
  • 层级决定绘制顺序。 父项先于子项绘制,较早的同级项先于后面的同级项,因此按钮文本会显示在按钮之上。详见绘制顺序与性能。
  • 只有启用输入的元素才会接收输入。 按钮图像启用了 useInput,事件会向祖先冒泡,详见输入。

不同开发方式的命名​

所有方式操作相同组件,同一属性具有四种书写形式:

开发方式风格示例
引擎camelCase 属性。向量和颜色使用 pc.Vec2、pc.Vec4、pc.Color 对象,传给 addComponent 时也可用数组fontSize: 36, anchor: [0.5, 1, 0.5, 1]
编辑器检查器字段采用单词首字母大写Font Size、Anchor
ReactcamelCase props,向量使用数组,颜色使用 CSS 颜色字符串fontSize={36}, anchor={[0.5, 1, 0.5, 1]}, color="#ff8c33"
Web Componentskebab-case 属性,向量使用空格分隔的数字font-size="36", anchor="0.5 1 0.5 1"

少数属性没有对应的 React prop 或 Web Components attribute。例如,React 保留了 key,<pc-element> 也没有 layers 和 rect 属性。这时应直接设置引擎组件:React 中通过 useParent() 或 <Entity ref> 获取实体;Web Components 中等待 whenReady 完成,再使用元素的 component 属性。

默认值有所不同​

组件默认值来自引擎,但 React 会修改部分默认值,因此不传选项时,不同方式创建的屏幕或元素可能表现不同:

引擎ReactWeb Components
无选项的屏幕世界空间,Scale Mode 为 None,640 × 320屏幕空间,Scale Mode 为 Blend,参考分辨率 1280 × 720世界空间,Scale Mode 为 None,640 × 320
元素锚点和轴心左下角:0, 0, 0, 0 和 0, 0左下角左下角
元素尺寸32 × 3232 × 3232 × 32
输入设备传给 AppOptions 的设备鼠标、触摸和元素输入鼠标、键盘和元素输入

请像本页示例一样,显式设置所依赖的属性。编辑器检查器会显示新实体的全部值,可以在那里核对。

另请参阅​