Antes de começar
Certifique-se de ter concluído os seguintes objetivos na seção anterior, Equipar seu Personagem:
Criamos um item de coleta de ressurgimento e o adicionamos ao seu nível
Criamos um lançador de dardos equipável para seu personagem segurar e usar
Projéteis Básicos
Seu personagem pode segurar seu lançador de dardos, e sua ferramenta tem vinculações de controle para usá-la, mas não faz jus ao nome dela. Nesta seção, você implementará a lógica de projéteis para fazer com que os dardos sejam lançados a partir do item equipado.
A Unreal Engine tem uma classe de componente de movimento de projétil que você pode adicionar a um ator para transformá-lo em um projétil. Ele inclui muitas variáveis úteis, como velocidade do projétil, ricochete e escala de gravidade.
Para lidar com o cálculo matemático da implementação de projéteis, você precisará pensar em várias coisas:
A transformação inicial, velocidade e direção do projétil.
Escolha se deseja gerar projéteis a partir do centro do personagem ou da ferramenta que ele equipou.
O comportamento que você deseja que o projétil tenha ao colidir com outro objeto.
Criar uma Classe Base de Projétil
Primeiro, você criará uma classe base de projétil e, em seguida, criará uma subclasse a partir para criar projéteis únicos para suas ferramentas.
Para começar a configurar uma classe base de projétil, siga estas etapas:
No Unreal Editor, acesse Ferramentas > Nova classe C++. Selecione Ator como a classe pai e nomeie a classe como
FirstPersonProjectile. Clique em Criar classe.No VS, acesse
FirstPersonProjectile.h. No topo do arquivo, declare para a frente umUProjectileMovementComponente umUSphereComponent.Você usará o componente de esfera para simular colisões entre o projétil e outros 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;Adicione os especificadores
BlueprintTypee Blueprintablepara expor essa classe a Blueprints:C++UCLASS(BlueprintType, Blueprintable) class FIRSTPERSON_API AFirstPersonProjectile : public AActorAbra
FirstPersonProjectile.cpp, no topo do arquivo, adicione uma instrução "include" em"GameFramework/ProjectileMovementComponent.h"para incluir a classe do componente de movimento do projétil.
#include "FirstPersonProjectile.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "Components/SphereComponent.h"
// Sets default values
AFirstPersonProjectile::AFirstPersonProjectile()Implementar Comportamento de Projétil ao Atingir Objetos
Para deixar o projétil mais realista, faça-o exercer uma força (um impulso) nos objetos atingidos. Por exemplo, se você atirar em um bloco ativado por física, o projétil empurrará o bloco ao longo do solo. Em seguida, remova o projétil após o impacto em vez de deixá-lo cumprir seu tempo de vida padrão. Crie uma função OnHit() para implementar esse comportamento.
Para implementar o comportamento de impacto do projétil, siga estas etapas:
Em
FirstPersonProjectile.h,na seçãopública, defina uma propriedadefloatdenominadaPhysicsForce.Adicione um macro
UPROPERTY()comEditAnywhere,BlueprintReadOnlyeCategory = "Projectile | Physics".É a quantidade de força que o projétil transmite ao atingir algo.
C++// The amount of force this projectile imparts on objects it collides with UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Projectile | Physics") float PhysicsForce = 100.0f;Defina uma função
voidOnHit(). É uma função do AActor chamada quando o ator colide com outro componente ou ator. Ela recebe os seguintes argumentos:HitComp: o componente que foi atingido.OtherActor: o ator que foi atingido.OtherComp: o componente que criou o impacto (neste caso, o CollisionComponent do projétil)."NormalImpulse":o impulso normal do impacto.Acerto: uma referência deFHitResultque contém mais dados sobre o evento Acerto, como hora, distância e posição.
C++// Called when the projectile collides with an object UFUNCTION() void OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);Em
FirstPersonProjectile.cpp, implemente a funçãoOnHit()definida no arquivo de cabeçalho. Dentro deOnHit(), em uma instruçãoif, verifique se:OtherActornão é nulo e não é o projétil em si.OtherCompnão é nulo e também simula 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()) { } }Isso verifica se o projétil atingiu um objeto diferente dele e que participa da física.
Dentro da instrução
if, useAddImpulseAtLocation()para adicionar um impulso ao componenteOtherComp.Passe para a função a velocidade do projétil multiplicada por
PhysicsForcee aplique-a na posição do ator do projétil.C++if ((OtherActor != nullptr) && (OtherActor != this) && (OtherComp != nullptr) && OtherComp->IsSimulatingPhysics()) { OtherComp->AddImpulseAtLocation(GetVelocity() * PhysicsForce, GetActorLocation()); }AddImpulseAtLocation()é uma função de física na Unreal Engine que aplica uma força instantânea (impulso) a um objeto de física simulado em uma posição específica no espaço do mundo. É útil quando você deseja simular um impacto, como uma explosão arremessando algo, uma bala atingindo um objeto ou uma porta sendo aberta.Por último, como o projétil atingiu outro ator, remova o projetor da cena chamando
Destroy().
A sua função OnHit() completa ficará desta forma:
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();
}
}Adicione a malha, o movimento e os componentes de colisão do projétil
Em seguida, adicione uma malha estática, uma lógica de movimento do projétil e uma esfera de colisão ao projétil e defina como o projétil deve se mover.
Para adicionar esses componentes ao seu projétil, siga estas etapas:
Em
FirstPersonProjectile.h, na Na seçãopublic, declare umTObjectPtrpara umUStaticMeshComponentchamadoProjectileMesh. Esta é a malha estática do projétil no mundo.Dê a ele uma macro
UPROPERTY()comEditAnywhere,BlueprintReadOnlyeCategory = "Projectile | Mesh".C++// Mesh of the projectile in the world UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Projectile | Mesh") TObjectPtr<UStaticMeshComponent> ProjectileMesh;Na seção
protegida, declare:Um
TObjectPtra umUSphereComponentdenominadoCollisionComponent.Um
TObjectPtra umUProjectileMovementComponentdenominadoProjectileMovement.
Dê a ambos uma macro
UPROPERTY()comVisibleAnywhere,BlueprintReadOnlyeCategory = "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;O ProjectileMovementComponent lida com a lógica de movimento para você. Ele calcula aonde seu Ator pai deve ir com base na velocidade, gravidade e outras variáveis. Depois, durante
marca de verificação, aplica o movimento ao projétil.Em
FirstPersonProjectile.cpp, na função de construtorAFirstPersonProjectile(), crie subobjetos padrão para os componentes de malha, colisão e movimento do projétil. Em seguida, anexe a malha do projétil ao componente de colisão.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);Chame
InitSphereRadius()para inicializar oCollisionComponentcom um raio de5.0f.Defina o nome do perfil de colisão do componente de colisão como
ProjétilusandoBodyInstance.SetCollisionProfileName().No Unreal Editor, seus perfis de colisão são armazenados em Configurações de Projeto, Engine, Colisão, e você pode definir até 18 perfis de colisão personalizados para usar no código. O comportamento padrão desse perfil de colisão "Projétil" é Bloco e cria colisões em qualquer objeto com o qual colide.
C++CollisionComponent->InitSphereRadius(5.0f); // Set the collision profile to the "Projectile" collision preset CollisionComponent->BodyInstance.SetCollisionProfileName("Projectile");Você definiu uma função
OnHit()anteriormente para ativar quando o projétil atinge algo, mas precisa de uma maneira de notificar quando essa colisão ocorre. Para fazer isso, use a macroAddDynamic()para assinar uma função paraOnComponentHitEventemCollisionComponent. Passe a esta macro a funçãoOnHit().C++// Set up a notification for when this component hits something blocking CollisionComponent->OnComponentHit.AddDynamic(this, &AFirstPersonProjectile::OnHit);Defina o
CollisionComponentcomo oRootComponentdo projétil e como oUpdatedComponentpara o componente de movimento a ser rastreado.C++// Set as root component RootComponent = CollisionComponent; ProjectileMovement->UpdatedComponent = CollisionComponent;Inicialize o componente
ProjectileMovementcom os seguintes valores:InitialSpeed: a velocidade inicial do projétil quando ele surge. Defina como3000.0f.MaxSpeed: a velocidade máxima do projétil. Defina como3000.0f.bRotationFollowVelocity: se o objeto deve girar para atingir a direção de sua velocidade. Por exemplo, como um avião de papel sobe e desce enquanto sobe e desce. Defina comoverdadeiro.bShouldBounce: se o projétil deve rebater nos obstáculos. Defina comoverdadeiro.
C++ProjectileMovement->UpdatedComponent = CollisionComponent; ProjectileMovement->InitialSpeed = 3000.f; ProjectileMovement->MaxSpeed = 3000.f; ProjectileMovement->bRotationFollowsVelocity = true; ProjectileMovement->bShouldBounce = true;
Defina a vida útil do projétil
Por padrão, você fará o projétil desaparecer alguns segundos após dispará-lo. No entanto, depois de derivar os Blueprints de projétil no editor, você pode experimentar alterar ou remover esse tempo padrão para tentar encher o nível com dardos de espuma.
Para fazer o projétil desaparecer após alguns segundos, siga estas etapas:
Em
FirstPersonProjectile.h, na seçãopública, declare um float denominadoProjectileLifespan.Dê a ele uma macro
UPROPERTY()comEditAnywhere,BlueprintReadOnlyeCategory = "Projectile | Lifespan".É o tempo de vida do projétil em segundos.
C++// Despawn after 5 seconds by default UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Projectile | Lifespan") float ProjectileLifespan = 5.0f;Em
FirstPersonProjectile.cpp, no final da função de construtorAFirstPersonProjectile(), defina oInitialLifeSpando projétil comoProjectileLifespanpara fazê-lo desaparecer após cinco segundos.C++// Disappear after 5.0 seconds by default. InitialLifeSpan = ProjectileLifespan;InitialLifeSpané uma propriedade herdada de AActor. É um float que define quanto tempo o ator vive antes de morrer. Um valor0significa que o Ator vive até o jogo parar.
Seu FirstPersonProjectile.h completo deve ter a seguinte aparência:
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "FirstPersonProjectile.generated.h"
class UProjectileMovementComponent;
class USphereComponent;
Sua função de construtor AFirstPersonProjectile completa ficará desta forma:
// 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);
Obter a Direção da Câmera do Personagem
Os projéteis devem surgir do próprio lançador de dardos. Portanto, você precisará fazer um cálculo para saber onde o lançador de dardos está e para onde ele está apontando. Como o lançador está anexado ao personagem do jogador, esses valores mudarão de acordo com onde o personagem está e para onde está olhando.
Seu personagem em primeira pessoa contém algumas das informações posicionais necessárias para lançar um dardo. Portanto, comece modificando a classe do personagem para capturar essas informações com um traçado de linha e retornar o resultado.
Para rastrear e obter as informações necessárias do seu personagem, siga estas etapas:
No VS, abra o
.he o.cppdos arquivos do seu personagem.No arquivo
.h, na seçãopública, declare uma nova função denominadaGetCameraTargetLocation()que retorna umFVector. Essa função retornará a posição no mundo para o qual o personagem está olhando.C++// Returns the location in the world the character is looking at UFUNCTION() FVector GetCameraTargetLocation();No arquivo
.cppdo personagem, implemente a funçãoGetCameraTargetLocation(). Comece declarando um FVector denominadoTargetPositionpara retornar.Crie um ponteiro para o
UWorldchamandoGetWorld().C++// The target position to return FVector TargetPosition; UWorld* const World = GetWorld();Adicione uma instrução
ifpara verificar seMundonão é nulo. Na instruçãoif, declare umFHitResultdenominadoAcerto.C++if (World != nullptr) { // The result of the line trace FHitResult Hit;FHitResulté uma struct no UE que armazena informações sobre o resultado de uma consulta de colisão, incluindo o Ator ou componente que foi atingido e onde ele foi atingido.Para encontrar o ponto para o qual a personagem está olhando, você vai simular um traçado de linha ao longo do vetor para o qual o personagem está olhando até um ponto distante. Se o traçado de linha colidir com um objeto, você saberá para onde seu personagem está olhando no mundo.
Declare dois valores constantes de FVector denominados TraceStart e TraceEnd:
Defina
TraceStartpara a posição deFirstPersonCameraComponent.Defina
TraceEndcomoTraceStartmais o vetor para a frente do componente de câmera multiplicado por um número bem grande. Isso garante que o rastro irá longe o suficiente para colidir com a maioria dos objetos no seu mundo, desde que o personagem não esteja olhando para o céu. (Se o personagem estiver olhando para o céu,TraceEndserá o ponto terminal do traçado de linha.)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;
Chame
LineTraceSingleByChannel()a partir doUWorldpara simular o rastro. PasseAcerto,TraceStart,TraceEnde umECollisionChannel::ECC_Visibility.Isso simula um traçado de linha de
TraceStartatéTraceEnd,colidindo com qualquer objeto visível e armazenando o resultado do rastro emAcerto.ECollisionChannel::ECC_Visibilityé o canal a ser usado para o rastro, e esses canais definem os tipos de objetos que o rastro deve tentar atingir. UseECC_Visibilitypara verificações de câmera em linha de visão.C++World->LineTraceSingleByChannel(Hit, TraceStart, TraceEnd, ECollisionChannel::ECC_Visibility);O valor
Acertoagora contém informações sobre o resultado, como a posição e a normal do impacto. Ele também sabe se o impacto foi resultado de uma colisão de objeto. O local do impacto (ou o ponto final da linha de rastro) é o local alvo da câmera para retorno.Use um operador ternário para definir
TargetPositioncomoHit.ImpactPointse o impacto for um impacto de bloqueio eHit.TraceEndse não for. Em seguida, retorneTargetPosition.C++TargetPosition = Hit.bBlockingHit ? Hit.ImpactPoint : Hit.TraceEnd; } return TargetPosition;
A sua função GetCameraTargetLocation() completa ficará desta forma:
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;
Gerar projéteis com DartLauncher::Use()
Agora que você sabe para onde o personagem está olhando, implemente o restante da lógica do projétil na função Use() do lançador de dardos. Você obterá a localização e a direção para lançar o projétil e, em seguida, gerará o projétil.
Para obter a localização e a rotação em que o projétil deve surgir, siga estes passos:
Em
DartLauncher.h, no topo do arquivo, adicione uma declaração de encaminhamento paraAFirstPersonProjectile.Na seção
pública, declare uma propriedadeTSubclassOf<AFirstPersonProjectile>denominada ProjectileClass. Este será o projétil que o lançador de dardos vai gerar. Dê a ele isso a macroUPROPERTY()comEditAnywhereeCategory = Projectile.DartLauncher.hagora deve ficar assim: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, adicione uma instrução include para"Kismet/KismetMathLibrary.h". A matemática de projéteis pode ser complicada, e este arquivo inclui várias funções úteis que você usará para lançar projéteis.C++#include "DartLauncher.h" #include "Kismet/KismetMathLibrary.h" #include "AdventureGame/AdventureCharacter.h"Comece a implementar a função
Use()do DartLauncher:Obtenha o
UWorldchamandoGetWorld().Adicione uma instrução
ifpara verificar seMundoeProjectileClassnão são nulos.Na instrução
if, obtenha a posição para a qual o personagem está olhando chamandoOwningCharacter->GetCameraTargetLocation().
C++void ADartLauncher::Use() { UWorld* const World = GetWorld(); if (World != nullptr && ProjectileClass != nullptr) { FVector TargetPosition = OwningCharacter->GetCameraTargetLocation(); } }Embora você queira gerar projéteis a partir da ferramenta que o personagem está segurando, talvez você não queira gerá-los diretamente do centro do objeto. A malha
SKM_Pistoldo lançador de dardos tem um soquete "Cano" que você pode usar para definir um ponto de surgimento preciso para seus dardos.Declare um novo
FVectordenominadoSocketLocatione defina-o como o resultado da denominada deGetSocketLocation("Muzzle")noToolMeshComponent.C++// Get the correct socket to spawn the projectile from FVector SocketLocation = ToolMeshComponent->GetSocketLocation("Muzzle");Em seguida, declare um
FRotatordenominadoSpawnRotation. Esta é a rotação (valores de arfagem, eixo vertical e eixo de inclinação) do projétil conforme ele surge.Defina isso como o resultado da chamada de
FindLookAtRotation()da biblioteca matemática kismet, transmitindoSocketLocationeTargetPositionque você obteve a partir do personagem do jogador.C++FRotator SpawnRotation = UKismetMathLibrary::FindLookAtRotation(SocketLocation, TargetPosition);FindLookAtRotationcalcula e retorna a rotação que você precisaria emSocketLocationpara enfrentarTargetPosition.Declare um
FVectordenominadoSpawnLocatione defina-o como o resultado da adição deSocketLocatione do vetor direto deSpawnRotationmultiplicado por10,0.O soquete do cano não fica exatamente na frente do lançador, então você precisará multiplicar o vetor por um deslocamento para que o projétil dispare a partir do local correto.
C++FVector SpawnLocation = SocketLocation + UKismetMathLibrary::GetForwardVector(SpawnRotation) * 10.0;
Agora que você tem um local e uma rotação, está pronto para gerar o projétil.
Para gerar um projétil, siga estes passos:
Ainda na função
Use(), declare umFActorSpawnParametersdenominadoActorSpawnParams. Esta classe inclui informações sobre onde e como gerar o ator.C++//Set Spawn Collision Handling Override FActorSpawnParameters ActorSpawnParams;Defina o valor
SpawnCollisionHandlingOverrideemActorSpawnParamscomoESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding.Isso tenta encontrar um lugar para gerar o projétil onde ele não colida com outro Ator (como dentro de uma parede) e não o gerará se um local adequado não for encontrado.
C++ActorSpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding;Use
SpawnActor()para gerar o projétil no cano do lançador de dardos, transmitindoProjectileClass,SpawnLocation,SpawnRotationeActorSpawnParams.C++// Spawn the projectile at the muzzle World->SpawnActor<AFirstPersonProjectile>(ProjectileClass, SpawnLocation, SpawnRotation, ActorSpawnParams);
Sua função Use() completa agora deve ficar assim:
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
Derivar uma classe e Blueprint de dardo de espuma
Agora que toda a lógica de geração está pronta, é hora de construir um projétil de verdade! Sua classe de lançador de dardos precisa de uma subclasse de AFirstPersonProjectile para ser iniciada, então você precisará criar uma em código para usar em seu nível.
Para derivar uma classe de projétil de dardo de espuma para usar no jogo, siga estas etapas:
No Unreal Editor, acesse Ferramentas > Nova classe C++.
Acesse Todas as classes, pesquise e selecione projeto em primeira pessoa como a classe pai e nomeie a classe
FoamDart. Clique em Criar classe.No VS, deixe esses arquivos como estão, salve seu código e compile-o.
Neste tutorial, você não implementará nenhum código de projétil personalizado além do que definiu em FirstPersonProjectile, mas poderá modificar a classe FoamDart por conta própria para atender às necessidades do seu projeto. Por exemplo, você pode tentar fazer com que os projéteis de dardo grudem em objetos em vez de desaparecerem ou quicarem.
Para criar um Blueprint de dardo de espuma, siga estes passos:
No Unreal Editor, crie uma classe de Blueprint baseada em FoamDart e nomeie-a
BP_FoamDart. Salve isso na sua pastaFirstPerson/Blueprints/Ferramentas.Com o Blueprint aberto, selecione o componente Malha do projétil e defina a Malha estática como SM_FoamBullet.
Salve e compile seu Blueprint.
No Navegador de Conteúdo, abra
BP_DartLauncher.No painel Detalhes, na seção Projétil, defina Classe de Projétil como
BP_FoamDart, salve e compile o Blueprint.Se você não vir
BP_FoamDartna lista, vá até o Navegador de Conteúdo, selecioneBP_FoamDart, depois volte para a propriedade Classe de Projétil e clique em Usar ativo selecionado do Navegador de Conteúdo.
É hora da grande revelação. Salve seus ativos e clique em Reproduzir. Quando o jogo começar, você pode correr até o lançador de dardos para pegá-lo. Pressionar o botão esquerdo do mouse faz um projétil sair do cano do lançador de dardos e rebater pelo nível! Esses projéteis devem desaparecer após cinco segundos e transmitir uma pequena força física aos objetos com os quais colidem (incluindo você!).
Próxima
Parabéns! Você concluiu o tutorial da Trilha do Programador em Primeira Pessoa e aprendeu muito ao longo do caminho!
Você implementou personagens e movimentos personalizados, criou itens de coleta e dados e até mesmo criou ferramentas equipáveis com seus próprios projéteis. Você tem tudo o que precisa para pegar esse projeto e transformá-lo em algo totalmente seu.
Aqui estão algumas sugestões:
Você pode expandir o inventário do jogador com diferentes tipos de itens? E quanto às pilhas de itens?
Você pode combinar coletas e projéteis para criar munição coletável? Que tal implementar esse sistema de munição no lançador de dardos?
Você pode desenvolver a ideia de consumíveis em consumíveis equipáveis? Que tal um kit de saúde que o jogador segura ou uma bola que ele pode pegar e arremessar?
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();