Archives Kwiecień 2021

Tworzenie Klasy Bazowej w C++

W projekcie obejmującym Blueprint i C ++ typowym przepływem pracy jest utworzenie klasy bazowej w C++ ze zmiennymi i funkcjami, a następnie utworzenie podrzędnych schematów, które będą definiować używane zasoby, które mogą definiować inne zmienne i funkcje specyficzne dla Blueprint.

W tym artykule zaimplementujemy klasę bazową PlayerProjectile w C ++. Ta klasa reprezentuje pocisk wystrzelony przez gracza. W przykładowym projekcie gracz ma trzy typy pocisków, które są reprezentowane przez schematy potomne PlayerProjectile .

Kliknij menu File w edytorze Unreal i wybierz opcję New C++ Class… , jak pokazano na poniższym zrzucie ekranu. 

Na następnym ekranie wybierz klasę aktora jako klasę nadrzędną i kliknij przycisk Nex .

W polu Name wpisz PlayerProjectile. W polu Path zachowaj domyślny folder projektu. Kliknij przycisk Create Class.

Ponieważ jest to pierwsza klasa C ++ w tym projekcie Blueprint, edytor Unreal przekształci ją w projekt C ++.

PlayerProjectile klasa użyje poniższych zmiennych

  • USphereComponent :  jest używany jako składnik główny i do testu kolizji.
  • UStaticMeshComponent : zawiera model, która będzie wizualnie reprezentować aktora.
  • UProjectileMovementComponent : komponent używany do poruszania aktora. 

Dodaj deklarację komponentów w pliku PlayerProjectile.h , które muszą mieć następującą zawartość: 

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "PlayerProjectile.generated.h"

UCLASS()
class TUTOPART3_API APlayerProjectile : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	APlayerProjectile();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
	UStaticMeshComponent* StaticMesh;
	
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
	class USphereComponent* CollisionComponent;
	
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly)	
	class UProjectileMovementComponent* ProjectileMovement;

};

W pliku PlayerProjectile.cpp mamy inicjalizację trzech komponentów wykonaną w konstruktorze. Nie zapomnij dodać linii #include .

#include "PlayerProjectile.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "Engine/CollisionProfile.h"
#include "Components/SphereComponent.h"

// Sets default values
APlayerProjectile::APlayerProjectile()
{
  PrimaryActorTick.bCanEverTick = true;

  InitialLifeSpan = 10.f;

  CollisionComponent = CreateDefaultSubobject<USphereComponent>(
                                             TEXT("CollisionComponent"));
  RootComponent = CollisionComponent;
  CollisionComponent->InitSphereRadius(20.f);
  CollisionComponent->SetCollisionProfileName(
                           UCollisionProfile::BlockAllDynamic_ProfileName);

  StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
  StaticMesh->SetupAttachment(CollisionComponent);
	
  ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>(
                                             TEXT("ProjectileMovement"));
  ProjectileMovement->InitialSpeed = 3000.f;
  ProjectileMovement->MaxSpeed = 3000.f;
  ProjectileMovement->ProjectileGravityScale = 0.f;
}

// Called when the game starts or when spawned
void APlayerProjectile::BeginPlay()
{
  Super::BeginPlay();
}

// Called every frame
void APlayerProjectile::Tick(float DeltaTime)
{
  Super::Tick(DeltaTime);
}

Skompiluj kod C ++.

Początkowe wartości przypisane do komponentów można modyfikować w podrzędnych Blueprints.

Zwróć uwagę, że nie zdefiniowaliśmy zasobu używanego przez static mesh. Powinniśmy unikać odwoływania się do folderów i zasobów bezpośrednio w kodzie C++, ponieważ zmiana nazwy zasobu lub przeniesienie go do innego folderu spowoduje błąd w kodzie C++, który będzie musiał zostać zaktualizowany i ponownie skompilowany.

Ten problem nie występuje w Blueprint. Edytor automatycznie aktualizuje odniesienia do zasobu w planach po zmianie nazwy lub przeniesieniu go do innego folderu. 


