הצילו את חיות המחמד שלכם
שיעור 18 מתוך 18 בקורס משחק Roblox: סימולטור חיות מחמד של Coddy.
המטבעות, המדבר וכל חיית המחמד עדיין צריכים להיות שם בפעם הבאה שהשחקן יצטרף. DataStore שומר טבלה לכל שחקן, תחת UserId שלו. חיות מחמד הן מופעים, ש-DataStore לא יכול לשמור, לכן שמור טבלה פשוטה של השם של כל חיית מחמד והאם היא בחוץ, ובנה מחדש את חיות המחמד מתוכה כשהשחקן מצטרף:
{ Coins = 120, Desert = true, Pets = { { Name = "Fox", Equipped = true } }שמור כשהשחקן עוזב (PlayerRemoving) וכשהשרת נסגר (game:BindToClose); טען ב-PlayerAdded. שתי הקריאות עלולות להיכשל בצד של Roblox, לכן עטוף אותן ב-pcall. ב-Roblox Studio, מאגרי נתונים פועלים לאחר פרסום המקום והפעלת Enable Studio Access to API Services.
אתגר
קשה- קבל את
DataStoreServiceואת DataStore בשםPets. - כתוב את
save(player): שמור אתCoins, אתDesertורשימה של{ Name, Equipped }עבור כל חיית מחמד, תחת ה־UserId של השחקן, בתוך pcall. קרא לה בעתPlayerRemovingועבור כל שחקן בתוךgame:BindToClose. - בתוך
PlayerAdded, לאחר יצירת התיקיות, טען את השמירה (בתוך pcall) ושחזר את המטבעות, את המאפיין Desert ואת חיות המחמד (דלג על שמות שאינם מופיעים ב־petInfo).
לחץ על Play, בקע ביצה, לחץ על Stop ואז על Play שוב: חיות המחמד שלך חזרו. לאחר מכן לחץ על Check.
נסו בעצמכם
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 = {} -- כל ערימה -> המקום שבו היא נמצאת
local lastHit = {} -- כל שחקן -> מתי הוא הכה לאחרונה
print("A Meadow pile gives " .. Settings.PileValue .. " coins")
-- Settings.Pets לפי שם
local petInfo = {}
for _, info in Settings.Pets do
petInfo[info.Name] = info
end
-- חיית מחמד: StringValue בתיקיית Pets של השחקן, שמכיל את שמה, עם
-- הנדירות והכוח שלה כמאפיינים
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
-- כמה חיות מחמד יש לשחקן בחוץ
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
-- מה חיות המחמד של השחקן מוסיפות לכל מכה
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
-- כל שחקן מקבל Coins בטבלת המובילים
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
-- חיות המחמד שבבעלותם
local pets = Instance.new("Folder")
pets.Name = "Pets"
pets.Parent = player
end)
-- ערימת מטבעות במקום מסוים: עותק של ServerStorage.CoinPile עם כמות החיים שלה
-- והערך שלה כמאפיינים
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
-- מכה מפחיתה 1, בתוספת הכוח של חיות המחמד של השחקן, מכמות החיים של הערימה;
-- כשהערך מגיע ל־0, הערימה נשברת ומעניקה את שווייה
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()
-- ערימה חדשה באותו מקום, כעבור כמה שניות
task.delay(Settings.RespawnTime, spawnPile, spot)
end
-- ערימה בכל נקודה, בכל אזור
for _, zone in workspace.Zones:GetChildren() do
for _, spot in zone.Spawns:GetChildren() do
spawnPile(spot)
end
end
-- הלקוח מבקש להכות בערימה. לעולם אין לסמוך על הלקוח: כל אחד יכול להפעיל
-- את ה־remote הזה עם כל דבר, מכל מקום, ובמהירות שירצה.
remotes.Hit.OnServerEvent:Connect(function(player, pile)
-- ערימה אמיתית
if typeof(pile) ~= "Instance" or pile.Parent ~= piles then
return
end
-- בטווח פגיעה
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
-- לא מהר מדי
local now = time()
if lastHit[player] and now - lastHit[player] < Settings.HitCooldown then
return
end
lastHit[player] = now
-- באזור שהשחקן פתח
if pile:GetAttribute("Zone") == "Desert" and not player:GetAttribute("Desert") then
return
end
hitPile(player, pile)
end)
-- הגרלה משוקללת: Chance של כל חיית מחמד (מתוך 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
-- בקיעה: ההנחיה של הביצה, שהתשלום עליה הוא במטבעות
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()
-- נשלפת מיד, אם יש מקום
local pet = givePet(player, name, equippedCount(player) < Settings.MaxEquipped)
print(player.Name .. " hatched a " .. name)
-- כולם מקבלים הודעה על חיות המחמד הנדירות ביותר
if pet:GetAttribute("Rarity") == "Legendary" then
remotes.Announce:FireAllClients(player.Name, name)
end
end)
-- חיות המחמד שהוצאו עוקבות אחרי בעליהן: לכל אחת יש אובייקט בעולם, שנשמר בשורה
-- מאחורי השחקן בכל פריים
local petModels = {} -- כל חיית מחמד -> האובייקט שלה בעולם
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
model:Destroy()
petModels[pet] = nil
end
end
end
end)
-- הלקוח מבקש להוציא חיית מחמד או להחזיר אותה. השרת בודק שחיית המחמד
-- שייכת לשחקן, ושלא הוצאו יותר מ-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)
-- השער ל-Desert: משלמים פעם אחת והוא נפתח, רק עבור אותו שחקן
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)
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.