1
+ import * as THREE from 'three' ;
2
+ import { PointerLockControls } from 'three/examples/jsm/controls/PointerLockControls.js' ;
3
+ import { WebGPURenderer } from './WebGPURenderer.js' ;
4
+ import * as CANNON from 'cannon-es' ;
5
+ import Stats from 'three/examples/jsm/libs/stats.module.js' ;
6
+ var isGameRunning = false ; // Track if the game is running
7
+ var paused = false ; // Track if the game is paused
8
+
9
+ document . addEventListener ( 'DOMContentLoaded' , function ( ) {
10
+ var mainButton = document . getElementById ( 'mainButton' ) ;
11
+ if ( mainButton ) {
12
+ mainButton . onclick = function ( ) {
13
+ if ( isGameRunning ) {
14
+ resumeGame ( ) ; // Resume the game if already started and paused
15
+ } else {
16
+ startGame ( ) ; // Start the game for the first time
17
+ }
18
+ } ;
19
+ } else {
20
+ console . error ( "Main button not found!" ) ;
21
+ }
22
+ } ) ;
23
+ function startGame ( ) {
24
+ controls . lock ( ) ; // Lock the pointer for the first time
25
+ isGameRunning = true ;
26
+ paused = false ;
27
+ document . getElementById ( 'mainButton' ) . innerText = 'Resume Game' ; // Change button to 'Resume Game' after start
28
+ document . getElementById ( 'menu' ) . style . display = 'none' ; // Hide the menu
29
+ animate ( ) ; // Start the game animation loop
30
+ }
31
+ function resumeGame ( ) {
32
+ controls . lock ( ) ; // Lock the pointer again to resume
33
+ paused = false ;
34
+ document . getElementById ( 'menu' ) . style . display = 'none' ; // Hide the menu
35
+ animate ( ) ; // Resume the animation loop
36
+ }
37
+ function pauseGame ( ) {
38
+ paused = true ;
39
+ document . getElementById ( 'menu' ) . style . display = 'block' ; // Show the menu when paused
40
+ }
41
+ var scene = new THREE . Scene ( ) ;
42
+
43
+ // Replace WebGLRenderer with WebGPURenderer
44
+ var renderer = new WebGPURenderer ( {
45
+ antialias : true
46
+ } ) ;
47
+ renderer . setSize ( window . innerWidth , window . innerHeight ) ;
48
+ renderer . shadowMap . enabled = true ;
49
+ document . body . appendChild ( renderer . domElement ) ;
50
+
51
+ // FPS Counter (Stats.js)
52
+ var stats = new Stats ( ) ;
53
+ document . body . appendChild ( stats . dom ) ;
54
+ var camera = new THREE . PerspectiveCamera ( 75 , window . innerWidth / window . innerHeight , 0.1 , 1000 ) ;
55
+ camera . position . set ( 0 , 1.8 , 5 ) ;
56
+ var controls = new PointerLockControls ( camera , document . body ) ;
57
+ document . body . addEventListener ( 'click' , function ( ) {
58
+ if ( ! isGameRunning ) return ; // Prevent locking controls before the game starts
59
+ controls . lock ( ) ;
60
+ } ) ;
61
+ controls . addEventListener ( 'lock' , function ( ) {
62
+ if ( ! paused ) document . getElementById ( 'menu' ) . style . display = 'none' ; // Hide the menu when the pointer is locked
63
+ } ) ;
64
+ controls . addEventListener ( 'unlock' , function ( ) {
65
+ if ( isGameRunning ) pauseGame ( ) ; // Show the menu when the pointer is unlocked and the game is running
66
+ } ) ;
67
+ window . addEventListener ( 'resize' , function ( ) {
68
+ renderer . setSize ( window . innerWidth , window . innerHeight ) ;
69
+ camera . aspect = window . innerWidth / window . innerHeight ;
70
+ camera . updateProjectionMatrix ( ) ;
71
+ } ) ;
72
+
73
+ // Load Babylon.js online skybox textures using CubeTextureLoader
74
+ var skyboxLoader = new THREE . CubeTextureLoader ( ) ;
75
+ var skyboxTexture = skyboxLoader . load ( [ 'https://playground.babylonjs.com/textures/skybox_px.jpg' , 'https://playground.babylonjs.com/textures/skybox_nx.jpg' , 'https://playground.babylonjs.com/textures/skybox_py.jpg' , 'https://playground.babylonjs.com/textures/skybox_ny.jpg' , 'https://playground.babylonjs.com/textures/skybox_pz.jpg' , 'https://playground.babylonjs.com/textures/skybox_nz.jpg' ] ) ;
76
+ scene . background = skyboxTexture ;
77
+
78
+ // Physics world setup (unchanged)
79
+ var world = new CANNON . World ( ) ;
80
+ world . gravity . set ( 0 , - 9.82 , 0 ) ;
81
+ world . broadphase = new CANNON . NaiveBroadphase ( ) ;
82
+ world . solver . iterations = 10 ;
83
+ var fixedTimeStep = 1 / 120 ;
84
+ var maxSubSteps = 3 ;
85
+
86
+ // Ground Physics and Mesh setup (unchanged)
87
+ var groundBody = new CANNON . Body ( {
88
+ type : CANNON . Body . STATIC ,
89
+ shape : new CANNON . Plane ( )
90
+ } ) ;
91
+ groundBody . quaternion . setFromEuler ( - Math . PI / 2 , 0 , 0 ) ;
92
+ world . addBody ( groundBody ) ;
93
+ var textureLoader = new THREE . TextureLoader ( ) ;
94
+ var groundTexture = textureLoader . load ( 'https://threejsfundamentals.org/threejs/resources/images/checker.png' ) ;
95
+ groundTexture . wrapS = groundTexture . wrapT = THREE . RepeatWrapping ;
96
+ groundTexture . repeat . set ( 10 , 10 ) ;
97
+ var groundMaterial = new THREE . MeshStandardMaterial ( {
98
+ map : groundTexture ,
99
+ metalness : 0.3 ,
100
+ roughness : 0.7
101
+ } ) ;
102
+ var ground = new THREE . Mesh ( new THREE . PlaneGeometry ( 50 , 50 ) , groundMaterial ) ;
103
+ ground . rotation . x = - Math . PI / 2 ;
104
+ ground . receiveShadow = true ;
105
+ scene . add ( ground ) ;
106
+
107
+ // Wall, Cube, Sphere setup (unchanged)
108
+ var wallTexture = textureLoader . load ( 'https://dl.polyhaven.org/file/ph-assets/Textures/jpg/2k/brick_wall_006/brick_wall_006_diff_2k.jpg' ) ;
109
+ var wallMaterial = new THREE . MeshStandardMaterial ( {
110
+ map : wallTexture ,
111
+ metalness : 0.0 ,
112
+ roughness : 0.8
113
+ } ) ;
114
+ var wall1 = new THREE . Mesh ( new THREE . BoxGeometry ( 10 , 5 , 1 ) , wallMaterial ) ;
115
+ wall1 . position . set ( 0 , 2.5 , - 5 ) ;
116
+ wall1 . castShadow = true ;
117
+ wall1 . receiveShadow = true ;
118
+ scene . add ( wall1 ) ;
119
+ var wall1Body = new CANNON . Body ( {
120
+ mass : 0 ,
121
+ shape : new CANNON . Box ( new CANNON . Vec3 ( 5 , 2.5 , 0.5 ) )
122
+ } ) ;
123
+ wall1Body . position . set ( 0 , 2.5 , - 5 ) ;
124
+ world . addBody ( wall1Body ) ;
125
+ var wall2 = new THREE . Mesh ( new THREE . BoxGeometry ( 10 , 5 , 1 ) , wallMaterial ) ;
126
+ wall2 . position . set ( - 5 , 2.5 , 0 ) ;
127
+ wall2 . rotation . y = Math . PI / 2 ;
128
+ wall2 . castShadow = true ;
129
+ wall2 . receiveShadow = true ;
130
+ scene . add ( wall2 ) ;
131
+ var wall2Body = new CANNON . Body ( {
132
+ mass : 0 ,
133
+ shape : new CANNON . Box ( new CANNON . Vec3 ( 5 , 2.5 , 0.5 ) )
134
+ } ) ;
135
+ wall2Body . position . set ( - 5 , 2.5 , 0 ) ;
136
+ wall2Body . quaternion . setFromEuler ( 0 , Math . PI / 2 , 0 ) ;
137
+ world . addBody ( wall2Body ) ;
138
+
139
+ // Light setup (unchanged)
140
+ var hemisphereLight = new THREE . HemisphereLight ( 0xddeeff , 0x0f0e0d , 1 ) ;
141
+ scene . add ( hemisphereLight ) ;
142
+ var directionalLight = new THREE . DirectionalLight ( 0xffffff , 1.5 ) ;
143
+ directionalLight . position . set ( 10 , 20 , 10 ) ;
144
+ directionalLight . castShadow = true ;
145
+ scene . add ( directionalLight ) ;
146
+
147
+ // Cube object with dynamic physics
148
+ var cubeMaterial = new THREE . MeshStandardMaterial ( {
149
+ color : 0xff0000
150
+ } ) ;
151
+ var cube = new THREE . Mesh ( new THREE . BoxGeometry ( 1 , 1 , 1 ) , cubeMaterial ) ;
152
+ cube . position . set ( 0 , 1 , 0 ) ;
153
+ cube . castShadow = true ;
154
+ scene . add ( cube ) ;
155
+ var cubeBody = new CANNON . Body ( {
156
+ mass : 2 ,
157
+ shape : new CANNON . Box ( new CANNON . Vec3 ( 0.5 , 0.5 , 0.5 ) )
158
+ } ) ;
159
+ cubeBody . position . set ( 0 , 1 , 0 ) ;
160
+ world . addBody ( cubeBody ) ;
161
+ var sphere = new THREE . Mesh ( new THREE . SphereGeometry ( 0.5 , 32 , 32 ) , new THREE . MeshStandardMaterial ( {
162
+ color : 0x00ff00
163
+ } ) ) ;
164
+ sphere . position . set ( 3 , 1 , 0 ) ;
165
+ sphere . castShadow = true ;
166
+ scene . add ( sphere ) ;
167
+ var sphereBody = new CANNON . Body ( {
168
+ mass : 2 ,
169
+ shape : new CANNON . Sphere ( 0.5 )
170
+ } ) ;
171
+ sphereBody . position . set ( 3 , 1 , 0 ) ;
172
+ world . addBody ( sphereBody ) ;
173
+ var playerBody = new CANNON . Body ( {
174
+ mass : 5 ,
175
+ shape : new CANNON . Sphere ( 1 )
176
+ } ) ;
177
+ playerBody . position . set ( 0 , 1 , 10 ) ;
178
+ world . addBody ( playerBody ) ;
179
+ var moveForward = false ,
180
+ moveBackward = false ,
181
+ moveLeft = false ,
182
+ moveRight = false ;
183
+ var canJump = false ;
184
+ var isSprinting = false ;
185
+ var baseMoveSpeed = 100 ;
186
+ var sprintMultiplier = 2 ;
187
+ var velocity = new THREE . Vector3 ( ) ;
188
+ var heldObject = null ;
189
+ var holder = new THREE . Vector3 ( ) ;
190
+ var pickupDistance = 2.5 ;
191
+
192
+ // Event listener for collisions to enable jumping (unchanged)
193
+ playerBody . addEventListener ( 'collide' , function ( event ) {
194
+ if ( event . body === groundBody ) {
195
+ canJump = true ;
196
+ }
197
+ } ) ;
198
+
199
+ // Input controls (unchanged)
200
+ document . addEventListener ( 'keydown' , function ( event ) {
201
+ switch ( event . code ) {
202
+ case 'KeyW' :
203
+ moveForward = true ;
204
+ break ;
205
+ case 'KeyS' :
206
+ moveBackward = true ;
207
+ break ;
208
+ case 'KeyA' :
209
+ moveLeft = true ;
210
+ break ;
211
+ case 'KeyD' :
212
+ moveRight = true ;
213
+ break ;
214
+ case 'ControlLeft' :
215
+ isSprinting = true ;
216
+ break ;
217
+ case 'Space' :
218
+ if ( canJump ) {
219
+ playerBody . velocity . y = 10 ;
220
+ canJump = false ;
221
+ }
222
+ break ;
223
+ case 'KeyE' :
224
+ if ( heldObject ) {
225
+ releaseObject ( ) ;
226
+ } else {
227
+ pickUpObject ( ) ;
228
+ }
229
+ break ;
230
+ case 'KeyF' :
231
+ if ( heldObject ) {
232
+ throwObject ( ) ;
233
+ }
234
+ break ;
235
+ }
236
+ } ) ;
237
+ document . addEventListener ( 'keyup' , function ( event ) {
238
+ switch ( event . code ) {
239
+ case 'KeyW' :
240
+ moveForward = false ;
241
+ break ;
242
+ case 'KeyS' :
243
+ moveBackward = false ;
244
+ break ;
245
+ case 'KeyA' :
246
+ moveLeft = false ;
247
+ break ;
248
+ case 'KeyD' :
249
+ moveRight = false ;
250
+ break ;
251
+ case 'ControlLeft' :
252
+ isSprinting = false ;
253
+ break ;
254
+ }
255
+ } ) ;
256
+
257
+ // Animation loop (unchanged)
258
+ var clock = new THREE . Clock ( ) ;
259
+ function animate ( ) {
260
+ if ( paused ) return ;
261
+ var delta = clock . getDelta ( ) ;
262
+ world . step ( fixedTimeStep , delta , maxSubSteps ) ;
263
+ updatePlayerMovement ( delta ) ;
264
+ wall1 . position . copy ( wall1Body . position ) ;
265
+ wall1 . quaternion . copy ( wall1Body . quaternion ) ;
266
+ wall2 . position . copy ( wall2Body . position ) ;
267
+ wall2 . quaternion . copy ( wall2Body . quaternion ) ;
268
+ cube . position . copy ( cubeBody . position ) ;
269
+ cube . quaternion . copy ( cubeBody . quaternion ) ;
270
+ sphere . position . copy ( sphereBody . position ) ;
271
+ sphere . quaternion . copy ( sphereBody . quaternion ) ;
272
+ stats . update ( ) ;
273
+ renderer . render ( scene , camera ) ;
274
+ requestAnimationFrame ( animate ) ;
275
+ }
276
+ animate ( ) ;
0 commit comments