Źródło:https://romeroblueprints.blogspot.com/2021/03/playerprojectile-creating-base-class-in.html

PlayerCharacter: Dostosowanie Blueprint

W tym artykule dokonamy niezbędnych zmian w Blueprint BP_PlayerCharacter, aby zaimplementować zmianę pocisku przez gracza.

Najpierw dodajmy mapowanie wejścia dla gracza, aby zmienić pocisk za pomocą klawisza Tab .

W Edytorze poziomów przejdź do menu Edycja-> Ustawienia projektu. Kliknij symbol + obok pozycji akcji , wpisz nazwę “Change Projectile dla nowego mapowania akcji i wybierz klawisz Tab :

Otwórz Blueprint BP_PlayerCharacter i  na wykresie zdarzeń dodaj zdarzenie InputAction Change Projectile i funkcję Change Projectile, którą stworzyliśmy w C++.

W zakładce My Blueprint kliknij ikonę oka i zaznacz opcję Show Inherited Variables , aby wyświetlić zmienne, które zdefiniowaliśmy w klasie C++. Zmienne znajdują się w kategorii Pocisk.

Wybierz Array ProjectileClasses. Na karcie Details dodaj 3 elementy do tablicy i wybierz klasy Blueprint BP_PlayerProjectile1BP_PlayerProjectile2 i BP_PlayerProjectile3. Każda z nich przedstawia rodzaj pocisku.

Na wykresie zdarzeń, w zdarzeniu InputAction Fire, poszukaj węzła SpawnActor . Kliknij i przeciągnij zmienną CurrentProjectileClass z Myblueprint i upuść ją na parametr Class SpawnActor.

Kiedy gracz strzela SpawnActor tworzy instancję klasy, która jest przechowywana w zmiennej CurrentProjectileClass.


Źródło:https://romeroblueprints.blogspot.com/2021/04/playercharacter-blueprint-adjustments.html

PlayerCharacter: Array of PlayerProjectile

PlayerCharacter można zmienić typ PlayerProjectile , który jest używany podczas gry. Klasy reprezentujące różne typy PlayerProjectile zostaną dodane do TArray  w klasie PlayerCharacter C++.

Każdy element TArray jest typu TSubclassOf <APlayerProjectile>. Użycie TSubclassOf umożliwia przechowywanie odniesień do klasy APlayerProjectile lub do dowolnej z jej klas potomnych (podklas).

Poniższy kod to nowa wersja pliku PlayerCharacter.h zawierającego zmienne i funkcje potrzebne do zmiany pocisków. Nowa treść jest pogrubiona. Należy pamiętać, że przed UCLASS() jest makro, oraz deklaracja o APlayerProjectile klasy została wykonana. W ten sposób wystarczy dodać #include „PlayerProjectile.h” do pliku cpp.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "PlayerCharacter.generated.h"

class APlayerProjectile;

UCLASS()
class TUTOPART3_API APlayerCharacter : public ACharacter
{
  GENERATED_BODY()

public:
  // Sets default values for this character's properties
  APlayerCharacter();

protected:
  // Called when the game starts or when spawned
  virtual void BeginPlay() override;

public:	
  // Called every frame
  virtual void Tick(float DeltaTime) override;

  // Called to bind functionality to input
  virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) 
                                                                            override;

  UFUNCTION(BlueprintCallable, Category = Movement)
  void MoveForward(float Value);
	
  UFUNCTION(BlueprintCallable, Category = Movement)
  void MoveRight(float Value);
	
  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Projectile)
  TSubclassOf<APlayerProjectile> CurrentProjectileClass;
	
  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Projectile)
  TArray< TSubclassOf<APlayerProjectile> > ProjectileClasses;
	
  UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = Projectile)
  int32 IndexProjectileClass;
	
  UFUNCTION(BlueprintCallable, Category = Projectile)
  void ChangeProjectile();
};

