Вводная


Пару лет назад мне пришла идея написать движок для Visual Novel на WinForms. Почему на WinForms? Потому что тогда я ничего другого и не умел толком. Периодически движок получал и получает обновления по настоящий день. За это время накопилось немного полезного кода, который может использоваться повсеместно.

Разделение текста на строки


            string ActorText_str = ""; // Конечная строка для отрисовки
            // string ActorText - весь текст, разбитый на массив по словам (Split(' '))

            int old_y = 35, str = 0, num = 0;
            MessBox_1.Image = (Image)new Bitmap(MessBox_1.Width, MessBox_1.Height);
            Graphics g = Graphics.FromImage(MessBox_1.Image);

            // Считаем строки
            old_y -= 14;
            for (var i = 0; i <= ActorText.Length; i++)
            {
                if (str < text_width & i != ActorText.Length)
                {
                    str += ActorText[i].Length;
                    if (i != ActorText.Length - 1)
                        if (str + ActorText[i + 1].Length >= text_width)
                            str = 1116;
                }
                else
                {
                    for (int j = num + 1; j <= i; j++)
                        ActorText_str += ActorText[j - 1] + " ";

                    if (i != ActorText.Length)
                        str = ActorText[i].Length;

                    old_y += 14;
                    num = i;
                    g.DrawString(ActorText_str, new Font(lua.GetTextFont(), 10, FontStyle.Bold), new SolidBrush(SetColor(lua.GetTextColor())), new Point(10, old_y)); // В целом, можно и TextBox использовать
                    ActorText_str = "";
                }
            }
            g.Dispose(); // Удаляем Graphics

Спрайты и PictureBox


Как известно, PictureBox имеет два слоя изображения. BackgroundImage & Image. В первых версиях движка для отрисовки спрайтов я использовал порядка 5 боксов. Такая система имела несколько больших минусов:

  • Проблемы с прозрачностью из-за многоуровневой наследовательности
  • Пролаги формы при обновлении

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

PictureBox ALeft; 
Bitmap SpriteListPic; // Наш массив спрайтов для текущего кадра

// FreeMovePicture - Спрайт, который нужно отрисовать
// posX, posY - Позиция на форме
// Scale - Масштабирование 
private void SpriteBoxesHolder(Image FreeMovePicture, int posX, int posY, float Scale = 2)
        {
            Graphics SpGr = Graphics.FromImage(SpriteListPic);
            SpGr.DrawImage(FreeMovePicture, posX * 2, posY * 2, FreeMovePicture.Size.Width / Scale, FreeMovePicture.Size.Height / Scale);
            ALeft.Image = SpriteListPic;
        }

LuaInterface и Try-Catch, как фича


Немного об опыте работы с LuaInterface:

  • Дополнение для статьи по LuaInterface по поводу LuaTable: Для большинства вещей можно обойтись и без функций, используя только таблицы.

                lua.NewTable("Scene"); // Создаём таблицу
    
    // Достаём из таблицы значение TextColor
    public string GetTextColor() 
    {
           return (string)lua.GetTable("Font")["TextColor"]; 
    }
    
  • Если вы не уверены, что такое значение в таблице вообще есть:

                Try
                {
                    Size = (double)lua.GetTable("Scene")["Image" + Convert.ToString(num) + "Scale"];
                }
                catch (Exception ex)
                {
                    Size = 2;
                }
    

    Lua вернёт значение, но не факт, что оно будет числом. Поэтому Catch(Exception).

Комментарии (5)


  1. nazgul-e0
    01.10.2019 09:33

    Try
    {
        Size = (double)lua.GetTable("Scene")["Image" + Convert.ToString(num) + "Scale"];
    }
    catch (Exception ex)
    {
        Size = 2;
    }
    

    Важно помнить что обработка Exception достаточно ресурсоемкий процесс.
    В этом случае более корректно использовать проверку на null + Double.TryParse


  1. roboter
    01.10.2019 11:33

    str = 1116;

    — такие «магические числа» нужно выносить в константы/дефайны.


    1. ForserX Автор
      01.10.2019 11:44

      дефайны в C#? А по поводу констант идея хорошая, да там в целом код рефакторить надо. Этот алгоритм ещё с 2017. Но пока руки не доходят.


      1. roboter
        01.10.2019 11:47

        Про дефайны это я обобщил, правило магических чисел не зависит от языка.


  1. yarosroman
    01.10.2019 11:49
    +1

    А зачем явный вызов Dispose делать? Есть же using.