В предыдущих частях мы создали мир и разместили в нём ресурсы. Пора начать их добывать. Для этого нам понадобится инструмент добычи. Но не один, а два. Первый будет рубящий, второй дробящий. Ведь камень особо не порубишь, а дерево наоборот не особо раздробишь. Вот так и получаем что нам нужны топор и кирка. Естественно возьмём уже готовые из тулбокса. И конечно переделаем скрипты их использования. (Выбрать что-то стоящее та ещё головная боль.)
Второй шаг, определить что мы получаем с ресурса и в каких.. пропорциях. Естественно исходя из используемого орудия труда. У нас уже есть Configure что отвечает за появление ресурсов. Создадим аналогичную таблицу для добычи ресов. Примерно такую, но в Роблоксе:
Но сперва мы должны определиться — что для нас главнее (удобнее): источник ресурсов, инструмент или же сами добываемые ресурсы? Я решил что это будут источники ресурсов. Потому что:
- Источников ресурсов будет гораздо больше, чем инструментов
- Самих ресурсов может быть слишком много
- У источников ресурсов может не быть полного перечня инструментов для добычи
- Источник ресурсов будет получать урон, если он присутствует в перечне
Это конечно не полный перечень доступного в натуральной игре, но пока что и этого будет достаточно. (Как минимум мы опустим такой критерий как величина урона в зависимости от инструмента и самого ресурса.) В итоге получаем следующий модуль конфигурации:
Ну вот, мы определились что, из чего и чем мы будем добывать. Теперь можно переходить к программированию инструментов. Хотя нет. Сперва нам нужно в наш инструмент добавить описание его типа (имена могут быть разные, а тип от этого не изменится) и базовую силу удара (поставим от балды — после исправим).
На примере кирки:
- StringValue.Name = IsType
- StringValue.Value = pickaxe
- IntegerValue.Name = BaseDamage
- IntegerValue.Value = 100
Мы звёзд с неба не хватаем, а потому будем делать всё сразу серверным скриптом (для пробы нам хватит). Пора ваять скрипт? Нет, сперва теория!
- Первично инструмент попадает в Backpack находящийся в Player-е соответствующего игрока
- При экипировке инструмента он переносится в персонажа игрока
- При снятии инструмента он переносится обратно в Backpack
- Кроме одеть/снять есть ещё вариант активации инструмента (для нас это — удар)
- В инструменте есть обязательный элемент Handle, определяющий как он будет держаться в руке
Из этого выходит что наша болванка скрипта будет выглядеть так:
-- скрипт управления инструментом добычи ресурсов local Players = game:GetService("Players") local me = script.Parent -- объект инструмента local isType = me:WaitForChild("IsType").Value -- тип инструмента local damage = me:WaitForChild("BaseDamage").Value -- полный урон local handle = me:WaitForChild("Handle") -- рукоять инструмента -- одели инструмент me.Equipped:Connect(function() print("одели") end) -- сняли инструмент me.Unequipped:Connect(function() print("сняли") end) -- активировали инструмент me.Activated:Connect(function() print("активировали") end)
Если обратить внимание, то нам как бы одел/снял не особо то и нужны. В реальности они нужны для воспроизведения звуков и анимации соответствующего действия, а нам же это не важно. С учётом сказанного, активировать мы можем только в случае, если у нас уже одет тулс. Т.е. при активации нам надо лишь произвести анимацию атаки и проверить во что мы попали за время этой самой атаки.
Анимацию будем запускать дедовским методом — создание текстовой строки в инструменте с её надписью. И.. всё таки пусть у нас повреждения наносит не рукоять, наконечник инструмента. А чтобы его определить мы просто зададим PrimaryPart в нашем инструменте с указанием на этот самый наконечник. Таким образом нам не придётся заботится о названии наконечника. Добавляем функцию столкновения и переменную активности атаки:
local attack = false -- активен ли режим атаки? local function Attack(hit) if attack == true then print(hit.Parent) -- в какую модель попали? end end handle.Touched:Connect(Attack) -- активировали инструмент me.Activated:Connect(function() print("активировали") attack = true -- включаем режим атаки -- запуск анимации local anim = Instance.new("StringValue") anim.Name = "toolanim" anim.Value = "Slash" anim.Parent = me task.wait(1) attack = false -- выключаем режим атаки end)
Ну что же, постучав по деревьям и камням (а так же по земле), мы находим что нам нужно дописать в функции атаки, чтобы она у нас реагировала только на попадание по нужным объектам. А ещё нам нужно определять, чтобы по одному и тому же объекту не попадали несколько раз…
А ещё.. нам нужно определить сколько всего ресурсов в источнике и его остаток «здоровья». И уничтожить объект если здоровье кончилось. Вот итоговый скрипт:
-- скрипт управления инструментом добычи ресурсов local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local me = script.Parent -- объект инструмента local resource = ReplicatedStorage:WaitForChild("Resource") -- папка с конфигами local config = require(resource:WaitForChild("Configure")) -- основной конфиг local extraction = require(resource:WaitForChild("Extraction")) -- конфиг инструментов local isType = me:WaitForChild("IsType").Value -- тип инструмента local damage = me:WaitForChild("BaseDamage").Value -- полный урон -- local handle = me:WaitForChild("Handle") -- рукоять инструмента local handle = me.PrimaryPart -- что наносит урон -- одели инструмент me.Equipped:Connect(function() -- print("одели") end) -- сняли инструмент me.Unequipped:Connect(function() -- print("сняли") end) local attack = false -- активен ли режим атаки? local target = {} -- список объектов по которым попали local function Attack(hit) if attack == true then -- print(hit.Parent) local model = hit.Parent -- в какую модель попали? if model:IsA("Model") then -- это модель? -- данная модель расположена в папке заспавненных ресурсов if model.Parent == workspace.Resource then if target[model] == nil then -- ещё не фиксировали данную цель target[model] = true -- фиксируем попадание end end end end end handle.Touched:Connect(Attack) -- активировали инструмент me.Activated:Connect(function() -- print("активировали") table.clear(target) -- зачищаем таблицу попаданий attack = true -- включаем режим атаки -- запуск анимации local anim = Instance.new("StringValue") anim.Name = "toolanim" anim.Value = "Slash" anim.Parent = me task.wait(1) -- ожидание конца анимации attack = false -- выключаем режим атаки -- warn(target) -- будем определять нанесённый урон и полученные ресурсы for object, b in pairs(target) do local find = config[object.Name] -- нет в конфиге = нет урона if find then -- есть в основном конфиге -- читаем, задаём стартовые значения local health = object:FindFirstChild("Health") -- осталось здоровья if health == nil then -- ещё не наносили урон = нет переменных local scale = object:GetScale() -- какой масштаб использован local orient, size = object:GetBoundingBox() -- нам нужен только размер -- создадим переменную здоровья в модели health = Instance.new("NumberValue") health.Name = "Health" health.Value = 300 * scale -- 300 это базовое здоровье (лучше в конфиг задать) health.Parent = object -- аналогично создадим переменную объёма ресурса local res = Instance.new("NumberValue") res.Name = "Resource" local size = (find.SizeMax - find.SizeMin) local def = find.RessMin + (find.RessMax - find.RessMin) / size * (scale - find.SizeMin) res.Value = def -- значение зависит от размера и заданных параметров res.Parent = object end local res = object:FindFirstChild("Resource") -- максимум ресурсов на удар print(object, health.Value, res.Value) -- рассчитаем что получаем local give = extraction[object.Name][isType] -- print(isType, give) for name, procent in pairs(give) do -- полученные ресурсы if name ~= "None" then local val =math.floor( (procent/100) * res.Value * math.random() ) if val > 0 then warn("Получено:", name, val) end end end -- теперь нанесём повреждание local newHealth = health.Value - damage if newHealth > 0 then health.Value = newHealth else -- уничтожаем объект object:Destroy() end end end end)
Внимательный читатель заметит, что наши конфиги имеют одинаковые блоки, а значит их можно объединить и избавиться от лишнего файла в игре.
Доработать (добавить) можно
- Анимации достал, убрал инструмент
- Анимации ударов под конкретный инструмент
- Визуал получения повреждений
- Озвучку удара, получение урона
- Сохранение полученных ресурсов в инвентаре игрока
- …придумайте сами…
Ну и собственно итоговый плейс: