Форум программистов, компьютерный форум, киберфорум
Unity, Unity3D
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
399 / 308 / 104
Регистрация: 07.05.2017
Сообщений: 2,211

Система крафта, схема проверки и хранения "чертежей"

07.01.2026, 19:00. Показов 722. Ответов 15

Студворк — интернет-сервис помощи студентам
Поделитесь други, кто какие инструменты шарпа использовал для этой цели. и какова основная схема проверки и хранения "чертежей" может быть.
заранее спасибо!
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
07.01.2026, 19:00
Ответы с готовыми решениями:

Как удобнее вывести рецепт крафта в инспектор?
Есть у меня в игре некоторое количество ресурсов, различных, они используются для крафта тех или...

2d чертеж в unity
друзья, нужна помощь!!! есть ооооочень большой 2d чертеж, сделанный в компасе, в котором порядка...

Хранение данных
Всем привет, я новичок в юнити, хотел задать следущий вопрос. Делаю игру с уровнями на android,...

15
1144 / 309 / 159
Регистрация: 30.07.2022
Сообщений: 1,782
Записей в блоге: 4
08.01.2026, 00:32
Gammister,

На мой взгляд struct это самый простой способ для хранения рецептов.

Тут зависит от того как вы в принципе организуете инвентарь.
И каким вы видите крафт. Референсы в студию. Или тех.задание хотя бы. Чтоб было от чего отталкиваться.
0
399 / 308 / 104
Регистрация: 07.05.2017
Сообщений: 2,211
08.01.2026, 14:15  [ТС]
хотя бы примерно, как майнкрафте. в принципе техническая часть инвентаря не очень интересна. сам способ хранения и проверки, сошелся ли рецепт. их ведь может быть много. допустим структура хранит в себе рецепт в каком виде? может быть рецепты хранить уже в классах с набором (массивом) более атомарных элементов в виде структур (ингредиентов).

в ролике CodeMonkey реализовано таким образом, что рецепт собирается по проверке расположения по определенным ячейкам. то есть чтобы собрать меч, ингредиенты нужно расположить вертикально и по середине панели 3х3.

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

сам инвентарь сейчас не важен. пока что. интересует, как именно организовать вот эту часть кода.

в общем я пока понимаю примерно так:

структуры / контейнеры для них (рецепты) / коллекции контейнеров для проверки в цикле / возврат объекта при активации создания.

визуал всего этого добра поэтапно обсудим, если возникнут проблемы. пока что интересна сама кодовая основа процесса. логический костяк так сказать.

пока что можно имитировать инвентарь можно заполнением массива в инспекторе. для теста.
заранее спасибо!

Добавлено через 12 минут
ну и айтемы конечно же будут производными классами либо под общим интерфейсом, что упростит совместимость, если что
0
1144 / 309 / 159
Регистрация: 30.07.2022
Сообщений: 1,782
Записей в блоге: 4
08.01.2026, 22:55
Лучший ответ Сообщение было отмечено Gammister как решение

Решение

Gammister, вижу рецепт как массив айтемов.
а крафт сравнение массива из рецепта с массивом "рабочего стола".

C#
1
2
3
4
5
6
7
8
9
[CreateAssetMenu(fileName = "NewItem", menuName = "Crafting/Item")]
public class Item : ScriptableObject
{
    public string ID;
    public string itemName;
    public Sprite icon;
    public int maxStackSize = 64;
    public GameObject prefab; // для дропа в мире
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[CreateAssetMenu(fileName = "NewRecipe", menuName = "Crafting/Recipe")]
public class Recipe : ScriptableObject
{
    [Header("Рецепт 3x3")]
    public Item[] ingredients = new Item[9]; // как в Minecraft
    
    [Header("Результат")]
    public Item result;
    public int resultAmount = 1;
    