Spójrzmy na każdą z nowych deklaracji:

  • TSubclassOf <APlayerProjectile> CurrentProjectileClass: Ta zmienna przechowuje odniesienie do klasy typu APlayerProjectile, która reprezentuje pocisk wybrany przez gracza.
  • TArray <TSubclassOf <APlayerProjectile>> ProjectileClasses:  Tablica przechowująca wszystkie odwołania do klas typu APlayerProjectile, które mogą być wybrane przez gracza. 
  • int32 IndexProjectileClass:  przechowuje indeks z pozycją w tablicy wybranego APlayerProjectile. 
  • void ChangeProjectile(): funkcja, która zmienia się na następny pocisk i aktualizuje zmienne. Kiedy osiągnie koniec, wraca do początku.

W pliku PlayerCharacter.cpp mamy definicję funkcji ChangeProjectile() . Ponadto w BeginPlay () funkcji, CurrentProjectileClass zmienna jest inicjowana z pierwszego elementu tablicy, który stanowi element o indeksie 0. Nowa wersja pliku wygląda następująco:

#include "PlayerCharacter.h"
#include "PlayerProjectile.h"

// Sets default values
APlayerCharacter::APlayerCharacter()
{
  // Set this character to call Tick() every frame.
  PrimaryActorTick.bCanEverTick = true;
}

// Called when the game starts or when spawned
void APlayerCharacter::BeginPlay()
{
  Super::BeginPlay();

  if(CurrentProjectileClass == nullptr && ProjectileClasses.Num() > 0)
  {
    CurrentProjectileClass = ProjectileClasses[0];
  }	
}

// Called every frame
void APlayerCharacter::Tick(float DeltaTime)
{
  Super::Tick(DeltaTime);
}

// Called to bind functionality to input
void APlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
  Super::SetupPlayerInputComponent(PlayerInputComponent);
}

void APlayerCharacter::MoveForward(float Value)
{
  AddMovementInput(GetActorForwardVector(), Value);
}

void APlayerCharacter::MoveRight(float Value)
{
  AddMovementInput(GetActorRightVector(), Value);
}

void APlayerCharacter::ChangeProjectile()
{
  IndexProjectileClass++;
	
  if(IndexProjectileClass == ProjectileClasses.Num()) 
  {
    IndexProjectileClass = 0;
  }
	
  CurrentProjectileClass = ProjectileClasses[IndexProjectileClass];
}

Źródło:https://romeroblueprints.blogspot.com/2021/03/playercharacter-array-of.html

PlayerCharacter: Konwertowanie Blueprint script do C++

W tym artykule, będziemy konwertować część skryptu Wzorca FirstPersonCharacter (przemianowany BP_PlayerCharacter ).

Decydując się na konwersję skryptu Blueprint do C ++, należy wziąć pod uwagę dwa ważne czynniki:

  • Złożoność : czasami konieczne jest wdrożenie logiki, która jest złożona lub obejmuje wiele obliczeń matematycznych. Ze względu na wizualny charakter Blueprint, tego typu skrypty mogą być mylące, gdy są reprezentowane przez węzły Blueprint, dzięki czemu implementacja w C ++ jest bardziej odpowiednia i czytelna.  
  • Szybkość :  szybkość wykonywania kodu C ++ jest większa niż w przypadku skryptu Blueprint. Nie oznacza to, że powinieneś przekonwertować wszystkie swoje Blueprints na C ++ tylko z tego powodu. Istnieje niezliczona ilość innych czynników, które będą określać wydajność projektu Unreal. Musisz sprawdzić, czy istnieją nietrywialne skrypty, które są wykonywane bardzo często, na przykład węzły Blueprint, które są połączone ze zdarzeniem Tick .

Przekonwertujemy prosty skrypt Blueprint na C ++, aby pokazać, jak to się robi. Otwórz Blueprint BP_PlayerCharacter i zobacz na wykresie zdarzenia działania, które są w ruchu . Usunąłem węzły związane z testem użytkowania HMD (Head Mount Display), aby przykład był prosty, jak pokazano na poniższym obrazku. 

Weźmy węzły Blueprint ze zdarzenia InputAxis MoveForward i przekonwertujmy je na pojedynczą funkcję C ++. W tym przykładzie istnieją tylko dwa węzły, ale gdyby było ich kilkadziesiąt, można by je również przekonwertować na pojedynczą funkcję C ++.  samą konwersję wykonamy dla zdarzenia InputAxis MoveRight .

