• Раскрывающийся список с объектами в WPF?

    WNeZRoS
    @WNeZRoS
    То что на картинке выглядит как Expander, в Header у него панель с иконкой и текстом, в Content - DataGrid с таблицей. Если таких экспандеров не фиксированное кол-во, то их можно генерить с помощью ItemsControl
    Ответ написан
    3 комментария
  • Почему Юнити перестает работать?

    WNeZRoS
    @WNeZRoS
    Возможно вечный цикл из-за того что if (oldCount != count) никогда не заходит внутрь т.к. этот код блокирует обработку кадров. Чтобы кадры продолжили обрабатываться надо в цикле использовать yield. Заодно можно заменить это ожидание циклом на корутину от юнити: yield return new WaitForSeconds(5);

    https://docs.unity3d.com/ScriptReference/WaitForSe...
    Ответ написан
    4 комментария
  • Как к поймать событие OnMouseLeftButtonUp из пользовательского элемента UIElement?

    WNeZRoS
    @WNeZRoS
    Чтобы ловить события мыши вне элемента этот элемент должен захватить мышь через Mouse.Capture. Захват надо не забыть отменить когда он уже не актуален, иначе другие элементы не смогут получать события мыши.
    Ответ написан
    Комментировать
  • Почему MouseMove не срабатывает?

    WNeZRoS
    @WNeZRoS
    У Canvas по умолчанию нет фона, соответственно курсору не за что зацепиться и MouseMove уходит окну. Если добавить для канваса Background="Transparent" (прозрачный цвет считается за фон, но визуально ничего не меняет), то всё будет работать.
    Раньше работало видимо потому что в канвасе были визуально видимые элементы.
    Ответ написан
    1 комментарий
  • Как получить информацию о версии Unreal'а, имея только uasset файлы?

    WNeZRoS
    @WNeZRoS
    Открываете файл в HEX редакторе или хотя бы в блокноте и видите что-то такое:
    lsldd2wvvvwajrb6hnkkt_ao0wi.png
    Ответ написан
    Комментировать
  • Как в wpf mvvc отобразить список элементов динамически?

    WNeZRoS
    @WNeZRoS
    Со структурой как у вас не понятно как оно должно работать.
    Если сделать ItemData типизированными, то всё становится проще - wpf может по типу выбирать подходящий DataTemplate, и значения мы получаем нужного типа, а не пойми что.

    public class SettingViewHost
    {
        public IReadOnlyCollection<SettingView>? Views { get; init; }
    }
    
    public class SettingView
    {
        public string? Name { get; init; }
        public IReadOnlyCollection<ItemData>? Options { get; init; }
    }
    
    public class ItemData
    {
        public string? Name { get; init; }
        public int GridRow { get; init; }
        public int GridColumn { get; init; }
    }
    
    public class BooleanItemData : ItemData // TODO implement INotifyPropertyChanged and raise PropertyChanged in Value setter
    {
        public bool Value { get; set; }
    }
    
    public class StringItemData : ItemData // TODO implement INotifyPropertyChanged and raise PropertyChanged in Value setter
    {
        public string Value { get; set; } = string.Empty;
    }


    Собираем SettingViewHost с любым количеством SettingView с разными внутренними настройками и закидываем во вью с такими шаблонами:

    <DataTemplate DataType="{x:Type local:StringItemData}">
        <StackPanel Orientation="Vertical">
            <TextBlock Text="{Binding Name, Mode=OneTime}" />
            <TextBox Text="{Binding Value}" />
        </StackPanel>
    </DataTemplate>
    
    <DataTemplate DataType="{x:Type local:BooleanItemData}">
        <CheckBox Content="{Binding Name, Mode=OneTime}" IsChecked="{Binding Value}" />
    </DataTemplate>
    
    <DataTemplate DataType="{x:Type local:SettingView}">
        <ItemsControl ItemsSource="{Binding Options}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Grid IsItemsHost="True">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition />
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition />
                            <RowDefinition />
                        </Grid.RowDefinitions>
                    </Grid>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="{x:Type ContentPresenter}">
                    <Setter Property="Grid.Column" Value="{Binding GridColumn, Mode=OneTime}" />
                    <Setter Property="Grid.Row" Value="{Binding GridRow, Mode=OneTime}" />
                    <Setter Property="Margin" Value="4" />
                </Style>
            </ItemsControl.ItemContainerStyle>
        </ItemsControl>
    </DataTemplate>
    
    <DataTemplate DataType="{x:Type local:SettingViewHost}">
        <StackPanel Orientation="Vertical">
            <ComboBox Name="ComboBox" ItemsSource="{Binding Views}">
                <ComboBox.ItemTemplate>
                    <DataTemplate DataType="{x:Type local:SettingView}">
                        <TextBlock Text="{Binding Name, Mode=OneTime}" />
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
            
            <ContentControl Content="{Binding ElementName=ComboBox, Path=SelectedItem}" />
        </StackPanel>
    </DataTemplate>


    Пример сделан с Grid'ом 2х2, можно использовать любую панель. Обычный Grid для динамических целей не удобен т.к. у него фиксированное кол-во строк и столбцов. Лучше использовать UniformGrid или что-то ещё, или развлекаться с attached dependency property или MarkupExtension чтобы динамически генерировать строки и столбцы.
    Ответ написан
    Комментировать
  • Как узнать нормаль поверхности на которой стоит персонаж?

    WNeZRoS
    @WNeZRoS
    У Collider2D есть метод GetContacts.

    Результатом этого метода будет массив или список ContactPoint2D.
    У ContactPoint2D есть поле normal - нормаль поверхности в точке коллизии.

    Collider2D collider;
    
    var contacts = new List<ContactPoint2D>();
    collider.GetContacts(contacts);
    
    foreach (var contact in contacts)
    {
        var surfaceNormal = contact.normal;
    }
    Ответ написан
    Комментировать
  • Что делает IEqualityComparer? Он вообще работает?

    WNeZRoS
    @WNeZRoS
    IEqualityComparer<T> используется в коде с обобщениями (generics).
    Например, он используется для ключей в Dictionary или для сравнения (Equals) элементов в ValueTuple.
    Если бы в Dictionary использовали object.Equals, а не IEqualityComparer<T>, то при сравнении ключей-структур постоянно бы происходил боксинг, что не очень эффективно. (У простых структур всё-равно будет боксинг, чтобы его не было надо реализовать IEquatable).

    Когда у вас уже известен тип большого смысле использовать IEqualityComparer<T> мало, есть более лаконичные вариант для Equals и GetHashCode.
    Ответ написан
  • Что не так с поворотом?

    WNeZRoS
    @WNeZRoS
    Всё зависит от того что вы хотите получить и что такое "криво выглядит".

    Можно, например, делать интерполяцию, тогда при подходе к 3 метрам расстояния дополнительный угол плавно уберётся:
    angle = Mathf.LerpAngle(angle, angle - additionalAngle, direction.magnitude - 3);


    А можно не давать целится ближе 3 метров:
    if (direction.magnitude < 3)
        targetPos = ownerPos + direction.normalized * 3;


    PS

    На вопрос можно было бы получить ответ быстрее если прикладывать больше контекста:
    - больше кода - всё что относится к повороту
    - как настроены объекты
    - видео или гифку с проблемой
    - видео как хотелось бы чтобы оно работало
    Ответ написан
    2 комментария
  • Как добиться отображения только силуэтов отдельных объектов?

    WNeZRoS
    @WNeZRoS
    Вам нужен Unlit шейдер

    unlit-shader-tutorial-basic-hardcoded-color.png

    Возможно так же понадобится сделать Outline для объектов.
    Ответ написан
    Комментировать
  • Как в логике mvvc wpf передать в класс ViewModel из view свойство класса .xaml.cs?

    WNeZRoS
    @WNeZRoS
    Почему это поле не передается через, передается null
    CommandParameter="{Binding ElementName=selfUserControl,Path=Points, Mode=OneWay}">, selfUserControl x:Name элемента.

    Проперти Points должен быть public

    Находил примеры, там везде свойство ItemsSource, но такого свойства нету у Canvas

    Надо использовать ItemsControl, у которого как раз есть ItemsSource, а Canvas использовать как панель для этого ItemsControl через ItemsPanel
    Ответ написан
    Комментировать
  • Как индефицировать объект списка по нажатию кнопки в нём?

    WNeZRoS
    @WNeZRoS
    Если используете команды, то надо у кнопки сделать CommandParameter="{Binding}" и тогда вьюмодель строки придёт в команду.
    Если на Click эвентах, то из аргументов эвента достать кнопку и посмотреть на её DataContext.
    Ответ написан
    Комментировать
  • Как разрабатывать ПО с GUI, который адаптируется под определённого пользователя?

    WNeZRoS
    @WNeZRoS
    использовать условные конструкции для решения об отображении или неотображении тех или иных элементов GUI, либо иметь разные XAML-формы для разных групп пользователей


    Это одно и тоже решение, просто условия разное меняют. Всё зависит от вида приложения можно применять разные решения.

    Для хороших WPF приложений принято использовать MVVM, соответственно для всего будут вьюмодели.
    Если это приложение - набор ярлыков, то можно просто не создавать вью модели или скрывать (BooleanToVisibilityConverter) недоступные ярлыки.
    Если что-то сложнее, то вероятно для разных пользователей будут разные вьюмодели и разные XAML шаблоны для них.
    Ответ написан
    Комментировать
  • Почему двумерные массивы работают чуть быстрее одновременых?

    WNeZRoS
    @WNeZRoS
    // [][] 4865
    // [,]  5192
    // []   4852


    int[] - простейший массив, в памяти лежит линейно.
    Работает за счёт IL инструкций (newarr, ldelem, ...), которые могут лучше оптимизировать jit компилятором

    int[,] - многомерный массив, в памяти лежит также линейно как int[].
    Работает через вызовы методов, а так же за счёт не популярности работает на общем коде с массивами где первый элемент может быть не по индексу 0. Соответственно, для доставания элементов требуется дополнительная математика и проверки.

    int[][] - массив массивов, в памяти линейно лежат ссылки на линейно лежащие строки.
    Работает медленнее int[] потому что требуется доступ к другим участкам памяти (строкам).
    Ответ написан
    Комментировать
  • Как виртуальные машины исполняют код и как правильно это реализовать?

    WNeZRoS
    @WNeZRoS
    Если вопрос при виртуальные машины по типу тех что используется для исполнения Java или C# кода, то инструкции в них гораздо проще. В CIL например, у большинства инструкций нет параметров, они просто берут нужные данные с конца стека. А когда параметры есть - он один: значение или токен переменной/функции.

    Можно посмотреть как C# преобразуется в инструкции виртуальной машины на sharplab.io, сопоставить и понять как оно выполняется.

    Например
    IL_0000: ldarg 1 // кладёт в стек первый аргумент
    IL_0001: ldarg 2 // кладёт в стек второй аргумент
    IL_0002: sub     // достаёт из стека два последних значения и отнимает последний от пред последнего (т.е. будет arg.2 - arg.1), результат складывается в стек
    IL_0003: brtrue.s IL_0011 // достаёт из стека значение, если оно не 0, переходит к инструкции IL_0011, если 0 исполнения идёт дальше на I_0005
    
    IL_0005: ldstr "zero" // загружает в стек строку "zero"
    IL_000a: call void System.Console::WriteLine(string) // вызывает вывод в консоль, из стека достаются N нужных значений для параметров (в данном случае 1), void функция ничего в стек не добавляет
    IL_000f: br.s IL_001b // переход (jump) к IL_001b
    
    IL_0011: ldstr "not zero" // загружает в стек строку "not zero"
    IL_0016: call void System.Console::WriteLine(string) // вызывает вывод в консоль, из стека достаётся 1 значения для параметра 
    
    IL_001b: ldstr "done" // загружает в стек строку ...
    IL_0020: call void System.Console::WriteLine(string) // ...


    Пример реализации простой виртуальной машины на основе примера выше

    (Код написан так чтобы работал, правильнее писать более безопасно и читабельнее)

    #include <stdio.h>
    
    enum Opcode {
        OP_LOAD_ARGUMENT,
        OP_LOAD_STRING,
        OP_SUBTRACT,
        OP_GOTO,
        OP_GOTO_IF_TRUE,
        OP_CALL,
        OP_RETURN
    };
    
    union Argument {
        int value;
        const void* pointer;
    };
    
    struct Instruction { 
        Opcode opcode; 
        Argument arg; 
    };
    
    void run_vm(const Instruction* instructions, const Argument* args) {
        Argument stack[16];
        
        Argument* stack_pointer = &stack[0];
        int address = 0;
    
        while(true) {
            const Instruction instruction = instructions[address];
            address++;
    
            switch(instruction.opcode) {
                case OP_RETURN:
                    return;
                
                case OP_LOAD_ARGUMENT:
                    *stack_pointer = args[instruction.arg.value];
                    stack_pointer++;
                    break;
    
                case OP_LOAD_STRING:
                    *stack_pointer = instruction.arg;
                    stack_pointer++;
                    break;
    
                case OP_SUBTRACT:
                {
                    stack_pointer--;
                    int b = stack_pointer->value;
                    
                    stack_pointer--;
                    int a = stack_pointer->value;
    
                    stack_pointer->value = a - b;
                    stack_pointer++;
                    break;
                }
    
                case OP_GOTO:
                    address = instruction.arg.value;
                    break;
    
                case OP_GOTO_IF_TRUE:
                    stack_pointer--;
                    if(stack_pointer->value != 0)
                        address = instruction.arg.value;
                    break;
    
                case OP_CALL:
                    void (* fn)(const void*) = (void (*)(const void*))instruction.arg.pointer;
                    stack_pointer--;
                    fn(stack_pointer->pointer);
                    break;
            }
        }
    }
    
    void print(const char* text) { printf("%s\n", text); }
    
    int main(int argc, char** argv) {
        const Instruction instructions[] = {
            /* 0 */ { OP_LOAD_ARGUMENT, { 0 } },
            /* 1 */ { OP_LOAD_ARGUMENT, { 1 } },
            /* 2 */ { OP_SUBTRACT, {} },
            /* 3 */ { OP_GOTO_IF_TRUE, { 0x7 } },
            /* 4 */ { OP_LOAD_STRING, { .pointer = "zero" } },
            /* 5 */ { OP_CALL, { .pointer = (void*)&print } }, // функции надо где-то регистрировать, чтобы знать сколько у них параметров и какого они типа
            /* 6 */ { OP_GOTO, { 0x9 } },
            /* 7 */ { OP_LOAD_STRING, { .pointer = "not zero" } },
            /* 8 */ { OP_CALL, { .pointer = (void*)&print } },
            /* 9 */ { OP_LOAD_STRING, { .pointer = "done" } },
            /* A */ { OP_CALL, { .pointer = (void*)&print } },
            /* B */ { OP_RETURN, {} }
        };
    
        const Argument args[] = { 
            { 100500 },
            { 777 }
         };
    
        run_vm(instructions, args);
        return 0;
    }



    Виртуальные машины для процессоров можно делать по такому же принципу, но они будут медленные и структура инструкций ограничена архитектурой процессора.
    Ответ написан
    Комментировать
  • Как блок питания определяет выходное напряжение?

    WNeZRoS
    @WNeZRoS
    При помощи USB Power Delivery
    Ответ написан
    Комментировать
  • Как получить последние 3 символа строки используя Lambda expression?

    WNeZRoS
    @WNeZRoS
    Попрактиковался в решении задачи "получить последние 3 символа" максимально не эффективным способом.
    Первый вариант самый правильный, чем дальше тем не оптимальнее. Второй больше всего похож на то что у вас вопросе.

    string n2string = "sdfihsdfguhdsfo[ghdfhgdsfhghdfsgdfhghdsfg9wh328932u82hbsab zb cx9832u83232hbnibcz";
    int countMinus3 = n2string.Length - 3;
    
    {
        string lastThreeSymbols = n2string.Substring(countMinus3);
        Console.WriteLine($"lastThreeSymbols = {lastThreeSymbols}");
    }
    {
        string lastThreeSymbols = string.Concat(n2string.Where((_, i) => i >= countMinus3));
        Console.WriteLine($"lastThreeSymbols = {lastThreeSymbols}");
    }
    {
        string lastThreeSymbols = n2string.Where((_, i) => i >= countMinus3).Aggregate(string.Empty, (s, c) => s + c);
        Console.WriteLine($"lastThreeSymbols = {lastThreeSymbols}");
    }
    {
        string lastThreeSymbols = n2string.Aggregate(string.Empty, (s, c) => (s.Length > 2 ? s.Substring(1) : s) + c);
        Console.WriteLine($"lastThreeSymbols = {lastThreeSymbols}");
    }
    Ответ написан
  • Какие есть решения для создания чертежа/развёртки из 3D модели созданной на основе другой модели?

    WNeZRoS
    @WNeZRoS
    У Blender есть встроенный аддон Paper Model для генерации схемы бумажной модели, возможно и для обёртки подойдёт.
    https://docs.blender.org/manual/en/latest/addons/i...
    Ответ написан
    Комментировать
  • Как можно сделать перебор по массиву быстрее?

    WNeZRoS
    @WNeZRoS
    Если было бы больше контекста, то можно было бы что-то увереннее советовать. По этому куску кода можно дать только такие комментарии (считая что Get* методы и итераторы не имеют сайд эффектов):
    var someItems = _someService.GetList();
    foreach (var item in someItems) // item внутри не используется, можно убрать этот foreach
    {
        var additionalItems = _additionItemsSerivce.GetList();
        foreach (var additionalItem in additionalItems)
        {
            var properties = additionalItem.Properties;
            foreach (var property in properties)
            {
                property.First = true;
                property.First = true; // зачем делать одно и тоже два раза?
                _additionItemsSerivce.UpdateProperies(additionalItem); // property не используется, значит можно вынести за этот foreach
            }
        }
    }


    Если по этим комментариям убрать лишнее, получится что-то такое:
    var additionalItems = _additionItemsSerivce.GetList();
    foreach (var additionalItem in additionalItems)
    {
        var properties = additionalItem.Properties;
        foreach (var property in properties)
            property.First = true;
        
        _additionItemsSerivce.UpdateProperies(additionalItem);
    }


    Так же странно что все проперти у вас получают флаг First, возможно вместо foreach по properties стоит получить только первый элемент и ему установить First = true.
    Ответ написан
    Комментировать
  • Как исправить ошибку "- Подпись кода: «apksigner» завершился с ошибкой #1" в Godot при экспорте проекта на Android?

    WNeZRoS
    @WNeZRoS
    Судя по таким же сообщениям на формах и баг трекере, проблема скорее всего в том что Godot использует build tools не той версии (скорее всего нужной версии вообще не установлено).

    Чтобы всё работала нужно установить всё именно тех версий что указана в документации к вашей версии Godot (для 3.6 - 30.0.3, для 4.0 - 33.0.2).
    Ответ написан