    public bool CanCraft(Item[] grid) // grid - это содержимое рабочего стола этот метод вызывается в окне крафта
    {
        for (int i = 0; i < 9; i++)
        {
            if (grid[i] != ingredients[i])
                return false;
        }
        return true;
    }
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class CraftingSystem : MonoBehaviour
{
    public Item[] craftingGrid = new Item[9]; // текущая сетка крафта
    public List<Recipe> allRecipes = new List<Recipe>();
    public PlayerInventory inventory;
    
    // Добавить предмет в сетку крафта
    public void AddToCraftingGrid(int slotIndex, Item item)
    {
        if (slotIndex < 0 || slotIndex >= 9) return;
        
        craftingGrid[slotIndex] = item;
        CheckForRecipe();
    }
    
    // Проверить рецепт
    private void CheckForRecipe()
    {
        foreach (var recipe in allRecipes)
        {
            if (recipe.CanCraft(craftingGrid))
            {
                CraftItem(recipe);
                return;
            }
        }
    }
    
    // Создать предмет
    private void CraftItem(Recipe recipe)
    {
        // Проверяем инвентарь
        if (inventory.RemoveItemsForCrafting(recipe.ingredients))
        {
            // Добавляем результат
            inventory.AddItem(recipe.result, recipe.resultAmount);
            
            // Очищаем сетку крафта
            ClearCraftingGrid();
        }
    }
    
    // Очистить сетку
    private void ClearCraftingGrid()
    {
        for (int i = 0; i < craftingGrid.Length; i++)
        {
            craftingGrid[i] = null;
        }
    }
}
Цитата Сообщение от Gammister Посмотреть сообщение
проверять на сходство с доступными рецептами
искать по ингредиентам рецепт может быть жутко неудобно, тем более, что ингредиенты могут быть в любом порядке. Сначала последний, а в конце первый.

ТОгда вам надо будет отсортировать каким то образом ингредиенты на рабочем столе и в рецепте(хотя бы по алфавиту),
чтобы их порядок всегда соответствовал единому стандарту. Это можно добавить в метод private void CheckForRecipe().
Тогда подойдет и пример приведенный в листинге выше. А длина массива, должна соответствовать самому длинному рецепту.
и наверное массивы лучше заменить на List<>, чтоб сортировать выло легче.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System.Linq;
using UnityEngine;
 
public class ItemSorter : MonoBehaviour
{
    public List<Item> items = new List<Item>();
    
    // Сортировка по возрастанию
    public void SortItemsAscending()
    {
        items = items.OrderBy(item => item.ID).ToList();
    }
    
    // Сортировка по убыванию
    public void SortItemsDescending()
    {
        items = items.OrderByDescending(item => item.ID).ToList();
    }
}
1
399 / 308 / 104
Регистрация: 07.05.2017
Сообщений: 2,211
09.01.2026, 16:59  [ТС]
спасибо огромное! разбираю ваш взгляд на решение задачи. правда структуры не вижу нигде, как ранее было предложено под хранение рецептов. это умышленно и переосмыслено, или для упрощения?
0
1144 / 309 / 159
Регистрация: 30.07.2022
Сообщений: 1,782
Записей в блоге: 4
09.01.2026, 18:27
Gammister,
Цитата Сообщение от Gammister Посмотреть сообщение
для упрощения
тема очень обширная и решений у одной и той же задачи тоже будет множество. лучше начать с каркаса, который будет по мере понимания происходящего дополняться фичами.
1
399 / 308 / 104
Регистрация: 07.05.2017
Сообщений: 2,211
18.01.2026, 14:28  [ТС]
пытаюсь более универсальную систему написать и уперся в сам метод проверки.
хотелось бы, чтоб пробегаясь по рецептам, он добавлял в лист возможные для создания объекты, которые возможно собрать с того, что есть на рабочем столе. вроде работает, но не совсем как нужно. можете помочь подправить?
вот скрипт для тестирования в инспекторе:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
 
public class CraftContainer : MonoBehaviour
{
    [SerializeField] ItemBase [] itemsCraft = new ItemBase[5];
    [Space, Header("Список рецептов")]
    [SerializeField] Recipe[] recipes = new Recipe[5];
 
    [Header("Возвращаем ообъект")]
    [SerializeField] List<ItemBase> itemsResult;
 
    [System.Serializable]
    public class Recipe
    {
        [SerializeField] public string nameRecipe;
        [SerializeField]
        ItemBase[] ingredients = new ItemBase[5];
        public
        ItemBase[] Ingredients => ingredients;
 
        [Header("Создаваемый префаб")]
        public
        ItemBase prefab;
    }
 
