476 lines
26 KiB
HTML
476 lines
26 KiB
HTML
<!DOCTYPE html><html lang="en-us"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><meta http-equiv="X-UA-Compatible" content="IE=edge"><base href="/"><script>window.ENABLE_ADS = true;</script><title>2v2.io | Building Simulator, Battle Royale Shooting Game</title><meta name="description" content="2v2.io is a building simulator and battle royale shooting game. Team up, build fast, and outgun rivals to be the last squad standing. Play free online now!"><meta name="keywords" content="2v2.io, FPS io game, 2v2 io, 2v2 io game, online FPS, io games, 2v2, 2v2 io online game, multiplayer FPS"><meta name="author" content="Legion Platforms"><meta name="robots" content="index, follow"><meta name="theme-color" content="#0a0a0a"><meta name="touch-action" content="manipulation"><link rel="dns-prefetch" href="https://files.2v2.io/"><link rel="canonical" href="https://2v2.io/"><link rel="icon" href="https://2v2.io/favicon/favicon.ico" type="image/x-icon"><meta property="og:type" content="website"><meta property="og:title" content="2v2.io | Building Simulator, Battle Royale Shooting Game"><meta property="og:description" content="2v2.io is a building simulator and battle royale shooting game. Team up, build fast, and outgun rivals to be the last squad standing. Play free online now!"><meta property="og:image" content="https://2v2.io/background-og.webp"><meta property="og:image:type" content="image/webp"><meta property="og:image:secure_url" content="https://2v2.io/background-og.webp"><meta property="og:image:width" content="1280"><meta property="og:image:height" content="720"><meta property="og:image:alt" content="2v2.io browser FPS game"><meta property="og:url" content="https://2v2.io"><meta property="og:site_name" content="2v2.io"><meta property="og:locale" content="en_US"><meta property="og:updated_time" content="2025-05-08T12:00:00Z"><meta property="og:determiner" content="the"><script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
|
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
|
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
|
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
|
})(window,document,'script','dataLayer','GTM-TRWMG587');</script><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="2v2.io | Building Simulator, Battle Royale Shooting Game"><meta name="twitter:description" content="2v2.io is a building simulator and battle royale shooting game. Team up, build fast, and outgun rivals to be the last squad standing. Play free online now!"><meta name="twitter:image" content="https://2v2.io/background-og.webp"><meta name="twitter:image:alt" content="2v2.io browser FPS game"><meta name="twitter:site" content="@2v2"><script async src="https://www.googletagmanager.com/gtag/js?id=G-ECPGZRERZQ"></script><script>window.dataLayer = window.dataLayer || [];
|
|
function gtag(){dataLayer.push(arguments);}
|
|
gtag('js', new Date());
|
|
|
|
gtag('config', 'G-ECPGZRERZQ');</script><meta property="og:video" content="https://www.youtube.com/embed/gnHtAXm_ssk"><meta property="og:video:type" content="text/html"><meta property="og:video:width" content="1280"><meta property="og:video:height" content="720"><meta property="og:video:secure_url" content="https://www.youtube.com/embed/zAq8leZVH5c"><meta property="og:video:tag" content="2v2.io, FPS io game, 2v2 io, 2v2 io game, online FPS, io games, 2v2, 2v2 io online game, multiplayer FPS"><meta content="#1d9ae7" data-react-helmet="true" name="theme-color"><meta name="rating" content="general"><meta name="distribution" content="global"><link rel="alternate" hreflang="en" href="https://2v2.io/"><link rel="alternate" hreflang="x-default" href="https://2v2.io/"><script type="application/ld+json">{
|
|
"@context": "https://schema.org",
|
|
"@type": "VideoGame",
|
|
"name": "2v2.io",
|
|
"description": "2v2.io is a building simulator and battle royale shooting game. Team up, build fast, and outgun rivals to be the last squad standing. Play free online now!",
|
|
"image": "https://2v2.io/background-og.webp",
|
|
"author": {
|
|
"@type": "Organization",
|
|
"name": "Legion Platforms"
|
|
},
|
|
"url": "https://2v2.io",
|
|
"genre": ["Action", "Multiplayer", "Minecraft", "Shooter", "Free", ".io", "FPS"],
|
|
"keywords": "2v2, 2v2.io, 2v2, Online Game, Free to Play, 2v2.io, FPS io game, 2v2 io, 2v2 io game, online FPS, io games, 2v2, 2v2 io online game, multiplayer FPS",
|
|
"publisher": {
|
|
"@type": "Organization",
|
|
"name": "Legion Platforms"
|
|
},
|
|
"aggregateRating": {
|
|
"@type": "AggregateRating",
|
|
"ratingValue": "4.8",
|
|
"reviewCount": "500000"
|
|
},
|
|
"sameAs": [
|
|
"https://www.facebook.com/2v2",
|
|
"https://twitter.com/2v2",
|
|
"https://www.instagram.com/2v2"
|
|
]
|
|
}</script><script type="application/ld+json" id="website-jsonld">{
|
|
"@context": "https://schema.org",
|
|
"@type": "WebSite",
|
|
"url": "https://2v2.io/",
|
|
"name": "2v2.io",
|
|
"potentialAction": {
|
|
"@type": "SearchAction",
|
|
"target": "https://2v2.io/search?q={search_term_string}",
|
|
"query-input": "required name=search_term_string"
|
|
}
|
|
}</script><script type="application/ld+json" id="org-jsonld">{
|
|
"@context": "https://schema.org",
|
|
"@type": "Organization",
|
|
"name": "Legion Platforms",
|
|
"url": "https://2v2.io",
|
|
"logo": "https://2v2.io/favicon/android-chrome-512x512.png",
|
|
"sameAs": [
|
|
"https://www.facebook.com/2v2",
|
|
"https://twitter.com/2v2",
|
|
"https://www.instagram.com/2v2"
|
|
]
|
|
}</script><link rel="preload" href="main.css" as="style" onload="this.rel='stylesheet'"><noscript><link rel="stylesheet" href="main.css"></noscript><link rel="preload" href="logo.webp" as="image" fetchpriority="high"><style>@media only screen and (max-width: 768px) {
|
|
body {
|
|
overflow: hidden;
|
|
}
|
|
}</style><meta name="mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"><meta name="apple-mobile-web-app-title" content="2v2.io"><meta name="application-name" content="2v2.io"><meta name="format-detection" content="telephone=no"><link rel="manifest" href="manifest.json"><link rel="apple-touch-startup-image" href="/splash/apple-splash-1125x2436.png" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3)"><link rel="dns-prefetch" href="//www.google-analytics.com"><link rel="preconnect" href="https://www.google-analytics.com" crossorigin><link rel="preconnect" href="https://2v2.io" crossorigin><link rel="preconnect" href="https://files.2v2.io" crossorigin><link rel="preconnect" href="https://www.googletagmanager.com" crossorigin><link rel="preconnect" href="https://www.youtube.com" crossorigin><meta http-equiv="Permissions-Policy" content="accelerometer=(), camera=(), microphone=(), geolocation=()"><link rel="sitemap" type="application/xml" title="Sitemap" href="https://2v2.io/sitemap.xml"><meta name="robots" content="index, follow"><meta name="googlebot" content="index, follow"><meta name="msvalidate.01" content="CA12CDD2C731B36A8DF91876E3CD78F3"><meta property="og:see_also" content="https://www.youtube.com/@2v2"><meta property="og:see_also" content="https://twitter.com/2v2"><meta property="og:see_also" content="https://www.instagram.com/2v2"><meta property="og:see_also" content="https://www.facebook.com/2v2"><meta http-equiv="Cache-Control" content="public, max-age=600"><meta name="msapplication-TileColor" content="#2d3030"><meta name="msapplication-config" content="https://2v2.io/browserconfig.xml"><link rel="icon" sizes="192x192" href="https://2v2.io/favicon/android-chrome-192x192.png"><link rel="icon" sizes="512x512" href="https://2v2.io/favicon/android-chrome-512x512.png"><link rel="apple-touch-icon" href="https://2v2.io/favicon/apple-touch-icon.png"><script>const url = window.location.href;
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
var unityLoadingIsSDKDependant = false;
|
|
let sdkScriptSrc = "sdk.js";
|
|
|
|
// Check query parameters first (more robust), then fallback to URL substring matching
|
|
if (url.includes("discord")) {
|
|
sdkScriptSrc = "discord_sdk.js";
|
|
unityLoadingIsSDKDependant = true;
|
|
} else if (urlParams.has("cg") || url.includes("crazygames")) {
|
|
window.ENABLE_ADS = false;
|
|
sdkScriptSrc = "cg_sdk.js";
|
|
// } else if (urlParams.has("poki") || url.includes("poki-gdn.com") || url.includes(".poki.")) {
|
|
// sdkScriptSrc = "poki_sdk.js";
|
|
} else if (urlParams.has("yandex") || url.includes("/yandex")) {
|
|
// Add Yandex SDK detection
|
|
sdkScriptSrc = "yandex_sdk.js";
|
|
} else if (urlParams.has("msn") || url.includes("/msn")) {
|
|
// Microsoft Start integration
|
|
sdkScriptSrc = "msn_sdk.js";
|
|
}
|
|
const sdkScript = document.createElement("script");
|
|
sdkScript.src = `${sdkScriptSrc}?v=8`; // update this when any sdk updates
|
|
document.head.appendChild(sdkScript);
|
|
|
|
|
|
function waitForSDKThenStart(callback) {
|
|
const maxWait = 10000; //ms
|
|
const interval = 10; //ms
|
|
let waited = 0;
|
|
|
|
if (!unityLoadingIsSDKDependant) {
|
|
callback();
|
|
return;
|
|
}
|
|
|
|
const check = () => {
|
|
if (window.SDK && typeof window.SDK.getBuildURL === "function") {
|
|
callback();
|
|
} else if (waited >= maxWait) {
|
|
console.warn("SDK not available in time, proceeding anyway.");
|
|
callback();
|
|
} else {
|
|
waited += interval;
|
|
setTimeout(check, interval);
|
|
}
|
|
};
|
|
check();
|
|
}</script><script>(function () {
|
|
function canonicalHrefFor(locationObj) {
|
|
return locationObj.origin + locationObj.pathname; // ignore query/fragment for canonical
|
|
}
|
|
|
|
function setCanonicalAndOgUrl() {
|
|
var href = canonicalHrefFor(window.location);
|
|
var canonical = document.querySelector('link[rel="canonical"]');
|
|
if (!canonical) {
|
|
canonical = document.createElement('link');
|
|
canonical.setAttribute('rel', 'canonical');
|
|
document.head.appendChild(canonical);
|
|
}
|
|
canonical.setAttribute('href', href);
|
|
|
|
var ogUrl = document.querySelector('meta[property="og:url"]');
|
|
if (ogUrl) ogUrl.setAttribute('content', href);
|
|
}
|
|
|
|
setCanonicalAndOgUrl();
|
|
|
|
var _ps = history.pushState;
|
|
history.pushState = function () { _ps.apply(history, arguments); setCanonicalAndOgUrl(); };
|
|
var _rs = history.replaceState;
|
|
history.replaceState = function () { _rs.apply(history, arguments); setCanonicalAndOgUrl(); };
|
|
window.addEventListener('popstate', setCanonicalAndOgUrl);
|
|
})();</script><script>(function () {
|
|
function toTitleCase(text) {
|
|
return text.replace(/[-_]+/g, ' ').replace(/\b\w/g, function (c) { return c.toUpperCase(); });
|
|
}
|
|
|
|
function injectBreadcrumbs() {
|
|
var path = window.location.pathname.replace(/\/$/, '');
|
|
if (path === '' || path === '/') {
|
|
var existingHome = document.getElementById('breadcrumbs-jsonld');
|
|
if (existingHome) existingHome.remove();
|
|
return;
|
|
}
|
|
|
|
var items = [ { name: 'Home', url: window.location.origin + '/' } ];
|
|
|
|
if (path === '/shop') {
|
|
items.push({ name: 'Shop', url: window.location.origin + '/shop' });
|
|
} else if (path === '/inventory') {
|
|
items.push({ name: 'Inventory', url: window.location.origin + '/inventory' });
|
|
} else if (path === '/classes') {
|
|
items.push({ name: 'Classes', url: window.location.origin + '/classes' });
|
|
} else if (path === '/play-with-friends') {
|
|
items.push({ name: 'Play With Friends', url: window.location.origin + '/play-with-friends' });
|
|
} else if (path === '/servers') {
|
|
items.push({ name: 'Servers', url: window.location.origin + '/servers' });
|
|
} else if (path === '/settings') {
|
|
items.push({ name: 'Settings', url: window.location.origin + '/settings' });
|
|
} else if (path === '/login') {
|
|
items.push({ name: 'Login', url: window.location.origin + '/login' });
|
|
} else if (path === '/free') {
|
|
items.push({ name: 'Free', url: window.location.origin + '/free' });
|
|
} else if (/^\/profile\//.test(path)) {
|
|
var username = path.split('/').pop();
|
|
items.push({ name: 'Profile', url: window.location.origin + '/profile/' });
|
|
items.push({ name: username, url: window.location.origin + path });
|
|
} else if (/^\/inspect_/.test(path)) {
|
|
items.push({ name: 'Inspect Item', url: window.location.origin + path });
|
|
} else if (/^\/bundle_/.test(path)) {
|
|
items.push({ name: 'Bundle', url: window.location.origin + path });
|
|
} else {
|
|
var seg = path.split('/').pop();
|
|
items.push({ name: toTitleCase(seg), url: window.location.origin + path });
|
|
}
|
|
|
|
var breadcrumbs = {
|
|
'@context': 'https://schema.org',
|
|
'@type': 'BreadcrumbList',
|
|
'itemListElement': items.map(function (item, index) {
|
|
return {
|
|
'@type': 'ListItem',
|
|
'position': index + 1,
|
|
'name': item.name,
|
|
'item': item.url
|
|
};
|
|
})
|
|
};
|
|
|
|
var existing = document.getElementById('breadcrumbs-jsonld');
|
|
if (existing) existing.remove();
|
|
var script = document.createElement('script');
|
|
script.type = 'application/ld+json';
|
|
script.id = 'breadcrumbs-jsonld';
|
|
script.text = JSON.stringify(breadcrumbs);
|
|
document.head.appendChild(script);
|
|
}
|
|
|
|
injectBreadcrumbs();
|
|
var _ps = history.pushState;
|
|
history.pushState = function () { _ps.apply(history, arguments); injectBreadcrumbs(); };
|
|
var _rs = history.replaceState;
|
|
history.replaceState = function () { _rs.apply(history, arguments); injectBreadcrumbs(); };
|
|
window.addEventListener('popstate', injectBreadcrumbs);
|
|
})();</script><script>(function () {
|
|
var routeToMeta = {
|
|
'/': {
|
|
title: '2v2.io | Building Simulator, Battle Royale Shooting Game',
|
|
description: '2v2.io is a building simulator and battle royale shooting game. Team up, build fast, and outgun rivals to be the last squad standing. Play free online now!'
|
|
},
|
|
'/shop': {
|
|
title: '2v2.io Shop | Items, Bundles & Cosmetics',
|
|
description: 'Browse the 2v2.io shop to unlock skins, bundles, and cosmetics. Earn, purchase, and equip items to stand out in battle.'
|
|
},
|
|
'/inventory': {
|
|
title: '2v2.io Inventory | Manage Your Skins & Items',
|
|
description: 'View and manage your unlocked items, skins, and cosmetics for 2v2.io. Equip your favorites and jump back into action.'
|
|
},
|
|
'/classes': {
|
|
title: '2v2.io Classes | Choose Your Playstyle',
|
|
description: 'Discover 2v2.io classes and tailor your loadout to your preferred playstyle.'
|
|
},
|
|
'/play-with-friends': {
|
|
title: '2v2.io | Play With Friends',
|
|
description: 'Create or join rooms and play 2v2.io with friends. Share your room code to squad up quickly.'
|
|
},
|
|
'/servers': {
|
|
title: '2v2.io Servers | Regions & Matchmaking',
|
|
description: 'Pick the best 2v2.io server region for lower ping and better matchmaking.'
|
|
},
|
|
'/settings': {
|
|
title: '2v2.io Settings | Controls & Graphics',
|
|
description: 'Tune your controls, graphics, and gameplay settings for the best 2v2.io experience.'
|
|
},
|
|
'/login': {
|
|
title: 'Login | 2v2.io',
|
|
description: 'Log in to your 2v2.io account to sync progress and items.'
|
|
},
|
|
'/free': {
|
|
title: 'Free Rewards | 2v2.io',
|
|
description: 'Claim your free rewards and bonuses in 2v2.io.'
|
|
}
|
|
};
|
|
|
|
function setMeta(meta) {
|
|
if (!meta) return;
|
|
if (meta.title) document.title = meta.title;
|
|
var desc = document.querySelector('meta[name="description"]');
|
|
if (desc && meta.description) desc.setAttribute('content', meta.description);
|
|
var ogTitle = document.querySelector('meta[property="og:title"]');
|
|
if (ogTitle && meta.title) ogTitle.setAttribute('content', meta.title);
|
|
var twTitle = document.querySelector('meta[name="twitter:title"]');
|
|
if (twTitle && meta.title) twTitle.setAttribute('content', meta.title);
|
|
var ogDesc = document.querySelector('meta[property="og:description"]');
|
|
if (ogDesc && meta.description) ogDesc.setAttribute('content', meta.description);
|
|
var twDesc = document.querySelector('meta[name="twitter:description"]');
|
|
if (twDesc && meta.description) twDesc.setAttribute('content', meta.description);
|
|
}
|
|
|
|
function updateRouteMeta() {
|
|
var path = window.location.pathname.replace(/\/$/, '') || '/';
|
|
var meta = routeToMeta[path];
|
|
|
|
// Pattern routes
|
|
if (!meta) {
|
|
if (/^\/inspect_/.test(path)) {
|
|
meta = {
|
|
title: 'Inspect Item | 2v2.io',
|
|
description: 'View item details and shareable links in 2v2.io.'
|
|
};
|
|
} else if (/^\/bundle_/.test(path)) {
|
|
meta = {
|
|
title: 'Bundle | 2v2.io',
|
|
description: 'Preview and purchase bundles in the 2v2.io shop.'
|
|
};
|
|
} else if (/^\/profile\//.test(path)) {
|
|
var username = path.split('/').pop();
|
|
meta = {
|
|
title: username ? (username + ' | Profile | 2v2.io') : 'Profile | 2v2.io',
|
|
description: 'View player profiles and stats in 2v2.io.'
|
|
};
|
|
}
|
|
}
|
|
|
|
setMeta(meta);
|
|
}
|
|
|
|
updateRouteMeta();
|
|
var _ps = history.pushState;
|
|
history.pushState = function () { _ps.apply(history, arguments); updateRouteMeta(); };
|
|
var _rs = history.replaceState;
|
|
history.replaceState = function () { _rs.apply(history, arguments); updateRouteMeta(); };
|
|
window.addEventListener('popstate', updateRouteMeta);
|
|
})();</script></head><body style="background-color: black; color: black;"><div id="videoad"></div><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-TRWMG587" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript><div id="unity-container"><canvas id="unity-canvas"></canvas></div><div id="unity-loading-container"><div id="loading-percentage">1%</div><img src="logo.webp" class="logo" alt="2v2.io Logo" decoding="async" fetchpriority="high"><div id="unity-loading-bar"><div id="unity-loading-bar-inner"></div></div></div><script type="application/ld+json" id="faq-jsonld">{
|
|
"@context": "https://schema.org",
|
|
"@type": "FAQPage",
|
|
"mainEntity": [
|
|
{
|
|
"@type": "Question",
|
|
"name": "Is 2v2.io a free FPS game?",
|
|
"acceptedAnswer": { "@type": "Answer", "text": "Yes. 2v2.io is free to play in your browser with no download required." }
|
|
},
|
|
{
|
|
"@type": "Question",
|
|
"name": "Can I play 2v2.io with friends?",
|
|
"acceptedAnswer": { "@type": "Answer", "text": "Yes. Create a room in Play With Friends and share the code for others to join instantly." }
|
|
},
|
|
{
|
|
"@type": "Question",
|
|
"name": "Does 2v2.io have items and skins?",
|
|
"acceptedAnswer": { "@type": "Answer", "text": "You can unlock and equip skins, items, and bundles in the Shop and Inventory." }
|
|
}
|
|
]
|
|
}</script><script>// Safe build URL
|
|
function getSafeBuildURL() {
|
|
try {
|
|
if (typeof window.SDK?.getBuildURL === "function") {
|
|
return window.SDK.getBuildURL();
|
|
}
|
|
} catch (e) {
|
|
console.warn("SDK.getBuildURL failed:", e);
|
|
}
|
|
return "Build"; // fallback
|
|
}
|
|
|
|
// Safe Streaming Assets URL
|
|
function getSafeStreamingAssetsUrl() {
|
|
try {
|
|
if (typeof window.SDK?.getStreamingAssetsUrl === "function") {
|
|
return window.SDK.getStreamingAssetsUrl();
|
|
}
|
|
} catch (e) {
|
|
console.warn("SDK.getStreamingAssetsUrl failed:", e);
|
|
}
|
|
return "/StreamingAssets"; // fallback
|
|
}
|
|
|
|
// Safe Static Resolution Scale Multi
|
|
function getSafeStaticResolutionScaleMulti() {
|
|
try {
|
|
if (typeof window.SDK?.getStaticResolutionScaleMulti === "function") {
|
|
return window.SDK.getStaticResolutionScaleMulti();
|
|
}
|
|
} catch (e) {
|
|
console.warn("SDK.getStaticResolutionScaleMulti failed:", e);
|
|
}
|
|
return 1.00; // fallback
|
|
}
|
|
|
|
waitForSDKThenStart(() => {
|
|
var buildUrl = getSafeBuildURL();
|
|
var loaderUrl = buildUrl + "/6f378362abf9416ee1d09b1b8bba5e6a.loader.js";
|
|
// Determine if we're on mobile
|
|
var isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
|
|
|
var safeStaticResolutionScaleMulti = getSafeStaticResolutionScaleMulti();
|
|
var config = {
|
|
dataUrl: buildUrl + "/71a45c7b34a597f90c357bb1c4bac865.data.br",
|
|
frameworkUrl: buildUrl + "/2369d1a903ef1992e469da7cedc792de.framework.js.br",
|
|
codeUrl: buildUrl + "/66321962c8ffc3be6d5594e349d2ebb4.wasm.br",
|
|
streamingAssetsUrl: getSafeStreamingAssetsUrl(),
|
|
companyName: "LEGiON Platforms",
|
|
productName: "2v2.io",
|
|
productVersion: "15z70982016",
|
|
autoSyncPersistentDataPath: true,
|
|
devicePixelRatio: 1.0 * safeStaticResolutionScaleMulti // default value, will be updated below
|
|
};
|
|
|
|
// Default DPR based on platform
|
|
var defaultDPR = safeStaticResolutionScaleMulti * (isMobile ? 1.3 : 1.0);
|
|
// Attempt to read the ResolutionScale from localStorage
|
|
var lsValue = localStorage.getItem("ResolutionScale");
|
|
var parsedValue = parseFloat(lsValue);
|
|
// If localStorage contains a valid number, use it; otherwise use the default.
|
|
var finalResolutionScaleValue = !isNaN(parsedValue) ? parsedValue : defaultDPR;
|
|
config.devicePixelRatio = finalResolutionScaleValue;
|
|
|
|
if (isMobile) {
|
|
document.addEventListener('touchmove', function(event) {
|
|
if (event.scale !== 1) {
|
|
event.preventDefault();
|
|
}
|
|
}, { passive: false });
|
|
}
|
|
|
|
var canvas = document.querySelector("#unity-canvas");
|
|
var loadingContainer = document.querySelector("#unity-loading-container");
|
|
var loadingBar = document.querySelector("#unity-loading-bar-inner");
|
|
var loadingPercentageElem = document.querySelector("#loading-percentage");
|
|
|
|
//progress simulation for better UX
|
|
const minProg = 51;
|
|
const maxProg = 99;
|
|
var targetProgress = minProg;
|
|
|
|
function updateProgress() {
|
|
targetProgress += 0.12;
|
|
targetProgress = Math.min(Math.max(targetProgress, minProg), maxProg);
|
|
loadingBar.style.width = targetProgress + "%";
|
|
loadingPercentageElem.textContent = Math.floor(targetProgress) + "%";
|
|
}
|
|
|
|
// Start the interval to update progress every 100ms
|
|
var progressInterval = setInterval(updateProgress, 100);
|
|
|
|
if (window.SDK && typeof window.SDK.loadingStart === 'function') {
|
|
window.SDK.loadingStart();
|
|
}
|
|
|
|
function startUnity() {
|
|
createUnityInstance(canvas, config, function(progress) {
|
|
var actualProgress = Math.min(Math.max(progress * 100, minProg), maxProg);
|
|
if (actualProgress > targetProgress) {
|
|
targetProgress = actualProgress;
|
|
}
|
|
}).then(function(unityInstance) {
|
|
window.unityInstance = unityInstance;
|
|
|
|
if (window.SDK && typeof window.SDK.loadingEnd === 'function') {
|
|
window.SDK.loadingEnd();
|
|
}
|
|
|
|
// Ensure the loading bar fills to 100% smoothly
|
|
targetProgress = 100;
|
|
loadingBar.style.width = "100%";
|
|
loadingPercentageElem.textContent = "100%";
|
|
clearInterval(progressInterval);
|
|
loadingContainer?.remove();
|
|
}).catch(function(message) {
|
|
clearInterval(progressInterval);
|
|
console.error(message);
|
|
});
|
|
}
|
|
|
|
function loadUnityLoaderWithRetry(url, attempt, maxAttempts) {
|
|
var script = document.createElement("script");
|
|
var cacheBust = (url.indexOf('?') === -1 ? '?' : '&') + 'retry=' + attempt + '&t=' + Date.now();
|
|
script.src = url + cacheBust;
|
|
script.addEventListener('load', startUnity, { once: true });
|
|
script.addEventListener('error', function () {
|
|
console.warn("Unity loader failed (attempt", attempt, "of", maxAttempts, ")", url);
|
|
if (attempt < maxAttempts) {
|
|
var nextAttempt = attempt + 1;
|
|
var retryDelayMs = Math.min(1000 * attempt, 3000);
|
|
loadingPercentageElem.textContent = 'Retrying… (' + nextAttempt + '/' + maxAttempts + ')';
|
|
setTimeout(function () {
|
|
loadUnityLoaderWithRetry(url, nextAttempt, maxAttempts);
|
|
}, retryDelayMs);
|
|
} else {
|
|
clearInterval(progressInterval);
|
|
loadingBar.style.width = "100%";
|
|
loadingPercentageElem.textContent = 'Load failed. Please refresh.';
|
|
console.error("Unity loader failed after", maxAttempts, "attempts:", url);
|
|
}
|
|
}, { once: true });
|
|
document.body.appendChild(script);
|
|
}
|
|
|
|
if (typeof window.createUnityInstance === 'function') {
|
|
startUnity();
|
|
} else {
|
|
var existingLoader = document.querySelector('script[src="' + loaderUrl + '"]');
|
|
if (existingLoader) {
|
|
existingLoader.addEventListener('load', startUnity, { once: true });
|
|
} else {
|
|
loadUnityLoaderWithRetry(loaderUrl, 1, 3);
|
|
}
|
|
}
|
|
});</script><noscript>Please enable JavaScript to run this game! Learn how <a href="https://support.google.com/adsense/answer/12654" target="_blank" rel="noopener noreferrer">here</a>.</noscript><script src="s/cursor.js" defer="defer"></script><script src="s/pwa.js" defer="defer"></script><script src="s/utils.js" defer="defer"></script><script src="s/analytics.js" defer="defer"></script><script src="s/pinger.js" defer="defer"></script><script src="s/exit-intent.js" defer="defer"></script><script>if ('serviceWorker' in navigator) {
|
|
window.addEventListener('load', function() {
|
|
navigator.serviceWorker.register('s/sw.js');
|
|
});
|
|
}</script><script defer src="https://static.cloudflareinsights.com/beacon.min.js/vcd15cbe7772f49c399c6a5babf22c1241717689176015" integrity="sha512-ZpsOmlRQV6y907TI0dKBHq9Md29nnaEIPlkf84rnaERnq6zvWvPUqr2ft8M1aS28oN72PdrCzSjY4U6VaAw1EQ==" data-cf-beacon='{"version":"2024.11.0","token":"1bfb393b72344e7f9d5c2908cabe8ce9","r":1,"server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
|
|
</body></html> |