备份CatanBuilding瘦身独立工程
This commit is contained in:
396
Assets/Scripts/Tools/ConvertTools.cs
Normal file
396
Assets/Scripts/Tools/ConvertTools.cs
Normal file
@@ -0,0 +1,396 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using GameCore;
|
||||
using UnityEngine;
|
||||
|
||||
public class ConvertTools
|
||||
{
|
||||
public static string ConvertTime2(int d, int h, int m, int s)
|
||||
{
|
||||
string str = "";
|
||||
int showCount = 0;
|
||||
int maxShowCount = 2;
|
||||
if (d > 0)
|
||||
{
|
||||
showCount++;
|
||||
str = $"{d}d ";
|
||||
}
|
||||
if (h > 0)
|
||||
{
|
||||
showCount++;
|
||||
str += $"{h}h ";
|
||||
}
|
||||
|
||||
if (showCount >= maxShowCount)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
else if (m > 0)
|
||||
{
|
||||
showCount++;
|
||||
str += $"{m}m ";
|
||||
}
|
||||
|
||||
if (showCount >= maxShowCount)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
else if (s > 0)
|
||||
{
|
||||
str += $"{s}s ";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
public static string ConvertTime2(TimeSpan timer)
|
||||
{
|
||||
return ConvertTime2(timer.Days, timer.Hours, timer.Minutes, timer.Seconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Only One Number, negative time will be considered as 0.
|
||||
/// </summary>
|
||||
/// <param name="timer"></param>
|
||||
/// <returns></returns>
|
||||
public static string ConvertTime3(TimeSpan timer)
|
||||
{
|
||||
if (timer.Days > 0)
|
||||
{
|
||||
return $"{timer.Days}d ";
|
||||
}
|
||||
if (timer.Hours > 0)
|
||||
{
|
||||
return $"{timer.Hours}h ";
|
||||
}
|
||||
if (timer.Minutes > 0)
|
||||
{
|
||||
return $"{timer.Minutes}m ";
|
||||
}
|
||||
|
||||
if (timer.Seconds > 0)
|
||||
{
|
||||
return $"{timer.Seconds}s ";
|
||||
}
|
||||
return "0s ";
|
||||
}
|
||||
/// <summary>
|
||||
/// hh:mm:ss
|
||||
/// </summary>
|
||||
/// <param name="timer"></param>
|
||||
/// <returns></returns>
|
||||
public static string ConvertTime(TimeSpan timer)
|
||||
{
|
||||
return timer.ToString(@"hh\:mm\:ss"); ;
|
||||
}
|
||||
|
||||
public static DateTime GetDateTimeYMD(DateTime date)
|
||||
{
|
||||
return new DateTime(date.Year, date.Month, date.Day);
|
||||
}
|
||||
|
||||
public static DateTime GetDateTimeSunDay(DateTime date)
|
||||
{
|
||||
var dayOfWeek = (int)date.DayOfWeek;
|
||||
int offset = 7 - (dayOfWeek == 0 ? 7 : dayOfWeek);
|
||||
|
||||
return GetDateTimeYMD(date.AddDays(Mathf.Abs(offset)));
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ("#,##0.#")
|
||||
/// </summary>
|
||||
/// <param name="num"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetNumberString(ulong num, bool keep = false)
|
||||
{
|
||||
string format = keep ? "#,##0.0" : "#,##0.#";
|
||||
string str;
|
||||
if (num < 1000)
|
||||
{
|
||||
str = num.ToString("#,##0");
|
||||
}
|
||||
else if (num < 1000000)
|
||||
{
|
||||
str = (num / 1000f).ToString(format) + "K";
|
||||
}
|
||||
else if (num < 1000000000)
|
||||
{
|
||||
str = (num / 1000000f).ToString(format) + "M";
|
||||
}
|
||||
else
|
||||
{
|
||||
str = (num / 1000000000f).ToString(format) + "G";
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/* public static ulong KeepThreeSignificantDigits(ulong value)
|
||||
{
|
||||
if (value == 0) return 0;
|
||||
|
||||
// ulong absValue = Math.Abs(value);
|
||||
ulong digits = (ulong)Math.Floor(Math.Log10(value)) + 1;
|
||||
|
||||
if (digits <= 3)
|
||||
return value;
|
||||
|
||||
ulong digitsToRemove = digits - 3;
|
||||
ulong factor = (ulong)Math.Pow(10, digitsToRemove);
|
||||
ulong rounded = (value / factor) * factor;
|
||||
|
||||
return rounded;
|
||||
} */
|
||||
|
||||
public static int KeepThreeSignificantDigits(int value)
|
||||
{
|
||||
if (value <= 0) return 0;
|
||||
|
||||
int digits = (int)Math.Floor(Math.Log10(value)) + 1;
|
||||
|
||||
if (digits <= 3)
|
||||
return value;
|
||||
|
||||
int digitsToRemove = digits - 3;
|
||||
int factor = (int)Math.Pow(10, digitsToRemove);
|
||||
int rounded = value / factor * factor;
|
||||
|
||||
return rounded;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ("#,##0.#")
|
||||
/// </summary>
|
||||
/// <param name="num"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetNumberString(int num, bool keep = false)
|
||||
{
|
||||
string format = keep ? "#,##0.0" : "#,##0.#";
|
||||
string str;
|
||||
if (num < 1000)
|
||||
{
|
||||
str = num.ToString("#,##0");
|
||||
}
|
||||
else if (num < 1000000)
|
||||
{
|
||||
str = (num / 1000f).ToString(format) + "K";
|
||||
}
|
||||
else
|
||||
{
|
||||
str = (num / 1000000f).ToString(format) + "M";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 折扣显示
|
||||
/// </summary>
|
||||
/// <param name="num"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetNumberString3(float num)
|
||||
{
|
||||
string str = "";
|
||||
if (num <= 1)
|
||||
{
|
||||
var discount = (1 - num) * 100;
|
||||
var decimalPart = discount - (int)discount;
|
||||
// if ( decimalPart < 0.001f )
|
||||
str = discount.ToString("F0");
|
||||
// else
|
||||
// str = discount.ToString("F1");
|
||||
}
|
||||
else
|
||||
Debug.LogError("[ConverTools::GetNumberString3] Discount Exceeds 1");
|
||||
return str + "%";
|
||||
}
|
||||
|
||||
public static string GetNumberStringRetain(double num, bool keep)
|
||||
{
|
||||
|
||||
string str = "";
|
||||
if (num < 0.1)
|
||||
{
|
||||
str = num.ToString("##0.00");
|
||||
}
|
||||
else if (keep)
|
||||
{
|
||||
str = num.ToString("##0.0");
|
||||
}
|
||||
else
|
||||
{
|
||||
str = num.ToString("##0.#");
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ("#,##0")
|
||||
/// </summary>
|
||||
/// <param name="num"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetNumberString2(ulong num)
|
||||
{
|
||||
//输出类似713,999,999
|
||||
|
||||
return num.ToString("#,##0");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ("#,##0")
|
||||
/// </summary>
|
||||
/// <param name="num"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetNumberString2(long num)
|
||||
{
|
||||
//输出类似713,999,999
|
||||
|
||||
return num.ToString("#,##0");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ("#,##0")
|
||||
/// </summary>
|
||||
/// <param name="num"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetNumberString2(int num)
|
||||
{
|
||||
//输出类似713,999,999
|
||||
|
||||
return num.ToString("#,##0");
|
||||
}
|
||||
/// <summary>
|
||||
/// 场景到UI 的坐标转换
|
||||
/// </summary>
|
||||
/// <param name="pos">场景中的全局坐标</param>
|
||||
/// <param name="local">是否转换成相对于UIRoot的局部坐标</param>
|
||||
/// <returns></returns>
|
||||
public static Vector3 WorldToScreenPoint(Vector3 pos, bool local = true)
|
||||
{
|
||||
Vector3 targetPos = Camera.main.WorldToScreenPoint(pos);
|
||||
Vector2 sizeDelta = UIManager.Instance.RectTrans.sizeDelta;
|
||||
|
||||
//先获取主画布下的分辨率宽高:
|
||||
float resolutionRatioWidth = sizeDelta.x;
|
||||
float resolutionRatioHeight = sizeDelta.y;
|
||||
|
||||
//计算主画布分辨率下的宽高和屏幕的宽高的比列:
|
||||
float widthRatio = resolutionRatioWidth / Screen.width;
|
||||
float heightRatio = resolutionRatioHeight / Screen.height;
|
||||
|
||||
//先分别乘以宽高比值
|
||||
targetPos.x *= widthRatio;
|
||||
targetPos.y *= heightRatio;
|
||||
|
||||
//计算在中心点的屏幕坐标
|
||||
targetPos.x -= resolutionRatioWidth * 0.5f;
|
||||
targetPos.y -= resolutionRatioHeight * 0.5f;
|
||||
if (local)
|
||||
{
|
||||
return targetPos;
|
||||
}
|
||||
return UIManager.Instance.RectTrans.transform.TransformPoint(targetPos);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将3D场景的坐标转化为某个UI组件下的局部坐标。
|
||||
/// </summary>
|
||||
/// <param name="worldPosition">3D场景下的坐标</param>
|
||||
/// <param name="uiRectTransform">目标UI组件,默认为UIRoot,但UIRoot可能会有刘海屏适配bug。</param>
|
||||
/// <returns>相对于uiRectTransform的局部UI坐标</returns>
|
||||
public static Vector2 WorldToUiLocalPosition(Vector3 worldPosition, RectTransform uiRectTransform = null)
|
||||
{
|
||||
// uiRectTransform ??= UIManager.Instance.RectTrans;
|
||||
var screenPoint = RectTransformUtility.WorldToScreenPoint(Camera.main, worldPosition);
|
||||
return screenPoint;
|
||||
// Debug.Log($"ScreenPoint: {screenPoint}");
|
||||
// RectTransformUtility.ScreenPointToLocalPointInRectangle(uiRectTransform, screenPoint, Camera.main, out var localHitPosition);
|
||||
// Debug.Log($"localHitPosition: {localHitPosition}");
|
||||
// return localHitPosition;
|
||||
}
|
||||
|
||||
public static string Encrypt(string text, string key)
|
||||
{
|
||||
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
|
||||
des.Key = Encoding.ASCII.GetBytes(key);
|
||||
des.IV = Encoding.ASCII.GetBytes(key);
|
||||
|
||||
ICryptoTransform encryptor = des.CreateEncryptor(des.Key, des.IV);
|
||||
byte[] inputBytes = Encoding.UTF8.GetBytes(text);
|
||||
byte[] outputBytes = encryptor.TransformFinalBlock(inputBytes, 0, inputBytes.Length);
|
||||
|
||||
return Convert.ToBase64String(outputBytes);
|
||||
}
|
||||
|
||||
const string RTMKey = "tbambooz";
|
||||
|
||||
public static string Decrypt(string text)
|
||||
{
|
||||
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
|
||||
des.Key = Encoding.ASCII.GetBytes(RTMKey);
|
||||
des.IV = Encoding.ASCII.GetBytes(RTMKey);
|
||||
|
||||
ICryptoTransform decryptor = des.CreateDecryptor(des.Key, des.IV);
|
||||
byte[] inputBytes = Convert.FromBase64String(text);
|
||||
byte[] outputBytes = decryptor.TransformFinalBlock(inputBytes, 0, inputBytes.Length);
|
||||
|
||||
return Encoding.UTF8.GetString(outputBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算相机偏转限制
|
||||
/// </summary>
|
||||
/// <param name="configuredRotationAngle">为正数0-180</param>
|
||||
/// <returns></returns>
|
||||
public static float CalculateActualRotationAngle(float configuredRotationAngle)
|
||||
{
|
||||
float fovRad = 30 * Mathf.Deg2Rad;
|
||||
float rotationAngleRad = configuredRotationAngle * Mathf.Deg2Rad;
|
||||
float aspectRatio = Screen.width / (float)Screen.height;
|
||||
aspectRatio = Mathf.Clamp(aspectRatio, 0.45f, 1);
|
||||
aspectRatio = Mathf.Atan(Mathf.Tan(fovRad) * aspectRatio);
|
||||
float actualRotationAngleRad = Mathf.Max(0, rotationAngleRad - aspectRatio);
|
||||
float actualRotationAngle = actualRotationAngleRad * Mathf.Rad2Deg;
|
||||
return actualRotationAngle;
|
||||
}
|
||||
public static string ConvertActiveTime(TimeSpan t)
|
||||
{
|
||||
if (t.Days > 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
if (t.Hours > 0)
|
||||
{
|
||||
return $"{t.Hours}h";
|
||||
}
|
||||
if (t.Minutes > 0)
|
||||
{
|
||||
return $"{t.Minutes}m";
|
||||
}
|
||||
if (t.Seconds > 0)
|
||||
{
|
||||
return $"{t.Seconds}s";
|
||||
}
|
||||
return "0s";
|
||||
}
|
||||
|
||||
static public void SetFSBlur(bool isActive, float depth = 6)
|
||||
{
|
||||
var feature = zzwater.URPHelper.FindAndCacheRendererFeature("FSBlur");
|
||||
if (feature == null)
|
||||
Debug.LogError($"Feature FSWave not found");
|
||||
else
|
||||
{
|
||||
feature.SetActive(isActive);
|
||||
if (isActive)
|
||||
{
|
||||
FullScreenPassRendererFeature fullScreenPassRendererFeature = feature as FullScreenPassRendererFeature;
|
||||
Material material = fullScreenPassRendererFeature.passMaterial;
|
||||
if (material != null)
|
||||
{
|
||||
material.SetFloat("_DepthThreshold", depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/Tools/ConvertTools.cs.meta
Normal file
3
Assets/Scripts/Tools/ConvertTools.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0d31e6c27a64041821743c06361aee8
|
||||
timeCreated: 1692100847
|
||||
43
Assets/Scripts/Tools/FileLogger.cs
Normal file
43
Assets/Scripts/Tools/FileLogger.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
public class FileLogger : MonoBehaviour
|
||||
{
|
||||
private string logFilePath;
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
// 定义日志文件路径
|
||||
logFilePath = Application.persistentDataPath + "/game_log.txt";
|
||||
|
||||
// 删除旧日志文件(如果存在)
|
||||
if (File.Exists(logFilePath))
|
||||
{
|
||||
File.Delete(logFilePath);
|
||||
}
|
||||
|
||||
// 注册自定义日志处理器
|
||||
Application.logMessageReceived += HandleLog;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
// 注销自定义日志处理器
|
||||
Application.logMessageReceived -= HandleLog;
|
||||
}
|
||||
|
||||
void HandleLog(string logString, string stackTrace, LogType type)
|
||||
{
|
||||
// 将日志信息写入文件
|
||||
using (StreamWriter writer = new StreamWriter(logFilePath, true))
|
||||
{
|
||||
writer.WriteLine($"[{type}] {logString}");
|
||||
if (type == LogType.Error || type == LogType.Exception)
|
||||
{
|
||||
writer.WriteLine(stackTrace); // 如果是错误或异常,写入堆栈跟踪
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Tools/FileLogger.cs.meta
Normal file
11
Assets/Scripts/Tools/FileLogger.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7059e1f13854ccf4297d334c3af811bb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
251
Assets/Scripts/Tools/FtMathUtils.cs
Normal file
251
Assets/Scripts/Tools/FtMathUtils.cs
Normal file
@@ -0,0 +1,251 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityRandom = UnityEngine.Random;
|
||||
using SystemRandom = System.Random;
|
||||
using UnityEngine;
|
||||
|
||||
public static class FtMathUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Split number into count pieces randomly.
|
||||
/// </summary>
|
||||
/// <param name="number">Number to split.</param>
|
||||
/// <param name="count">Number of pieces.</param>
|
||||
/// <param name="res">Result. Meaningless if result if false.</param>
|
||||
/// <returns>False if fail to split.</returns>
|
||||
public static bool RandomSplit(int number, int count, out List<int> res)
|
||||
{
|
||||
res = new List<int>();
|
||||
if (number < count || number <= 0 || count <= 0)
|
||||
return false;
|
||||
var baseNumbers = new HashSet<int> { 0 };
|
||||
while (baseNumbers.Count < count)
|
||||
baseNumbers.Add(UnityRandom.Range(1, number - 1));
|
||||
var baseList = baseNumbers.OrderBy(e => e).ToList();
|
||||
for (int i = 1; i < baseList.Count; i++)
|
||||
res.Add(baseList[i] - baseList[i - 1]);
|
||||
res.Add(number - baseList[^1]);
|
||||
return res.Count == count;
|
||||
}
|
||||
|
||||
public static bool ScaleByBase(int num, int baseNum, out int res)
|
||||
{
|
||||
res = baseNum;
|
||||
if (num <= 0 || baseNum <= 0)
|
||||
return false;
|
||||
if (num <= baseNum)
|
||||
return true;
|
||||
res = num / baseNum * baseNum;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int GetRandomIdxFromWeightList(IEnumerable<int> weightList)
|
||||
{
|
||||
// Check for null or empty list
|
||||
if (weightList == null || !weightList.Any())
|
||||
{
|
||||
Debug.LogError("[GetRandomIdxFromWeightList]: Weight list is null or empty. Returning 0.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
var accWeightList = new List<int>();
|
||||
int tmp = 0;
|
||||
foreach (int w in weightList)
|
||||
{
|
||||
// Check for negative weights
|
||||
if (w < 0)
|
||||
{
|
||||
Debug.LogError($"[GetRandomIdxFromWeightList]: Negative weight detected: {w}. Returning 0.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp += w;
|
||||
accWeightList.Add(tmp);
|
||||
}
|
||||
|
||||
// Check for all zero weights
|
||||
if (accWeightList[^1] <= 0)
|
||||
{
|
||||
Debug.LogError("[GetRandomIdxFromWeightList]: Total weight is zero or negative. Returning 0.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = UnityRandom.Range(0, accWeightList[^1]);
|
||||
for (int i = 0; i < accWeightList.Count; i++)
|
||||
{
|
||||
if (tmp < accWeightList[i])
|
||||
return i;
|
||||
}
|
||||
return accWeightList.Count - 1;
|
||||
}
|
||||
|
||||
public static int GetRandomIdxFromWeightList(IEnumerable<int> weightList, SystemRandom rng)
|
||||
{
|
||||
// Check for null or empty list
|
||||
if (weightList == null || !weightList.Any())
|
||||
{
|
||||
Debug.LogError("[GetRandomIdxFromWeightList]: Weight list is null or empty. Returning 0.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
var accWeightList = new List<int>();
|
||||
int tmp = 0;
|
||||
foreach (int w in weightList)
|
||||
{
|
||||
// Check for negative weights
|
||||
if (w < 0)
|
||||
{
|
||||
Debug.LogError("[GetRandomIdxFromWeightList]: Negative weight detected. Returning 0.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp += w;
|
||||
accWeightList.Add(tmp);
|
||||
}
|
||||
|
||||
// Check for all zero weights
|
||||
if (accWeightList[^1] <= 0)
|
||||
{
|
||||
Debug.LogError("[GetRandomIdxFromWeightList]: Total weight is zero or negative. Returning 0.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = rng.Next(0, accWeightList[^1]);
|
||||
for (int i = 0; i < accWeightList.Count; i++)
|
||||
{
|
||||
if (tmp < accWeightList[i])
|
||||
return i;
|
||||
}
|
||||
return accWeightList.Count - 1;
|
||||
}
|
||||
|
||||
public static int GetRandomIdxFromWeightList(IEnumerable<float> weightList, SystemRandom rng)
|
||||
{
|
||||
// Check for null or empty list
|
||||
if (weightList == null || !weightList.Any())
|
||||
{
|
||||
Debug.LogError("[GetRandomIdxFromWeightList]: Weight list is null or empty. Returning 0.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
var accWeightList = new List<float>();
|
||||
double tmp = 0d;
|
||||
foreach (float w in weightList)
|
||||
{
|
||||
// Check for negative weights
|
||||
if (w < 0)
|
||||
{
|
||||
Debug.LogError("[GetRandomIdxFromWeightList]: Negative weight detected. Returning 0.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp += w;
|
||||
accWeightList.Add((float)tmp);
|
||||
}
|
||||
|
||||
// Check for all zero weights
|
||||
if (accWeightList[^1] <= 0)
|
||||
{
|
||||
Debug.LogError("[GetRandomIdxFromWeightList]: Total weight is zero or negative. Returning 0.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = rng.NextDouble() * accWeightList[^1];
|
||||
for (int i = 0; i < accWeightList.Count; i++)
|
||||
{
|
||||
if (tmp < accWeightList[i])
|
||||
return i;
|
||||
}
|
||||
return accWeightList.Count - 1;
|
||||
}
|
||||
|
||||
public static T PickRandomItemWithWeight<T>(IEnumerable<T> items, SystemRandom rng, System.Func<int, float> weightGetter)
|
||||
{
|
||||
var weightList = items.Select((x, i) => weightGetter(i)).ToList();
|
||||
return items.ElementAt(GetRandomIdxFromWeightList(weightList, rng));
|
||||
}
|
||||
|
||||
public static T PickRandomItemWithWeight<T>(IEnumerable<T> items, System.Func<int, int> weightGetter)
|
||||
{
|
||||
var weightList = items.Select((x, i) => weightGetter(i)).ToList();
|
||||
return items.ElementAt(GetRandomIdxFromWeightList(weightList));
|
||||
}
|
||||
|
||||
public static Vector2 CalculateBezierCurve(float t, Vector2 p0, Vector2 p1, Vector2 p2)
|
||||
{
|
||||
if (t < 0 || t > 1)
|
||||
return Vector2.zero;
|
||||
Vector2 a = Vector2.Lerp(p0, p1, t);
|
||||
Vector2 b = Vector2.Lerp(p1, p2, t);
|
||||
return Vector2.Lerp(a, b, t);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ("#,##0") Display number with comma, integer part only.
|
||||
/// </summary>
|
||||
/// <param name="num"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetNumberString(float num)
|
||||
{
|
||||
string str;
|
||||
if (num < 1000)
|
||||
{
|
||||
str = num.ToString("#,##0");
|
||||
}
|
||||
else if (num < 1000000)
|
||||
{
|
||||
str = (num / 1000f).ToString("#,##0") + "K";
|
||||
}
|
||||
else if (num < 1000000000)
|
||||
{
|
||||
str = (num / 1000000f).ToString("#,##0") + "M";
|
||||
}
|
||||
else
|
||||
{
|
||||
str = (num / 1000000000f).ToString("#,##0") + "G";
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
public static int[] BitWisePositionScan(int num)
|
||||
{
|
||||
var res = new List<int>();
|
||||
int idx = 0;
|
||||
while (num != 0)
|
||||
{
|
||||
if ((num & 1) == 1)
|
||||
res.Add(idx);
|
||||
num >>= 1;
|
||||
idx++;
|
||||
}
|
||||
return res.ToArray();
|
||||
}
|
||||
|
||||
public static void ShuffleList<T>(IList<T> list, System.Random rng)
|
||||
{
|
||||
for (int i = list.Count - 1; i > 0; i--)
|
||||
{
|
||||
int j = rng.Next(i + 1);
|
||||
(list[j], list[i]) = (list[i], list[j]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a random point in a corn-shaped spread.
|
||||
/// </summary>
|
||||
/// <param name="spreadHalfAngle">In degree.</param>
|
||||
/// <param name="spreadNearRange">Close range.</param>
|
||||
/// <param name="spreadFarRange">Far range.</param>
|
||||
/// <param name="direction">In radians. Default is upward vertical, 90 degrees.</param>
|
||||
/// <returns>A random delta</returns>
|
||||
public static Vector2 GetCornSpread(float spreadHalfAngle, float spreadNearRange, float spreadFarRange, float direction = 90)
|
||||
{
|
||||
var halfAngleRadians = Mathf.Deg2Rad * spreadHalfAngle;
|
||||
var angle = UnityRandom.Range(-halfAngleRadians, halfAngleRadians);
|
||||
angle += Mathf.Deg2Rad * direction;
|
||||
var radius = UnityRandom.Range(spreadNearRange, spreadFarRange);
|
||||
return new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * radius;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Tools/FtMathUtils.cs.meta
Normal file
11
Assets/Scripts/Tools/FtMathUtils.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 494ccf553197cfd47abb1e4a4544586c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
46
Assets/Scripts/Tools/MoveMainCameraToThisLocation.cs
Normal file
46
Assets/Scripts/Tools/MoveMainCameraToThisLocation.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using asap.core;
|
||||
using game;
|
||||
using GameCore;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class MoveMainCameraToThisLocation : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
public bool m_IsSolo = true;
|
||||
|
||||
private Vector3 originalLocalScale;
|
||||
private Quaternion originalRotation;
|
||||
private Vector3 originalPosition;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (m_IsSolo)
|
||||
{
|
||||
Camera camera = this.transform.GetComponent<Camera>();
|
||||
camera.tag = "MainCamera";
|
||||
}
|
||||
else
|
||||
{
|
||||
Camera main = Camera.main;
|
||||
main.transform.localScale = originalLocalScale = this.transform.localScale;
|
||||
main.transform.rotation = originalRotation = this.transform.rotation;
|
||||
main.transform.position = originalPosition = this.transform.position;
|
||||
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
Camera cameraMain = Camera.main;
|
||||
if (cameraMain != null)
|
||||
{
|
||||
cameraMain.transform.localScale = originalLocalScale;
|
||||
cameraMain.transform.rotation = originalRotation;
|
||||
cameraMain.transform.position = originalPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Tools/MoveMainCameraToThisLocation.cs.meta
Normal file
11
Assets/Scripts/Tools/MoveMainCameraToThisLocation.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1a5d1e8f6f54ba747abbd4bd1b98d47e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
120
Assets/Scripts/Tools/Triangulator.cs
Normal file
120
Assets/Scripts/Tools/Triangulator.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class Triangulator
|
||||
{
|
||||
private List<Vector2> m_points = new List<Vector2>();
|
||||
|
||||
public Triangulator(Vector2[] points)
|
||||
{
|
||||
m_points = new List<Vector2>(points);
|
||||
}
|
||||
|
||||
public int[] Triangulate()
|
||||
{
|
||||
List<int> indices = new List<int>();
|
||||
|
||||
int n = m_points.Count;
|
||||
if (n < 3)
|
||||
return indices.ToArray();
|
||||
|
||||
int[] V = new int[n];
|
||||
if (Area() > 0)//如果逆时针选点,点的index正向记录
|
||||
{
|
||||
for (int v = 0; v < n; v++)
|
||||
V[v] = v;
|
||||
}
|
||||
else
|
||||
{//如果顺时针选点,点的index反向记录
|
||||
for (int v = 0; v < n; v++)
|
||||
V[v] = (n - 1) - v;
|
||||
}
|
||||
|
||||
int nv = n;
|
||||
int count = 2 * nv;
|
||||
for (int v = nv - 1; nv > 2;)
|
||||
{
|
||||
if ((count--) <= 0)
|
||||
return indices.ToArray();
|
||||
|
||||
int u = v;
|
||||
if (nv <= u)
|
||||
u = 0;
|
||||
v = u + 1;
|
||||
if (nv <= v)
|
||||
v = 0;
|
||||
int w = v + 1;
|
||||
if (nv <= w)
|
||||
w = 0;
|
||||
|
||||
if (Snip(u, v, w, nv, V))//u,v,w三点是否能构成三角面
|
||||
{
|
||||
int a, b, c, s, t;
|
||||
a = V[u];
|
||||
b = V[v];
|
||||
c = V[w];
|
||||
indices.Add(a);
|
||||
indices.Add(b);
|
||||
indices.Add(c);
|
||||
for (s = v, t = v + 1; t < nv; s++, t++)//增加一个三角数据,把这个三角剪去
|
||||
V[s] = V[t];
|
||||
nv--;
|
||||
count = 2 * nv;
|
||||
}
|
||||
}
|
||||
|
||||
indices.Reverse();//翻转法线
|
||||
return indices.ToArray();
|
||||
}
|
||||
|
||||
private float Area()
|
||||
{
|
||||
int n = m_points.Count;
|
||||
float A = 0.0f;
|
||||
for (int p = n - 1, q = 0; q < n; p = q++)
|
||||
{
|
||||
Vector2 pval = m_points[p];
|
||||
Vector2 qval = m_points[q];
|
||||
A += pval.x * qval.y - qval.x * pval.y;//两向量叉乘只取z值,如果为负则顺时针
|
||||
}
|
||||
return (A * 0.5f);
|
||||
}
|
||||
|
||||
private bool Snip(int u, int v, int w, int n, int[] V)
|
||||
{
|
||||
int p;
|
||||
Vector2 A = m_points[V[u]];
|
||||
Vector2 B = m_points[V[v]];
|
||||
Vector2 C = m_points[V[w]];
|
||||
if (Mathf.Epsilon > (((B.x - A.x) * (C.y - A.y)) - ((B.y - A.y) * (C.x - A.x))))//判断三点是否为顺时针排列,如果是的话是凹陷,不计算三角
|
||||
return false;
|
||||
for (p = 0; p < n; p++)
|
||||
{
|
||||
if ((p == u) || (p == v) || (p == w))
|
||||
continue;
|
||||
Vector2 P = m_points[V[p]];
|
||||
if (InsideTriangle(A, B, C, P))//是否有其他的点在三角形内部,是,不计算三角
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool InsideTriangle(Vector2 A, Vector2 B, Vector2 C, Vector2 P)
|
||||
{
|
||||
float ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
|
||||
float cCROSSap, bCROSScp, aCROSSbp;
|
||||
|
||||
ax = C.x - B.x; ay = C.y - B.y;
|
||||
bx = A.x - C.x; by = A.y - C.y;
|
||||
cx = B.x - A.x; cy = B.y - A.y;
|
||||
apx = P.x - A.x; apy = P.y - A.y;
|
||||
bpx = P.x - B.x; bpy = P.y - B.y;
|
||||
cpx = P.x - C.x; cpy = P.y - C.y;
|
||||
|
||||
aCROSSbp = ax * bpy - ay * bpx;
|
||||
cCROSSap = cx * apy - cy * apx;
|
||||
bCROSScp = bx * cpy - by * cpx;
|
||||
|
||||
return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));//都是逆时针,P在ABC内
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Tools/Triangulator.cs.meta
Normal file
11
Assets/Scripts/Tools/Triangulator.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7061521568a2c1a4196b1aa20722b9f2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user