Newer
Older
Kusanagi-system-M / test / test-es2.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 wall_1 = new THREE.Mesh(
  new THREE.BoxGeometry(5, 5, 1), // 幅, 高さ, 奥行き
  new THREE.MeshStandardMaterial({ color: 0x4444ff })
);
wall_1.position.set(0, 0.5, -10); // 地面からの高さを考慮してY=2.5
scene.add(wall_1);

const wall_1Body = new Body({
  mass: 0, // 静的
  shape: new Box(new Vec3(2.5, 2.5, 0.5)), // 半分のサイズを指定
  position: new Vec3(0, 0.5, -10)
});
world.addBody(wall_1Body);


// プレイヤーの物理ボディ
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) => {
  const contact = e.contact;

  const contactNormal = new Vec3();
  if (contact.bi.id === playerBody.id) {
    contact.ni.negate(contactNormal);
  } else {
    contactNormal.copy(contact.ni);
  }

  if (contactNormal.y > 0.5) {
    canJump = true;
  }
});

function animate() {
  requestAnimationFrame(animate);

// プレイヤー操作
const moveSpeed = 5;

const forward = new THREE.Vector3();
controls.getDirection(forward);
forward.y = 0;
forward.normalize();

const right = new THREE.Vector3();
right.crossVectors(forward, camera.up);

// 入力方向をベクトルとして合成
direction.set(0, 0, 0);
if (keyState['KeyW']) direction.add(forward);
if (keyState['KeyS']) direction.sub(forward);
if (keyState['KeyA']) direction.sub(right);
if (keyState['KeyD']) direction.add(right);

direction.normalize();
velocity.set(direction.x * moveSpeed, playerBody.velocity.y, direction.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();