Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[Unreal Engine] Wywoływanie metod klas dziedziczących po ActorComponent.

Ostatnio zmodyfikowano 2018-10-26 20:00
Autor Wiadomość
latajacaryba
Temat założony przez niniejszego użytkownika
[Unreal Engine] Wywoływanie metod klas dziedziczących po ActorComponent.
» 2018-10-07 14:53:25
Witam,
Mam pytanie odnośnie Unreal Engine'a, na które im bardziej próbuję znaleźć odpowiedź, tym mniej rozumiem. Mianowicie; skoro aktor przechowuje kontener (wskaźników do?) ActorComponentów, to w jaki sposób wywoływać metody klas dziedziczących po ActorComponent, skoro nie wiemy przecież, jaki faktyczny obiekt kryje się pod danym indeksem konetnera? Powiedzmy, że chcę wywołać metodę AddRadialForce(...) która znajduje się w klasie UMovementComponent, która to klasa jest potomkiem wspomnianego ActorComponent. Mam więc tylko tablicę ActorComponentów (wskaźników do nich?) i wiem, że gdzieś tam jest (lub nie, kto wie?) UMovementComponent. Klasa ActorComponent tej metody nie zawiera, tak że nie jest możliwe dowolne wywoływanie sobie tej metody na każdym obiekcie tablicy.

Proszę o naprowadzenie mnie na odpowiednie tory, bo póki co kompletnie nie rozumiem jak miałoby to działać. Prawdopodobnie po prostu źle zrozumiałem jak ma to w UE działać, dlatego byłbym wdzięczny za sprostowanie  :\
P-172554
pekfos
» 2018-10-07 15:38:05
P-172555
michal11
» 2018-10-07 18:53:06
Przecież nie odwołujesz się do komponentów aktora bezpośrednio przez indeks.

Konwencja jest taka, ze przy dodawaniu komponentu do aktora dodajesz również funkcje "getter" pobierająca ten komponent (spójrz sobie jak to wygląda w np. ACharacter, przykładowa funkcja http://api.unrealengine.com​/INT/API/Runtime/Engine​/GameFramework/ACharacter​/GetMesh/index.html). Masz jeszcze funkcję w aktorze FindComponentByClass<> (http://api.unrealengine.com​/INT/API/Runtime/Engine​/GameFramework/AActor​/FindComponentByClass/1​/index.html) i podobne. Jeszcze innym sposobem jest wywoływanie funkcji na komponencie przez aktora, wtedy aktor ma funkcję AddRadialForce i przekazuje po prostu argumenty dalej do odpowiedniego komponentu (tak działa np. SetActorLocation() w aktorze). Każde to rozwiązanie ma swoje plusy i minusy i od ciebie zależy które wybierzesz i które pasuje najlepiej do danego problemu i architektury gry którą robisz. Jeszcze na koniec mały protip, używanie FindComponentByClass<> jest raczej niepolecane ze względu na potencjalne wysoki koszt wykonania (w najgorszym przypadku iteracja po wszystkich komponentach aktora).
P-172564
latajacaryba
Temat założony przez niniejszego użytkownika
» 2018-10-07 20:25:56
Dziękuję Wam za odpowiedzi :)

@michal11
odnośnie funkcji getter; jak ją dodać? Bo w przykładzie który podałeś wygląda na to, że jest to zwykła metoda klasy ACharacter. Jak więc przypisać do metody obiekt, który ma zwracać (zakładając, że metoda ta nie jest obiektem funkcyjnym a więc nie może posiadać stanu)?

Co do sposobu z metodą w klasie Actor; chyba nie do końca go zrozumiałem, bo nasuwa mi się pytanie, skąd sam Actor ma wiedzieć, gdzie przetrzymuje obiekt na którego rzecz ma wywołać metodę, skoro ma tylko kontener komponentów?

No i na koniec, czy sposoby (oprócz tego z wyszukiwaniem obiektów po typie) nie naruszają zasady open-closed? Bo po dodaniu nowego typu komponentu muszę tworzyć w klasie Actor funkcję get, lub metodę, która wywołana wywołuje metodę już konkretnego komponentu.

