Files
rltn/loading-overlay.patch
2025-08-18 17:27:14 +03:00

151 lines
6.3 KiB
Diff
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

diff --git a/src/Game.js b/src/Game.js
--- a/src/Game.js
+++ b/src/Game.js
@@ -28,9 +28,12 @@ function Game({ avatarUrl, gender }) {
// 2) реф для группы «города»
const cityGroupRef = useRef(null);
// 3) реф для группы «интерьера»
const interiorGroupRef = useRef(null);
- const cleanupTimerRef = useRef(null);
+ const cleanupTimerRef = useRef(null);
+ // Глобальный менеджер прогресса загрузки (используем в GLTFLoader)
+ const loadingManagerRef = useRef(null);
+
// камеры
const orthoCamRef = useRef(null);
const fpCamRef = useRef(null);
const cameraRef = useRef(null);
const rendererRef = useRef(null);
@@ -347,6 +350,7 @@ function Game({ avatarUrl, gender }) {
}));
}, []);
//Телефон
+
const scene = new THREE.Scene();
const playerRef = useRef(null);
const cityMeshesRef = useRef([]);
const cityObjectsDataRef = useRef([]);
const loadedCityObjectsRef = useRef({});
@@ -744,6 +748,59 @@ function Game({ avatarUrl, gender }) {
if (!mount) {
console.log('[DEBUG] mountRef.current не определён!');
return;
}
+ // ─────────────────────────────────────────────
+ // Красивый загрузочный оверлей + LoadingManager
+ // ─────────────────────────────────────────────
+ let overlayEl = null, barEl = null, textEl = null;
+ function createLoadingOverlay() {
+ if (overlayEl) return;
+ overlayEl = document.createElement('div');
+ Object.assign(overlayEl.style, {
+ position: 'fixed', inset: '0', zIndex: 2000,
+ display: 'flex', flexDirection: 'column',
+ alignItems: 'center', justifyContent: 'center',
+ background: 'linear-gradient(135deg,#0f172a,#1e293b)',
+ color: '#fff', fontFamily: 'system-ui, Arial, sans-serif'
+ });
+ textEl = document.createElement('div');
+ Object.assign(textEl.style, {
+ fontSize: '24px', fontWeight: 700, opacity: 0.9, marginBottom: '16px'
+ });
+ textEl.textContent = 'Загрузка ресурсов...';
+ overlayEl.appendChild(textEl);
+ const barWrap = document.createElement('div');
+ Object.assign(barWrap.style, {
+ width: '320px', height: '10px',
+ background: 'rgba(255,255,255,0.15)',
+ borderRadius: '999px', overflow: 'hidden',
+ boxShadow: '0 6px 20px rgba(0,0,0,0.35)'
+ });
+ barEl = document.createElement('div');
+ Object.assign(barEl.style, {
+ width: '0%', height: '100%',
+ transition: 'width .15s ease',
+ background: 'linear-gradient(90deg,#22d3ee,#38bdf8,#60a5fa)'
+ });
+ barWrap.appendChild(barEl);
+ overlayEl.appendChild(barWrap);
+ const pct = document.createElement('div');
+ Object.assign(pct.style, { marginTop: '12px', fontSize: '14px', opacity: 0.8 });
+ pct.id = 'loadingPct';
+ pct.textContent = '0%';
+ overlayEl.appendChild(pct);
+ document.body.appendChild(overlayEl);
+ }
+ function updateLoadingOverlay(percent, text) {
+ if (!overlayEl) return;
+ const p = Math.max(0, Math.min(100, Math.round(percent || 0)));
+ if (barEl) barEl.style.width = p + '%';
+ const pct = overlayEl.querySelector('#loadingPct');
+ if (pct) pct.textContent = p + '%';
+ if (text && textEl) textEl.textContent = text;
+ }
+ function removeLoadingOverlay() {
+ if (!overlayEl) return;
+ overlayEl.style.transition = 'opacity .2s ease';
+ overlayEl.style.opacity = '0';
+ setTimeout(() => {
+ overlayEl && overlayEl.remove();
+ overlayEl = barEl = textEl = null;
+ }, 220);
+ }
+ // Общий менеджер загрузки (для GLTF/Texture и т.п.)
+ const loadingManager = new THREE.LoadingManager();
+ loadingManagerRef.current = loadingManager;
+ loadingManager.onStart = (_url, loaded, total) => {
+ createLoadingOverlay();
+ updateLoadingOverlay(total ? (loaded / total) * 100 : 5, 'Загрузка ресурсов...');
+ };
+ loadingManager.onProgress = (_url, loaded, total) => {
+ updateLoadingOverlay(total ? (loaded / total) * 100 : 50);
+ };
+ loadingManager.onLoad = () => {
+ updateLoadingOverlay(100, 'Инициализация сцены...');
+ setTimeout(removeLoadingOverlay, 150);
+ };
+
console.log(' useEffect начало');
const baseOffset = new THREE.Vector3(-200, 150, -200);
const planarDist = Math.hypot(baseOffset.x, baseOffset.z);
const radius = Math.hypot(planarDist, baseOffset.y);
@@ -825,8 +882,9 @@ function Game({ avatarUrl, gender }) {
socket.on('economy:inventory', setInventory);
socket.on('gameTime:update', ({ time }) => setGameTime(time));
- const gltfLoader = new GLTFLoader();
- const animLoader = new GLTFLoader();
+ // Лоадеры, учитывающиеся в прогрессе через loadingManagerRef
+ const gltfLoader = new GLTFLoader(loadingManagerRef.current || undefined);
+ const animLoader = new GLTFLoader(loadingManagerRef.current || undefined);
async function loadPlayerModel(avatarUrl) {
return new Promise((resolve, reject) => {
gltfLoader.load(avatarUrl, (gltf) => {
if (!gltf.scene) return reject('GLTF.scene отсутствует');
@@ -1168,6 +1226,18 @@ function Game({ avatarUrl, gender }) {
setSelectedHouse(null);
}
+ // Мини-лоадер при загрузке интерьеров (обёртка поверх loadInteriorScene)
+ const _origLoadInteriorScene = loadInteriorScene;
+ loadInteriorScene = async (interiorId) => {
+ try {
+ // показываем мини-оверлей на время подзагрузки интерьера
+ createLoadingOverlay();
+ updateLoadingOverlay(30, 'Загрузка интерьера...');
+ await _origLoadInteriorScene(interiorId);
+ } finally {
+ setTimeout(removeLoadingOverlay, 120);
+ }
+ };
+
function onMouseWheel(e) {
e.preventDefault();
const delta = -e.deltaY * 0.001;
if (e.ctrlKey) {