패키지 번들

*이 콘텐츠는 AI(베타)를 사용해 번역되었으며, 오류가 있을 수 있습니다. 이 페이지를 영어로 보려면 여기를 클릭하세요.

패키지 기능 패키지는 할인된 가격으로 플레이어에게 아이템 컬렉션을 판매하는 기능을 아웃-오브-더-박스로 제공합니다.플레이어가 사용자 정의 경험 통화 또는 Robux로 패키지를 구매할 수 있는지, 사용하려는 패키지 유형, 판매하려는 아이템 세트 및 게임 플레이 중에 플레이어에게 알릴 방법을 선택할 수 있습니다.

패키지의 사용자 지정 옵션을 사용하여 경험의 디자인 및 수익 목표에 맞게 번들을 조정할 수 있습니다. 예를 들어:

  • 새로운 플레이어에게 가치를 제공하고 조기 지출을 유도하는 할인된 스타터 팩을 제공하여 낮은 변환율 메트릭을 타겟팅하고 초기 비용을 절감합니다.
  • 다양한 가격 지점에서 아이템을 묶음으로써 플레이어 범위에 호소하여 지출 깊이를 늘리는 것
  • 라이브 작업(LiveOps)을 통해 한정된 시간의 독점 아이템 패키지를 제공하여 라이브 작업 이벤트를 수익화합니다.

패키지 가져오기

크리에이터 스토어는 Roblox와 Roblox 커뮤니티가 제작한 모든 자산을 찾을 수 있는 도구 상자의 탭 으로, 모델, 이미지, 메쉬, 오디오, 플러그인, 비디오 및 폰트 자산을 포함하여 프로젝트 내에서 사용할 수 있는 모든 자산을 찾을 수 있습니다.크리에이터 스토어를 사용하여 기능 패키지를 포함하여 개방형 경험에 직접 하나 이상의 자산을 추가할 수 있습니다!

모든 기능 패키지는 적절하게 작동하려면 코어 기능 패키지가 필요합니다.코어 및 패키지 번들 기능 패키지 자산이 인벤토리에 있으면 코어번들 기능 패키지 자산을 플랫폼의 모든 프로젝트에서 재사용할 수 있습니다.

인벤토리에서 경험으로 패키지를 가져오려면:

  1. 다음 구성 요소의 코어패키지 번들 기능 패키지를 클릭하여 Studio 내에서 인벤토리에 추가하여 인벤토리에 추가 링크를 클릭하여 인벤토리에 패키지를 추가합니다.

  2. 도구 모음에서 보기 탭을 선택합니다.

  3. 클릭하십시오 도구 상자 . 도구 상자 창이 표시됩니다.

    Studio's View tab with the Toolbox tool highlighted.
  4. 도구 상자 창에서 인벤토리 탭을 클릭하십시오. 내 모델 정렬이 표시됩니다.

    Studio's Toolbox window with the Inventory tab highlighted.
  5. 클릭하십시오 기능 패키지 핵심 타일, 그리고 패키지 기능 번들 타일.두 패키지 폴더가 모두 탐색기 창에 표시됩니다.

  6. 패키지 폴더를 ReplicatedStorage 로 드래그합니다.

  7. 데이터 저장소 호출을 허용하여 패키지로 플레이어 구매를 추적합니다.

    1. 도구 모음의 탭에서 게임 설정 을 선택합니다.
    2. 보안 탭으로 이동한 후 API 서비스에 스튜디오 액세스 활성화 를 활성화합니다.

통화 정의

경험에 자체 통화 시스템이 있는 경우 코어 기능 패키지로 등록하여 정의할 수 있습니다.If your experience has its own currency system, you can register those with the ReplicatedStorage.FeaturePackagesCore.Configs.Currencies feature package by defining them in .이 파일에는 이미 주석이 달린 보석 통화의 예가 있으며, 자신의 것으로 교체합니다.

