create-playcanvas 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -16
- package/dist/index.mjs +20 -20
- package/package.json +2 -2
- package/templates/_shared/{ar-placement → ar}/README.md +1 -1
- package/templates/_shared/blank/README.md +7 -0
- package/templates/_shared/first-person-game/AGENTS.md +11 -0
- package/templates/_shared/first-person-game/README.md +21 -0
- package/templates/_shared/first-person-game/public/level.glb +0 -0
- package/templates/_shared/first-person-game/src/game.css +47 -0
- package/templates/_shared/first-person-game/src/game.ts +232 -0
- package/templates/_shared/{sprite-game → platformer}/README.md +1 -1
- package/templates/_shared/{sprite-game/src/sprite-game.ts → platformer/src/platformer.ts} +3 -3
- package/templates/_shared/{third-person-controller → third-person-game}/README.md +1 -1
- package/templates/_shared/{vr-starter → vr}/README.md +1 -1
- package/templates/engine/ar/index.html +20 -0
- package/templates/engine/{ar-placement → ar}/src/main.ts +22 -12
- package/templates/engine/base/package.json +2 -2
- package/templates/engine/first-person-game/index.html +26 -0
- package/templates/engine/first-person-game/src/main.ts +167 -0
- package/templates/engine/platformer/index.html +19 -0
- package/templates/engine/{sprite-game → platformer}/src/main.ts +21 -13
- package/templates/engine/product-configurator/index.html +30 -0
- package/templates/engine/product-configurator/src/main.ts +33 -32
- package/templates/engine/third-person-game/index.html +19 -0
- package/templates/engine/{third-person-controller → third-person-game}/src/main.ts +16 -11
- package/templates/engine/vr/index.html +20 -0
- package/templates/engine/{vr-starter → vr}/src/main.ts +22 -12
- package/templates/index.ts +14 -14
- package/templates/react/{ar-placement → ar}/src/App.tsx +1 -1
- package/templates/react/base/package.json +2 -2
- package/templates/react/first-person-game/src/App.tsx +140 -0
- package/templates/react/{sprite-game → platformer}/src/App.tsx +3 -3
- package/templates/react/{third-person-controller → third-person-game}/src/App.tsx +1 -1
- package/templates/react/{vr-starter → vr}/src/App.tsx +1 -1
- package/templates/web-components/{ar-placement → ar}/index.html +2 -2
- package/templates/web-components/base/package.json +2 -2
- package/templates/web-components/first-person-game/index.html +80 -0
- package/templates/web-components/first-person-game/src/main.ts +74 -0
- package/templates/web-components/{sprite-game → platformer}/index.html +2 -2
- package/templates/web-components/{sprite-game → platformer}/src/main.ts +2 -2
- package/templates/web-components/{third-person-controller → third-person-game}/index.html +2 -2
- package/templates/web-components/{vr-starter → vr}/index.html +2 -2
- package/templates/_shared/first-person-controller/README.md +0 -7
- package/templates/_shared/first-person-controller/src/controller.ts +0 -18
- package/templates/_shared/spinning-cube/README.md +0 -7
- package/templates/engine/first-person-controller/src/main.ts +0 -138
- package/templates/react/first-person-controller/src/App.tsx +0 -115
- package/templates/web-components/first-person-controller/index.html +0 -163
- package/templates/web-components/first-person-controller/src/main.ts +0 -15
- /package/templates/_shared/{ar-placement → ar}/src/ar-placement.ts +0 -0
- /package/templates/_shared/{first-person-controller → first-person-game}/src/scripts.d.ts +0 -0
- /package/templates/_shared/{third-person-controller → third-person-game}/src/controller.ts +0 -0
- /package/templates/_shared/{third-person-controller → third-person-game}/src/scripts.d.ts +0 -0
- /package/templates/_shared/{vr-starter → vr}/src/vr.ts +0 -0
- /package/templates/_shared/{vr-starter → vr}/src/xr.d.ts +0 -0
- /package/templates/engine/{spinning-cube → blank}/src/main.ts +0 -0
- /package/templates/react/{spinning-cube → blank}/src/App.tsx +0 -0
- /package/templates/web-components/{ar-placement → ar}/src/main.ts +0 -0
- /package/templates/web-components/{spinning-cube → blank}/index.html +0 -0
- /package/templates/web-components/{spinning-cube → blank}/src/main.ts +0 -0
- /package/templates/web-components/{third-person-controller → third-person-game}/src/main.ts +0 -0
- /package/templates/web-components/{vr-starter → vr}/src/main.ts +0 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { AssetElement, EntityElement } from '@playcanvas/web-components';
|
|
2
|
+
import { whenReady } from '@playcanvas/web-components';
|
|
3
|
+
import type { Asset } from 'playcanvas';
|
|
4
|
+
import { ProceduralSky } from 'playcanvas/scripts/esm/sky/procedural-sky.mjs';
|
|
5
|
+
|
|
6
|
+
import { CARDS, Game } from './game';
|
|
7
|
+
import type { GameEvents } from './game';
|
|
8
|
+
import './game.css';
|
|
9
|
+
import './starter.css';
|
|
10
|
+
|
|
11
|
+
// The HUD follows the game's state
|
|
12
|
+
const hud = {
|
|
13
|
+
orbs: document.getElementById('orbs')!,
|
|
14
|
+
time: document.getElementById('time')!,
|
|
15
|
+
card: document.getElementById('card')!,
|
|
16
|
+
title: document.getElementById('card-title')!,
|
|
17
|
+
hint: document.getElementById('card-hint')!,
|
|
18
|
+
joystick: document.getElementById('joystick')!,
|
|
19
|
+
knob: document.getElementById('joystick-knob')!
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const onState: GameEvents['game:state'] = (state, found, total, seconds) => {
|
|
23
|
+
const card = CARDS[state];
|
|
24
|
+
hud.orbs.textContent = `${found} / ${total}`;
|
|
25
|
+
hud.time.textContent = `${seconds}s`;
|
|
26
|
+
hud.card.hidden = !card;
|
|
27
|
+
if (card) {
|
|
28
|
+
hud.title.textContent = card.title;
|
|
29
|
+
hud.hint.textContent = card.hint;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// A thumb on the left of the screen steers, and the circle and knob show where it is
|
|
34
|
+
const onJoystick: GameEvents['joystick:left'] = (baseX, baseY, knobX, knobY) => {
|
|
35
|
+
hud.joystick.hidden = hud.knob.hidden = baseX < 0;
|
|
36
|
+
hud.joystick.style.left = `${baseX}px`;
|
|
37
|
+
hud.joystick.style.top = `${baseY}px`;
|
|
38
|
+
hud.knob.style.left = `${knobX}px`;
|
|
39
|
+
hud.knob.style.top = `${knobY}px`;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const { app } = await whenReady('pc-app');
|
|
43
|
+
app!.on('game:state', onState);
|
|
44
|
+
app!.on('joystick:left', onJoystick);
|
|
45
|
+
|
|
46
|
+
// The player is awaited as its components rather than the <pc-entity> holding them - an entity
|
|
47
|
+
// becomes ready before its component children do, and the game needs its rigid body to exist
|
|
48
|
+
await Promise.all([
|
|
49
|
+
whenReady('pc-entity[name="player"] > pc-collision'),
|
|
50
|
+
whenReady('pc-entity[name="player"] > pc-rigid-body'),
|
|
51
|
+
whenReady('pc-entity[name="sun"] > pc-light'),
|
|
52
|
+
whenReady('pc-camera')
|
|
53
|
+
]);
|
|
54
|
+
const [level, sun, sky, player, camera, game] = await Promise.all([
|
|
55
|
+
whenReady<AssetElement>('pc-asset#level'),
|
|
56
|
+
whenReady<EntityElement>('pc-entity[name="sun"]'),
|
|
57
|
+
whenReady<EntityElement>('pc-entity[name="sky"]'),
|
|
58
|
+
whenReady<EntityElement>('pc-entity[name="player"]'),
|
|
59
|
+
whenReady<EntityElement>('pc-entity[name="camera"]'),
|
|
60
|
+
whenReady<EntityElement>('pc-entity[name="game"]')
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
// Engine scripts are resolved by the bundler, so they are attached through the entity rather than
|
|
64
|
+
// with <pc-script-instance name="...">, which only resolves scripts fetched at runtime by <pc-asset>.
|
|
65
|
+
// The sky's default luminance is scene-scale bright, so turn it down to keep the yard out of clipping
|
|
66
|
+
sky.entity!.addComponent('script');
|
|
67
|
+
sky.entity!.script!.create(ProceduralSky, {
|
|
68
|
+
properties: { luminance: 0.3, azimuth: 150, elevation: 45, sunLight: sun.entity }
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
game.entity!.addComponent('script');
|
|
72
|
+
game.entity!.script!.create(Game, {
|
|
73
|
+
properties: { level: level.asset as Asset<'container'>, player: player.entity, camera: camera.entity }
|
|
74
|
+
});
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<link rel="icon" type="image/png" href="/src/assets/playcanvas.png" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
-
<title>
|
|
7
|
+
<title>Platformer</title>
|
|
8
8
|
</head>
|
|
9
9
|
<body>
|
|
10
10
|
<pc-app>
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
</pc-app>
|
|
26
26
|
<div class="hud">
|
|
27
27
|
<section class="panel">
|
|
28
|
-
<h1>
|
|
28
|
+
<h1>Platformer</h1>
|
|
29
29
|
<p>Use A/D or the arrow keys to move and Space to jump.</p>
|
|
30
30
|
</section>
|
|
31
31
|
</div>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { EntityElement } from '@playcanvas/web-components';
|
|
2
2
|
import { whenReady } from '@playcanvas/web-components';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { Platformer } from './platformer';
|
|
5
5
|
import './starter.css';
|
|
6
6
|
|
|
7
7
|
const game = await whenReady<EntityElement>('pc-entity[name="game"]');
|
|
8
8
|
game.entity!.addComponent('script');
|
|
9
|
-
game.entity!.script!.create(
|
|
9
|
+
game.entity!.script!.create(Platformer);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<link rel="icon" type="image/png" href="/src/assets/playcanvas.png" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
-
<title>Third-Person
|
|
7
|
+
<title>Third-Person Game</title>
|
|
8
8
|
</head>
|
|
9
9
|
<body>
|
|
10
10
|
<pc-app>
|
|
@@ -184,7 +184,7 @@
|
|
|
184
184
|
</pc-app>
|
|
185
185
|
<div class="hud">
|
|
186
186
|
<section class="panel">
|
|
187
|
-
<h1>Third-Person
|
|
187
|
+
<h1>Third-Person Game</h1>
|
|
188
188
|
<p>Click the scene, then use WASD to move, mouse to orbit and Space to jump.</p>
|
|
189
189
|
</section>
|
|
190
190
|
</div>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<link rel="icon" type="image/png" href="/src/assets/playcanvas.png" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
-
<title>
|
|
7
|
+
<title>Virtual Reality</title>
|
|
8
8
|
</head>
|
|
9
9
|
<body>
|
|
10
10
|
<pc-app>
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
</pc-app>
|
|
71
71
|
<div class="hud">
|
|
72
72
|
<section class="panel">
|
|
73
|
-
<h1>
|
|
73
|
+
<h1>Virtual Reality</h1>
|
|
74
74
|
<p id="xr-status">Checking VR support…</p>
|
|
75
75
|
<div class="controls"><button id="xr-button" disabled>Enter VR</button></div>
|
|
76
76
|
</section>
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { Entity, RigidBodyComponentSystem } from 'playcanvas';
|
|
2
|
-
import { FirstPersonController } from 'playcanvas/scripts/esm/first-person-controller.mjs';
|
|
3
|
-
|
|
4
|
-
export const addFirstPersonController = (player: Entity, camera: Entity) => {
|
|
5
|
-
(player.rigidbody!.system as RigidBodyComponentSystem).gravity.set(0, -18, 0);
|
|
6
|
-
if (!player.script) player.addComponent('script');
|
|
7
|
-
player.script!.create(FirstPersonController, {
|
|
8
|
-
properties: {
|
|
9
|
-
camera,
|
|
10
|
-
jumpForce: 650,
|
|
11
|
-
speedGround: 55
|
|
12
|
-
}
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
return () => {
|
|
16
|
-
player.script?.destroy('firstPersonController');
|
|
17
|
-
};
|
|
18
|
-
};
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AppBase,
|
|
3
|
-
AppOptions,
|
|
4
|
-
CameraComponentSystem,
|
|
5
|
-
CollisionComponentSystem,
|
|
6
|
-
Color,
|
|
7
|
-
Entity,
|
|
8
|
-
FILLMODE_FILL_WINDOW,
|
|
9
|
-
LightComponentSystem,
|
|
10
|
-
RenderComponentSystem,
|
|
11
|
-
RESOLUTION_AUTO,
|
|
12
|
-
RigidBodyComponentSystem,
|
|
13
|
-
ScriptComponentSystem,
|
|
14
|
-
StandardMaterial,
|
|
15
|
-
Vec3,
|
|
16
|
-
WasmModule,
|
|
17
|
-
createGraphicsDevice
|
|
18
|
-
} from 'playcanvas';
|
|
19
|
-
|
|
20
|
-
import { addFirstPersonController } from './controller';
|
|
21
|
-
import './starter.css';
|
|
22
|
-
|
|
23
|
-
WasmModule.setConfig('Ammo', {
|
|
24
|
-
glueUrl: './ammo/ammo.wasm.js',
|
|
25
|
-
wasmUrl: './ammo/ammo.wasm.wasm'
|
|
26
|
-
});
|
|
27
|
-
await new Promise<void>((resolve) => {
|
|
28
|
-
WasmModule.getInstance('Ammo', () => resolve());
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
document.body.insertAdjacentHTML(
|
|
32
|
-
'beforeend',
|
|
33
|
-
'<div class="hud"><section class="panel"><h1>First-Person Controller</h1><p>Click the scene, then use WASD, mouse look and Space to jump.</p></section></div>'
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
const canvas = document.getElementById('application-canvas') as HTMLCanvasElement;
|
|
37
|
-
const device = await createGraphicsDevice(canvas);
|
|
38
|
-
const options = new AppOptions();
|
|
39
|
-
options.graphicsDevice = device;
|
|
40
|
-
options.componentSystems = [
|
|
41
|
-
RenderComponentSystem,
|
|
42
|
-
CameraComponentSystem,
|
|
43
|
-
LightComponentSystem,
|
|
44
|
-
ScriptComponentSystem,
|
|
45
|
-
CollisionComponentSystem,
|
|
46
|
-
RigidBodyComponentSystem
|
|
47
|
-
];
|
|
48
|
-
|
|
49
|
-
const app = new AppBase(canvas);
|
|
50
|
-
app.init(options);
|
|
51
|
-
app.start();
|
|
52
|
-
app.setCanvasFillMode(FILLMODE_FILL_WINDOW);
|
|
53
|
-
app.setCanvasResolution(RESOLUTION_AUTO);
|
|
54
|
-
|
|
55
|
-
const material = (color: Color) => {
|
|
56
|
-
const result = new StandardMaterial();
|
|
57
|
-
result.diffuse = color;
|
|
58
|
-
result.emissive = new Color(color.r * 0.2, color.g * 0.2, color.b * 0.2);
|
|
59
|
-
result.update();
|
|
60
|
-
return result;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const floor = material(new Color(0.28, 0.3, 0.32));
|
|
64
|
-
const wall = material(new Color(0.42, 0.45, 0.48));
|
|
65
|
-
const blue = material(new Color(0.08, 0.29, 0.48));
|
|
66
|
-
const green = material(new Color(0.18, 0.4, 0.22));
|
|
67
|
-
const wood = material(new Color(0.48, 0.27, 0.1));
|
|
68
|
-
const metal = material(new Color(0.28, 0.33, 0.38));
|
|
69
|
-
|
|
70
|
-
const block = (
|
|
71
|
-
name: string,
|
|
72
|
-
position: [number, number, number],
|
|
73
|
-
scale: [number, number, number],
|
|
74
|
-
blockMaterial: StandardMaterial
|
|
75
|
-
) => {
|
|
76
|
-
const entity = new Entity(name);
|
|
77
|
-
entity.setPosition(...position);
|
|
78
|
-
entity.setLocalScale(...scale);
|
|
79
|
-
entity.addComponent('render', { type: 'box', material: blockMaterial });
|
|
80
|
-
entity.addComponent('collision', {
|
|
81
|
-
type: 'box',
|
|
82
|
-
halfExtents: new Vec3(scale[0] / 2, scale[1] / 2, scale[2] / 2)
|
|
83
|
-
});
|
|
84
|
-
entity.addComponent('rigidbody', { type: 'static' });
|
|
85
|
-
app.root.addChild(entity);
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
block('floor', [0, -0.1, 0], [18, 0.2, 18], floor);
|
|
89
|
-
block('back-wall', [0, 1.5, -9], [18, 3, 0.3], wall);
|
|
90
|
-
block('front-wall', [0, 1.5, 9], [18, 3, 0.3], wall);
|
|
91
|
-
block('left-wall', [-9, 1.5, 0], [0.3, 3, 18], wall);
|
|
92
|
-
block('right-wall', [9, 1.5, 0], [0.3, 3, 18], wall);
|
|
93
|
-
block('blue-crate', [-2, 0.75, -3], [1.5, 1.5, 1.5], blue);
|
|
94
|
-
block('green-crate', [3, 0.5, 1], [2.5, 1, 1], green);
|
|
95
|
-
block('cargo-left-0', [-5.5, 0.75, -5.5], [2, 1.5, 2], wood);
|
|
96
|
-
block('cargo-left-1', [-5.5, 2, -5.5], [1.5, 1, 1.5], blue);
|
|
97
|
-
block('cargo-right-0', [5.3, 0.6, -4.8], [2.4, 1.2, 2], green);
|
|
98
|
-
block('cargo-right-1', [5.3, 1.7, -4.8], [1.5, 1, 1.5], wood);
|
|
99
|
-
block('cargo-center', [0, 0.6, -6.5], [2.2, 1.2, 1.8], blue);
|
|
100
|
-
for (const [i, z] of [-3.5, 0, 3.5].entries()) {
|
|
101
|
-
block(`shelf-left-post-${i}`, [-6.8, 1.4, z], [0.25, 2.8, 0.25], metal);
|
|
102
|
-
block(`shelf-right-post-${i}`, [6.8, 1.4, z], [0.25, 2.8, 0.25], metal);
|
|
103
|
-
}
|
|
104
|
-
block('shelf-left-low', [-6.8, 0.65, 0], [1.1, 0.18, 7.5], metal);
|
|
105
|
-
block('shelf-left-high', [-6.8, 2.1, 0], [1.1, 0.18, 7.5], metal);
|
|
106
|
-
block('shelf-right-low', [6.8, 0.65, 0], [1.1, 0.18, 7.5], metal);
|
|
107
|
-
block('shelf-right-high', [6.8, 2.1, 0], [1.1, 0.18, 7.5], metal);
|
|
108
|
-
block('pallet', [-2.5, 0.15, 2.5], [3, 0.3, 2], wood);
|
|
109
|
-
|
|
110
|
-
const player = new Entity('player');
|
|
111
|
-
player.setPosition(0, 1, 5);
|
|
112
|
-
player.addComponent('collision', { type: 'capsule', radius: 0.45, height: 1.8 });
|
|
113
|
-
player.addComponent('rigidbody', { type: 'dynamic', mass: 80, angularFactor: Vec3.ZERO });
|
|
114
|
-
app.root.addChild(player);
|
|
115
|
-
|
|
116
|
-
const camera = new Entity('camera');
|
|
117
|
-
camera.addComponent('camera', { clearColor: new Color(0.38, 0.64, 0.86), fov: 80 });
|
|
118
|
-
camera.setLocalPosition(0, 0.65, 0);
|
|
119
|
-
player.addChild(camera);
|
|
120
|
-
addFirstPersonController(player, camera);
|
|
121
|
-
|
|
122
|
-
const light = new Entity('light');
|
|
123
|
-
light.addComponent('light', {
|
|
124
|
-
type: 'directional',
|
|
125
|
-
intensity: 2.5,
|
|
126
|
-
castShadows: true,
|
|
127
|
-
shadowBias: 0.2,
|
|
128
|
-
normalOffsetBias: 0.05
|
|
129
|
-
});
|
|
130
|
-
light.setEulerAngles(50, 30, 0);
|
|
131
|
-
app.root.addChild(light);
|
|
132
|
-
|
|
133
|
-
const fill = new Entity('fill');
|
|
134
|
-
fill.addComponent('light', { type: 'directional', intensity: 0.8 });
|
|
135
|
-
fill.setEulerAngles(-25, -140, 0);
|
|
136
|
-
app.root.addChild(fill);
|
|
137
|
-
|
|
138
|
-
window.addEventListener('resize', () => app.resizeCanvas());
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { Application, Entity } from '@playcanvas/react';
|
|
2
|
-
import { Camera, Collision, Light, Render, RigidBody } from '@playcanvas/react/components';
|
|
3
|
-
import { useMaterial, usePhysics } from '@playcanvas/react/hooks';
|
|
4
|
-
import type { Entity as PcEntity, StandardMaterial } from 'playcanvas';
|
|
5
|
-
import { useEffect, useRef } from 'react';
|
|
6
|
-
|
|
7
|
-
import { addFirstPersonController } from './controller';
|
|
8
|
-
import './starter.css';
|
|
9
|
-
|
|
10
|
-
function Block({
|
|
11
|
-
name,
|
|
12
|
-
position,
|
|
13
|
-
scale,
|
|
14
|
-
material
|
|
15
|
-
}: {
|
|
16
|
-
name: string;
|
|
17
|
-
position: [number, number, number];
|
|
18
|
-
scale: [number, number, number];
|
|
19
|
-
material: StandardMaterial;
|
|
20
|
-
}) {
|
|
21
|
-
return (
|
|
22
|
-
<Entity name={name} position={position} scale={scale}>
|
|
23
|
-
<Render type="box" material={material} />
|
|
24
|
-
<Collision type="box" halfExtents={[scale[0] / 2, scale[1] / 2, scale[2] / 2]} />
|
|
25
|
-
<RigidBody type="static" />
|
|
26
|
-
</Entity>
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function Scene() {
|
|
31
|
-
const player = useRef<PcEntity>(null);
|
|
32
|
-
const camera = useRef<PcEntity>(null);
|
|
33
|
-
const { isPhysicsLoaded } = usePhysics();
|
|
34
|
-
const floor = useMaterial({ diffuse: '#474d52', emissive: '#0e0f10', gloss: 0.2 });
|
|
35
|
-
const wall = useMaterial({ diffuse: '#6b737a', emissive: '#151718', gloss: 0.25 });
|
|
36
|
-
const blue = useMaterial({ diffuse: '#154a7a', emissive: '#040f18', gloss: 0.4 });
|
|
37
|
-
const green = useMaterial({ diffuse: '#2e6638', emissive: '#09140b', gloss: 0.2 });
|
|
38
|
-
const wood = useMaterial({ diffuse: '#7a451a', emissive: '#180e05', gloss: 0.2 });
|
|
39
|
-
const metal = useMaterial({ diffuse: '#475461', emissive: '#0e1113', gloss: 0.5 });
|
|
40
|
-
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
if (isPhysicsLoaded && player.current && camera.current) {
|
|
43
|
-
return addFirstPersonController(player.current, camera.current);
|
|
44
|
-
}
|
|
45
|
-
}, [isPhysicsLoaded]);
|
|
46
|
-
|
|
47
|
-
return (
|
|
48
|
-
<>
|
|
49
|
-
<Entity name="light" rotation={[50, 30, 0]}>
|
|
50
|
-
<Light type="directional" intensity={2.5} castShadows shadowBias={0.2} normalOffsetBias={0.05} />
|
|
51
|
-
</Entity>
|
|
52
|
-
<Entity name="fill" rotation={[-25, -140, 0]}>
|
|
53
|
-
<Light type="directional" intensity={0.8} />
|
|
54
|
-
</Entity>
|
|
55
|
-
<Block name="floor" position={[0, -0.1, 0]} scale={[18, 0.2, 18]} material={floor} />
|
|
56
|
-
<Block name="back-wall" position={[0, 1.5, -9]} scale={[18, 3, 0.3]} material={wall} />
|
|
57
|
-
<Block name="front-wall" position={[0, 1.5, 9]} scale={[18, 3, 0.3]} material={wall} />
|
|
58
|
-
<Block name="left-wall" position={[-9, 1.5, 0]} scale={[0.3, 3, 18]} material={wall} />
|
|
59
|
-
<Block name="right-wall" position={[9, 1.5, 0]} scale={[0.3, 3, 18]} material={wall} />
|
|
60
|
-
<Block name="blue-crate" position={[-2, 0.75, -3]} scale={[1.5, 1.5, 1.5]} material={blue} />
|
|
61
|
-
<Block name="green-crate" position={[3, 0.5, 1]} scale={[2.5, 1, 1]} material={green} />
|
|
62
|
-
<Block name="cargo-left-0" position={[-5.5, 0.75, -5.5]} scale={[2, 1.5, 2]} material={wood} />
|
|
63
|
-
<Block name="cargo-left-1" position={[-5.5, 2, -5.5]} scale={[1.5, 1, 1.5]} material={blue} />
|
|
64
|
-
<Block name="cargo-right-0" position={[5.3, 0.6, -4.8]} scale={[2.4, 1.2, 2]} material={green} />
|
|
65
|
-
<Block name="cargo-right-1" position={[5.3, 1.7, -4.8]} scale={[1.5, 1, 1.5]} material={wood} />
|
|
66
|
-
<Block name="cargo-center" position={[0, 0.6, -6.5]} scale={[2.2, 1.2, 1.8]} material={blue} />
|
|
67
|
-
{[-3.5, 0, 3.5].flatMap((z, i) => [
|
|
68
|
-
<Block
|
|
69
|
-
key={`left-${i}`}
|
|
70
|
-
name={`shelf-left-post-${i}`}
|
|
71
|
-
position={[-6.8, 1.4, z]}
|
|
72
|
-
scale={[0.25, 2.8, 0.25]}
|
|
73
|
-
material={metal}
|
|
74
|
-
/>,
|
|
75
|
-
<Block
|
|
76
|
-
key={`right-${i}`}
|
|
77
|
-
name={`shelf-right-post-${i}`}
|
|
78
|
-
position={[6.8, 1.4, z]}
|
|
79
|
-
scale={[0.25, 2.8, 0.25]}
|
|
80
|
-
material={metal}
|
|
81
|
-
/>
|
|
82
|
-
])}
|
|
83
|
-
<Block name="shelf-left-low" position={[-6.8, 0.65, 0]} scale={[1.1, 0.18, 7.5]} material={metal} />
|
|
84
|
-
<Block name="shelf-left-high" position={[-6.8, 2.1, 0]} scale={[1.1, 0.18, 7.5]} material={metal} />
|
|
85
|
-
<Block name="shelf-right-low" position={[6.8, 0.65, 0]} scale={[1.1, 0.18, 7.5]} material={metal} />
|
|
86
|
-
<Block name="shelf-right-high" position={[6.8, 2.1, 0]} scale={[1.1, 0.18, 7.5]} material={metal} />
|
|
87
|
-
<Block name="pallet" position={[-2.5, 0.15, 2.5]} scale={[3, 0.3, 2]} material={wood} />
|
|
88
|
-
<Entity name="player" ref={player} position={[0, 1, 5]}>
|
|
89
|
-
<Collision type="capsule" radius={0.45} height={1.8} />
|
|
90
|
-
<RigidBody type="dynamic" mass={80} angularFactor={[0, 0, 0]} />
|
|
91
|
-
<Entity name="camera" ref={camera} position={[0, 0.65, 0]}>
|
|
92
|
-
<Camera clearColor="#61a3db" fov={80} />
|
|
93
|
-
</Entity>
|
|
94
|
-
</Entity>
|
|
95
|
-
</>
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function App() {
|
|
100
|
-
return (
|
|
101
|
-
<>
|
|
102
|
-
<Application usePhysics>
|
|
103
|
-
<Scene />
|
|
104
|
-
</Application>
|
|
105
|
-
<div className="hud">
|
|
106
|
-
<section className="panel">
|
|
107
|
-
<h1>First-Person Controller</h1>
|
|
108
|
-
<p>Click the scene, then use WASD, mouse look and Space to jump.</p>
|
|
109
|
-
</section>
|
|
110
|
-
</div>
|
|
111
|
-
</>
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export default App;
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<link rel="icon" type="image/png" href="/src/assets/playcanvas.png" />
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
-
<title>First-Person Controller</title>
|
|
8
|
-
</head>
|
|
9
|
-
<body>
|
|
10
|
-
<pc-app>
|
|
11
|
-
<pc-material id="floor-material" diffuse="#474d52" emissive="#0e0f10" gloss="0.2"></pc-material>
|
|
12
|
-
<pc-material id="wall-material" diffuse="#6b737a" emissive="#151718" gloss="0.25"></pc-material>
|
|
13
|
-
<pc-material id="blue-material" diffuse="#154a7a" emissive="#040f18" gloss="0.4"></pc-material>
|
|
14
|
-
<pc-material id="green-material" diffuse="#2e6638" emissive="#09140b" gloss="0.2"></pc-material>
|
|
15
|
-
<pc-material id="wood-material" diffuse="#7a451a" emissive="#180e05" gloss="0.2"></pc-material>
|
|
16
|
-
<pc-material id="metal-material" diffuse="#475461" emissive="#0e1113" gloss="0.5"></pc-material>
|
|
17
|
-
<pc-wasm name="Ammo" glue="./ammo/ammo.wasm.js" wasm="./ammo/ammo.wasm.wasm"></pc-wasm>
|
|
18
|
-
<pc-scene>
|
|
19
|
-
<pc-entity name="light" rotation="50 30 0"
|
|
20
|
-
><pc-light
|
|
21
|
-
type="directional"
|
|
22
|
-
intensity="2.5"
|
|
23
|
-
cast-shadows
|
|
24
|
-
shadow-bias="0.2"
|
|
25
|
-
normal-offset-bias="0.05"
|
|
26
|
-
></pc-light
|
|
27
|
-
></pc-entity>
|
|
28
|
-
<pc-entity name="fill" rotation="-25 -140 0"
|
|
29
|
-
><pc-light type="directional" intensity="0.8"></pc-light
|
|
30
|
-
></pc-entity>
|
|
31
|
-
<pc-entity name="floor" position="0 -0.1 0" scale="18 0.2 18"
|
|
32
|
-
><pc-render type="box" material="floor-material"></pc-render
|
|
33
|
-
><pc-collision type="box" half-extents="9 0.1 9"></pc-collision
|
|
34
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
35
|
-
></pc-entity>
|
|
36
|
-
<pc-entity name="back-wall" position="0 1.5 -9" scale="18 3 0.3"
|
|
37
|
-
><pc-render type="box" material="wall-material"></pc-render
|
|
38
|
-
><pc-collision type="box" half-extents="9 1.5 0.15"></pc-collision
|
|
39
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
40
|
-
></pc-entity>
|
|
41
|
-
<pc-entity name="front-wall" position="0 1.5 9" scale="18 3 0.3"
|
|
42
|
-
><pc-render type="box" material="wall-material"></pc-render
|
|
43
|
-
><pc-collision type="box" half-extents="9 1.5 0.15"></pc-collision
|
|
44
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
45
|
-
></pc-entity>
|
|
46
|
-
<pc-entity name="left-wall" position="-9 1.5 0" scale="0.3 3 18"
|
|
47
|
-
><pc-render type="box" material="wall-material"></pc-render
|
|
48
|
-
><pc-collision type="box" half-extents="0.15 1.5 9"></pc-collision
|
|
49
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
50
|
-
></pc-entity>
|
|
51
|
-
<pc-entity name="right-wall" position="9 1.5 0" scale="0.3 3 18"
|
|
52
|
-
><pc-render type="box" material="wall-material"></pc-render
|
|
53
|
-
><pc-collision type="box" half-extents="0.15 1.5 9"></pc-collision
|
|
54
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
55
|
-
></pc-entity>
|
|
56
|
-
<pc-entity name="blue-crate" position="-2 0.75 -3" scale="1.5 1.5 1.5"
|
|
57
|
-
><pc-render type="box" material="blue-material"></pc-render
|
|
58
|
-
><pc-collision type="box" half-extents="0.75 0.75 0.75"></pc-collision
|
|
59
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
60
|
-
></pc-entity>
|
|
61
|
-
<pc-entity name="green-crate" position="3 0.5 1" scale="2.5 1 1"
|
|
62
|
-
><pc-render type="box" material="green-material"></pc-render
|
|
63
|
-
><pc-collision type="box" half-extents="1.25 0.5 0.5"></pc-collision
|
|
64
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
65
|
-
></pc-entity>
|
|
66
|
-
<pc-entity name="cargo-left-0" position="-5.5 0.75 -5.5" scale="2 1.5 2"
|
|
67
|
-
><pc-render type="box" material="wood-material"></pc-render
|
|
68
|
-
><pc-collision type="box" half-extents="1 0.75 1"></pc-collision
|
|
69
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
70
|
-
></pc-entity>
|
|
71
|
-
<pc-entity name="cargo-left-1" position="-5.5 2 -5.5" scale="1.5 1 1.5"
|
|
72
|
-
><pc-render type="box" material="blue-material"></pc-render
|
|
73
|
-
><pc-collision type="box" half-extents="0.75 0.5 0.75"></pc-collision
|
|
74
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
75
|
-
></pc-entity>
|
|
76
|
-
<pc-entity name="cargo-right-0" position="5.3 0.6 -4.8" scale="2.4 1.2 2"
|
|
77
|
-
><pc-render type="box" material="green-material"></pc-render
|
|
78
|
-
><pc-collision type="box" half-extents="1.2 0.6 1"></pc-collision
|
|
79
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
80
|
-
></pc-entity>
|
|
81
|
-
<pc-entity name="cargo-right-1" position="5.3 1.7 -4.8" scale="1.5 1 1.5"
|
|
82
|
-
><pc-render type="box" material="wood-material"></pc-render
|
|
83
|
-
><pc-collision type="box" half-extents="0.75 0.5 0.75"></pc-collision
|
|
84
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
85
|
-
></pc-entity>
|
|
86
|
-
<pc-entity name="cargo-center" position="0 0.6 -6.5" scale="2.2 1.2 1.8"
|
|
87
|
-
><pc-render type="box" material="blue-material"></pc-render
|
|
88
|
-
><pc-collision type="box" half-extents="1.1 0.6 0.9"></pc-collision
|
|
89
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
90
|
-
></pc-entity>
|
|
91
|
-
<pc-entity name="shelf-left-post-0" position="-6.8 1.4 -3.5" scale="0.25 2.8 0.25"
|
|
92
|
-
><pc-render type="box" material="metal-material"></pc-render
|
|
93
|
-
><pc-collision type="box" half-extents="0.125 1.4 0.125"></pc-collision
|
|
94
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
95
|
-
></pc-entity>
|
|
96
|
-
<pc-entity name="shelf-left-post-1" position="-6.8 1.4 0" scale="0.25 2.8 0.25"
|
|
97
|
-
><pc-render type="box" material="metal-material"></pc-render
|
|
98
|
-
><pc-collision type="box" half-extents="0.125 1.4 0.125"></pc-collision
|
|
99
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
100
|
-
></pc-entity>
|
|
101
|
-
<pc-entity name="shelf-left-post-2" position="-6.8 1.4 3.5" scale="0.25 2.8 0.25"
|
|
102
|
-
><pc-render type="box" material="metal-material"></pc-render
|
|
103
|
-
><pc-collision type="box" half-extents="0.125 1.4 0.125"></pc-collision
|
|
104
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
105
|
-
></pc-entity>
|
|
106
|
-
<pc-entity name="shelf-right-post-0" position="6.8 1.4 -3.5" scale="0.25 2.8 0.25"
|
|
107
|
-
><pc-render type="box" material="metal-material"></pc-render
|
|
108
|
-
><pc-collision type="box" half-extents="0.125 1.4 0.125"></pc-collision
|
|
109
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
110
|
-
></pc-entity>
|
|
111
|
-
<pc-entity name="shelf-right-post-1" position="6.8 1.4 0" scale="0.25 2.8 0.25"
|
|
112
|
-
><pc-render type="box" material="metal-material"></pc-render
|
|
113
|
-
><pc-collision type="box" half-extents="0.125 1.4 0.125"></pc-collision
|
|
114
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
115
|
-
></pc-entity>
|
|
116
|
-
<pc-entity name="shelf-right-post-2" position="6.8 1.4 3.5" scale="0.25 2.8 0.25"
|
|
117
|
-
><pc-render type="box" material="metal-material"></pc-render
|
|
118
|
-
><pc-collision type="box" half-extents="0.125 1.4 0.125"></pc-collision
|
|
119
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
120
|
-
></pc-entity>
|
|
121
|
-
<pc-entity name="shelf-left-low" position="-6.8 0.65 0" scale="1.1 0.18 7.5"
|
|
122
|
-
><pc-render type="box" material="metal-material"></pc-render
|
|
123
|
-
><pc-collision type="box" half-extents="0.55 0.09 3.75"></pc-collision
|
|
124
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
125
|
-
></pc-entity>
|
|
126
|
-
<pc-entity name="shelf-left-high" position="-6.8 2.1 0" scale="1.1 0.18 7.5"
|
|
127
|
-
><pc-render type="box" material="metal-material"></pc-render
|
|
128
|
-
><pc-collision type="box" half-extents="0.55 0.09 3.75"></pc-collision
|
|
129
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
130
|
-
></pc-entity>
|
|
131
|
-
<pc-entity name="shelf-right-low" position="6.8 0.65 0" scale="1.1 0.18 7.5"
|
|
132
|
-
><pc-render type="box" material="metal-material"></pc-render
|
|
133
|
-
><pc-collision type="box" half-extents="0.55 0.09 3.75"></pc-collision
|
|
134
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
135
|
-
></pc-entity>
|
|
136
|
-
<pc-entity name="shelf-right-high" position="6.8 2.1 0" scale="1.1 0.18 7.5"
|
|
137
|
-
><pc-render type="box" material="metal-material"></pc-render
|
|
138
|
-
><pc-collision type="box" half-extents="0.55 0.09 3.75"></pc-collision
|
|
139
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
140
|
-
></pc-entity>
|
|
141
|
-
<pc-entity name="pallet" position="-2.5 0.15 2.5" scale="3 0.3 2"
|
|
142
|
-
><pc-render type="box" material="wood-material"></pc-render
|
|
143
|
-
><pc-collision type="box" half-extents="1.5 0.15 1"></pc-collision
|
|
144
|
-
><pc-rigid-body type="static"></pc-rigid-body
|
|
145
|
-
></pc-entity>
|
|
146
|
-
<pc-entity name="player" position="0 1 5">
|
|
147
|
-
<pc-collision type="capsule" radius="0.45" height="1.8"></pc-collision>
|
|
148
|
-
<pc-rigid-body type="dynamic" mass="80" angular-factor="0 0 0"></pc-rigid-body>
|
|
149
|
-
<pc-entity name="camera" position="0 0.65 0"
|
|
150
|
-
><pc-camera clear-color="#61a3db" fov="80"></pc-camera
|
|
151
|
-
></pc-entity>
|
|
152
|
-
</pc-entity>
|
|
153
|
-
</pc-scene>
|
|
154
|
-
</pc-app>
|
|
155
|
-
<div class="hud">
|
|
156
|
-
<section class="panel">
|
|
157
|
-
<h1>First-Person Controller</h1>
|
|
158
|
-
<p>Click the scene, then use WASD, mouse look and Space to jump.</p>
|
|
159
|
-
</section>
|
|
160
|
-
</div>
|
|
161
|
-
<script type="module" src="/src/main.ts"></script>
|
|
162
|
-
</body>
|
|
163
|
-
</html>
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { EntityElement } from '@playcanvas/web-components';
|
|
2
|
-
import { whenReady } from '@playcanvas/web-components';
|
|
3
|
-
|
|
4
|
-
import { addFirstPersonController } from './controller';
|
|
5
|
-
import './starter.css';
|
|
6
|
-
|
|
7
|
-
await Promise.all([
|
|
8
|
-
whenReady('pc-entity[name="player"] > pc-collision'),
|
|
9
|
-
whenReady('pc-entity[name="player"] > pc-rigid-body')
|
|
10
|
-
]);
|
|
11
|
-
const [player, camera] = await Promise.all([
|
|
12
|
-
whenReady<EntityElement>('pc-entity[name="player"]'),
|
|
13
|
-
whenReady<EntityElement>('pc-entity[name="camera"]')
|
|
14
|
-
]);
|
|
15
|
-
addFirstPersonController(player.entity!, camera.entity!);
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|