Bevor du anfängst
Stellen Sie sicher, dass Sie die folgenden Ziele im vorherigen Abschnitt, Ihren Charakter ausrüsten, erreicht haben:
Einen respawnenden Abhol-Gegenstand erstellt und Ihrem Level hinzugefügt
Einen ausrüstbaren Dart-Launcher erstellt, den Ihr Charakter halten und benutzen kann
Einfache Projektile
Ihr Charakter kann Ihren Dart-Launcher halten, und Ihr Werkzeug hat Steuerelementbindungen, um ihn zu benutzen, aber er wird seinem Namen nicht ganz gerecht. In diesem Abschnitt werden Sie Projektil-Logik implementieren, damit Pfeile aus dem ausgerüsteten Gegenstand schießen.
Die Unreal Engine hat eine Projektil-Bewegung-Komponente, die Sie einem Actor hinzufügen können, um ihn in ein Projektil zu verwandeln. Sie enthält viele hilfreiche Variablen wie Projektilgeschwindigkeit, Sprungkraft und Schwerkraftskalierung.
Hinsichtlich der Mathematik für die Implementierung von Projektilen müssen Sie verschiedene Dinge bedenken:
Die anfängliche Transformation, Geschwindigkeit und Richtung des Projektils.
Ob Sie Projektile aus der Mitte des Charakters oder dem Werkzeug, mit dem er ausgerüstet ist, spawnen wollen.
Welches Verhalten das Projektil zeigen soll, wenn es mit einem anderen Objekt kollidiert.
Eine Projektil-Basis-Klasse erstellen
Sie erstellen zuerst eine Basis-Projektil-Klasse und legen dann eine Subklasse davon an, um einzigartige Projektile für Ihre Werkzeuge zu erstellen.
Befolgen Sie diese Schritte, um eine Basis-Projektil-Klasse einzurichten:
Gehen Sie im Unreal Editor zu Werkzeuge > Neue C++-Klasse. Wählen Sie Actor als Parent-Klasse aus und benennen Sie die Klasse
FirstPersonProjectile. Klicken Sie auf Klasse erstellen.Gehen Sie in VS zu
FirstPersonProjectile.h. Deklarieren Sie oben in der Datei eineUProjectileMovementComponentund eineUSphereComponent.Sie verwenden die Kugel-Komponente, um Kollisionen zwischen dem Projektil und anderen Objekten zu simulieren.
C++// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "FirstPersonProjectile.generated.h" class UProjectileMovementComponent; class USphereComponent;Fügen Sie die Bezeichnet
BlueprintTypeundBlueprint-fähighinzu, um diese Klasse für Blueprints bereitzustellen:C++UCLASS(BlueprintType, Blueprintable) class FIRSTPERSON_API AFirstPersonProjectile : public AActorÖffnen Sie
FirstPersonProjectile.cpp, Fügen Sie oben in der Datei eine include-Anweisung für„GameFramework/ProjectileMovementComponent.h“ein, um die Projektil-Bewegung-Komponentenklasse einzubinden.
#include "FirstPersonProjectile.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "Components/SphereComponent.h"
// Sets default values
AFirstPersonProjectile::AFirstPersonProjectile()Projektilverhalten beim Tauftreffen auf Objekte implementieren
Um Ihr Projektil realistischer zu gestalten, können Sie dafür sorgen, dass es eine Kraft (einen Impuls) auf Objekte ausübt, die es trifft. Wenn Sie zum Beispiel auf einen physikfähigen Block schießen, würde das Projektil den Block über den Boden bewegen. Entfernen Sie dann das Projektil nach dem Einschlag, anstatt es seine Standard-Lebensdauer ablaufen zu lassen. Erstellen Sie eine OnHit()-Funktion, um dieses Verhalten zu implementieren.
Befolgen Sie diese Schritte, um das Trefferverhalten des Projektils zu implementieren:
Definiere in
FirstPersonProjectile.himpublic-Abschnitt einefloat-Eigenschaft namensPhysicsForce.Geben Sie ihr ein
UPROPERTY()-Makro mitEditAnywhere,BlueprintReadOnlyundCategory = „Projectile | Physics“.Das ist die ausgeübte Kraft des Projektils, wenn es auf etwas trifft.
C++// The amount of force this projectile imparts on objects it collides with UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Projectile | Physics") float PhysicsForce = 100.0f;Definieren Sie eine
void-FunktionOnHit(). Das ist eine Funktion von AActor, die abgerufen wird, wenn der Actor mit einer anderen Komponente oder einem anderen Actor kollidiert. Sie nimmt die folgenden Argumente entgegen:HitComp: Die Komponente, die getroffen wurde.OtherActor: Der Actor, der getroffen wurde.OtherComp: Die Komponente, die den Treffer erstellt hat (in diesem Fall die CollisionComponent des Projektils).NormalImpulse: Der normale Impuls des Treffers.Hit: EineFHitResult-Referenz, die mehr Daten über das Treffer-Event enthält (z. B. Zeit, Distanz und Ort).
C++// Called when the projectile collides with an object UFUNCTION() void OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);Implementieren Sie in
FirstPersonProjectile.cppdieOnHit()-Funktion, die Sie in Ihrer Header-Datei definiert haben. Prüfen Sie inOnHit()in einerif-Anweisung folgendes:OtherActorist nicht null und ist nicht das Projektil selbst.OtherCompist nicht null und simuliert ebenfalls Physik.
C++void AFirstPersonProjectile::OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit) { // Only add impulse and destroy projectile if we hit a physics if ((OtherActor != nullptr) && (OtherActor != this) && (OtherComp != nullptr) && OtherComp->IsSimulatingPhysics()) { } }Damit wird geprüft, ob das Projektil ein Objekt getroffen hat, das nicht es selbst war, und zur Physik fähig ist.
Verwenden Sie in der
if-AnweisungAddImpulseAtLocation(), um einen Impuls zurOtherComp-Komponente hinzuzufügen.Übergeben Sie dieser Funktion die Geschwindigkeit des Projektils multipliziert mit der
PhysicsForceund wenden Sie diese am Ort des Projektil-Actors an.C++if ((OtherActor != nullptr) && (OtherActor != this) && (OtherComp != nullptr) && OtherComp->IsSimulatingPhysics()) { OtherComp->AddImpulseAtLocation(GetVelocity() * PhysicsForce, GetActorLocation()); }AddImpulseAtLocation()ist eine Physik-Funktion in der Unreal Engine, die eine momentane Kraft (Impuls) auf ein simuliertes Physik-Objekt an einem spezifischen Ort im Welt-Bereich anwendet. Das ist nützlich, wenn Sie einen Aufprall simulieren möchten, etwa eine Explosion, die etwas fortschleudert, eine Kugel, die ein Objekt trifft, oder eine Tür, die sich öffnet.Da dieses Projektil einen anderen Actor getroffen hat, entfernen Sie den Projektor aus der Szene, indem Sie
Destroy()aufrufen.
Ihre fertige Funktion OnHit() sollte wie folgt aussehen:
void AFirstPersonProjectile::OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
// Only add impulse and destroy projectile if we hit a physics
if ((OtherActor != nullptr) && (OtherActor != this) && (OtherComp != nullptr) && OtherComp->IsSimulatingPhysics())
{
OtherComp->AddImpulseAtLocation(GetVelocity() * PhysicsForce, GetActorLocation());
Destroy();
}
}Mesh, Bewegung und Kollisionskomponenten des Projektils hinzufügen
Fügen Sie als Nächstes ein statisches Mesh, Projektilbewegungslogik und eine Kollisionskugel zu Ihrem Projektil hinzu und definieren Sie, wie sich das Projektil bewegen soll.
Um diese Komponenten zu deinem Projektil hinzuzufügen, befolge diese Schritte:
Deklariere in
FirstPersonProjectile.himöffentlicher-Abschnitt, deklarieren Sie einenTObjectPtrzu einerUStaticMeshComponentmit dem NamenProjectileMesh. Dies ist das statische Mesh des Projektils in der Welt.Geben Sie ihm ein
UPROPERTY()-Makro mitEditAnywhere,BlueprintReadOnlyundCategory = “Projectile | Mesh“.C++// Mesh of the projectile in the world UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Projectile | Mesh") TObjectPtr<UStaticMeshComponent> ProjectileMesh;Deklarieren Sie im
protected-Abschnitt:Ein
TObjectPtrzu einerUSphereComponentnamensCollisionComponent.Ein
TObjectPtrzu einerUProjectileMovementComponentnamensProjectileMovement.
Geben Sie beiden ein
UPROPERTY()-Makro mitVisibleAnywhere,BlueprintReadOnlyundCategory = „Projectile | Components“.C++// Sphere collision component UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Projectile | Components") TObjectPtr<USphereComponent> CollisionComponent; // Projectile movement component UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Projectile | Components") TObjectPtr<UProjectileMovementComponent> ProjectileMovement;Die ProjectileMovementComponent übernimmt die Bewegungslogik für Sie. Sie berechnet basierend auf Geschwindigkeit, Schwerkraft und anderen Variablen, wohin sich der Parent-Actor bewegen soll. Dann wendet sie während des
Ticksdie Bewegung auf das Projektil an.Erstellen Sie in
FirstPersonProjectile.cppin der Constructor-FunktionAFirstPersonProjectile()Standard-Unterobjekte für Mesh, Kollision und Projektilbewegungskomponenten des Projektils. Koppeln Sie dann das Projektil-Mesh an der Kollisionskomponente an.C++// Sets default values AFirstPersonProjectile::AFirstPersonProjectile() { // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. PrimaryActorTick.bCanEverTick = true; // Use a sphere as a simple collision representation CollisionComponent = CreateDefaultSubobject<USphereComponent>(TEXT("CollisionComponent")); check(CollisionComponent != nullptr);Rufen Sie
InitSphereRadius()auf, um dieCollisionComponentmit einem Radius von5.0fzu initialisieren.Legen Sie den Name des Kollisionsprofils der Kollisionskomponente auf
„Projectile“fest, indem SieBodyInstance.SetCollisionProfileName()verwenden.Im Unreal Editor werden Ihre Kollisionsprofile unter Projekt-Einstellungen > Engine > Kollision gespeichert, und Sie können bis zu 18 benutzerdefinierte Kollisionsprofile definieren, die Sie im Code verwenden können. Das Standardverhaltenn dieses „Projektil“-Kollisionsprofils ist Block und erstellt Kollisionen für jedes Objekt, mit dem es kollidiert.
C++CollisionComponent->InitSphereRadius(5.0f); // Set the collision profile to the "Projectile" collision preset CollisionComponent->BodyInstance.SetCollisionProfileName("Projectile");Sie haben vorhin eine
OnHit()-Funktion definiert, die aktiviert wird, wenn das Projektil etwas trifft, aber Sie benötigen eine Möglichkeit, um zu melden, wenn es zu einer solchen Kollision kommt. Verwenden Sie dazu dasAddDynamic()-Makro, um eine Funktion beiOnComponentHitEventinCollisionComponentzu abonnieren. Übergeben Sie diesem Makro dieOnHit()-Funktion.C++// Set up a notification for when this component hits something blocking CollisionComponent->OnComponentHit.AddDynamic(this, &AFirstPersonProjectile::OnHit);Legen Sie die
CollisionComponentals dieRootComponentdes Projektils und alsUpdatedComponentfür die Bewegung fest, die verfolgt werden soll.C++// Set as root component RootComponent = CollisionComponent; ProjectileMovement->UpdatedComponent = CollisionComponent;Initialisieren Sie die
ProjectileMovement-Komponente mit den folgenden Werten:InitialSpeed:Die anfängliche Geschwindigkeit des Projektils, wenn es spawnt. Setzen Sie dies auf3000.0f.MaxSpeed: Die maximale Geschwindigkeit des Projektils. Setzen Sie dies auf3000.0f.bRotationFollowVelocity: Ob das Objekt rotieren soll, um die Richtung seiner Geschwindigkeit zu erreichen. Zum Beispiel, wie ein Papierflieger beim Steigen und Fallen hoch- und runtergeht. Setzen Sie dies auf“True.bShouldBounce: Ob das Projektil von Hindernissen abprallen soll. Setzen Sie dies auf“True.
C++ProjectileMovement->UpdatedComponent = CollisionComponent; ProjectileMovement->InitialSpeed = 3000.f; ProjectileMovement->MaxSpeed = 3000.f; ProjectileMovement->bRotationFollowsVelocity = true; ProjectileMovement->bShouldBounce = true;
Lebensdauer des Projektils festlegen
Standardmäßig lassen Sie das Projektil einige Sekunden nach dem Abfeuern verschwinden. Allerdings können Sie beim Ableiten Ihrer Projektil-Blueprints im Editor damit experimentieren, diese Zeit zu ändern oder zu entfernen, um Ihr Level mit Schaumstoffdarts zu füllen!
Um das Projektil nach einigen Sekunden verschwinden zu lassen, befolgen Sie diese Schritte:
Deklarieren Sie in
FirstPersonProjectile.himpublic-Abschnitt einen Float namensProjectileLifespan.Geben Sie ihm ein
UPROPERTY()-Makro mitEditAnywhere,BlueprintReadOnlyundCategory = „Projectile | Lifespan“.Dies ist die Lebensdauer des Projektils in Sekunden.
C++// Despawn after 5 seconds by default UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Projectile | Lifespan") float ProjectileLifespan = 5.0f;Legen Sie in
FirstPersonProjectile.cppam Ende derAFirstPersonProjectile()-Constructor-Funktion dieInitialLifeSpandes Projektils aufProjectileLifespanfest, damit es nach fünf Sekunden verschwindet.C++// Disappear after 5.0 seconds by default. InitialLifeSpan = ProjectileLifespan;InitialLifeSpanist eine Eigenschaft, die von AActor geerbt wird. Ein Float-Wert bestimmt, wie lange der Actor lebt, bevor er stirbt. Ein Wert von0bedeutet, dass der Actor so lange lebt, bis das Spiel stoppt.
Ihre fertige FirstPersonProjectile.h sollte wie folgt aussehen:
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "FirstPersonProjectile.generated.h"
class UProjectileMovementComponent;
class USphereComponent;
Ihre fertige Constructor-Funktion AFirstPersonProjectile sollte wie folgt aussehen:
// Sets default values
AFirstPersonProjectile::AFirstPersonProjectile()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
// Use a sphere as a simple collision representation
CollisionComponent = CreateDefaultSubobject<USphereComponent>(TEXT("CollisionComponent"));
check(CollisionComponent != nullptr);
Charakter-Kamerarichtung abrufen
Projektile sollen aus dem Dart-Launcher selbst spawnen. Sie müssen also ein wenig rechnen, um herauszufinden, wo der Launcher ist und wohin er zeigt. Da der Launcher am Spieler-Charakter angekoppelt ist, ändern sich diese Werte basierend auf, wo sich der Charakter befindet und wohin er schaut.
Ihr First-Person-Charakter enthält einige der Positionsinformationen, die Sie zum Start eines Darts benötigen. Beginnen Sie also damit, Ihre Charakter-Klasse zu modifizieren, damit sie diese Informationen mit einem Linien-Trace erfasst und das Ergebnis zurückgibt.
Befolgen Sie diese Schritte, um mit einem Trace die benötigten Informationen von Ihrem Charakter abzurufen:
Öffnen Sie in VS die
.h- und.cpp-Dateien Ihres Charakters.Deklarieren Sie in der
.h- Datei impublic-Abschnitt eine neue Funktion namensGetCameraTargetLocation(), die einenFVectorzurückgibt. Diese Funktion gibt den Ort in der Welt zurück, zu dem der Charakter blickt.C++// Returns the location in the world the character is looking at UFUNCTION() FVector GetCameraTargetLocation();Implementieren Sie in der
.cpp-Datei Ihres Charakters die FunktionGetCameraTargetLocation(). Beginnen Sie mit der Deklaration eines FVector namensTargetPosition, der zurückgegeben werden soll.Erstellen Sie einen Zeiger auf
UWorld, indem SieGetWorld()aufrufen.C++// The target position to return FVector TargetPosition; UWorld* const World = GetWorld();Fügen Sie eine
if-Anweisung hinzu, um zu prüfen, obWeltnicht null ist. Deklarieren Sie in derif-Anweisung einFHitResultnamensHit.C++if (World != nullptr) { // The result of the line trace FHitResult Hit;FHitResultist eine Struktur in der UE, die Informationen über das Ergebnis einer Kollisionsabfrage speichert, darunter den Actor oder die Komponente, die getroffen wurden, und wo sie getroffen wurden.Um den Punkt zu finden, den der Charakter betrachtet, simulieren Sie einen Linien-Trace entlang des Vektors, den der Charakter betrachtet, zu einem entfernten Punkt. Wenn der Linien-Trace mit einem Objekt kollidiert, wissen Sie, wohin in der Welt Ihr Charakter blickt.
Deklarieren Sie zwei konstante FVector-Werte namens TraceStart und TraceEnd:
Setzen Sie
TraceStartauf die Position derFirstPersonCameraComponent.Setzen Sie
TraceEndaufTraceStartplus den Vorwärtsvektor der Kamera-Komponente, multipliziert mit einer sehr großen Zahl. Dies stellt sicher, dass der Trace weit genug geht, um mit den meisten Objekten in Ihrer Welt zu kollidieren, solange Ihr Charakter nicht in den Himmel blickt. (Wenn der Charakter in den Himmel blickt, istTraceEndder Endpunkt des Linien-Trace.)C++// Simulate a line trace from the character along the vector they're looking down const FVector TraceStart = FirstPersonCameraComponent->GetComponentLocation(); const FVector TraceEnd = TraceStart + FirstPersonCameraComponent->GetForwardVector() * 10000.0;
Rufen Sie
LineTraceSingleByChannel()aus derUWorldauf, um den Trace zu simulieren. Übergeben SieHit,TraceStart,TraceEndund einECollisionChannel::ECC_Visibility.Das simuliert eine Linien-Trace von
TraceStartbisTraceEnd, der mit allen sichtbaren Objekten kollidiert, und speichert das Ergebnis des Trace inHit.ECollisionChannel::ECC_Visibilityist der Kanal für das Tracing, und diese Kanäle definieren, welche Objekttypen Ihr Trace treffen soll. Nutzen SieECC_Visibilityfür Sichtlinie-Kameraprüfungen.C++World->LineTraceSingleByChannel(Hit, TraceStart, TraceEnd, ECollisionChannel::ECC_Visibility);Der
Hit-Wert enthält nun Informationen über das Trefferergebnis, etwa die Position und die Normale des Einschlags. Er weiß auch, ob der Treffer das Ergebnis einer Kollision mit einem Objekt war. Der Ort des Aufschlags (oder der Endpunkt der Trace-Linie) ist die Kameraziel-Position, die zurückgegeben werden soll.Nutzen Sie einen ternären Operator, um
TargetPositionentweder aufHit.ImpactPointzu setzen, wenn der Treffer ein blockierender Treffer war, oder aufHit.TraceEnd, wenn dies nicht der Fall war. Geben sie dann dieTargetPositionzurück.C++TargetPosition = Hit.bBlockingHit ? Hit.ImpactPoint : Hit.TraceEnd; } return TargetPosition;
Ihre fertige Funktion GetCameraTargetLocation() sollte wie folgt aussehen:
FVector AADventureCharacter::GetCameraTargetLocation()
{
// The target position to return
FVector TargetPosition;
UWorld* const World = GetWorld();
if (World != nullptr)
{
// The result of the line trace
FHitResult Hit;
Projektile mit DartLauncher::Use() spawnen
Nun, da Sie wissen, wohin der Charakter blickt, können Sie die restliche Projektil-Logik in der Use()-Funktion Ihres Dart-Launchers implementieren. Sie rufen den Ort und die Richtung zum Starten des Projektils ab, und spawnen dann das Projektil.
Befolgen Sie diese Schritte, um den Ort und die Drehung abzurufen, an denen das Projektil spawnen soll:
Fügen Sie in
DartLauncher.hoben in der Datei eine Vorwärts-Deklaration fürAFirstPersonProjectilehinzu.Deklarieren Sie im
public-Abschnitt eineTSubclassOf<AFirstPersonProjectile>-Eigenschaft namens ProjectileClass. Das ist das Projektil, das der Launcher spawnt. Geben Sie ihm dasUPROPERTY()-Makro mitEditAnywhereundCategory = Projectile.DartLauncher.hsollte nun wie folgt aussehen:C++// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "AdventureGame/EquippableToolBase.h" #include "AdventureGame/FirstPersonProjectile.h" #include "DartLauncher.generated.h" class AFirstPersonProjectile;DartLauncher.cpp, fügen Sie eine include-Anweisung für„Kismet/KismetMathLibrary.h“ hinzu. Projektil-Mathematik kann kompliziert sein, und diese Datei enthält mehrere nützliche Funktionen, die Sie zum Abfeuern von Projektilen verwenden werden.C++#include "DartLauncher.h" #include "Kismet/KismetMathLibrary.h" #include "AdventureGame/AdventureCharacter.h"Beginnen Sie mit der Implementierung der
Use()-Funktion von DartLauncher:Rufen Sie
UWorldmitGetWorld()ab.Fügen Sie eine
if-Anweisung ein, um zu prüfen, obWorldund dieProjectileClassnicht null sind.Rufen Sie in der
if-Anweisung die Position ab, zu der der Charakter blickt, indem SieOwningCharacter->GetCameraTargetLocation()aufrufen.
C++void ADartLauncher::Use() { UWorld* const World = GetWorld(); if (World != nullptr && ProjectileClass != nullptr) { FVector TargetPosition = OwningCharacter->GetCameraTargetLocation(); } }Auch wenn Sie Projektile aus dem Werkzeug spawnen möchten, das der Charakter hält, möchten Sie diese möglicherweise nicht direkt aus dem Zentrum des Objekts spawnen. Das
SKM_Pistol-Mesh des Dart-Launchers hat einen „Mündung“-Socket, mit dem Sie einen präzisen Spawnpunkt für Ihre Pfeile festlegen können.Deklarieren Sie einen neuen
FVectornamensSocketLocationund legen Sie diesen auf das Ergebnis des Aufrufs vonGetSocketLocation(„Muzzle“)auf derToolMeshComponentfest.C++// Get the correct socket to spawn the projectile from FVector SocketLocation = ToolMeshComponent->GetSocketLocation("Muzzle");Deklarieren Sie als Nächstes einen
FRotatornamensSpawnRotation. Dies ist die Drehung (Nickachsen-, Gierachsen- und Rollachsenwerte) des Projektils, während es spawnt.Stellen Sie dies auf das Ergebnis des Aufrufs von
FindLookAtRotation()aus der kismet-Mathematik-Bibliothek und übergeben SieSocketLocationundTargetPosition, die Sie vom Spieler-Charakter abgerufen haben.C++FRotator SpawnRotation = UKismetMathLibrary::FindLookAtRotation(SocketLocation, TargetPosition);FindLookAtRotationberechnet die Drehung, die Sie amSocketLocationbenötigen, um sich derTargetPositionzuzuwenden, und gibt diese zurück.Deklarieren Sie einen
FVectornamensSpawnLocationund setzen Sie diesen auf das Ergebnis der Addition vonSocketLocationund dem Vorwärts-Vektor derSpawnRotationmultipliziert mit10.0.Das Mündung-Socket befindet sich nicht ganz vorne am Launcher. Daher müssen Sie den Vektor mit einem Versatz multiplizieren, damit das Projektil vom richtigen Ort abgefeuert wird.
C++FVector SpawnLocation = SocketLocation + UKismetMathLibrary::GetForwardVector(SpawnRotation) * 10.0;
Nachdem Sie jetzt den Ort und die Drehung festgelegt haben, können Sie das Projektil spawnen.
Um ein Projektil zu spawnen, befolgen Sie diese Schritte:
Immer noch in der
Use()-Funktion, deklarieren Sie einFActorSpawnParametersnamensActorSpawnParams. Diese Klasse enthält Informationen dazu, wo und wie der Actor gespawnt wird.C++//Set Spawn Collision Handling Override FActorSpawnParameters ActorSpawnParams;Legen Sie den
SpawnCollisionHandlingOverride-Wert inActorSpawnParamsaufESpawnActorCollisionHandlingMethod::AdjustWennPossibleButDontSpawnWennCollidingfest.Damit wird versucht, einen Platz zu finden, an dem das Projektil gespawnt wird, wo es nicht mit einem anderen Actor kollidiert (etwa in einer Wand). Es wird nicht spawnen, wenn kein geeigneter Ort gefunden wird.
C++ActorSpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding;Verwenden Sie
SpawnActor(), um das Projektil an der Mündung des Launchers zu spawnen und übergeben SieProjectileClass,SpawnLocation,SpawnRotationundActorSpawnParams.C++// Spawn the projectile at the muzzle World->SpawnActor<AFirstPersonProjectile>(ProjectileClass, SpawnLocation, SpawnRotation, ActorSpawnParams);
Deine fertige Funktion Use() sollte jetzt wie folgt aussehen:
void ADartLauncher::Use()
{
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, TEXT("Using the dart launcher!"));
UWorld* const World = GetWorld();
if (World != nullptr && ProjectileClass != nullptr)
{
FVector TargetPosition = OwningCharacter->GetCameraTargetLocation();
// Get the correct socket to spawn the projectile from
Eine Foam-Dart-Klasse und einen Blueprint ableiten
Jetzt ist die gesamte Spawn-Logik erledigt und es ist Zeit ein echtes Projektil bauen! Ihre Dart-Launcher -Klasse benötigt eine Subklasse von AFirstPersonProjectile zum Feuern. Also müssen Sie eine im Code erstellen, um sie in Ihrem Level zu verwenden.
Befolgen Sie diese Schritte, um eine Foam-Dart-Projektil-Klasse für die Verwendung im Spiel abzuleiten:
Gehen Sie im Unreal Editor zu Werkzeuge > Neue C++-Klasse.
Gehen Sie zu Alle Klassen, suchen Sie nach First Person Projectile und wählen Sie diese als Parent-Klasse aus. Nennen Sie die Klasse
FoamDart. Klicken Sie auf Klasse erstellen.Lassen Sie diese Dateien in VS unverändert, speichern Sie Ihren Code und kompilieren Sie ihn.
In diesem Tutorial werden Sie keinen benutzerdefiniert Projektil-Code implementieren, der über das hinausgeht, was Sie in FirstPersonProjectile definiert haben. Sie können die FoamDart-Klasse aber selbst modifizieren, um sie an die Anforderungen Ihres Projekts anzupassen. Sie könnten zum Beispiel versuchen, die Projektile an Objekten haften zu lassen, anstatt sie verschwinden oder abprallen zu lassen.
Um einen Foam-Dart-Blueprint zu erstellen, befolgen Sie diese Schritte:
Erstellen Sie im Unreal Editor eine Blueprint-Klasse basierend auf FoamDart und nennen Sie diese
BP_FoamDart. Speichern Sie dies in Ihrem OrdnerFirstPerson/Blueprints/Tools.Wählen Sie bei geöffnetem Blueprint die Komponente Projectile Mesh und setzen Sie das statische Mesh auf SM_FoamBullet.
Speichern und kompilieren Sie Ihren Blueprint.
Öffnen Sie im Inhaltsbrowser den
BP_DartLauncher.Legen Sie im Details -Panel im Abschnitt Projektil die Projektilklasse auf
BP_FoamDartfest, speichern Sie dann den Blueprint und kompilieren Sie ihn.Wenn Sie
BP_FoamDartnicht in der Liste sehen, gehen Sie zum Inhaltsbrowser, wählen SieBP_FoamDartaus, kehren Sie dann zur Eigenschaft Projektilklasse zurück und klicken Sie auf Ausgewähltes Asset aus dem Inhaltsbrowser verwenden.
Es ist Zeit für die große Enthüllung. Speichern Sie Ihre Assets und klicken auf Spielen. Wenn das Spiel beginnt, können Sie zum Dart-Launcher laufen, um ihn aufzuheben. Ein Druck auf die linke Maustaste spawnt ein Projektil aus der Mündung des Launchers und lässt es durch das Level hüpfen! Diese Projektile sollten nach fünf Sekunden verschwinden und auf die Objekte, mit denen sie kollidieren, eine geringe physikalische Kraft ausüben (Sie eingeschlossen!).
Als Nächstes
Glückwunsch! Sie haben das Tutorial des First-Person-Programmierer-Tracks abgeschlossen und dabei viel gelernt!
Sie haben benutzerdefinierte Charaktere und Bewegung implementiert, Abholpunkte und Daten-Assets erstellt und sogar ausrüstbare Werkzeuge mit eigenen Projektilen entwickelt! Sie haben alles, was Sie brauchen, um aus diesem Projekt etwas ganz Besonderes zu machen.
Hier sind ein paar Vorschläge:
Können Sie das Inventar der Spieler mit verschiedenen Arten von Gegenständen erweitern? Was ist mit Stapeln von Gegenständen?
Können Sie Abholpunkte und Projektile kombinieren, um aufnehmbare Munition zu erstellen? Wie wäre es, dieses Munitionssystem im Dart-Launcher zu implementieren?
Können Sie die Idee von Verbrauchsgegenständen zu ausrüstbaren Verbrauchsgegenständen entwickeln? Wie wäre es mit einem Gesundheitspaket, das der Spieler bei sich trägt, oder einem Ball, den er aufheben und werfen kann?
Vollständiger Code
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "FirstPersonProjectile.generated.h"
class UProjectileMovementComponent;
class USphereComponent;
// Fill out your copyright notice in the Description page of Project Settings.
#include "FirstPersonProjectile.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "Components/SphereComponent.h"
// Sets default values
AFirstPersonProjectile::AFirstPersonProjectile()
{
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Camera/CameraComponent.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "GameFramework/Character.h"
#include "InputActionValue.h"
// Copyright Epic Games, Inc. All Rights Reserved.
#include "AdventureCharacter.h"
#include "EquippableToolBase.h"
#include "EquippableToolDefinition.h"
#include "ItemDefinition.h"
#include "InventoryComponent.h"
// Sets default values
AAdventureCharacter::AAdventureCharacter()
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "AdventureGame/EquippableToolBase.h"
#include "AdventureGame/FirstPersonProjectile.h"
#include "DartLauncher.generated.h"
class AFirstPersonProjectile;
// Copyright Epic Games, Inc. All Rights Reserved.
#include "DartLauncher.h"
#include "Kismet/KismetMathLibrary.h"
#include "AdventureGame/AdventureCharacter.h"
void ADartLauncher::Use()
{
UWorld* const World = GetWorld();