junkerstock
 vrm-test13 

<!DOCTYPE html>
<html>
<head>
<title>A-Frame VRM Component Test (with Event Listener)</title>
<meta charset="utf-8">

<script type="importmap">{"imports": {"three": "https://threejs.org/build/three.module.js"}}</script>
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script src="https://binzume.github.io/aframe-vrm/dist/aframe-vrm.js"></script>

</head>
<body>

<a-scene id="myScene" background="color: #ECECEC">
<a-assets>
<a-asset-item id="vrm-model" src="./vrm/tesA1_V0a.vrm"></a-asset-item>
</a-assets>

<a-entity
vrm="src: #vrm-model; lookAt: #camera"
position="0 0 -2"
scale="1.2 1.2 1.2"
rotation="0 180 0">
</a-entity>

<a-entity id="rig" position="0 0 5" camera-relative-controls>
<a-entity id="camera" camera="far: 20000;" look-controls="pointerLockEnabled: false; touchEnabled: false" position="0 1.6 0">
<a-entity cursor="rayOrigin: mouse; fuse: false;" raycaster="objects: a-sphere;" position="0 0 -1" geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03;" material="color: black; shader: flat; opacity: 0.7;"></a-entity>
</a-entity>
<a-entity id="leftHand" oculus-touch-controls="hand: left;"></a-entity>
<a-entity id="rightHand" oculus-touch-controls="hand: right;" laser-controls="hand: right;" raycaster="objects: a-sphere;"></a-entity>
</a-entity>

<a-entity light="type: ambient; color: #888"></a-entity>
<a-entity light="type: directional; color: #FFF; intensity: 1.0; castShadow: true" position="-2 3 2"></a-entity>

<a-plane id="ground" position="0 0 0" rotation="-90 0 0" width="100" height="100" color="#7BC8A4" shadow="receive: true"></a-plane>