통화

Gems = {
displayName = "Gems",
symbol = "💎",
icon = nil,
},

스크립트는 코어 기능 패키지에 통화에 대한 일부 메타데이터를 알려줍니다:

  • (필수) displayName - 통화 이름. 기호나 아이콘을 지정하지 않으면 구매 버튼(예: "100 보석")에서 이 이름이 사용됩니다.
  • (옵션) symbol - 통화의 아이콘으로 사용할 텍스트 캐릭터가 있는 경우, 구매 버튼(예: "💎100")의 displayName 대신 사용됩니다.
  • (옵션) icon - 통화에 대한 AssetId 이미지 아이콘이 있는 경우 구매 버튼의 displayName 대신 사용됩니다(즉,이미지는 가격 "🖼️100"의 왼쪽에 배치됩니다)

통화가 설정되면 해당 정보가 번들의 연결된 개발자 제품에서 가져오는 대신 헤드업 디스플레이에 대한 패키지 가격, 통화 및 아이콘을 수동으로 지정해야 합니다.

패키지

-- 개발 제품을 사용하려면 하나의 번들사용되는 고유한 devProductId를 제공해야 합니다.
-- 개발자 제품에서 패키지 가격과 아이콘을 가져올 것입니다
pricing = {
priceType = CurrencyTypes.PriceType.Marketplace,
devProductId = 1795621566,
},
-- 그렇지 않으면, 개발 제품 대신 경험 통화를 사용하려면 다음을 사용할 수 있습니다.
-- 여기 가격은 경험 내 통화이며 Robux가 아닙니다
pricing = {
priceType = CurrencyTypes.PriceType.InExperience,
price = 79,
currencyId = "Gems",
icon = 18712203759,
},

또한 BundlesExample 스크립트를 참조하여 setInExperiencePurchaseHandler 를 호출해야 합니다.

패키지 예시

local function awardInExperiencePurchase(
_player: Player,
_bundleId: Types.BundleId,
_currencyId: CurrencyTypes.CurrencyId,
_price: number
)
-- 플레이어가 패키지를 구매할 수 있는 통화가 충분한지 확인
-- 플레이어 데이터 업데이트, 아이템 제공 등
-- 플레이어에서 통화 공제
task.wait(2)
return true
end
local function initializePurchaseHandlers()
local bundles = Bundles.getBundles()
for bundleId, bundle in bundles do
-- 시장 가격 입력없으면 패키지는 개발자 제품과 연결되지 않습니다
if not bundle or bundle.pricing.priceType ~= "Marketplace" then
continue
end
Bundles.setPurchaseHandler(bundleId, awardMarketplacePurchase)
receiptHandlers[bundle.pricing.devProductId] = receiptHandler
end
-- 번들에 사용하는 경험 통화가 있는 경우 처리기를 여기에 설정하십시오
for currencyId, _ in Currencies do
Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)
end
end

특히, 예제 내에서 루프를 통해 호출되는 를 채워야 합니다(즉,각 통화 ID는 처리기에 연결되어 Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)를 통해 연결됩니다.

패키지 정의

경험에서 사용할 수 있는 모든 패키지는 동일한 폴더에 있는 ReplicatedStorage.Bundles.Configs.Bundles 스크립트에서 내보낸 유형으로 정의될 수 있으며, 모든 패키지는 Types 스크립트에서 내보낸 유형으로 정의될 수 있습니다.

를 사용하는 경우, 경험에 있는 것과 일치하도록 패키지의 주요 를 업데이트해야 합니다.이것은 패키지 자체를 구매하기 위해 MarketplaceService을 통해 요청될 내용입니다. 번들에 대해 별도 판매를 추적하기 쉽도록 새 개발자 제품을 사용하는 것이 강력히 권장됩니다. 여러 항목이 포함된 패키지를 원하고 이러한 항목이 이미 경험에서 개발자 제품으로 표시되는 경우, 제품 정보를 통해 검색될 아이템 가격/아이템ID/이름을 명시적으로 설정할 필요가 없습니다.