Musimy znaleźć funkcje C ++ odpowiadające węzłom Blueprint. Pod nazwą węzła Blueprint znajduje się linia Target is … , która wskazuje klasę, w której zdefiniowano funkcję reprezentowaną przez węzeł. Na powyższym obrazku mamy dwa węzły, których celem jest aktor i dwa węzły z pionem docelowym . Wszystkie te funkcje będą dostępne w naszej klasie C ++ PlayerCharacter, ponieważ klasa Character dziedziczy zmienne i funkcje klasy Pawn, a klasa Pawn dziedziczy zmienne i funkcje klasy Actor .

Pierwszym krokiem jest wyszukanie funkcji w Unreal Engine API Reference . Poszukaj nazwy węzła Blueprint, usuwając puste miejsca, na przykład AddMovementInput . W dokumentacji API można zobaczyć opis parametrów funkcji. Niestety, dokumentacja API nie wskazuje, czy parametr jest opcjonalny. Aby to sprawdzić, spójrz na stronę funkcji w dokumentacji API, aby znaleźć ścieżkę i nazwę pliku nagłówkowego . Poszukaj pliku w folderze silnika swojego projektu . Otwórz plik i poszukaj nazwy funkcji w pliku. Deklaracja funkcji AddMovementInput jest wykonywana w następujący sposób:

UFUNCTION(BlueprintCallable, Category="Pawn|Input", meta=(Keywords="AddInput"))
virtual void AddMovementInput(FVector WorldDirection, float ScaleValue = 1.0f, 
                                                      bool bForce = false);

Zauważ, że parametry ScaleValue i bForce przyjmują wartości domyślne. Oznacza to, że te parametry są opcjonalne i funkcję AddMovementInput można wywołać, przekazując tylko parametr WorldDirection .

Wcześniej utworzyliśmy klasę C ++ PlayerCharacter, która ma być używana jako klasa nadrzędna Blueprint BP_PlayerCharacter . Otwórz plik PlayerCharacter.h i dodaj deklaracje dla nowych funkcji MoveForward () i MoveRight (), jak pokazano w kodzie poniżej.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "PlayerCharacter.generated.h"

UCLASS()
class TUTOPART3_API APlayerCharacter : public ACharacter
{
  GENERATED_BODY()

public:
  // Sets default values for this character's properties
  APlayerCharacter();

protected:
  // Called when the game starts or when spawned
  virtual void BeginPlay() override;

public:	
  // Called every frame
  virtual void Tick(float DeltaTime) override;

  // Called to bind functionality to input
  virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) 
                                                                            override;

  UFUNCTION(BlueprintCallable, Category = Movement)
  void MoveForward(float Value);
	
  UFUNCTION(BlueprintCallable, Category = Movement)
  void MoveRight(float Value);
};

W pliku PlayerCharacter.cpp mamy implementację funkcji MoveForward () i MoveRight () przy użyciu tej samej logiki, która była w skrypcie Blueprint.

#include "PlayerCharacter.h"

// Sets default values
APlayerCharacter::APlayerCharacter()
{
  // Set this character to call Tick() every frame.
  PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void APlayerCharacter::BeginPlay()
{
  Super::BeginPlay();	
}

// Called every frame
void APlayerCharacter::Tick(float DeltaTime)
{
  Super::Tick(DeltaTime);
}

// Called to bind functionality to input
void APlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
  Super::SetupPlayerInputComponent(PlayerInputComponent);
}

void APlayerCharacter::MoveForward(float Value)
{
  AddMovementInput(GetActorForwardVector(), Value);
}

void APlayerCharacter::MoveRight(float Value)
{
  AddMovementInput(GetActorRightVector(), Value);
}

Pierwszy parametr funkcji AddMovementInput () otrzymuje wartość zwracaną z wywoływanej funkcji.

