-
로블록스 코딩 실습 31 - 상점에 아이템 등록Roblox 코딩 2026. 1. 6. 21:58
상점에 아이템 “등록(추가)”하는 구조 만들기: 상품 테이블 + 자동 UI 생성 + 서버 검증
실습 30에서 상점을 “한 품목”으로 만들었다면, 실습 31에서는 상점이 실제로 운영 가능한 형태가 되도록 아이템 등록(상품 추가) 구조를 만든다.
핵심 목표는 다음 3가지다.- 상품 목록(PRODUCTS)에 아이템을 등록하면
- UI가 자동으로 버튼을 생성하고
- 서버는 등록된 상품만 구매 처리한다
이 구조가 잡히면 이후에는 상품이 5개든 50개든 “등록만”으로 확장된다.
0. 준비물 (30편 구성 그대로 사용)
- ReplicatedStorage/ShopPurchase (RemoteEvent)
- ServerStorage에 판매할 Tool 또는 지급 대상(예: Sword, Potion 등)
- StarterGui/ShopGui (ScreenGui)
- leaderstats.Coins 존재
이번 실습에서는 UI 구조를 “목록형”으로 바꾼다.
1. UI 구조 변경 (목록 자동 생성용)
StarterGui/ShopGui에 아래처럼 구성한다.
- ShopGui (ScreenGui)
- Frame
- Title (TextLabel)
- Close (TextButton)
- ItemList (ScrollingFrame) ← 상품 버튼이 들어갈 컨테이너
- UIListLayout ← 세로 정렬
- ItemButtonTemplate (TextButton) ← 템플릿 버튼 (Visible=false)
- Frame
중요 포인트
- ItemButtonTemplate.Visible = false로 숨겨둔다
- 코드가 템플릿을 Clone하여 ItemList에 붙인다
2. “상품 등록” 데이터 구조 설계
상품 등록의 중심은 클라이언트와 서버가 “같은 상품 목록”을 공유하는 것이다.
가장 안전한 방식은 상품 목록을 ModuleScript로 만들고 ReplicatedStorage에 둬서 공유하는 방식이다.(1) ReplicatedStorage에 ModuleScript 생성
이름: ShopCatalog
-- ReplicatedStorage/ShopCatalog local ShopCatalog = {} -- 상품 등록은 여기서만 한다. -- id: 구매 식별자(중복 금지) -- name: UI 표시명 -- price: 가격 -- grant: 지급 방식(여기서는 Tool 지급) -- toolName: ServerStorage에 있는 Tool 이름 ShopCatalog.Products = { { id = "Sword", name = "Sword", price = 50, grant = "Tool", toolName = "Sword", }, { id = "Shield", name = "Shield", price = 75, grant = "Tool", toolName = "Shield", }, { id = "SpeedBoots", name = "Speed Boots (10s)", price = 40, grant = "Effect", effectName = "SpeedBoost", duration = 10, }, } return ShopCatalog이제 상점 아이템 등록은 이 파일에서 한 줄 추가로 끝난다.
3. 실습 31의 핵심: 자동 UI 생성 (클라이언트)
StarterPlayer > StarterPlayerScripts에 LocalScript 생성: ShopClient31
local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local player = Players.LocalPlayer local purchaseEvent = ReplicatedStorage:WaitForChild("ShopPurchase") local catalog = require(ReplicatedStorage:WaitForChild("ShopCatalog")) local shopGui = player:WaitForChild("PlayerGui"):WaitForChild("ShopGui") local frame = shopGui:WaitForChild("Frame") local closeBtn = frame:WaitForChild("Close") local itemList = frame:WaitForChild("ItemList") local templateBtn = frame:WaitForChild("ItemButtonTemplate") -- 초기화: 기존 생성 버튼 정리(템플릿 제외) local function clearItemButtons() for _, child in ipairs(itemList:GetChildren()) do if child:IsA("TextButton") then child:Destroy() end end end -- UI 생성: 상품 등록 목록을 읽어 자동 버튼 생성 local function buildShopUI() clearItemButtons() for _, product in ipairs(catalog.Products) do local btn = templateBtn:Clone() btn.Visible = true btn.Name = "Item_" .. product.id btn.Text = string.format("%s (%d)", product.name, product.price) btn.Parent = itemList btn.MouseButton1Click:Connect(function() purchaseEvent:FireServer(product.id) end) end end -- 열고 닫기 shopGui.Enabled = false local shopButton = workspace:WaitForChild("ShopButton") local clickDetector = shopButton:WaitForChild("ClickDetector") clickDetector.MouseClick:Connect(function(clickedPlayer) if clickedPlayer ~= player then return end buildShopUI() shopGui.Enabled = true end) closeBtn.MouseButton1Click:Connect(function() shopGui.Enabled = false end)이제 상품을 추가할 때 UI를 손댈 필요가 없다.
ShopCatalog.Products에 등록만 하면 된다.
4. 서버 구매 처리: “등록된 상품만” 처리하도록 검증 강화
ServerScriptService에 Script 생성: ShopServer31
local ReplicatedStorage = game:GetService("ReplicatedStorage") local ServerStorage = game:GetService("ServerStorage") local Players = game:GetService("Players") local purchaseEvent = ReplicatedStorage:WaitForChild("ShopPurchase") local catalog = require(ReplicatedStorage:WaitForChild("ShopCatalog")) -- id로 상품 찾기 local function findProduct(productId) for _, product in ipairs(catalog.Products) do if product.id == productId then return product end end return nil end local function getCoinsValue(player) local leaderstats = player:FindFirstChild("leaderstats") if not leaderstats then return nil end return leaderstats:FindFirstChild("Coins") end local function grantTool(player, toolName) local template = ServerStorage:FindFirstChild(toolName) if not template then return end local backpack = player:FindFirstChild("Backpack") if not backpack then return end local tool = template:Clone() tool.Parent = backpack end local function grantEffect(player, effectName, duration) -- 예시: SpeedBoost 효과 -- 캐릭터 Humanoid WalkSpeed를 duration 동안 증가 if effectName ~= "SpeedBoost" then return end local character = player.Character if not character then return end local humanoid = character:FindFirstChildOfClass("Humanoid") if not humanoid then return end local original = humanoid.WalkSpeed humanoid.WalkSpeed = original + 8 task.delay(duration, function() -- 캐릭터가 바뀌거나 humanoid가 없을 수 있으므로 안전 체크 local c = player.Character local h = c and c:FindFirstChildOfClass("Humanoid") if h then h.WalkSpeed = original end end) end purchaseEvent.OnServerEvent:Connect(function(player, productId) -- 서버 검증 1: 등록된 상품인지 확인 local product = findProduct(productId) if not product then return end -- 서버 검증 2: 코인 존재/충분 여부 local coins = getCoinsValue(player) if not coins then return end if coins.Value < product.price then return end -- 차감 coins.Value -= product.price -- 지급 if product.grant == "Tool" then grantTool(player, product.toolName) elseif product.grant == "Effect" then grantEffect(player, product.effectName, product.duration or 5) end end)서버는 productId를 믿지 않고, 반드시 ShopCatalog.Products에서 조회해 처리한다.
이 검증이 상점 시스템의 안전성을 결정한다.
5. “아이템 등록” 방법 정리 (실습 31의 결론)
상점에 아이템을 등록하는 절차는 다음 2단계로 고정된다.
1) ServerStorage에 지급할 Tool 준비
- ServerStorage/Sword
- ServerStorage/Shield
2) ReplicatedStorage/ShopCatalog에 상품 추가
{ id = "Shield", name = "Shield", price = 75, grant = "Tool", toolName = "Shield", },끝이다.
UI 버튼 생성과 구매 처리는 자동으로 따라온다.반응형'Roblox 코딩' 카테고리의 다른 글
로블록스 게임을 만들 때 “구조”를 먼저 생각해야 하는 이유 (0) 2026.01.12 로블록스 상점 시스템을 만들면서 가장 많이 막혔던 5가지 (1) 2026.01.11 로블록스 코딩 실습 30 - 간단 상점(Shop) 시스템 (0) 2026.01.05 로블록스 코딩 실습 29-환경 인터랙션 시스템 (0) 2026.01.04 로블록스(Roblox) 코딩 실습 28 : 유저 생성 콘텐츠(UGC) 자동화, 실시간 이벤트 시스템, 확장된 퀘스트 시스템, 유저 커뮤니티 시스템, 플레이어 행동 기반 AI 스토리텔링, 인공지능 음성 합성(TTS) 추가 (1) 2025.03.01