<script>
(function () {
document.addEventListener('DOMContentLoaded', function () {
const sceneEl = document.querySelector('a-scene');

function initializeApp() {
// 球の生成
initializeSpheres();

// ▼▼▼ ここが追加した「探知機」のコードです ▼▼▼
const vrmEntity = document.querySelector('a-entity[vrm]');
if (vrmEntity) {
console.log("VRMエンティティを発見。イベント監視を開始します。");
vrmEntity.addEventListener('model-loaded', function (event) {
console.log("!!!VRMモデルの読み込みが完了しました!!!", event.detail.model);
alert("VRMモデルの読み込みに成功しました!");
});
vrmEntity.addEventListener('model-error', function (event) {
console.error("XXX VRMモデルの読み込みに失敗しました XXX", event.detail.error);
alert("VRMモデルの読み込みに失敗しました。コンソールを確認してください。");
});
} else {
console.error("VRMエンティティが見つかりませんでした。");
}
// ▲▲▲ ここまでが追加したコードです ▲▲▲
}

if (sceneEl.hasLoaded) {
initializeApp();
} else {
sceneEl.addEventListener('loaded', initializeApp, {once: true});
}

function initializeSpheres() {
const numberOfSpheres = 20;
const groundSize = 100;
const spawnArea = groundSize / 2 * 0.9;
for (let i = 0; i < numberOfSpheres; i++) {
const sphereEl = document.createElement('a-sphere');
const radius = Math.random() * 1.5 + 0.2;
const x = (Math.random() - 0.5) * 2 * spawnArea;
const y = radius;
const z = (Math.random() - 0.5) * 2 * spawnArea;
const color = `hsl(${Math.random() * 360}, 70%, 50%)`;
sphereEl.setAttribute('position', {x, y, z});
sphereEl.setAttribute('radius', radius);
sphereEl.setAttribute('color', color);
sphereEl.setAttribute('shadow', 'cast: true');
sceneEl.appendChild(sphereEl);
}
}
});

AFRAME.registerComponent('camera-relative-controls', { schema: { targetSpeed: { type: 'number', default: 5 }, acceleration: { type: 'number', default: 10 }, damping: { type: 'number', default: 8 }, brakingDeceleration: { type: 'number', default: 20 }, enabled: { type: 'boolean', default: true }, rotationSpeed: { type: 'number', default: 1.5 }, pitchLimit: { type: 'number', default: 85 }, verticalSpeed: { type: 'number', default: 30 } }, init: function () { this.keys = {}; this.leftThumbstickInput = { x: 0, y: 0 }; this.rightThumbstickInput = { x: 0, y: 0 }; this.currentVelocity = new THREE.Vector3(); this.ZERO_VECTOR = new THREE.Vector3(); this.cameraDirection = new THREE.Vector3(); this.cameraRight = new THREE.Vector3(); this.moveDirection = new THREE.Vector3(); this.desiredVelocity = new THREE.Vector3(); this.cameraWorldQuaternion = new THREE.Quaternion(); this.rigEl = this.el; this.cameraEl = this.el.querySelector('[camera]'); this.isReady = false; if (!this.cameraEl) { console.error('camera-relative-controls: カメラエンティティが見つかりません。'); } this.el.sceneEl.addEventListener('loaded', () => { this.leftHand = document.getElementById('leftHand'); if (this.leftHand) { this.leftHand.addEventListener('thumbstickmoved', this.onLeftThumbstickMoved.bind(this)); } else { console.warn("camera-relative-controls: 左手コントローラー(#leftHand)が見つかりません。"); } this.rightHand = document.getElementById('rightHand'); if (this.rightHand) { this.rightHand.addEventListener('thumbstickmoved', this.onRightThumbstickMoved.bind(this)); } else { console.warn("camera-relative-controls: 右手コントローラー(#rightHand)が見つかりません。"); } }); this.onKeyDown = this.onKeyDown.bind(this); this.onKeyUp = this.onKeyUp.bind(this); window.addEventListener('keydown', this.onKeyDown); window.addEventListener('keyup', this.onKeyUp); }, remove: function () { window.removeEventListener('keydown', this.onKeyDown); window.removeEventListener('keyup', this.onKeyUp); if (this.leftHand) { try { this.leftHand.removeEventListener('thumbstickmoved', this.onLeftThumbstickMoved.bind(this)); } catch(e){} } if (this.rightHand) { try { this.rightHand.removeEventListener('thumbstickmoved', this.onRightThumbstickMoved.bind(this)); } catch(e){} } }, onLeftThumbstickMoved: function (evt) { this.leftThumbstickInput.x = evt.detail.x; this.leftThumbstickInput.y = evt.detail.y; }, onRightThumbstickMoved: function (evt) { this.rightThumbstickInput.x = evt.detail.x; this.rightThumbstickInput.y = evt.detail.y; }, tick: function (time, timeDelta) { if (!this.data.enabled) return; if (!this.isReady) { if (this.cameraEl && this.cameraEl.object3D && this.cameraEl.object3D.matrixWorld) { this.isReady = true; } else { if (!this.cameraEl) { this.cameraEl = this.el.querySelector('[camera]'); } return; } } if (!this.cameraEl || !this.cameraEl.object3D || !this.rigEl || !this.rigEl.object3D) { return; } const data = this.data; const dt = timeDelta / 1000; if (this.rigEl.sceneEl.is('vr-mode')) { if (Math.abs(this.rightThumbstickInput.x) > 0.1) { const yawAngle = -this.rightThumbstickInput.x * data.rotationSpeed * dt; this.rigEl.object3D.rotation.y += yawAngle; } if (Math.abs(this.rightThumbstickInput.y) > 0.1) { const verticalMovement = this.rightThumbstickInput.y * data.verticalSpeed * dt; this.rigEl.object3D.position.y -= verticalMovement; } } const position = this.rigEl.object3D.position; const cameraObject = this.cameraEl.object3D; cameraObject.getWorldQuaternion(this.cameraWorldQuaternion); this.cameraDirection.set(0, 0, -1).applyQuaternion(this.cameraWorldQuaternion); if (this.cameraDirection.lengthSq() > 0.0001) this.cameraDirection.normalize(); this.cameraRight.set(1, 0, 0).applyQuaternion(this.cameraWorldQuaternion); this.cameraRight.y = 0; if (this.cameraRight.lengthSq() > 0.0001) this.cameraRight.normalize(); this.moveDirection.set(0, 0, 0); if (this.keys['KeyW'] || this.keys['ArrowUp']) { this.moveDirection.add(this.cameraDirection); } if (this.keys['KeyS'] || this.keys['ArrowDown']) { this.moveDirection.sub(this.cameraDirection); } if (this.keys['KeyA'] || this.keys['ArrowLeft']) { this.moveDirection.sub(this.cameraRight); } if (this.keys['KeyD'] || this.keys['ArrowRight']) { this.moveDirection.add(this.cameraRight); } if (Math.abs(this.leftThumbstickInput.y) > 0.1) { const forwardBackward = this.cameraDirection.clone().multiplyScalar(-this.leftThumbstickInput.y); this.moveDirection.add(forwardBackward); } if (Math.abs(this.leftThumbstickInput.x) > 0.1) { const leftRight = this.cameraRight.clone().multiplyScalar(this.leftThumbstickInput.x); this.moveDirection.add(leftRight); } const isInputActive = this.moveDirection.lengthSq() > 0.0001; if (isInputActive) { this.moveDirection.normalize(); } let lerpFactor = data.damping; const isCurrentlyMoving = this.currentVelocity.lengthSq() > 0.01; if (isInputActive) { let isOpposingInput = false; if (isCurrentlyMoving) { const dotProduct = this.currentVelocity.dot(this.moveDirection); if (dotProduct < -0.1) { isOpposingInput = true; } } if (isOpposingInput) { this.desiredVelocity.copy(this.ZERO_VECTOR); lerpFactor = data.brakingDeceleration; } else { this.desiredVelocity.copy(this.moveDirection).multiplyScalar(data.targetSpeed); lerpFactor = data.acceleration; } } else { this.desiredVelocity.copy(this.ZERO_VECTOR); lerpFactor = data.damping; } const effectiveLerpFactor = 1.0 - Math.exp(-lerpFactor * dt); this.currentVelocity.lerp(this.desiredVelocity, effectiveLerpFactor); if (this.currentVelocity.lengthSq() < 0.0001) { this.currentVelocity.copy(this.ZERO_VECTOR); } if (this.currentVelocity.lengthSq() > 0) { const deltaPosition = this.currentVelocity.clone().multiplyScalar(dt); position.add(deltaPosition); } },
onKeyDown: function (event) { if (!this.data.enabled) { return; } if (['KeyW', 'ArrowUp', 'KeyS', 'ArrowDown', 'KeyA', 'ArrowLeft', 'KeyD', 'ArrowRight'].includes(event.code)) { this.keys[event.code] = true; } },
onKeyUp: function (event) { if (this.keys[event.code] !== undefined) { delete this.keys[event.code]; } }
});
})();
</script>
</body>
</html>


使用変数

-------( Function )
background
camera
cameraDirection
cameraEl
cameraObject
cameraRight
charset
color
controls
currentVelocity
cursor
data
deltaPosition
desiredVelocity
dotProduct
dt
eftThumbstickInput
eraWorldQuaternion
ffectiveLerpFactor
forwardBackward
geometry
ghtThumbstickInput
groundSize
height
i
id
initializeApp -------( Function )
initializeSpheres -------( Function )
isCurrentlyMoving
isInputActive
isOpposingInput
isReady
keys
leftHand
leftRight
lerpFactor
light
material
moveDirection
numberOfSpheres
onKeyDown
onKeyUp
position
radius
raycaster
rigEl
rightHand
rotation
scale
sceneEl
shadow
spawnArea
sphereEl
src
type
verticalMovement
vrm
vrmEntity
width
x
y
yawAngle
z
ZERO_VECTOR

Content-type: text/html error-smemo8

ERROR !

ファイルの差し替えに失敗しました: ./smemo8.log