경작 5일차 c++ 헤더 / 유니티랑 싸우기

한정화·2023년 2월 1일
0

#230201 수

뭐지? 거대한 코딩 세계관에 갇힌 npc가 된 것만 같아.. 알고리즘 하다가 빡치면 unity 하러 가고 unity 하다가 빡치면 c++ 하러 가고 c++ 하다가 빡치면 js.. 그만! ㅋㅋ그만 말해도 될 것 같다. 어쨌든 프로그래밍된 npc도 이렇게 하진 않을 거ㅇ
왜 이렇게 오프닝부터 화가 나있냐면 오늘은 유니티 PlayerPrefs로 승률 통계를 만드는 벨로그를 쓰려고 했는데 고작 ui button 비활성화에서 헤매서 3시간만에 강종했기 때문이다. 승률 통계 근처도 못 감 (유니티 너 내일까지 나한테 말 걸면 진짜 싸움나는 거야 너 조심해라) 그래도 오늘 깨달은 게 있다면 하이러키뷰 오브젝트를 refer하는 type을 모르겠으면 Edit Script를 통해 확인할 수 있다는 점이었다.

내가 확인하고 싶은 건

NickNameSaveButton = GameObject.Find("NickNameSave")<GetComponent>(Type);

에서 TMP button의 type이 TMP_Button인지 Button인지 button인지 버튼(아님)인지.. 확인하기 위함이었는데

하여튼 옆에 있는 점 세 개를 누르고 Edit Script를 누르면

이렇게 오브젝트 script가 뜨고

타입을 확인할 수 있다.

namespace UnityEngine.UI;

라는 것은 이 오브젝트를 refer하기 위해선 코드에

using UnityEngine.UI;

가 있어야 한다는 뜻이고,

public class Button : ...

는 이 버튼의 type이 Button이라는 것이다.
그래서 나는 코드를

public Button NicknameSaveButton;

..(생략)..

NicknameSaveButton = GameObject.Find("NicknameSave").GetComponent<Button>();
NicknameSaveButton.gameObject.SetActive(false);

로 짜서 오류를 해결할 수 있었다.

잠깐 유니티 얘기를 해보자면

void Start(){
        if(!PlayerPrefs.HasKey("USER_ID")){
            userId = PlayerPrefs.GetString("USER_ID", $"User {Random.Range(1,3)}");
            if(userId!=null && userIF!=null){
                userIF.text = userId;
            }
            PhotonNetwork.NickName = userId;
        }
        else{
            NicknameSaveButton = GameObject.Find("NicknameSave").GetComponent<Button>();
            NicknameSaveButton.gameObject.SetActive(false);
            userId = PlayerPrefs.GetString("USER_ID");
            PhotonNetwork.NickName = userId;
        }
    }

내가 하고 싶었던 것은 기존에 저장된 닉네임(userId)이 없으면 받아서 저장하고

if(!PlayerPrefs.HasKey("USER_ID")){
	userId = PlayerPrefs.GetString ~ 
}

저장된 닉네임이 이미 있으면 닉네임 저장 버튼을 화면에서 없애고(비활성화)

else{
	NicknameSaveButton.GameObject.SetActive(false);
}

기존 닉네임을 불러와 띄우는 것

userId = PlayerPrefs.GetString("USER_ID");

이었다. 그런데 이번엔 다른 쪽에서 오류가 나서 내가 잘 만든 건지는 확인할 길이 없게 되었다..

다른 쪽 오류는

Operation JoinLobby (229) not called because client is not connected or not ready yet, client state: JoiningLobby

이거였는데, 솔직히 말하면 진짜 왜 그런지 모르겠다. 내가 이해한 바로는 이미 로비에 있는 클라이언트를 다시 로비에 입장하라고 명령해서 오류가 났다는 것인데, ....왜죠? 왜 제가 로비 입장하라고 하지도 않았는데 먼저 들어가셨죠 클라이언트씨(아님)? 혹은 JoinLobby씨는 왜 제가 한 번밖에 호출 안 했는데 실행이 두 번 돼서 오류를 내는 것이죠? 진짜 모르겠다 혹시 틀렸나 해서 unity 책이랑도 비교해보고 인터넷에도 쳐보고 해봤는데 왜 이러는지 전혀 모르겠음 그냥.. 미래의 내가 알아서 하겠지 싶다. 이 친구로 내가 1시간이나 날려먹었다는 사실을 믿을 수가 없다. 난 바본가봐..

그나저나 나 진짜 벨로그 체질 아닐까..?(흘러나오는 destiny ost) 분명 c++ 얘기하려고 켰는데 유니티 얘기를 이렇게 길게 하다니 대박 역시 어릴 때 작가가 되고 싶었던 나다워. 이렇게 끊임없이 글을 쓸 수 있는 것도 솔직히 능력인 것 같은데 글솜씨만 좋았어도 진짜 작가가 될 수 있지 않았을까


