Mariya Mariya

Всем привет!
Начали работу над мебелью в домик Сырны, и первым сделали чайный столик с чайным сервизом. А так же продолжаем работу над анимациями.

Wings' might Wings' might

Всем привет)
За неделю в игру было добавлено меню настроек, переделана старая локация, добавлены новые враги и повышена производительности

alexprey alexprey

А мне кажется это такой особый хитрый ход, хотя с другой стороны как разработчики успеют к этому подготовиться получше 🤔

Dreaman Dreaman

Всем привет!
Для проекта "Mental State" разработано новое устройство, которое уже полностью функционирует внутри игрового мира. Оно носит название "Репульсивер". Совместно с очередными большими воротами это устройство образует новую головоломку...

...
Mariya Mariya

Всем привет!
На этой неделе мы научили Сырну летать!

Tartal Tartal

alexprey, кастомизации - создание внешности персонажа? Я всегда любил это, но не думаю, что это будет к месту в мясном шутере)
EfimovMax, да, есть немного)

Tartal Tartal

Jusper, точно не помню, уже как полгода точно) Я вроде в Дискорде немного обсуждал эту тему. Пока немножко попробовал движок - мне очень нравится. Ну, в конце концов, он идеально подходит под жанры, с которыми я хочу работать...

alexprey alexprey

Первая тема крутая очень!

EfimovMax EfimovMax

MyPixel Games, напиши мне в Вк https://vk.com/efimovmax
Я работал с вокселями, смогу помочь.

alexprey alexprey

MyPixel Games, где есть скрын с видом сетки? По идее же легко конвертится в простой меш группировкой + генерацией текстурной карты без фильтрации

MyPixel Games MyPixel Games

alexprey, посмотрите какая там полигональная сетка. Мы сначала наделали моделек, а потом проверили и нас схватил ужас от количества полигонов и невозможности урезать это самое количество. Как-то переживем...

alexprey alexprey

MyPixel Games, хм, такие простые модельки, странно, что это приносит проблемы с производительность

MyPixel Games MyPixel Games

Jusper, антураж + проще в производстве. Конечно, с оптимизацией все не так хорошо. Точнее, совсем не хорошо.

Tartal Tartal

Как раз то, что нужно. Большое спасибо за собранную информацию)

Jusper Jusper

EfimovMax, точно, воксели :)

EfimovMax EfimovMax

Jusper, под лоуполи+пиксели ты имеешь ввиду воксели?)

Jusper Jusper

У меня возник вопрос)
Почему вы выбрали именно такой (лоуполи + пиксели) визуальный стиль?

EfimovMax EfimovMax

Tartal, второй на обезьяну похож, а третий на михалыча с завода :)
Мне нравится первый вариант

Логотип проекта Unity

Гипертекст

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

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

Для того чтобы работать с гипертекстом добавьте следующий класс:

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class Hypertext
{
    public string link_null = "<null>";
    public string color_normal = "black", 
                  color_link = "blue";
    public GUIStyle style = new GUIStyle("label") { richText = true, fontSize = 15, fontStyle = FontStyle.Bold };

    private readonly List<Text> phrases = new List<Text>();

    private struct Text
    {
        public Action action;
        public string text;
        public int index;
    }

    private int GetIndexForLast(string str)
        { return (phrases.Count == 0 ? 0 : phrases[phrases.Count - 1].index) + str.Length; }

    public void Add(string str, Action action = null)
        { phrases.Add(new Text { text = str, index = GetIndexForLast(str), action = action}); }

    public void AddFormat(string str, params Action[] actions)
    {
        const char lBracket = '{', 
                   rBracket = '}';
        int currAction = 0;
        var cursor = 0;
        while (true)
        {
            var rIndex = str.IndexOf(rBracket, cursor);
            if (rIndex == -1) break;
            var lIndex = str.LastIndexOf(lBracket, rIndex);
            if (lIndex == -1) break;
            
            var l1 = lIndex - cursor;
            if (l1 != 0) Add(str.Substring(cursor, l1));

            var l2 = rIndex - lIndex - 1;
            var linktext = (l2 != 0) ? str.Substring(lIndex + 1, l2) : link_null;
            if (actions != null && currAction < actions.Length)
                Add(linktext, actions[currAction++]);
            else
                Add(linktext);

            cursor = rIndex + 1;
        }
        if (cursor != str.Length)
            Add(str.Substring(cursor, str.Length - cursor));
    }

    private static string Color(string color, string content)
        { return "<color=" + color + ">" + content + "</color>"; }

    private string GetSimpleString()
        { return phrases.Aggregate("", (str, p) => str + (p.action == null || !string.IsNullOrEmpty(p.text) ? p.text : link_null)); }

    private string GetRichString()
    {
        return phrases.Aggregate("", (str, p) => str + 
            (p.action == null
                ? Color(color_normal, p.text)
                : !string.IsNullOrEmpty(p.text)
                    ? Color(color_link, p.text)
                    : Color(color_link, link_null)));

    }

    private Text GetTextFromCursor(int index)
        { return phrases.FirstOrDefault(x => index < x.index); }

    public static void DrawLayout(GUIStyle style, string str, params Action[] actions)
    {
        var h = new Hypertext {style = new GUIStyle(style) { richText = true }};
        h.AddFormat(str, actions);
        h.DoDrawLayout();
    }

    public static void DrawLayout(string str, params Action[] actions)
    {
        var h = new Hypertext();
        h.AddFormat(str, actions);
        h.DoDrawLayout();
    }

    public void DoDrawLayout()
    {
        var textRich = GetRichString();
        var textSimple = GetSimpleString();
        var rect = GUILayoutUtility.GetRect(new GUIContent(textSimple), style);
        var index = style.GetCursorStringIndex(rect, new GUIContent(textSimple), Event.current.mousePosition - new Vector2(3, 0));
        var focusText = GetTextFromCursor(index);
        
        GUI.Label(rect, textRich, style);

        if (Event.current.type == EventType.MouseDown && focusText.action != null)
        {
            focusText.action.Invoke();
            Event.current.Use();
        }
    }
}

Примеры использования

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

  1. Формирование гипертекста "частями"
var a = new Hypertext(); 
a.Add("Мама ");
a.Add("мыла", () => Debug.Log("click"));
a.Add(" раму");
a.DoDrawLayout();

В этом случае ключевым является метод Add, и если после текста мы вводим функтор () => { /*Наши действия*/ }, то это слово считается за ссылку.

  1. Формирование гипертекста в одной строке
var a = new Hypertext();
a.AddFormat("Мама {мыла} раму", () => Debug.Log("click"));
a.DoDrawLayout();

В этом случае ключевым является метод AddFormat, в котором все ссылки мы обособляем фигурными скобками, а после, через запятые, указываем функтор-действие на каждую ссылку.

  1. Статическим методом
Hypertext.DrawLayout("Мама {мыла} {раму}", 
                     () => Debug.Log("нажато 'мыла'"), 
                     () => Debug.Log("нажато 'раму'"));

Этот метод по сути работает так же как и второй способ, но позволяет сэкономить в писанине.

Скриншот как пример работы 2 способа:

Гипертекст — Unity — DevTribe: Разработка игр

Кроме того в классе есть несколько дополнительных полей, которые позволяют немного разнообразить ссылки:
style - отвечает за стиль, используемый для рисования надписи
link_null - позволяет указать текст, который будет выводиться если ссылка не имеет названия (должна же оставаться возможность нажимать на нее, верно?)
color_normal - указывает цвет обычного текста (в виде строки)
color_link - указывает цвет ссылок (в виде строки)
Указание цвета в виде строки должно соответствовать правилам указанным вот здесь



Есть какие-то идеи как это можно использовать? Тоесть кроме как для работы в консоли применения ему я придумать не могу. Или это скорее для неигровых приложений?

RiseD_Konst, в редакторах, например. У меня за год было уже 3 таких случая, когда текст вроде слитный, но и вроде должен содержать в себе какой-то функционал. А в целом применение широкое его было как я написал в редакторе триггеров, который я пишу как аналог редактору триггеров в варкрафте, где как раз ссылки и используются.

В еve почти все в этих гиперссылках...

RiseD_Konst, в диалоговой системе. Когда в тексте подсвечиваются слова темы, кликая на которые персонаж рассказывает об этом. Как в морровинде

Нот бэд! На этом реально будет замутить систему диалогов как в морровинде, насколько я понимаю? Вот там была реально шикарная система развития диалогов.

MF, в точку) Я это ведь в предыдущем коменте и написал

alexprey, я только потом заметил, когда отредактировать уже не мог =)