읽기 파일 README

{
itemType = ItemTypes.ItemType.DevProduct,
devProductId = <DEV_PRODUCT_ID>,
metadata = {
caption = {
text = "x1",
color = Color3.fromRGB(236, 201, 74),
} -- 설명은 선택 사항입니다! 이 필드를 생략할 수도 있습니다
}
},

그렇지 않으면 수동으로 이러한 항목 세부 정보를 구성할 수 있습니다:

읽기 파일 README

{
itemType = ItemTypes.ItemType.Robux,
priceInRobux = 49,
icon = <IMAGE_ASSET_ID>,
metadata = {
caption = {
text = "x1",
color = Color3.fromRGB(236, 201, 74),
} -- 캡션은 선택적입니다! 이 필드를 생략할 수도 있습니다
}
},

예를 들어, 전체 번들은 아마도 이렇게 보일 것입니다:

읽기 파일 README

local starterBundle: Types.RelativeTimeBundle = {
bundleType = Types.BundleType.RelativeTime,
-- 개발 제품을 사용하려면 하나의 번들사용되는 고유한 devProductId를 제공해야 합니다.
-- 개발자 제품에서 패키지 가격과 아이콘을 가져올 것입니다
pricing = {
priceType = CurrencyTypes.PriceType.Marketplace,
devProductId = <DEV_PRODUCT_ID>,
},
-- 그렇지 않으면, 개발 제품 대신 경험 통화를 사용하려면 다음을 사용할 수 있습니다.
-- 여기 가격은 경험 내 통화이며 Robux가 아닙니다
-- 가격 = {
-- priceType = 통화 유형.PriceType.InExperience,
-- 가격 = 79,
-- 통화 ID = <CURRENCY_ID>,
-- 아이콘 = <IMAGE_ASSET_ID>,
-- },
includedItems = {
[1] = {
-- 아이템 자체는 개발자 제품을 통해 판매되지 않으므로 Robux의 가치와 아이콘을 나타내세요
-- The priceInRobux는 패키지가 패키지 가격과 내용의 합계 값의 상대적 값을 표시하도록 돕습니다
itemType = ItemTypes.ItemType.Robux,
priceInRobux = 49,
icon = <IMAGE_ASSET_ID>,
-- 또는 이 제품에 개발자 제품 가격과 아이콘이 있고 devProductId만 설정하면 됩니다.
-- 가격과 아이콘은 개발자 제품에서 가져옵니다
-- devProductId = <항목_개발_제품_ID>
-- 필요한 경우 UI와 관련된 선택적 메타데이터 필드가 더 있습니다
metadata = {
caption = {
text = "x1",
color = Color3.fromRGB(236, 201, 74),
},
},
},
[2] = {
itemType = ItemTypes.ItemType.Robux,
priceInRobux = 99,
icon = <IMAGE_ASSET_ID>,
metadata = {
caption = {
text = "x1",
color = Color3.fromRGB(236, 201, 74),
},
},
},
[3] = {
itemType = ItemTypes.ItemType.Robux,
priceInRobux = 149,
icon = <IMAGE_ASSET_ID>,
metadata = {
caption = {
text = "x1",
color = Color3.fromRGB(236, 201, 74),
},
},
},
},
singleUse = true, -- 구매하거나 만료되면 경험이 (onPlayerAdded)에서 프롬프트를 시도해도 더 이상 유효하지 않습니다. 스튜디오에서 테스트하는 동안 이를 거짓으로 만들 수 있습니다.
durationInSeconds = 900, -- 15분
includesOfflineTime = false, -- 경험에서 지나간 시간만 계산하기
metadata = {
displayName = "STARTER BUNDLE",
description = "Save 75% and get a head start!",
},
}

서버 논리 통합

