1.플레이어 백팩 선언
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 |
#pragma once
#include "GameFramework/Character.h"
#include "MyCharacter.generated.h"
//class APickupItem;
UCLASS()
class BOOK_0528_API AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AMyCharacter();
TMap<FString, int> Backpack;
TMap<FString, UTexture2D*> Icons;
bool inventoryShowing;
void Pickup(APickupItem *item);
}; |
cs |
14)플레이어의 백팩을 위한 Map
15)아이템 아이콘들
17)백팩이 현재 보여지고 있는지 여부
18)아이템을 습득하도록 하는 멤버 함수
주석처리된 전방선언은 PickupItem 클래스를 만든 후 풀어주기.
project setting - input - action Mapping 으로 가서 i키를 누르면 inventory가 뜨게 입력해준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 |
#include "Book_0528.h"
#include "MyCharacter.h"
#include "PickupItem.h"
#include "MyHUD.h"
// Sets default values
AMyCharacter::AMyCharacter()
{
inventoryShowing = false;
}
void AMyCharacter::SetupPlayerInputComponent(class UInputComponent* InputComponent)
{
InputComponent->BindAction("Inventory", IE_Pressed, this, &AMyCharacter::ToggleInventory);
}
void AMyCharacter::debug(int slot, FColor color, FString mess){
if (GEngine){
GEngine->AddOnScreenDebugMessage(slot, 5.f, color, mess);
}
}
void AMyCharacter::ToggleInventory(){
debug(0, FColor::Red, "inventory true");
}
|
cs |
2.PickupItem 클래스 생성
부모클래스로 Actor를 선택해서 PickupItem클래스를 생성한다.
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 |
#pragma once
#include "GameFramework/Actor.h"
#include "PickupItem.generated.h"
class AMyHUD;
UCLASS()
class BOOK_0528_API APickupItem : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
APickupItem();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Item)
FString Name;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Item)
int32 Quantity;
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = Item)
USphereComponent* ProxSphere;
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = Item)
UStaticMeshComponent* Mesh;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Item)
UTexture2D* Icon;
UFUNCTION(BlueprintNativeEvent, Category = Collision)
void Prox(AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex,
bool bFromSweep, const FHitResult & SweepResult);
virtual void APickupItem::Prox_Implementation(AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep,
const FHitResult & SweepResult);
}; |
cs |
18)얻는 아이템 이름
21)아이템 개수
24)아이템을 줍는데 사용되는 충돌 구체
27)아이템 메시
30)UI/캔버스에서 보여질 아이템 아이콘
32~)proxSphere 안으로 무언가 들어오면 이 함수가 실행된다.
여기까지하면 이렇게.
1
2
3
4
5
6
7
8
9
10
11
12
13 |
APickupItem::APickupItem()
{
Name = "UNKNOWN ITEM";
Quantity = 0;
ProxSphere = CreateDefaultSubobject<USphereComponent>(TEXT("ProxSphere"));
Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
RootComponent = Mesh;
Mesh->SetSimulatePhysics(true);
ProxSphere->OnComponentBeginOverlap.AddDynamic(this, &APickupItem::Prox);
ProxSphere->AttachTo(Mesh);
} |
cs |
3,4)이름, 갯수 초기화
5,6)언리얼 객체 초기화_상속받은 기본값을 가지고 있을 수는 있지만, 메시는 비어있는 채로 시작할 것.
나중에 블루프린트 내에서 실제 메시를 로드해야한다.
8,9)루트 객체를 메시로 만든다, 실제 물리를 시뮬레이트_습득 아이템들을 버리거나 이동했을때 튕겨지거나 굴러가게끔.
11)충돌 구체가 다른 액터랑 겹치면 APickupItem::Prox()가 실행되게 한다.
12)습득아이템의 ProxSphere 컴포넌트가 메시 루트 컴포넌트와 연결되었는지 확인한다.
레벨상에서 메시가 움직였을때 ProxSphere가 따라가게끔.
이 단계를 잊어버리면 메시가 움직여도 ProxSphere가 따라가지 않는다.
3.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 |
void APickupItem::Prox_Implementation(AActor* OtherActor, UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex, bool bFromSweep, const FHitResult &SweepResult)
{
if (Cast<AMyCharacter>(OtherActor) == nullptr){
return;
}
AMyCharacter *cha = Cast<AMyCharacter>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
APlayerController* pcon = GetWorld()->GetFirstPlayerController();
AMyHUD* hud = Cast<AMyHUD>(pcon->GetHUD());
hud->addMessage(Message(FString(TEXT("Picked up:")) + FString::FromInt(Quantity) + FString(TEXT("/"))
+ Name, 5.f, FColor::White));
cha->Pickup(this);
Destroy();
}
|
cs |
4)겹쳐진 액터가 플레이어가 아니면 그냥 종료.
7)플레이어에게 아이템을 주기위해 플레이어 아바타의 참조를 얻는다.
playerPawn객체는 실제로 AAvatar인스턴스이고 Cast<AAvatar>명령을 사용하여 AAvatar클래스로 형변환한다.
UGameStatics함수 집합은 전역함수라 어디서든지 접근할 수 있다.
8)컨트롤러의 참조를 얻는다.
9)컨트롤러에서 HUD의 참조를 얻는다. HUD는 실제로 플레이어의 컨트롤러에 붙어있어서 이렇게 접근한다.
12)플레이어가 아이템 줍줍. (원래 7~8 사이쯤에 위치해야되는데 옮기다보니까.. )
this 키워드를 사용한다. _this_픽업에 자기 자신을 참조하는 방법.
그리고 백팩에 아이템이 들어왔나 확인한다.
1
2
3
4
5
6
7
8
9 |
void AMyCharacter::Pickup(APickupItem *Item){
if (Backpack.Find(Item->Name)){
Backpack[Item->Name] += Item->Quantity;
}
else{
Backpack.Add(Item->Name, Item->Quantity);
Icons.Add(Item->Name, Item->Icon);
}
} |
cs |
3)이미 백팩에 아이템이 있으므로 수량을 ++
7)없다면 추가
4.인벤토리 그리기_DrawTexture() 사용
아이콘의 종류, 현재 위치, 크기에 대한 정보를 저장하는 구조체를 선언해서 위젯에 모든 정보가 표시되도록.
위젯 구조체의 네개의 멤버 함수가 각각 위젯의 왼쪽,오른쪽, 위, 아래값을 얻는 함수이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 |
struct Icon{
FString name;
UTexture2D* tex;
Icon(){ name = "UNKNOWN ICON"; tex = 0; }
Icon(FString& iName, UTexture2D* iTex)
{
name = iName;
tex = iTex;
}
};
struct Widget{
Icon icon;
FVector2D pos, size;
Widget(Icon iicon){
icon = iicon;
}
float left(){ return pos.X;}
float right(){ return pos.X + size.X; }
float top(){ return pos.Y; }
float bottom(){ return pos.Y + size.Y; }
}
} |
cs |
스크린에 위젯을 그리는 함수를 작성한다.
DrawWidgets() 함수 호출은 DrawHUD()함수에 추가되어야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 |
void AMyHUD::DrawWidgets(){
for (int c = 0; c < widgets.Num(); c++)
{
DrawTexture(widgets[c].icon.tex, widgets[c].pos.X, widgets[c].pos.Y,
widgets[c].size.X, widgets[c].size.Y, 0, 0, 1, 1);
// draws relative to center.. don't want to use this version
//DrawText( icons[c].name, pos, hudFont, FVector2D(.6f, .6f), FColor::Yellow );
DrawText(widgets[c].icon.name, FLinearColor::Yellow,
widgets[c].pos.X, widgets[c].pos.Y,
hudFont, .6f, false);
}
}
void AMyHUD::DrawHUD(){
Super::DrawHUD();
dims.X = Canvas->SizeX;
dims.Y = Canvas->SizeY;
DrawWidgets();
} |
cs |
116~)캔버스 변수 내에만 dims가 존재한다. addWidget()에서 사용하기 위해 업데이트.
I키를 눌렀을때 실행할 ToggleInventory()
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 |
void AMyCharacter::ToggleInventory(){
APlayerController* pcon = GetWorld()->GetFirstPlayerController();
AMyHUD* hud = Cast<AMyHUD>(pcon->GetHUD());
if (!inventoryShowing){
inventoryShowing = true;
pcon->bShowMouseCursor = true;
for (TMap<FString, int>::TIterator it = Backpack.CreateIterator(); it; ++it){
debug(0, FColor::Red, "inventory true");
FString fs = it->Key + FString::Printf(TEXT("x %d"), it->Value);
UTexture2D* tex = NULL;
if (Icons.Find(it->Key))
tex = Icons[it->Key];
Widget w(Icon(fs, tex));
hud->addWidget(w);
}
}
else if(inventoryShowing == true){
hud->clearWidgets();
inventoryShowing = false;
pcon->bShowMouseCursor = false;
return;
}
} |
cs |
2,3) 컨트롤러와 HUD를 얻는다.
11) coin x 5 같은 식으로 아이템의 이름과 개수를 조합
1
2
3
4
5
6
7
8
9
10
11
12
13
14 |
void AMyHUD::addWidget(Widget widget){
FVector2D start(200, 200), pad(12, 12);
widget.size = FVector2D(100, 100);
widget.pos = start;
for (int c = 0; c < widgets.Num(); c++){
widget.pos.X += widget.size.X + pad.X;
if (widget.pos.X + widget.size.X > dims.X){
widget.pos.X = start.X;
widget.pos.Y += widget.size.Y + pad.Y;
}
}
widgets.Add(widget);
} |
cs |
2,3)격자를 기반으로 한 위젯의 위치를 찾아서 아이콘을 그린다.
6~)위치 계산
8~)오른쪽에 공간이 없다면 다음줄로 이동.
여기까지하면 이렇게.
'프로그래밍 > Unreal' 카테고리의 다른 글
Blueprint Tutorial)Toggling a Light with the Level BP (0) | 2017.07.12 |
---|---|
[26]_2 (2) | 2017.06.12 |
0607/그냥정리 (0) | 2017.06.07 |
[24]템플릿과 자주 사용되는 컨테이너들_2 (0) | 2017.06.06 |
[23] 템플릿과 자주 사용되는 컨테이너들 (0) | 2017.06.04 |