Mile widziane byłby jakieś opisy źródłowe tego, jak to ma działać ^^
P-172567
michal11
» 2018-10-08 00:57:57
Może prościej będzie z przykładem

C/C++
UCLASS()
class AProjectile
    : public AActor
{
    GENERATED_UCLASS_BODY(); // ten srednik tutaj jest bledem ale bez niego rozjezdza się formatowanie
public:
   
    FORCEINLINE USphereComponent * GetCollisionComp() const { return CollisionComp; }
    FORCEINLINE UStaticMeshComponent * GetProjectileMesh() const { return ProjectileMesh; }
    FORCEINLINE UProjectileMovementComponent * GetProjectileMovement() const { return ProjectileMovement; }
   
protected:
   
    UPROPERTY( VisibleAnywhere, Category = "Projectile" )
    USphereComponent * CollisionComp;
   
    UPROPERTY( VisibleAnywhere, Category = "Projectile" )
    UStaticMeshComponent * ProjectileMesh;
   
    UPROPERTY( VisibleAnywhere, Category = "Projectile|Movement" )
    UProjectileMovementComponent * ProjectileMovement;
   
};

getter to metoda która coś zwraca i zwykle przyjmuję nazwę get… (dlatego takie funkcje nazywane są getterami właśnie).


słowa klucze które mogą ci trochę rozjaśnić to "cast" i "rtti" (plus to co zalinkował pekfos).
P-172573
latajacaryba
Temat założony przez niniejszego użytkownika
» 2018-10-26 14:03:40
Chyba trochę źle zrozumiałem zasadę działania UE... A więc gwoli ścisłości; to nie tak, że komponenty trzymane są w jednej tablicy? Tak bym wnioskował z powyższego przykładu, skoro występują tam wskaźniki do konkretnych komponentów i nie są one elementami tablicy. Z drugiej strony jak wywoływać FindComponentByClass<> jeśli nie mam jakiegoś zbioru komponentów?
P-172681
michal11
» 2018-10-26 20:00:41
W aktorze komponent są trzymane w tablicy i dodatkowo scene komponenty są trzymane hierarchicznie (spójrz na RootComponent). Nic nie stoi na przeszkodzie żeby mieć 2 wskaźniki na ten sam obiekt (komponent), jeden wskaźnik w tablicy w aktorze i dugi jako składowa klasy do którego można się odwoływać bezpośrednio.

FindComponentByClass<> wywołujesz na dowolnym aktorze i on przeszukuje tablicę komponentów w aktorze.


Edit.
Może fragment nagłówka Actor.h ci trochę bardziej rozjaśni sytuację

C/C++
UCLASS( /*...*/ )
class ENGINE_API AActor
    : public UObject
{
    GENERATED_BODY();
   
protected:
    /** Collision primitive that defines the transform (location, rotation, scale) of this Actor. */
    UPROPERTY( BlueprintGetter = K2_GetRootComponent, Category = "Utilities|Transformation" )
    USceneComponent * RootComponent;
   
private:
    /**
    * All ActorComponents owned by this Actor. Stored as a Set as actors may have a large number of components
    * @see GetComponents()
    */
    TSet < UActorComponent *> OwnedComponents;
};


i fragment pliku Actor.cpp
C/C++
UActorComponent * AActor::FindComponentByClass( const TSubclassOf < UActorComponent > ComponentClass ) const
{
    UActorComponent * FoundComponent = nullptr;
   
    if( UClass * TargetClass = ComponentClass.Get() )
    {
        for( UActorComponent * Component: OwnedComponents )
        {
            if( Component && Component->IsA( TargetClass ) )
            {
                FoundComponent = Component;
                break;
            }
        }
    }
   
    return FoundComponent;
}

czyli jak widać pomyliłem się i komponent są trzymane w secie a nie tablicy.
P-172682
« 1 »
  Strona 1 z 1