Menu
CoddyTech

Danh sách thú cưng

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

Người chơi cần thấy thú cưng của mình. HUD có một ScrollingFrame tên Inventory với UIListLayout bên trong. Thành phần này xếp các mục bên trong lần lượt từ trên xuống dưới theo thứ tự LayoutOrder. Mỗi thú cưng có một TextButton ở đó. AutomaticCanvasSize của nó là Y, nên vùng hiển thị tự mở rộng theo danh sách và người chơi có nhiều thú cưng có thể cuộn danh sách.

Máy khách tạo danh sách từ thư mục Pets mà máy chủ lưu trong dữ liệu của người chơi, rồi tạo lại danh sách khi thư mục thay đổi: ChildAdded khi một thú cưng nở, và GetAttributeChangedSignal("Equipped") của từng thú cưng khi thú cưng được trang bị hoặc tháo ra.

pet:GetAttributeChangedSignal("Equipped"):Connect(showPets)

Tạo lại danh sách nghĩa là xóa các nút cũ trước, để danh sách không bao giờ hiển thị một thú cưng hai lần.

challenge icon

Thử thách

Trung bình

Hiển thị thú cưng trên màn hình, mỗi thú cưng có một nút.

  1. Trong PetClient: local pets = me:WaitForChild("Pets").
  2. Viết showPets(): xóa các TextButton trong hud.Inventory, rồi thêm một nút cho mỗi thú cưng, hiển thị Cat (out) khi thú cưng có thuộc tính Equipped, Cat khi không có.
  3. Gọi hàm này ngay bây giờ, khi có sự kiện pets.ChildAdded và khi mỗi thú cưng có sự kiện GetAttributeChangedSignal("Equipped"), cho cả thú cưng hiện có lẫn thú cưng mới.

Nhấn Chơi rồi ấp trứng: Cat (out) sẽ hiển thị trong danh sách. 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 Settings = require(game.ReplicatedStorage.Settings)

local remotes = game.ReplicatedStorage.Remotes
local piles = workspace.Piles
local petParts = workspace.PetParts
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 gần nhất

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, lưu tên
-- và có độ hiếm, sức mạnh làm 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 mà 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 đều 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
end)

-- Một đống xu tại một vị trí: bản sao của ServerStorage.CoinPile, có lượng máu
-- và giá trị làm thuộc tính
local function spawnPile(spot)
	local pile = ServerStorage.CoinPile:Clone()
	pile.Position = spot.Position
	pile:SetAttribute("MaxHealth", Settings.PileHealth)
	pile:SetAttribute("Health", Settings.PileHealth)
	pile:SetAttribute("Value", Settings.PileValue)
	pile.HealthGui.Label.Text = pile:GetAttribute("Health") .. "/" .. pile:GetAttribute("MaxHealth")
	pileSpot[pile] = spot
	pile.Parent = piles
	return pile
end

-- Mỗi cú đánh trừ 1 cộng với sức mạnh thú cưng của người chơi khỏi lượng máu của đống xu;
-- Khi còn 0 máu, đống xu vỡ và trả 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 ở cùng vị trí
	task.delay(Settings.RespawnTime, spawnPile, spot)
end

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

-- Máy khách yêu cầu đánh một đống xu. Đừng tin máy khách: bất kỳ ai cũng có thể gửi
-- sự kiện từ xa 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 đánh
	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
	hitPile(player, pile)
end)

-- Lượt chọn có trọng số: Chance của mỗi thú cưng (trên 100) quyết định phần của nó trên dải xác suất
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 ở 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 thú cưng ra ngay nếu còn chỗ
	local pet = givePet(player, name, equippedCount(player) < Settings.MaxEquipped)
	print(player.Name .. " hatched a " .. name)
end)

-- Thú cưng đang được trang bị đi theo chủ: mỗi con có một bộ phận trong thế giới, luôn nằm
-- thành một hàng phía sau người chơi trong mỗi khung hình
local petModels = {} -- mỗi thú cưng -> bộ phận tương ứng trong thế giới trò chơ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)
			end
		end
	end
end)

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