Tylko uwaga dotycząca parametru Value używanego w funkcjach ruchu. Jeśli wartość jest ujemna, ruch będzie odbywał się w przeciwnym kierunku.

Skompiluj kod C ++.

Otwórz Blueprint BP_PlayerCharacter . Na wykresie zdarzeń zastąpimy węzły Blueprint, które są w ruchu wejściowym , naszymi funkcjami C ++. Zachowaj węzły zdarzeń InputAxis i usuń pozostałe.

Kliknij prawym przyciskiem myszy Blueprint Event Graph , poszukaj naszych funkcji C ++ w menu kontekstowym w kategorii Ruch i dodaj je do wykresu zdarzeń, który powinien wyglądać następująco:

Zwróć uwagę, że celem węzłów schematu jest postać gracza .

Zrobiliśmy ten prosty przykład, abyś mógł zrozumieć ten proces konwersji.


Źródło:https://romeroblueprints.blogspot.com/2021/03/playercharacter-converting-blueprint.html

PlayerCharacter: Reparenting w Blueprint

Gracz będzie reprezentowany w naszym projekcie przez Blueprint FirstPersonCharacter, który jest częścią szablonu First Person w Unreal Engine. Ale chcemy, aby część jego logiki znajdowała się w klasie C++.

Aby dowiedzieć Blueprint rodzic klasa C++, umieść kursor myszy nad Blueprint w Content Browser , aby wyświetlić okno z informacjami. Klasa nadrzędna C ++ to klasa należąca do jego klasy. Poniższy obraz przedstawia informacje dotyczące Blueprint FirstPersonCharacter , którego nadrzędną klasą C ++ jest Character.

Musimy stworzyć w C ++ klasę typu Character, która stanie się nową klasą nadrzędną FirstPersonCharacter Blueprint.

Content Browser, przejdź do TutoPart3 folder, który znajduje się wewnątrz C++ Classes. Kliknij prawym przyciskiem myszy wolne miejsce i wybierz opcję New C++ Class.

Na następnym ekranie wybierz klasę Character jako klasę nadrzędną i kliknij przycisk Next.

W polu Name wpisz PlayerCharacter. W polu Path zachowaj domyślny folder projektu. Kliknij przycisk Create Class.

Teraz zmieńmy Blueprint FirstPersonCharacter używać PlayerCharacter jako klasy nadrzędnej.

Ale najpierw zmienić nazwę Blueprint FirstPersonCharacter do BP_PlayerCharacter zachować standardową nazwę, która będzie używana przez innych klas w grze. Otwórz Blueprint i kliknij przycisk Class Settings. We właściwoścj wyszukaj i wybierz klasę PlayerCharacter.

Skompiluj i zapisz Blueprint

W następnym artykule przekonwertujemy część skryptu tego BP na klasę PlayerCharacter w języku C++.


Źródło:https://romeroblueprints.blogspot.com/2021/03/playercharacter-reparenting-blueprint.html

EnemyProjectile: Tworzenie Naprowadzającego pocisku

W tym artykule utworzymy klasę bazową C ++ reprezentującą pociski samonaprowadzające, które są wystrzeliwane z dział wroga.

Content Browser , przejdź do folderu TutoPart3który znajduje się wewnątrz C++ Classes. Kliknij prawym przyciskiem myszy wolne miejsce i wybierz opcję New C++ Class … :

Na następnym ekranie wybierz klasę aktora jako klasę nadrzędną i kliknij przycisk Next.

W polu Name wpisz EnemyProjectile. W polu Path zachowaj domyślny folder projektu. Kliknij przycisk Create Class.

EnemyProjectile klasa użyje cztery rodzaje elementów:

  • USphereComponent: jest używany jako komponent główny i do testowania kolizji.
  • UStaticMeshComponent: zawiera statyczną siatkę, która będzie wizualnie reprezentować pocisk.
  • UParticleSystemComponent: komponent z emiterem cząstek, który będzie używany do symulacji wpływu ognia na pocisk.
  • UProjectileMovementComponent: komponent używany do przemieszczania pocisku. Zostanie skonfigurowany tak, aby podążał za graczem.

