<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>First Person Game</title>
<style>
body { margin: 0; }
canvas { display: block; }
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
let scene, camera, renderer;
let moveForward = false, moveBackward = false, moveLeft = false, moveRight = false;
let velocity = new THREE.Vector3();
let direction = new THREE.Vector3();
let canJump = false;
let prevTime = performance.now();
let cubes = [], cubeVelocities = [];
let heldCube = null;
const speed = 150.0;
const jumpVelocity = 75.0;
const gravity = 9.8 * 50.0;
const pickUpDistance = 2.0;
const originalCubeScale = 1;
const heldCubeScale = 0.5;
const friction = 0.1; // Friction coefficient
let pitch = 0, yaw = 0;
init();
animate();
function init() {
// Scene and camera setup
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.y = 1.6;
// Renderer setup
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Ground
const groundGeometry = new THREE.PlaneGeometry(50, 50);
const groundMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = -Math.PI / 2;
scene.add(ground);
// Tangible cubes
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0x0000ff });
for (let i = 0; i < 3; i++) {
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.set(Math.random() * 30 - 15, 1.6, Math.random() * 30 - 15);
cubes.push(cube);
cubeVelocities.push(new THREE.Vector3());
scene.add(cube);
}
// Event listeners for movement
document.addEventListener('keydown', onKeyDown);
document.addEventListener('keyup', onKeyUp);
// Lock the mouse
document.body.addEventListener('click', () => {
document.body.requestPointerLock();
});
document.addEventListener('mousemove', onMouseMove);
window.addEventListener('resize', onWindowResize);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function onKeyDown(event) {
switch (event.code) {
case 'KeyW': moveForward = true; break;
case 'KeyS': moveBackward = true; break;
case 'KeyA': moveLeft = true; break;
case 'KeyD': moveRight = true; break;
case 'Space':
if (canJump) {
velocity.y = jumpVelocity;
canJump = false;
}
break;
case 'KeyF':
pickOrThrowCube();
break;
}
}
function onKeyUp(event) {
switch (event.code) {
case 'KeyW': moveForward = false; break;
case 'KeyS': moveBackward = false; break;
case 'KeyA': moveLeft = false; break;
case 'KeyD': moveRight = false; break;
}
}
function onMouseMove(event) {
if (document.pointerLockElement) {
const sensitivity = 0.002;
yaw -= event.movementX * sensitivity;
pitch -= event.movementY * sensitivity;
pitch = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, pitch));
camera.rotation.y = yaw;
camera.rotation.x = pitch;
camera.rotation.z = 0; // Prevent rolling sideways
}
}
function pickOrThrowCube() {
if (heldCube) {
// Throw the held cube
const throwVelocity = new THREE.Vector3();
camera.getWorldDirection(throwVelocity);
throwVelocity.multiplyScalar(200); // Throw strength
heldCube.position.add(throwVelocity.multiplyScalar(0.02));
cubeVelocities[cubes.indexOf(heldCube)].copy(throwVelocity);
heldCube.scale.set(originalCubeScale, originalCubeScale, originalCubeScale); // Reset cube scale
heldCube = null;
} else {
// Pick up a cube if close enough and looking at it
const raycaster = new THREE.Raycaster();
raycaster.setFromCamera(new THREE.Vector2(0, 0), camera);
const intersects = raycaster.intersectObjects(cubes);
if (intersects.length > 0) {
const intersect = intersects[0];
if (intersect.distance < pickUpDistance) {
heldCube = intersect.object;
cubeVelocities[cubes.indexOf(heldCube)].set(0, 0, 0); // Stop the cube's movement
heldCube.scale.set(heldCubeScale, heldCubeScale, heldCubeScale); // Make the cube smaller
heldCube.position.copy(camera.position).add(camera.getWorldDirection(new THREE.Vector3()).multiplyScalar(1.5));
}
}
}
}
function animate() {
requestAnimationFrame(animate);
// Update time
const time = performance.now();
const delta = (time - prevTime) / 1000;
// Movement logic
direction.z = Number(moveForward) - Number(moveBackward);
direction.x = Number(moveRight) - Number(moveLeft);
direction.normalize();
velocity.x -= velocity.x * 10.0 * delta;
velocity.z -= velocity.z * 10.0 * delta;
velocity.y -= gravity * delta;
if (moveForward || moveBackward || moveLeft || moveRight) {
const frontDirection = new THREE.Vector3();
camera.getWorldDirection(frontDirection);
const rightDirection = new THREE.Vector3();
rightDirection.crossVectors(camera.up, frontDirection).normalize();
frontDirection.multiplyScalar(direction.z * speed * delta);
rightDirection.multiplyScalar(direction.x * speed * delta);
velocity.add(frontDirection).add(rightDirection);
}
camera.position.addScaledVector(velocity, delta);
// Collision detection with barriers
camera.position.x = Math.max(-24, Math.min(24, camera.position.x));
camera.position.z = Math.max(-24, Math.min(24, camera.position.z));
if (camera.position.y < 1.6) {
velocity.y = 0;
camera.position.y = 1.6;
canJump = true;
}
// Update held cube position
if (heldCube) {
heldCube.position.copy(camera.position).add(camera.getWorldDirection(new THREE.Vector3()).multiplyScalar(1.5));
}
// Cube collision logic
for (let i = 0; i < cubes.length; i++) {
if (cubes[i] !== heldCube) {
// Apply friction
cubeVelocities[i].x *= (1 - friction);
cubeVelocities[i].z *= (1 - friction);
// Apply gravity to cubes
cubeVelocities[i].y -= gravity * delta;
cubes[i].position.addScaledVector(cubeVelocities[i], delta);
// Cube collision with ground: stop bouncing
if (cubes[i].position.y < 0.5) {
cubes[i].position.y = 0.5;
cubeVelocities[i].y = 0; // Stop upward velocity
}
// Simple cube interaction logic for pushing
for (let j = 0; j < cubes.length; j++) {
if (i !== j) {
const distance = cubes[i].position.distanceTo(cubes[j].position);
if (distance < 1.5) { // If cubes are close enough
const collisionDirection = new THREE.Vector3().subVectors(cubes[i].position, cubes[j].position).normalize();
const relativeVelocity = new THREE.Vector3().subVectors(cubeVelocities[i], cubeVelocities[j]);
if (relativeVelocity.dot(collisionDirection) < 0) { // Only push if moving toward each other
const pushAmount = 0.02; // Adjust to control push force
cubeVelocities[i].add(collisionDirection.clone().multiplyScalar(pushAmount));
cubeVelocities[j].sub(collisionDirection.clone().multiplyScalar(pushAmount));
}
}
}
}
}
}
renderer.render(scene, camera);
prevTime = time;
}
</script>
</body>
</html>
你需要添加
在您的
init()
函数
季节: 旋转矩阵乘法顺序
您可以在此处查看闻名的信息:Https://en.wikipedia.org/wiki/euler_angles#rotation_matrix也要添加此信息:
const axesHelper = new THREE.AxesHelper( 15 )
//axesHelper.renderOrder = 1;
axesHelper.material.depthTest = false;
scene.add( axesHelper )
中它将显示世界轴(并且将始终处于所有对象的顶部),我需要在chekek chek的同时,所以也许您将来也需要它