git lfs installgit initgit branch -M mainmain으로 설정git statusgit add .git commit -m "Initial commit"git remote add origin <원격저장소주소>git lfs pullclass UBoxComponent; // 헤더
#include "Components/BoxComponent.h"//cpp
UStruct(BlueprintType) 으로 SpawnEntry.ActorClass SpawnCount 관리virtual void OnConstruction(const FTransform& Transform) override;
#if WITH_EDITOR
virtual void PostEditMove(bool bFinished) override;
#endif
void SpawnActor(const FSpawnEntry& Entry)
{
if (!Entry.ActorClass)
{
return;
}
UWorld* World = GetWorld();
if (!World)
{
return;
}
FActorSpawnParameters Params;
Params.Owner = this;
Params.SpawnCollisionHandlingOverride =
ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding;
AActor* SpawnedActor = World->SpawnActor<AActor>(
Entry.ActorClass,
SpawnLocation,
SpawnRotation,
Params
);
SetBoxExtent(FVector)BoxVolume->GetScaledBoxExtent();SpawnVolume->GetComponentTransform().TransformPosition(LocalPoint) : 로컬 좌표 월드좌표로 변환FVector::XAxisVectors의 길이가 4 또는 6인지 먼저 확인해야 한다.true를 반환한다.false를 반환한다.#include <string>
#include <vector>
using namespace std;
bool solution(string s) {
bool answer = true;
if (s.size() != 4 && s.size() != 6) return false;
for (char a: s)
{
if(a<=47 || 58 <= a)
{
answer = false;
break;
}
}
return answer;
}
47, 58 대신 '0', '9'를 사용하면 숫자 판별 의도가 더 잘 드러난다.answer = false; break; 쓸거면 걍 거기서 바로 return false 해버려도 깔끔하긴 함E:\Unreal Projects 폴더 하에 있는 프로젝트 폴더에 git 을 집어넣는 방법이다.gitignore .gitattributes 생성
- Git에 올릴 것은 Config, Content, Source, .uproject 정도
- .gitattributes 는 큰 파일 전송용 Git LFS와 같이 쓰기 위해서 쓴다.
- 이건 AI의 도움을 받는 게 일단은 가장 편할 거 같다.
이번에 쓴 건
/.vs
/Binaries
/DerivedDataCache
/Intermediate
/Saved
*.sln
*.opensdf
*.sdf
*.VC.db
*.VC.opendb
*.vsconfig
*.suo
*.user
*.userprefs
*_BuiltData.uasset
Plugins/*/Binaries
Plugins/*/Intermediate
*.uasset filter=lfs diff=lfs merge=lfs -text
*.umap filter=lfs diff=lfs merge=lfs -text
Git LFS 초기화
cmd 입력.git lfs install 입력Git 저장소 초기화
git init: 저장소 초기화git branch -M main: main 브랜치 만들기git status 치면 파일들 체크 가능 -> 여기서 ignore 되야 하는 파일들 ignore 되고있는지 확인add/commit
git add . 에서 더한다. . 에 주의git status 로 확인git commit -m "Initial commit" 으로 첫 커밋. 원격 저장소 생성
.gitignore 도 우리가 직접 만들었으니 필요 없다.git remote add origin https://주소 로 원격 저장소 연결.
Test
New tab - Clone 에서 내 원격 저장소 URL 넣으면 된다.git lfs pull Yes 하고 받아서 실행해 보면 완료.
UPROPERTY 나 기본 BeginPlay 등을 제외한 헤더class UBoxComponent; // Box collision 미리 선언
USTRUCT(BlueprintType)
struct FSpawnEntry
{
GENERATED_BODY()
TSubclassOf<AActor> ActorClass;
int32 SpawnCount = 1;
// 이 항목이 true면 Yaw를 랜덤하게 줌
bool bRandomYaw = false;
};
ActorClass : 해당 스폰 액터가 받을 플랫폼 액터 등등SpawnCount : 몇개나 스폰할지SpawnEntry 구조체 TArray 에 원하는 액터/스폰갯수 집어넣는 식으로 스폰이 구현된다.protected:
virtual void OnConstruction(const FTransform& Transform) override;
#if WITH_EDITOR
virtual void PostEditMove(bool bFinished) override;
#endif
public:
TObjectPtr<UBoxComponent> SpawnVolume;
TArray<FSpawnEntry> SpawnEntries;
bool bSpawnOnBeginPlay = true;
void SpawnActors();
FVector GetRandomPointInVolume() const;
private:
void SpawnSingleActor(const FSpawnEntry& Entry);
void FixRotation();
SpawnVolume : 얘를 위해 UBoxComponent 미리 선언함. 스폰이 일어날 박스 콜리전 OnConstruction : 액터가 에디터에서 생성되거나, 디테일 패널에서 값이 바뀌거나, 블루프린트가 갱신되거나, 월드에 배치될 때 호출. 거기서 X축, Y축을 FixRotation 으로 잡아줌#if WITH_EDITOR : 에디터로 열 때만 컴파일되는 함수라는 의미. PostEditMove : 액터를 에디터에서 이동/회전시킨 후 호출된다. 여기서 다시 FixRotation으로 잡아줌TArray<FSpawnEntry> 로 스폰할 액터들 배열 만들어 주고, 여기서 SpawnActors 에서 각 FSpawnEntry별로 SpawnSingleActor 해준다.#include "Components/BoxComponent.h" : 미리 선언 해둔 박스 컴포넌트 여기서 사용#include "Engine/World.h" : World 가져와서 실제 액터를 월드에 넣는 데 써야 한다.#include "DrawDebugHelpers.h"SetBoxExtent(FVector) 로 사이즈 설정.Extent는 Half Lengthconst FVector Extent = SpawnVolume->GetScaledBoxExtent();FMath::FRandRange(-Extent.X, Extent.X)return SpawnVolume->GetComponentTransform().TransformPosition(LocalPoint); 로 SpawnVolume 기준으로 계산한 로컬 좌표를 월드 좌표로 변환시켜 반환한다.SpawnVolume->SetCollisionEnabled(ECollisionEnabled::NoCollision);void ASpawnActor::SpawnSingleActor(const FSpawnEntry& Entry)
{
if (!Entry.ActorClass)
{
return;
}
UWorld* World = GetWorld();
if (!World)
{
return;
}
const FVector SpawnLocation = GetRandomPointInVolume();
GetWorld()GetWorld() 를 매번 스폰할 때마다 호출하는 이유GetWorld() 는 포인터만 반환하는 함수이므로 그렇게 부담이 크지 않고FRotator SpawnRotation = FRotator::ZeroRotator;
if (Entry.bRandomYaw)
{
SpawnRotation.Yaw = FMath::FRandRange(0.f, 360.f);
}
Default를 먼저 집어넣고 필요한 경우에만 랜덤값 넣어주기FActorSpawnParameters Params;
Params.Owner = this;
Params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding;
SpawnActor() 함수에 넘길 파라미터들 지정해 주는 곳. 즉 World.h 에 속해 있는 함수다. Owner는 "누가 해당 액터를 스폰했는지 적는 칸. GetOwner 등으로 SpawnActor를 참조할 수 있게 만들어 준다.SpawnCollisionHandlingOverride : 스폰 위치가 겹칠 때 어떻게 할래? 묻는 것Adjust... 여기는 위치를 조금 조정해서 스폰해 보고 그래도 해결 안되면 스폰 하지 마라는 뜻SpawnSingleActor 가 실패할 수 있다는 의미AActor* SpawnedActor = World->SpawnActor<AActor>(
Entry.ActorClass,
SpawnLocation,
SpawnRotation,
Params
);
SpawnEntry 구조체인 Entry 의 멤버변수 ActorClass 의 액터를 스폰. Transform은 SpawnLocation, SpawnRotation, Params 내용도 전달하기AActor* 포인터라 MovingPlatform 등등 다 대응 가능. 지역 변수라 함수 끝나면 포인터 소멸TArray<AActor*> 같은 거 만들어서 관리하기.nullptr 이 들어갈 수 있음에 유의!TArray<SpawnEntries> 에 대한 for문, Entry.SpawnCount 로 두 번째 for문 돌리면 됨.SpawnVolume 등을 알아야 하는 스폰 대상이 있을 수 있다. class ASpawnActor* SpawnActor; 하고#include "SpawnActor.hint32 RandomXYZ = FMath::RandRange(0, 2);
switch (RandomXYZ)
{
case 0:
if (FMath::RandBool())
{
RealMoveVector = FVector(MoveSpeed, 0.f, 0.f);
Destination = StartLocation + MaxRange * FVector(1.f, 0.f, 0.f);
break;
}
RealMoveVector = FVector(-MoveSpeed, 0.f, 0.f);
Destination = StartLocation + MaxRange * FVector(-1.f, 0.f, 0.f);
break;
case 1:
if (FMath::RandBool())
{
RealMoveVector = FVector(0.f, MoveSpeed, 0.f);
Destination = StartLocation + MaxRange * FVector(0.f, 1.f, 0.f);
break;
}
RealMoveVector = FVector(0.f, -MoveSpeed, 0.f);
Destination = StartLocation + MaxRange * FVector(0.f, -1.f, 0.f);
break;
case 2:
RealMoveVector = FVector(0.f, 0.f, MoveSpeed);
Destination = StartLocation + MaxRange * FVector(0.f, 0.f, 1.f);
break;
default:
break;
}
case 0:
{
const float Sign = FMath::RandBool() ? 1.f : -1.f;
RealMoveVector = FVector::XAxisVector * MoveSpeed * Sign;
Destination = StartLocation + FVector::XAxisVector * MaxRange * Sign;
break;
}
SpawnActor() 실행 시 콜리전 체크 할 때 좀 더 넓은 범위의 콜리전 체크를 해도 좋을 거고RandTpActor 는 순간이동 할 때마다 콜리전 체크를 수행하는 게 더 좋을 거고 (혹은 두 세 곳만 오가는 Teleport를 한다던지)MovingActor 의 경우 시작점-끝점까지 범위 전체에 대해 Spawn을 방지해 줄 필요가 있다.
| 랭크 | 누적 경험치량 | 다음 랭크까지 추가로 필요한 경험치 |
|---|---|---|
| 0 | 0 | 700 |
| 1 | 700 | 800 |
| 2 | 1,500 | 900 |
| 3 | 2,400 | 1,000 |
| 4 | 3,400 | 1,200 |
| 5 | 4,600 | 2,400 |
| 6 | 7,000 | 3,600 |
| 7 | 10,600 | 4,900 |
| 8 | 15,500 | 6,500 |
| 9 | 22,000 | - |