Announcement

Collapse
No announcement yet.

What is the proper way to set up an APawn subclass for blueprintability?

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

    What is the proper way to set up an APawn subclass for blueprintability?

    I'm trying to create an APawn subclass in C++, because I'm going to do more math than would be comfortable in blueprint.

    I'd like this Pawn to have a hierarchy of static mesh components: Body -> Femur -> Tibia -> Metatarsal.
    (Actually, there are more Femurs, etc; one chain per leg.)

    I do NOT want to do this as a skinned mesh; I want to define a separate mesh for each.

    Now, I've set up the APawn with a number of properties:

    Code:
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    UStaticMeshComponent *Root;
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    UStaticMeshComponent *Body;
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    UStaticMeshComponent *FrontLeftFemur;
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    UStaticMeshComponent *FrontLeftTibia;
    ....
    I then create the Root and the different components as follows:

    Code:
    (inside the constructor, taking an FObjectInitializer):
    
    	Root = OI.CreateAbstractDefaultSubobject<UStaticMeshComponent>(this, TEXT("Root"));
    	RootComponent = Root;	//	for AActor
    	Root->SetupAttachment(nullptr, TEXT("Root"));
    	Body = NewObject<UStaticMeshComponent>(this, L"Body");
    	Body->AttachToComponent(Root, FAttachmentTransformRules::KeepRelativeTransform, L"Body");
    	Body->RegisterComponent();
    	FrontLeftFemur = MakeLegBone(BodyMesh, L"FrontLeftFemur");
    	FrontLeftTibia = MakeLegBone(LegLeftUpper, L"FrontLeftTibia");
            .....
    The MakeLegBone function does this:

    Code:
    UStaticMeshComponent *AStompyRobotPawn::MakeLegBone(UStaticMeshComponent *Parent, FName const &Name)
    {
    	UStaticMeshComponent *ret = NewObject<UStaticMeshComponent>(this, Name);
    	ret->AttachToComponent(Parent, FAttachmentTransformRules::KeepRelativeTransform, FName(Name));
    	ret->RegisterComponent();
    	ret->bCreatedByConstructionScript_DEPRECATED = true;
    	ret->bAllowAnyoneToDestroyMe = true;
    	return ret;
    }

    I can create a blueprint subclass of this object, call it BP_Pawn, and then open it up.
    First, it doesn't open with a Viewport, so I have to click the "open full blueprint editor" to get there.
    Second, when I try to save, I get the error:

    Can't save .../Documents/Unreal Projects/TestProject/Content/NewBlueprint.uasset: Graph is linked to private object(s) in an external package.
    External Object(s):
    Body
    LeftFrontFemur
    LeftFrontTibia
    ...

    Try to find the chain of references to that object (may take some time)?

    I think I'm perhaps on the right way, but there are specifics about how to create these components to make them show up properly in the blueprint editor, and then be able to save them.
    What am I missing here? I've read the documentation for the APawn and UStaticMeshComponent classes, but they aren't particularly helpful with the "why" of the outer surroundings.
    What's a good link for the surrounding environment knowledge I need to have to move forward with this?

    #2
    Use CreateDefaultSubobject<>() instead of NewObject<>()
    | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

    Comment


      #3
      Originally posted by BrUnO XaVIeR View Post
      Use CreateDefaultSubobject<>() instead of NewObject<>()
      This. Working fine for me with DefaultSubobject.

      also:

      Code:
      	Root->SetupAttachment(nullptr, TEXT("Root"));
      why?
      @CarstenZarbock - Follow me on Twitter, thank you

      Comment


        #4
        You should also mark you component properties as (VisibleAnywhere, BlueprintReadOnly), plus add a category specifier.
        With subobjects, editable means you can actually recreate the subobject from a blueprint rather than just edit it's properties, which I don't think is what you intend and has some limitations and side effects regarding how they show up.

        Comment


          #5
          Use CreateDefaultSubobject<>() instead of NewObject<>()
          Why? What is the different between CreateDefaultSubobject<> and NewObject<> ?
          What about NewObject<> would cause the problems with the chain reference?

          Root->SetupAttachment(nullptr, TEXT("Root"));
          why?
          Why not?
          It looks like each component needs to be attached to something, and I'd like it to be attached to the actor itself.
          What's mistaken about this assumption?

          VisibleAnywhere, BlueprintReadOnly
          OK, I'll try that. Thanks! The description "has some side effects" is somewhat helpful, and more precision (or, ideally, a pointer to the documentation that actually specifies these side effects) would be great!

          Do I need to RegisterComponent the root component? The documentation just says "adds to outer Actor's Components array" but doesn't tell me what happens if it's not there, or whether some components are auto-registered.
          Last edited by jwatte; 02-27-2017, 12:50 AM.

          Comment


            #6
            Originally posted by jwatte View Post
            Why not?
            It looks like each component needs to be attached to something, and I'd like it to be attached to the actor itself.
            What's mistaken about this assumption?
            Yes, but "nullptr" doesn't mean you're attaching it to the actor - you're just trying to attach it to something nonexistent.
            I'm not sure, but the first created subobject will be setup as the rootcomponent by default - if you don't attach it to something else or the default root scene component.
            (RootComponent = Root

            Code:
            Root->SetupAttachment(nullptr, TEXT("Root"));
            So that's pretty much useless code and would crash - if there wouldn't be an exception handler for a nullptr inside SetupAttachment().
            @CarstenZarbock - Follow me on Twitter, thank you

            Comment


              #7
              Originally posted by jwatte View Post
              Why? What is the different between CreateDefaultSubobject<> and NewObject<> ?
              What about NewObject<> would cause the problems with the chain reference?

              OK, I'll try that. Thanks! The description "has some side effects" is somewhat helpful, and more precision (or, ideally, a pointer to the documentation that actually specifies these side effects) would be great!

              Do I need to RegisterComponent the root component? The documentation just says "adds to outer Actor's Components array" but doesn't tell me what happens if it's not there, or whether some components are auto-registered.
              It's just one of UE4's many rules, never call NewObject from within a UObject class constructor. In a constructor, you're creating a default subobject (something that should exist for every instance of that class) and that needs the special handling provided by CreateDefaultSubobject.

              As for the EditAnywhere side effects, you should be able to see the difference if you try it. Properties get displayed in a non-standard way, all categories collapsed by default. Also it may not play nice with the component list in Blueprints, I don't remember exactly. Documentation link? That's optimistic

              And as for registering, pretty certain there's no need to manually register any component if it's created as a subobject in the constructor, they should all get auto-registered.

              Comment


                #8
                Alright, that gives me something to go on. Thanks all!
                (And, in fact, it does work as I expect when I use CreateDefaultSubobject<>())

                "You should never use NewObject in object construction" is a fine rule, I guess, I just would like to know where I can read up on this rule (and others like it) without having to post in forums for each function I'm trying to use ...

                Comment

                Working...
                X