先說結論 : Switch case 再Case數量 > 5 之後比 if else 還快 ( 但快非常少 )
為什麼? 他經過什麼轉換?
Switch Case 是語法糖 所以他會經過轉換 基本上就是轉成 if else 的形式 只是會做一些優化處理
以下為轉換程式碼
如果 case 是數字常數時->會轉成樹狀查詢
轉成:
物件格式:
結論: 當switch case 是數字常數時會比較快 or 非數字常數要超過5個以上才會優化
參考:
先說結論 : Switch case 再Case數量 > 5 之後比 if else 還快 ( 但快非常少 )
為什麼? 他經過什麼轉換?
Switch Case 是語法糖 所以他會經過轉換 基本上就是轉成 if else 的形式 只是會做一些優化處理
以下為轉換程式碼
如果 case 是數字常數時->會轉成樹狀查詢
int a = 100; |
轉成:
int num = 100; |
物件格式:
Object b = "100"; |
| case 數量 >5 時 會先轉HashCode 所以能夠被樹狀查詢 ( 會比較快點 ) 轉成: |
object obj = "100"; |
結論: 當switch case 是數字常數時會比較快 or 非數字常數要超過5個以上才會優化
參考:
Array & List 常常要做 null check & out of range check 寫起來麻煩 把這段寫成擴充函式方便些
public static class ArraySafe
{
public static bool IsSafe<T>(this T[] array, int index)
{
return array != null && index >= 0 && index < array.Length;
}
public static bool IsSafe<T>(this System.Collections.Generic.List<T> array, int index)
{
return array != null && index >= 0 && index < array.Count;
}
public static bool TryGetElement<T>(this T[] array, int index, out T element)
{
if (array == null || index < 0 || index >= array.Length)
{
element = default(T);
return false;
}
element = array[index];
return true;
}
public static bool TryGetElement<T>(this System.Collections.Generic.List<T> list, int index, out T element)
{
if (list == null || index < 0 || index >= list.Count)
{
element = default(T);
return false;
}
element = list[index];
return true;
}
}
public static class BitHelper
{
public static byte[] BoolAryToBits(bool[] bools)
{
if (bools == null)
{
Debug.LogError("get null? ");
return null;
}
int len = bools.Length >> 3;
if (bools.Length % 8 != 0)
{
len++;
}
byte[] result = new byte[len];
for (int i = 0; i < bools.Length; i++)
{
bool setTrue = bools[i];
if (((i >> 3) < result.Length) && setTrue)
{
result[i >> 3] |= (byte)(1 << (i & 7));//一個bit可以為0或1足夠判斷了
}
}
return result;
}
}
Unity C# 版本:
using UnityEngine;
using System.Collections.Generic;
[System.Serializable]
public class PoissonDiscHelper
{
int _w;
int _h;
float _r;
[SerializeField]
public List<Vector2> Points = new List<Vector2>();
[SerializeField]
List<Vector2> CandidatePoints = new List<Vector2>();
public List<Vector2> Gen(int w, int h, float r)
{
_w = w;
_h = h;
_r = r;
Points.Clear();
CandidatePoints.Clear();
AddPointToMax();
return Points;
}
private void AddPointToMax()
{
int limit = 9999;
int idx = 0;
while ((Points.Count == 0 || CandidatePoints.Count > 0) && idx < limit)
{
AddPoint();
idx++;
}
}
private void AddPoint()
{
Vector2 newP;
if (Points.Count == 0)
{
System.Random r = new System.Random();
newP = new Vector2(r.Next(0, _w), r.Next(0, _h));
}
else
{
if (CandidatePoints.Count <= 0)
{
Debug.LogFormat("Total Done. Point Count: {0}", Points.Count);
return;
}
int rand = Random.Range(0, CandidatePoints.Count - 1);
newP = CandidatePoints[rand];
CandidatePoints.RemoveAt(rand);
}
Points.Add(newP);
int rayCount = 64;
for (int rayI = 0; rayI < rayCount; rayI++)
{
Vector3 dir3 = Rotate(new Vector3(0, 0, 1), Vector3.up, rayI * 360f / rayCount);
Vector2 dir = new Vector2(dir3.x, dir3.z);
Vector2 candiate = newP + (dir.normalized * _r);
if (candiate.x <= _r / 4 || candiate.y <= _r / 4)
{
continue;
}
if (candiate.x > _w - _r / 4 || candiate.y > _h - _r / 4)
{
continue;
}
CandidatePoints.Add(candiate);
}
foreach (Vector2 p in Points)
{
for (int i = CandidatePoints.Count - 1; i >= 0; i--)
{
Vector2 cp = CandidatePoints[i];
if (Vector2.Distance(cp, p) < _r - 0.001f)
{
CandidatePoints.RemoveAt(i);
}
}
}
}
private Vector3 Rotate(Vector3 source, Vector3 axis, float angle)
{
Quaternion q = Quaternion.AngleAxis(angle, axis);// 旋转系数
return q * source;// 返回目标点
}
}
/// <summary>
/// 计算一个Vector3绕指定轴旋转指定角度后所得到的向量。
/// </summary>
/// <param name="source">旋转前的源Vector3</param>
/// <param name="axis">旋转轴</param>
/// <param name="angle">旋转角度</param>
/// <returns>旋转后得到的新Vector3</returns>
public Vector3 Rotate(Vector3 source, Vector3 axis, float angle)
{
Quaternion q = Quaternion.AngleAxis(angle, axis);// 旋转系数
return q * source;// 返回目标点
}
這裡實現一個可以做 上一步 & 下一步 的命令模式 如果要新增指令 只要繼承 ICommand 並實作 Execute() && Undo() 就行了 使用時只要呼叫 _cmd = new XXXCmd(); _cmd.Execute(); _cmdHistoryMgr.StoreCommand(_cmd);
上一步只需要呼叫 _cmdHistoryMgr.Undo(); 下一步則是呼叫 _cmdHistoryMgr.Redo(); 不需要管Command的細節 達到擴充性。
using System.Collections.Generic;
public interface ICommand
{
void Execute();
void Undo();
}
public interface ICommandManager
{
void StoreCommand(ICommand cmd);
void ClearAllCommand();
void Undo();
void Redo();
}
public class CommandHistoryManager : ICommandManager
{
Stack<ICommand> _undoStack = new Stack<ICommand>();
Stack<ICommand> _redoStack = new Stack<ICommand>();
public void ClearAllCommand()
{
_undoStack.Clear();
_redoStack.Clear();
}
public void StoreCommand(ICommand cmd)
{
_undoStack.Push(cmd);
}
public void Redo()
{
if (_redoStack.Count <= 0)
{
return;
}
ICommand cmd = _redoStack.Pop();
cmd.Execute();
_undoStack.Push(cmd);
}
public void Undo()
{
if(_undoStack.Count <= 0)
{
return;
}
ICommand cmd =_undoStack.Pop();
cmd.Undo();
_redoStack.Push(cmd);
}
}
1byte => 0~255
byte[3] 剛好可以對應 Color 的RGB( 0~255,0~255,0~255)
如果有要做 儲存 or 讀取 or 傳輸 可以用這轉換減少容量
public static class ColorUtility
{
public const uint ColorWhiteInt = 4294967295;
public const uint ColorBlackInt = 4278190080;
static byte[] Byte4 = new byte[4];
public static Color32 ToColor(uint colorInt)
{
byte r = (byte)(colorInt >> 0);
byte g = (byte)(colorInt >> 8);
byte b = (byte)(colorInt >> 16);
byte a = (byte)(colorInt >> 24);
return new Color32(r, g, b, a);
}
public static uint ToColorInt(Color32 c)
{
Byte4[0] = c.r;
Byte4[1] = c.g;
Byte4[2] = c.b;
Byte4[3] = c.a;
uint colorInt = BitConverter.ToUInt32(Byte4, 0);
return colorInt;
}
}