Newer
Older
Kusanagi-system-M / test / test-es.js
import * as THREE from 'three';
import { PointerLockControls } from 'three/examples/jsm/controls/PointerLockControls.js';
import { World, Body, Box, Sphere, Vec3 } from 'cannon-es';

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// ライト
scene.add(new THREE.HemisphereLight(0xffffff, 0x444444));

// 地面
const floor = new THREE.Mesh(new THREE.BoxGeometry(100, 1, 100), new THREE.MeshStandardMaterial({ color: 0x888888 }));
floor.position.y = -0.5;
scene.add(floor);

// 物理ワールド
const world = new World();
world.gravity.set(0, -9.82, 0);

// 地面の物理
const groundBody = new Body({
  mass: 0,
  shape: new Box(new Vec3(50, 0.5, 50)),
  position: new Vec3(0, -0.5, 0)
});
world.addBody(groundBody);

// プレイヤーの物理ボディ(球体)
const playerRadius = 1;
const playerBody = new Body({
  mass: 5,
  shape: new Sphere(playerRadius),
  position: new Vec3(0, 5, 0),
  linearDamping: 0.9
});
world.addBody(playerBody);

// FPSコントロール
const controls = new PointerLockControls(camera, document.body);

document.addEventListener('click', () => {
  controls.lock();
});

const velocity = new Vec3();
const direction = new THREE.Vector3();
const keyState = {};

document.addEventListener('keydown', (e) => { keyState[e.code] = true; });
document.addEventListener('keyup', (e) => { keyState[e.code] = false; });

let canJump = false;

playerBody.addEventListener('collide', (e) => {
  // 地面と接触したらジャンプ可能に
  if (e.contact.ni.y > 0.5) {
    canJump = true;
  }
});

function animate() {
  requestAnimationFrame(animate);

  // プレイヤー操作
  direction.set(0, 0, 0);
  if (keyState['KeyW']) direction.z -= 1;
  if (keyState['KeyS']) direction.z += 1;
  if (keyState['KeyA']) direction.x -= 1;
  if (keyState['KeyD']) direction.x += 1;
  direction.normalize();

  const moveSpeed = 10;
  const euler = new THREE.Euler(0, camera.rotation.y, 0);
  const moveDir = direction.clone().applyEuler(euler);

  velocity.set(moveDir.x * moveSpeed, playerBody.velocity.y, moveDir.z * moveSpeed);
  playerBody.velocity.copy(velocity);

  if (keyState['Space'] && canJump) {
    playerBody.velocity.y = 8;
    canJump = false;
  }

  world.step(1/60);

  // プレイヤーの物理ボディにカメラを追従
  camera.position.copy(playerBody.position);

  renderer.render(scene, camera);
}

animate();