[gemini] Re-implement Rune Ring (Portal-Tethered) (#476) #496
60
app.js
60
app.js
@@ -821,6 +821,33 @@ function createPortal(config) {
|
|||||||
light.position.set(0, 3.5, 1);
|
light.position.set(0, 3.5, 1);
|
||||||
group.add(light);
|
group.add(light);
|
||||||
|
|
||||||
|
// Rune Ring (Portal-tethered)
|
||||||
|
const runeCount = 8;
|
||||||
|
const runeRingRadius = 4.5;
|
||||||
|
const runes = [];
|
||||||
|
for (let i = 0; i < runeCount; i++) {
|
||||||
|
const angle = (i / runeCount) * Math.PI * 2;
|
||||||
|
const runeGeo = new THREE.BoxGeometry(0.3, 0.8, 0.1);
|
||||||
|
const runeMat = new THREE.MeshStandardMaterial({
|
||||||
|
color: portalColor,
|
||||||
|
emissive: portalColor,
|
||||||
|
emissiveIntensity: 0.8,
|
||||||
|
transparent: true,
|
||||||
|
opacity: 0.7,
|
||||||
|
roughness: 0.2,
|
||||||
|
metalness: 0.5,
|
||||||
|
});
|
||||||
|
const rune = new THREE.Mesh(runeGeo, runeMat);
|
||||||
|
rune.position.set(
|
||||||
|
Math.cos(angle) * runeRingRadius,
|
||||||
|
4,
|
||||||
|
Math.sin(angle) * runeRingRadius
|
||||||
|
);
|
||||||
|
rune.rotation.y = angle + Math.PI / 2;
|
||||||
|
group.add(rune);
|
||||||
|
runes.push(rune);
|
||||||
|
}
|
||||||
|
|
||||||
// Label
|
// Label
|
||||||
const labelCanvas = document.createElement('canvas');
|
const labelCanvas = document.createElement('canvas');
|
||||||
labelCanvas.width = 512;
|
labelCanvas.width = 512;
|
||||||
@@ -860,7 +887,8 @@ function createPortal(config) {
|
|||||||
ring,
|
ring,
|
||||||
swirl,
|
swirl,
|
||||||
pSystem,
|
pSystem,
|
||||||
light
|
light,
|
||||||
|
runes
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -986,20 +1014,7 @@ function createAmbientStructures() {
|
|||||||
scene.add(crystal);
|
scene.add(crystal);
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let i = 0; i < 5; i++) {
|
|
||||||
const angle = (i / 5) * Math.PI * 2;
|
|
||||||
const r = 10;
|
|
||||||
const geo = new THREE.OctahedronGeometry(0.4, 0);
|
|
||||||
const mat = new THREE.MeshStandardMaterial({
|
|
||||||
color: NEXUS.colors.primary,
|
|
||||||
emissive: NEXUS.colors.primary,
|
|
||||||
emissiveIntensity: 0.5,
|
|
||||||
});
|
|
||||||
const stone = new THREE.Mesh(geo, mat);
|
|
||||||
stone.position.set(Math.cos(angle) * r, 5 + Math.sin(i * 1.3) * 1.5, Math.sin(angle) * r);
|
|
||||||
stone.name = 'runestone_' + i;
|
|
||||||
scene.add(stone);
|
|
||||||
}
|
|
||||||
|
|
||||||
const coreGeo = new THREE.IcosahedronGeometry(0.6, 2);
|
const coreGeo = new THREE.IcosahedronGeometry(0.6, 2);
|
||||||
const coreMat = new THREE.MeshPhysicalMaterial({
|
const coreMat = new THREE.MeshPhysicalMaterial({
|
||||||
@@ -1427,6 +1442,12 @@ function gameLoop() {
|
|||||||
positions[i * 3 + 1] += Math.sin(elapsed + i) * 0.002;
|
positions[i * 3 + 1] += Math.sin(elapsed + i) * 0.002;
|
||||||
}
|
}
|
||||||
portal.pSystem.geometry.attributes.position.needsUpdate = true;
|
portal.pSystem.geometry.attributes.position.needsUpdate = true;
|
||||||
|
|
||||||
|
// Animate runes
|
||||||
|
portal.runes.forEach((rune, i) => {
|
||||||
|
rune.position.y = 4 + Math.sin(elapsed * 2 + i * 0.5) * 0.2;
|
||||||
|
rune.rotation.z = elapsed * 0.8 + i;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Animate Vision Points
|
// Animate Vision Points
|
||||||
@@ -1463,14 +1484,7 @@ function gameLoop() {
|
|||||||
dustParticles.rotation.y = elapsed * 0.01;
|
dustParticles.rotation.y = elapsed * 0.01;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < 5; i++) {
|
|
||||||
const stone = scene.getObjectByName('runestone_' + i);
|
|
||||||
if (stone) {
|
|
||||||
stone.position.y = 5 + Math.sin(elapsed * 0.8 + i * 1.3) * 0.8;
|
|
||||||
stone.rotation.y = elapsed * 0.5 + i;
|
|
||||||
stone.rotation.x = elapsed * 0.3 + i * 0.7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const core = scene.getObjectByName('nexus-core');
|
const core = scene.getObjectByName('nexus-core');
|
||||||
if (core) {
|
if (core) {
|
||||||
|
|||||||
Reference in New Issue
Block a user