Cổng sa mạc
Bài học 16 trên 20 trong khóa học Trò chơi Roblox: mô phỏng thú cưng của Coddy.
Bức tường đỏ ở phía sau là cổng dẫn đến Sa mạc, có lời nhắc "Unlock". Thanh toán Settings.GatePrice sẽ mở cổng, nhưng chỉ mở cho người chơi đã thanh toán.
Cần có cả hai phía. Máy chủ lấy tiền xu và ghi nhận trạng thái mở khóa dưới dạng thuộc tính Desert của người chơi để mọi quy tắc đều có thể kiểm tra. Client theo dõi thuộc tính đó và mở cổng trên màn hình của riêng mình: trong Roblox, thiết bị của mỗi người chơi điều khiển nhân vật của chính họ, vì vậy một bức tường mà LocalScript làm cho không còn va chạm sẽ cho người chơi đó đi qua, trong khi bức tường vẫn có va chạm với mọi người khác.
-- máy khách
workspace.Gate.CanCollide = false
workspace.Gate.Transparency = 0.7Ẩn lời nhắc ở cổng theo cách tương tự sẽ ngăn lời nhắc đó đề xuất mở khóa lần thứ hai.
Thử thách
KhóMở cổng Sa mạc cho người chơi trả phí.
- Trong
PetServer, tạiworkspace.Gate.ProximityPrompt.Triggered: dừng lại nếu người chơi có thuộc tínhDeserthoặc có ít xu hơnSettings.GatePrice; nếu không, trừ số xu tương ứng với giá và đặtDesertthành true. - Trong
PetClient,openGate(): nếume:GetAttribute("Desert"), đặt CanCollide của cổng thành false và Transparency thành 0.7. Gọi hàm này ngay bây giờ và khi Desert thay đổi.
Nhấn “Chơi”, kiếm 100 xu để mở khóa: bức tường mờ đ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í của nó
local lastHit = {} -- mỗi người chơi -> thời điểm đá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
-- 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 đưa ra
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
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, lưu 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 cú đá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 giá trị sức khỏe về 0, đống xu vỡ ra 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
-- Máy khách yêu cầu đánh một đống xu. Đừng bao giờ tin máy khách: bất kỳ ai cũng có thể kích hoạt
-- 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 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)
-- Chọn ngẫu nhiên theo trọng số: Chance của mỗi thú cưng (trên thang 100) là phần tương ứng trên dải lựa chọn
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)
end)
-- Thú cưng đang ở ngoài đi theo chủ: mỗi con 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 ở mỗi khung hình
local petModels = {} -- mỗi thú cưng tương ứng với một 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 thú cưng đi: bộ phận của nó cũng biến mất
model:Destroy()
petModels[pet] = nil
end
end
end
end)
-- Máy khách yêu cầu cho thú cưng ra ngoài hoặc cất đi. Máy chủ kiểm tra xem thú cưng có
-- thuộc về người chơi và số thú cưng đang ở ngoài 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)
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