Menu
CoddyTech

Trang bị tối đa ba thú cưng

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

Nhấn nút của thú cưng sẽ cho thú cưng ra ngoài hoặc cất đi. TextButton phát sự kiện Activated khi được nhấn (nhấp hoặc chạm), ở phía client. Client yêu cầu máy chủ thông qua remotes.Equip, gửi chính thú cưng đó.

Máy chủ luôn kiểm tra: thú cưng phải là một instance trong Pets của chính người chơi này (kẻ khai thác có thể gửi bất cứ thứ gì), và số thú cưng ở ngoài không được vượt quá Settings.MaxEquipped. Sau đó, máy chủ đảo trạng thái Equipped, rồi thay đổi này được đồng bộ ngược lại: danh sách được vẽ lại và thú cưng xuất hiện hoặc biến mất.

challenge icon

Thử thách

Trung bình

Đưa thú cưng ra hoặc cất đi bằng nút của nó.

  1. Trong PetClient, sự kiện Activated của mỗi nút gọi remotes.Equip cùng với thú cưng tương ứng.
  2. Trong PetServer, khi có sự kiện remotes.Equip.OnServerEvent: dừng lại nếu Parent của thú cưng không phải là player.Pets; đảo trạng thái Equipped, chỉ đưa thú cưng ra khi số thú cưng đang ở ngoài ít hơn Settings.MaxEquipped.
  3. Trong Heartbeat, hủy phần của thú cưng được cất đi.

Nhấn Chơi rồi nhấn Cat (đang ở ngoài): Cat sẽ được cất đi. 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 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

-- Một thú cưng: StringValue trong thư mục Pets của người chơi, lưu tên của nó, cùng
-- độ hiếm và sức mạnh dưới dạng 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 lần đánh
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
end)

-- Một đống xu tại một vị trí: bản sao của ServerStorage.CoinPile, có máu
-- và giá trị dưới dạng 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 lần đánh trừ 1 máu của đống xu, cộng thêm sức mạnh thú cưng của người chơi;
-- Khi máu về 0, đố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 tại 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

-- Client yêu cầu đánh đống xu. Đừng tin client: bất kỳ ai cũng có thể kích hoạt
-- remote này với dữ liệu bất kỳ, từ bất cứ đâu, nhanh đến mức tùy thích.
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
	hitPile(player, pile)
end)

-- Lượt chọn ngẫu nhiên có trọng số: Chance của mỗi pet (trên 100) là 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 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 ngay nếu còn chỗ
	local pet = givePet(player, name, equippedCount(player) < Settings.MaxEquipped)
	print(player.Name .. " hatched a " .. name)
end)

-- Các pet được đưa ra sẽ đi theo chủ: mỗi pet có một bộ phận trong thế giới, luôn được giữ
-- 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 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)
			end
		end
	end
end)

-- Bài học 15: Trang bị tối đa ba thú cưng sẽ ở đây
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