    [ContextMenu("Проверить рецепты")]
    void RecipeCalculate()
    {
        int indexTrue = 0;
 
        for (int i = 0; i < recipes.Length; i++)
        {
            if (recipes[i].Ingredients.Length == itemsCraft.Length) // если колличество ингредиентов равно положенным 
            {
                if (recipes[i].Ingredients.SequenceEqual(itemsCraft))
                {
                    itemsResult.Add(recipes[i].prefab);
                    print($"Возвращаем объект ''{recipes[i].nameRecipe}''");
                }
            }
            else
            {
                for (int j = 0; j < itemsCraft.Length; j++)
                {
                    if (itemsCraft[j].ItemName == recipes[i].Ingredients[j].ItemName)
                    {
                        indexTrue++;
                        if (/*j == recipes[i].Ingredients.Length - 1 && */indexTrue == recipes[i].Ingredients.Length - 1)
                        {
                            print($"Возвращаем объект ''{recipes[i].nameRecipe}''");
                            itemsResult.Add(recipes[i].prefab);
                            indexTrue = 0;
                            //continue;
                        }
                    }
                    //else
                    //{
                    //    indexTrue = 0;
                    //    continue;
                    //}
                }
            }
        }
    }
}
пока, что без инвентаря.

дело в том, что на рабочем столе тоже может быть разное количество ингредиентов, а небольших рецептов, может собраться два из того, что на столе.

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

Добавлено через 1 минуту
а так же после проверки рецептов, выдает ошибку о выходе за пределы массива.
0
293 / 256 / 107
Регистрация: 26.10.2012
Сообщений: 806
20.01.2026, 13:59
C#
1
2
3
4
5
    public class Recipe
    {
        ItemBase[] ingredients = new ItemBase[5];
        public bool CanCraft(IEnumerable<ItemBase> items) => !ingredients.Except(items).Any();
    }
1
399 / 308 / 104
Регистрация: 07.05.2017
Сообщений: 2,211
20.01.2026, 17:23  [ТС]
Спасибо!
жаль, что вы не прокомментировали, что именно этот делает. по идее возвращает совпадающие айтемы, но смущает метод Any. переводится, как любой.

и еще... что передавать в этот метод в качестве аргумента? по идее itemsCraft?
и где именно его вызывать в моем случае? во внешнем цикле?
сейчас штудирую библиотеку линк. там много интересных методов.
0
1144 / 309 / 159
Регистрация: 30.07.2022
Сообщений: 1,782
Записей в блоге: 4
21.01.2026, 01:59
Gammister,

C#
1
ItemBase[] ingredients = new ItemBase[5];
Рецепт хранит ровно 5 ингредиентов (фиксированный размер массива).
Использует базовый класс ItemBase, что позволяет использовать любые предметы-наследники.
По умолчанию все ингредиенты равны null.

C#
1
public bool CanCraft(IEnumerable<ItemBase> items) => !ingredients.Except(items).Any();
ingredients.Except(items) - находит ингредиенты из рецепта, которых нет в переданной коллекции items.
.Any() - проверяет, есть ли такие отсутствующие ингредиенты.
Проще говоря: метод возвращает true, если ВСЕ ингредиенты из рецепта присутствуют в предоставленной коллекции.

Метод проверяет только наличие ТИПОВ предметов.
Если в рецепте нужны 2 одинаковых предмета, а в items только 1 - метод вернет true.

Except() удаляет дубликаты.
Порядок ингредиентов не важен.
1
399 / 308 / 104
Регистрация: 07.05.2017
Сообщений: 2,211
21.01.2026, 02:17  [ТС]
разобрался!

Добавлено через 12 минут
Цитата Сообщение от ieretsumi Посмотреть сообщение
Если в рецепте нужны 2 одинаковых предмета, а в items только 1 - метод вернет true.
а вот это нужно будет доработать. пока что вызываю проверку, если в рецепте ингредиентов <= чем айтемов на верстаке. в itemsCraft. пока на скорый тест вроде работает. но с утра более детально прогоню. вывел логи. пока ток вот:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    void ExaminationRecipes()
    {
        for (int i = 0; i < _recipes.Length; i++)
        {
            if (_recipes[i].Ingredients.Length <= _craftItems.Length)
            {
                if (_recipes[i].CanCraft(_craftItems))
                {
                    print($"Рецепт ''{_recipes[i].nameRecipe}'': {_recipes[i].CanCraft(_craftItems)}");
                    _resultItems.Add(_recipes[i].GetCraftItem());
                }               
            }
            else
            {
                print($"Рецепт ''{_recipes[i].nameRecipe} недостаточно ингредиентов");
            }
        }
    }
0
293 / 256 / 107
Регистрация: 26.10.2012
Сообщений: 806
21.01.2026, 07:57
Блин, забыл что метод Except не учитывает повторения.
Тогда вот ручное определение применимости набора предметов для рецепта.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ItemBase[] ingredients = new ItemBase[5];
public bool CanCraft(IEnumerable<ItemBase> items){
      //заполняем словарь хранящий число использований от типа
      var ingredientCount = new Dictionary<ItemBase, int>():
      foreach(var ingredient in ingredients) 
      {
             ingredientCount.TryGetValue(ingredient, out var count);  //если нет - то count = 0        
             ingredientCount[ingredient] = ++count; //обновляем/добавляем количество в словаре
      }
      foreach(var item in items)
      {
             if (!ingredients.TryGetValue(item, out var count)) continue;
             //если ингредиент есть, то уменьшаем число использований или удаляем из словаря
             count--;
             if (count > 0) ingredientCount[item] = count;
             else ingredientCount.Remove(item);
       }
       return ingredientCount.Count == 0;
}
1
399 / 308 / 104
Регистрация: 07.05.2017
Сообщений: 2,211
21.01.2026, 12:52  [ТС]
благодарю вас други !!
еще хочу добавить, что фиксированный размер itemsCraft = 5, это все условно и он не будет постоянным и будет листом скорее всего. это просто для хранения добавляемых ингредиентов на верстак. фиксированный размер будет уже у UI панельки для ингредиентов. некоторые ячейки могут быть пустыми и порядок видимого на ней не будет учитываться. просто сам лист имеющихся буду сортировать по его прайсу, а на экране они могут добавляться пользователем в любом порядке. и будет скорее всего = 9. но это уже визуальный момент. к нему скоро подойду.

конечный результат вижу примерно так:

на панель (3х3 (возможность стакаться для экономии пространства вообще будет шикарно)) добавляются ингредиенты из инвентаря в любом порядке, и при совпадении рецептов (их может быть не один), в отдельном месте показываются возможные предметы. при наведении курсора на один из них, рецепты пересчитываются с учетом того, который под которым курсор, и те, которым уже не хватает ингредиентов, становятся не активными. это все еще до создания делается. ну и конечно убирать из доп. панели предметы, которым уже не хватает ингредиентов.

такая вот амбициозная задумка.

Сам базовый класс айтема вот такой:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using System;
using UnityEngine;
 
[Serializable]
public abstract class ItemBase : MonoBehaviour
{
    /// <summary>
    /// Тип распространенности айтема
    /// </summary>
    public enum ItemPrevalenceType
    { 
        LEGENDARY,
        RARE,
        ORDINARY,
        COMMON
    };
 
