ROBLOX — Монетизация — Проблемы реальности

Автор: | 27 марта, 2020
Поделиться...

Описанные ранее способы монетизации конечно работают. Но вот пришла беда, откуда не ждали! Они «теряются» если персонаж умирает! Или когда игрок жмёт «Reset character». Вот уж действительно — нежданчик.

Пришлось пересмотреть подход к сохранению информации о покупки конкретным игроком.

Во первых данная информация должна хранится на сервере.

Во вторых данная информация должна загружаться после смерти персонажа.

В третьих там должна храниться информация и о временных покупках, если они накладывают какой-то эффект на самого персонажа.

Варианты были разные. Но у всех были какие-либо недостатки и тут меня осенило! Единственное что не изменяется пока игрок не вышел это сам игрок! Провёл небольшое тестирование и вот оно — решение найдено = нужно хранить данные о покупках в переменных, которые будут лежать в самом игроке!

Но, так как при входе игрока этих переменных нет, то их надо создать. А также нужно их читать, когда игрок воскрешается.

Для начала, переделал код для GamePass-а:

--[[
https://developer.roblox.com/en-us/api-reference/event/Player/CharacterAdded
https://developer.roblox.com/en-us/api-reference/event/Player/CharacterRemoving/index.html
https://developer.roblox.com/en-us/api-reference/property/Player/Character/index.html
https://developer.roblox.com/en-us/api-reference/event/IntValue/Changed
]]--
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local tmp

local id1 = 8626045 -- id gamepass - 5s

-- ищем игрока
-- добавляем ему флаг, что оно куплено
-- убираем с экрана возможность покупки

local function buy(tmp)
	local plr = game.Players:FindFirstChild(tmp)
	local char =  plr.Character:WaitForChild("HumanoidRootPart")
	RunService.Stepped:wait()
	char = plr.Character
	if char ~= nil then -- игрок не покинул игру
		if game:GetService("MarketplaceService"):UserOwnsGamePassAsync(game.Players[char.Name].UserId, id1) then
			-- что тут нужно сделать?!			
			char.Humanoid.WalkSpeed = 30
			
			if plr:FindFirstChild("Buy") == nil then -- проверяем наличие переменной, если нет - создаём
				local Buy = Instance.new("IntValue")
				Buy.Parent = plr
				Buy.Name = "Buy"
				Buy.Value = 5
			end		
			-- а теперь убираем Frame покупки
			local pl = game.Players:FindFirstChild(plr.Name)
			if pl ~= nil then
				pl.PlayerGui.Main.GamePass.Visible=false
				pl.PlayerGui.Main.Answer.Visible=true
			end			
		end
	end	
end

-- проверка уже приобретённого пропуска при подключении игрока
game.Players.PlayerAdded:Connect(function(plr)
	plr.CharacterAdded:connect(function(char)
		buy(char.Name)
	end)

    plr.CharacterRemoving:Connect(function(char)		
		buy(char.Name)
		local pl = plr -- Players:GetPlayerFromCharacter(char)
		if pl:FindFirstChild("Buy") ~= nil then -- проверяем наличие переменной
			if pl.Buy.Value == 3 then
				pl.PlayerGui.Main.GameDev.Visible=false
				pl.PlayerGui.Main.Answer.Visible=true
			end
		end
    end)
end)

-- проверка на совершении покупки
game:GetService("MarketplaceService").PromptGamePassPurchaseFinished:Connect(function(plr,ido,purchased)
	if purchased and ido == id1 then -- пропуск с id1
		-- local char = plr.Character
		buy(plr.Name)
	end
end)

Как можно заметить, я немножко оптимизировал. Вынес код необходимых действий из блоков на вход игрока и покупку игроком GamePass в самой игре в отдельный блок, которому в качестве параметра просто передаётся имя игрока.

В подключении игрока теперь не только создание чара — CharacterAdded, но и его удаление — CharacterRemoving. Это удаление и происходит при смерти персонажа или когда нажата вышеупомянутая кнопка.

Так же добавил «уборку» с экрана возможности покупки GamePass-а, если он у нас уже куплен. Нечего ему глаза мозолить.

Так как у GamePass-а значение 5 чуть выше, чем у временной покупки — 3 , то обошёлся одной переменной.

local MS = game:GetService("MarketplaceService") -- сокращение для вызова сервиса

local function processReceipt(ReceiptInfo)
	local player = game:GetService("Players"):GetPlayerByUserId(ReceiptInfo.PlayerId) -- получаем Id игрока
	
	if not player then -- если не игрок, то вылетаем
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end
	
	-- если игрок найден, выполняем действия
	-- print(ReceiptInfo.PlayerId .. " buy " .. ReceiptInfo.ProductId)	
	local char=player.Character
	if player:FindFirstChild("Buy") == nil then -- проверяем наличие переменной, если нет - создаём
		local Buy = Instance.new("IntValue")
		Buy.Parent = player
		Buy.Name = "Buy"
		Buy.Value=3
	else
		player.Buy.Value = 3
	end
	char.Humanoid.WalkSpeed = 30
	-- а теперь убираем Frame покупки
	local pl = game.Players:FindFirstChild(player.Name)
	if pl ~= nil then
		pl.PlayerGui.Main.GameDev.Visible=false
		pl.PlayerGui.Main.Answer.Visible=true
	end
	
	-- возвращаем, что покупка произведена
	return Enum.ProductPurchaseDecision.PurchaseGranted
	
end

MS.ProcessReceipt= processReceipt

Как видим, всё оказалось не так уж и страшно, если знать что искать.

Остальные скрипты (для кнопок) остались без изменений.

И как всегда, результат можно увидеть и опробовать на странице арифметического тренажёра:

https://www.roblox.com/games/4789977549/Math-Rocket


Поделиться...

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *