Menu
CoddyTech

Carregar ao Entrar

Lição 20 de 20 do curso Jogo Roblox: Simulador de Pets da Coddy.

Agora leia o salvamento quando o jogador entrar. GetAsync retorna o que SetAsync armazenou sob a chave, ou nil para um jogador que nunca salvou. Também pode falhar, então chame-o em um pcall, que retorna se funcionou e, em seguida, o valor:

local ok, saved = pcall(function()
	return saveStore:GetAsync(player.UserId)
end)
if ok and saved then
	print(saved.Coins)
end

Carregue depois de criar as pastas, para que os pets tenham uma pasta Pets onde possam ficar. Ignore qualquer nome salvo que não esteja em petInfo: um pet removido do jogo não deve impedir a entrada de um jogador.

challenge icon

Desafio

Difícil

Devolva aos jogadores o que eles salvaram.

  1. Em PlayerAdded, depois de criar a pasta Pets: local ok, saved = pcall(function() return saveStore:GetAsync(player.UserId) end).
  2. Se ok and saved: defina Coins como saved.Coins e o atributo Desert como saved.Desert.
  3. Para cada pet salvo em petInfo, givePet(player, pet.Name, pet.Equipped == true).

Pressione “Jogar”, choque um ovo, pressione Stop e depois pressione “Jogar” novamente: suas moedas e seus pets estarão de volta. Em seguida, pressione “Verificar”.

Experimente você mesmo

local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local RunService = game:GetService("RunService")
local DataStoreService = game:GetService("DataStoreService")
local Settings = require(game.ReplicatedStorage.Settings)

local remotes = game.ReplicatedStorage.Remotes
local piles = workspace.Piles
local petParts = workspace.PetParts
local saveStore = DataStoreService:GetDataStore("Pets")
local pileSpot = {} -- cada pilha -> o local onde ela está
local lastHit = {} -- cada jogador -> quando atacou pela última vez

print("A Meadow pile gives " .. Settings.PileValue .. " coins")

-- Settings.Pets por nome
local petInfo = {}
for _, info in Settings.Pets do
	petInfo[info.Name] = info
end

-- Um pet: um StringValue na pasta Pets do jogador que guarda seu nome, com
-- sua raridade e seu poder como atributos
local function givePet(player, name, equipped)
	local info = petInfo[name]
	local pet = Instance.new("StringValue")
	pet.Name = "Pet"
	pet.Value = name
	pet:SetAttribute("Rarity", info.Rarity)
	pet:SetAttribute("Power", info.Power)
	pet:SetAttribute("Equipped", equipped)
	pet.Parent = player.Pets
	return pet
end

-- quantos pets um jogador tem ativos
local function equippedCount(player)
	local count = 0
	for _, pet in player.Pets:GetChildren() do
		if pet:GetAttribute("Equipped") then
			count += 1
		end
	end
	return count
end

-- o que os pets de um jogador acrescentam a cada ataque
local function petPower(player)
	local power = 0
	for _, pet in player.Pets:GetChildren() do
		if pet:GetAttribute("Equipped") then
			power += pet:GetAttribute("Power")
		end
	end
	return power
end

-- Todo jogador recebe Coins no placar
Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local coins = Instance.new("IntValue")
	coins.Name = "Coins"
	coins.Parent = leaderstats

	-- os pets que eles possuem
	local pets = Instance.new("Folder")
	pets.Name = "Pets"
	pets.Parent = player
	-- Lição 20: o carregamento ao entrar vai aqui
end)

-- Uma pilha de moedas em um local: uma cópia de ServerStorage.CoinPile com sua vida
-- e seu valor como atributos
local function spawnPile(spot)
	local desert = spot.Parent.Parent.Name == "Desert"
	local health = desert and Settings.DesertHealth or Settings.PileHealth
	local pile = ServerStorage.CoinPile:Clone()
	pile.Position = spot.Position
	pile:SetAttribute("MaxHealth", health)
	pile:SetAttribute("Health", health)
	pile:SetAttribute("Value", desert and Settings.DesertValue or Settings.PileValue)
	pile:SetAttribute("Zone", spot.Parent.Parent.Name)
	pile.HealthGui.Label.Text = pile:GetAttribute("Health") .. "/" .. pile:GetAttribute("MaxHealth")
	pileSpot[pile] = spot
	pile.Parent = piles
	return pile
end

-- Um golpe reduz a vida de uma pilha em 1, mais o poder dos pets do jogador;
-- ao chegar a 0, a pilha se quebra e concede seu valor
local function hitPile(player, pile)
	local health = pile:GetAttribute("Health") - (1 + petPower(player))
	if health > 0 then
		pile:SetAttribute("Health", health)
		pile.HealthGui.Label.Text = health .. "/" .. pile:GetAttribute("MaxHealth")
		return
	end
	player.leaderstats.Coins.Value += pile:GetAttribute("Value")
	local spot = pileSpot[pile]
	pileSpot[pile] = nil
	pile:Destroy()
	-- uma nova pilha no mesmo lugar, alguns segundos depois
	task.delay(Settings.RespawnTime, spawnPile, spot)
