wco_models 3.1.0.324 → 3.1.0.326

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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/production_theme.scss +4 -1
  3. data/app/assets/stylesheets/wco/main.scss +4 -0
  4. data/app/assets/stylesheets/wco/studio.scss +12 -4
  5. data/app/controllers/wco/api/newspartials_controller.rb +1 -1
  6. data/app/controllers/wco/api/newsproducer_controller.rb +5 -0
  7. data/app/controllers/wco/newspartials_controller.rb +1 -0
  8. data/app/models/iro/datapoint.rb +1 -1
  9. data/app/models/iro/option.rb +16 -2
  10. data/app/models/iro/position.rb +4 -6
  11. data/app/models/iro/priceitem.rb +42 -4
  12. data/app/models/iro/purse.rb +2 -0
  13. data/app/models/iro/stock.rb +1 -2
  14. data/app/models/tda/option.rb +4 -9
  15. data/app/models/wco/newspartial.rb +12 -4
  16. data/app/views/wco/api/newsproducer/README_newsproducer.txt +12 -0
  17. data/app/views/wco/api/newsproducer/_scenes.js-bk +20 -0
  18. data/app/views/wco/api/newsproducer/_scenes.js.erb +15 -0
  19. data/app/views/wco/api/newsproducer/{_studio_blue.js → _studio_blue1.js} +4 -1
  20. data/app/views/wco/api/newsproducer/_studio_blue2.js +912 -0
  21. data/app/views/wco/api/newsproducer/_studio_coc.js +769 -0
  22. data/app/views/wco/api/newsproducer/_studio_coc.js-bk +389 -0
  23. data/app/views/wco/api/newsproducer/_studio_coc.js-cannon +677 -0
  24. data/app/views/wco/api/newsproducer/_studio_fps.js +1018 -0
  25. data/app/views/wco/api/newsproducer/_studio_ra2.js +255 -0
  26. data/app/views/wco/api/newsproducer/_touch_controls.js +708 -0
  27. data/app/views/wco/api/newsproducer/_touch_pad.css +200 -0
  28. data/app/views/wco/api/newsproducer/games_fps.html +504 -0
  29. data/app/views/wco/api/newsproducer/{studio_green.html.erb → studio_blue0.html.erb} +1 -1
  30. data/app/views/wco/api/newsproducer/{studio_blue.html.erb → studio_blue1.html.erb} +3 -3
  31. data/app/views/wco/api/newsproducer/studio_blue2.html.erb +146 -0
  32. data/app/views/wco/api/newsproducer/studio_coc.html.erb +95 -0
  33. data/app/views/wco/api/newsproducer/studio_fps.html.erb +199 -0
  34. data/app/views/wco/api/newsproducer/studio_ra2.html.erb +95 -0
  35. data/app/views/wco/newspartials/_show_in_newsvideo.haml +6 -7
  36. data/app/views/wco/newspartials/index.haml-trash +6 -0
  37. data/config/initializers/08_integrations.rb +14 -1
  38. data/config/initializers/08_integrations.rb-example +0 -2
  39. data/config/routes.rb +3 -0
  40. data/lib/shortcuts.rb +1 -1
  41. data/lib/tasks/office_tasks.rake +7 -5
  42. metadata +23 -7
  43. data/app/views/wco/api/newsproducer/README.txt +0 -2
  44. /data/app/views/wco/api/newsproducer/{_studio_green.js → _studio_blue0.js} +0 -0