서버가 패키지 기능 팩과 위의 방법과 상호작용하는 방법을 보여주는 을 살펴보세요.아래 스니펫은 해당 스크립트에서 나옵니다.

주로 패키지 번들 기능 패키지를 경험에 끌어들인 후 네 가지를 연결해야 합니다.

  1. 구매 처리기를 Bundles.setPurchaseHandler를 통해 연결하여 구매가 처리될 때 보상 아이템에 호출할 함수를 지정합니다.

    패키지 예시

    local function awardMarketplacePurchase(_player: Player, _bundleId: Types.BundleId, _receiptInfo: { [string]: any })
    -- 플레이어 데이터 업데이트, 아이템 제공 등
    -- ... 그리고 구매 정보를 기록하여 사용자가 이미 이 번들보유하고 있는지 확인할 수 있습니다
    task.wait(2)
    return Enum.ProductPurchaseDecision.PurchaseGranted
    end
    local function awardInExperiencePurchase(
    _player: Player,
    _bundleId: Types.BundleId,
    _currencyId: CurrencyTypes.CurrencyId,
    _price: number
    )
    -- 플레이어가 패키지를 구매할 수 있는 통화가 충분한지 확인
    -- 플레이어 데이터 업데이트, 아이템 제공 등
    -- 플레이어에서 통화 공제
    task.wait(2)
    return true
    end
    local function initializePurchaseHandlers()
    local bundles = Bundles.getBundles()
    for bundleId, bundle in bundles do
    -- 시장 가격 입력없으면 패키지는 개발자 제품과 연결되지 않습니다
    if not bundle or bundle.pricing.priceType ~= "Marketplace" then
    continue
    end
    Bundles.setPurchaseHandler(bundleId, awardMarketplacePurchase)
    receiptHandlers[bundle.pricing.devProductId] = receiptHandler
    end
    -- 번들에 사용하는 경험 통화가 있는 경우 처리기를 여기에 설정하십시오
    for currencyId, _ in Currencies do
    Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)
    end
    end
  2. 논리를 MarketplaceService.ProcessReceipt에 연결하지만, 경험에 이미 판매 중개발자 제품이 있으면 다른 곳에서 수행할 수 있습니다.본질적으로, 개발자 제품 영수증이 처리되는 경우, 이제 Bundles.getBundleByDevProduct 를 호출하여 제품이 번들속해 있는지 확인합니다.그렇다면 스크립트는 Bundles.processReceipt 을 호출합니다.

    패키지 예시

    -- 플레이어에게 요금을 청구해야 하는지 여부를 결정하기 위해 마켓플레이스에서 받은 영수증 처리
    local function processReceipt(receiptInfo): Enum.ProductPurchaseDecision
    local userId, productId = receiptInfo.PlayerId, receiptInfo.ProductId
    local player = Players:GetPlayerByUserId(userId)
    if not player then
    return Enum.ProductPurchaseDecision.NotProcessedYet
    end
    local handler = receiptHandlers[productId] -- 제품의 핸들러 가져오기
    local success, result = pcall(handler, receiptInfo, player) -- 구매 논리가 성공했는지 처리기를 호출하여 확인하세요
    if not success or not result then
    warn("Failed to process receipt:", receiptInfo, result)
    return Enum.ProductPurchaseDecision.NotProcessedYet
    end
    return Enum.ProductPurchaseDecision.PurchaseGranted
    end
    local function receiptHandler(receiptInfo: { [string]: any }, player: Player)
    local bundleId, _bundle = Bundles.getBundleByProductId(receiptInfo.ProductId)
    if bundleId then
    -- 이 구매는 번들속하며, 패키지가 처리하도록 합니다
    local purchaseDecision = Bundles.processReceiptAsync(player, bundleId, receiptInfo)
    return purchaseDecision == Enum.ProductPurchaseDecision.PurchaseGranted
    end
    -- 이 구매는 번들속하지 않습니다,
    -- ... 여기에 기존 논리가 있으면 모두 처리합니다 if you have any
    return false
    end
  3. 연결 Players.PlayerAdded:Connect(Bundles.OnPlayerAdded) 그래서 패키지 번들 기능 패키지가 플레이어에게 아직 만료되지 않은 활성 패키지를 다시 요청합니다.

    읽기 파일 README

    local function onPlayerAdded(player: Player)
    -- 플레이어가 참여할 때 패키지에 알려서 데이터를 다시 로드할 수 있도록 하기
    Bundles.onPlayerAdded(player)
    -- 모든 새 사용자에게 제공하고 싶은 스타터 패키지가 있는 경우 여기에서 요청할 수 있습니다
    -- ... 패키지는 플레이어가 이미 구매했거나 반복할 수 없기 때문에 만료된 경우 처리합니다
    -- Bundles.promptIfValidAsync(플레이어, "스타터 번들")
    -- 여기에서 예제로 호출하는 경우, 언제든지 또는 원하는 위치에서 호출할 수 있습니다
    onPromptBundleXYZEvent(player)
    end
  4. 프롬프트 패키지. 게임 플레이따라 이것이 달라지지만, 예제에서는 StarterBundle onPlayerAdded 을 사용하여 플레이어를 프롬프트합니다.

    • 패키지 기능 패키지 논리는 플레이어가 번들이미 구매했거나 제안을 이미 만료했을 경우 중복 제안을 받지 않도록 보장합니다(패키지 구성에 따라).

    • 번들을 플레이어에게 프롬프트하려면 Bundles.promptIfValidAsync(player, bundleId) 를 호출하십시오.

    읽기 파일 README

    local function onPromptBundleXYZEvent(player: Player)
    -- 사용하려는 경험 이벤트를 연결하여 플레이어가 패키지를 받을 때를 번들
    -- ... 플레이어에게 패키지를 제공하도록 요청하기 위해 적격 기준을 충족할 때마다 이런 일이 발생합니다
    -- 예를 들어, 플레이어가 참여하거나 플레이어가 레벨업할 때 패키지를 프롬프트하려는 경우...
    task.spawn(Bundles.promptIfValidAsync, player, <Some_Bundle_Id>)
    -- ... 여러 번들을 생성하는 경우, task.spawn()를 사용하여 위의 함수 호출을 래핑하면 카운트다운 간의 차이가 최소화됩니다
    end