end

-- Uma pilha em cada ponto, em cada zona
for _, zone in workspace.Zones:GetChildren() do
	for _, spot in zone.Spawns:GetChildren() do
		spawnPile(spot)
	end
end

-- O cliente pede para atingir uma pilha. Nunca confie no cliente: qualquer pessoa pode acionar
-- esse remote com qualquer coisa, de qualquer lugar, tão rápido quanto quiser.
remotes.Hit.OnServerEvent:Connect(function(player, pile)
	-- uma pilha de verdade
	if typeof(pile) ~= "Instance" or pile.Parent ~= piles then
		return
	end
	-- ao alcance
	local character = player.Character
	local root = character and character:FindFirstChild("HumanoidRootPart")
	if not root or (root.Position - pile.Position).Magnitude > Settings.Reach then
		return
	end
	-- não rápido demais
	local now = time()
	if lastHit[player] and now - lastHit[player] < Settings.HitCooldown then
		return
	end
	lastHit[player] = now
	-- em uma zona que o jogador desbloqueou
	if pile:GetAttribute("Zone") == "Desert" and not player:GetAttribute("Desert") then
		return
	end
	hitPile(player, pile)
end)

-- Um sorteio ponderado: a Chance de cada pet (de um total de 100) é sua parcela da faixa
local function rollPet()
	local roll = math.random() * 100
	for _, info in Settings.Pets do
		roll -= info.Chance
		if roll <= 0 then
			return info.Name
		end
	end
	return Settings.Pets[1].Name
end

-- Chocagem: o prompt do ovo, pago com moedas
workspace.Egg.ProximityPrompt.Triggered:Connect(function(player)
	local coins = player.leaderstats.Coins
	if coins.Value < Settings.EggPrice then
		return
	end
	coins.Value -= Settings.EggPrice
	local name = rollPet()
	-- equipado imediatamente, se houver espaço
	local pet = givePet(player, name, equippedCount(player) < Settings.MaxEquipped)
	print(player.Name .. " hatched a " .. name)
	-- todos ficam sabendo dos pets mais raros
	if pet:GetAttribute("Rarity") == "Legendary" then
		remotes.Announce:FireAllClients(player.Name, name)
	end
end)

-- Os pets equipados seguem seu dono: cada um tem uma peça no mundo, mantida
-- em uma fileira atrás do jogador a cada quadro
local petModels = {} -- cada pet -> sua peça no mundo
RunService.Heartbeat:Connect(function()
	for _, player in Players:GetPlayers() do
		local root = player.Character and player.Character:FindFirstChild("HumanoidRootPart")
		local pets = player:FindFirstChild("Pets")
		local slot = 0
		for _, pet in pets and pets:GetChildren() or {} do
			local model = petModels[pet]
			if pet:GetAttribute("Equipped") and root then
				slot += 1
				if not model then
					model = ServerStorage.PetModels[pet.Value]:Clone()
					model.Parent = petParts
					petModels[pet] = model
				end
				model.CFrame = root.CFrame * CFrame.new((slot - 2) * 3, -1.5, 4)
			elseif model then
				-- guardado: sua peça é removida
				model:Destroy()
				petModels[pet] = nil
			end
		end
	end
end)

-- O cliente pede para equipar ou guardar um pet. O servidor verifica se o pet pertence
-- ao jogador e se não há mais de MaxEquipped pets equipados.
remotes.Equip.OnServerEvent:Connect(function(player, pet)
	if typeof(pet) ~= "Instance" or pet.Parent ~= player.Pets then
		return
	end
	if pet:GetAttribute("Equipped") then
		pet:SetAttribute("Equipped", false)
	elseif equippedCount(player) < Settings.MaxEquipped then
		pet:SetAttribute("Equipped", true)
	end
end)

-- O portão do Desert: pague uma vez para abri-lo, apenas para esse jogador
workspace.Gate.ProximityPrompt.Triggered:Connect(function(player)
	local coins = player.leaderstats.Coins
	if player:GetAttribute("Desert") or coins.Value < Settings.GatePrice then
		return
	end
	coins.Value -= Settings.GatePrice
	player:SetAttribute("Desert", true)
end)

-- Salvamento: Coins, o Desert e todos os pets
local function save(player)
	local pets = {}
	for _, pet in player.Pets:GetChildren() do
		table.insert(pets, { Name = pet.Value, Equipped = pet:GetAttribute("Equipped") == true })
	end
	local data = {
		Coins = player.leaderstats.Coins.Value,
		Desert = player:GetAttribute("Desert") == true,
		Pets = pets,
	}
	pcall(function()
		saveStore:SetAsync(player.UserId, data)
	end)
end

Players.PlayerRemoving:Connect(save)

game:BindToClose(function()
	for _, player in Players:GetPlayers() do
		save(player)
	end
end)
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Jogo Roblox: Simulador de Pets

Pratique por conta própria: Playground de Roblox