Stack
후입선출
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StackNode<T>
{
public T data;
public StackNode<T> prev;
}
public class StackCustom<T> where T : new()
{
public StackNode<T> top;
public void Push(T data)
{
var stackNode = new StackNode<T>();
stackNode.data = data; // 노드에 data 넣어주고
stackNode.prev = top; // 이전 top을 새 노드의 prev에 연결 = 이전 top이 노드의 밑(Prev)으로 내려감
top = stackNode; // top에는 새로운 data(새 노드)가 들어감
}
public T Pop() // stack에서 데이터를 제거하는 메서드 -> 제일 위의 것부터 나감(후입선출)
{
if (top == null) // top이 비어있으면 stack이 다 비어있는 것
{
return new (); // T 타입의 기본 생성자 호출
}
var result = top.data; // 제거될 현재 top.data를 result에 담아주고
top = top.prev; // 새로운 top은 top의 prev 데이터와 이어줌 = 현재 top의 이전 노드를 새로운 top으로 설정
return result; // 제거된 데이터 return
}
public T Peek() // stack의 top 데이터 확인하는 메서드
{
if (top == null)
{
return new();
}
return top.data; // 현재 top의 데이터 반환
}
}
public class DataStructure : MonoBehaviour
{
void Start()
{
StackCustom<int> stack = new StackCustom<int>();
stack.Push(1);
stack.Push(2);
stack.Push(3);
stack.Pop();
Debug.Log(stack.Pop());
Debug.Log(stack.Peek());
}
}
움직이는 코드 짜기
[NonSerialized] // public이지만 인스펙터에 노출 안됨, c# class에서는 접근 가능
public float Speed = 3.0f;
[SerializeField] // private이지만 인스펙터에 노출 됨, c# class에서는 접근 불가
private float Speed2 = 3.0f;
void Update()
{
Vector3 movePos = Vector3.zero;
if (Input.GetKey(KeyCode.W))
{
movePos += transform.forward;
}
if (Input.GetKey(KeyCode.S))
{
movePos -= transform.forward;
}
if (Input.GetKey(KeyCode.A))
{
movePos -= transform.right;
}
if (Input.GetKey(KeyCode.D))
{
movePos += transform.right;
}
transform.position += movePos.normalized * Speed2 * Time.deltaTime;
}
Stack을 이용해 움직임 취소까지 짜기
ex. 오버워치 트레이서의 시간 돌리는 스킬
[NonSerialized] // public이지만 인스펙터에 노출 안됨, c# class에서는 접근 가능
public float Speed = 3.0f;
[SerializeField] // private이지만 인스펙터에 노출 됨, c# class에서는 접근 불가
private float Speed2 = 3.0f;
private Stack<Vector3> position_stack = new Stack<Vector3>();
void Update()
{
// 캐릭터의 이동 방향 저장
Vector3 movePos = Vector3.zero;
if (Input.GetKey(KeyCode.W))
{
movePos += transform.forward;
}
if (Input.GetKey(KeyCode.S))
{
movePos -= transform.forward;
}
if (Input.GetKey(KeyCode.A))
{
movePos -= transform.right;
}
if (Input.GetKey(KeyCode.D))
{
movePos += transform.right;
}
// 이동했던 위치의 기록을 위해 키에서 손을 뗄 때마다 위치 저장
if (Input.GetKeyDown(KeyCode.W) ||
Input.GetKeyDown(KeyCode.S) ||
Input.GetKeyDown(KeyCode.A) ||
Input.GetKeyDown(KeyCode.D))
{
movePos = Vector3.zero; // 이동 위치 기록을 새로 시작
position_stack.Push(transform.position); // 현재 캐릭터의 위치를 스택에 저장
}
// 스페이스바 누르면 이전 위치로 되돌아가는 코드
if (Input.GetKeyDown(KeyCode.Space))
{
if (position_stack.Count > 0) // 스택에 아무것도 없는데 스페이스바 누르면 오류 -> 버그 방지
{
transform.position = position_stack.Pop(); // 스택의 top(가장 마지막에 저장된) 위치 가져오고 삭제
}
}
transform.position += movePos.normalized * Speed2 * Time.deltaTime; // 캐릭터 이동 업데이트
}
괄호 검사
public bool AreBracketBalanced(string expression)
{
Stack<char> stack = new Stack<char>();
foreach (char c in expression)
{
if (c == '(' || c == '[' || c == '{')
{
stack.Push(c);
}
else if (c == ')' || c == ']' || c == '}')
{
if (stack.Count == 0)
return false;
char top = stack.Pop();
if ((c == ')' && top != '(') ||
(c == ']' && top != '[') ||
(c == '}' && top != '{'))
{
return false;
}
}
}
return stack.Count == 0;
}
Unity Editor 메뉴 아이템 만들기
using UnityEditor;
public class ScopeChecker : EditorWindow
{
[MenuItem("Window/Scope Checker")]
public static void ShowWindow()
{
GetWindow<ScopeChecker>("Scope Checker");
}
}
텍스트 input창 추가하기
using UnityEditor;
public class ScopeChecker : EditorWindow
{
private string _text;
[MenuItem("Window/Scope Checker")]
public static void ShowWindow()
{
GetWindow<ScopeChecker>("Scope Checker");
}
// input text 입력란 추가
private void OnGUI()
{
_text = EditorGUILayout.TextField("Text", _text);
}
}
아래처럼 수정할 수도 있음
pixel값을 width랑 height에 준 것
_text = EditorGUILayout.TextField("Text", _text, GUILayout.Width(300), GUILayout.Height(300));
만약 직접적인 값이 없다면 반응형임(창 사이즈에 따라 사이즈 변환)
_text = EditorGUILayout.TextField("Text", _text, GUILayout.Height(300));
아까 작성한 괄호 검사 코드를 넣고 검사 결과에 따라 알림창 띄우기
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class ScopeChecker : EditorWindow
{
private string _text;
[MenuItem("Window/Scope Checker")]
public static void ShowWindow()
{
GetWindow<ScopeChecker>("Scope Checker");
}
private void OnGUI()
{
_text = EditorGUILayout.TextField("Text", _text, GUILayout.Height(300));
// _text = EditorGUILayout.TextField("Text", _text);
// 에디터 상에서 버튼을 누르면 true 반환되어 해당 조건문에 들어감
if (GUILayout.Button("Check Scope"))
{
if (AreBracketBalanced(_text))
{
// 알림창 띄우기
EditorUtility.DisplayDialog("Scope Check", "Scope Check Success", "OK");
}
else
{
EditorUtility.DisplayDialog("Scope Check", "Scope Check Fail", "OK");
}
}
}
public bool AreBracketBalanced(string expression)
{
Stack<char> stack = new Stack<char>();
foreach (char c in expression)
{
if (c == '(' || c == '[' || c == '{')
{
stack.Push(c);
}
else if (c == ')' || c == ']' || c == '}')
{
if (stack.Count == 0)
return false;
char top = stack.Pop();
if ((c == ')' && top != '(') ||
(c == ']' && top != '[') ||
(c == '}' && top != '{'))
{
return false;
}
}
}
return stack.Count == 0;
}
}
잘 뜬다
input창 형식을 TextArea로 바꿔주기
_text = EditorGUILayout.TextArea(_text, GUILayout.Height(300));
그럼 줄바꿈도 들어가는 textarea로 되어 보기 더 편함
isNullOrEmpty로 타입 검사 가능
if (GUILayout.Button("Check Scope") && string.IsNullOrEmpty(_text))
Debug.Assert로 예외 처리
Debug.Assert(false);
GUI 내용물을 가로(or세로)로 정렬하는 법
private void OnGUI()
{
// 여기부터 GUI 내용물을 가로로 정렬
EditorGUILayout.BeginHorizontal();
_text = EditorGUILayout.TextArea(_text, GUILayout.Height(300));
// _text = EditorGUILayout.TextField("Text", _text);
// 에디터 상에서 버튼을 누르면 true 반환되어 해당 조건문에 들어감
if (GUILayout.Button("Check Scope") && string.IsNullOrEmpty(_text))
{
if (AreBracketBalanced(_text))
{
// 알림창 띄우기
EditorUtility.DisplayDialog("Scope Check", "Scope Check Success", "OK");
}
else
{
EditorUtility.DisplayDialog("Scope Check", "Scope Check Fail", "OK");
}
}
// 이 위까지 들어간 GUI 내용물을 가로로 정렬
EditorGUILayout.EndHorizontal();
}
아래처럼 TextArea랑 Button이 가로로 정렬됨
HeaderAttribute를 이용해 Inspector 꾸미기
using UnityEngine;
public class LayoutComponent : MonoBehaviour
{
[Header("Life")]
public string data1;
public string data2;
public string data3;
[Header("Love")]
public string data4;
public string data5;
public string data6;
[Header("Power")]
public string data7;
}
[Header("Life"), Tooltip("인생에 관한 변수입니다")]
public string data1;
[Tooltip("인생에 관한 변수2입니다")]
public string data2;
public string data3;
Range로 슬라이더 넣기
int나 float 가능
[Header("Power"), Range(0.1f, 5f)]
public string data7;
LayoutComponent를 수정하기
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(LayoutComponent))] // LayoutComponent.cs에 선언한 LayoutComponent class를 수정
public class LayoutCompEditor : Editor
{
private SerializedProperty data1Property;
// start()랑 유사하게 Editor가 켜졌을 때 실행됨
private void OnEnable()
{
data1Property = serializedObject.FindProperty("data1"); // 직렬화 : LayoutComponent의 data1 변수를 가져옴
}
// override : 부모에 있는 함수를 재정의
public override void OnInspectorGUI() // 기존에 있던 OnIspectorGUI를 override로 재정의
{
// base.OnInspectorGUI(); // 부모 object에 있는 OnInspectorGUI를 그대로 사용 = LayoutComponent 그대로 뜸
serializedObject.Update(); // data1을 업데이트 해줌
EditorGUILayout.PropertyField(data1Property);
}
}
기타 다양한 Methods
BeginVertical, BeginToggleGroup, EndScrollView 등을 자주 사용
Foldout : 접기 기능 추가
indentLevel++ : depth 추가
public override void OnInspectorGUI() // 기존에 있던 OnIspectorGUI를 override로 재정의
{
// base.OnInspectorGUI(); // 부모 object에 있는 OnInspectorGUI를 그대로 사용 = LayoutComponent 그대로 뜸
serializedObject.Update(); // data1을 업데이트 해줌
foldState = EditorGUILayout.Foldout(foldState, "Layout")
if (foldState)
{
EditorGUILayout.LabelField("Label"); // label 붙이기
EditorGUI.indentLevel++; // depth 주기
EditorGUILayout.PropertyField(data1Property); // 그대로 가져옴
// 이렇게도 가져올 수 있음
data2Property.stringValue = EditorGUILayout.TextField("Data 2", data2Property.stringValue);
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(data3Property); // 그대로 가져옴
EditorGUI.indentLevel--;
EditorGUILayout.PropertyField(data4Property); // 그대로 가져옴
EditorGUILayout.PropertyField(data5Property); // 그대로 가져옴
EditorGUILayout.PropertyField(data6Property); // 그대로 가져옴
EditorGUI.indentLevel--;
}
}
코테
두 수의 나눗셈
이거 하면서 c# 형변환 방법을 알게됨
using System;
public class Solution {
public int solution(int num1, int num2) {
float answer = (num1 / (float)num2) * 1000;
return (int)answer;
}
}
숫자 비교하기
삼항 쓰는건 똑같네 굿
using System;
public class Solution {
public int solution(int num1, int num2) {
return num1 == num2 ? 1 : -1;
}
}
는 분수 덧셈에서 막혀서 정답률 높은 순으로 다시 진행;
이미 이전에 푼 사칙연산까지 8개 풀었길래 각도기 추가로 풀어봄
각도기
각도기 문제도 조건이 정해져 있어서 삼항으로 가능하길래 삼항으로 풀었음
using System;
public class Solution {
public int solution(int angle) {
return angle < 90 ? 1 : angle == 90 ? 2 : angle < 180 ? 3 : 4;
}
}
삼항 처음 쓸 땐 진짜 헷갈렸는데 이제 익숙해지니 안헷갈림
얼른 C#과 Unity에도 익숙해져야만...
'공부 > [TIL] Game Bootcamp' 카테고리의 다른 글
[멋쟁이사자처럼 부트캠프 TIL] 유니티 게임 개발 3기 : 자료구조(Queue), 오브젝트 풀링 등 (1) | 2024.12.06 |
---|---|
[멋쟁이사자처럼 부트캠프 TIL] 유니티 게임 개발 3기 : LINQ (6) | 2024.12.05 |
[멋쟁이사자처럼 부트캠프 TIL] 유니티 게임 개발 3기 : 자료구조(LinkedList) (1) | 2024.12.03 |
[멋쟁이사자처럼 부트캠프 TIL] 유니티 게임 개발 3기 : 라이더 설치, 자료구조 (2) | 2024.12.02 |
[멋쟁이사자처럼 부트캠프 TIL] 유니티 게임 개발 3기 : Flappy Bird 만들기 (2) | 2024.11.29 |