Free Unity DevФорум

TacBattleAI тестовая сцена на Unity 6.3 URP с библиотеками от Tac

Страницы: 1 2 3 Следующая »
#0
(Правка: 6:06) 5:56, 13 дек 2025

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

Вы можете использовать эту сцену для обучения и/или тестирования своих прототипов. Данный репозиторий содержит, в составе проекта на Unity 6.3. URP библиотеки/компоненты исходного кода, которые могут облегчить начальную разработку ваших прототипов. Все компоненты, которые не рекомендуется изменять самостоятельно, включают в себя сокращение Tac, и находятся в соответствующих директориях/namespace/dll.

Особенностью библиотек Tac является их продуманная архитектура и легкость, благодаря чему их можно собирать как конструктор для разных прототипов игр. На данный момент можно выделить:

1. TacCamera - простейшая камера, которая позволяет перемещаться в игре, пролетая над поверхностью, т.н. "камера сверху"
2. TacItemCreate - минимальный набор, который позволяет перекрыть создание моделей в игре, выстроив правильную архитектуру "сущностей"
3. TacItemMove - позволяет перемещать/располагать/строить предметы в игре
4. TacStandart - общие компоненты, расширяющие функциональность классов Unity и требующиеся практически для каждого компонента
5. TacWireframe - Управление визуальной сеткой (wireframe), что позволяет отобразить пересечение модели, или прозрачность стен, заменяя модель сеткой определенного цвета

Репозиторий

P.S. Конечно сердце этого проекта - это документация с видео туториалами, которые выложу со временем, тем быстрее, чем появится заинтересованные.
P.P.S. Конечно, это только начало ... за несколько лет накопилось много кода, который превращается в бесполезный, если его не выкладывать и не поддерживать. (на дискетах много кода, когда то выбросил) Гавнокод поддерживать не хочется, а красивые решения отдавать жалко :) Но я могу себе позволить, могу даже подискутировать на сколько решения красивые. Но призываю создавать движение в обе стороны, а не только я -> вам, но постарайтесь быть полезны и вы -> мне.

#1
13:24, 13 дек 2025

А вот как это начиналось, в ролике основы, но после этого ряд компонентов переосмыслены и оформлены лучше

Запустить видео по клику - Как делать игрыЗапустить видео по клику - Как делать игры

#2
(Правка: 14:53) 14:32, 14 дек 2025

Великий архитектор.

Пожалуйста, объясни мне, кривозубому крестьянину, зачем ты использовал ключевое слово partial в примере?

Я правда пытаюсь понять твою гениальную идею.

Код из твоего репозитория:

namespace Tac
{
    public abstract class Item : MonoBehaviour
    {
    public int ObjectId;
    public int GroupId = -1;
    public string ModelName = "";
    public ModelTypes ModelType = ModelTypes.Model;
  }
}

namespace Tac.ItemMove
{
  public partial class Item2 : Item
  {
    public bool AllowMove = true;
  }
  public class ItemMove
  {
      public void Move(Item2 item, ... ) { ... }
  }
}

namespace Tac.ItemRotate
{
  public partial class Item2 : Item
  {
    public bool AllowRotate = true;
  }
  public class ItemRotate
  {
      public void Rotate(Item2 item, ... ) { ... }
  }
}
#3
(Правка: 22:39) 21:13, 14 дек 2025

Storm54
Спасибо за вопрос. Я запишу видео-урок, подождите немного.

Только вот давайте без ёрничества.

upd.

Запустить видео по клику - Как делать игрыЗапустить видео по клику - Как делать игры

#4
0:33, 15 дек 2025

Ок, отвечу серьезно.

Досмотрел до 18 минуты ответ видео. Все доводы DeepSeek абсолютно правильны, SRP и полиморфизм страдает, тут добавить нечего.

Просто вернемся к коду из репозитория:

namespace Tac
{
    public abstract class Item : MonoBehaviour
    {
    public int ObjectId;
    public int GroupId = -1;
    public string ModelName = "";
    public ModelTypes ModelType = ModelTypes.Model;
  }
}

namespace Tac.ItemMove
{
  public partial class Item2 : Item
  {
    public bool AllowMove = true;
  }
  public class ItemMove
  {
      public void Move(Item2 item, ... ) { ... }
  }
}

namespace Tac.ItemRotate
{
  public partial class Item2 : Item
  {
    public bool AllowRotate = true;
  }
  public class ItemRotate
  {
      public void Rotate(Item2 item, ... ) { ... }
  }
}

В данном случае здесь два независимых класса Item2, а именно: Tac.ItemMove.Item2 и Tac.ItemRotate.Item2.

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

Оно делает крайне простую вещь: Позволяет объявлять части класса в нескольких файлах (как, например, в C++, когда можно реализацию каждого метода вынести в отдельный файл). В C# это нужно было для кодогенерации, например, в WinForms, когда часть класса окна с визуальными компонентами генерировалась в отдельном файле.

Т.е. в вашей архитектуре Вы предложили просто сложить всю логику и данные в один огромный класс.

