희귀한 반려동물 소식
Coddy의 Roblox 게임: 펫 시뮬레이터 코스 레슨. 18개 중 17번째.
누군가 전설 펫을 부화시키면 전체 서버가 이를 알아야 합니다. FireAllClients는 모든 플레이어의 클라이언트에서 동시에 RemoteEvent를 발생시킵니다:
-- 서버
remotes.Announce:FireAllClients(player.Name, name)
-- 클라이언트
remotes.Announce.OnClientEvent:Connect(function(who, pet)
end)각 클라이언트는 HUD의 Banner에 몇 초 동안 소식을 표시합니다. OnClientEvent는 서버가 보낸 내용만 정확히 받습니다. 이쪽에서는 플레이어가 추가되지 않습니다.
챌린지
어려움PetServer에서 알을 부화시킨 후, 펫의 Rarity가Legendary이면 플레이어의 Name과 펫의 이름을 모든 클라이언트에 전달하도록remotes.Announce를 실행하세요.PetClient에서remotes.Announce.OnClientEvent가 발생하면 Banner의 텍스트를Player1 hatched a Dragon!으로 설정하고, Banner를 표시한 다음 4초간 기다렸다가 숨기세요.
플레이를 누른 다음 확인을 누르세요. 확인 과정에서 Dragon이 부화합니다.
직접 해보기
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
-- 펫: 플레이어의 Pets 폴더에 있는 StringValue로, 펫의 이름을 담고 있으며
-- 희귀도와 힘을 속성으로 가짐
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
-- 클라이언트가 더미를 공격하도록 요청한다. 클라이언트를 절대 신뢰하지 말 것: 누구나
-- 어디서든 무엇이든 인자로 이 리모트를 원하는 만큼 빠르게 호출할 수 있다.
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)
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)
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.