O inventário é essencial para RPGs e jogos de sobrevivência no Roblox. Falhas de design causam duplicação de itens e atrasos em dispositivos móveis.
Usando validação centralizada no servidor, estruturas modulares e bloqueio de sessão no DataStore, desenvolvedores constroem economias protegidas e altamente responsivas.
1. Modelos de Inventário: Slots Fixos vs. Grade Espacial vs. Peso
Escolhendo a arquitetura ideal para a dinâmica do jogo:
- Slots Fixos: Modelo clássico de barra rápida com índices pré-definidos. Operações em O(1) e fácil serialização.
- Grade Espacial (Tetris): Itens ocupam múltiplas células estilo Diablo, exigindo cálculo de colisão 2D.
- Limite de Peso: O acúmulo de massa reduz progressivamente a velocidade de corrida e estamina.
2. Autoridade do Servidor & Interface Otimista
Interações imediatas com máxima segurança:
- Previsão de UI Otimista: O ícone se move localmente na hora, sem aguardar resposta de rede do servidor.
- Validação no Servidor: Checagem de propriedade, peso e limites antes de efetivar a mudança.
- Reversão Transparente: Transações inválidas provocam retorno suave do item à posição anterior.
3. Estruturas de Dados e Serialização de Pilhas
Organização eficiente de propriedades em Luau:
- Modelo Base vs. Instância: Nomes e pesos base em ReplicatedStorage, UUID e durabilidade salvos no jogador.
- Fusão de Pilhas: Cálculo de espaço livre e transferência atômica de quantidades.
- Compressão de Armazenamento: Descarte de slots vazios para respeitar o teto de 4MB do DataStore.
-- Gerenciador de Inventário com Autoridade de Servidor
local InventoryManager = {}
InventoryManager.__index = InventoryManager
local ItemDatabase = require(game.ReplicatedStorage.ItemDatabase)
function InventoryManager.new(player, maxSlots, maxWeight)
local self = setmetatable({}, InventoryManager)
self.Player = player
self.MaxSlots = maxSlots or 30
self.MaxWeight = maxWeight or 100
self.Slots = table.create(self.MaxSlots, false)
self.CurrentWeight = 0
self.IsLocked = false
return self
end
function InventoryManager:AddItem(itemId, amount)
if self.IsLocked then return false, "INVENTORY_LOCKED" end
local itemData = ItemDatabase[itemId]
if not itemData then return false, "INVALID_ITEM" end
local addedWeight = itemData.Weight * amount
if self.CurrentWeight + addedWeight > self.MaxWeight then
return false, "OVER_ENCUMBERED"
end
for slotIndex = 1, self.MaxSlots do
local slot = self.Slots[slotIndex]
if slot and slot.Id == itemId and slot.Count < itemData.MaxStack then
local space = itemData.MaxStack - slot.Count
local toAdd = math.min(space, amount)
slot.Count = slot.Count + toAdd
amount = amount - toAdd
self.CurrentWeight = self.CurrentWeight + (itemData.Weight * toAdd)
if amount <= 0 then return true end
end
end
for slotIndex = 1, self.MaxSlots do
if not self.Slots[slotIndex] then
self.Slots[slotIndex] = {
UUID = game:GetService("HttpService"):GenerateGUID(false),
Id = itemId,
Count = amount,
Durability = itemData.MaxDurability
}
self.CurrentWeight = self.CurrentWeight + (itemData.Weight * amount)
return true
end
end
return false, "INVENTORY_FULL"
end
return InventoryManager
4. Proteção Anti-Duplicação e Bloqueio de Sessão
Prevenção contra desconexões forçadas e trocas fraudulentas:
- Bloqueio no MemoryStore: Chave distribuída temporária que impede operações concorrentes.
- Trocas Atômicas: Troca executada em um único quadro de servidor ou cancelamento geral se alguém cair.
- Limite de Requisições: Intervalo mínimo de 100ms para evitar sobrecarga maliciosa de pacotes.
5. Experiência Tátil em Dispositivos Móveis
Navegação fluida em celulares e tablets:
- Áreas de Toque de pelo menos 44px: Ajuste de escala dinâmico para facilitar toques com os dedos.
- Menus Radiais por Toque Longo: Solução para substituir o botão direito em telas sensíveis.
- Feedback Háptico: Vibrações sutis via HapticService ao equipar ou soltar itens.
Frequently Asked Questions
Por que a lógica de inventário deve rodar no servidor?
Processamento no cliente facilita manipulação de dados e duplicação de itens raros.
Como a interface otimista melhora a resposta?
O item se move na tela no mesmo instante, sendo corrigido apenas se o servidor rejeitar a ação.
O que é bloqueio de sessão no DataStore?
Garante que apenas uma instância de servidor salve dados do jogador simultaneamente, prevenindo clonagem.
Como evitar falhas ao arrastar itens no celular?
Movendo um clone visual durante o toque e validando a posição do slot apenas ao soltar o dedo.