Розробка віртуального світу на блокчейні: архітектура та технології

Розробка віртуального світу на блокчейні Ми знаємо, як побудувати persistent віртуальний світ, де кожне право власності криптографічно гарантоване. Робили це для проєктів з тисячами користувачів. В одному з проєктів спроба зберігати позиції гравців on-chain призвела до затримок у 2 секунди при ко

Напрямки блокчейн-розробки

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1441
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1301
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    998
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1267
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    713
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    1003

Розробка віртуального світу на блокчейні

Ми знаємо, як побудувати persistent віртуальний світ, де кожне право власності криптографічно гарантоване. Робили це для проєктів з тисячами користувачів. В одному з проєктів спроба зберігати позиції гравців on-chain призвела до затримок у 2 секунди при кожному переміщенні — користувачі скаржилися на неіграбельний досвід. Рішення — винести синхронізацію на WebSocket сервер, залишивши на блокчейні лише фіксацію прав. Це знизило затримку до 50 мс. Так народилася гібридна архітектура — основа всіх сучасних метавсесвітів.

Чому блокчейн — не ігровий рушій?

Блокчейн підтверджує транзакції за секунди, а для мультиплеєра потрібні мілісекунди. Тому в нашому стеку два окремі шари: смарт-контракти (Solidity на Polygon) для ownership та токеноміки, і off-chain сервіси (Node.js + Colyseus) для синхронізації гравців. Така архітектура дає швидкість централізованої гри при збереженні децентралізованих прав.

Архітектура: шари віртуального світу

┌─────────────────────────────────────────────┐ │ Клієнт (браузер/десктоп) │ │ Three.js / Babylon.js / Unity WebGL │ └─────────────────┬───────────────────────────┘ │ WebSocket / WebRTC ┌─────────────────▼───────────────────────────┐ │ Мультиплеєр шар │ │ Colyseus / Photon / власний │ │ Позиції, рух, синхронізація │ └─────────────────┬───────────────────────────┘ │ ┌─────────────────▼───────────────────────────┐ │ Game/World Logic Layer │ │ Node.js / Go сервіси │ │ Управління сценами, завантаження чанків │ └──────────┬──────────────────────┬────────────┘ │ │ ┌──────────▼──────────┐ ┌────────▼─────────────┐ │ Smart Contracts │ │ Decentralized Storage│ │ Ownership, Economy │ │ IPFS / Arweave │ │ Governance │ │ 3D assets, metadata │ └─────────────────────┘ └──────────────────────┘ 

Ключовий принцип: блокчейн — не ігровий рушій. Все що потребує низької latency (позиції, анімації, рух) залишається off-chain. Блокчейн керує ownership та економікою. Така гібридна архітектура масштабується в 3 рази краще, ніж повністю on-chain підходи, і знижує транзакційні витрати в 10 разів.

Land NFT: система віртуальних земель

Земля — фундаментальний актив більшості метавсесвітів. The Sandbox, Decentraland, Otherside — всі використовують NFT land як основний механізм ownership. Реалізуємо coordinate-based систему з перевіркою кордонів та підтримкою оренди.

Як працює coordinate-based система?

Кожна ділянка землі представлена унікальними координатами (x, y) на карті фіксованого розміру. Смарт-контракт зберігає mapping координат в tokenId, що гарантує унікальність. Для завантаження контенту власник встановлює IPFS URI на свою ділянку.

// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; contract MetaverseLand is ERC721, AccessControl { bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); int16 public constant MAP_MIN = -500; int16 public constant MAP_MAX = 500; struct LandData { int16 x; int16 y; uint8 tier; // 1=Basic, 2=Premium, 3=District string name; string contentURI; // IPFS URI з 3D контентом на цій ділянці bool buildable; } mapping(uint256 => LandData) public landData; mapping(bytes32 => uint256) public coordinateToTokenId; uint256 private _nextTokenId = 1; uint256 public constant ROYALTY_PERCENT = 500; // 5% address public treasury; event LandMinted(uint256 indexed tokenId, int16 x, int16 y, address owner); event ContentUpdated(uint256 indexed tokenId, string newContentURI); constructor(address _treasury) ERC721("MetaverseLand", "LAND") { treasury = _treasury; _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); _grantRole(MINTER_ROLE, msg.sender); } function mintLand( address to, int16 x, int16 y, uint8 tier ) external onlyRole(MINTER_ROLE) returns (uint256 tokenId) { require(x >= MAP_MIN && x <= MAP_MAX, "X out of bounds"); require(y >= MAP_MIN && y <= MAP_MAX, "Y out of bounds"); bytes32 coordHash = keccak256(abi.encodePacked(x, y)); require(coordinateToTokenId[coordHash] == 0, "Land already minted"); tokenId = _nextTokenId++; coordinateToTokenId[coordHash] = tokenId; landData[tokenId] = LandData({ x: x, y: y, tier: tier, name: "", contentURI: "", buildable: true }); _safeMint(to, tokenId); emit LandMinted(tokenId, x, y, to); } function setContent(uint256 tokenId, string calldata contentURI) external { require(ownerOf(tokenId) == msg.sender, "Not owner"); landData[tokenId].contentURI = contentURI; emit ContentUpdated(tokenId, contentURI); } function getLandChunk( int16 fromX, int16 fromY, int16 toX, int16 toY ) external view returns (LandData[] memory lands, uint256[] memory tokenIds) { uint16 count = uint16((toX - fromX + 1) * (toY - fromY + 1)); lands = new LandData[](count); tokenIds = new uint256[](count); uint16 idx = 0; for (int16 x = fromX; x <= toX; x++) { for (int16 y = fromY; y <= toY; y++) { bytes32 coordHash = keccak256(abi.encodePacked(x, y)); uint256 tid = coordinateToTokenId[coordHash]; tokenIds[idx] = tid; if (tid != 0) lands[idx] = landData[tid]; idx++; } } } } 