다음 ReceiptIds의 중복 녹음에 대한 모범 사례 지침을 고려하십시오:

  • 패키지 기능 패키지는 동일한 영수증을 두 번 처리하지 않도록 ReceiptIds를 기록하지만, 구매 처리기가 구매 처리기가 이미 완료된 후에 실패하면 다음 재시도에서 아이템을 다시 수여하지 않도록 알기 위해 테이블 내에서 ReceiptIds를 기록해야 합니다.

  • 패키지 기능 패키지는 구매가 어느 단계에서든 실패하면 ReceiptId를 기록하지 않으므로 구매처리기의 일부로 받기를 처리하기 전에 테이블에서 ReceiptId를 기록하는지 확인해야 합니다.

  • 이러한 중복은 모든 구매 논리가 적절하게 처리되었으며 데이터 저장소와 패키지 번들 기능 패키지의 데이터 저장소가 최종 일관성에 도달했으며 데이터 저장소가 진실의 근원이라는 것을 보장하는 데 도움이 됩니다.

상수 구성

코어 기능 패키지의 상수는 두 곳에서 살아갑니다:

  • 공유 상수는 ReplicatedStorage.FeaturePackagesCore.Configs.SharedConstants에 살고 있습니다.

  • 이 경우 패키지별 상수, 즉 패키지 번들 기능 패키지가 ReplicatedStorage.Bundles.Configs.Constants에 살고 있습니다.

