ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 무기 생성
    Game Programming/언리얼 2023. 10. 17. 14:44

    무기 생성을 위해 Mesh, Flash Light, Point Light를 Weapon.cpp에서 구현했다.


    Weapon.h

    private:
    	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Light, meta = (AllowPrivateAccess = "true"));
    	class UPointLightComponent* PointLight;
    
    private:
    	void CreateMesh();
    protected:
    	void CreateLightFromBP(const FString& socketName);
    public:
    	void TurnLight(bool bLight);
    	void ToggleLight();
    	const class USkeletalMeshSocket* GetBarrelSocket();
    	FTransform GetSocketTransform();

    Weapon.cpp

    AWeapon::AWeapon()
    {
    	PointLight = CreateDefaultSubobject<UPointLightComponent>(TEXT("WeaponsFlashlight"));
    	PointLight->Mobility = EComponentMobility::Movable;
    	PointLight->SetRelativeRotation(FRotator(0.0f, 0.0f, 0.0f));
    	PointLight->SetVisibility(false);
    	PointLight->UpdateColorAndBrightness();
    	PointLight->AttenuationRadius = 200.f;
    	PointLight->SetRelativeLocation(FVector(50.f, 0.f, 0.f));
    	PointLight->SetupAttachment(GetRootComponent());
    }

    케릭터 클래스에서 사용한 코드를 Weapon클래스로 가져왔다.

    void AWeapon::CreateMesh()
    {
    	USkeletalMesh* GunMesh = Cast<USkeletalMesh>(StaticLoadObject(USkeletalMesh::StaticClass(), NULL, TEXT("/Game/MyProject/Weapons/Meshs/SK_HeavyMachineGun.SK_HeavyMachineGun")));
    	ItemMesh->SetSkeletalMesh(GunMesh);
    	SetRootComponent(ItemMesh);
    }

    StaticLoadObject 함수를 사용해서 아이템 메시를 GunMesh로 변경했다.

    void AWeapon::CreateLightFromBP(const FString& socketName)
    {
    	UObject* LightObject = Cast<UObject>(StaticLoadObject(UObject::StaticClass(), NULL, TEXT("/Game/Voyager/Blueprints/BP_FlashLightWeapon.BP_FlashLightWeapon")));
    
    	UBlueprint* GeneratedLightBP = Cast<UBlueprint>(LightObject);
    	if (!GeneratedLightBP)
    		return;
    	UClass* LightClass = GeneratedLightBP->StaticClass();
    	if (LightClass == NULL)
    		return;
    
    	UWorld* World = GetWorld();
    	FActorSpawnParameters SpawnParams;
    	SpawnParams.Owner = this;
    	SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
    	AActor* actor = World->SpawnActor<AActor>(GeneratedLightBP->GeneratedClass, GetActorLocation(), GetActorRotation(), SpawnParams);
    	actor->AttachToComponent(ItemMesh, FAttachmentTransformRules::SnapToTargetNotIncludingScale, *socketName);
    }
    actor->AttachToComponent(ItemMesh, FAttachmentTransformRules::SnapToTargetNotIncludingScale, *socketName);

    AttachtoComponent 부분이 다른데, MyCharacter.cpp에서 GetMesh()를 사용했다면, ItemMesh를 사용했다.

    FlashLightSocket을 추가로 만들어, HandLight를 부착했다.

     

    FTransform AWeapon::GetSocketTransform()
    {
    	const USkeletalMeshSocket* MeshSocket = ItemMesh->GetSocketByName("BarrelSocket");
    	return MeshSocket->GetSocketTransform(ItemMesh);
    }

    FTransform을 Weapon으로부터 가져와야하기 때문에, BarrelSocket을 가져와 Transform을 읽어오는 함수를 따로 만들었다.


    MyCharacter.cpp

    	UObject* WeaponObject = Cast<UObject>(StaticLoadObject(UObject::StaticClass(), NULL, TEXT("/Game/MyProject/Weapons/BaseWeapon/BaseWeapon.BaseWeapon")));
    
    	UBlueprint* GeneratedBP = Cast<UBlueprint>(WeaponObject);
    	if (!GeneratedBP)
    		return;
    	UClass* WeaponClass = GeneratedBP->StaticClass();
    
    	if (WeaponClass == NULL)
    		return;
    
    	UWorld* World = GetWorld();
    	FActorSpawnParameters SpawnParams;
    	SpawnParams.Owner = this;
    	SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
    
    	AWeapon* DefaultWeapon = World->SpawnActor<AWeapon>(GeneratedBP->GeneratedClass, GetActorLocation(), GetActorRotation(), SpawnParams);
    
    	if (DefaultWeapon == NULL)
    		return;
    
    	const USkeletalMeshSocket* HandSokcet = GetMesh()->GetSocketByName(
    		FName("hand_rSocket"));
    
    	if (!HandSokcet == NULL)
    		return;
    
    	HandSokcet->AttachActor(DefaultWeapon, GetMesh());
    
    	EquippedWeapon = DefaultWeapon;

    블루 프린트 에셋에서 Weapon을 생성하여 hand_rSocket에 붙이는 코드. EquippedWeapon으로 생성한 무기를 저장하고 있는다.

    	if (EquippedWeapon)
    	{
    		const USkeletalMeshSocket* BarrelSocket = EquippedWeapon->GetBarrelSocket();
    
    		if (BarrelSocket)
    		{
    			FTransform SocketTransform = EquippedWeapon->GetSocketTransform();
    			FVector3d vecScale(1.f, 1.f, 1.f);
    			SocketTransform.SetScale3D(vecScale);

    Weapon으로부터 Transform을 읽어 MuzzleFlash와 Bullet 파티클을 만드는데 행렬 크기의 영향을 받지 않도록 스케일을 단위 스케일로 만들었다.

     

    추가)

    Spawn Weapon when using blueprint
    
    if (DefaultWeaponClass)
    {
        // Spawn the Weapon
        AWeapon* DefaultWeapon = GetWorld()->SpawnActor<AWeapon>(DefaultWeaponClass);
    
        // Get the Hand Socket
        const USkeletalMeshSocket* HandSokcet = GetMesh()->GetSocketByName(
            FName("hand_rSocket"));
    
        if (HandSokcet)
        {
            // Attach the Weapon to the hand socket RightHandSocket
            HandSokcet->AttachActor(DefaultWeapon, GetMesh());
        }
        EquippedWeapon = DefaultWeapon;
    }

    평소 TSubclassOf타입에 대해 궁금했는데,

    유데미 강좌에서는 TSubclassOf 타입의 DefaultWeaponClass 변수를 사용하여 무기를 손에 붙였다.

    TSubclassOf 타입이란 객체의 블루프린트 타입이라 이해하면 될 것 같다.

    'Game Programming > 언리얼' 카테고리의 다른 글

    무기 버리기  (1) 2023.10.17
    아이템 Enum값 추가  (0) 2023.10.17
    클래스 배열 PickupWdigetBP 바인딩  (1) 2023.10.17
    Bind item name  (1) 2023.10.16
    Create Door  (1) 2023.10.15
Designed by Tistory.