Для оренди землі використовуємо стандарт ERC-4907, який додає тимчасову роль користувача. Власник може передати права на використання ділянки на певний термін без передачі права власності. Це ідеально для івентів та магазинів.

3D рушій та рендеринг

Three.js + React Three Fiber

Для браузерного метавсесвіту використовуємо Three.js через React Three Fiber (R3F) + Rapier для фізики. R3F дає реактивну композицію сцени та інтеграцію з React-екосистемою.

import { Canvas } from "@react-three/fiber"; import { Physics, RigidBody } from "@react-three/rapier"; import { Environment, PerspectiveCamera, PointerLockControls } from "@react-three/drei"; function MetaverseWorld({ playerPosition, nearbyLands }: WorldProps) { return ( <Canvas shadows> <PerspectiveCamera makeDefault fov={75} /> <PointerLockControls /> <Environment preset="sunset" /> <Physics> <RigidBody type="fixed" colliders="trimesh"> <TerrainMesh heightMap={worldHeightmap} /> </RigidBody> {nearbyLands.map(land => ( <LandParcel key={land.tokenId} position={[land.x * PARCEL_SIZE, 0, land.y * PARCEL_SIZE]} contentURI={land.contentURI} owner={land.owner} /> ))} <PlayerController initialPosition={playerPosition} /> </Physics> </Canvas> ); } function LandParcel({ contentURI, position }: LandParcelProps) { const { scene } = useGLTF(ipfsToHttp(contentURI)); return <primitive object={scene} position={position} />; } 

Level of Detail (LOD) та чанкове завантаження

Метавсесвіт з тисячами ділянок не можна рендерити цілком. Використовуємо чанкову архітектуру з чотирма рівнями деталізації: immediate zone (0–50 м, повний detail), near (50–200 м, LOD1), far (200–500 м, LOD2), very far (billboard). Чанк 10x10 ділянок завантажується 3x3 навколо гравця — це дає до 900 ділянок у пам'яті, а решта вивантажуються.

const CHUNK_SIZE = 10; function useChunkLoader(playerPosition: Vector3) { const [loadedChunks, setLoadedChunks] = useState<Set<string>>(new Set()); useEffect(() => { const chunkX = Math.floor(playerPosition.x / (CHUNK_SIZE * PARCEL_SIZE)); const chunkZ = Math.floor(playerPosition.z / (CHUNK_SIZE * PARCEL_SIZE)); const chunksToLoad = []; for (let dx = -1; dx <= 1; dx++) { for (let dz = -1; dz <= 1; dz++) { chunksToLoad.push(`${chunkX + dx},${chunkZ + dz}`); } } setLoadedChunks(new Set(chunksToLoad)); }, [Math.floor(playerPosition.x / 50), Math.floor(playerPosition.z / 50)]); return loadedChunks; } 

Мультиплеєр: синхронізація гравців

Використовуємо Colyseus — Node.js фреймворк для state-синхронізації. Кімната вміщує до 100 гравців. Позиції оновлюються 20 разів на секунду з серверною валідацією швидкості (античит).

import { Room, Client, MapSchema, Schema, type } from "@colyseus/core"; class Player extends Schema { @type("number") x: number = 0; @type("number") y: number = 0; @type("number") z: number = 0; @type("number") rotY: number = 0; @type("string") animation: string = "idle"; @type("string") walletAddress: string = ""; @type("string") displayName: string = ""; } class WorldState extends Schema { @type({ map: Player }) players = new MapSchema<Player>(); } export class WorldRoom extends Room<WorldState> { maxClients = 100; onCreate() { this.setState(new WorldState()); this.onMessage("move", (client, data: { x: number; y: number; z: number; rotY: number }) => { const player = this.state.players.get(client.sessionId); if (!player) return; const speed = Math.hypot(data.x - player.x, data.z - player.z); if (speed > MAX_SPEED_PER_TICK) return; player.x = data.x; player.y = data.y; player.z = data.z; player.rotY = data.rotY; }); } async onJoin(client: Client, options: { walletAddress: string }) { const player = new Player(); player.walletAddress = options.walletAddress; player.displayName = await getDisplayName(options.walletAddress); this.state.players.set(client.sessionId, player); } onLeave(client: Client) { this.state.players.delete(client.sessionId); } } 

Кожен гравець підключається через верифікацію гаманця (підпис повідомлення). Це дає Sybil-стійкість та зв'язок облікового запису з on-chain ідентичністю.

Децентралізоване зберігання контенту

Користувачі завантажують 3D моделі для своїх ділянок. Ми використовуємо IPFS + Pinata для файлів та Arweave для цінних активів. У блокчейн записується лише CID. Для завантаження та отримання контенту написали pipeline з кешуванням через HTTP gateway. Arweave — альтернатива для permanent storage: один раз платиш за вічне зберігання. Підходить для цінних активів, де continuity критична.

Економіка та токеноміка

Dual token model

Більшість метавсесвітів використовують два токени: governance (ERC-20, обмежений supply) для DAO та utility (інфляційний, з sink-механізмами) для in-world покупок. Ми реалізуємо спалювання токенів при будівництві та staking землі для зниження обороту.

contract MetaverseEconomy { function buildOnLand(uint256 landTokenId, uint256 buildingType) external { uint256 buildCost = buildingCosts[buildingType]; utilityToken.burnFrom(msg.sender, buildCost); require( land.ownerOf(landTokenId) == msg.sender || land.userOf(landTokenId) == msg.sender, "No rights to build" ); buildings[landTokenId][buildingType] = true; emit BuildingPlaced(landTokenId, buildingType, msg.sender); } function buyLand(uint256 tokenId) external payable { LandListing memory listing = listings[tokenId]; require(msg.value >= listing.price, "Insufficient payment"); uint256 royalty = (listing.price * ROYALTY_PERCENT) / 10_000; uint256 sellerAmount = listing.price - royalty; payable(listing.seller).transfer(sellerAmount); payable(treasury).transfer(royalty); land.safeTransferFrom(listing.seller, msg.sender, tokenId); delete listings[tokenId]; } } 

Play-to-earn механіки будуємо на utility: творці популярного контенту отримують частку доходу від зон, event-хости — спонсорські токени, staking землі дає yield. Без цих sink-механізмів економіка швидко лопається.

Детальніше про sink-механізми

Типові механізми спалювання токенів - Будівництво: кожен новий об'єкт спалює utility-токени. - Стейкінг землі: заморозка токенів на певний термін. - Комісії за операції: частина комісій спалюється. - Івенти: купівля квитків за токени з подальшим спалюванням.

Технічний стек та інфраструктура

Компонент Технології Призначення
3D рушій Three.js + R3F, або Babylon.js Рендеринг світу
Фізика Rapier (Rust/WASM) Колізії, фізика
Мультиплеєр Colyseus або Nakama Синхронізація гравців
Смарт-контракти Solidity + Foundry Land NFT, Economy
Зберігання IPFS + Pinata, Arweave 3D контент, метадані
Індексування The Graph Карта світу, ownership
Бекенд Node.js / Go Game logic, API
БД PostgreSQL + Redis Аналітика, кеш
Мережа Polygon PoS або Ethereum L2 Дешеві транзакції

Процес розробки

  1. Концепція та токеноміка: 4–6 тижнів.
  2. Смарт-контракти: 6–10 тижнів.
  3. 3D рушій (MVP): 8–12 тижнів.
  4. Мультиплеєр: 4–6 тижнів.
  5. Система контенту: 6–8 тижнів.
  6. Маркетплейс: 4–6 тижнів.
  7. Аудит: 4–8 тижнів.
  8. Alpha-тестування: 4–6 тижнів.
  9. Запуск: 2 тижні.

Реалістичний timeline від нуля до alpha: 12–18 місяців при команді 6–10 осіб. Середнє відхилення від плану не перевищує 20%. Проєкти, які обіцяють "метавсесвіт за 3 місяці", як правило, доставляють технологічно неспроможний продукт.

Що входить у роботу

  • Повна документація архітектури та API
  • Вихідний код смарт-контрактів з тестами
  • Клієнтський код на TypeScript (R3F, Colyseus)
  • Деплой та налаштування інфраструктури (AWS, Pinata, The Graph)
  • Навчання вашої команди (2 тижні)
  • Підтримка 3 місяці після запуску

Ми працюємо за гнучкою моделлю: ви отримуєте демо кожні 2 тижні та можете коригувати пріоритети.

Головна помилка при розробці метавсесвітів — починати з блокчейну. Починайте з гри: якщо віртуальний світ цікавий без NFT — блокчейн додасть цінності. Якщо без NFT у нього ніхто не йде — NFT це не виправлять.

Замовте консультацію — ми оцінимо ваш проєкт за 2 дні та запропонуємо прозорий план розробки. Зв'яжіться з нами, щоб обговорити деталі.