public class SaveData
{
public string appIconPath;
public Texture2D AppIcon
{
get
{
if (appIconPath == null)
{
return null;
}
return AssetDatabase.LoadAssetAtPath<Texture2D>(appIconPath);
}
set
{
appIconPath = AssetDatabase.GetAssetPath(value);
}
}
public static string folderPath
{
get
{
return $"{Application.dataPath}/Editor";
}
}
public static string filePath
{
get
{
return $"{folderPath}/{typeof(WordMasterSDKwindow)}{nameof(SaveData)}.json";
}
}
public void Save()
{
if (System.IO.Directory.Exists(folderPath) == false)
{
System.IO.Directory.CreateDirectory(folderPath);
}
System.IO.File.WriteAllText(filePath, JsonUtility.ToJson(this));
}
public static SaveData Load()
{
if (System.IO.File.Exists(filePath))
{
return JsonUtility.FromJson<SaveData>(System.IO.File.ReadAllText(filePath));
}
else
{
return new SaveData();
}
}
}
에디터윈도우 serializedObject , PropertyField 예제
이거 쓰면 prefs 쓸 필요가 없다. 다만 git에는 안 올라간다
public SceneAsset[] sceneAssets;
void OnGUI()
{
var serializedObject = new SerializedObject(this);
EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(sceneAssets)), true);
serializedObject.ApplyModifiedProperties();
}
serializedObject, prefs 혼합예제
단순하게 몇개 필드만 쓸거라면 serializedObject , JSON 혼합보다 낫다
public RenderTexture renderTexture;
public Coordinator coordinator;
public Object folder;
SerializedObject serializedObject;
void OnGUI()
{
string GetKey(string fieldname)
{
return $"{GetType().FullName}+{fieldname}";
}
if (serializedObject == null)
{
serializedObject = new SerializedObject(this);
coordinator = FindObjectOfType<Coordinator>();
{
var path = EditorPrefs.GetString(GetKey(nameof(folder)), null);
if (path != null)
{
folder = AssetDatabase.LoadAssetAtPath<Object>(path);
}
}
{
var path = EditorPrefs.GetString($"{GetType().FullName}+{nameof(renderTexture)}", null);
if (path != null)
{
renderTexture = AssetDatabase.LoadAssetAtPath<RenderTexture>(path);
}
}
}
serializedObject.Update();
{
EditorGUI.BeginChangeCheck();
{
EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(coordinator)));
EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(folder)));
EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(renderTexture)));
}
if (EditorGUI.EndChangeCheck())
{
EditorPrefs.SetString(GetKey(nameof(folder)), AssetDatabase.GetAssetPath(folder));
EditorPrefs.SetString(GetKey(nameof(renderTexture)), AssetDatabase.GetAssetPath(renderTexture));
}
}
serializedObject.ApplyModifiedProperties();
}
serializedObject , JSON 혼합예제
#if UNITY_EDITOR
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class SampleWindow : EditorWindow
{
public SceneAsset[] sceneAssets;
[System.Serializable]
public class SaveData
{
public string[] sceneAssetPaths;
public static string FolderPath
{
get
{
return $"{Application.dataPath}/Editor";
}
}
public static string FilePath
{
get
{
return $"{FolderPath}/{typeof(SaveData)}.json";
}
}
public void Save()
{
System.IO.File.WriteAllText(FilePath, JsonUtility.ToJson(this));
}
public static SaveData Load()
{
if (System.IO.File.Exists(FilePath))
{
return JsonUtility.FromJson<SaveData>(System.IO.File.ReadAllText(FilePath));
}
else
{
return new SaveData();
}
}
}
public void Save()
{
if(sceneAssets!=null)
{
saveData.sceneAssetPaths = System.Array.ConvertAll(sceneAssets, x => AssetDatabase.GetAssetPath(x));
}
saveData.Save();
}
public void Load()
{
saveData = SaveData.Load();
sceneAssets = System.Array.ConvertAll(saveData.sceneAssetPaths, x => AssetDatabase.LoadAssetAtPath<SceneAsset>(x));
}
public SaveData saveData;
[UnityEditor.MenuItem("Window/SampleWindow")]
public static void Init()
{
GetWindow<SampleWindow>(false, "SampleWindow");
}
void OnGUI()
{
if (saveData == null)
{
Load();
}
EditorGUI.BeginChangeCheck();
{
var serializedObject = new SerializedObject(this);
EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(sceneAssets)));
serializedObject.ApplyModifiedProperties();
}
if (EditorGUI.EndChangeCheck())
{
Save();
}
}
}
#endif
float2 center = 0.5;
float2 pos = i.uv.xy-center;
float2 dir = ((atan2(pos.x,-pos.y)*2/3.14)/4+0.75)%1;
p1,p2,r,center를 이용하여 p3를 구하는 공식 챗GPT가 짜줬다
float2 FindIntersection(float2 p1, float2 p2, float R, float2 center)
{
float2 dir = normalize(p2 - p1);
float2 diff = p1 - center;
// 원의 중심에서 선까지의 거리 d 계산
float d = abs(diff.x * dir.y - diff.y * dir.x);
// 만약 d가 R보다 크면 교점이 없음
if (d >= R)
return float2(0, 0);
// L 계산: L = sqrt(R^2 - d^2)
float L = sqrt(R * R - d * d);
// 원의 중심에서 교점까지의 거리 h 계산: h = sqrt(R^2 - L^2)
float h = sqrt(R * R - L * L);
float2 midpoint = p1 + dot(center - p1, dir) * dir; // 선 위의 원의 중심에 수직인 점
// 두 교점은 midpoint에서 ±L만큼 dir 방향으로 떨어져 있음
float2 intersection1 = midpoint + L * dir;
float2 intersection2 = midpoint - L * dir;
// 이 예제에서는 두 교점 중 하나만 반환합니다.
// 필요에 따라 두 교점 중 원하는 교점을 선택하여 반환하면 됩니다.
return intersection1;
}
/// <summary>
/// 이름을 GUI에 표시함
/// </summary>
/// <param name="wordDictionary">이름</param>
/// <param name="wid">가로크기</param>
/// <param name="hei">세로크기</param>
void DrawWordDictionary(string Name, int wid, int hei)
{
}
널은 안됨
class NotNullContainer<T> where T : notnull
{
}
new한정자
new가 붙은거만 넣을수 있음
public static T GetClass<T>(string text) where T : new()
{
if(text=="ok")
{
var targetClass = new T();
return targetClass;
}
else
{
return null;
}
}
is 연산자
어디서 온건지 알 수 없는 obj등을 처리할 때 쓰인다
if ((objData is Dictionary<string, object>)==false)
{
Debug.LogError("objData는 Dictionary<string, object>가 아닙니다");
return;
}
//아래와 동일함
if ((objData.GetType() == typeof(Dictionary<string, object>))==false)
{
Debug.LogError("objData는 Dictionary<string, object>가 아닙니다");
return;
}
as 연산자
캐스팅 연산자인데 좀 복잡함 아래 참고
서로 동일한 코드를 나타내고 있다
string text= obj as string;
//위아래 동일함
string text;
if (obj is string)
{
text = (string)obj;
}
else
{
text = null;
}
if else 간소화 (남용은 금지, 복수로 쓰게될경우 가독성이 개판된다)
bool A;
if (B)
{
A = C;
}
else
{
A = D;
}
//위아래 동일
bool A=B?C:D;
null체크 간소화
if (A != null)
{
if (B != null)
{
return C;
}
}
return null;
//위아래 동일
return A?.B?.C;
?[]연산 에러발생시 null반환
다만 인덱스 오류는 캐치가 안 된다
string text = null;
if (array!=null)
{
text = array[1];
}
//위아래 동일
var text = array?[1];
아래건 동일분기 처리를 좀 알아봐야 겠다
switch 간소화 (유니티 안됨, 비주얼스튜디오 2019 자동화 안됨)
switch(condition)
{
case 1:
A=B;
break;
case 2:
A=C;
break;
default:
A=D;
break;
}
//위아래 동일
condition switch
{
1 => A=B;
2 => A=C;
_ => A=D;
}
튜플
void Start()
{
var (min, max) = FindMinMax(1, 2, 3, 4);
Debug.Log("min: " + min);
Debug.Log("max: " + max);
}
(int min, int max) FindMinMax(params int[] input)
{
var min = Mathf.Min(input);
var max = Mathf.Max(input);
return (min, max);
}
여러개 리턴할때 사용
유니티도 된다
??연산
null처리할때 좋음
아래 네개 모두 동일한 코드이다
string a = null;
Debug.Log(a ?? "ABC"); //ABC반환
a = "a";
Debug.Log(a ?? "BCD"); //a반환
//위아래 동일
string a = null;
Debug.Log(a is string ? a:"ABC"); //ABC반환
a = "a";
Debug.Log(a is string ? a:"BCD"); //a반환
//위아래 동일
string a = null;
Debug.Log(a==null ? "ABC":a); //ABC반환
a = "a";
Debug.Log(a==null ? "BCD":a); //a반환
//위아래 동일
string a = null;
if(a!=null)
{
Debug.Log(a);
}
else
{
Debug.Log("ABC");
}
a = "a";
if(a!=null)
{
Debug.Log(a);
}
else
{
Debug.Log("BCD");
}
인덱스 체크 간소화
근데 어차피 쓰려면 null체크 추가로 들어가서 그렇게 효율적이진 않음 오히려 협업할때는 누구나 알기쉬운 위쪽이 나을수도 있겠다
if((index >= 0)&&(index < array.Length))
{
var item = array[index];
//작동할 코드
}
//위아래 동일
var item = array.ElementAtOrDefault(index);
if(item != null)
{
//작동할 코드
}
로컬함수
외부로 표출될 필요가 없는 함수 작성시 매우매우 유용하다.
특히 최장점은 같은 이름의 함수를 여러군데서 쓸수있다는 점
함수를 사용할때마다 생성하는 방식인지
성능을 절약하기 위해 static을 붙이라는 문구가 뜨는데 유니티 2019에서는 미지원이다
void SampleFunction()
{
Debug.Log(LocalFunction("test")); //long text
Debug.Log(LocalFunction("te")); //short text
Debug.Log(LocalFunction("")); //short text
string LocalFunction(string text)
{
if(text.Length>2)
{
return "long text";
}
return "short text";
}
}
모든 스크립트에 using을 적용
몰론 함부로 쓰면 ㅈ된다
global using System;
함수내부 조건식 Predicate
public static class Array
{
//Array.FindIndexAll(arr,x=>x>1);
//혹은 arr.FindIndexAll(x=>x>1);
public static int[] FindIndexAll<T>(this T[] array, System.Predicate<T> match)
{
var indexList = new List<int>();
for (int i = 0; i < array.Length; i++)
{
if (match.Invoke(array[i]))
{
indexList.Add(i);
}
}
return indexList.ToArray();
}
//2개인자
//Array.FindAll(arr,x=>x.Item1>x.Item2)
public static int[] FindAll<T>(T[] array, System.Predicate<(T previous,T target)> match)
{
var indexList = new List<int>();
for (int i = 0; i < array.Length; i++)
{
if (match.Invoke((array[i-1],array[i])))
{
indexList.Add(i);
}
}
return indexList.ToArray();
}
}