Command 패턴으로 Undo, Redo 만들기
아래 코드에는 버그가 있음 : if (Input.GetKeyDown(KeyCode.W) || Input.GetKeyDown(KeyCode.D || ~ 이 조건문은 키 두개 이상 동시 입력하는 상황을 충족하지 못함
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface ICommand
{
void Execute();
void Undo();
}
public class CommandManager : MonoBehaviour
{
private Stack<ICommand> undoStack = new Stack<ICommand>();
private Stack<ICommand> redoStack = new Stack<ICommand>();
public void ExecuteCommand(ICommand command)
{
// 커맨드 객체의 execute를 실행한다.
command.Execute();
// 언두했을 때 command의 undo를 호출하기 위해 undo stack에 넣는다.
undoStack.Push(command);
// executeCommand가 호출 되면 가장 최신의 작업을 한 것이므로 redoStack은 비운다.
redoStack.Clear();
}
public void Undo()
{
if (undoStack.Count > 0)
{
// 가장 최근에 실행 된 커멘드를 가져와서
ICommand command = undoStack.Pop();
// Undo시킨다.
command.Undo();
// 그리고 다시 redo 할수 있기 때문에 redoStack에 넣는다.
redoStack.Push(command);
}
}
public void Redo()
{
if (redoStack.Count > 0)
{
// 가장 최근에 언두 된 커맨드를 가져와서
ICommand command = redoStack.Pop();
// Execute해준다.
command.Execute();
// 그리고 다시 Undo할수 있도록 undoStack에 넣어준다.
undoStack.Push(command);
}
}
public float Speed = 3.0f;
public float RotateSpeed = 3.0f;
// Update is called once per frame
void Update()
{
Vector3 movePos = Vector3.zero;
Vector3 deltaRot = 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.GetKey(KeyCode.R))
{
deltaRot += transform.right * (Time.deltaTime * RotateSpeed);
}
if (Input.GetKey(KeyCode.Q))
{
deltaRot -= transform.right * (Time.deltaTime * RotateSpeed);
}
// 움직였던 정보를 기록하기 위해 키를 뗄 때마다 위치를 기록한다.
if (Input.GetKeyDown(KeyCode.W) ||
Input.GetKeyDown(KeyCode.S) ||
Input.GetKeyDown(KeyCode.A) ||
Input.GetKeyDown(KeyCode.D))
{
var moveCommand = new MoveCommand(transform, transform.position);
ExecuteCommand(moveCommand);
}
if (Input.GetKeyDown(KeyCode.Q) ||
Input.GetKeyDown(KeyCode.R))
{
Quaternion newRotation = transform.rotation;
var rotateCommand = new RotateCommand(transform, newRotation);
ExecuteCommand(rotateCommand);
}
// 왔던 포지션으로 되돌아가는 코드
if (Input.GetKeyDown(KeyCode.Space))
{
}
Vector3 addtivePosition = movePos.normalized * Speed * Time.deltaTime;
transform.position += addtivePosition;
transform.rotation = Quaternion.LookRotation(transform.forward + deltaRot, Vector3.up); ;
}
}
public class MoveCommand : ICommand
{
private Transform _transform;
private Vector3 _oldPosition;
private Vector3 _newPosition;
public MoveCommand(Transform transform, Vector3 newPosition)
{
// 이동하려는 트랜스폼 객체를 참조한다.
_transform = transform;
// 언두할때 돌아갈 포지션을 저장한다.
_oldPosition = _transform.position;
// execute시에 셋팅될 포지션 값을 저장한다.
_newPosition = newPosition;
}
public void Execute()
{
// newPosition으로 갱신힌다.
_transform.position = _newPosition;
}
public void Undo()
{
// oldPosition으로 undo한다.
_transform.position = _oldPosition;
}
}
public class RotateCommand : ICommand
{
private Transform _transform;
private Quaternion _oldRotation;
private Quaternion _newRotation;
public RotateCommand(Transform transform, Quaternion newRotation)
{
// 이동하려는 트랜스폼 객체를 참조한다.
_transform = transform;
// 언두할때 돌아갈 회전값을 저장한다.
_oldRotation = _transform.rotation;
// execute시에 셋팅될 회전 값을 저장한다.
_newRotation = newRotation;
}
public void Execute()
{
// newPosition으로 갱신힌다.
_transform.rotation = _newRotation;
}
public void Undo()
{
// oldPosition으로 undo한다.
_transform.rotation = _oldRotation;
}
}
버그 수정한 코드
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface ICommand
{
void Execute();
void Undo();
}
public class CommandManager : MonoBehaviour
{
private Stack<ICommand> undoStack = new Stack<ICommand>();
private Stack<ICommand> redoStack = new Stack<ICommand>();
public void ExecuteCommand(ICommand command)
{
// 커맨드 객체의 execute를 실행한다.
command.Execute();
// 언두했을 때 command의 undo를 호출하기 위해 undo stack에 넣는다.
undoStack.Push(command);
// executeCommand가 호출 되면 가장 최신의 작업을 한 것이므로 redoStack은 비운다.
redoStack.Clear();
}
public void Undo()
{
if (undoStack.Count > 0)
{
// 가장 최근에 실행 된 커멘드를 가져와서
ICommand command = undoStack.Pop();
// Undo시킨다.
command.Undo();
// 그리고 다시 redo 할수 있기 때문에 redoStack에 넣는다.
redoStack.Push(command);
}
}
public void Redo()
{
if (redoStack.Count > 0)
{
// 가장 최근에 언두 된 커맨드를 가져와서
ICommand command = redoStack.Pop();
// Execute해준다.
command.Execute();
// 그리고 다시 Undo할수 있도록 undoStack에 넣어준다.
undoStack.Push(command);
}
}
// CommandManager의 update 함수 교안에 적용됨
public float Speed = 3.0f;
public float RotateSpeed = 3.0f;
public Vector3 MoveDelta = Vector3.zero;
public Vector3 RotateDelta = Vector3.zero;
private bool prevMoved = false;
// Update is called once per frame
void Update()
{
Vector3 movePos = Vector3.zero;
Vector3 deltaRot = 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.GetKey(KeyCode.R))
{
deltaRot += transform.right * (Time.deltaTime * RotateSpeed);
}
if (Input.GetKey(KeyCode.Q))
{
deltaRot -= transform.right * (Time.deltaTime * RotateSpeed);
}
Vector3 addtivePosition = movePos.normalized * Speed * Time.deltaTime;
// 움직였던 정보를 기록하기 위해 키를 땔때마다 위치를 기록한다.
if (movePos == Vector3.zero && MoveDelta != Vector3.zero)
{
var moveCommand = new MoveCommand(transform, transform.position - MoveDelta);
ExecuteCommand(moveCommand);
MoveDelta = Vector3.zero;
return;
}
if (deltaRot == Vector3.zero && RotateDelta != Vector3.zero)
{
var rotateCommand = new RotateCommand(transform, Quaternion.LookRotation(transform.forward - RotateDelta, Vector3.up));
ExecuteCommand(rotateCommand);
RotateDelta = Vector3.zero;
return;
}
// 왔던 포지션으로 되돌아가는 코드
if (Input.GetKeyDown(KeyCode.Space))
{
Undo();
return;
}
transform.position += addtivePosition;
transform.rotation = Quaternion.LookRotation(transform.forward + deltaRot, Vector3.up);
MoveDelta += addtivePosition;
RotateDelta += deltaRot;
}
}
public class MoveCommand : ICommand
{
private Transform _transform;
private Vector3 _oldPosition;
private Vector3 _newPosition;
public MoveCommand(Transform transform, Vector3 rollbackPosition)
{
// 이동하려는 트랜스폼 객체를 참조한다.
_transform = transform;
// 언두할때 돌아갈 포지션을 저장한다.
_oldPosition = rollbackPosition;
// execute시에 셋팅될 포지션 값을 저장한다.
_newPosition = transform.position;
}
public void Execute()
{
// newPosition으로 갱신힌다.
_transform.position = _newPosition;
}
public void Undo()
{
// oldPosition으로 undo한다.
_transform.position = _oldPosition;
}
}
public class RotateCommand : ICommand
{
private Transform _transform;
private Quaternion _oldRotation;
private Quaternion _newRotation;
public RotateCommand(Transform transform, Quaternion rollbackRotation)
{
// 이동하려는 트랜스폼 객체를 참조한다.
_transform = transform;
// 언두할때 돌아갈 회전값을 저장한다.
_oldRotation = rollbackRotation;
// execute시에 셋팅될 회전 값을 저장한다.
_newRotation = _transform.rotation;
}
public void Execute()
{
// newPosition으로 갱신힌다.
_transform.rotation = _newRotation;
}
public void Undo()
{
// oldPosition으로 undo한다.
_transform.rotation = _oldRotation;
}
}
LINQ (Language Integrated Query)
C#에서 데이터 쿼리 및 조작을 위한 강력한 기능
Unity 게임 개발에서 LINQ를 사용하여 코드를 더 간결하고 효율적으로 만들 수 있음
LINQ 없이 기능 구현
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public struct MonsterTest
{
public string name;
public int health;
}
public class LinqExample : MonoBehaviour
{
public List<MonsterTest> monsters = new List<MonsterTest>()
{
new MonsterTest() { name = "A", health = 100 },
new MonsterTest() { name = "A", health = 30 },
new MonsterTest() { name = "B", health = 100 },
new MonsterTest() { name = "B", health = 30 },
new MonsterTest() { name = "C", health = 100 },
new MonsterTest() { name = "C", health = 30 },
};
void Start()
{
List<MonsterTest> filters = new List<MonsterTest>();
// 몬스터 테스트 그룹에서 A 네임을 가진 hp 30 이상의 오브젝트들을 리스트화해서 체력 높은 순으로 출력
for (var i = 0; i < monsters.Count; i++)
{
if (monsters[i].name == "A" && monsters[i].health >= 30)
{
filters.Add(monsters[i]);
}
}
filters.Sort((e, r) => e.health >= r.health ? -1 : 1);
for (var i = 0; i < filters.Count; i++)
{
Debug.Log($"name: {filters[i].name}, health: {filters[i].health}");
}
}
}
LINQ로 구현
함수형 LINQ
var linqFilter = monsters.Select(e => e).
Where(e => e.name == "A" && e.health >= 30).
OrderByDescending(e => e.health).ToList();
for (var i = 0; i < linqFilter.Count; i++)
{
Debug.Log($"name: {linqFilter[i].name}, health: {linqFilter[i].health}");
}
둘의 출력값이 똑같은 것을 알 수 있음
쿼리를 예약어로 쓸 수도 있음
// 다른 방법 : LINQ 확장 메서드
var linqFilter2 = (
from e in monsters
where e is {name: "A", health: >= 30}
orderby e.health
descending
select e
// select new { e.name, e.health } // 해당 요소만 가져오기
).ToList();
for (var i = 0; i < linqFilter2.Count; i++)
{
Debug.Log($"name: {linqFilter2[i].name}, health: {linqFilter2[i].health}");
}
얘 또한 출력값 동일함
C# 튜플
js의 오브젝트와 비슷
여러 가지 데이터를 묶어서 한 번에 저장할 수 있는 작은 상자
이 상자는 여러 칸으로 나누어져 있고, 각 칸마다 다른 값을 넣을 수 있음
튜플을 왜 쓸까?
만약 게임에서 "이름"과 "점수"를 한꺼번에 저장하고 싶다고 해봐요.
보통은 변수 2개를 만들어야 해요:
string playerName = "Alice";
int score = 100;
튜플 만드는 방법
(string, int) playerInfo = ("Alice", 100);
- ("Alice", 100) → 이게 바로 튜플
- 첫 번째 칸: 이름 "Alice"
- 두 번째 칸: 점수 100
튜플 사용하기
// 1번 방식: item1 ~ item8까지 꺼낼 수 있음
(string, int) playerInfo = ("Alice", 100);
Console.WriteLine(playerInfo.Item1); // 첫 번째 칸: "Alice"
Console.WriteLine(playerInfo.Item2); // 두 번째 칸: 100
// 2번 방식 : 네이밍 가능
(string name, int score) playerInfo = ("Alice", 100);
Console.WriteLine(playerInfo.name); // "Alice"
Console.WriteLine(playerInfo.score); // 100
게임시간 30초동안 hp가 가장 높은 몬스터 찾기
일단 30초를 세어야 하는데 두가지 방법이 있음
- 코루틴 사용
- update 사용
코루틴 사용
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
public float battleTime = 30.0f;
// 코루틴 메서드 선언
IEnumerator BattlerTimer()
{
while (battleTime >= 0.0f)
{
yield return new WaitForSeconds(1.0f); // 1초 대기 (Unity가 1초 쉬고 다시 실행)
battleTime -= 1.0f; // 1초씩 차감
}
}
void Start()
{
// 코루틴 시작 => Unity에서 게임 시작되면 코루틴 함수 호출
StartCoroutine(BattlerTimer());
}
}
코루틴에는 다양한 리턴이 있음
Update 사용
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
// 코루틴 사용 안할 때
public float _stepBattleDuration = 0.0f;
void Update()
{
if (0 >= battleTime)
return;
if (_stepBattleDuration >= 1.0f)
{
Debug.Log(battleTime.ToString());
battleTime -= 1.0f;
_stepBattleDuration = 0.0f;
}
_stepBattleDuration += Time.deltaTime;
}
}
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
public class EnemyManager : MonoBehaviour
{
public List<GameObject> enemies;
void Start()
{
// 체력이 50 이하인 적들만 필터링
var lowHealthEnemies = enemies.Where(e => e.GetComponent<Enemy>().health <= 50);
// 적들을 체력 순으로 정렬
var sortedEnemies = enemies.OrderBy(e => e.GetComponent<Enemy>().health);
// 적들의 평균 체력 계산
float averageHealth = enemies.Average(e => e.GetComponent<Enemy>().health);
// 결과 출력
Debug.Log($"Low health enemies count: {lowHealthEnemies.Count()}");
Debug.Log($"First enemy health after sorting: {sortedEnemies.First().GetComponent<Enemy>().health}");
Debug.Log($"Average enemy health: {averageHealth}");
}
}
경주
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Random = UnityEngine.Random;
[Serializable]
public class PlayerData
{
public string playerName;
[NonSerialized]
public float Distance;
}
public class GameManager : MonoBehaviour
{
public float battleTime = 30.0f;
public List<PlayerData> Players = new List<PlayerData>();
// 코루틴 메서드 선언
IEnumerator BattlerTimer()
{
while (battleTime >= 0.0f)
{
yield return new WaitForSeconds(1.0f); // 1초 대기 (Unity가 1초 쉬고 다시 실행)
foreach (var playerData in Players)
{
playerData.Distance += Random.Range(0.0f, 1.0f);
}
var ranks = (from p in Players orderby p.Distance select p).ToList ();
for (var i = 0; i < ranks.Count; i++)
{
Debug.Log($"Rank {i+1} : {ranks[i].playerName} / distance : {ranks[i].Distance}");
}
battleTime -= 1.0f; // 1초씩 차감
}
}
void Start()
{
// 코루틴 시작 => Unity에서 게임 시작되면 코루틴 함수 호출
StartCoroutine(BattlerTimer());
}
}
화면 만들기
Import 해주면 추가되었다고 메세지 뜨면서 리소스 추가됨
UI/Image 추가해서 버튼 잘 보이게 해주고
버튼 사이즈 조절
한글 폰트 지원을 위해 한글 폰트 추가
참고
[Unity] UGUI TextMeshPro 한글 폰트 추가하기
UGUI 한글 입력 문제를 해결하기위해 TextMeshPro로 텍스트를 변경하고 한글을 입력했더니 한글이 안나오는 이슈가 있었다. 이유는 셋팅된 폰트에 한글이 없기 때문이었고, 한글폰트를 추가해주기
cho22.tistory.com
해당 폰트 사용
Panel에 Vertical Layout Group 넣고 Middle Center로 설정해준 뒤, 사이즈 조정하고 버튼 복제 => 정렬됨
해당 체크하면 자식들의 사이즈가 부모를 벗어나지 않음
버튼 나머지 다 지우고 RaceButton 스크립트 추가
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class RaceButton : MonoBehaviour
{
public TMP_Text text;
}
GameManager.cs 수정
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using Random = UnityEngine.Random;
[Serializable]
public class PlayerData
{
public string playerName;
[NonSerialized]
public float Distance;
}
public class GameManager : MonoBehaviour
{
public float battleTime = 30.0f;
// 경마에 참여할 플레이어 리스트
public List<PlayerData> Players = new List<PlayerData>();
// ui에 표현될 버튼 프리팹
public RaceButton templateButton;
// 버튼들이 붙을 부모 오브젝트
public Transform RaceButtonParent;
// 생성된 버튼들 관리
private List<RaceButton> raceButtons = new List<RaceButton>();
// 코루틴 메서드 선언
IEnumerator BattlerTimer()
{
for (var i = 0; i < Players.Count; i++)
{
// 오브젝트 생성하기
var newObj = Instantiate(templateButton.gameObject, RaceButtonParent);
// RaceButton 컴포넌트 캐싱
raceButtons.Add(newObj.GetComponent<RaceButton>());
}
while (battleTime >= 0.0f)
{
yield return new WaitForSeconds(1.0f); // 1초 대기 (Unity가 1초 쉬고 다시 실행)
foreach (var playerData in Players)
{
playerData.Distance += Random.Range(0.0f, 1.0f);
}
var ranks = (from p in Players orderby p.Distance descending select p).ToList ();
for (var i = 0; i < ranks.Count; i++)
{
Debug.Log($"Rank {i+1} : {ranks[i].playerName} / distance : {ranks[i].Distance}");
raceButtons[i].text.text = ranks[i].playerName;
}
battleTime -= 1.0f; // 1초씩 차감
}
}
void Start()
{
// 코루틴 시작 => Unity에서 게임 시작되면 코루틴 함수 호출
StartCoroutine(BattlerTimer());
}
}
하고 나서 유니티 에디터 가서 Template Button, Race Button Parent에 각각 RaceButton Prefab, Panel 바인딩 해주면 끝
결과물
에러
버튼에 스크립트 추가하는데 다음과 같은 에러가 발생함
스크립트명이 다르지도 않아서 당황하다가 질문하면서 유니티 껐다 키니까 SafeMode로 키라고 뜸
엥? 하고 키니 GameManager.cs의 Button 템플릿에 에러가 있었음
질문에 친절한 답변들도 많이 달렸는데 이렇게 다른 스크립트에서 문법 오류가 나면 컴파일이 되지 않아 오류가 날 수 있다! 라는 사실을 알게 됨
굿
Can't add script component 'RaceButton' because the script class cannot be found. Make sure that there are no compile errors and that the file name and class name match.
움직임 추가
// GameManager.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;
using Random = UnityEngine.Random;
using Vector3 = System.Numerics.Vector3;
[Serializable] // 이 클래스는 Unity의 Inspector에서 표시될 수 있음.
public class PlayerData
{
public string playerName; // 플레이어 이름
[NonSerialized] public float Distance; // 플레이어가 이동한 거리 (저장되지 않음)
[NonSerialized] public int Rank; // 현재 플레이어의 순위 (저장되지 않음)
[NonSerialized] public RaceButton RaceButton; // 플레이어와 연결된 UI 버튼
}
public class GameManager : MonoBehaviour
{
public float battleTime = 30.0f; // 경기가 진행되는 총 시간
public List<PlayerData> Players = new List<PlayerData>(); // 경기에 참여하는 플레이어 데이터 목록
public RaceButton templateButton; // 버튼 프리팹 (UI의 템플릿)
public Transform RaceButtonParent; // 버튼들이 배치될 부모 오브젝트(UI 컨테이너)
// 특정 플레이어의 UI 버튼을 순위에 따라 새로운 위치로 이동시키는 코루틴
IEnumerator GoToNextPosition(PlayerData pd, int newRank, Vector2 newPosition)
{
pd.Rank = newRank; // 플레이어의 새로운 순위를 업데이트
pd.RaceButton.text.text = $"{pd.playerName} / {pd.Distance.ToString("0.00") + " km"}"; // UI 텍스트 업데이트
RectTransform target = pd.RaceButton.rect; // 이동할 UI 버튼의 RectTransform 참조
float time = 0.0f;
const float lerpTime = 0.3f; // 이동에 걸릴 시간
Vector2 initPosition = target.anchoredPosition; // 현재 위치 저장
// 지정된 시간 동안 초기 위치에서 새 위치로 이동
while (lerpTime >= time)
{
target.anchoredPosition = Vector2.Lerp(initPosition, newPosition, time / lerpTime); // 위치 보간
time += Time.deltaTime;
yield return null; // 한 프레임 쉬고 다시 실행
}
target.anchoredPosition = newPosition; // 최종 위치 설정
}
// 경기 타이머를 관리하고 각 플레이어의 상태를 업데이트하는 코루틴
IEnumerator BattlerTimer()
{
List<Vector2> ui_positions = new List<Vector2>(); // UI 버튼의 초기 위치를 저장
for (var i = 0; i < Players.Count; i++)
{
// UI 버튼을 생성하고 RaceButton 컴포넌트를 가져옴
var newObj = Instantiate(templateButton.gameObject, RaceButtonParent);
RaceButton raceButton = newObj.GetComponent<RaceButton>();
raceButton.text.text = Players[i].playerName; // 버튼 텍스트에 플레이어 이름 설정
Players[i].RaceButton = raceButton; // 생성한 버튼을 플레이어 데이터에 연결
Players[i].Rank = i; // 초기 순위 설정
}
yield return null; // 한 프레임 대기
// 생성된 UI 버튼들의 초기 위치를 저장
for (var i = 0; i < Players.Count; i++)
{
ui_positions.Add(Players[i].RaceButton.rect.anchoredPosition);
}
// 버튼 배치를 고정하기 위해 VerticalLayoutGroup 비활성화
RaceButtonParent.GetComponent<VerticalLayoutGroup>().enabled = false;
// 경기 시간이 남아있는 동안 반복
while (battleTime >= 0.0f)
{
Debug.Log(battleTime); // 남은 시간 디버그 출력
yield return new WaitForSeconds(1.0f); // 1초 대기
// 모든 플레이어의 이동 거리를 무작위로 증가
foreach (var playerData in Players)
{
playerData.Distance += Random.Range(0.0f, 1.0f);
Debug.Log(playerData.Distance);
}
// 이동 거리 기준으로 플레이어를 내림차순 정렬
var ranks = (from p in Players orderby p.Distance descending select p).ToList();
// 정렬된 순위에 따라 UI 버튼 위치를 업데이트
for (var i = 0; i < ranks.Count; i++)
{
StartCoroutine(GoToNextPosition(ranks[i], i, ui_positions[i]));
}
battleTime -= 1.0f; // 경기 시간을 1초 줄임
}
}
void Start()
{
StartCoroutine(BattlerTimer()); // 경기 타이머 코루틴 시작
}
private float _stepBattleDuration = 1.0f; // 경기 단계의 시간 (현재 사용되지 않음)
}
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
// RaceButton 클래스는 UI 버튼을 관리하는 컴포넌트
public class RaceButton : MonoBehaviour
{
public TMP_Text text; // 버튼에 표시되는 텍스트
public RectTransform rect; // 버튼의 위치와 크기를 관리하는 RectTransform
public Button clickButton; // 버튼 클릭 이벤트를 처리하는 Button
private void Awake()
{
// RectTransform과 Button 컴포넌트를 초기화
rect = GetComponent<RectTransform>();
clickButton = GetComponent<Button>();
}
}
'공부 > [TIL] Game Bootcamp' 카테고리의 다른 글
[멋쟁이사자처럼 부트캠프 TIL] 유니티 게임 개발 3기 : 정렬 (0) | 2024.12.11 |
---|---|
[멋쟁이사자처럼 부트캠프 TIL] 유니티 게임 개발 3기 : 자료구조(Queue), 오브젝트 풀링 등 (1) | 2024.12.06 |
[멋쟁이사자처럼 부트캠프 TIL] 유니티 게임 개발 3기 : 자료구조(Stack) (2) | 2024.12.04 |
[멋쟁이사자처럼 부트캠프 TIL] 유니티 게임 개발 3기 : 자료구조(LinkedList) (1) | 2024.12.03 |
[멋쟁이사자처럼 부트캠프 TIL] 유니티 게임 개발 3기 : 라이더 설치, 자료구조 (2) | 2024.12.02 |