전체 글 (100)

  • 2021.11.01
  • 2021.11.01
  • 2021.10.28
  • 2021.10.28
  • 2021.10.28
  • 2021.10.28
  • 2021.10.28
  • 2021.10.28
  • 2021.10.28
  • 2021.10.28
  • 2021.10.28
  • 2021.10.28
  • 11
    01

    COMMENT
     
    11
    01

    숫자 0~9 : 48~57

    영문 대문자 : 65~90

    영문 소문자 : 97~122

    COMMENT
     
    10
    28

    특정 문자 탐색

    find(탐색 문자열) // 인덱스를 준다.

    '.' 위치를 알아내는 함수를 만들고 있는데

    만약에. 이 없다면 이상한 숫자를 주는 것이다.

    이는 없으면 -1을 리턴해줄 거라 생각했는데

    위치를 벗어나서 다른 부분을 참조하는지 높은 숫자가 나오는 것이다..

    아래 if문처럼 이런 식으로 방지 할 수 있다.

     

    String 생성 방법

    std::string str="str";

    //std::string str("str2");

    //std::string *pstr=new string("string3");

    //delete pstr;

    //return;

    string 크기

    크기는 size와 length 함수로 알 수가 있다.

    같은 역할을 하지만 전 자바에서 length를 써와서

    length를 선호합니다.

    문자열 비교

    '==', '!=', '<', '>' 등등 우리가 아는 그 비교를 할 수 있다

    참고로 A가 65 소문자 a가 97이다. 아스키코드 기준으로 비교 가능

    특정 문자 빼오기

    배열처럼 인덱스 사용하거나

    at(위치 인덱스),front(),back() 쓰면 알 수 있다.

    글자 추가

    +, += 연산자 오버 로딩이 되어 있어서 추가 가능

    중간에 삽입은 insert(추가 위치, 문자열) 하면 된다.

    append(추가할 양, 문자할 문자)도 있다.

     

    COMMENT
     
    10
    28

     

    3D 프로그래밍 수학에서 중요한 것은 벡터의 내적이다.

    벡터의 내적은 왜 사용할까..?

     

    1. 두 벡터의 사이각을 구하기 위해

    2. 두 벡터를 분해해 수직 및 평행한 벡터를 얻기 위해

    3. 두 벡터가 가리키는 방향의 차이를 알기 위해 사용한다.

     

    벡터의 외적은 두 벡터의 직교인 벡터를 구할 수 있다.

     

    내적과 외적은 벡터를 마치 수처럼 곱한다는 개념이다.

    결과로는 내적은  스칼라 값의 결과, 외적은 벡터값의 결과이다.

    위 공식처럼 각 성분을 곱해서 더하는 것이다. 결과값은 스칼라이다.

     

    만일 ab가 = 0 직교, ab > 0 면 각도는 예각, ab < 0 면 각도는 둔각

    예를 들어 u(1,2,3)v(-4,0,-1)일때 둘의 내적은

    (1*-4)+(2*0)+(3*-1)=-7 이니 0보다 작으니까 둘 사이는 둔각이다.

     

    정규화된 벡터 ab라면 cos만 남게되면.

    ab 직각을 이루고 있다면 내적값은 0이 되고

    다른 방향을 보고 있다면 내적값은 -1이되고

    같은 방향을 보고 있다면 내적값은 1이 된다.

    이는 게임에서는 내적을 이용해 같은 곳을 바라보는지 다른 방향을 바라보는지 유추 가능하다.

    내적으로 사이각을 구하는 방법은

    코사인 식을 활용해서 도출한다. 벡터의 길이 분의 내적인 공식이다. 

    벡터의 길이는 피타고라스의 정리를 사용한다. 

    그러면 코사인 세타값을 얻고 arccos이나 cos-1 함수를 사용해

    알고 있는 코사인 세타 값으로 각을 구할 수 있다.

     

    아래는 함수로 구현한 것이다.

    float AngleFromCosine( D3DXVECTOR2& p1, D3DXVECTOR2& p2 )
    {
    	// a^2 = b^2 + c^2 - 2b cos A
    	return acos( (p1.x * p2.x + p1.y * p2.y) / (D3DXVec2Length( &p1 ) * D3DXVec2Length( &p2 )) );
    }

     

    이는 빛의 강도 조명연산, 쉐도우 연산에 적용될수 있다.

     

    -------------------------

     

    외적은 마찬가지로 곱하지만 결과값은 벡터이다.

    외적은 두 벡터에 서로 직교하는 벡터를 반환한다.

    따라서 면을 이루는 벡터를 이용해 직교하는 벡터 즉,

    면의 법선벡터를 구하는데에 사용할 수 있다.

     

    교환법칙이 성립하지 않기 때문에 교환할경우 방향이 바뀐다.

     

    교환법칙이 성립하지않는 예시)

    x=(2,1,3) y=(2,0,0) 일때 아래 공식을 적용하면

    x X y 는 (0,6,-2)이고 y X x 는 (0,-6,2)  가 나온다.

     

     

     

    COMMENT
     
    10
    28

    https://docs.microsoft.com/ko-kr/windows/uwp/graphics-concepts/graphics-pipeline

     

    그래픽 파이프라인 - UWP applications

    Direct3D 그래픽 파이프라인은 실시간 게임 애플리케이션용 그래픽을 생성하도록 설계되었습니다. 데이터는 각각의 구성 가능하거나 프로그래밍 가능한 각 단계를 통해 입력에서 출력으로 흐릅

    docs.microsoft.com

    윈도우

    윈도우 시스템의 모든 애플리케이션은

    메시지(또는 이벤트)를 기반으로 구동된다.

    윈도우 프로그래밍은 애플리케이션에서 사용자가 발생시키는

    메시지에 대한 처리 "루틴"을 만들어 주는 것이라고 할 수 있다.

    윈도우는 WinMain() 함수의 원형을 쓰는데 전형적으로

    1. 윈도우 클래스 생성

    2. 윈도우 클래스 등록

    3. 윈도우 생성

    4. 윈도우 화면에 표시

    5. 메시지 큐로 메시지 받아 윈도우 프로시저로 보냄

    윈도우 창은 앞의 루틴으로 진행된다.

     

    DirectX11

    다이렉트X는 그래픽카드에 직접 명령하는 API로 빠른 처리가 가능하다.

    아래는 다렉 파이프라인이다. 이 파이프라인을 타고 게임이 뿌려진다.

    IA user-filled buffer로부터 원시 데이터를 읽어들여 그 후 파이프라인 단계에서 사용될 primitive types(line list, triangle strips 등등)데이터로 assemble하는 역할을 수행한다.
    VS input assembler 단계를 통과한 vertices들을 처리하는 단계. transformation, skinning, morphing, and per-vertex lighting과 같은 작업을 수행.
    vertex shader는 단일 input vertex을 받고 output으로 단일 vertex를 출력한다.
    HS 다이렉트11은 테셀레이션(GPU에서 low-detail subdivision surface를 higher-detail primitves로 바꾸는)을 구현하기위한 3가지의 새로운 단계를 support합니다. Hull shader, tesselator, domain shader 단계가 그것입니다.
    TS 도메인(quad, tri or line)을 더 많은 작은 오브젝트(triangles, points or lines)로 잘게 나누는 작업을 수행한다.
    DS 잘게 나누어진 포인트의 vertex position를 계산하는 단계.
    GS 정점을 input으로 받아 application-specified 쉐이더를 적용하고 생성된 정점들을 출력한다.
    버텍스 쉐이더와는 다르게 기하쉐이더는 입력으로 full primitive의 정점을 받는다. 기하쉐이더는 edge 인접 원시 데이터들을 입력을 받을 수 있다.
    SO 기하 쉐이더단계(또는 정점쉐이더 단계)에서 메모리에 있는 하나 이상의 버퍼로 정점 데이터를 연속적으로 출력하는 단계. 메모리에 출력된 데이터들은 pipeline에서 다시 읽어들일 수 있다.
    RS vector 정보를 레스터 이미지(픽셀)로 변환하는 단계.
    PS 픽셀 라이팅이나 post-processing과 같은 쉐이딩을 가능하게하는 단계.
    OM 최종출력되는 픽셀의 색상을 생성한다. depth/stencil를 수행하여 실제로 렌더링여부를 결정하고 최종색상을 blend 한다.

    윈도우를 생성하고 DirectX를 활용하기위해

    스왑체인, 렌더타겟 뷰, 뷰포트세팅,

    디바이스/디바이스컨텍스트 객체 생성 등의 작업이 필요하다.

     

     

    COMMENT
     
    10
    28

    깃허브는 100MB 넘는 파일을 올리지 못한다.

    그래서 LFS를 사용해 파일을 분할해서 올린다.

     

    git lfs 설정

    git lfs install

     

    git lfs 해제

    git lfs uninstall

     

    git lfs 관리할 파일 추적 (그 파일 처음 lfs 타깃 하면 1번 생략)

    1. git rm --cached <file path>

    2. git lfs track <file path>

    "file path" 쌍따옴표

    git .gitattributes 등록

     

    git add .gitattributes

    git commit -m "update gitattributes for lfs"

    git push

     

    커밋 하면 된다.

    //

    LFS File 관리 해제

     

    git lfs untrack <file>

    (또는. gitattributes에서 수동으로 삭제 후)

     

    git rm --cached <file>

    git add <file>

     

    위는 예시

    아무것도 몰라도 이것만 따라치면

    100MB 파일 헤매지않고 보낼수 있을것이다.

    ㅜㅜ고생하지말자

     

    +해프닝

     

    근데 오늘 커밋 하려는데 Git Warning: LF will be replaced by CRLF가 엄청 많이 뜨는 것이다.

     

    구글에 검색하니까 이걸 cmd에 쳐보라는 것이다.

    git config --global core.autocrlf false

     

    해결되었다.

     

    'Github' 카테고리의 다른 글

    Azure Dev Ops 사용  (0) 2022.05.03
    COMMENT
     
    10
    28

    유니티에서 플레이어의 주화, 아이템, HP 등, 사용자가 수정하면 안되는 것을

    Json으로 저장하고 이를 읽을 수 없는 파일로 변환하면 보안을 유지할 수 있다.

     

    반면에 PlayerPrefs는 보안이 취약해 해상도나 음소거등 설정, 즉 수정을 해도

    게임에 별 상관없는 것들을 주로 한다.

     

    1. Json

    [System.Serializable]
    public class Serialization<T>
    {
        public Serialization(List<T> _target)=> target = _target;
        public List<T> target;
    }
    
    public class DataManager : MonoBehaviour
    {
        public TextAsset ItemDatabase;
        public List<Item> AllItemList;
        string filePath;
        
            private void Start()        
            {   
             // Load();
             //txt 파일을 읽어옴. 엑셀 파일로 작성되었음 text 클래스으로 한줄 한줄 잘라냄
            string[] line = ItemDatabase.text.Substring(0, ItemDatabase.text.Length-1).Split('\n');
            for (int i = 0; i < line.Length; i++)
            {
                line[i] = line[i].Trim(); //이거 추가
                string[] row = line[i].Split('\t');
                AllItemList.Add(new Item(row[0], row[1], row[2], row[3]));
            }
            filePath = Application.persistentDataPath + "/allitemdata.txt";
            }
            
          void Save()
        {
            
            string jdata = JsonUtility.ToJson(new Serialization<Item>(AllItemList));
            File.WriteAllText(filePath, jdata);
        }
         void Load()
        {
            //if(!File.Exists(filePath)) {ResetItemClick(); return; }
    
            string jdata = File.ReadAllText(filePath);
            AllItemList=JsonUtility.FromJson<Serialization<Item>>(jdata).target;
        }
    }

    위는 Json를 이용한 DB 구축에 쓰인 코드이다.

     

    엑셀파일로 작성된것을 TXT 뽑고 유니티에 넣는다.

     

    그리고 그것 text 클래스로 한줄 한줄 잘라내서 자료구조 리스트에 담는다.

     

    리스트에 담은 것을 JsonUtility 유니티 제공 클래스로 Json화해서 읽고 불러오는 것이다.

     

    2. PlayerPrefs

     

    PlayerPrefs

    안드로이드 개발할때 sharedpreference인가 키값에

    저장하는 함수가 있는데 유사하다. 

    유니티에서 보니까 또 반갑다.

     

    Static Functions

    DeleteAll preference에서 모든 key와 값들을 제거합니다. 사용 시 경고가 뜹니다.
    DeleteKey 키와 대응하는 값을 삭제합니다.
    GetFloat Preference 파일에 존재하는 /key/에 대응하는 값을 반환합니다.
    GetInt Preference 파일에 존재하는 /key/에 대응하는 값을 반환합니다.
    GetString Preference 파일에 존재하는 /key/에 대응하는 값을 반환합니다.
    HasKey 키가 존재하는지 확인합니다.
    Save 수정된 모든 preferences를 디스크에 씁니다.
    SetFloat /key/로 식별된 Preference의 값을 설정합니다.
    SetInt /key/로 식별된 Preference의 값을 설정합니다.
    SetString /key/로 식별된 Preference의 값을 설정합니다.

     

    아래는 예시이다.

     

    public void _save()
    
    {
    
    PlayerPrefs.SetString("name", name);
    
    PlayerPrefs.SetInt ("type", type);
    
    PlayerPrefs.SetInt ("age", age);
    
    PlayerPrefs.SetInt ("friendship",friendship);
    
    PlayerPrefs.SetInt ("money", money);
    
    PlayerPrefs.Save();
    
    }
    
    public void _load()
    
    {
    
    name= PlayerPrefs.GetString("name");
    
    type = PlayerPrefs.GetInt("type");
    
    age = PlayerPrefs.GetInt("age");
    
    friendship= PlayerPrefs.GetInt("friendship");
    
    money= PlayerPrefs.GetInt("money");
    
    
    tx_name.text=name;
    
    tx_money.text=""+money;
    
    }

    메모장으로 몇번 만지면 다 수정가능하니 보안은 매우 취약하다.

     

     

    COMMENT
     
    10
    28

     

    C#에서 프로퍼티는 우리가 만든 타입의 값을 외부에서 접근할 수 있도록 하면서 객체 지향에서의 캡슐화를 지원한다.

    //property
    public int HP
    {
            get{return hp;}
            set
            {
                hp=value;
                sliderHp.value = value;
            }
    }
    
    private int hp;
    ..///
    
    //사용 예시
    
    private void AddDamage()
    {
            HP = HP - 1; 
           //앞 HP가 Set 뒤 HP가 Get 부분을 담당함
           //HP-=1;
    }

     

    hp 값과 같이 private으로 정보 은닉해야하는 값들은 프로퍼티를 쓰면 좋다

     

    COMMENT
     
    10
    28

     

    공포게임 아오오니를 보면 멍청하게 플레이어를

     

    따라가지 못하고 벽에서 비비적 거리고 있는 걸 볼 수 있다.

     

    맵의 형태를 모르고 그저 타겟의 위치로 가려하다보면 아오오니가 된다.

     

    출발지에서 목적지까지 갈 수 있는 빠른 길을 컴퓨터가 탐색하는 것 중에

     

    에이스타 알고리즘이란게 있다. 그것과 유사한 것이 유니티에 내장되있다고 한다.

     

    유니티 길찾기
    Window -> AI -> Navigation
    
    1. 맵오브젝트 선택 Navigation static으로 설정
    2. 베이크
    3. 네비 먹일 오브젝트에 Nav Mesh Agent 컴포넌트 추가
    4. 스크립트 생성 using UnityEngine.AI;
    5. NavmeshAgent agent; 타겟변수
       void Start()
       {
        agent=GetComponent<NavmeshAgent>();
       }
       void Update()
       {
        //변수에 직접 넣거나
        agent.destination = target.positon;
        //함수에 넣는 방식 agent.SetDestination(target.position)  이 방법이 더 좋음
       }
    
    
    멈추고 싶을때
    agent.isStopped = true;

     

    COMMENT
     
    10
    28

     

    다른 스크립트의 함수 변수를 불러오고 싶을 때는 여러 가지 방법이 있다.

     

    그 중에 쉽게 쓸 수 있는 방법을 생각나는대로 적어보았다.

     

    첫 번째 방법

    • 데이터(Data) 영역 (정적 메모리)
    • 스택(Stack) 영역
    • 힙(Heap) 영역

    Static으로 선언하는 것이다. 정적 메모리에 담으면 어디든 접근 가능하다.

     

    두 번째 방법으로는

    Find 함수를 쓰는 것이다.

    //find 사용 예시 하이라이키 창에 모두 뒤져서 게임메니져를 찾아서 gm에다가 담아 넣는다
    GameManager gm = GameObject.Find("GameManager").GetComponent<GameManager>();
    //gm 스크립트에 있는 함수 Hit()를 호출 시에는 이렇게 쓴다.
    gm.Hit();

    Find를 쓰면 편하지만 하이라이키를 다 뒤져서 찾아다니기 때문에 하이라이키에 뭐가 많을 때는 찾기 힘들어져서 메모리 상 좋지 않다고 한다.

    마치 컴퓨터가 장롱 속에서 게임 매니저라는 옷을 찾다가 게임이 멈춰버릴 수도 있다는 것?

     

    세 번째 방법으로는

    제일 직관적인 방법이다.

    //변수 선언
    public GameObject 스크립트;
    
    // 인스펙터 창에 해당 오브젝트 끌어온다.
    
    //함수 호출 사용시
    스크립트.GetComponent<스크립트이름>().함수()

     

    마지막으로 싱글톤 패턴이다.

    Singleton 패턴은 단 하나의 객체를 생성해서 사용하는 디자인 패턴이다.

    단, 컴포넌트 하나만 있어야 한다.

    public static 클래스이름 instance;
    private void Awake()
    {
        instance=this;
    }
    
    //함수 호출 사용시
    
    클래스이름.instance.함수();
    COMMENT
     
    10
    28

     

    유니티 래그돌 적용법

     

    1. 뼈대 Bone에 Ragdoll를 추가

     

     

     

    맨 오른쪽 사진와 같은 창이 뜰텐데,

     

    본인 뼈구조에 맞는 뼈 오브젝트를 넣으면 된다.

     

    해당 뼈가 없을 경우 중복되지않게만 유사한 뼈를 넣어주면 됨.

     

    해당 뼈에 컴포넌트(리지드바디, 캐릭터조인트, 콜라이더)가 생성된 것을 확인할 수 있다.

     

    2. 스크립트

     

    래그돌은 이벤트(죽을때 등등)가 있을 때만 작동하여야한다.

     

    첨부터 래그돌이 적용되어선 안된다.

        public GameObject skeleton;
        void Start()
        {
                setRigidbodyState(true);
                setColliderState(false);
        }
    
        void setRigidbodyState(bool state)
        {
    // 뼈 안에 있는 리지드바디 상태를 제어한다.
            Rigidbody[] rigidbodies = skeleton.GetComponentsInChildren<Rigidbody>();
            foreach(Rigidbody rigidbody in rigidbodies)
            {
                rigidbody.isKinematic = state;
            }
        }
    
        void setColliderState(bool state)
        {
    // 뼈 안에 있는 콜라이더 상태를 제어한다.
            Collider[] colliders = skeleton.GetComponentsInChildren<Collider>();
            foreach (Collider collider in colliders)
            {
                collider.enabled= state;
            }
        }

     

    setRigidbodyState()의 경우 iskinematic,

    isKinematic이 활성화 되어있는 경우에, 힘, 충돌 또는 조인트등의

    물리효과가 리지드바디에 영향을 주지 않는다. 그래서 초기값 true

    setColliderState는 그냥 콜라이더 끄나 안끄냐 이기때문에 초기값 false로 해주고

    죽었을때만 반대로 해주는 함수를 해주면 된다.

     

        void DestroyRPC()
        {
            gameObject.GetComponent<Animator>().enabled = false;
            Destroy(gameObject, 5f);
            setRigidbodyState(false);
            setColliderState(true);
        }

     

    애니메이터도 반드시 꺼줘야함.

     

    좀 더 화끈하게 죽는 걸 원하면 Addforce로 밀쳐내는 효과를 주던지 하면 더 좋을듯

     

    COMMENT
     
    10
    28

     

     

    UI가 아닌 3D 오브젝트에 텍스트를 쓰고 싶다면,

    유니티에서 제공하는 TextMeshPro를 사용하면 된다.

     

    UI에서 했던 것처럼 폰트도 바꾸고 정렬도 하고 다 할 수 있다.

     

    using TMPro;
    public class Example : MonoBehaviour
    {
        private TextMeshPro numText;
    
        private void Start()
        {
            numText = GetComponentInChildren<TextMeshPro>();
        }

     

    색상 변경 가능

    //색상 변경
        private void StateNumChange(bool b)
        {
            if (b)
                numText.color = new Color32(255, 255, 255, 255);
            else
                numText.color = new Color32(100,100,100,255);
        }

     

    사실 numText.color = new Color(100,100,100,255); 변경이 안되서

    머리 굴리고 있었는데 Color뒤에 32를 써야한단다.

     

     

    Color 구조체는 각 24비트까지만 적용이 되어 RGBA값을 표현하고

    Color32 구조체는 각 8비트 영역을 해서 더 많은 컬러를 표현 할 수 있는 차이다.

     

     

    http://digitalnativestudios.com/textmeshpro/docs/ScriptReference/TextMeshPro.html

    TextMesh Pro Documentation:

     

     

    COMMENT
     
    1 ··· 5 6 7 8 9