@@ -0,0 +1,200 @@
1
+ .rotation-pad {
2
+ position: absolute;
3
+ display: none;
4
+ z-index: 10;
5
+ pointer-events: none;
6
+ touch-action: none;
7
+ }
8
+
9
+ .rotation-pad.is-active {
10
+ display: block;
11
+ }
12
+
13
+ .rotation-pad .region {
14
+ position: relative;
15
+ z-index: 2;
16
+ touch-action: none;
17
+ width: 100px;
18
+ height: 100px;
19
+ background: radial-gradient(rgba(218, 225, 230, 0.25) 5%, rgba(218, 225, 230, 0.50) 95%),
20
+ url("/vendor/TouchControls/images/cam.png") center center no-repeat;
21
+ border: 2px solid rgba(218, 225, 230, 0.25);
22
+ border-radius: 90px;
23
+ box-shadow: 0px 0px 5px rgba(194, 200, 204, 0.55);
24
+ -webkit-user-select: none;
25
+ }
26
+
27
+ .rotation-pad .handle {
28
+ z-index: 1;
29
+ pointer-events: none;
30
+ opacity: 0.7;
31
+ position: absolute;
32
+ height: 30px;
33
+ width: 30px;
34
+ top: 50%;
35
+ left: 50%;
36
+ margin: -15px 0 0 -15px;
37
+ background: radial-gradient(rgba(215, 225, 255, 0.70) 0%, rgba(215, 225, 255, 0.50) 100%);
38
+ /*border: 1px solid rgba(145, 105, 245, 0.90);*/
39
+ border-radius: 50%;
40
+ box-shadow: 0px 0px 7px rgba(195, 205, 245, 0.9);
41
+ text-align: center;
42
+ font: 24px/44px"Courier New", Courier, monospace;
43
+ -webkit-user-select: none;
44
+ }
45
+
46
+ .movement-pad {
47
+ position: absolute;
48
+ bottom: 10px;
49
+ left: 20px;
50
+ z-index: 10;
51
+ touch-action: none;
52
+ }
53
+
54
+ .movement-pad .region {
55
+ position: relative;
56
+ z-index: 2;
57
+ touch-action: none;
58
+ width: 100px;
59
+ height: 100px;
60
+ background: radial-gradient(rgba(218, 225, 230, 0.25) 5%, rgba(218, 225, 230, 0.50) 95%),
61
+ url("/vendor/TouchControls/images/nav.png") center center no-repeat;
62
+ border: 2px solid rgba(218, 225, 230, 0.25);
63
+ border-radius: 90px;
64
+ box-shadow: 0px 0px 5px rgba(194, 200, 204, 0.55);
65
+ -webkit-user-select: none;
66
+ }
67
+
68
+ .movement-pad .handle {
69
+ z-index: 1;
70
+ pointer-events: none;
71
+ opacity: 0.1;
72
+ position: absolute;
73
+ height: 30px;
74
+ width: 30px;
75
+ top: 0px;
76
+ left: 0px;
77
+ background: radial-gradient(rgba(215, 225, 255, 0.70) 0%, rgba(215, 225, 255, 0.50) 100%);
78
+ /*border: 1px solid rgba(145, 105, 245, 0.90);*/
79
+ border-radius: 50%;
80
+ box-shadow: 0px 0px 7px rgba(195, 205, 245, 0.9);
81
+ text-align: center;
82
+ font: 24px/44px"Courier New", Courier, monospace;
83
+ -webkit-user-select: none;
84
+ }
85
+
86
+ .btn {
87
+ display: inline-block;
88
+ padding: 6px 12px;
89
+ margin-bottom: 0;
90
+ font-size: 14px;
91
+ font-weight: normal;
92
+ line-height: 1.428571429;
93
+ text-align: center;
94
+ white-space: nowrap;
95
+ vertical-align: middle;
96
+ cursor: pointer;
97
+ background-image: none;
98
+ border: 1px solid transparent;
99
+ border-radius: 4px;
100
+ -webkit-user-select: none;
101
+ -moz-user-select: none;
102
+ -ms-user-select: none;
103
+ -o-user-select: none;
104
+ user-select: none;
105
+ }
106
+
107
+ .btn:focus {
108
+ outline: thin dotted;
109
+ outline: 5px auto -webkit-focus-ring-color;
110
+ outline-offset: -2px;
111
+ }
112
+
113
+ .btn:hover,
114
+ .btn:focus {
115
+ color: #333333;
116
+ text-decoration: none;
117
+ }
118
+
119
+ .btn:active,
120
+ .btn.active {
121
+ background-image: none;
122
+ outline: 0;
123
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
124
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
125
+ }
126
+
127
+ .btn-default {
128
+ text-shadow: 0 1px 0 #fff;
129
+ background-image: -webkit-linear-gradient(top, #f2f2f2 0%, #acbfce 100%);
130
+ background-image: linear-gradient(to bottom, #f2f2f2 0%, #acbfce 100%);
131
+ background-repeat: repeat-x;
132
+ border-color: #ccc;
133
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffacbfce', GradientType=0);
134
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
135
+ }
136
+
137
+ .btn-default:hover,
138
+ .btn-default:focus {
139
+ background-color: #acbfce;
140
+ background-position: 0 -15px;
141
+ }
142
+
143
+ .btn-default:active,
144
+ .btn-default.active {
145
+ background-color: #acbfce;
146
+ border-color: #9a9a9a;
147
+ }
148
+
149
+
150
+
151
+ .navpad {
152
+ position: absolute;
153
+ bottom: 4px;
154
+ text-align: center;
155
+ z-index: 99;
156
+ /*border: 1px solid blue;*/
157
+ }
158
+
159
+ .navpad.rotation-handle {
160
+ cursor: pointer;
161
+ /*border: 1px solid red;*/
162
+ /*opacity: 0.6;*/
163
+ }
164
+
165
+ .navKey {
166
+ direction: ltr;
167
+ position: absolute;
168
+ width: 100px;
169
+ text-align: center;
170
+ vertical-align: middle;
171
+ /*border: 1px solid red;*/
172
+ }
173
+
174
+ .navKey button {
175
+ width: 30px;
176
+ height: 30px;
177
+ padding: 0;
178
+ font-family: monospace, "Century Gothic", sans;
179
+ font-size: 12px;
180
+ border-radius: 2px;
181
+ }
182
+
183
+ .navKey button>span {
184
+ font-family: "Tahoma";
185
+ font-size: 11px;
186
+ vertical-align: super;
187
+ margin: 0 -4px 0 -2px;
188
+ }
189
+
190
+ .navKey div:first-child {
191
+ margin: 0 1px 3px 1px;
192
+ /*border: 1px solid blue;*/
193
+ }
194
+
195
+ .navKey div:nth-child(2) button {
196
+
197
+ margin: 0 1px 0 1px;
198
+ /*padding: 0;*/
199
+ /*border: 1px solid green;*/
200
+ }
@@ -0,0 +1,504 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <title>three.js - misc - octree collisions</title>
5
+ <meta charset=utf-8 />
6
+ <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
7
+ <meta property="og:title" content="three.js - misc - octree collisions">
8
+ <meta property="og:type" content="website">
9
+ <meta property="og:url" content="https://threejs.org/examples/games_fps.html">
10
+ <meta property="og:image" content="https://threejs.org/examples/screenshots/games_fps.jpg">
11
+ <link type="text/css" rel="stylesheet" href="main.css">
12
+ </head>
13
+ <body>
14
+ <div id="info">
15
+ Octree threejs demo - basic collisions with static triangle mesh<br />
16
+ MOUSE to look around and to throw balls<br/>
17
+ WASD to move and SPACE to jump
18
+ </div>
19
+ <div id="container"></div>
20
+
21
+ <script type="importmap">
22
+ {
23
+ "imports": {
24
+ "three": "../build/three.module.js",
25
+ "three/addons/": "./jsm/"
26
+ }
27
+ }
28
+ </script>
29
+
30
+ <script type="module">
31
+
32
+ import * as THREE from 'three';
33
+
34
+ import Stats from 'three/addons/libs/stats.module.js';
35
+
36
+ import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
37
+
38
+ import { Octree } from 'three/addons/math/Octree.js';
39
+ import { OctreeHelper } from 'three/addons/helpers/OctreeHelper.js';
40
+
41
+ import { Capsule } from 'three/addons/math/Capsule.js';
42
+
43
+ import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
44
+
45
+ const timer = new THREE.Timer();
46
+ timer.connect( document );
47
+
48
+ const scene = new THREE.Scene();
49
+ scene.background = new THREE.Color( 0x88ccee );
50
+ scene.fog = new THREE.Fog( 0x88ccee, 0, 50 );
51
+
52
+ const camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.1, 1000 );
53
+ camera.rotation.order = 'YXZ';
54
+
55
+ const fillLight1 = new THREE.HemisphereLight( 0x8dc1de, 0x00668d, 1.5 );
56
+ fillLight1.position.set( 2, 1, 1 );
57
+ scene.add( fillLight1 );
58
+
59
+ const directionalLight = new THREE.DirectionalLight( 0xffffff, 2.5 );
60
+ directionalLight.position.set( - 5, 25, - 1 );
61
+ directionalLight.castShadow = true;
62
+ directionalLight.shadow.camera.near = 0.01;
63
+ directionalLight.shadow.camera.far = 500;
64
+ directionalLight.shadow.camera.right = 30;
65
+ directionalLight.shadow.camera.left = - 30;
66
+ directionalLight.shadow.camera.top = 30;
67
+ directionalLight.shadow.camera.bottom = - 30;
68
+ directionalLight.shadow.mapSize.width = 1024;
69
+ directionalLight.shadow.mapSize.height = 1024;
70
+ directionalLight.shadow.radius = 4;
71
+ directionalLight.shadow.bias = - 0.00006;
72
+ scene.add( directionalLight );
73
+
74
+ const container = document.getElementById( 'container' );
75
+
76
+ const renderer = new THREE.WebGLRenderer( { antialias: true } );
77
+ renderer.setPixelRatio( window.devicePixelRatio );
78
+ renderer.setSize( window.innerWidth, window.innerHeight );
79
+ renderer.setAnimationLoop( animate );
80
+ renderer.shadowMap.enabled = true;
81
+ renderer.shadowMap.type = THREE.VSMShadowMap;
82
+ renderer.toneMapping = THREE.ACESFilmicToneMapping;
83
+ container.appendChild( renderer.domElement );
84
+
85
+ const stats = new Stats();
86
+ stats.domElement.style.position = 'absolute';
87
+ stats.domElement.style.top = '0px';
88
+ container.appendChild( stats.domElement );
89
+
90
+ const GRAVITY = 30;
91
+
92
+ const NUM_SPHERES = 100;
93
+ const SPHERE_RADIUS = 0.2;
94
+
95
+ const STEPS_PER_FRAME = 5;
96
+
97
+ const sphereGeometry = new THREE.IcosahedronGeometry( SPHERE_RADIUS, 5 );
98
+ const sphereMaterial = new THREE.MeshLambertMaterial( { color: 0xdede8d } );
99
+
100
+ const spheres = [];
101
+ let sphereIdx = 0;
102
+
103
+ for ( let i = 0; i < NUM_SPHERES; i ++ ) {
104
+
105
+ const sphere = new THREE.Mesh( sphereGeometry, sphereMaterial );
106
+ sphere.castShadow = true;
107
+ sphere.receiveShadow = true;
108
+
109
+ scene.add( sphere );
110
+
111
+ spheres.push( {
112
+ mesh: sphere,
113
+ collider: new THREE.Sphere( new THREE.Vector3( 0, - 100, 0 ), SPHERE_RADIUS ),
114
+ velocity: new THREE.Vector3()
115
+ } );
116
+
117
+ }
118
+
119
+ const worldOctree = new Octree();
120
+
121
+ const playerCollider = new Capsule( new THREE.Vector3( 0, 0.35, 0 ), new THREE.Vector3( 0, 1, 0 ), 0.35 );
122
+
123
+ const playerVelocity = new THREE.Vector3();
124
+ const playerDirection = new THREE.Vector3();
125
+
126
+ let playerOnFloor = false;
127
+ let mouseTime = 0;
128
+
129
+ const keyStates = {};
130
+
131
+ const vector1 = new THREE.Vector3();
132
+ const vector2 = new THREE.Vector3();
133
+ const vector3 = new THREE.Vector3();
134
+
135
+ document.addEventListener( 'keydown', ( event ) => {
136
+
137
+ keyStates[ event.code ] = true;
138
+
139
+ } );
140
+
141
+ document.addEventListener( 'keyup', ( event ) => {
142
+
143
+ keyStates[ event.code ] = false;
144
+
145
+ } );
146
+
147
+ container.addEventListener( 'mousedown', () => {
148
+
149
+ document.body.requestPointerLock();
150
+
151
+ mouseTime = performance.now();
152
+
153
+ } );
154
+
155
+ document.addEventListener( 'mouseup', () => {
156
+
157
+ if ( document.pointerLockElement !== null ) throwBall();
158
+
159
+ } );
160
+
161
+ document.body.addEventListener( 'mousemove', ( event ) => {
162
+
163
+ if ( document.pointerLockElement === document.body ) {
164
+
165
+ camera.rotation.y -= event.movementX / 500;
166
+ camera.rotation.x -= event.movementY / 500;
167
+
168
+ }
169
+
170
+ } );
171
+
172
+ window.addEventListener( 'resize', onWindowResize );
173
+
174
+ function onWindowResize() {
175
+
176
+ camera.aspect = window.innerWidth / window.innerHeight;
177
+ camera.updateProjectionMatrix();
178
+
179
+ renderer.setSize( window.innerWidth, window.innerHeight );
180
+
181
+ }
182
+
183
+ function throwBall() {
184
+
185
+ const sphere = spheres[ sphereIdx ];
186
+
187
+ camera.getWorldDirection( playerDirection );
188
+
189
+ sphere.collider.center.copy( playerCollider.end ).addScaledVector( playerDirection, playerCollider.radius * 1.5 );
190
+
191
+ // throw the ball with more force if we hold the button longer, and if we move forward
192
+
193
+ const impulse = 15 + 30 * ( 1 - Math.exp( ( mouseTime - performance.now() ) * 0.001 ) );
194
+
195
+ sphere.velocity.copy( playerDirection ).multiplyScalar( impulse );
196
+ sphere.velocity.addScaledVector( playerVelocity, 2 );
197
+
198
+ sphereIdx = ( sphereIdx + 1 ) % spheres.length;
199
+
200
+ }
201
+
202
+ function playerCollisions() {
203
+
204
+ const result = worldOctree.capsuleIntersect( playerCollider );
205
+
206
+ playerOnFloor = false;
207
+
208
+ if ( result ) {
209
+
210
+ // determine if the surface we bumped into is something we can stand on
211
+
212
+ playerOnFloor = result.normal.y >= 0.15; // allow slopes up to ~81° but ignore sheer vertical walls
213
+
214
+ if ( ! playerOnFloor ) {
215
+
216
+ playerVelocity.addScaledVector( result.normal, - result.normal.dot( playerVelocity ) );
217
+
218
+ }
219
+
220
+ if ( result.depth >= 1e-10 ) {
221
+
222
+ playerCollider.translate( result.normal.multiplyScalar( result.depth ) );
223
+
224
+ }
225
+
226
+ }
227
+
228
+ }
229
+
230
+ function updatePlayer( deltaTime ) {
231
+
232
+ let damping = Math.exp( - 4 * deltaTime ) - 1;
233
+
234
+ if ( ! playerOnFloor ) {
235
+
236
+ playerVelocity.y -= GRAVITY * deltaTime;
237
+
238
+ // small air resistance
239
+ damping *= 0.1;
240
+
241
+ }
242
+
243
+ playerVelocity.addScaledVector( playerVelocity, damping );
244
+
245
+ const deltaPosition = playerVelocity.clone().multiplyScalar( deltaTime );
246
+ playerCollider.translate( deltaPosition );
247
+
248
+ playerCollisions();
249
+
250
+ camera.position.copy( playerCollider.end );
251
+
252
+ }
253
+
254
+ function playerSphereCollision( sphere ) {
255
+
256
+ const center = vector1.addVectors( playerCollider.start, playerCollider.end ).multiplyScalar( 0.5 );
257
+
258
+ const sphere_center = sphere.collider.center;
259
+
260
+ const r = playerCollider.radius + sphere.collider.radius;
261
+ const r2 = r * r;
262
+
263
+ // approximation: player = 3 spheres
264
+
265
+ for ( const point of [ playerCollider.start, playerCollider.end, center ] ) {
266
+
267
+ const d2 = point.distanceToSquared( sphere_center );
268
+
269
+ if ( d2 < r2 ) {
270
+
271
+ const normal = vector1.subVectors( point, sphere_center ).normalize();
272
+ const v1 = vector2.copy( normal ).multiplyScalar( normal.dot( playerVelocity ) );
273
+ const v2 = vector3.copy( normal ).multiplyScalar( normal.dot( sphere.velocity ) );
274
+
275
+ playerVelocity.add( v2 ).sub( v1 );
276
+ sphere.velocity.add( v1 ).sub( v2 );
277
+
278
+ const d = ( r - Math.sqrt( d2 ) ) / 2;
279
+ sphere_center.addScaledVector( normal, - d );
280
+
281
+ }
282
+
283
+ }
284
+
285
+ }
286
+
287
+ function spheresCollisions() {
288
+
289
+ for ( let i = 0, length = spheres.length; i < length; i ++ ) {
290
+
291
+ const s1 = spheres[ i ];
292
+
293
+ for ( let j = i + 1; j < length; j ++ ) {
294
+
295
+ const s2 = spheres[ j ];
296
+
297
+ const d2 = s1.collider.center.distanceToSquared( s2.collider.center );
298
+ const r = s1.collider.radius + s2.collider.radius;
299
+ const r2 = r * r;
300
+
301
+ if ( d2 < r2 ) {
302
+
303
+ const normal = vector1.subVectors( s1.collider.center, s2.collider.center ).normalize();
304
+ const v1 = vector2.copy( normal ).multiplyScalar( normal.dot( s1.velocity ) );
305
+ const v2 = vector3.copy( normal ).multiplyScalar( normal.dot( s2.velocity ) );
306
+
307
+ s1.velocity.add( v2 ).sub( v1 );
308
+ s2.velocity.add( v1 ).sub( v2 );
309
+
310
+ const d = ( r - Math.sqrt( d2 ) ) / 2;
311
+
312
+ s1.collider.center.addScaledVector( normal, d );
313
+ s2.collider.center.addScaledVector( normal, - d );
314
+
315
+ }
316
+
317
+ }
318
+
319
+ }
320
+
321
+ }
322
+
323
+ function updateSpheres( deltaTime ) {
324
+
325
+ spheres.forEach( sphere => {
326
+
327
+ sphere.collider.center.addScaledVector( sphere.velocity, deltaTime );
328
+
329
+ const result = worldOctree.sphereIntersect( sphere.collider );
330
+
331
+ if ( result ) {
332
+
333
+ sphere.velocity.addScaledVector( result.normal, - result.normal.dot( sphere.velocity ) * 1.5 );
334
+ sphere.collider.center.add( result.normal.multiplyScalar( result.depth ) );
335
+
336
+ } else {
337
+
338
+ sphere.velocity.y -= GRAVITY * deltaTime;
339
+
340
+ }
341
+
342
+ const damping = Math.exp( - 1.5 * deltaTime ) - 1;
343
+ sphere.velocity.addScaledVector( sphere.velocity, damping );
344
+
345
+ playerSphereCollision( sphere );
346
+
347
+ } );
348
+
349
+ spheresCollisions();
350
+
351
+ for ( const sphere of spheres ) {
352
+
353
+ sphere.mesh.position.copy( sphere.collider.center );
354
+
355
+ }
356
+
357
+ }
358
+
359
+ function getForwardVector() {
360
+
361
+ camera.getWorldDirection( playerDirection );
362
+ playerDirection.y = 0;
363
+ playerDirection.normalize();
364
+
365
+ return playerDirection;
366
+
367
+ }
368
+
369
+ function getSideVector() {
370
+
371
+ camera.getWorldDirection( playerDirection );
372
+ playerDirection.y = 0;
373
+ playerDirection.normalize();
374
+ playerDirection.cross( camera.up );
375
+
376
+ return playerDirection;
377
+
378
+ }
379
+
380
+ function controls( deltaTime ) {
381
+
382
+ // gives a bit of air control
383
+ const speedDelta = deltaTime * ( playerOnFloor ? 25 : 8 );
384
+
385
+ if ( keyStates[ 'KeyW' ] ) {
386
+
387
+ playerVelocity.add( getForwardVector().multiplyScalar( speedDelta ) );
388
+
389
+ }
390
+
391
+ if ( keyStates[ 'KeyS' ] ) {
392
+
393
+ playerVelocity.add( getForwardVector().multiplyScalar( - speedDelta ) );
394
+
395
+ }
396
+
397
+ if ( keyStates[ 'KeyA' ] ) {
398
+
399
+ playerVelocity.add( getSideVector().multiplyScalar( - speedDelta ) );
400
+
401
+ }
402
+
403
+ if ( keyStates[ 'KeyD' ] ) {
404
+
405
+ playerVelocity.add( getSideVector().multiplyScalar( speedDelta ) );
406
+
407
+ }
408
+
409
+ if ( playerOnFloor ) {
410
+
411
+ if ( keyStates[ 'Space' ] ) {
412
+
413
+ playerVelocity.y = 15;
414
+
415
+ }
416
+
417
+ }
418
+
419
+ }
420
+
421
+ const loader = new GLTFLoader().setPath( './models/gltf/' );
422
+
423
+ loader.load( 'collision-world.glb', ( gltf ) => {
424
+
425
+ scene.add( gltf.scene );
426
+
427
+ worldOctree.fromGraphNode( gltf.scene );
428
+
429
+ gltf.scene.traverse( child => {
430
+
431
+ if ( child.isMesh ) {
432
+
433
+ child.castShadow = true;
434
+ child.receiveShadow = true;
435
+
436
+ if ( child.material.map ) {
437
+
438
+ child.material.map.anisotropy = 4;
439
+
440
+ }
441
+
442
+ }
443
+
444
+ } );
445
+
446
+ const helper = new OctreeHelper( worldOctree );
447
+ helper.visible = false;
448
+ scene.add( helper );
449
+
450
+ const gui = new GUI( { width: 200 } );
451
+ gui.add( { debug: false }, 'debug' )
452
+ .onChange( function ( value ) {
453
+
454
+ helper.visible = value;
455
+
456
+ } );
457
+
458
+ } );
459
+
460
+ function teleportPlayerIfOob() {
461
+
462
+ if ( camera.position.y <= - 25 ) {
463
+
464
+ playerCollider.start.set( 0, 0.35, 0 );
465
+ playerCollider.end.set( 0, 1, 0 );
466
+ playerCollider.radius = 0.35;
467
+ camera.position.copy( playerCollider.end );
468
+ camera.rotation.set( 0, 0, 0 );
469
+
470
+ }
471
+
472
+ }
473
+
474
+
475
+ function animate() {
476
+
477
+ timer.update();
478
+
479
+ const deltaTime = Math.min( 0.05, timer.getDelta() ) / STEPS_PER_FRAME;
480
+
481
+ // we look for collisions in substeps to mitigate the risk of
482
+ // an object traversing another too quickly for detection.
483
+
484
+ for ( let i = 0; i < STEPS_PER_FRAME; i ++ ) {
485
+
486
+ controls( deltaTime );
487
+
488
+ updatePlayer( deltaTime );
489
+
490
+ updateSpheres( deltaTime );
491
+
492
+ teleportPlayerIfOob();
493
+
494
+ }
495
+
496
+ renderer.render( scene, camera );
497
+
498
+ stats.update();
499
+
500
+ }
501
+
502
+ </script>
503
+ </body>
504
+ </html>
@@ -24,4 +24,4 @@ Status:<span id='status'>pending</span>
24
24
  text-align: center; " >
25
25
  </div>
26
26
 
27
- <script type="module"><%= render 'studio_green.js' %></script>
27
+ <script type="module"><%= render 'studio_blue0.js' %></script>