Last active
February 11, 2025 03:49
-
-
Save Curookie/42c979a7de7d656ec8cf6b8c01ea0457 to your computer and use it in GitHub Desktop.
Unity 유니티 실무2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
유니티 실무1 - https://gist.github.com/Curookie/5de19e581eb54cff7d7b643408ba930c | |
----- 진짜 정말 많이 쓰는 3가지 프레임워크 코드 공유 ----- | |
1. 트랜스 폼 아래에 모든 게임오브젝트 제거 | |
public static void DestroyAllChildren(this Transform tran) { | |
var children = new List<GameObject>(); | |
for (var i = 0; i < tran.childCount; i++) { | |
children.Add(tran.GetChild(i).gameObject); | |
} | |
var failsafe = 0; | |
while (children.Count > 0 && failsafe < 200) { | |
var child = children[0]; | |
GameObject.DestroyImmediate(child); | |
if (children[0] == child) { | |
children.RemoveAt(0); | |
} | |
failsafe++; | |
} | |
} | |
2. 해당 트랜스폼의 가장 가까운 부모 캔버스 찾는 거 | |
public static Canvas GetTopmostCanvas(this Transform tran) { | |
Canvas[] parentCanvases = tran.GetComponentsInParent<Canvas>(); | |
if (parentCanvases != null && parentCanvases.Length > 0) { | |
return parentCanvases[parentCanvases.Length - 1]; | |
} | |
return null; | |
} | |
3. 스크린 값 (마우스 포인터) Vector2가 있을경우 World 좌표로 자동변환 단 변환할 좌표 트랜스폼을 제시 | |
public static Vector3? ScreenToWorld(this Vector2 screenPos_, Transform targetTrans_) { | |
var targetCanvas_ = targetTrans_.GetTopmostCanvas(); | |
Vector3? worldCursorPos_ = null; | |
if(targetCanvas_) { | |
if(targetCanvas_.renderMode == RenderMode.ScreenSpaceOverlay) { | |
worldCursorPos_ = screenPos_; | |
} else { | |
worldCursorPos_ = targetCanvas_.worldCamera.ScreenToWorldPoint(new Vector3(screenPos_.x, screenPos_.y, targetCanvas_.planeDistance)); | |
} | |
} else { } | |
return worldCursorPos_; | |
} | |
----- URP 2D, Overlay Camera에서 2D Light가 적용이 안되는 이슈 (2022.3.34f1)----- | |
이슈 : | |
메인 Base 캠은 1,2,3 레이어 Culling | |
Overlay 캠은 4 레이어를 Culling 했는데 | |
1번 레이어에 있는 2D Light - Global 효과가 | |
SortingLayer설정과 상관없이 Overlay캠에 적용된 4번 레이어에 적용이 안됨. | |
해결법 : 2D Light를 하나더 만들어서 2D Light 오브젝트 레이어를 같은 레이어(4번 레이어)로 변경시 됨. | |
----- 코드로 게임 오브젝트 생성시 ------ | |
new GameObject("Contents", typeof(CanvasRenderer), typeof(RectTransform)) | |
이런식으로 생성하면 컴포넌트도 쉽게 붙일 수 있다. | |
------ RectTransform 가져오는 다른 방법 ------ | |
보통 transform.GetComponent<RectTransform>() 으로 가져오는데 | |
transform as RectTransform 으로 가져올수도 있다. | |
(transform as RectTransform).블라블라 이런식도 가능 | |
------ 커스텀 디버거 Custom Debug ------ | |
[HideInCallstack] 콜백에 커스텀 디버깅 코드가 스태킹되서 콘솔 볼때 스트레스 받을 때 쓰는 어트리뷰트가 있었는데 2022.3 에서 지원 안한다. | |
그대신 콘솔 창에 햄버거 아이콘 누르고 Strip logging stacking 체크해주면 자동으로 커스텀 디버깅 스태킹이 사라짐. | |
[예시] | |
Common : AAAA | |
UnityEngine.Debug:Log (object) | |
GameFrameworks.DBug:<Log>g___Log|6_0 (GameFrameworks.DBug/<>c__DisplayClass6_0&) (at Assets/Plugins/GameFrameworks/Utility/DBug.cs:53) | |
GameFrameworks.DBug:Log (string,GameFrameworks.DBug/PrintLogType) (at Assets/Plugins/GameFrameworks/Utility/DBug.cs:42) | |
TokaTonTon.GameSceneManager:OnEnable () (at Assets/02_Script/Manager/GameSceneManager.cs:54) | |
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&) | |
Common : AAAA | |
UnityEngine.Debug:Log (object) | |
TokaTonTon.GameSceneManager:OnEnable () (at Assets/02_Script/Manager/GameSceneManager.cs:54) | |
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&) | |
------ Tilemap에서 반 칸짜리 타일(Half Tile) 구분할때 유용한 방법 ------ | |
이름을 텍스쳐 이름을 HALF_ 이런식으로 넣고 이름으로 구분하는거 유용하다. TilemapCollider2D 개별 체크안됨. | |
foreach (var position in bounds.allPositionsWithin) | |
{ | |
Vector3Int tilePosition = new Vector3Int(position.x, position.y, 0); | |
if (tilemap.HasTile(tilePosition)) | |
{ | |
bool isHalf = false; | |
Tile tile = tilemap.GetTile<Tile>(position); | |
if (tile) | |
{ | |
if (tile.name != null && tile.name.Contains("HALF")) | |
{ | |
isHalf = true; | |
} else if (tile.sprite != null && tile.sprite.name.Contains("HALF")) | |
{ | |
isHalf = true; | |
} | |
} | |
Vector3Int aboveTilePosition = new Vector3Int(tilePosition.x, tilePosition.y + (isHalf ? 0 : 1), 0); | |
if (!tilemap.HasTile(aboveTilePosition)||isHalf) | |
{ | |
Vector3 worldPosition = tilemap.CellToWorld(aboveTilePosition); | |
Vector3Int localPosition = tilemap.layoutGrid.WorldToCell(worldPosition); | |
walkableTiles.Add((Vector2Int)localPosition); | |
} | |
} | |
------ Post Processing 스크립트로 제어할 때 주의할 점 ------ | |
1. _dOF.focalLength.value = 0; | |
2. _dOF.focalLength = new ClampedFloatParameter(0, 1, 300, true); | |
두 가지 방안이 있는데 | |
이렇게 제어할 때는 반드시 min max 값이 inspector의 min max값과 동일해야한다. | |
아래방식대로 적용할때는 override가 필요할경우 즉시 반영해야할경우 아래 방식으로 true해서 처리해야함. | |
종류마다 1, 2 스크립팅을 다르게 해야할 필요가 있어보임. Depth of Field는 1번방식으로만 적용됨. (2022.3.34f1 기준) | |
------ Timeline Pasue 할때 이미 완료되서 Hold된 애니메이션 초기화 되는 현상 막는법 ----- | |
pD_Director.Pause(); | |
pD_Director.RebuildGraph(); | |
정지하고 직후 Graph를 Rebuild시켜준다. | |
------ CinemachineVirutalCamera Noise 안먹을 때! ---- | |
컴포넌트 달려있는 오브젝트를 복제해서 생성할 경우 Noise가 안먹는 상황이 발생했다. (2022.3.34f1 버전 기준) | |
Body 컴포넌트 None , Noise 컴포넌트 None으로 바꾼다음 다시 설정하면 제대로 먹힘. | |
------ 픽셀 게임 만들때 Texture 설정 ------- | |
PPU - 32나 64 | |
Filter Mode - Point | |
Compression - None | |
------ area.bounds.Contains() 2DCollider의 bounds.Contains 함수가 제대로 작동안될때 ------ | |
2DCollider.bounds.Contains(Vector3) 로 체크할때 분명히 범위안에 있는데 false가 뜨는경우 | |
z값을 2DCollider의 z값으로 설정하면 제대로 먹힘 | |
ex) | |
잘못된 예 - area&&target&&area.bounds.Contains(target.transform.position); | |
옳은 예 - area&&target&&area.bounds.Contains(new Vector3(target.transform.position.x, target.transform.position.y, area.transform.position.z)); | |
----- Awake보다 빨리 실행시키는 방법 ------ | |
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] | |
static void PreAwake() { | |
} | |
스태틱함수로 만들어야함. | |
----- 컴파일 제외 꿀팁 ------ | |
안쓰는 스크립트를 컴파일 제외 시키고싶을때 폴더 명 앞에 ~ 를 붙여주면 완전히 무시할 수 있다. | |
----- Master Audio BGM 팁 ----- | |
var track1Playing = PlaylistController.InstanceByName("BGM_Track1")?.ActiveAudioSource?.clip?.name ?? ""; | |
BGM 켜져 있는지 체크 | |
----- Assembly Definition 사용 시 매우매우 주의할점 ------ | |
기본적으로 Auto Referecnce 라는 체크박스가 켜져있는데 내가 일반적으로 컴파일안할거면 절대 꺼놔야한다!!! 켜놓으면 | |
그냥 기존에 컴파일하던대로 자동으로 컴파일 과정에 포함되서 쓰는 의미가 없다. | |
ex) example 붙은 Assembly Definition - Auto Reference 반드시 끄기 | |
+ Define Constraints에 UNITY_INCLUDE_TESTS 넣어서 제외 시키기 | |
+ Include Platforms에 QNX 이런거만 체크해서 제외 시키기 | |
----- 에디터에서 isPlaying이 아닐때 PlayMode 아닐때 tranform 을 코드로 바꿀경우 적용이 안될 수 있는데 이때 ---- | |
delayCall 로 변경하면 적용됨 | |
ex) | |
#if UNITY_EDITOR | |
EditorApplication.delayCall += () => { | |
sR_Main.transform.localPosition = new Vector3(Building.GetOffset.x, Building.GetOffset.y, 0); | |
}; | |
if(!Application.isPlaying) { | |
EditorUtility.SetDirty(sR_Main.gameObject); | |
SceneView.RepaintAll(); | |
} | |
#else | |
sR_Main.transform.localPosition = new Vector3(Building.GetOffset.x, Building.GetOffset.y, 0); | |
#endif | |
----- 유니티 프로젝트 에디터 버전 체크하는 법 ------ | |
ProjectSettings/ProjectVersion.txt 에서 확인 가능하다. | |
----- 에디터 코드 꿀팁 HelpBox 잘 활용하면 매우 쉽고 빠르게 인스펙터 이쁘게 꾸밀 수 있다. (기본 디자인이 둥근 사각형이라 좋음)------ | |
예시) Editor 코드 | |
protected void InitializeStyles() | |
{ | |
foldoutStyle = new GUIStyle(EditorStyles.foldout) | |
{ | |
fontStyle = FontStyle.Bold, | |
margin = new RectOffset(15, 0, 4, 4), | |
border = new RectOffset(1, 1, 1, 1), | |
}; | |
headerStyle = new GUIStyle(EditorStyles.helpBox) | |
{ | |
padding = new RectOffset(10, 10, 8, 8), | |
margin = new RectOffset(4, 4, 4, 4), | |
border = new RectOffset(1, 1, 1, 1), | |
}; | |
contentBoxStyle = new GUIStyle(EditorStyles.helpBox) | |
{ | |
padding = new RectOffset(10, 10, 5, 5), | |
margin = new RectOffset(0, 0, 4, 4), | |
border = new RectOffset(1, 1, 1, 1), | |
}; | |
vector2Style = new GUIStyle(EditorStyles.numberField) | |
{ | |
fixedWidth = 150, | |
fontSize = 12, | |
fontStyle = FontStyle.Bold | |
}; | |
originalBGColor = GUI.backgroundColor; | |
} | |
protected virtual void MainSettings() { | |
if (!stylesInitialized) { | |
InitializeStyles(); | |
stylesInitialized = true; | |
} | |
EditorGUILayout.PropertyField(_SO_Creature, new GUIContent("프리셋")); | |
DrawSpritePreview(); | |
GUI.backgroundColor = new Color(0.1f, 0.1f, 0.1f); | |
EditorGUILayout.BeginVertical(headerStyle); | |
GUI.backgroundColor = originalBGColor; | |
EditorGUILayout.BeginHorizontal(); | |
EditorGUILayout.LabelField("현재 속도:", GUILayout.Width(70)); | |
GUILayoutOption[] options = { GUILayout.Width(180) }; | |
velocity.vector2Value = EditorGUILayout.Vector2Field("", velocity.vector2Value, options); | |
GUILayout.FlexibleSpace(); | |
if (GUILayout.Button(isAllHide ? "Show All" : "Hide All", GUILayout.Width(70))) { | |
isAllHide = !isAllHide; | |
ToggleFoldouts(isAllHide); | |
} | |
EditorGUILayout.EndHorizontal(); | |
EditorGUILayout.EndVertical(); | |
GUI.backgroundColor = new Color(0.1f, 0.1f, 0.1f); | |
EditorGUILayout.BeginVertical(headerStyle); | |
GUI.backgroundColor = originalBGColor; | |
showBaseSettings = EditorGUILayout.Foldout(showBaseSettings, "기본", true, foldoutStyle); | |
if(showBaseSettings) { | |
EditorGUILayout.BeginVertical(contentBoxStyle); | |
DrawOptionalProperty(applyMass, mass, "무게", "1 - 10"); | |
DrawOptionalProperty(applyFriction, friction, "마찰력", "0 - 1"); | |
DrawOptionalProperty(applyBounce, bounciness, "반동력", "0 - 1"); | |
DrawOptionalProperty(applyPush, null, "밀림 여부", "False or True"); | |
EditorGUILayout.EndVertical(); | |
} | |
EditorGUILayout.EndVertical(); | |
GUI.backgroundColor = new Color(0.1f, 0.1f, 0.1f); | |
EditorGUILayout.BeginVertical(headerStyle); | |
GUI.backgroundColor = originalBGColor; | |
showDetailSettings = EditorGUILayout.Foldout(showDetailSettings, "세부 설정", true, foldoutStyle); | |
if(showDetailSettings) { | |
EditorGUILayout.BeginVertical(contentBoxStyle); | |
EditorGUILayout.PropertyField(serializedObject.FindProperty("gravityModifier"), new GUIContent("중력 가산치")); | |
EditorGUILayout.Space(10); | |
EditorGUILayout.PropertyField(serializedObject.FindProperty("minGroundNormalY"), new GUIContent("지면착지 판정각")); | |
EditorGUILayout.EndVertical(); | |
} | |
EditorGUILayout.EndVertical(); | |
} | |
----- 태그 비교 최적화 ----- | |
transform.gameObject.tag == "AA" 하는 것보다 transform.CompareTag("AA") 하는게 조금 더 이점이 있다. | |
----- collider.Cast 함수 ----- | |
collider의 가장자리에서 특정 방향 및 거리에 떨어진 Collider를 찾을 때 사용하면 유용하다. | |
ex) 콜라이더의 오른쪽 shellRadius 만큼 떨어진 영역 안에 있는 모든 콜라이더를 찾는 예제 | |
var colliders = body.GetComponents<Collider2D>(); | |
var hitBufferPush = new RaycastHit2D[16]; | |
int count = 0; | |
foreach (var collider in colliders) | |
{ | |
if (!collider.isTrigger) | |
{ | |
count += collider.Cast(Vector2.right, contactFilter, hitBufferPush, shellRadius); | |
} | |
} | |
----- 스크립트를 에디터에서 혹은 빌드 후 가장 먼저 실행시키는 법 (PlayMode 아닐때에도 실행) ----- | |
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] 태그로 빌드 이후에도 가장 먼저 실행가능 | |
에디터에서만 하려면 | |
#if UNITY_EDITOR | |
[InitializeOnLoadMethod] | |
#endif | |
ex) 현재 씬에 매니저씬이 없으면 자동으로 불러오려는 상황 예시 | |
#if UNITY_EDITOR | |
using UnityEditor; | |
using UnityEditor.SceneManagement; | |
#endif | |
using UnityEngine; | |
using UnityEngine.SceneManagement; | |
public class AutoLoadManagerScene : MonoBehaviour | |
{ | |
private const string ManagerSceneName = "Manager"; | |
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] | |
private static void LoadManagerSceneInPlayMode() | |
{ | |
if (!IsSceneLoaded(ManagerSceneName)) | |
{ | |
SceneManager.LoadSceneAsync(ManagerSceneName, LoadSceneMode.Additive); | |
Debug.Log($"Manager scene '{ManagerSceneName}' automatically loaded in Play Mode."); | |
} | |
} | |
#if UNITY_EDITOR | |
[InitializeOnLoadMethod] | |
private static void LoadManagerSceneInEditMode() | |
{ | |
EditorApplication.update += () => | |
{ | |
if (!Application.isPlaying && !IsSceneLoaded(ManagerSceneName)) | |
{ | |
EditorSceneManager.OpenScene($"Assets/01_Scene/{ManagerSceneName}.unity", OpenSceneMode.Additive); | |
Debug.Log($"Manager scene '{ManagerSceneName}' automatically loaded in Edit Mode."); | |
} | |
}; | |
} | |
#endif | |
private static bool IsSceneLoaded(string sceneName) | |
{ | |
for (int i = 0; i < SceneManager.sceneCount; i++) | |
{ | |
if (SceneManager.GetSceneAt(i).name == sceneName) | |
return true; | |
} | |
return false; | |
} | |
} | |
----- UI Toolkit 으로 .uss 스타일 시트를 만들 수 있다. ----- | |
Unity UI Toolkit 패키지로 | |
웹에서 css 처럼 에디터 상 커스텀 스타일을 쉽게 만들 수 있다. | |
----- Easy Save 3 파일 저장 ----- | |
ES3File은 Easy Save 3에서 제공하는 기능 중 하나로, 메모리 내에서 작동하는 저장 파일 객체 | |
이 객체는 파일을 직접적으로 다루기보다, 메모리 상에서 파일의 내용을 관리하고 수정한 후에 최종적으로 디스크에 저장하거나 로드하는 방식을 사용 | |
성능 최적화: 파일을 자주 읽고 쓰지 않고 메모리에서 작업을 처리함으로써 성능이 향상 | |
버퍼링 기능: 데이터를 수집한 뒤 한 번에 저장하거나 로드할 수 있어 효율적 | |
안정성: 데이터를 메모리에서 작업한 후에 문제가 발생할 경우 디스크로 저장되지 않으므로 안정성 높음 | |
ES3File _es3File = new ES3File(filePath, es3Settings); | |
_es3File.Save<string>(key, data); | |
_es3File.Sync(); | |
// 비동기로 데이터를 파일에 저장하기도 가능 | |
await _es3File.SyncAsync(); | |
------ uGUI Slider 키보드 제어 막기 ----- | |
Slider가 좌우 키제어(Horizontal and Vertical axes)를 받아서 예상치 못한 Slider Value값이 변경되어 UI가 바뀌는 현상이 있을 수 있다. | |
키보드 제어를 막으려면 Navigation 옵션을 None으로 두면 됨. | |
코드로만 제어하려면 (안전하게 마우스 제어도 막으려면) Interactable 도 false로 하자. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment