Đồng xu sa mạc
Bài học 17 trên 20 trong khóa học Trò chơi Roblox: mô phỏng thú cưng của Coddy.
Sa mạc có các điểm xuất hiện riêng, cùng những đống tài nguyên cứng hơn và có giá trị cao hơn: Settings.DesertHealth và Settings.DesertValue. Tạo các đống tài nguyên ở mọi khu vực và thêm thuộc tính Zone cho mỗi đống để cho biết nó thuộc khu vực nào. Mỗi điểm xuất hiện biết khu vực của mình: nó nằm trong Zones.Desert.Spawns, nên spot.Parent.Parent.Name là "Desert".
Cổng chỉ mở trên màn hình của người chơi, và kẻ khai thác có thể mở bất kỳ bức tường nào trên màn hình của họ. Vì vậy, quy tắc kiểm tra Hit của máy chủ có thêm một điều kiện: đống tài nguyên ở Sa mạc sẽ bỏ qua những người chơi không có thuộc tính Desert. Máy khách mở cửa, máy chủ duy trì các quy tắc.
Thử thách
KhóLấp đầy sa mạc bằng những đống xu cứng cáp hơn và giá trị hơn.
- Trong
spawnPile, với một vị trí cóspot.Parent.Parent.NamelàDesert, hãy dùngSettings.DesertHealthvàSettings.DesertValue; đặt thuộc tínhZonecủa mỗi đống xu thành tên đó. - Tạo đống xu tại các vị trí của mọi vùng trong
workspace.Zones. - Trong trình xử lý
Hit, bỏ qua đống xu ở sa mạc nếu thuộc tínhDesertcủa người chơi chưa được đặt.
Nhấn Chơi: các đống xu có nhãn 8/8 nằm trên cát. 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 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, lưu tê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 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 người chơi đá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)
-- Đố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 từ thú cưng của người chơi;
-- Khi còn 0 máu, đống xu vỡ và trả số xu theo 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
-- Bài học 17: Desert Coins sẽ nằm ở đây
-- 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ể gửi
-- remote này với bất kỳ dữ liệu nào, từ bất kỳ đâu, nhanh tùy ý.
remotes.Hit.OnServerEvent:Connect(function(player, pile)
-- đống xu phải tồn tại
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 đánh quá nhanh
local now = time()
if lastHit[player] and now - lastHit[player] < Settings.HitCooldown then
return
end
lastHit[player] = now
hitPile(player, pile)
end)
-- Chọn ngẫu nhiên có trọng số: Chance của mỗi thú cưng, tính 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 tương tá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 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,
-- 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 tương ứng 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 tương ứng biến mất
model:Destroy()
petModels[pet] = nil
end
end
end
end)
-- Client yêu cầu trang bị hoặc cất thú cưng. Máy chủ kiểm tra: thú cưng
-- thuộc về người chơi, và số thú cưng được trang bị không vượt quá MaxEquipped.
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ả phí 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)
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