Originally posted by Maxime.Dupart
View Post
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); };
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(); };
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.
Comment