Menu
CoddyTech

희귀한 반려동물 소식

Coddy의 Roblox 게임: 펫 시뮬레이터 코스 레슨. 18개 중 17번째.

누군가 전설 펫을 부화시키면 전체 서버가 이를 알아야 합니다. FireAllClients는 모든 플레이어의 클라이언트에서 동시에 RemoteEvent를 발생시킵니다:

-- 서버
remotes.Announce:FireAllClients(player.Name, name)
-- 클라이언트
remotes.Announce.OnClientEvent:Connect(function(who, pet)
end)

각 클라이언트는 HUD의 Banner에 몇 초 동안 소식을 표시합니다. OnClientEvent는 서버가 보낸 내용만 정확히 받습니다. 이쪽에서는 플레이어가 추가되지 않습니다.

challenge icon

챌린지

어려움
  1. PetServer에서 알을 부화시킨 후, 펫의 Rarity가 Legendary이면 플레이어의 Name과 펫의 이름을 모든 클라이언트에 전달하도록 remotes.Announce를 실행하세요.
  2. 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)
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

Roblox 게임: 펫 시뮬레이터의 모든 레슨