Menu
CoddyTech

Tải khi tham gia

Bài học 20 trên 20 trong khóa học Trò chơi Roblox: mô phỏng thú cưng của Coddy.

Bây giờ hãy đọc dữ liệu đã lưu khi người chơi tham gia. GetAsync trả về giá trị mà SetAsync đã lưu dưới khóa đó, hoặc nil nếu người chơi chưa từng lưu. Lệnh này cũng có thể thất bại, vì vậy hãy gọi nó trong pcall. pcall trả về trạng thái thành công và sau đó là giá trị:

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

Hãy tải dữ liệu sau khi tạo các thư mục, để thú cưng có thư mục Pets để lưu vào. Bỏ qua mọi tên đã lưu không có trong petInfo: thú cưng bị xóa khỏi trò chơi không nên làm gián đoạn việc tham gia.

challenge icon

Thử thách

Khó

Khôi phục cho người chơi những gì họ đã lưu.

  1. Trong PlayerAdded, sau khi tạo thư mục Pets: local ok, saved = pcall(function() return saveStore:GetAsync(player.UserId) end).
  2. Nếu ok and saved: đặt Coins thành saved.Coins và thuộc tính Desert thành saved.Desert.
  3. Với mỗi thú cưng đã lưu trong petInfo, gọi givePet(player, pet.Name, pet.Equipped == true).

Nhấn Chơi, ấp trứng, nhấn Dừng, rồi nhấn Chơi lần nữa: bạn sẽ có lại số xu và thú cưng của mình. Sau đó nhấn Kiểm tra.

Tự làm thử

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 = {} -- mỗi đống xu -> vị trí đặt đống xu đó
local lastHit = {} -- mỗi người chơi -> thời điểm họ đánh lần cuối

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

-- Settings.Pets theo tên
local petInfo = {}
for _, info in Settings.Pets do
	petInfo[info.Name] = info
end

-- Thú cưng: một StringValue trong thư mục Pets của người chơi, chứa tên thú cưng, với
-- độ hiếm và sức mạnh là các thuộc tính
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

-- số thú cưng người chơi đang cho ra ngoài
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

-- sức mạnh thú cưng cộng thêm vào mỗi cú đánh của người chơi
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

-- Mỗi người chơi có Coins trên bảng xếp hạng
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

	-- những thú cưng họ sở hữu
	local pets = Instance.new("Folder")
	pets.Name = "Pets"
	pets.Parent = player
	-- Bài học 20: Đặt phần tải dữ liệu khi tham gia ở đây
end)

-- Đống xu tại một vị trí: bản sao của ServerStorage.CoinPile, với lượng máu
-- và giá trị là các thuộc tính
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

-- Mỗi lần đánh làm máu của đống xu giảm 1 cộng với sức mạnh của thú cưng mà người chơi sở hữu;
-- khi máu về 0, đống xu vỡ và người chơi nhận số xu tương ứng với giá trị của nó
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()
	-- vài giây sau, một đống xu mới xuất hiện tại cùng vị trí
	task.delay(Settings.RespawnTime, spawnPile, spot)
end

-- Mỗi vị trí trong mỗi khu vực đều có một đống xu
for _, zone in workspace.Zones:GetChildren() do
	for _, spot in zone.Spawns:GetChildren() do
		spawnPile(spot)
	end
end

-- Client yêu cầu đánh một đống xu. Đừng bao giờ tin client: bất kỳ ai cũng có thể gửi
-- remote này với dữ liệu bất kỳ, từ bất kỳ đâu, nhanh tùy ý.
remotes.Hit.OnServerEvent:Connect(function(player, pile)
	-- đống xu có thật
	if typeof(pile) ~= "Instance" or pile.Parent ~= piles then
		return
	end
	-- trong tầm với
	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
	-- không quá nhanh
	local now = time()
	if lastHit[player] and now - lastHit[player] < Settings.HitCooldown then
		return
	end
	lastHit[player] = now
	-- trong khu vực người chơi đã mở khóa
	if pile:GetAttribute("Zone") == "Desert" and not player:GetAttribute("Desert") then
		return
	end
	hitPile(player, pile)
end)

-- Chọn ngẫu nhiên có trọng số: Chance của mỗi thú cưng là phần của nó trên thang 100
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

-- Ấp trứng: dùng lời nhắc của quả trứng và trả bằng xu
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()
	-- Cho ra ngoài ngay nếu còn chỗ
	local pet = givePet(player, name, equippedCount(player) < Settings.MaxEquipped)
	print(player.Name .. " hatched a " .. name)
	-- Mọi người đều biết khi có thú cưng hiếm nhất xuất hiện
	if pet:GetAttribute("Rarity") == "Legendary" then
		remotes.Announce:FireAllClients(player.Name, name)
	end
end)

-- Thú cưng đang ở ngoài đi theo chủ: mỗi con có một bộ phận trong thế giới,
-- xếp thành hàng sau người chơi ở mỗi khung hình
local petModels = {} -- mỗi thú cưng -> bộ phận của nó trong thế giới
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
				-- Cất đi: bộ phận của nó biến mất
				model:Destroy()
				petModels[pet] = nil
			end
		end
	end
end)

-- Client yêu cầu đưa thú cưng ra ngoài hoặc cất đi. Máy chủ kiểm tra: thú cưng
-- thuộc về người chơi và không có quá MaxEquipped con ở ngoài.
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)

-- Cổng Desert: trả tiền một lần để mở cổng, chỉ cho người chơi đó
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)

-- Lưu: Coins, Desert và mọi thú cưng
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 iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Trò chơi Roblox: mô phỏng thú cưng

Tự luyện tập: Playground Roblox