![](https://habrastorage.org/getpro/habr/upload_files/d35/b7e/2f4/d35b7e2f42f4c04d9b24fb5f4b35a97f.png)
Разрабатывая Idle игры часто сталкиваются с тем что нужно выразить число через его сокращенную форму. Если в игре используются маленькие числа (хотя бы до 20 знаков), то такие числа в принципе можно выражать в их существующем виде. Для примера в проекте unity создам отображение монет и кнопку, которая будет умножать число монет на некое значение:
![](https://habrastorage.org/getpro/habr/upload_files/ba2/56d/ce1/ba256dce127385a7c7ef48c2eb41b209.png)
Добавлю на кнопку скрипт который будет брать число из текстового поля с монетам и умножать его на число:
using System.Numerics; using UnityEngine; using UnityEngine.UI; public class MLMon : MonoBehaviour { BigInteger money = 1; [SerializeField] GameObject TextMoney; [SerializeField] int Multiplier; public void ButtonClick() { money *= Multiplier; TextMoney.GetComponent<Text>().text = money.ToString(); } }
Сам класс имеет 3 свойства – количество монет, ссылка по отображение монет и множитель. Свойства множителя и отображения монет отображены как сериализуемое поле. И 1 метод который будет умножать имеющееся у нас количество монет на множитель и записывать полученное число в отображение.
![](https://habrastorage.org/getpro/habr/upload_files/936/2a0/8e1/9362a08e143f67a79ad374f618967c9a.png)
Нажимая на кнопку наше число умножается каждый раз и в какой то момент становится слишком большим и неудобным для чтения:
![](https://habrastorage.org/getpro/habr/upload_files/343/1ec/fac/3431ecfacb6538650703e9a2e0639dd0.gif)
Первый способ которым можно сократить запись это выразить его через экспоненциальную запись, для этого добавлю в форму вывода ещё одно отображение и внесу небольшое изменение в код :
using System.Numerics; using UnityEngine; using UnityEngine.UI; public class MLMon : MonoBehaviour { BigInteger money = 1; [SerializeField] GameObject TextMoney, TextMoneyE; [SerializeField] int Multiplier; public void ButtonClick() { money *= Multiplier; TextMoney.GetComponent<Text>().text = money.ToString( ); TextMoneyE.GetComponent<Text>().text = money.ToString("E"); } }
Таким образом выводимое число будет выглядеть так:
![](https://habrastorage.org/getpro/habr/upload_files/22a/d38/117/22ad38117adda122d6109dc4cb21d8b7.gif)
В целом количество знаков уменьшилось, но рассмотрим другой метод вывода информации.
Будем выводить числа в виде 1а,1b,1c,…,100xx. Для примера если наше число = 1000 то будем заменять назначение «1А», если число =10000 то заменяем его на «10А», если число 1000000 то заменяем на 1B и так далее.
Область вывода информации теперь имеет 3 поля вывода числа выглядит это так:
![](https://habrastorage.org/getpro/habr/upload_files/f67/c85/c83/f67c85c837f7cd7684a513375f4f8461.png)
Итоговый код выглядит у нас таким вот образом:
using System; using System.Numerics; using UnityEngine; using UnityEngine.UI; public class MLMon : MonoBehaviour { BigInteger money = 1; [SerializeField] GameObject TextMoney, TextMoneyE, TextMoneyABC; [SerializeField] int Multiplier; public void ButtonClick() { money *= Multiplier; TextMoney.GetComponent<Text>().text = money.ToString( ); TextMoneyE.GetComponent<Text>().text = money.ToString("E"); TextMoneyABC.GetComponent<Text>().text = TO_abc(money.ToString()); } int[] arrayCountDigit = new int[6] { 26, 702, 18278, 475254, 12356630, 321272406 }; char[] lit = new char[26] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; public string TO_abc(string biStr) { int lengthNumb = biStr.ToString().Length; if (lengthNumb > 3) { int countLiderNumber = lengthNumb % 3; if (countLiderNumber == 0) countLiderNumber = 3; int CountNumberForTransformation = (lengthNumb - countLiderNumber) / 3; string NameLiterIsNmber = ""; byte level = 1; for (int i = 0; i < arrayCountDigit.Length; i++) { if (CountNumberForTransformation > arrayCountDigit[i]) { level++; } else { break; } } for (int i = level; i > 0; i--) { int del = i > 1 ? arrayCountDigit[i - 2] : 0; int currentindex = (int)(Math.Ceiling((CountNumberForTransformation - del) / Math.Pow(26, i - 1))); if (currentindex > 26) currentindex = currentindex % 26; currentindex--; if (currentindex < 0) { currentindex = 25; } NameLiterIsNmber += lit[currentindex]; } string first3number = biStr.ToString().Substring(0, countLiderNumber + 1).Insert(countLiderNumber, ","); return first3number + NameLiterIsNmber; } return biStr.ToString(); }
Поясню по коду:
int[] arrayCountDigit = new int[6] { 26, 702, 18278, 475254, 12356630, 321272406 };
Массив который сообщает сколько существует значений в определенном диапазоне чисел.
В первом у нас 26 значений a,b,c,…,z
Во втором 702 = a,b,c,…,z + комбинации значений aa,ab,ac,…,az,ba,bb,…,zz
В третьем 18278 = предыдущий диапазон + комбинации значений aaa,aab,aac,…,zzz
char[] lit = new char[26] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
Буквы которыми будем заменять цифры храним в виде массива
int lengthNumb = biStr.ToString().Length; if (lengthNumb > 3) {код} return biStr.ToString();
считаем длину числа и если оно меньше 4 то нет смысла с ним что либо делать и просто вернем само число. Если же число в длину 4 и более то заменяем цифры буквами:
int countLiderNumber = lengthNumb % 3; if (countLiderNumber == 0) countLiderNumber = 3;
Считаем количество цифр которые мы будем выводить перед буквами, это может быть от 1 до 3 знаков так как высшие разряды заменяются буквами (999 — это ещё число 999, а вот при 1000 значение становится 1А) .Соответственно если число знаков делится на 3 то считаем что выводится 3 цифры.
1 = 1
1000 = 1А (000=А)
10000 = 10А (000=А)
1000000 =1B (000000=B)
int CountNumberForTransformation = (lengthNumb - countLiderNumber) / 3;
Считаем количество знаков которые нам нужно преобразовать в буквы, это общее количество знаков за исключением лидирующих цифр деленное на 3 ( так как преобразовываем тыщи).
byte level = 1; for (int i = 0; i < arrayCountDigit.Length; i++) { if (CountNumberForTransformation > arrayCountDigit[i]) { level++; } else { break; } }
Считаем уровень данных который нужно преобразовать, для этого сравниваем количество преобразовываемых данных с очередным значением массива разрядов.
string NameLiterIsNmber = "";
создаем переменную в которую и будем записывать преобразованные числа, и уровень числа для подсчета группы разрядов. А вот дальше начинаем преобразовывать.
for (int i = level; i > 0; i--) { int del = i > 1 ? arrayCountDigit[i - 2] : 0; int currentindex = (int)(Math.Ceiling((CountNumberForTransformation - del) / Math.Pow(26, i - 1))); if (currentindex > 26) currentindex = currentindex % 26; currentindex--; if (currentindex < 0) { currentindex = 25; } NameLiterIsNmber += lit[currentindex]; }
Проходим по каждому уровню преобразовываемых данных и рассчитываем букву которую будем заменять в данном разряде(делим число знаков за исключением предыдущего уровня на 26 в степени текущего уровня). Получив индекс текущей буквы дописываем эту букву в строковое представление числа.
string first3number = biStr.ToString().Substring(0, countLiderNumber + 1).Insert(countLiderNumber, ","); return first3number + NameLiterIsNmber;
Для большей детальности выводим десятую долю нашего числа
1100 = 1,1А
25500=25,5А
И возвращаем полученное число.
Ну и собственно итоговый вариант:
![](https://habrastorage.org/getpro/habr/upload_files/c5f/0ca/d0f/c5f0cad0fcb1da7daf72dc7e5cd8886f.gif)
Доклад закончил!
ссылка на оригинал статьи https://habr.com/ru/articles/727738/
Добавить комментарий