Roblox добавил публикацию EditableImage прямо из игры в инвентарь
Переименование и запуск функции
Метод AssetService:PromptCreateAssetAsync(Instance) переименован в AssetService:PromptCreatePlatformContentAsync(Object). Теперь функция принимает Object вместо Instance, что задаёт более чистый стандарт для всех будущих промптов создания и публикации ассетов внутри игры.
Сегодня загрузка EditableImage напрямую через PromptCreatePlatformContentAsync полностью выпущена и работает. Разработчики могут публиковать EditableImage прямо из геймплея в инвентарь игроков без необходимости выводить их на внешние страницы.
Требования к тестированию
При тестировании в Studio обязательно используйте опубликованное место (published place), иначе публикация завершится ошибкой. Также в настройках игры должно быть включено «Allow Mesh / Image APIs».
Для работы метода Prompt необходимо, чтобы CoreGui был загружен, поэтому перед вызовом публикации нужно дождаться player.CharacterAdded:Wait().
Пример серверного скрипта
Официальный пример рисует логотип Roblox прямо из ServerScript и предлагает игроку загрузить его. Ниже полный код для проверки:
local AssetService = game:GetService("AssetService") local Players = game:GetService("Players") local BLUE = {49, 86, 255} local WHITE = {255, 255, 255} local SIZE = 400 local CENTER = SIZE / 2 local OUTER_HALF = 100 local INNER_HALF = 28 local ANGLE = math.rad(15) local COS = math.cos(ANGLE) local SIN = math.sin(ANGLE) local SAMPLES = 4 local function isInsideSquare(x, y, halfSize) return math.abs(x) <= halfSize and math.abs(y) <= halfSize end local function generateLogo() local editableImage = AssetService:CreateEditableImage({ Size = Vector2.new(SIZE, SIZE), }) if not editableImage then warn("Could not create EditableImage. Make sure access to the Editable Mesh / Image apis is enabled.") return nil end local pixels = buffer.create(SIZE * SIZE * 4) for py = 0, SIZE - 1 do for px = 0, SIZE - 1 do local whiteSamples = 0 -- Test subpixel positions to antialias the edges. for sy = 0, SAMPLES - 1 do for sx = 0, SAMPLES - 1 do local screenX = px + (sx + 0.5) / SAMPLES - CENTER local screenY = py + (sy + 0.5) / SAMPLES - CENTER -- Undo the square's clockwise rotation. local x = screenX * COS + screenY * SIN local y = -screenX * SIN + screenY * COS local outer = isInsideSquare(x, y, OUTER_HALF) local inner = isInsideSquare(x, y, INNER_HALF) if outer and not inner then whiteSamples += 1 end end end local coverage = whiteSamples / (SAMPLES * SAMPLES) local offset = (py * SIZE + px) * 4 for channel = 1, 3 do local background = BLUE[channel] local foreground = WHITE[channel] local value = background + (foreground - background) * coverage buffer.writeu8(pixels, offset + channel - 1, math.floor(value + 0.5)) end buffer.writeu8(pixels, offset + 3, 255) end end editableImage:WritePixelsBuffer( Vector2.zero, Vector2.new(SIZE, SIZE), pixels ) return editableImage end Players.PlayerAdded:Connect(function(player) -- CoreGui needs to be loaded for the Prompt method to work. player.CharacterAdded:Wait() local logo = generateLogo() local success, result, assetId = pcall(function() return AssetService:PromptCreatePlatformContentAsync(player, logo, Enum.AssetType.Image) end) if success then print("Published successfully! Result:", result, "AssetId:", assetId) else warn("Failed to publish image:", result) end end)
Интерактивный редактор на LocalScript
Для более интерактивного сценария создайте RemoteEvent с именем PublishDrawing в ReplicatedStorage. Затем добавьте LocalScript в StarterPlayerScripts: он обрабатывает взаимодействие пользователя, при публикации записывает EditableImage в buffer и отправляет его через RemoteEvent на сервер.
-- LocalScript in StarterPlayer > StarterPlayerScripts local Players = game:GetService("Players") local AssetService = game:GetService("AssetService") local UserInputService = game:GetService("UserInputService") local player = Players.LocalPlayer -- Configuration local CANVAS_SIZE = 256 local BRUSH_RADIUS = 5 local BACKGROUND = Color3.fromRGB(255, 255, 255) local COLORS = { Color3.fromRGB(25, 25, 35), Color3.fromRGB(255, 70, 70), Color3.fromRGB(255, 170, 40), Color3.fromRGB(255, 220, 60), Color3.fromRGB(70, 200, 110), Color3.fromRGB(50, 130, 255), Color3.fromRGB(160, 90, 255), Color3.fromRGB(255, 110, 200), Color3.fromRGB(255, 255, 255), } -- Helpers local function make(className, props, parent) local object = Instance.new(className) for key, value in pairs(props) do object[key] = value end object.Parent = parent return object end local function round(gui, radius) make("UICorner", { CornerRadius = UDim.new(0, radius), }, gui) end -- UI local gui = make("ScreenGui", {
