<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <link rel="stylesheet" href="button.css"> <!-- CSSファイルをリンク --> </head> <body> <div id="WebGL-output"></div> <div id="overlay"><!-- 透明なオーバーレイ --> <button id="myCircleButton">☺</button> </div> <script type="module"> import * as THREE from "https://unpkg.com/three@0.126.1/build/three.module.js"; import { PointerLockControls } from "https://unpkg.com/three@0.126.1/examples/jsm/controls/PointerLockControls.js"; import { GLTFLoader } from "https://unpkg.com/three@0.126.1/examples/jsm/loaders/GLTFLoader.js"; let camera; let scene; let renderer; let controls; let mixer; // アニメーションミキサー let moveForward = false; let moveBackward = false; let moveLeft = false; let moveRight = false; let bChanLoaded = false; // B-chan.glbがロードされたかどうかを示すフラグ let VirtualShop, WorldStick, bchanModel; function init() { // シーンの作成 scene = new THREE.Scene(); scene.background = new THREE.Color(0xffffff); // 背景色 // カメラの作成 camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(1, 5, 5); camera.lookAt(new THREE.Vector3(0, 0, 0)); // ライトの作成 const light = new THREE.SpotLight(0xffffff, 1.0); light.position.set(100, 500, 500); scene.add(light); light.castShadow = true; // モデルの読み込み const loader = new GLTFLoader(); loader.load( 'https://www.yatex.org/gitbucket/j2311/about-Leaflet/raw/main/VirtualShop-final.glb', function (gltf) { VirtualShop = gltf.scene; scene.add(VirtualShop); } ); loader.load( 'https://www.yatex.org/gitbucket/j2311/about-Leaflet/raw/main/worldstick.glb', function (gltf) { WorldStick = gltf.scene; scene.add(WorldStick); } ); loader.load( 'https://www.yatex.org/gitbucket/j2311/about-Leaflet/raw/main/B-chan_plus_defult.glb', function (gltf) { bchanModel = gltf.scene; scene.add(bchanModel); bChanLoaded = true; // モデルがロードされたときにフラグを更新 // アニメーションミキサーの設定 mixer = new THREE.AnimationMixer(bchanModel); gltf.animations.forEach((clip) => { mixer.clipAction(clip).play(); // アニメーションを再生 }); } ); // カメラコントロールの作成 controls = new PointerLockControls(camera, document.body); const outputDiv = document.getElementById("WebGL-output"); outputDiv.addEventListener("click", function () { controls.lock(); }); // 透明オーバーレイのクリックイベントを無効化 const overlay = document.getElementById("overlay"); overlay.addEventListener("click", function (event) { event.preventDefault(); event.stopPropagation(); // イベントの伝播を止める }); // キーボードのキー操作 document.addEventListener("keydown", handleKeyDown); document.addEventListener("keyup", handleKeyUp); // レンダラーの作成 renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true }); renderer.setSize(window.innerWidth * 0.8, window.innerHeight * 0.8); document.getElementById("WebGL-output").appendChild(renderer.domElement); } function handleKeyDown(event) { switch (event.key) { case "w": case "ArrowUp": moveForward = true; break; case "s": case "ArrowDown": moveBackward = true; break; case "a": case "ArrowLeft": moveLeft = true; break; case "d": case "ArrowRight": moveRight = true; break; case "g": // Move B-chan.glb forward if (bChanLoaded) { bchanModel.position.z -= 0.5; // 動かす方向を調整 } break; case "b": // Move B-chan.glb backward if (bChanLoaded) { bchanModel.position.z += 0.5; // 動かす方向を調整 } break; case "f": // Move B-chan.glb left if (bChanLoaded) { bchanModel.position.x -= 0.5; // 動かす方向を調整 } break; case "h": // Move B-chan.glb right if (bChanLoaded) { bchanModel.position.x += 0.5; // 動かす方向を調整 } break; case "r": // Rotate B-chan.glb around Y-axis (left-right rotation) if (bChanLoaded) { bchanModel.rotation.y += Math.PI / 16; // 回転角度を指定(ここでは 22.5度) } break; } } function handleKeyUp(event) { switch (event.key) { case "w": case "ArrowUp": moveForward = false; break; case "s": case "ArrowDown": moveBackward = false; break; case "a": case "ArrowLeft": moveLeft = false; break; case "d": case "ArrowRight": moveRight = false; break; } } function updateCameraPosition() { const speed = 10; const direction = new THREE.Vector3(); const { x, y, z } = controls.getObject().position; direction.x = Number(moveRight) - Number(moveLeft); direction.z = Number(moveBackward) - Number(moveForward); direction.normalize(); const delta = speed * 0.1; controls.getObject().translateX(direction.x * delta); controls.getObject().translateZ(direction.z * delta); } function animate() { requestAnimationFrame(animate); updateCameraPosition(); if (mixer) mixer.update(0.01); // アニメーションの更新 renderer.render(scene, camera); } // クリック時の処理 document.addEventListener("dblclick", function (event) { event.preventDefault(); const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; raycaster.setFromCamera(mouse, camera); const intersects = raycaster.intersectObjects(scene.children, true); if (intersects.length > 0) { if (intersects[0].object.name == "back") { window.open("https://www.yatex.org/gitbucket/j2311/about-Leaflet/pages/buy.html"); } console.log(intersects[0]); } }); // 円ボタンのクリックイベント document.getElementById("myCircleButton").addEventListener("click", function() { if (mixer) { mixer.clipAction(mixer._clips[0]).play(); // 最初のアニメーションを再生 } }); // 初期化とアニメーションの開始 init(); animate(); </script> </body> </html>