    [Space]
    [SerializeField] private ItemPrevalenceType _prevalenceType;
 
    public ItemPrevalenceType PrevalenceType => _prevalenceType;
 
    [Space]
    [SerializeField] protected string _itemName;
    public string ItemName => _itemName;
 
    [SerializeField] protected string Description;
    [Space]
    [SerializeField] protected int _prise;
 
    public static event Action<ItemBase> OnCreateEndAddItem;
 
 
    public void RegistrationItem() // добавляем себя при создании в коллекцию
    {
        print($"{gameObject.name}, Добаляюсь в список ");
        OnCreateEndAddItem?.Invoke(this);    
    }
}
0
399 / 308 / 104
Регистрация: 07.05.2017
Сообщений: 2,211
23.01.2026, 15:40  [ТС]
Цитата Сообщение от jetyb Посмотреть сообщение
Блин, забыл что метод Except не учитывает повторения.
Тогда вот ручное определение применимости набора предметов для рецепта.
метод TryGetValue не видит. что это может быть ?

0
293 / 256 / 107
Регистрация: 26.10.2012
Сообщений: 806
24.01.2026, 12:17
Замените ingredients на ingredientCount .
1
399 / 308 / 104
Регистрация: 07.05.2017
Сообщений: 2,211
Вчера, 18:59  [ТС]
Цитата Сообщение от jetyb Посмотреть сообщение
Замените ingredients на ingredientCount
Спасибо большое! работает. но не совсем так, как нужно.

например, для создания монеты нужно 2 куска руды, а на столе руды 4. но четырех кусков так же достаточно для создания слитка. по идее должно выдать две монеты и слиток.

пока вот так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    void ExaminationRecipes()
    {
        SortItemCraft();
 
        for (int i = 0; i < _recipes.Count; i++) // проход по рецептам
        {
            if (_craftItems.Count >= _recipes[i].Ingredients.Count)
            {
                if (_recipes[i].CanCraft(_craftItems))
                {
                    _resultItems.Add(_recipes[i].GetPrefab());
                }
            }
            else print($"''{_recipes[i].RecipeName}'' не хватает ингредиентов");
        }
    }
Добавлено через 21 минуту
мне тут подсказали в телеге в группе по Unity использовать рекурсию, я на своем коде по пробовал :
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    private void RecipesExamination(int i)
    {
        for (int j = 0; j < _recipes[i].Ingredients.Count; j++) // проход по конкретному рецепту
        {
            if (_recipes[i].Ingredients[j].ItemName == _craftItems[j].ItemName)
            {
                if (j == _recipes[i].Ingredients.Count - 1)
                {
                    print($"Рецепт ''{_recipes[i].RecipeName}'' сощелся");
                    _resultItems.Add(_recipes[i].GetPrefab());
 
                    if(j < _craftItems.Count - _recipes[i].Ingredients.Count)
                    {
                        print($"Итераций достаточно для продолжения {_craftItems.Count - _recipes[i].Ingredients.Count}");
                        RecipesExamination(j); 
                        // после этого вызова комп задумался на секунды и выдал 7 с лишним тысяч префабов ))
                    }
                }
            }
            else
            {
                print($"Ингредиент ''{_recipes[i].RecipeName}'' не совпал");
            }
        }
    }
походу не правильно попробовал )) и не до конца вестак проверяет, хотя выдает и слиток и монету (но должен две). уже хорошо.
но как-то в эту сторону возможно двигаться...
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
Вчера, 18:59
Помогаю со студенческими работами здесь

