Antes de empezar
Asegúrate de haber completado los siguientes objetivos de la sección anterior, Equipa a tu personaje:
Se ha creado un objeto de reaparición que reaparece y se ha añadido a tu nivel.
Se ha creado un iniciador de dardos equipable para que lo sujete y lo use tu personaje.
Proyectiles básicos
Tu personaje puede usar tu iniciador de dardos y tu herramienta tiene vinculaciones de control para usarlo, pero no hace honor a su nombre. En esta sección, implementarás la lógica de los proyectiles para que los dardos se lancen disparados del objeto equipado.
Unreal Engine cuenta con una clase de componente de movimiento de proyectiles que puedes añadir a un actor para convertirlo en un proyectil. Incluye muchas variables útiles, como la velocidad del proyectil, el rebote o la escala de gravedad.
Para gestionar las matemáticas a la hora de implementar proyectiles, tendrás que pensar en varios aspectos:
La transformación inicial, la velocidad y la dirección del proyectil.
Ya sea que quieras generar proyectiles desde el centro del personaje o desde la herramienta que tengan equipada.
Qué comportamiento quieres que tenga el proyectil cuando colisione con otro objeto.
Crear una clase base de proyectil
Primero crearás una clase base de proyectil, y luego crearás subclases de la misma para crear proyectiles únicos para tus herramientas.
Para empezar a ajustar una clase de proyectil base, sigue estos pasos:
En Unreal Editor, ve a Herramientas > Nueva clase C++. Selecciona Actor como clase principal y nombra la clase
FirstPersonProjectile. Haz clic en Crear clase.En VS, ve a
FirstPersonProjectile.h. En la parte superior del archivo, haz una declaración directa deUProjectileMovementComponentyUSphereComponent.Usarás el componente para simular colisiones entre el proyectil y otros objetos.
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;Añadir los especificadores
BlueprintTypeyBlueprintablepara exponer esta clase a los blueprints:C++UCLASS(BlueprintType, Blueprintable) class FIRSTPERSON_API AFirstPersonProjectile : public AActorAbre
FirstPersonProjectile.cpp, En la parte superior del archivo, añade una declaración de inclusión para«GameFramework/ProjectileMovementComponent.h»para incluir la clase del componente de movimiento del proyectil.
#include "FirstPersonProjectile.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "Components/SphereComponent.h"
// Sets default values
AFirstPersonProjectile::AFirstPersonProjectile()Implementación del comportamiento de los proyectiles al impactar contra objetos
Para que tu proyectil sea más realista, puedes hacer que ejerza cierta fuerza (un impulso) sobre los objetos a los que impacta. Por ejemplo, si disparas a un bloque con físicas activadas, el proyectil empujará el bloque contra el suelo. Luego, elimina el proyectil después del impacto en lugar de dejar que cumpla su ciclo de vida predeterminado. Crea una función OnHit() para implementar este comportamiento.
Para implementar un comportamiento de impacto de un proyectil, sigue estos pasos:
En
FirstPersonProjectile.h, en la secciónpública, define una propiedadfloatllamadaPhysicsForce.Dale una macro
UPROPERTY()conEditAnywhere,BlueprintReadOnlyyCategoría = «Proyectil | Física».Es la cantidad de fuerza que aplica el proyectil cuando impacta contra algo.
C++// The amount of force this projectile imparts on objects it collides with UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Projectile | Physics") float PhysicsForce = 100.0f;Define una función
nulaOnHit(). Se trata de una función de AActor que se llama cuando el actor colisiona con otro componente o actor. Toma los siguientes argumentos:HitComp: el componente afectado.OtherActor: el actor afectado.OtherComp: el componente que creó el impacto (en este caso, el componente CollisionComponent del proyectil).NormalImpulse: el impulso normal del impacto.Hit: una referencia deFHitResultque contiene más datos sobre el evento de impacto, como el tiempo, la distancia y la posición.
C++// Called when the projectile collides with an object UFUNCTION() void OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);En
FirstPersonProjectile.cpp, implementar la funciónOnHit()que definiste en tu archivo de cabecera. Dentro deOnHit(), en una declaraciónif, comprueba que:OtherActorno es nulo y no es el proyectil en sí.OtherCompno es nulo y también simula la física.
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()) { } }Esto comprueba que el proyectil impacta en un objeto que no sea él mismo y participa en la física.
Dentro de la sentencia
if, usaAddImpulseAtLocation()para añadir un impulso al componenteOtherComp.Con esta función, transfiere la velocidad del proyectil multiplicada por
PhysicsForcey aplícala en la posición del actor del proyectil.C++if ((OtherActor != nullptr) && (OtherActor != this) && (OtherComp != nullptr) && OtherComp->IsSimulatingPhysics()) { OtherComp->AddImpulseAtLocation(GetVelocity() * PhysicsForce, GetActorLocation()); }AddImpulseAtLocation()es una función de física de Unreal Engine que aplica una fuerza instantánea (impulso) a un objeto de física simulado en una posición específica del espacio en el entorno. Es útil cuando se quiere simular un impacto, como una explosión que arroja algo, una bala que impacta contra un objeto o una puerta que se abre de par en par.Por último, dado que este proyectil ha alcanzado a otro actor, elimina al proyector de la escena llamando a
Destroy().
Tu función OnHit() completa debería tener el siguiente aspecto:
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();
}
}Añade la malla, el movimiento y los componentes de colisión del proyectil
A continuación, añade una malla estática, una lógica de movimiento de proyectiles y una esfera de colisión a tu proyectil y definir cómo debe moverse el proyectil.
Para añadir estos componentes a tu proyectil, sigue estos pasos:
En
FirstPersonProjectile.h, en la secciónpublic, declara unTObjectPtra unUStaticMeshComponentdenominadoProjectileMesh. Esta es la malla estática del proyectil en el mundo.Dale una marco
UPROPERTY()conEditAnywhere,BlueprintReadOnly, yCategory = «Projectile | Mesh».C++// Mesh of the projectile in the world UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Projectile | Mesh") TObjectPtr<UStaticMeshComponent> ProjectileMesh;En la sección
protegida, declare:un
TObjectPtrpara unUSphereComponentllamadoCollisionComponent.un
TObjectPtra unUProjectileMovementComponentllamadoProjectileMovement.
Asigna a ambos una macro
UPROPERTY()conVisibleAnywhere,BlueprintReadOnlyyCategory = «Projectile | componentes».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;El componente ProjectileMovementComponent gestiona la lógica de movimiento por ti. Calcula dónde debería ir su actor principal en función de la velocidad, la gravedad y otras variables. Luego, durante
el tic, aplica el movimiento al proyectil.En
FirstPersonProjectile.cpp, en la función de constructorAFirstPersonProjectile(), crea subobjetos predeterminados para los componentes de malla, colisión y movimiento del proyectil. A continuación, adjunta la malla del proyectil al componente de colisión.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);Llama a
InitSphereRadius()para inicializarCollisionComponentcon un radio de5,0 f.Establece que el nombre del perfil de colisión del componente de colisión sea
«Projectile»conBodyInstance.SetCollisionProfileName().En Unreal Editor, tus perfiles de colisión se almacenan en Configuración del proyecto > Motor > Colisión, y puedes definir hasta 18 perfiles de colisión personalizados que usar en el código. El comportamiento predeterminado de este perfil de colisión de «proyectiles» es Bloquear y crea colisiones en cualquier objeto con el que colisiona.
C++CollisionComponent->InitSphereRadius(5.0f); // Set the collision profile to the "Projectile" collision preset CollisionComponent->BodyInstance.SetCollisionProfileName("Projectile");Ya has definido una función
OnHit()para que se active cuando el proyectil impacte en algo, pero necesitas una forma de notificarlo cuando se produzca la colisión. Para ello, usa la macroAddDynamic()para suscribir una función aOnComponentHitEventenCollisionComponent. Transfiere a esta macro la funciónOnHit().C++// Set up a notification for when this component hits something blocking CollisionComponent->OnComponentHit.AddDynamic(this, &AFirstPersonProjectile::OnHit);Establece
CollisionComponentcomo el componenteraízdel proyectil y comoUpdatedComponentpara que el componente de movimiento realice el pista de.C++// Set as root component RootComponent = CollisionComponent; ProjectileMovement->UpdatedComponent = CollisionComponent;Inicia el componente
ProjectileMovementcon los siguientes valores:InitialSpeed: la velocidad inicial del proyectil cuando se genera. Ajústalo a3000.0f.MaxSpeed: la velocidad máxima del proyectil. Ajústalo a3000.0f.bRotationFollowVelocity: determina si el objeto debe rotar para marcar la dirección de su velocidad. Por ejemplo, cómo un avión de papel sube y baja a medida que asciende y desciende. Establezca esto entrue.bShouldBounce: determina si el proyectil debe rebotar en los obstáculos. Establezca esto entrue.
C++ProjectileMovement->UpdatedComponent = CollisionComponent; ProjectileMovement->InitialSpeed = 3000.f; ProjectileMovement->MaxSpeed = 3000.f; ProjectileMovement->bRotationFollowsVelocity = true; ProjectileMovement->bShouldBounce = true;
Establecer la vida útil del proyectil
Por defecto, harás desaparecer el proyectil unos segundos después de dispararlo. Sin embargo, una vez que hayas derivado tus blueprints de proyectiles en el editor, puedes probar cambiando o eliminando este tiempo predeterminado para intentar llenar tu nivel con dardos de espuma.
Para hacer que el proyectil desaparezca transcurridos unos segundos, sigue estos pasos:
En
FirstPersonProjectile.h, en la secciónpública, declara un float llamadoProjectileLifespan.Dale una macro
UPROPERTY()conEditAnywhere,BlueprintReadOnlyyCategory = «Projectile | Vida útil».La vida útil del proyectil en segundos.
C++// Despawn after 5 seconds by default UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Projectile | Lifespan") float ProjectileLifespan = 5.0f;En
FirstPersonProjectile.cpp, al final de la función de constructorAFirstPersonProjectile(), establece que el valor deInitialLifeSpandel proyectil seaProjectileLifespanpara que desaparezca transcurridos cinco segundos.C++// Disappear after 5.0 seconds by default. InitialLifeSpan = ProjectileLifespan;InitialLifeSpanes una propiedad heredada de AActor. Es un float que establece cuánto tiempo vive el actor antes de morir. Si el valor es0,el actor vivirá hasta que el juego se detenga.
Tu FirstPersonProjectile.h completo debería verse de la siguiente manera:
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "FirstPersonProjectile.generated.h"
class UProjectileMovementComponent;
class USphereComponent;
Tu función de constructor AFirstPersonProjectile completa debería tener el siguiente aspecto:
// 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);
Obtener la dirección de la cámara del personaje
Los proyectiles deberían aparecer desde el propio iniciador de dardos, por lo que tendrás que hacer algunas matemáticas para saber dónde está el iniciador de dardos y hacia dónde apunta. Dado que el iniciador está asociado al personaje jugable, estos valores cambiarán en función de dónde se encuentre el personaje y hacia dónde mire.
Tu personaje en primera persona contiene parte de la información posicional que necesitas para lanzar un dardo, así que empieza modificando tu clase personaje para capturar esa información con una traza de línea y devolver el resultado.
Si quieres usar una traza para obtener la información que necesitas de tu personaje, sigue estos pasos:
En VS, abre los
.hy.cppde tu personaje.En la
.h, en la secciónpública, declara una nueva función llamadaGetCameraTargetLocation()que devuelve unFVector. Esta función devolverá la posición del mundo que el personaje está mirando.C++// Returns the location in the world the character is looking at UFUNCTION() FVector GetCameraTargetLocation();En el
.cppde tu personaje, implementa la funciónGetCameraTargetLocation(). Comienza por declarar un FVector denominadoTargetPositionpara devolver.Crea un puntero a
UWorldllamando aGetWorld().C++// The target position to return FVector TargetPosition; UWorld* const World = GetWorld();Añadir una instrucción
ifpara comprobar quemundono es un valor nulo. En la instrucciónif, declara unFHitResultllamadoHit.C++if (World != nullptr) { // The result of the line trace FHitResult Hit;FHitResultes una struct de UE que almacena información sobre el resultado de una consulta de colisión, incluido el actor o componente que se ha encontrado y dónde se ha encontrado.Para encontrar el punto al que mira el personaje, hay que simular la traza de una línea a lo largo del vector hacia el que mira el personaje hasta un punto distante. Si la traza colisiona con un objeto, sabrás a qué parte del mundo está mirando tu personaje.
Declara dos valores FVector constantes llamados TraceStart y TraceEnd:
Establece
TraceStarten la posición deFirstPersonCameraComponent.Establece
TraceEndcomoTraceStartmás el vector de avance del componente de cámara multiplicado por un número muy grande. Esto garantiza que la traza llegue lo suficientemente lejos como para colisionar con la mayoría de los objetos de tu mundo siempre que tu personaje no esté mirando al cielo. (Si el personaje mira al cielo,TraceEndes el punto terminal de la traza lineal.)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;
Llama a
LineTraceSingleByChannel()desdeUWorldpara simular la traza. PásaloHit,TraceStart,TraceEndy unECollisionChannel::ECC_Visibility.Simula la traza de una línea desde
TraceStarthastaTraceEnd, colisionando con cualquier objeto visible y almacenando el resultado del traza enHit.ECollisionChannel::ECC_Visibilityes el canal que se usará para el trazado. Estos canales definen qué tipos de objetos debería intentar alcanzar tu traza. UsaECC_Visibilitypara las comprobaciones de cámara con línea de visión.C++World->LineTraceSingleByChannel(Hit, TraceStart, TraceEnd, ECollisionChannel::ECC_Visibility);El valor de
impactoahora contiene información sobre el resultado del impacto, como la posición y la normal del impacto. También sabe si el impacto fue resultado de una colisión de un objeto. La posición del impacto (o el punto final de la línea de la traza) es la posición del objetivo de la Cámara a la que volver.Usa un operador ternario para establecer
TargetPositionenHit.ImpactPointsi el impacto fue un bloqueo oHit.TraceEnden caso contrario. Luego, devuelve laTargetPosition.C++TargetPosition = Hit.bBlockingHit ? Hit.ImpactPoint : Hit.TraceEnd; } return TargetPosition;
Tu función GetCameraTargetLocation() completa debería tener el siguiente aspecto:
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;
aparecer de proyectiles con DartLauncher::Use()
Ahora que ya sabes hacia dónde mira el personaje, puedes implementar el resto de la lógica del proyectil en la función Use() de tu lanzador de dardos. Obtendrás la posición y la dirección para lanzamiento el proyectil y, a continuación, aparecerá el proyectil.
Para obtener la posición y la rotación en las que debería aparecer el proyectil, sigue estos pasos:
En
DartLauncher.h, en la parte superior del archivo, añade una declaración directa paraAFirstPersonProjectile.En la sección
pública, declara una propiedadTSubclassOf<AFirstPersonProjectile>llamada ProjectileClass. Este será el proyectil que generará el iniciador de dardos. Dale a esto la macroUPROPERTY()conEditAnywhereyCategoría = proyectil.Ahora
DartLauncher.h debería tener el siguiente aspecto: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, añade una instrucción include para«Kismet/KismetMathLibrary.h». Las matemáticas de proyectiles pueden ser complicadas, y este archivo incluye varias funciones útiles para lanzar proyectiles.C++#include "DartLauncher.h" #include "Kismet/KismetMathLibrary.h" #include "AdventureGame/AdventureCharacter.h"Empieza a implementar la función
Use()de DartLauncher:Obtén el
UWorldllamando aGetWorld().Añadir una instrucción
ifpara comprobar quemundoyProjectileClassno son nulos.En la declaración
if, llama aOwningCharacter->GetCameraTargetLocation()para obtener la posición a la que mira el personaje.
C++void ADartLauncher::Use() { UWorld* const World = GetWorld(); if (World != nullptr && ProjectileClass != nullptr) { FVector TargetPosition = OwningCharacter->GetCameraTargetLocation(); } }Aunque quieras generar proyectiles desde la herramienta que empuña el personaje, puede que no te interese generar directamente desde el centro del objeto. La malla
SKM_Pistoldel lanzador de dardos tiene un socket de boca que puedes usar para establecer un punto de aparición preciso para tus dardos.Declara un nuevo
FVectorllamadoSocketLocationy ajústalo al resultado de una llamada aGetSocketLocation(«Muzzle»)en elToolMeshComponent.C++// Get the correct socket to spawn the projectile from FVector SocketLocation = ToolMeshComponent->GetSocketLocation("Muzzle");A continuación, declara un
FRotatorllamadoSpawnRotation. Es la rotación (valores de pitch, guiñada y alabeo) del proyectil a medida que se genera.Establece el resultado de llamar a
FindLookAtRotation()desde la biblioteca matemática Kismet, pasandoSocketLocationyTargetPositiondel personaje jugador.C++FRotator SpawnRotation = UKismetMathLibrary::FindLookAtRotation(SocketLocation, TargetPosition);FindLookAtRotationcalcula y devuelve la rotación necesaria enSocketLocationpara orientarse haciaTargetPosition.Declara un
FVectorllamadoSpawnLocationy establece que sea el resultado de sumarSocketLocationy el vector directo deSpawnRotationmultiplicado por10,0.El socket de la boca no se encuentra exactamente en la parte delantera del iniciador, por lo que tendrás que multiplicar el vector por una compensación para que el proyectil se dispare desde la posición adecuada.
C++FVector SpawnLocation = SocketLocation + UKismetMathLibrary::GetForwardVector(SpawnRotation) * 10.0;
Ahora que ya conoces la posición y la rotación, ya puedes generar el proyectil.
Para generar un proyectil, sigue estos pasos:
Aún en la función
Use(), declara unFActorSpawnParametersllamadoActorSpawnParams. Esta clase incluye información sobre dónde y cómo generar al actor.C++//Set Spawn Collision Handling Override FActorSpawnParameters ActorSpawnParams;Establece el valor
SpawnCollisionHandlingOverridedeActorSpawnParamsenESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding.Intenta encontrar un lugar para generar el proyectil donde no colisione con otro actor (como dentro de una pared) y no aparezca si no se encuentra una posición adecuada.
C++ActorSpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding;Usa
SpawnActor()generar el proyectil en la boca del iniciador de dardos, pasandoProjectileClass,SpawnLocation,SpawnRotationyActorSpawnParams.C++// Spawn the projectile at the muzzle World->SpawnActor<AFirstPersonProjectile>(ProjectileClass, SpawnLocation, SpawnRotation, ActorSpawnParams);
Tu función Use() completa ahora debería verse de la siguiente manera:
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
Derive a la Clase Foam Dart y blueprint
Ahora que toda la lógica de generación está lista, ¡es el momento de crear un proyectil de verdad! Tu clase de iniciador de dardos necesita una subclase de AFirstPersonProjectile para el lanzamiento, por lo que tendrás que compilar una en el código para usarla en tu nivel.
Para derivar una clase de proyectil de dardo de espuma para usarla en el juego, sigue estos pasos:
En Unreal Editor, ve a Herramientas > Nueva clase C++.
Ve a Todas las clases, busca y selecciona Proyectil de primera persona como la clase principal y nombra la clase
FoamDart. Haz clic en Crear clase.En VS, deja estos archivos tal y como están, guarda el código y compílalo.
En este tutorial no implementarás ningún código de proyectil personalizado aparte del definido en FirstPersonProjectile, pero puedes modificar la clase FoamDart por tu cuenta para adaptarla a las necesidades de tu proyecto. Por ejemplo, podrías intentar que los proyectiles de los dardos se adhieran a los objetos en lugar de desaparecer o rebotar.
Para crear un blueprint de dardo de espuma, sigue estos pasos:
En Unreal Editor, crea una clase de blueprint basada en FoamDart y llámala
BP_FoamDart. Guárdalo en tu carpetaFirstPerson/Blueprints/Tools.Con el blueprint abierto, selecciona el componente de malla de proyectil y establece la malla estática como SM_FoamBullet.
Guarda y compila tu blueprint.
En el explorador de contenido, abre
BP_DartLauncher.En el panel Detalles, en la sección Proyectil, establece la clase de proyectil en
BP_FoamDarty, a continuación, guarda y compila el blueprint.No se aparece
BP_FoamDarten la lista, ve al explorador de contenido, seleccionaBP_FoamDarty, a continuación, vuelve a la propiedad Clase de proyectil y haz clic en Usar el recurso seleccionado del explorador de contenido.
Ha llegado la hora de la gran revelación. Guarda tus recursos y clic en Play. Cuando empiece el juego, puedes correr hasta el iniciador de dardos para recogerlo. Al pulsar el botón izquierdo del ratón, se genera un proyectil en la boca del iniciador y rebota por el nivel. Estos proyectiles deberían desaparecer tras cinco segundos y ejercer una pequeña fuerza física sobre los objetos con los que colisionen (¡incluyéndote a ti!).
Siguiente
¡Enhorabuena! ¡Has completado el tutorial de la pista del programador en primera persona y has aprendido mucho por el camino!
Has implementado movimientos y personajes personalizado, has creado objetos para recoger y recursos de datos e incluso has creado herramientas equipables con sus propios proyectiles. Ya tienes todo lo que necesitas para convertir este proyecto en algo tuyo.
Aquí hay algunas sugerencias:
¿Se puede ampliar el inventario del jugador con distintos tipos de objetos? ¿Qué pasa con las pilas de elementos?
¿Se pueden combinar objetos que se pueden recoger y proyectiles para crear munición que se pueda recoger? ¿Qué te parece implementar este sistema de munición en el lanzadardos?
¿Puedes desarrollar la idea de los consumibles para convertirlos en consumibles equipables? ¿Qué tal un paquete de salud que el jugador pueda sujetar o una pelota que pueda coger y lanzar?
Código completo
// 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();