Dodaj deklarację komponentów w pliku EnemyProjectile.h, która będzie wyglądać następująco:

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "EnemyProjectile.generated.h"

UCLASS()
class TUTOPART3_API AEnemyProjectile : public AActor
{
  GENERATED_BODY()
	
public:	
  // Sets default values for this actor's properties
  AEnemyProjectile();

protected:
  // Called when the game starts or when spawned
  virtual void BeginPlay() override;

public:	
  // Called every frame
  virtual void Tick(float DeltaTime) override;
	
  UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
  UStaticMeshComponent* StaticMesh;
	
  UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
  class USphereComponent* CollisionComponent;
	
  UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
  class UParticleSystemComponent* Particles;

  UPROPERTY(VisibleAnywhere, BlueprintReadOnly)	
  class UProjectileMovementComponent* ProjectileMovement;
	
};

W pliku EnemyProjectile.cpp mamy inicjalizację komponentów wykonana w konstruktorze. Nie zapomnij dodać linii #include dla komponentów

#include "EnemyProjectile.h"
#include "Engine/CollisionProfile.h"
#include "Components/SphereComponent.h"
#include "Particles/ParticleSystemComponent.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "Kismet/GameplayStatics.h"


// Sets default values
AEnemyProjectile::AEnemyProjectile()
{
  PrimaryActorTick.bCanEverTick = true;

  InitialLifeSpan = 10.f;
	
  CollisionComponent = CreateDefaultSubobject<USphereComponent>(
                                             TEXT("CollisionComponent"));
  RootComponent = CollisionComponent;
  CollisionComponent->InitSphereRadius(25.f);
  CollisionComponent->SetCollisionProfileName(
                              UCollisionProfile::BlockAllDynamic_ProfileName);

  StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
  StaticMesh->SetupAttachment(CollisionComponent);
	
  Particles = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("Particles"));
  Particles->SetupAttachment(StaticMesh);
	
  ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>(
                                             TEXT("ProjectileMovement"));
  ProjectileMovement->InitialSpeed = 300.f;
  ProjectileMovement->MaxSpeed = 300.f;
  ProjectileMovement->bRotationFollowsVelocity = true;
  ProjectileMovement->bIsHomingProjectile = true;
  ProjectileMovement->HomingAccelerationMagnitude = 300.f;
  ProjectileMovement->ProjectileGravityScale = 0.f;
}

// Called when the game starts or when spawned
void AEnemyProjectile::BeginPlay()
{
  Super::BeginPlay();
	
  APawn* PlayerPawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
	
  if(PlayerPawn)
  {
    ProjectileMovement->HomingTargetComponent = PlayerPawn->GetRootComponent();
  }
}

// Called every frame
void AEnemyProjectile::Tick(float DeltaTime)
{
  Super::Tick(DeltaTime);
}

Wykonane zostały następujące kroki przy konfiguracji UProjectileMovementComponent.

  • Przypisałem wartość true do zmiennej bRotationFollowsVelocity, aby pocisk obracał się, gdy zmienia kierunek
  • Przypisałem wartość true do zmiennej bIsHomingProjectile, aby wskazać, że jest to pocisk samonaprowadzający
  • Przypisałem wartość zmiennej HomingAccelerationMagnitude , która wskazuje przyspieszenie, z jakim pocisk będzie poruszał się w kierunku celu. Użyłem tej samej wartości, co prędkość pocisku
  • Usunąłem siłę grawitacji z pocisku, przypisując wartość 0 do zmiennej ProjectileGravityScale
  • Ostatnim krokiem jest przypisanie USceneComponent do zmiennej HomingTargetComponent, która będzie używana jako cel. Odbywa się to w funkcji BeginPlay(). Celem jest RootComponent gracza.  

Skompiluj kod C ++. Zasoby systemu static mesh oraz particle zostaną wybrane w Blueprint Child Poza tym początkowe wartości przypisane do komponentów mogą być modyfikowane w podklasach Blueprints. 


Źródło:https://romeroblueprints.blogspot.com/2021/04/enemyprojectile-creating-homing.html