Announcement

Collapse
No announcement yet.

Plugin Object Pool Component

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

    Originally posted by Maxime.Dupart View Post
    Hello Bruno,
    I've just bought your plugin to handle the classic issue of projectile/bullet spawning.

    So far, in C++ i have Reparent-ed my bullets from AActor to APooledActor, changed their ProjectileMovementComponent to your PooledProjectile .

    in the level, i created a pool on an empty actor in the level using the Subclass of a bullet i'm using as test.

    Right now my bullets are spawned in C++ and destroyed in Blueprints.
    Not 100% sure on how i should handle the spawning, and how to get a reference to the pool via C++.

    That Blueprint demo example project would be something like this in C++ (without touching any blueprint side parameters)...

    (UE4.17) Example of a Pooled Actor class created in C++, named APlayerBulletRank3, with a Pooled Projectile Component attached:

    PlayerBulletRank3.h
    Code:
    #pragma once
    
    #include "OBJPool.h"
    
    #include "CoreMinimal.h"
    #include "GameFramework/Actor.h"
    #include "PlayerBulletRank3.generated.h"
    
    UCLASS()
    class POOL_API APlayerBulletRank3 : public APooledActor
    {
        GENERATED_BODY()
        //
        APlayerBulletRank3();
    
    protected:
    
        UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (DisplayName = "Projectile Component"))
        UPooledProjectile* ProjectilePhyX;
    
    public:
    
        UPROPERTY(EditAnywhere, BlueprintReadOnly)
        float BulletSpeed = 3000;
    
        /// Manually fire this Projectile, instead of relying on Component Initialization.
        UFUNCTION(Category = "Projectile", BlueprintNativeEvent, meta = (DisplayName = "Shoot", Keywords = "shoot projectile"))
        void Shoot(); virtual void Shoot_Implementation();
    
        /// Manually stops this Projectile, instead of relying on Component Destruction.
        UFUNCTION(Category = "Projectile", BlueprintNativeEvent, meta = (DisplayName = "Break", Keywords = "break projectile"))
        void Break(); virtual void Break_Implementation();
    
        UFUNCTION()
        void OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult& Hit);
    
    };
    PlayerBulletRank3.cpp
    Code:
    #include "GAME.h"
    #include "PlayerBulletRank3.h"
    
    
    // Sets default values
    APlayerBulletRank3::APlayerBulletRank3()
    {
        UStaticMeshComponent* ProjectileMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Projectile Mesh"));
        RootComponent = ProjectileMesh;
    
        static ConstructorHelpers::FObjectFinder<UStaticMesh> ProjectileAsset(TEXT("StaticMesh'/Game/TwinStick/Meshes/TwinStickProjectile.TwinStickProjectile'"));
        if (ProjectileAsset.Succeeded()) { ProjectileMesh->SetStaticMesh(ProjectileAsset.Object); }
    
        ProjectileMesh->SetEnableGravity(false);
        ProjectileMesh->SetSimulatePhysics(true);
        ProjectileMesh->bGenerateOverlapEvents = true;
        ProjectileMesh->SetNotifyRigidBodyCollision(true);
        ProjectileMesh->SetCollisionProfileName(FName("Projectile"));
        ProjectileMesh->SetCollisionResponseToAllChannels(ECR_Ignore);
        ProjectileMesh->SetCollisionResponseToChannel(ECC_Pawn,ECR_Block);
        ProjectileMesh->SetCollisionResponseToChannel(ECC_WorldStatic,ECR_Block);
        ProjectileMesh->SetCollisionResponseToChannel(ECC_WorldDynamic,ECR_Block);
        ProjectileMesh->OnComponentHit.AddDynamic(this,&APlayerBulletRank3::OnHit);
    
        //
    
        ProjectilePhyX = CreateDefaultSubobject<UPooledProjectile>(TEXT("Projectile Component"));
        ProjectilePhyX->MaxSpeed = BulletSpeed;
        ProjectilePhyX->InitialSpeed = BulletSpeed;
        ProjectilePhyX->Direction = FVector::ForwardVector;
    
        OnPoolBeginPlay.AddDynamic(this,&APlayerBulletRank3::Shoot);
        OnPoolEndPlay.AddDynamic(this,&APlayerBulletRank3::Break);
    }
    
    void APlayerBulletRank3::Shoot_Implementation() {
        ProjectilePhyX->InitialSpeed = BulletSpeed;
        ProjectilePhyX->MaxSpeed = BulletSpeed;
        ProjectilePhyX->Shoot();
    }
    
    void APlayerBulletRank3::Break_Implementation() {
        ProjectilePhyX->Break();
    }
    
    void APlayerBulletRank3::OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult &Hit)
    {
        if (!OtherActor->IsValidLowLevelFast() || !OtherComponent->IsValidLowLevelFast()) {ReturnToPool(); return;}
        //
        if ((OtherActor != this) && OtherComponent->IsAnySimulatingPhysics()) {
            OtherComponent->AddImpulseAtLocation(GetVelocity()*20,GetActorLocation(),NAME_None);
            GEngine->AddOnScreenDebugMessage(1,1.f,FColor::Red,FString::Printf(TEXT("HIT! : %s"),*OtherActor->GetName()));
            /// Apply here amount of damage to OtherActor based on  Weapon/Bullet  class...
        }
        //
        ReturnToPool();
    }

    (UE4.17) Example of an Empty Actor created in C++, inside Game's module, used as a container with a Pool Component attached, made to spawn bullets of type APlayerBulletRank3:

    PlayerBulletRank3Pool.h
    Code:
    #pragma once
    
    #include "PlayerBulletRank3.h"
    
    #include "CoreMinimal.h"
    #include "GameFramework/Actor.h"
    #include "Runtime/Engine/Public/TimerManager.h"
    #include "PlayerBulletRank3Pool.generated.h"
    
    UCLASS()
    class POOL_API APlayerBulletRank3Pool : public AActor
    {
        GENERATED_BODY()
        //
        APlayerBulletRank3Pool();
    
    private:
    
        UPROPERTY()
        FTimerHandle TimerHandle;
    
    protected:
    
        UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (DisplayName = "Pool Component"))
        UObjectPool* BulletPool;
    
        // Called when the game starts or when created
        virtual void BeginPlay() override;
    
    public:
    
        UFUNCTION()
        void Fire();
    
    };
    PlayerBulletRank3Pool.cpp
    Code:
    #include "GAME.h"
    #include "PlayerBulletRank3Pool.h"
    
    
    // Sets default values
    APlayerBulletRank3Pool::APlayerBulletRank3Pool()
    {
        UBoxComponent* PoolRoot = CreateDefaultSubobject<UBoxComponent>(TEXT("Volume"));
        PoolRoot->SetCollisionEnabled(ECollisionEnabled::NoCollision);
        PoolRoot->SetCollisionObjectType(ECC_WorldStatic);
        RootComponent = PoolRoot;
    
        //
    
        BulletPool = CreateDefaultSubobject<UObjectPool>(TEXT("Pool Component"));
        BulletPool->TemplateClass = APlayerBulletRank3::StaticClass();
        BulletPool->AutoInitialize = true;
        BulletPool->PoolSize = 20;
    }
    
    // Called when the game starts or when created
    void APlayerBulletRank3Pool::BeginPlay()
    {
        Super::BeginPlay();
        //
        const FTimerDelegate Timer = FTimerDelegate::CreateUObject(this,&APlayerBulletRank3Pool::Fire);
        GetWorld()->GetTimerManager().SetTimer(TimerHandle,Timer,1.0f,true);
    }
    
    void APlayerBulletRank3Pool::Fire() {
        bool Result;
        FPoolSpawnOptions SpawnOptions;
        SpawnOptions.ActorTickEnabled = true;
        SpawnOptions.EnableCollision = true;
        SpawnOptions.SimulatePhysics = true;
        SpawnOptions.CollisionType = EPoolCollisionType::QueryAndPhysics;
        //
        FTransform SpawnTransform = FTransform(GetTransform().GetRotation().GetForwardVector().ToOrientationRotator(),GetTransform().GetTranslation(),FVector(1.f,1.f,1.f));
        //
        for (auto &BLT : BulletPool->GetInactiveObjects<APlayerBulletRank3>()) {
            float BulletSpeed = FMath::RandRange(500,3000);
            BLT->BulletSpeed = BulletSpeed;
        }
        //
        auto Projectile = BulletPool->BeginDeferredSpawnFromPool(this,BulletPool,SpawnOptions,SpawnTransform,ESpawnActorCollisionHandlingMethod::AlwaysSpawn,this,false,Result);
        auto Bullet = Cast<APlayerBulletRank3>(Projectile);
        if (Bullet) {
            BulletPool->FinishDeferredSpawnFromPool(Bullet,SpawnTransform);
            UE_LOG(LogTemp,Warning,TEXT("{Pool}:: FIRED!"));
        }
    }

    GAME.Build.cs:
    Code:
    PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
    
    PrivateDependencyModuleNames.AddRange(new string[] { "OBJPool" });

    Now all it takes is placing the Empty Actor into the Game's level.
    If was this a weapon then I'd spawn from Pool a bullet in the location of the gun's barrel and using its axis orientation to automatically aim the bullet then just let it go.
    Last edited by BrUnO XaVIeR; 10-01-2017, 08:03 PM.
    | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

    Comment


      Oh boy, thank you for your fast answer Bruno it's more than i needed !
      *rate 5 stars on Marketplace*
      LinkedIn | Link custom Shaders in 4.21/4.22/4.23 | Atmosphere Modelisation | Distance Matching Locomotion | Nvidia GameWorks builds - 4.19.2 : VXGI2.0, Blast, HairWorks, Flow - Plugins: VictoryBP

      Comment


        Hi Bruno.

        I've just bought this plugin hoping it will help me out. Although I now realise it may not perfectly drop into my project.

        To cut a long story short, my blueprint creates lots of static mesh components to create 3d text (I have 256 static meshes for each character in the ascii set). My blueprint arranges these to form text, but it's hitching a lot of the time if there are quite a few characters. Am I right in thinking your plugin won't handle static mesh components? Should I instead create a generic blueprint actor which just contains a static mesh component which I can set?

        What do you think?

        Thanks

        Comment


          Originally posted by Dannington View Post
          Hi Bruno.

          I've just bought this plugin hoping it will help me out. Although I now realise it may not perfectly drop into my project.

          To cut a long story short, my blueprint creates lots of static mesh components to create 3d text (I have 256 static meshes for each character in the ascii set). My blueprint arranges these to form text, but it's hitching a lot of the time if there are quite a few characters. Am I right in thinking your plugin won't handle static mesh components? Should I instead create a generic blueprint actor which just contains a static mesh component which I can set?

          What do you think?

          Thanks
          Your problem sounds like excessive drawcalls.
          This plugin doesn't batch drawcalls, so you won't see any performance gains from what you're doing.

          And yes, pooling happens on Actor level together with all its Components; creating or deleting Components won't make any use of the pooling system.
          | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

          Comment


            Thanks. Just to be clear - the hitch only happens when I spawn the mesh components, when it’s done performance is fine. Actually, looking in to pooling may have given me an answer in that I’m going to try to make my own pool of SM components at startup - say 500 in an array, then reuse them rather than destroying and creating them as I do at the moment. This should eliminate the memory allocation part of the process which I gather may be the cause of the hitching.

            thanks for the plugin anyway - I can use it in a separate part of the same project for some more performance gains.

            Comment


              Originally posted by Dannington View Post
              Thanks. Just to be clear - the hitch only happens when I spawn the mesh components, when it’s done performance is fine. Actually, looking in to pooling may have given me an answer in that I’m going to try to make my own pool of SM components at startup - say 500 in an array, then reuse them rather than destroying and creating them as I do at the moment. This should eliminate the memory allocation part of the process which I gather may be the cause of the hitching.

              thanks for the plugin anyway - I can use it in a separate part of the same project for some more performance gains.
              Did you try hierarchical static mesh instancing for this?
              https://docs.unrealengine.com/latest...f/bOjYP-c4qhA/
              | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

              Comment


                I possibly went on a bit of a wild goose chase there following your comment on HISM’s - but i’m right in thinking it only replicates a single mesh right, the same as a regular ISM? I have about 200 different meshes for my ascii character set. I’m still thinking of using actors instead of SM components so I can use your pool system.

                Comment


                  You can attach one ISM Component for each letter mesh then instantiate them as needed.
                  I'm not sure if nowadays they force you to instantiate only the one main static mesh component of an Actor, but back then when I tested it I was able to use different mesh components per ISM Components inside the Blueprint Actor and instantiate them through Blueprint Nodes separately.
                  | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

                  Comment


                    After removing character pool component from "level placed"-blueprint (it holds all pools to be spawned with the node), editor wont load the project/level anymore. Until I renamed the blueprint.

                    Was getting this error in log:
                    [2017.10.20-22.57.55:326][ 0]LogWindows: Error: Fatal error: [File:\Build\++UE4+Release-4.17+Compile\Sync\Engine\Source\Runtime\CoreUObject\Private\UObject\LinkerLoad.cpp] [Line: 2277]
                    [2017.10.20-22.57.55:326][ 0]LogWindows: Error: Failed import: ArmPoolNewComp_C ArmPoolNewComp_C /Game/AAObjectPools/UnitPoolStorageBP.UnitPoolStorageBP_C:ArmPoolNewComp_GEN_VARIABLE (file B:/WarProject17/Content/AAObjectPools/UnitPoolStorageBP.uasset)


                    Comment


                      When delete any asset in level, replace references then clean redirectors.
                      This isn't just for pool actors, its safety procedure for anything you delete which is referred by other actors.
                      Never click the "Force Delete" button unless you're pretty sure about it.
                      | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

                      Comment


                        Latest version updated to UE4.18 and submitted to Marketplace team for review.
                        | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

                        Comment


                          Was there any change in code?

                          Launcher says update is available for 4.18, but couldn't download it (because of Launcher bug). So I just bumped up the engine version and compiled it with the rest of stuff.
                          Should I download an update later? Anything changed in 4.18 version?

                          Comment


                            Originally posted by kjustynski View Post
                            Was there any change in code?

                            Launcher says update is available for 4.18, but couldn't download it (because of Launcher bug). So I just bumped up the engine version and compiled it with the rest of stuff.
                            Should I download an update later? Anything changed in 4.18 version?
                            I usually program with old versions and github 'live' versions of the engine in mind, so if you can recompile binaries yourself, most of the time, the plugin just works unless they've made a major engine change.
                            In the case of 4.16, 4.17 and 4.18, the plugin is pretty much the same code. You can compile binaries from 4.17 to use on 4.18, no problems there.
                            | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

                            Comment


                              Hi Bruno. Loving the performance gains with your plugin but am encountering a very annoying and possibly detrimental bug.

                              I essentially can't delete your "spawn actor from pool node" from my weapon blueprint class (4.17)

                              Whenever I try and unplug the pool reference, it crashes unreal every time, so I basically can't remove the node and just have to unplug it and put it aside in my blueprint and duplicate a new one. Picture attached.

                              Also, I couldn't figure out how to set many child classes for the node, so I just made a separate pool component with each child projectile template - Is this the correct workflow, or is there some way to avoid doing this? Finally, is there a way to set the velocity for when it bounces? Before I was dividing velocity by 5 but that isn't an exposed option for the pooled projectile parent class.

                              Thanks!

                              -DSP

                              Comment


                                Sorry to double post - but I've confirmed that I simply can't delete or plug into your node at all for some reason - Instant crash every time. I'm thinking to revert the blueprint and try again fresh, but I'm not too thrilled at the possibility of this being a recurring problem. Any ideas?

                                Comment

                                Working...
                                X