summaryrefslogtreecommitdiff
path: root/serve/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'serve/index.html')
-rw-r--r--serve/index.html42
1 files changed, 41 insertions, 1 deletions
diff --git a/serve/index.html b/serve/index.html
index f0105e3..32c195b 100644
--- a/serve/index.html
+++ b/serve/index.html
@@ -2342,9 +2342,11 @@ function tick(now) {
}
}
// interpolate other players' drones toward their latest state
+ myTrail.update(S.p, camera); // радужный хвост игрока
for (const id in peers) {
const p = peers[id];
p.group.position.lerp(p.tp, 0.2);
+ if (p.trail) p.trail.update(p.group.position, camera); // хвост пира
p.group.quaternion.slerp(p.tq, 0.25);
for (let i = 0; i < 4; i++) { p.discs[i].material.color.setHSL((p.h + i * 0.25) % 1, 1, 0.55); p.discs[i].rotation.z += dt * 12 * (p.rf[i] || 1) * (p.ts || 1); }
}
@@ -2412,6 +2414,43 @@ function makeLabel(text) {
const spr = new THREE.Sprite(new THREE.SpriteMaterial({ map: new THREE.CanvasTexture(cv), depthTest: false, transparent: true }));
spr.scale.set(9, 2.25, 1); return spr;
}
+// радужный светящийся исчезающий хвост (билборд-лента) за игроком
+function makeTrail() {
+ const N = 46;
+ const geo = new THREE.BufferGeometry();
+ const pos = new Float32Array(N * 2 * 3), col = new Float32Array(N * 2 * 3);
+ geo.setAttribute('position', new THREE.BufferAttribute(pos, 3));
+ geo.setAttribute('color', new THREE.BufferAttribute(col, 3));
+ const idx = [];
+ for (let i = 0; i < N - 1; i++) { const a = i * 2, b = a + 1, c = a + 2, d = a + 3; idx.push(a, b, c, b, d, c); }
+ geo.setIndex(idx);
+ const mat = new THREE.MeshBasicMaterial({ vertexColors: true, transparent: true, blending: THREE.AdditiveBlending, depthWrite: false, side: THREE.DoubleSide, opacity: 0.6 });
+ const mesh = new THREE.Mesh(geo, mat); mesh.frustumCulled = false; scene.add(mesh);
+ const hist = [], _d = new THREE.Vector3(), _v = new THREE.Vector3(), _off = new THREE.Vector3(), _c = new THREE.Color();
+ let hue = 0;
+ return {
+ mesh,
+ update(p, cam) {
+ hist.unshift(p.clone()); if (hist.length > N) hist.pop();
+ hue = (hue + 0.018) % 1;
+ for (let i = 0; i < N; i++) {
+ const h = hist[Math.min(i, hist.length - 1)], nx = hist[Math.min(i + 1, hist.length - 1)];
+ _d.subVectors(h, nx); if (_d.lengthSq() < 1e-6) _d.set(0, 0, 1); _d.normalize();
+ _v.subVectors(h, cam.position).normalize();
+ _off.crossVectors(_d, _v); if (_off.lengthSq() < 1e-6) _off.set(1, 0, 0); _off.normalize();
+ const fade = 1 - i / N, w = 0.5 + fade * 1.9, A = i * 6, B = A + 3;
+ pos[A] = h.x + _off.x * w; pos[A + 1] = h.y + _off.y * w; pos[A + 2] = h.z + _off.z * w;
+ pos[B] = h.x - _off.x * w; pos[B + 1] = h.y - _off.y * w; pos[B + 2] = h.z - _off.z * w;
+ _c.setHSL((hue + i / N) % 1, 1.0, 0.45); const f = fade * fade;
+ col[A] = _c.r * f; col[A + 1] = _c.g * f; col[A + 2] = _c.b * f;
+ col[B] = _c.r * f; col[B + 1] = _c.g * f; col[B + 2] = _c.b * f;
+ }
+ geo.attributes.position.needsUpdate = true; geo.attributes.color.needsUpdate = true;
+ }
+ };
+}
+const myTrail = makeTrail();
+
function makePeerDrone() {
const g = new THREE.Group();
g.add(new THREE.Mesh(new THREE.BoxGeometry(1.5, 0.4, 1.5), new THREE.MeshStandardMaterial({ color: 0x333842, roughness: 0.5 })));
@@ -2431,11 +2470,12 @@ function updatePeer(id, name, s) {
const d = makePeerDrone(); scene.add(d.group);
const lbl = makeLabel(name); lbl.position.set(0, 3.2, 0); d.group.add(lbl);
p = peers[id] = { group: d.group, discs: d.discs, label: lbl, tp: new THREE.Vector3(), tq: new THREE.Quaternion(), rf: [1, 1, 1, 1], h: 0 };
+ p.trail = makeTrail();
}
p.tp.set(s.x, s.y, s.z); if (s.q) p.tq.set(s.q[0], s.q[1], s.q[2], s.q[3]); p.rf = s.rf || [1, 1, 1, 1]; p.h = s.h || 0; p.ts = s.ts || 1;
if (s.dm && DRONES[s.dm]) p.group.scale.setScalar(DRONES[s.dm].scale); // peer видят твою модель по размеру
}
-function removePeer(id) { if (peers[id]) { scene.remove(peers[id].group); delete peers[id]; } }
+function removePeer(id) { if (peers[id]) { scene.remove(peers[id].group); if (peers[id].trail) scene.remove(peers[id].trail.mesh); delete peers[id]; } }
function connectMP() {
try {
const proto = location.protocol === 'https:' ? 'wss' : 'ws';