Menu
CoddyTech

사막의 동전

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

사막에는 자체 지점이 있으며, 사막의 더미는 더 단단하고 더 많은 가치를 지닙니다. Settings.DesertHealth와 Settings.DesertValue를 사용하세요. 모든 구역에 더미를 생성하고, 각 더미에 어디에 있는지 나타내는 Zone 특성을 부여하세요. 지점은 자신의 구역을 알고 있습니다. Zones.Desert.Spawns 안에 있으므로 spot.Parent.Parent.Name은 "Desert"입니다.

문은 플레이어의 화면에서만 열리며, 악용자는 자신의 화면에서 어떤 벽이든 열 수 있습니다. 따라서 서버의 Hit 검사에 규칙이 하나 더 추가됩니다. 사막 더미는 Desert 특성이 없는 플레이어를 무시합니다. 클라이언트는 문을 열고, 서버는 규칙을 지킵니다.

challenge icon

챌린지

어려움
  1. spawnPile에서 Desert의 스팟에는 Desert의 체력과 값을 사용하고, 모든 더미의 Zone 속성을 해당 구역의 이름으로 설정합니다.
  2. workspace.Zones의 모든 구역에 있는 스팟에 더미를 생성합니다.
  3. Hit 처리기에서 Desert 속성이 설정되지 않은 플레이어에게는 Desert 더미를 무시합니다.

플레이를 누른 다음 확인을 누릅니다.

직접 해보기

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 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

-- 타격 한 번은 코인 더미의 체력을 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

-- Meadow의 모든 지점에 더미를 하나씩 생성한다
for _, spot in workspace.Zones.Meadow.Spawns:GetChildren() do
	spawnPile(spot)
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
	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 게임: 펫 시뮬레이터의 모든 레슨