Browse Source

Game FPS example improved (#22506)

* Improved performance in game_fps

* air control + adjust throw power

* playerSphereCollision in game_fps

* simplified throwBall calculation

* Docs and examples switch retains filter

* Revert "Docs and examples switch retains filter"

This reverts commit d49dbf8830aa73c7af7d53e14908ae381c5200b9.

* Code formatting fix
Octo 3 years ago
parent
commit
e184597413
1 changed files with 95 additions and 34 deletions
  1. 95 34
      examples/games_fps.html

+ 95 - 34
examples/games_fps.html

@@ -74,7 +74,7 @@
 
 			const GRAVITY = 30;
 
-			const NUM_SPHERES = 20;
+			const NUM_SPHERES = 100;
 			const SPHERE_RADIUS = 0.2;
 
 			const STEPS_PER_FRAME = 5;
@@ -105,9 +105,14 @@
 			const playerDirection = new THREE.Vector3();
 
 			let playerOnFloor = false;
+			let mouseTime = 0;
 
 			const keyStates = {};
 
+			const t_vector = new THREE.Vector3();
+			const t_vector2 = new THREE.Vector3();
+			const t_vector3 = new THREE.Vector3();
+
 			document.addEventListener( 'keydown', ( event ) => {
 
 				keyStates[ event.code ] = true;
@@ -124,6 +129,14 @@
 
 				document.body.requestPointerLock();
 
+				mouseTime = performance.now();
+
+			} );
+
+			document.addEventListener( 'mouseup', () => {
+
+				throwBall();
+
 			} );
 
 			document.body.addEventListener( 'mousemove', ( event ) => {
@@ -148,20 +161,26 @@
 
 			}
 
-			document.addEventListener( 'click', () => {
+			function throwBall() {
 
 				const sphere = spheres[ sphereIdx ];
 
 				camera.getWorldDirection( playerDirection );
 
-				sphere.collider.center.copy( playerCollider.end );
-				sphere.velocity.copy( playerDirection ).multiplyScalar( 30 );
+				sphere.collider.center.copy( playerCollider.end ).addScaledVector( playerDirection, playerCollider.radius * 1.5 );
+
+				// throw the ball with more force if we hold the button longer, and if we move forward
+
+				let impulse = 15 + 30 * ( 1 - Math.exp( ( mouseTime - performance.now() ) * 0.001 ));
+
+				sphere.velocity.copy( playerDirection ).multiplyScalar( impulse );
+				sphere.velocity.addScaledVector( playerVelocity, 2 );
 
 				sphereIdx = ( sphereIdx + 1 ) % spheres.length;
 
-			} );
+			}
 
-			function playerCollitions() {
+			function playerCollisions() {
 
 				const result = worldOctree.capsuleIntersect( playerCollider );
 
@@ -185,33 +204,67 @@
 
 			function updatePlayer( deltaTime ) {
 
-				if ( playerOnFloor ) {
-
-					const damping = Math.exp( - 3 * deltaTime ) - 1;
-					playerVelocity.addScaledVector( playerVelocity, damping );
+				let damping = Math.exp( - 4 * deltaTime ) - 1;
 
-				} else {
+				if ( ! playerOnFloor ) {
 
 					playerVelocity.y -= GRAVITY * deltaTime;
 
+					// small air resistance
+					damping *= 0.1;
+
 				}
 
+				playerVelocity.addScaledVector( playerVelocity, damping );
+
 				const deltaPosition = playerVelocity.clone().multiplyScalar( deltaTime );
 				playerCollider.translate( deltaPosition );
 
-				playerCollitions();
+				playerCollisions();
 
 				camera.position.copy( playerCollider.end );
 
 			}
 
+			function playerSphereCollision( sphere ) {
+
+				const center = t_vector.addVectors( playerCollider.start, playerCollider.end ).multiplyScalar( 0.5 );
+
+				const sphere_center = sphere.collider.center;
+
+				const r = playerCollider.radius + sphere.collider.radius;
+				const r2 = r * r;
+
+				// approximation: player = 3 spheres
+
+				for ( let point of [ playerCollider.start, playerCollider.end, center ] ) {
+
+					const d2 = point.distanceToSquared( sphere_center );
+
+					if ( d2 < r2 ) {
+
+						const normal = t_vector.subVectors( point, sphere_center ).normalize();
+						const v1 = t_vector2.copy( normal ).multiplyScalar( normal.dot( playerVelocity ) );
+						const v2 = t_vector3.copy( normal ).multiplyScalar( normal.dot( sphere.velocity ) );
+
+						playerVelocity.add( v2 ).sub( v1 );
+						sphere.velocity.add( v1 ).sub( v2 );
+
+						const d = ( r - Math.sqrt( d2 ) ) / 2;
+						sphere_center.addScaledVector( normal, - d );
+
+					}
+
+				}
+			}
+
 			function spheresCollisions() {
 
-				for ( let i = 0; i < spheres.length; i ++ ) {
+				for ( let i = 0, length = spheres.length; i < length; i ++ ) {
 
 					const s1 = spheres[ i ];
 
-					for ( let j = i + 1; j < spheres.length; j ++ ) {
+					for ( let j = i + 1; j < length; j ++ ) {
 
 						const s2 = spheres[ j ];
 
@@ -221,9 +274,10 @@
 
 						if ( d2 < r2 ) {
 
-							const normal = s1.collider.clone().center.sub( s2.collider.center ).normalize();
-							const v1 = normal.clone().multiplyScalar( normal.dot( s1.velocity ) );
-							const v2 = normal.clone().multiplyScalar( normal.dot( s2.velocity ) );
+							const normal = t_vector.subVectors( s1.collider.center, s2.collider.center ).normalize();
+							const v1 = t_vector2.copy( normal ).multiplyScalar( normal.dot( s1.velocity ) );
+							const v2 = t_vector3.copy( normal ).multiplyScalar( normal.dot( s2.velocity ) );
+
 							s1.velocity.add( v2 ).sub( v1 );
 							s2.velocity.add( v1 ).sub( v2 );
 
@@ -242,7 +296,7 @@
 
 			function updateSpheres( deltaTime ) {
 
-				spheres.forEach( sphere =>{
+				spheres.forEach( sphere => {
 
 					sphere.collider.center.addScaledVector( sphere.velocity, deltaTime );
 
@@ -262,11 +316,17 @@
 					const damping = Math.exp( - 1.5 * deltaTime ) - 1;
 					sphere.velocity.addScaledVector( sphere.velocity, damping );
 
-					spheresCollisions();
+					playerSphereCollision( sphere );
+
+				} );
+
+				spheresCollisions();
+
+				for ( let sphere of spheres ) {
 
 					sphere.mesh.position.copy( sphere.collider.center );
 
-				} );
+				}
 
 			}
 
@@ -293,33 +353,34 @@
 
 			function controls( deltaTime ) {
 
-				const speed = 25;
+				// gives a bit of air control
+				let speedDelta = deltaTime * ( playerOnFloor ? 25 : 8 );
 
-				if ( playerOnFloor ) {
+				if ( keyStates[ 'KeyW' ] ) {
 
-					if ( keyStates[ 'KeyW' ] ) {
+					playerVelocity.add( getForwardVector().multiplyScalar( speedDelta ) );
 
-						playerVelocity.add( getForwardVector().multiplyScalar( speed * deltaTime ) );
+				}
 
-					}
+				if ( keyStates[ 'KeyS' ] ) {
 
-					if ( keyStates[ 'KeyS' ] ) {
+					playerVelocity.add( getForwardVector().multiplyScalar( - speedDelta ) );
 
-						playerVelocity.add( getForwardVector().multiplyScalar( - speed * deltaTime ) );
+				}
 
-					}
+				if ( keyStates[ 'KeyA' ] ) {
 
-					if ( keyStates[ 'KeyA' ] ) {
+					playerVelocity.add( getSideVector().multiplyScalar( - speedDelta ) );
 
-						playerVelocity.add( getSideVector().multiplyScalar( - speed * deltaTime ) );
+				}
 
-					}
+				if ( keyStates[ 'KeyD' ] ) {
 
-					if ( keyStates[ 'KeyD' ] ) {
+					playerVelocity.add( getSideVector().multiplyScalar( speedDelta ) );
 
-						playerVelocity.add( getSideVector().multiplyScalar( speed * deltaTime ) );
+				}
 
-					}
+				if ( playerOnFloor ) {
 
 					if ( keyStates[ 'Space' ] ) {