좀만 더 날 두면 코딩과 관련 없는 얘기로 한바닥을 채울 것 같아서 그냥 수평선을 그어버렸다. 이제 끝~ 진짜 c++ 얘기를 하겠어

농장주님(not god)께서 동방에서 책을 꺼내시길래 안 받으려고 친구 뒤에 숨어있었는데 쥐뿔도 안 통했다. 아마 내가 숨으려고 했다는 것도 모르셨을 듯. 하여튼 <열혈 c++ 프로그래밍> 책을 선물로 빌려주셨다.

지금 공부하고 있던 <명품 c++ programming>에서 아직 하지 않은 파트는 상속, 했지만 설렁설렁 공부한 파트는 복사 생성자헤더 파일이라서 이 셋을 중심적으로 보기로 했다. 할 땐 연산자 중복이 제일 어렵긴 했는데 (friend, static과 포인터와 오버로딩이 다 섞이면 파이썬으로 코딩을 시작했던 뉴비에겐 대환장 파티가 되는 것이다) 빡세게 공부했었으니까 괜찮지 않을까? 시간 남으면 연산자 중복도 다시 공부해보고 아니면.. 말고ㅎ


1. 헤더 파일

내가 c를 공부할 때도, c++를 공부할 때도 가장 연습을 적게 한 것이 헤더 파일과 소스파일 분리인 것 같다. c를 공부할 때 딱 한 챕터에서만 시키길래 그렇게 해보고 그 다음부터는 귀찮아서 안 했다. 때마침 그런 나를 저격하는 문장이 43쪽에 있길래

c++를 제대로 공부하려면 다음의 내용을 잘 알고 있어야 한다.
-헤더 파일의 의미와 정의 방법
-헤더 파일에 삽입할 내용과 소스파일에 삽입할 내용을 구분하는 방법
-둘 이상의 헤더파일과 소스파일을 만들어서 하나의 실행파일로 컴파일하는 방법
이와 관련해서 전혀 감이 없다면, C언어 기본서를 참조하여 이 부분을 복습하기 바라며, ...

와 난 저 세 가지 중에 마지막을 해봤다는 것을 제외하고는 아무것도 아는 게 없었다. 하지만 c언어 기본서는 나에게 없으므로 어쩔 수 없이 검색해서 알아보도록 하자. thank you google!

1) 헤더 파일의 의미와 정의 방법
헤더 파일은 공통으로 사용되는 함수, 클래스, 명령어를 미리 선언한 별도의 파일이다. c++의 경우 #include <라이브러리.h>로 헤더 파일을 선언한다.

2) 헤더 파일에 삽입할 내용과 소스파일에 삽입할 내용을 구분하는 방법
헤더 파일에는 함수의 선언부, 소스 파일에는 함수의 정의가 삽입된다.

3) 둘 이상의 헤더파일과 소스파일을 만들어서 하나의 실행방법으로 컴파일하는 방법
헤더 파일 - 함수 선언 삽입
소스 파일1 - 함수 정의 삽입 (구현)
소스 파일2 - #include<라이브러리.h>, main 함수 삽입

그러면 이제 주어진 문제를 풀어보자. 다음을 헤더파일과 소스파일로 분리하면 된다.

#include <iostream>
 
namespace BestComImpl{
        void SimpleFunc(void);
}
 
namespace ProgComImpl{
        void SimpleFunc(void);
}
 
int main(void){
        BestComImpl::SimpleFunc();
        ProgComImpl::SimpleFunc();
        return 0;
}
 
void BestComImpl::SimpleFunc(void){
        std::cout <<"BestCom이 정의한 함수"<< std::endl;
}
 
void ProgComImpl::SimpleFunc(void){
        std::cout<<"ProgCom이 정의한 함수"<<std::endl;
}

내 코드:

예전에 명품 c++에서 공부할 땐 중복 컴파일 방지를 위해서
#ifndef HEADER (만약 선언되지 않았으면) / (의미 선언되어있다면)
#define HEADER (선언)

#endif (여기까지 header의 내용 실행) / (여기까지 무시)
을 써서 main.cpp에서 헤더 파일이 두 번째 읽힐 때부터 #define을 통해 무시되어 중복선언을 막았던 것으로 기억한다. 그런데 비스에서 헤더파일을 만드니까 #pragma once가 자동생성되어있길래 그냥 그걸 썼다. 차이를 찾아보니 pragma once는 한 번 다른 파일에서 include 되면 다시 읽지 않는 방식을 택한다고 한다. 그래서 pragma once가 더 빠르다는데 나는 인간이라 그 차이를 느끼지 못하겠다

문제가 누구나 헤더파일과 소스파일을 분리할 수 있게 되어있어서 굉장히 쉬웠다


2. 복사 생성자

는 내일 써보도록 하자..

0개의 댓글