<!DOCTYPE html>
<html>
<head>
<title>A-Frame - 3D巨大迷路 (ライブラリ安定版)</title>
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/c-frame/aframe-physics-system@v4.0.1/dist/aframe-physics-system.min.js"></script>
<script src="https://unpkg.com/aframe-look-at-component@0.8.0/dist/aframe-look-at-component.min.js"></script>
<script src="https://unpkg.com/aframe-troika-text/dist/aframe-troika-text.min.js"></script>
</head>
<body>
<a-scene id="myScene" vr-mode-ui="enabled: true" background="color: #87CEEB" physics="debug: true; gravity: -9.8;">
<a-entity id="rig">
<a-entity id="player"
camera="userHeight: 1.6; far: 20000;"
look-controls="pointerLockEnabled: false; touchEnabled: false"
wasd-controls="acceleration: 80;"
dynamic-body="shape: capsule; mass: 5; height: 1.6; radius: 0.4; linearDamping: 0.97; angularDamping: 1; fixedRotation: true;">
<a-entity id="mouseCursor" cursor="rayOrigin: mouse" raycaster="objects: .maze-wall, 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 id="leftHand" oculus-touch-controls="hand: left;"></a-entity>
<a-entity id="rightHand" oculus-touch-controls="hand: right;" laser-controls="hand: right" raycaster="objects: .maze-wall, a-sphere;"></a-entity>
</a-entity>
</a-entity>
<a-entity light="type: ambient; color: #888"></a-entity>
<a-entity light="type: directional; color: #FFF; intensity: 0.8; castShadow: true" position="-100 200 100"></a-entity>
<a-box id="ground"
position="0 -0.05 0"
width="500"
height="0.1"
depth="500"
color="#7BC8A4"
shadow="receive: true"
static-body="friction: 0.2">
</a-box>
<script>
// --- SCRIPT BLOCK 2: Main Scene Logic (変更なし) ---
document.addEventListener('DOMContentLoaded', function () {
const sceneEl = document.querySelector('a-scene');
if (sceneEl.hasLoaded) { initializeWorld(); } else { sceneEl.addEventListener('loaded', initializeWorld, {once: true}); }
const MAZE_GRID_SIZE = 99;
const MAZE_CELL_SIZE = 4;
const WALL_HEIGHT = 8;
function initializeWorld() {
console.log("Generating maze data...");
const mazeData = generateMazeData(MAZE_GRID_SIZE);
console.log("Creating 3D maze from data...");
create3DMaze(mazeData);
setPlayerStartPosition();
createSpheres();
}
function generateMazeData(gridSize) {
let ary = Array.from({ length: gridSize }, () => Array(gridSize).fill(0));
for (let i = 0; i < gridSize; i++) { ary[i][0] = 1; ary[i][gridSize - 1] = 1; ary[0][i] = 1; ary[gridSize - 1][i] = 1; }
for (let i = 1; i < (gridSize - 1) / 2; i++) {
for (let j = 1; j < (gridSize - 1) / 2; j++) {
const x = i * 2; const y = j * 2; ary[x][y] = 1;
const isStartArea = (i === 1 && j === 1);
let ranten;
if (isStartArea) { ranten = Math.random() < 0.5 ? 0 : 2; } else { ranten = Math.floor(Math.random() * 4); }
if (ranten === 0) { ary[x + 1][y] = 1; } else if (ranten === 1) { ary[x - 1][y] = 1; } else if (ranten === 2) { ary[x][y + 1] = 1; } else if (ranten === 3) { ary[x][y - 1] = 1; }
}
}
return ary;
}
function create3DMaze(mazeData) {
const gridSize = mazeData.length; const offset = (gridSize - 1) / 2;
for (let i = 0; i < gridSize; i++) {
for (let j = 0; j < gridSize; j++) {
if (mazeData[i][j] === 1) {
const wall = document.createElement('a-box');
const x = (i - offset) * MAZE_CELL_SIZE; const y = WALL_HEIGHT / 2; const z = (j - offset) * MAZE_CELL_SIZE;
wall.setAttribute('position', {x: x, y: y, z: z});
wall.setAttribute('width', MAZE_CELL_SIZE); wall.setAttribute('height', WALL_HEIGHT); wall.setAttribute('depth', MAZE_CELL_SIZE);
wall.setAttribute('color', '#A0522D'); wall.setAttribute('material', { roughness: 0.8 });
wall.setAttribute('shadow', 'cast: true; receive: false'); wall.classList.add('maze-wall');
wall.setAttribute('static-body', 'friction: 0.2');
sceneEl.appendChild(wall);
}
}
}
console.log("3D maze created.");
}
function setPlayerStartPosition() {
const rigEl = document.getElementById('rig');
const gridSize = MAZE_GRID_SIZE;
const offset = (gridSize - 1) / 2;
const startGridX = 1;
const startGridZ = 1;
const startWorldX = (startGridX - offset) * MAZE_CELL_SIZE;
const startWorldZ = (startGridZ - offset) * MAZE_CELL_SIZE;
rigEl.setAttribute('position', `${startWorldX} 1.6 ${startWorldZ}`);
}
function createSpheres() {
const numberOfSpheres = 30; const spawnRadius = MAZE_GRID_SIZE / 2 * MAZE_CELL_SIZE * 1.1;
for (let i = 0; i < numberOfSpheres; i++) {
const sphereEl = document.createElement('a-sphere');
const radius = Math.random() * 3 + 0.5;
const angle = Math.random() * Math.PI * 2; const distance = spawnRadius + Math.random() * 50;
const x = Math.cos(angle) * distance; const z = Math.sin(angle) * distance; const y = radius;
const color = `hsl(${Math.random() * 360}, 70%, 50%)`;
sphereEl.setAttribute('position', {x: x, y: y, z: z});
sphereEl.setAttribute('radius', radius); sphereEl.setAttribute('color', color); sphereEl.setAttribute('shadow', 'cast: true');
sceneEl.appendChild(sphereEl);
}
}
});
</script>
</a-scene>
</body>
</html>
使用変数
-------( Function ) | |
angle | |
ary | |
background | |
body | |
camera | |
color | |
controls | |
create3DMaze -------( Function ) | |
createSpheres -------( Function ) | |
cursor | |
depth | |
distance | |
generateMazeData -------( Function ) | |
geometry | |
gridSize | |
height | |
i | |
id | |
initializeWorld -------( Function ) | |
isStartArea | |
j | |
light | |
material | |
mazeData | |
MAZE_CELL_SIZE | |
MAZE_GRID_SIZE | |
numberOfSpheres | |
offset | |
physics | |
position | |
radius | |
ranten | |
raycaster | |
rigEl | |
sceneEl | |
setPlayerStartPosition -------( Function ) | |
shadow | |
spawnRadius | |
sphereEl | |
src | |
startGridX | |
startGridZ | |
startWorldX | |
startWorldZ | |
ui | |
wall | |
WALL_HEIGHT | |
width | |
x | |
y | |
z |