Хранение данных
Здравствуйте. Такой вопрос. В игре будет например 50 уровней. Уровни однотипные, меняется например...

Хранение диалогов в играх
Как более корректно сохранять диалоги в играх или подсказки? В xml?, если да, то как? К примеру в...

Хранение и использование данных в Unity
Доброго времени суток! Пишу простенькую 2d игрушку-тест под Windows. Дело дошло до самой игровой...

Работа с изображениями и видео, их хранение. Советы по выбору БД
Короче, хочу попробовать в целях обучения сделать что-то наподобие Instagram, только намного...

Как организовать хранение информации об игроках?
Здравствуйте! Ребят, есть задумка, но вот если с одиночными играми все более-менее понятно, то как...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Новые блоги и статьи
Загрузка PNG-файла с альфа-каналом с помощью библиотеки SDL3_image на Android
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
влияние грибов на сукцессию
anaschu 26.01.2026
Бифуркационные изменения массы гриба происходят тогда, когда мы уменьшаем массу компоста в 10 раз, а скорость прироста биомассы уменьшаем в три раза. Скорость прироста биомассы может уменьшаться за. . .
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
Установка Android SDK, NDK, JDK, CMake и т.д.
8Observer8 25.01.2026
Содержание блога Перейдите по ссылке: https:/ / developer. android. com/ studio и в самом низу страницы кликните по архиву "commandlinetools-win-xxxxxx_latest. zip" Извлеките архив и вы увидите. . .
Вывод текста со шрифтом TTF на Android с помощью библиотеки SDL3_ttf
8Observer8 25.01.2026
Содержание блога Если у вас не установлены Android SDK, NDK, JDK, и т. д. то сделайте это по следующей инструкции: Установка Android SDK, NDK, JDK, CMake и т. д. Сборка примера Скачайте. . .
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
моя боль
iceja 24.01.2026
Выложила интерполяцию кубическими сплайнами www. iceja. net REST сервисы временно не работают, только через Web. Написала за 56 рабочих часов этот сайт с нуля. При помощи perplexity. ai PRO , при. . .
Модель сукцессии микоризы
anaschu 24.01.2026
Решили писать научную статью с неким РОманом
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru