2024년 1월 31일 수요일
Unity - DefaultExecutionOrder
2024년 1월 29일 월요일
2024년 1월 24일 수요일
Unity - Random.Range
UnityEngine.Random 클래스
유니티에서 난수를 생성하려고 할 때 사용하는 클래스이며
범위가 Int형일 경우에는 0, 1, ...이런식으로 소숫점 부분은 날려버리고
Float 형일 때는 소숫점 7번째 자리까지 리턴한다.
Float형은 최대범위 까지 포함하여 리턴하므로 주의해야 한다.
float 형인지 int 형인지 구분하기 위해서
평소에 float형이면 .0f까지 붙이는 습관을 기르는 것이 좋다고 생각한다.
2024년 1월 22일 월요일
Unity - 모바일 safeArea
핸드폰 기종마다 다르지만 아이폰 13처럼 카메라가
화면을 가리는 경우가 가끔 있다.
유니티를 모바일 게임으로 배포하게 될 경우
처리해줘야 한다.
Screen.safeArea로 카메라 쪽 가리는 공간의 크기를 구할 수 있다.
m_topSpace = Screen.safeArea.height / Screen.height
safeArea 높이를 원래 해상도 높이로 나누어 비율을 구하고
이를 월드내 오브젝트의 위치를 옮겨주면 된다.
2024년 1월 18일 목요일
Unity - 미로 게임
미로 생성을 위한 코드는 여기서 가져옴
[유니티] 절차적 생성을 위한 미로 생성 알고리즘 2 (velog.io)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | using System.Collections.Generic; using UnityEngine; using static UnityEditor.PlayerSettings; public class MazeRunner : MonoBehaviour { [SerializeField] private DragToMoveController m_controller; [SerializeField] private GameObject m_wall;//미로 안쪽 벽의 프리펩 private bool[,] m_map; private int m_mazeWidth = 11;//벽까지 포함한 크기 private int m_mazeHeight = 17;//벽까지 포함한 크기 private Vector2Int m_pos = Vector2Int.zero; private Vector2Int[] m_direction = { Vector2Int.up, Vector2Int.down, Vector2Int.left, Vector2Int.right }; private Stack<Vector2Int> m_stackDir = new Stack<Vector2Int>(); //지나온 길의 방향 저장 private float m_timer = 0.0f;//타이머 private void Start() { m_timer = 10.0f; m_controller.SetMoveSpeed(6.0f); m_map = new bool[m_mazeWidth, m_mazeHeight];//미로 크기 9x9 m_pos = new Vector2Int(1, 1); for (int x = 0; x < m_mazeWidth; x++) { for (int y = 0; y < m_mazeHeight; y++) { m_map[x, y] = true; //모든 타일을 벽으로 채움 } } BuildMaze(); //벽 배치 for (int x = 1; x < m_mazeWidth-1; x++) { for (int y = 1; y < m_mazeHeight-1; y++) { if (m_map[x, y]) { GameObject obj = Instantiate(m_wall, transform.GetChild(1)); obj.transform.position = new Vector3(0.8f * x-4, 0.8f, 0.8f * y-6.8f); } } } } // Update is called once per frame private void FixedUpdate() { m_timer -= Time.deltaTime; m_controller.UpdateMove(); } private void BuildMaze() { do { int index = -1; //-1은 갈 수 있는 길이 없음을 의미 RandDirection(); //방향 무작위로 섞음 for (int i = 0; i < m_direction.Length; i++) { if (CheckWall(i)) { index = i; //선택한 방향에 길이 없을 경우 방향 배열의 인덱스 저장 break; } } if (index != -1) //갈 수 있는 길이 있을 경우 { for (int i = 0; i < 2; i++) //길과 길 사이에 벽을 생성하기 위해 3칸을 길로 바꿈 { m_stackDir.Push(m_direction[index]); //스택에 방향 저장 m_pos += m_direction[index]; //위치 변수 수정 m_map[m_pos.x, m_pos.y] = false; //타일 생성 } } else //갈 수 있는 길이 없을 경우 { for (int i = 0; i < 2; i++) //길을 만들 때 3칸을 만들었기 때문에 뒤로 돌아갈 때도 3칸 이동 { m_map[m_pos.x, m_pos.y] = false; //완성된 길 의미 m_pos += m_stackDir.Pop() * -1; //방향을 저장하는 스택에서 데이터를 꺼낸뒤 -1을 곱해 방향 반전 } } } while (m_stackDir.Count != 0); //스택이 0이라는 것은 모든 길을 순회했다는 것을 의미하므로 반복문 종료 } private void RandDirection() //무작위로 방향을 섞는 메소드 { for (int i = 0; i < m_direction.Length; i++) { int randNum = Random.Range(0, m_direction.Length); //4방향 중 무작위로 방향 선택 Vector2Int temp = m_direction[randNum]; //현재 인덱스에 해당하는 방향과 랜덤으로 선택한 방향을 서로 바꿈 m_direction[randNum] = m_direction[i]; m_direction[i] = temp; } } private bool CheckWall(int index) { if ((m_pos + m_direction[index] * 2).x > m_mazeWidth - 2) return false; //2를 곱하는 이유는 길과 길 사이에 벽이 있기 때문 if ((m_pos + m_direction[index] * 2).x < 0) return false; if ((m_pos + m_direction[index] * 2).y > m_mazeHeight - 2) return false; if ((m_pos + m_direction[index] * 2).y < 0) return false; if (!m_map[(m_pos + m_direction[index] * 2).x, (m_pos + m_direction[index] * 2).y]) return false; return true; } private void OnTriggerEnter(Collider other) { if (other.tag == "Player") Debug.LogFormat("GameClear in {0}sec", m_timer); } } | cs |
bool 배열에 미로를 설계하고 이것에 맞춰서
벽 프리펩을 Instantiate 구현해준다.
가끔 막히는 경우가 있다. 이럴 땐
m_map[x, y] = false; 특정 위치의 벽을 없애면 그만이다.
2024년 1월 17일 수요일
Unity - 오브젝트 크기를 화면 해상도로 맞추기
사진에서 플레이 버튼을 누르게 되면
가로 방향의 Collider는 화면 밖에 있기 때문에
화면 밖으로 굴러가게 된다.
이를 방지하려면 어떻게 해야 할까
Collider를 위치를 움직여서 화면 밖으로 나가지 못하게 하면 된다.
하지만 모바일 게임 같은 경우 기종에 따라 화면 크기가 제 각각이라
현재 해상도를 가져와서 이를 World Space로 변환 해주고 가로 길이 만큼
위치를 변경해주면 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | using UnityEngine; class WallCollisions : MonoBehaviour { [Header("Wall Collisions")] public GameObject m_left; public GameObject m_right; private float m_camSize = 10.0f; //테스트용 private void Start() { SetWalls(); } public void SetOrthographicSize(Camera camera) { m_camSize = camera.orthographicSize; } //사방면의 벽을 화면 크기에 맞춰서 옮기는 함수 public void SetWalls() { float aspect = (float)Screen.width / Screen.height; float worldWidth = m_camSize * aspect; m_left.transform.position = new Vector3(-worldWidth, 0, 0); m_right.transform.position = new Vector3(worldWidth, 0, 0); } } | cs |
2024년 1월 14일 일요일
Unity - 캐릭터 이동 (Velocity)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | using Unity.VisualScripting; using UnityEngine; public class JumpRopeGame : MonoBehaviour { private Rigidbody m_rigidbody; private float m_speed = 3.0f;//이동 속도 private float m_jumpPower = 300.0f;//점프 거리 private bool m_readyJump;//점프가능한 상태인지 확인하는 변수 private bool m_rayHitted;//레이캐스트 hit한 물체가 있는지 확인하는 변수 private void Start() { m_rigidbody = GetComponent<Rigidbody>(); } private void Update() { float dis = 0.0f; {//땅과의 거리 측정 Ray ray = new Ray(transform.position, Vector3.down);//캐릭터 위치에서 y -1방향으로 레이 생성 RaycastHit hit; if (Physics.Raycast(ray, out hit)) dis = ray.origin.y - hit.point.y; } if (dis < 0.51f) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); Vector3 hitpos; RaycastHit hit; m_rayHitted = Physics.Raycast(ray, out hit); if (m_rayHitted && TouchManager.instance.IsBegan())//처음 터치한 대상이 플레이어일 때 점프가능한 상태로 만들기 {//점프 가능한 상태일 때는 플레이어 이동이 안됨 m_readyJump = hit.transform.tag == "Player" ? true : false; } if (m_readyJump && !TouchManager.instance.IsHolding())//점프 준비 상태에서 손을 땟을 때 { if (TouchManager.instance.IsDragUp())//위로 드래그 했을 경우 { m_readyJump = false;//준비 상태 해제 m_rigidbody.AddForce(new Vector3(0, m_jumpPower, 0));//위로 AddForce } } if (m_rayHitted && TouchManager.instance.IsHolding() && !m_readyJump)//터치 누르고 있는 상태일 때 & 점프 준비 상태가 아닐 때 { if (hit.transform.tag == "Terrain") { hitpos = hit.point; } else { hitpos = transform.position; } hitpos = hitpos - transform.position; hitpos.y = 0; m_rigidbody.velocity = hitpos.normalized * m_speed; } } } } | cs |
결과
추가로 Rigidbody를 사용하여 이동시킬 때
Rigidbody와 Character Controller를 동시에 추가하면 안됨
2024년 1월 10일 수요일
2024년 1월 4일 목요일
Unity Tutorial - Input System
일반적으로 Input.GetKey() 함수등으로 입력을 받아와서
그에 따른 행동을 하거나 값을 변경하여 캐릭터를 이동하거나
점프시켰는데 이번에는 Input System으로 구현해보려고 한다.
(주의! 자동으로 껏다 켜짐)
캐릭터를 이동시켜야하는데 이는 캐릭터 오브젝트에 Input Action을 끌어다 놓으면 된다.
버튼 이벤트처럼 동작된 Action에 해당하는 함수를 호출하는 방식인데
이는 불필요한 함수 호출을 줄일 수 있어서 좋다
전달받은 Vector2 값을 변수에 저장하여 이를 캐릭터의 Transform Position이나
Character Controller로 이동 시키면 된다.
이를 InputSystem으로 교체해야 한다.
Unity Tutorial - Animation Blend Tree
캐릭터가 움직일 때, 앞으로 가는 모션과 옆으로 갈 때는 움직이는 방향에 맞춰서
애니메이션을 지정하면 된다.
그런데 대각선으로 이동할때 해당 방향에 맞는 모션이 없으면 어떻게 할까
이를 위해 블랜드 트리를 사용하여 앞으로 가는 모션과 옆으로가는 모션을
블랜드 하여 대각선으로 가는 모션을 만들 수 있다.
우클릭해서 블랜드 트리 생성
블랜드 트리 내에서 애니메이션을 변수에 맞춰서 애니메이션을 전환해주는데
파라미터 타입은 Float만 된다. 다른 타입은 파라미터로 지정이 안됨
캐릭터가 움직이고 있는 방향을 디그리로 바꿔서
SetFloat함수로 Animator로 전달
아래쪽의 Automate Thresholds를 체크 해제 후
애니메이션들을 끌어다 놓는다.
원하는 파라미터를 지정하고 Threshold칸에 어떤 값일 때
애니메이션이 전환이 될지 적는다.
각 애니메이션 마다 프레임 길이가 다르므로 재생속도도 설정
(왼쪽 걷기 모션 안보여서 둘다 오른쪽으로 해둠)
결과
캐릭터가 이상하게 이동될땐 Animator 컴포넌트에서 Root
c++ thread.h
c++에서 쓰레드 돌릴려면 thread.h 헤더를 쓰면 되는데 이 친구는 쓰레드가 아직 실행 중인지, 아니면 강제 종료하거나 하는 함수가 없어서 조금 아쉬운 애다. std::thread 는 로컬 변수로 선언하든 new 동적 할당을 하든 start 함...
-
c++ 소켓은 winsock2로 구현할 수 있는데 자바의 소켓이랑은 많이 달랐음 클라이언트에서 데이터 보내기 및 받기 - Win32 apps | Microsoft Learn 예시 코드로는 ms 설명서에 제대로 나와있기는 한데 일단 winsock.h 과...
-
https://www.figma.com/ 이번 팀 과제에서는 피그마 사이트를 활용하여 회의를 진행했다. 회의에서 정한 프로젝트 주제는 서바이벌 게임으로 발헤임이나 마크같이 건축과 자원캐기 등 생존에 필요한 기능들을 구현하고 게임 컨셉과 스토리, ...
-
c++에서 쓰레드 돌릴려면 thread.h 헤더를 쓰면 되는데 이 친구는 쓰레드가 아직 실행 중인지, 아니면 강제 종료하거나 하는 함수가 없어서 조금 아쉬운 애다. std::thread 는 로컬 변수로 선언하든 new 동적 할당을 하든 start 함...