전체 글 (93)
-
2023.08.18 [BT] 요약
각 노드들은 자신의 상태를 반환해야 합니다 Selector는 자식 노드를 실행하여 이 중 하나라도 True를 리턴하면 True를 리턴 > Selector Node는 자식 노드 중에서 처음으로 Success 나 Running 상태를 가진 노드가 발생하면 그 노드까지 진행하고 멈춥니다. 그러므로 Evaluate() 메소드 구현은 아래와 같습니다. 1. 자식 상태: Running일 때 -> Running 반환 2. 자식 상태: Success 일 때 -> Success 반환 3. 자식 상태: Failure일 때 -> 다음 자식으로 이동 Sequence는 모든 자식 노드가 True를 리턴할 때 True를 리턴 (Sequence는 자식 중 하나라도 False면 False를 리턴) > Sequence Node는 자식..
-
2023.04.03 데이터 값이 갑자기 지수승으로 바뀌는 경우
여러 가지가 있긴 한데 하나씩 확인 중 1. 파일입출력에서 지수승 뜨는 값은 보통 값이 0 인 경우가 많음. 2. long 을 float 에 넣을 때 지수승으로 바뀔 수 있음 --> 메모리 구조가 달라서 값이 날아가는 것 같음. ex. long startX = (m_Size) * -1; ulong startGap = 0; float posX = startX + startGap;
-
2023.03.03 MFC 윈도우 창 분할 시 에러날 때
윈도우창 분할할 때 빨간 에러박스 뜰 때 하위로 넣을 창의 속성이 child 인지 확인해볼 것.
-
2023.03.01 Git 을 사용해서 팀 작업하기
Visual Code 가 아닌, Visual Studio 사용 팀 작업 전에 해야할 것1. git bash 열어서 git config --list 입력(remote 하기 : 원격 저장소랑 연결하기)2. VS 에서 remote 체크 (메뉴 - Git > 설정 > 옵션 > Git 리포지토리 설정 > 원격 > 프로젝트이름.git 연결되어있는지 확인) My 브랜치 선택 > My 로컬 이 생긴다. (아마 동일한 듯)브랜치 이름: Name 커밋 : VS (로컬) 에 저장푸시 : 깃허브 브랜치에 저장풀리퀘스트 : 머지 + 저장 을 요청 끌어오기(파란색 pull) : Name 원격 > Name로컬 로 받는 것이다.우리가 받아야하는 건 : origin master > Name 로컬 이거 하는 방법이 명령 프롬프트 (g..
-
2022.11.12 [C++] C++ 스타일 파일입출력
fin 은 자동 개행을 한다 read / wirte 는 개행을 하지 않는다 C++ 스타일 파일 입출력을 사용하려면 아래 헤더파일을 추가해야한다 1. 파일에 쓰기 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 #include using namespace std; class CPlayer { public: void private: char* m_pName; int m_iHp; } void SaveData() { ofstream fout; // 파일 열기 // std::ios_base::binary : 바이너리 모드 fout.open("PlayerData.txt", std::ios_base::binar..
[BT] 요약2023. 8. 18. 20:48
각 노드들은 자신의 상태를 반환해야 합니다
Selector는 자식 노드를 실행하여 이 중 하나라도 True를 리턴하면 True를 리턴
> Selector Node는 자식 노드 중에서 처음으로 Success 나 Running 상태를 가진 노드가 발생하면 그 노드까지 진행하고 멈춥니다.
그러므로 Evaluate() 메소드 구현은 아래와 같습니다.
1. 자식 상태: Running일 때 -> Running 반환
2. 자식 상태: Success 일 때 -> Success 반환
3. 자식 상태: Failure일 때 -> 다음 자식으로 이동
Sequence는 모든 자식 노드가 True를 리턴할 때 True를 리턴 (Sequence는 자식 중 하나라도 False면 False를 리턴)
> Sequence Node는 자식 노드를 왼쪽에서 오른쪽으로 진행하면서 Failure 상태가 나올 때까지 진행하게 됩니다.
그러므로 Evaluate() 메소드 구현은 아래와 같습니다.
1. 자식 상태: Running 일 때 -> Running 반환
2. 자식 상태: Success 일 때 -> 다음 자식으로 이동
3. 자식 상태: Failure 일 때 -> Failure 반환
Sequence Node 의 주의점
Running 상태일 때는 그 상태를 계속 유지해야 하기 때문에
다음 자식 노드로 이동하면 안 되고, 다음 프레임 때도 그 자식에 대한 평가를 진행해야 합니다.
예를 들어, Sequence Node에 적 발견(Detect), 이동(Move), 공격(Attack) 총 3개의 자식 노드가 있다고 가정해 보겠습니다.
( 프레임마다 노드에 진입하는 상황은 "N차"로 가정하였습니다.)
1차 : 적을 발견하고 적을 향해 이동해야한다.
2차 : 발견한 적을 향해 아직 이동 중이다.
3차 : 발견한 적을 향해 아직 이동 중이다.
4차 : 이동이 완료되어 적을 공격한다.
만약 이때 running에서 반환되지 않고 다음 자식 노드로 이동하게 되면 어떻게 될까요?
당연히 아직 적에게 다가가지도 못했는데 적을 향해 공격하게 됩니다.
그러므로, Running 상태에서는 Success와 다르게 다음 자식으로 이동하지 않고 Running을 반환해 줘서 다음 진입 시에도 Running 상태를 유지할 수 있도록 해주어야 합니다.
유의할 점은 노드는 추가된 순서에 따라 차례대로 호출 되기때문에 노드 순서가 캐릭터의 행동에 영향을 끼치게 됩니다.
오크 사냥 행동 트리가 작동 되는 동작 순서
Root에 Selector를 먼저 추가하였기 때문에 실행되면 Selector의 노드를 먼저 탐하게 됩니다. Selector에는 오크를 찾아 공격하는 시퀀스와 플레이어를 이동하는 시퀀스 2개가 추가되어있습니다.
먼저 첫번째 시퀀스인 오크를 찾아 공격하는 시퀀스를 탐색하게됩니다. CheckIsHereOrc 노드를 통해 오크가 현 위치에 있는 경우 True가 리턴되기 때문에 다음 노드인 AttackOrc 노드가 실행됩니다. 만약 오크가 없다면 False가 리턴 되기 때문에 다음 노드를 실행하지 않고, 현재 시퀀스 노드도 False를 리턴 합니다.
첫 번째 시퀀스가 False가 되면, Selector는 다음 시퀀스 노드를 탐색하게 됩니다. 두 번째 시퀀스에는 PlayerMove 만 있습니다. 이는 플레이어 이동 후 True를 리턴하게됩니다. Selector는 두 번째 시퀀스에서 True를 리턴 받았기 때문에 True를 리턴해줍니다.
Root는 이제 다음 노드인 IsPlayerDead를 실행합니다. 플레이어가 죽었다면 True, 아직 안죽었으면 False를 리턴합니다.
이렇게 노드들을 탐색하면서 Root 노드가 True를 리턴하게 되면 (IsPlayerDead가 True면) 프로그램을 종료하게 됩니다.
▼ 코드
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
|
class Node
{
public:
virtual bool Invoke() = 0;
};
class CompositeNode : public Node
{
public:
void AddChild(Node *node)
{
mChildren.emplace_back(node);
}
const std::list<Node*>& GetChildren()
{
return mChildren;
}
private:
std::list<Node*> mChildren;
};
class Selector : public CompositeNode
{
public:
virtual bool Invoke() override
{
for (auto node : GetChildren())
{
if (node->Invoke())
return true;
}
return false;
}
};
class Sequence : public CompositeNode
{
public:
virtual bool Invoke() override
{
for (auto node : GetChildren())
{
if (!node->Invoke())
return false;
}
return true;
}
};
|
cs |
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
|
BT::Sequence *root = new BT::Sequence(); // 루트 노드(시퀀스 노드로 생성)
BT::Selector *selector = new BT::Selector(); // 셀렉터
BT::Sequence *seqOrcKill = new BT::Sequence(); // 오크가 있으면 오크를 공격하는 시퀀스
BT::Sequence *seqMove = new BT::Sequence(); // 플레이어 이동 시퀀스
BT::Node *playerIsDead = new PlayerIsDead(); // 플레이어가 죽었는지 체크
BT::Node *checkIsHereOrc = new CheckIsHereOrc(); // 현 위치에 오크가 있는지 체크
BT::Node *attackOrc = new AttackOrc(); // 오크 공격 액션
BT::Node *playerMove = new PlayerMove(); // 플레이어 이동 액션
root->AddChild(selector);
root->AddChild(playerIsDead);
selector->AddChild(seqOrcKill);
selector->AddChild(seqMove);
seqOrcKill->AddChild(checkIsHereOrc);
seqOrcKill->AddChild(attackOrc);
seqMove->AddChild(playerMove);
while (!root->Invoke())
{
std::cout << "--------------------------------------" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
|
cs |
< 스스로 정리 >
셀렉터 노드 : 자식 list 를 가진다. 순회하며 자식의 invoke 를 호출한다. 상태를 받아서 반환한다.
시퀀서 노드 : 자식 list 를 가진다. 순회하며 식의 invoke 를 호출한다. 상태를 받아서 반환한다.
액터 노드 : update 함수를 가진다. update 안에 있는 invoke 를 호출하여 러닝, 성공, 실패 상태를 반환한다.
매 틱하다 BT 루트부터 시작하여 Update를 호출해서 진행한다.
'Language > C++' 카테고리의 다른 글
[C++] 함수 객체와 임시 객체 (0) | 2023.11.23 |
---|---|
[펌] 생성자 소멸자 관련 (0) | 2023.08.19 |
[C++] C++ 스타일 파일입출력 (0) | 2022.11.12 |
[C] C 스타일 파일입출력 (0) | 2022.11.12 |
[C] 문자열 상수 (0) | 2022.10.23 |
데이터 값이 갑자기 지수승으로 바뀌는 경우2023. 4. 3. 17:58
여러 가지가 있긴 한데 하나씩 확인 중
1. 파일입출력에서 지수승 뜨는 값은 보통 값이 0 인 경우가 많음.
2. long 을 float 에 넣을 때 지수승으로 바뀔 수 있음
--> 메모리 구조가 달라서 값이 날아가는 것 같음.
ex.
long startX = (m_Size) * -1;
ulong startGap = 0;
float posX = startX + startGap;
'[에러정리]' 카테고리의 다른 글
MFC 윈도우 창 분할 시 에러날 때 (0) | 2023.03.03 |
---|---|
[ue4 error] msb3073 [ code : 6 ] (0) | 2021.02.02 |
[ue4 error] lnk1104 (0) | 2021.02.02 |
[visual studio error] '마이그레이션 필요' 프로젝트를 로드하고 다시 시작하세요 (0) | 2021.01.07 |
[Unity] exe 실행파일에서 InputManager에서 만든 버튼이 입력되지 않는 실행버그 (0) | 2017.09.01 |
MFC 윈도우 창 분할 시 에러날 때2023. 3. 3. 21:15
윈도우창 분할할 때 빨간 에러박스 뜰 때
하위로 넣을 창의 속성이 child 인지 확인해볼 것.
'[에러정리]' 카테고리의 다른 글
데이터 값이 갑자기 지수승으로 바뀌는 경우 (0) | 2023.04.03 |
---|---|
[ue4 error] msb3073 [ code : 6 ] (0) | 2021.02.02 |
[ue4 error] lnk1104 (0) | 2021.02.02 |
[visual studio error] '마이그레이션 필요' 프로젝트를 로드하고 다시 시작하세요 (0) | 2021.01.07 |
[Unity] exe 실행파일에서 InputManager에서 만든 버튼이 입력되지 않는 실행버그 (0) | 2017.09.01 |
Git 을 사용해서 팀 작업하기2023. 3. 1. 22:44
Visual Code 가 아닌, Visual Studio 사용
팀 작업 전에 해야할 것
1. git bash 열어서 git config --list 입력
(remote 하기 : 원격 저장소랑 연결하기)
2. VS 에서 remote 체크
(메뉴 - Git > 설정 > 옵션 > Git 리포지토리 설정 > 원격 > 프로젝트이름.git 연결되어있는지 확인)
My 브랜치 선택 > My 로컬 이 생긴다. (아마 동일한 듯)
브랜치 이름: Name
커밋 : VS (로컬) 에 저장
푸시 : 깃허브 브랜치에 저장
풀리퀘스트 : 머지 + 저장 을 요청
끌어오기(파란색 pull) : Name 원격 > Name
로컬 로 받는 것이다.
우리가 받아야하는 건 : origin master > Name 로컬
이거 하는 방법이 명령 프롬프트 (git 콘솔창 을 명령 프롬프트 로 대체 가능)
(다른 사람이 올린 코드가 내꺼랑 컨플릭트 날 수도 있으니)
커밋 한 후에(푸시는 하지말 것 !) 명령 프롬프트에 입력
git pull origin master
1. 정상이면 fild update .. 이렇게 뜸.
2. 컨틀릭트 나면.. 코드에 에러난 게 보임. (빌드돌려보셈)
여기서 체크박스에 코드 선택해서 합치거나 지워서 맞추면 됨
'[궁금해요]' 카테고리의 다른 글
visual studio 프로젝트 이름 변경 방법 (5) | 2016.06.16 |
---|
[C++] C++ 스타일 파일입출력2022. 11. 12. 20:09
fin 은 자동 개행을 한다
read / wirte 는 개행을 하지 않는다
C++ 스타일 파일 입출력을 사용하려면 아래 헤더파일을 추가해야한다
<fstream>
1. 파일에 쓰기
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
|
#include <fstream>
using namespace std;
class CPlayer
{
public:
void
private:
char* m_pName;
int m_iHp;
}
void SaveData()
{
ofstream fout;
// 파일 열기
// std::ios_base::binary : 바이너리 모드
fout.open("PlayerData.txt", std::ios_base::binary);
// 1. char 배열 저장
// 파일에 쓰기
int _arrLen = strlen(m_pName);
fout.write(m_pName, sizeof(char) * _arrLen);
// 2. 정수 저장 : 일반 원시 변수
// 파일에 쓰기
fout.write((char*)&m_iHp, sizeof(int));
// 파일 닫기
fout.close();
}
|
cs |
2. 파일 읽기
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
|
#include <fstream>
using namespace std;
class CPlayer
{
public:
void Set_Info(/*매개변수들*/);
private:
char* m_pName;
int m_iHp;
}
void LoadData()
{
ifstream fin;
// 파일 열기
// std::ios_base::binary : 바이너리 모드
fin.open("PlayerData.txt",std::ios_base::binary);
// 파일이 정상적으로 열렸는가
if (fin.is_open() == true)
{
char _arr[30] = "";
int _hp = 0;
// 파일 읽기 : 1. char 배열
fin.read(_arr, sizeof(_arr));
// 파일 읽기 : 2. 일반 원시 변수
fin.read((char*)&m_iHp, sizeof(int));
// 데이터 셋팅
Set_Info(_arr, _hp);
// 파일 닫기
fin.close();
}
}
|
cs |
출처 :
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=kks227&logNo=220227175866
'Language > C++' 카테고리의 다른 글
[펌] 생성자 소멸자 관련 (0) | 2023.08.19 |
---|---|
[BT] 요약 (0) | 2023.08.18 |
[C] C 스타일 파일입출력 (0) | 2022.11.12 |
[C] 문자열 상수 (0) | 2022.10.23 |
[C++] 코드 위치나 정보를 받아오는 매크로 들 (0) | 2022.05.08 |