Идея глупая, непонятно на что Вы вообще надеялись, когда это опубликовали.

#5
(Правка: 1:14) 0:46, 15 дек 2025

Storm54
> В данном случае здесь два независимых класса Item2, а именно: Tac.ItemMove.Item2 и Tac.ItemRotate.Item2.
Там была описка, это один и тот же класс, я уже поправил.

Остальное видимо нет смысла комментировать, думайте, может поймете. Пока много самоуверенности и не знание предмета.

Storm54
> Досмотрел до 18 минуты
Если посмотрели бы дальше, поняли бы (хотя не факт) свои ошибки и дипсика.

Storm54
> Т.е. в вашей архитектуре Вы предложили просто сложить всю логику и данные в один огромный класс.
это придумали вы, я такого не предлагал.

#6
0:54, 15 дек 2025

Что касается SRP, в трех частях (может поймете, что это само по себе глупо, и для структурщиков )

Рассматриваем книгу Б. Мартина "Быстрая разработка программ", конкретно пытаясь понять как им и Б. Косом программировалась игра "Боулинг" (этому посвящена одна из глав). Делаем это, чтобы понять вначале контекст как возник и кто тот человек, который предложил принцип единой ответственности. Понимаем, что это "заядлый структурщик", который пробывал себя в роли ООП`шника, подробное рассмотрение "игры в боулинг" однозначно приводит нас к этому пониманию. Подтверждается, что этот принцип (единой ответственности) позволяет немного сгладить эффекты, когда на объектно-ориентированном языке программируют те, кто думают исключительно структурно. Получается немного лучше, чем полностью в структурной (процедурной) парадигме, но все же далеко, если думать сразу в терминах ООП. Показывается пример того, если программировать "игру боулинг" изначально с помощью ООП, и становится понятно чем это отличается.


Непосредственно рассматриваем принцип единой ответственности и его связь с ролями  и полнотой класса. Приходим к выводу, что принцип сформулирован не четко и для своего применения имеет мало примеров и случаев, является скорее критерием того, когда имеет смысл разделять класс на части в зависимости от ролей. А зачастую приводимые примеры не выдерживают ни какой критики.

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

+ Показать
#7
1:05, 15 дек 2025

tac
> это придумали вы, я такого не предлагал.

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

В Вашем же примере создается один убер класс (в данном случае Item2), который содержит в себе все поля. Это приведет к одному огромному монолиту, просто потому, что логика по работает с определенным компонентом уже находится в этом классе, не получится создать другой класс (например, ItemX, который наследуется напрямую от Item) и при этом переиспользовать логику из Item2 - отсутствие полиморфизма, дипсик про это и написал.

Итого: это вообще никак не применимо в реальном проекте. Ровно тоже самое, что и описать всю логику в одном классе. Попробуйте доказать обратное на простом примере, сделать два класса: Monster и Building и в них добавить поле со здовьем и взаимодействием с ним. Без явного или косвенного дублирования кода это сделать не получится

#8
(Правка: 1:16) 1:07, 15 дек 2025

Storm54
> В реальной программе вариаций компонентов будет крайне много.
Мы можем обсуждать не в вакууме, и не с вашими предположениями, которые совершенно не верны (просто в каждом вашем слове, но у меня нет желания переубеждать человека, который не уважительно общается). Можно просто открыть репозиторий и посмотреть как организованны реальные Tac-компоненты.

Если хотите задать вопрос: уважительно опишите вашу проблему и опасения.

#9
(Правка: 1:39) 1:27, 15 дек 2025

tac
> Мы можем обсуждать не в вакууме, и не с вашими предположениями, которые совершенно не верны (просто в каждом вашем слове, но у меня нет желания переубеждать человека, который не уважительно общается). Можно просто открыть репозиторий и посмотреть как организованны реальные Tac-компоненты.

Ковыряться в репозитории ноунейма - много чести, уж извините. Я итак потратил время и посмотрел половину 40-минутного ролика, в котором весь контент - озвучивание текста на экране без аргументации, а с возгласами в духе "не согласен с дипсиком".

Просто приведу самый краткий пример кода, который только возможен и который раскрывает проблему.
Напишите решение этой проблемы и вопрос закрыт.

public class Entity
{
  public int EntityId;
  
  public string Name;
}

// Monster file 1
public partial class Monster : Entity
{
  public int Health;
  
  public void Damage() { Health--; }
}

// Monster file 2
public partial class Monster : Entity
{
  public Vector2 MoveSpeed;

  public void StartMove() { MoveSpeed = new Vector2(10, 0); }
}

// Building file 1
public partial class Bulding : Entity
{
  public int Health;
  
  public void Damage() { Health--; }
}

// Building file 2
public partial class Bulding : Entity
{
  public int WallLevel;
  
  public void IncreaseWallLevel() { WallLevel++; }
}

Monster и Building имеют здоровье, при этом монстр умеет двигаться в точку, а у строения может улучшаться уровень стены. Легко заметить, что код здоровья дублируется - его просто никак не написать иначе, т.к. поля Health находятся в разных классах и не связаны, следовательно, я не могу написать в одном месте логику, а приходится дублировать ее.

Как мне быть?

tac
> Остальное видимо нет смысла комментировать, думайте, может поймете. Пока много самоуверенности и не знание предмета.

Без кода с решением проблемы - пустая болтовня.

#10
(Правка: 3:04) 2:30, 15 дек 2025

Storm54
> Как мне быть?

Например, вот так. Но ваш пример перпендикулярен и слабо показывает особенности partial-подхода. Не надо думать, что появление partial-подхода, удаляет ООП, я не такой же "идеолог" как ECSники, которые готовы уничтожить ООП и обязать всех страдать ерундой. Возможно не очевидно, но разница между AgentMover и Agent, в том, что AgentMover управляет сразу множеством Agent, так же как BuildingCreator строит разные Building. Аналогично и DamageControl. В реальности, скорее там будет не передача параметра, а просто просмотр своего списка всех агентов, строений и т.п.. А также, возможно и появление методов в самом Agent/Building - причем Agent с большой вероятностью, а Building скорее нет. Это связано с тем, что агент перемещается сам, а здание само не строится..

> Легко заметить, что код здоровья дублируется - его просто никак не написать иначе, т.к. поля Health находятся в разных классах и не связаны, следовательно, я не могу написать в одном месте логику, а приходится дублировать ее.
Это я не понял, видимо вы рассуждаете в каком то своем контексте, который мне не известен. Скорее всего, вы что-то не доформализовали. Если у вас единая логика для Health, то и поля легко объединить. Если вы хотели сказать, что Здоровье монстра и Прочность здание это разное и их требуется различать, то можно сделать интерфейс, очень напрашивалось, но я не сделал, т.к. не ясен контекст. Поэтому если логика одинакова - нужно объединить в одно понятие. , а если понятия все же разные, у них будут различия в реализации. Поэтому микро примеры плохо отражают. Но когда у вас спадет спесь, стоит посмотреть реальные примеры.

// MyGame.dll
public class MyMonster : Agent
{
}

public class MyBuilding : Building
{
}

// TacLibrary.dll

// BuildingCreator
public class BuildingCreator
{
  public void OnIncreaseWallLevel(Bulding building) { building.WallLevel++; }
}
public class Bulding : Item2
{
  public int WallLevel;
}


// DamageControl.cs
public class DamageControl
{
  public void OnDamage(Item2 entity) { entity.Health--; }
}

// AgentMover.cs
public class AgentMover
{
  public void StartMove(Agent agent) { agent.MoveSpeed = new Vector2(10, 0); }
}
public class Agent : Item2
{
  public Vector2 MoveSpeed;
}

// Common.cs
public partial class Item2 : EntityId
{
  public int Health;
}


// TacStandart.dll
public class EntityId
{
  public int Id;
  public string Name;
}

P.S. у меня в рукаве еще много решений - заходите еще, только вытирайте ноги и мойте рот.

#11
3:00, 15 дек 2025

tac
> Это я не понял, видимо вы рассуждаете в каком то своем контексте, который мне не известен. Скорее всего, вы что-то не доформализовали.

Что именно не было понятно? Health находился в двух классах, это и было дублированием логики.

В коде выше Вы просто перенесли Health в базовый класс, это было предсказуемо.
Что будем делать, когда еще несколько полей появится? Будем все в базовый класс переносить?

#12
(Правка: 3:20) 3:10, 15 дек 2025

Storm54
> Что будем делать, когда еще несколько полей появится? Будем все в базовый класс переносить?
Тут важно сказать каких "несколько" полей. Для разных полей будет разный подход. Да, что-то попадет в общий класс. Но это будет не так много. Вы очень преувеличиваете количество полей, которые общи с различными сущностями. Более того, это будет удобно ровно до того момента, чтобы легко настроить префаб, т.е. не сами поля, а их значения для разных моделей. И это как раз удобно делать в одном месте.

Но у меня есть и еще пару трюков. Логику можно разделить на ту которая относится к 3d - пространству и взаимодействию в нем, и прочую бизнес-логику. Поэтому мне не кто не мешает создать два уровня логики, наделив если нужно префаб модели двумя или более классами данных, которые не будут пересекаться.

#13
(Правка: 7:43) 7:35, 15 дек 2025

Storm54
Свой бред оставь себе, и приходи когда разберешься и что-то будешь иметь сказать по сути. Терпеть твои оскорбления тут никто не будет. Я вижу лишь то, что ты не понимаешь ООП от слова совсем, поэтому обсуждать с тобой продвинутые вещи рано.

#14
9:49, 15 дек 2025

То есть ты потер сообщение, где я указал, что ты не понимаешь понятие абстракции, после чего оставил сообщение, где указал, что я не понимаю ООП ?

Сильный ход, сразу видно уверенного в себе специалиста. Это твой фокус из рукава?)

Страницы: 1 2 3 Следующая »
Free Unity DevФорум