
#20221218 :: 터미널~
#20221219 :: 터미널 노드 체인 연결
#20221220 :: 비동기, 트랜지션 아이디어, 터미널 해결과제
#20221221 :: 터미널 해결과제 수행@@
#20221222 :: 역행노드 버그 해결, 비동기랑 코루틴이랑 기타 등등
#20221218 :: 터미널~
터미널 데이터 구조 변화
기존 : Dictionary<linkNumber, nodeIndex>
변경 후 : Dictionary<linkNumber, Tuple<nodeIndex, linkNumber>>
연결 노드의 링크넘버도 저장하는걸로~
#20221219 :: 터미널 노드 체인 연결
public void TerminalUpdate(){
foreach(var i in this.terminalStatus.Where(n => n.nodeIndex > 0)){
if(Physics2D.Raycast(i.nodePos, Vector3.back)){
Node target = Physics2D.Raycast(i.nodePos, Vector3.back).collider.gameObject.GetComponent<Node>();
if (target.GetType().Name == "StageNode").
{
StageNode stage = (StageNode)target;
int itemIndex = i.linkNode.ContainsKey("InputItem") ? i.linkNode["InputItem"].Item1 : -1; // Item2 == OutputItem
if (itemIndex != -1)
{
if(Physics2D.Raycast(this.terminalStatus[itemIndex].nodePos, Vector3.back)){
stage.leftItem = Physics2D.Raycast(this.terminalStatus[itemIndex].nodePos, Vector3.back)
.collider.gameObject.GetComponent<ItemNode>();
}
else
stage.leftItem = null;
}
else
{
stage.leftItem = null;
}
if (WorldLevelManager.Instance.levelStatus[stage.levelNumber].clearStatus)
{
stage.nextStage.gameObject.SetActive(true);
if (stage.leftItem != null && stage.leftItem.power >= stage.defense)
stage.rightItem.gameObject.SetActive(true);
else
stage.rightItem.gameObject.SetActive(false);
}
else
{
stage.nextStage.gameObject.SetActive(false);
stage.rightItem.gameObject.SetActive(false);
}
}
}
}
}
1. 노드 위치 변경하고 연결 재설정했을 때 연결을 잘 못 찾아가는 버그 있음.
⇒ 아마 레이캐스팅에 실패한 듯? 노드 위치가 잘 저장되는지 확인해 봐야겠음.
⇒ 혹은 SetActive가 안되어 있어서 레이캐스팅이 넘어가 버린 걸 지도(이 경우 D 눌러서 갱신하면 다시 생김)
2. 색깔 변경하고 싶음. 지금 뭔가 크리스마스트리 같음..;;
3. 연결 끊었을 때 나머지 연결 노드들도 끊어지는 연출? 애니메이션 추가하자
#20221220 :: 비동기, 트랜지션 아이디어, 터미널 해결과제
문제 상황
터미널 갱신을 언제 하면 좋을까?
해답
1. 씬 로드 시 비동기 처리
유니티 AsyncOperation과 비동기 장면 전환
안녕하세요. 창작자 픽케입니다. 게임 애플리케이션은 다양한 장면(Scene)들의 흐름(Flow)으로 구성되고,...
blog.naver.com
public void LoadTerminal(){
StartCoroutine(CouroutineForLoadTerminal());
}
private IEnumerator CouroutineForLoadTerminal(){
AsyncOperation asyncOper = SceneManager.LoadSceneAsync("TerminalScene"); // 비동기 처리
while(!asyncOper.isDone){
yield return null;
}
// 씬로드 완료시 터미널업데이트 실행
TerminalUpdate();
// 암전처리
// 트랜지션
}
2. 연결 갱신 시
API : 기본적으로 제공해 주는 문법 ex) C의 printf 같은 거
터미널 해결과제
- 노드 SetActive(false) 상태로 백그라운드 움직이면 false 상태인 객체는 nodePos 업데이트 안 함;;
- 노드를 SetActive(false)로 만들지 말기 → 그러면 연결 어떻게 구현?
- 활성화되지 않은 노드는 빨간색으로 만들기, 혹은 자물쇠 잠금
→ 상태변화를 만들어서 연결 해제 구현
→ 다른 노드의 할당을 방지하기 위해서 언젠간 추가하긴 해야 됨
- 활성화되지 않은 노드는 빨간색으로 만들기, 혹은 자물쇠 잠금
- 배경 말고 카메라를 움직이는 걸로 바꾸기 → 이러면 해결됨 ㅇㅇ
- 노드를 SetActive(false)로 만들지 말기 → 그러면 연결 어떻게 구현?
- 노드 사라지고 생겨나는 애니메이션 작동 중, 연결 시도하면 버그 발생.
- 애니메이션 도중에는 카메라 이동 말고는 아무것도 못하게 하기
- 노드 클릭 시 color 바꾸기!
- 노드 클릭하면 노드 연결 흐름 시각화 (유니티처럼, 잘 모르겠으면 아래 사진 참고 ㄱㄱ)
5. Math노드 구현
6. Skill노드 구현
7. 맵 확대 축소 기능 : 카메라 이동으로 바꾸면 구현가능
8. 미니맵 : 카메라 이동으로 바꾸면 구현가능
9. 노드 다중선택
트랜지션 아이디어
추가 아이디어
스테이지 노드 숫자(출력아이템 개수) → 변환 노드 (스테이지를 아이템으로) → 조합노드
→ 곱하기 노드 → 복사노드 ⇒ 출력을 숫자만큼
#20221221 :: 터미널 해결과제 수행@@
터미널 해결과제(해결완료는 초록색, 하는 중은 노란색)
- 노드 SetActive(false) 상태로 백그라운드 움직이면 false 상태인 객체는 nodePos 업데이트 안 함;;
- 노드를 SetActive(false)로 만들지 말기 → 그러면 연결 어떻게 구현?
- 활성화되지 않은 노드는 빨간색으로 만들기, 혹은 자물쇠 잠금
→ 상태변화를 만들어서 연결 해제 구현
→ 다른 노드의 할당을 방지하기 위해서 언젠간 추가하긴 해야 됨
- 활성화되지 않은 노드는 빨간색으로 만들기, 혹은 자물쇠 잠금
- 배경 말고 카메라를 움직이는 걸로 바꾸기 → 이러면 해결됨 ㅇㅇ
- 노드를 SetActive(false)로 만들지 말기 → 그러면 연결 어떻게 구현?
- 노드 사라지고 생겨나는 애니메이션 작동 중, 연결 시도하면 버그 발생.
- 애니메이션 도중에는 카메라 이동 말고는 아무것도 못하게 하기 ⇒ 로딩바 추가
- 노드 클릭 시 color 바꾸기!
- 노드 클릭하면 노드 연결 흐름 시각화 (유니티처럼)
- Math노드 구현
- Skill노드 구현
- 맵 확대 축소 기능 : 카메라 이동으로 바꾸면 구현가능
미니맵 : 카메라 이동으로 바꾸면 구현가능노드 다중선택
Lock
꺼진 상태 → 그대로는 생략가능
- left 아이템 null
- right 켜진 상태 → 락 걸기
- right 꺼진 상태 → 그대로
- left 아이템 null X
- left 아이템 lock
- right 켜진 상태 → 락 걸기
- right 꺼진 상태 → 그대로
- left 아이템 lock X
- left 아이템 공격력 만족
- right 켜진 상태
- right 락 상태 → 락 풀기
- right 꺼진 상태
- ⇒ 켜기
- right 락 상태 → 락 풀기
- right 켜진 상태
- left 아이템 공격력 만족
- left 아이템 lock
-
-
- 불만족
- right 꺼진 상태 → 그대로
- 불만족
-
if(WorldLevelManager.Instance.levelStatus[stage.levelNumber].clearStatus == 아이템써서 클리어){
if(stage.leftItem == null){
//stage.rightItem = 1. 안보여 2. 락
if(stage.rightItem.gameObject.activeSelf){ // 락이 되거라
stage.rightItem.isLock = true;
// 락 거는 애니메이션
stage.rightItem.OffAnimation();
yield return new WaitUntil(() => stage.rightItem.isAnimationEnd);
}
}
else{ //레프트아이템 null 이 아닌 상태 : 1. 보여, 2. 락
if(stage.leftItem.isLock){
//stage.rightItem = 1. 안보여 2. 락
if(stage.rightItem.gameObject.activeSelf){ // 락이 되거라
stage.rightItem.isLock = true;
// 락 걸리는 애니메이션
stage.rightItem.OffAnimation();
yield return new WaitUntil(() => stage.rightItem.isAnimationEnd);
}
}else if(stage.leftItem.power >= stage.defnse){ // 라이트 보여주거나, 락을 풀거라
if(stage.rightItem.isLock){ // 락 걸린 상태
stage.rightItem.isLock = false;
// 락 풀리는 애니메이션
stage.rightItem.OnAnimation();
yield return new WaitUntil(() => stage.rightItem.isAnimationEnd);
}else{
stage.rightItem.gameObject.SetActive(true);
yield return new WaitUntil(() => stage.rightItem.gameObject.activeSelf); // 비동기 처리
// 아이템 생기는 애니메이션
stage.rightItem.OnAnimation();
yield return new WaitUntil(() => stage.rightItem.isAnimationEnd);
}
}
}
}
Chat GPT의 정리
코드는 스테이지 클리어 여부를 판단하는 if문으로 시작합니다. 만약 스테이지 클리어를 위해 아이템을 사용해야 하는 상황이라면, 레프트 아이템이 없는 경우와 있는 경우로 나뉩니다.
레프트 아이템이 없는 경우엔, 라이트 아이템을 락하는 등의 처리가 이루어집니다. 라이트 아이템이 이미 락되어 있는 상태이면, 라이트 아이템을 락하는 애니메이션이 실행됩니다. 라이트 아이템이 락이 되지 않은 상태이면, 라이트 아이템을 활성화하고 아이템이 활성화되는 애니메이션을 실행합니다.
레프트 아이템이 있는 경우엔, 레프트 아이템이 락되어 있는지, 혹은 라이트 아이템을 보여줘야 하는지에 따라 다른 처리가 이루어집니다. 레프트 아이템이 락되어 있으면, 라이트 아이템을 락하는 애니메이션이 실행됩니다. 레프트 아이템이 락되어 있지 않고, 라이트 아이템의 파워가 방어력보다 높으면, 라이트 아이템을 보여주는 애니메이션을 실행합니다. 만약 라이트 아이템이 이미 활성화된 상태라면, 라이트 아이템을 락하는 애니메이션을 실행합니다.
코드에서 사용된 yield return new WaitUntil(() => stage.rightItem.isAnimationEnd);는 해당 코드가 실행되는 동안, stage.rightItem.isAnimationEnd가 참이 될 때까지 대기하게 됩니다.
문제 상황
노드 연결 역행이 가능
그러나 씬을 로드할 경우 모든 노드들이 false인 상태에서
노드 갱신은 인덱스 1부터 시작하므로
역행 노드의 경우는 오류가 발생
따라서 시스템에서 버그를 없애려면
방법1
- 먼저 노드를 전부 다 켜놓고
- 끌 노드를 선택해서 끄기
- 로딩 끝 이후 플레이
방법2
- 역행 노드를 없애기 (자신보다 작은 인덱스에 접근 방지) ⇒ 근데 이러면 나중에 조합노드를 사용 못함…
- ⇒ 그러면 스테이지 노드에 한해서만 역행노드 금지.
추가 버그 발생 : 씬 로드 안 해도 역행노드 인식을 잘 못함;;
가운데 노드는 레프트가 없는데도 활성화되어있음 (버그)
이경우 한 번 더 노드 갱신을 해야 적용됨;;
따라서 그냥 역행노드를 없애야 할 듯;
방법3 => 채택
- 스테이지 : 인덱스 작은 아이템 / 아이템 : 인덱스 작은 스테이지로 구분해서 노드 갱신
- 노드 갱신 - 스테이지 노드 갱신
- 이전노드(자신보다 작은 인덱스) 아이템만 갱신 및 참조
3. 인덱스 큰 아이템은 아이템 노드 갱신에서 갱신할 것!
4. 노드 갱신 - 아이템 노드 갱신
5. 이전 노드(자신보다 작은 인덱스) 스테이지 갱신 다시 한번 확인 ⇒ 아이템 link를 통해서 노드인덱스 구하기
6. 스테이지 left Item != null 인경우 이미 연결 갱신한 상태이므로 넘어가기
7. null 상태인 경우 아이템 연결되어 있는지 확인 후 갱신
역행만 문제발생함.
다했는데도 버그 생겨 ㅠㅠㅠ
버그 1 (다음날 해결됨)
이 상태로 씬 리로드하면 버그남;;
근데 이때 노드 재갱신하면 다시 생김;;
뭐임??? 두 번째 레벨만 저런 버그 나는데????
⇒ 해결완료~ (레벨넘버가 이상했었음)~~
안 고쳐짐 ~~~~ 이번엔 사진상태로 세 번째 레벨 들어갔다 왔더니 버그발생
⇒ yield return에 문제 있는 거 같음
⇒ 항상 이러지는 않는다는 게 개빡침 망할 비동기
백그라운드 Awake에서 터미널 갱신 실행하기아이템1, 스테이지1 도 첫 시작엔 setActive false 해버리기
버그2 (해결됨)
if (output.input.output != null)
{ // input 한개당 output 한개만 연결(하나의 input에 연결 여러개 금지!)
Debug.Log("이미 있지롱");
output.target = output.start;
output.BezierLine();
output.input = null; // 무조건 null로 만들기 **중요!
this.output = null;
}
인풋에 추가함(빼먹은 나의 실수^^)
** 위치 수정 if ⇒ else if 로(밑에꺼 먼저 체크해야 됐음 ㅇㅅㅇ)
#20221222 :: 역행노드 버그 해결, 비동기랑 코루틴이랑 기타 등등
코루틴 제어법
[유니티 매뉴얼] 코루틴(CoRoutine)
1. 코루틴 일반 함수를 호출하면 값을 반환하기 전에 실행 완료됩니다. 이는 함수에서 수행되는 모든 액션이 하나의 프레임 업데이트 내에서 발생해야 한다는 것을 의미합니다. 시간이 지남에
coderzero.tistory.com
1. 코루틴을 아예 처음부터 다시 시작하고 싶다. (yield return을 무시하고 진짜 쌩처음)
코루틴을 여러번 호출할때의 처리 (코루틴 변수로 제어)
1234567891011121314151617181920212223242526272829303132333435363738394041424344using System.C...
blog.naver.com
if(runningCoroutine != null)
StopCoroutine(runningCoroutine);
runningCoroutine = StartCoroutine(FadeToZero(zoomText)); // **코루틴은 1개만 돌리도록 할것. 안하면 막 글자 사라지는 버그남
⇒ 재할당 하면 된다. (기존의 코루틴은 멈추고 새로운 코루틴이 덮어씌워진다.)
비동기 버그(해결됨)
[Unity] MonoBehaviour 총정리 및 생명주기(Lifecycle)
1. 모노 (Mono) .Net은 마이크로 소프트(MicroSoft)에서 C언어에 자바의 장점을 수용하여 개발한 MS Windows 프로그램 개발 및 실행 환경이자 언어이다. 네트워크와 UI 등의 많은 작업을 캡슐화 하여 코딩
skuld2000.tistory.com
[Unity] Physics.Raycast 완벽 가이드
들어가며 Unity의 Physics.Raycast는 직선을 씬에 투영하여 대상에 적중되면 true를 리턴하는 물리 함수다. Raycast 함수는 캐스팅 성공 실패에 따른 결과만 리턴하는 간단한 형태에서 부터 대상과 Ray의
kukuta.tistory.com
- 역행 노드(아이템) 레이캐스팅 실패 이슈.
- 아마 절묘하게 노드가 setActive 하는 사이에 그 노드를 레이캐스팅해 버려서(못 찾아서) 그런 걸로 추정..
- setActive 아래 별의별 yield return 사용해 봄
1. yield return new WaitUntil(() => stage.rightItem.gameObject.activeSelf);
// 완전한 setActive를 체크하면 되지 않을까? 응 실패
2. yield return new WaitUntil(() => stage.rightItem.GetComponent<BoxCollider2D>().enabled);
// 레이캐스팅은 콜라이더와 충돌하니까 콜라이더를 체크하면 되지 않을까? 왜 실패..
3. yield return new WaitUntil(() => stage.rightItem.transform.postion
== terminalStatus[stage.rightItem.nodeIndex].nodePos);
// start 함수에서 위치 재설정을 하니까 위치가 정확해질때까지 기다려볼까? 응 실패
4. yield return null;
// 한프레임만으로는 걍 실패
5. yield return new WaitForEndOfFrame();
// 너도 짧다 이녀석아
6. yield return new WaitForSeconds(1.5f);
// 얘는 성공... 따라서 레이캐스팅은 충분한 시간이 주어진다면 가능함.. 근데 1.5초는 너무 김.
4. 6번만 성공했는데 실제로 사용하기엔 너무 좀 아님;;
5. 결론
- 스테이지 노드 갱신 중
- 스테이지의 left가 역행노드인지 판별한다 (인덱스 구별 : 스테이지 < 아이템)
- 역행노드가 있다면 resetCount++
- 아이템 노드 갱신 중
- 아이템이 역행노드인지 판별한다 (인덱스 구별 : 스테이지 < 아이템)
- 역행노드라면 resetCount- -
- resetCount>0이라면 노드 갱신을 다시 시작한다.
이렇게 하면 레이캐스팅에 실패해서 노드갱신을 빼먹더라도
갱신을 할 때까지 (레이캐스팅에 성공할 때까지) 코드를 반복 실행한다.
…
레이캐스팅 리소스 많이 잡아먹을 텐데.. 이게 최선?? ㅠㅠ
'개인 프로젝트 > Node Princess' 카테고리의 다른 글
Node Princess :: 개발일지 #10 - BGM 스케치 (0) | 2024.02.16 |
---|---|
Node Princess :: 개발일지 #9 - 터미널 구현 (4) (0) | 2024.02.16 |
Node Princess :: 개발일지 #7 - A* 패스파인딩 (0) | 2024.02.16 |
Node Princess :: 개발일지 #6 - 캐릭터 컨셉 (0) | 2024.02.16 |
Node Princess :: 개발일지 #5 - 터미널 구현 (2) (1) | 2024.02.16 |
틀린 부분은 언제든지 말씀해주세요!!! 감사합니다!