경험의 디자인 요구 사항을 충족하기 위해 조정할 주요 사항:

  • 사운드 자산 ID
  • 구매 효과 지속 시간 및 파편 색상 구매 효과 지속 시간 및 파편 색상
  • 헤드업 디스플레이 축소 가능성 주의

또한, 번역에 대한 문자열을 하나의 위치로 분리할 수 있습니다: ReplicatedStorage.FeaturePackagesCore.Configs.TranslationStrings.

UI 구성 요소 사용자 지정

색상, 글꼴 및 투명도와 같은 패키지 개체를 수정하여 번들 프롬프트의 시각적 표현을 조정할 수 있습니다.그러나 계층적으로 개체 중 하나를 이동하면 코드가 찾을 수 없으므로 코드를 조정해야 합니다.

프롬프트는 두 가지 고위 구성 요소로 구성됩니다:

  • PromptItem – 번들 내의 각 항목에 대해 반복되는 개별 구성 요소(아이템 이미지, 캡션, 이름, 가격).
  • Prompt – 프롬프트 창 자체.

경고 표시는 두 가지 구성 요소로 구성됩니다:

  • HudItem – 각 메뉴 옵션을 헤드업 디스플레이에 나타내는 개별 구성 요소.
  • Hud – 프로그래밍 방식으로 채워지기 위해 HudItems로 채워집니다.

헤드업 디스플레이에 대한 더 많은 제어를 원하는 경우, ReplicatedStorage.Bundles.Objects.BundlesGui 내에 기존 HUD UI만 사용하는 대신, 자신의 디자인 요구 사항을 충족하기 위해 항목을 이동할 수 있습니다.단지 클라이언트 스크립트 동작을 업데이트하는 것만으로는 충분하지 않습니다. 스크립트 ReplicatedStorage.Bundles.Client.UIController에서 클라이언트 스크립트 동작을 업데이트해야 합니다.

API 참조

유형

상대 시간

플레이어에게 RelativeTime 패키지가 제공되면 시간 제한이 끝날 때까지 사용할 수 있습니다.이 유형은 플레이어의 헤드업 디스플레이에 표시되며, 패키지가 만료되거나 플레이어가 구매할 때까지 미래의 세션에 대해 자동으로 프롬프트합니다.

이 패키지 유형의 일반적인 예는 24시간 동안 모든 새 플레이어에게 표시되는 일회용 스타터 팩 제안입니다.스타터 팩 번들을 구현하는 방법에 대한 업계 모범 사례는 스타터 팩 디자인을 참조하십시오.

이름유형설명
includeOfflineTimebool (옵션) 설정되지 않으면 경험에서 소비한 시간만 남은 제안 기간에 포함됩니다.
singleUsebool(옵션) 설정되지 않으면 구매가 구매되거나 만료된 후 다시 활성화될 수 있습니다.설정되면 처음 구매하거나 만료된 후 번들ID로 호출하면 다시는 요청되지 않습니다.

고정 시간

플레이어에게 FixedTime 패키지가 제공되면 UTC의 세트 조정된 시간이 끝날 때까지 사용할 수 있습니다.이 유형은 플레이어의 헤드업 디스플레이에 표시되며, 패키지가 만료되거나 플레이어가 구매할 때까지 미래의 세션에 대해 자동으로 프롬프트합니다.

이 패키지 유형의 일반적인 예는 특정 월에만 사용할 수 있는 휴가 제안입니다.

일회성 OneTime

A OneTime 패키지는 플레이어에게 제공된 순간에만 사용할 수 있습니다.플레이어의 헤드업 디스플레이에 표시되지 않으며, 플레이어가 프롬프트를 닫으면 서버에 의해 다시 프롬프트가 표시될 때까지 다시 열 수 없습니다.

이 패키지 유형의 일반적인 예는 플레이어가 경험 내 통화를 더 구매하기를 원할 때 제공하는 제안입니다.