1- import { deviceType , rootPath } from 'examples/utils' ;
1+ // @config DESCRIPTION <div style='text-align:center'><div>(<b>WASDQE</b>) Move</div></div>
2+ import { data } from 'examples/observer' ;
3+ import { deviceType , rootPath , fileImport } from 'examples/utils' ;
24import * as pc from 'playcanvas' ;
35
4- const canvas = /** @type {HTMLCanvasElement } */ ( document . getElementById ( 'application-canvas' ) ) ;
6+ const { CameraControls } = await fileImport ( `${ rootPath } /static/scripts/camera-controls.mjs` ) ;
7+
8+ const canvas = document . getElementById ( 'application-canvas' ) ;
9+ if ( ! ( canvas instanceof HTMLCanvasElement ) ) {
10+ throw new Error ( 'No canvas found' ) ;
11+ }
512window . focus ( ) ;
613
714const gfxOptions = {
@@ -10,21 +17,29 @@ const gfxOptions = {
1017 twgslUrl : `${ rootPath } /static/lib/twgsl/twgsl.js`
1118} ;
1219
20+ const assets = {
21+ helipad : new pc . Asset (
22+ 'helipad-env-atlas' ,
23+ 'texture' ,
24+ { url : `${ rootPath } /static/assets/cubemaps/helipad-env-atlas.png` } ,
25+ { type : pc . TEXTURETYPE_RGBP , mipmaps : false }
26+ ) ,
27+ statue : new pc . Asset ( 'statue' , 'container' , { url : `${ rootPath } /static/assets/models/statue.glb` } )
28+ } ;
29+
1330const device = await pc . createGraphicsDevice ( canvas , gfxOptions ) ;
1431device . maxPixelRatio = Math . min ( window . devicePixelRatio , 2 ) ;
1532
1633const createOptions = new pc . AppOptions ( ) ;
1734createOptions . graphicsDevice = device ;
18- createOptions . mouse = new pc . Mouse ( document . body ) ;
19- createOptions . keyboard = new pc . Keyboard ( window ) ;
2035
2136createOptions . componentSystems = [
2237 pc . RenderComponentSystem ,
2338 pc . CameraComponentSystem ,
2439 pc . LightComponentSystem ,
2540 pc . ScriptComponentSystem
2641] ;
27- createOptions . resourceHandlers = [ pc . ScriptHandler ] ;
42+ createOptions . resourceHandlers = [ pc . TextureHandler , pc . ContainerHandler , pc . ScriptHandler ] ;
2843
2944const app = new pc . AppBase ( canvas ) ;
3045app . init ( createOptions ) ;
@@ -40,105 +55,112 @@ app.on('destroy', () => {
4055 window . removeEventListener ( 'resize' , resize ) ;
4156} ) ;
4257
43- const assets = {
44- script : new pc . Asset ( 'script' , 'script' , { url : ` ${ rootPath } /static/scripts/camera/fly-camera.js` } )
45- } ;
58+ await new Promise ( ( resolve ) => {
59+ new pc . AssetListLoader ( Object . values ( assets ) , app . assets ) . load ( resolve ) ;
60+ } ) ;
4661
4762/**
48- * @param {pc.Asset[] | number[] } assetList - The asset list.
49- * @param {pc.AssetRegistry } assetRegistry - The asset registry.
50- * @returns {Promise<void> } The promise.
63+ * Calculate the bounding box of an entity.
64+ *
65+ * @param {pc.BoundingBox } bbox - The bounding box.
66+ * @param {pc.Entity } entity - The entity.
67+ * @returns {pc.BoundingBox } The bounding box.
5168 */
52- function loadAssets ( assetList , assetRegistry ) {
53- return new Promise ( ( resolve ) => {
54- const assetListLoader = new pc . AssetListLoader ( assetList , assetRegistry ) ;
55- assetListLoader . load ( resolve ) ;
69+ const calcEntityAABB = ( bbox , entity ) => {
70+ bbox . center . set ( 0 , 0 , 0 ) ;
71+ bbox . halfExtents . set ( 0 , 0 , 0 ) ;
72+ entity . findComponents ( 'render' ) . forEach ( ( render ) => {
73+ render . meshInstances . forEach ( ( /** @type {pc.MeshInstance } */ mi ) => {
74+ bbox . add ( mi . aabb ) ;
75+ } ) ;
5676 } ) ;
57- }
58- await loadAssets ( Object . values ( assets ) , app . assets ) ;
59- app . scene . ambientLight = new pc . Color ( 0.2 , 0.2 , 0.2 ) ;
60- app . start ( ) ;
61-
62- // *********** Helper functions *******************
63- /**
64- * @param {pc.Color } color - The color.
65- * @returns {pc.StandardMaterial } The material.
66- */
67- function createMaterial ( color ) {
68- const material = new pc . StandardMaterial ( ) ;
69- material . diffuse = color ;
70- // we need to call material.update when we change its properties
71- material . update ( ) ;
72- return material ;
73- }
77+ return bbox ;
78+ } ;
7479
7580/**
76- * @param {pc.Vec3 } position - The position.
77- * @param {pc.Vec3 } size - The size.
78- * @param {pc.Material } material - The material.
81+ * @param {pc.Entity } focus - The entity to focus the camera on.
82+ * @returns {CameraControls } The camera-controls script.
7983 */
80- function createBox ( position , size , material ) {
81- // create an entity and add a model component of type 'box'
82- const box = new pc . Entity ( ) ;
83- box . addComponent ( 'render' , {
84- type : 'box' ,
85- material : material
84+ const createFlyCamera = ( focus ) => {
85+ const camera = new pc . Entity ( ) ;
86+ camera . addComponent ( 'camera' ) ;
87+ camera . addComponent ( 'script' ) ;
88+ camera . setPosition ( 0 , 20 , 30 ) ;
89+ app . root . addChild ( camera ) ;
90+
91+ const bbox = calcEntityAABB ( new pc . BoundingBox ( ) , focus ) ;
92+
93+ /** @type {CameraControls } */
94+ const script = camera . script . create ( CameraControls , {
95+ attributes : {
96+ enableOrbit : false ,
97+ enablePan : false ,
98+ focusPoint : bbox . center ,
99+ sceneSize : bbox . halfExtents . length ( ) ,
100+ pitchRange : new pc . Vec2 ( - 90 , 90 )
101+ }
86102 } ) ;
87103
88- // move the box
89- box . setLocalPosition ( position ) ;
90- box . setLocalScale ( size ) ;
91-
92- // add the box to the hierarchy
93- app . root . addChild ( box ) ;
94- }
95-
96- // *********** Create Boxes *******************
104+ return script ;
105+ } ;
97106
98- // create a few boxes in our scene
99- const red = createMaterial ( pc . Color . RED ) ;
100- for ( let i = 0 ; i < 3 ; i ++ ) {
101- for ( let j = 0 ; j < 2 ; j ++ ) {
102- createBox ( new pc . Vec3 ( i * 2 , 0 , j * 4 ) , pc . Vec3 . ONE , red ) ;
103- }
104- }
107+ app . start ( ) ;
105108
106- // create a floor
107- const white = createMaterial ( pc . Color . WHITE ) ;
108- createBox ( new pc . Vec3 ( 0 , - 0.5 , 0 ) , new pc . Vec3 ( 10 , 0.1 , 10 ) , white ) ;
109+ app . scene . ambientLight . set ( 0.4 , 0.4 , 0.4 ) ;
109110
110- // *********** Create lights *******************
111+ app . scene . skyboxMip = 1 ;
112+ app . scene . skyboxIntensity = 0.4 ;
113+ app . scene . envAtlas = assets . helipad . resource ;
111114
112- // make our scene prettier by adding a directional light
115+ // Create a directional light
113116const light = new pc . Entity ( ) ;
114- light . addComponent ( 'light' , {
115- type : 'omni' ,
116- color : new pc . Color ( 1 , 1 , 1 ) ,
117- range : 100
118- } ) ;
119- light . setLocalPosition ( 0 , 0 , 2 ) ;
120-
121- // add the light to the hierarchy
117+ light . addComponent ( 'light' ) ;
118+ light . setLocalEulerAngles ( 45 , 30 , 0 ) ;
122119app . root . addChild ( light ) ;
123120
124- // *********** Create camera *******************
125-
126- // Create an Entity with a camera component
127- const camera = new pc . Entity ( ) ;
128- camera . addComponent ( 'camera' , {
129- clearColor : new pc . Color ( 0.5 , 0.5 , 0.8 ) ,
130- nearClip : 0.3 ,
131- farClip : 30
132- } ) ;
121+ const statue = assets . statue . resource . instantiateRenderEntity ( ) ;
122+ statue . setLocalPosition ( 0 , - 0.5 , 0 ) ;
123+ app . root . addChild ( statue ) ;
124+
125+ const multiCameraScript = createFlyCamera ( statue ) ;
126+
127+ data . set ( 'attr' , [
128+ 'lookSensitivity' ,
129+ 'lookDamping' ,
130+ 'moveDamping' ,
131+ 'pitchRange' ,
132+ 'moveSpeed' ,
133+ 'sprintSpeed' ,
134+ 'crouchSpeed'
135+ ] . reduce ( ( /** @type {Record<string, any> } */ obj , key ) => {
136+ const value = multiCameraScript [ key ] ;
137+
138+ if ( value instanceof pc . Vec2 ) {
139+ obj [ key ] = [ value . x , value . y ] ;
140+ return obj ;
141+ }
133142
134- // add the fly camera script to the camera
135- camera . addComponent ( 'script' ) ;
136- camera . script . create ( 'flyCamera' ) ;
143+ obj [ key ] = multiCameraScript [ key ] ;
144+ return obj ;
145+ } , { } ) ) ;
137146
138- // add the camera to the hierarchy
139- app . root . addChild ( camera ) ;
147+ const tmpVa = new pc . Vec2 ( ) ;
148+ data . on ( '*:set' , ( /** @type {string } */ path , /** @type {any } */ value ) => {
149+ const [ category , key , index ] = path . split ( '.' ) ;
150+ if ( category !== 'attr' ) {
151+ return ;
152+ }
140153
141- // Move the camera a little further away
142- camera . translate ( 2 , 0.8 , 9 ) ;
154+ if ( Array . isArray ( value ) ) {
155+ multiCameraScript [ key ] = tmpVa . set ( value [ 0 ] , value [ 1 ] ) ;
156+ return ;
157+ }
158+ if ( index !== undefined ) {
159+ const arr = data . get ( `${ category } .${ key } ` ) ;
160+ multiCameraScript [ key ] = tmpVa . set ( arr [ 0 ] , arr [ 1 ] ) ;
161+ return ;
162+ }
163+ multiCameraScript [ key ] = value ;
164+ } ) ;
143165
144166export { app } ;
0 commit comments