上一篇文章写了整体框架,这篇文章来贴出我自己跟着siki学院的飞机大作战视频所制作的代码,编译环境为VS2019,UE4.26完美运行。
SpaceShip.cpp
#include "SpaceShip.h"
#include "Components/StaticMeshComponent.h"
#include "Components/SphereComponent.h"
#include "Camera/CameraComponent.h"
#include "Gameframework/PlayerController.h"
#include "Kismet/KismetMathLibrary.h"
#include "Gameframework/SpringArmComponent.h"
#include "Misc/App.h"
#include "Engine/World.h"
#include "Bullet.h"
#include "TimerManager.h"
#include "Enemy.h"
#include "Kismet/GameplayStatics.h"
#include "Sound/SoundCue.h"
#include "Particles/ParticleSystemComponent.h"
#include "Particles/ParticleSystem.h"
// Sets default values
ASpaceShip::ASpaceShip()
{
// Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
CollisionComp = CreateDefaultSubobject(TEXT("CollisionComp"));
RootComponent = CollisionComp;
ShipSM = CreateDefaultSubobject(TEXT("ShipSM"));
ShipSM->SetupAttachment(RootComponent);
SpringArmComp = CreateDefaultSubobject(TEXT("SpringArmComp"));
SpringArmComp->SetupAttachment(RootComponent);
CameraComp = CreateDefaultSubobject(TEXT("CameraComp"));
CameraComp->SetupAttachment(SpringArmComp);
SpawnPoint = CreateDefaultSubobject(TEXT("SpawnPoint"));
SpawnPoint->SetupAttachment(ShipSM);
ThrusterParticleComp = CreateDefaultSubobject(TEXT("ThrusterParticleComp"));
ThrusterParticleComp->SetupAttachment(RootComponent);
Speed = 2500.0f;
TimeBetweenShot = 0.2f;
bDead = false;
}
// Called when the game starts or when spawned
void ASpaceShip::BeginPlay()
{
Super::BeginPlay();
PC = Cast(GetController());
PC->bShowMouseCursor = true;
}
void ASpaceShip::LookAtCursor()
{
FVector MouseLocation, MouseDirection;
PC->DeprojectMousePositionToWorld(MouseLocation, MouseDirection);
FVector TargetLocation = FVector(MouseLocation.X, MouseLocation.Y, GetActorLocation().Z);
FRotator Rotator = UKismetMathLibrary::FindLookAtRotation(GetActorLocation(), TargetLocation);
SetActorRotation(Rotator);
}
void ASpaceShip::MoveUp(float Value)
{
if (Value != 0) {
bUpMove = true;
}
else {
bUpMove = false;
}
AddMovementInput(FVector::ForwardVector, Value);
}
void ASpaceShip::MoveRight(float Value)
{
if (Value != 0) {
bRightMove = true;
}
else {
bRightMove = false;
}
AddMovementInput(FVector::RightVector, Value);
}
void ASpaceShip::Move()
{
AddActorWorldOffset(ConsumeMovementInputVector() * Speed * FApp::GetDeltaTime(), true);
}
void ASpaceShip::Fire()
{
if (Bullet && !bDead)
{
FActorSpawnParameters SpawnParams;
GetWorld()->SpawnActor(Bullet, SpawnPoint->GetComponentLocation(), SpawnPoint->GetComponentRotation(), SpawnParams);
if (ShootCue) UGameplayStatics::PlaySoundAtLocation(this, ShootCue, GetActorLocation());
}
}
void ASpaceShip::StartFire()
{
GetWorldTimerManager().SetTimer(TimerHandle_BetweenShot, this, &ASpaceShip::Fire, TimeBetweenShot, true, 0.0f);
}
void ASpaceShip::EndFire()
{
GetWorldTimerManager().ClearTimer(TimerHandle_BetweenShot);
}
void ASpaceShip::RestartLevel()
{
UGameplayStatics::OpenLevel(this, "MainMap");
}
void ASpaceShip::onDeath()
{
bDead = true;
CollisionComp->SetVisibility(false, true);
if (GameOverCue) UGameplayStatics::PlaySoundAtLocation(this, GameOverCue, GetActorLocation());
if (ExplosionParticle) UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ExplosionParticle, GetActorLocation(), FRotator::ZeroRotator, true);
GetWorldTimerManager().SetTimer(TimerHandle_Restart, this, &ASpaceShip::RestartLevel, 2.0f, false);
}
// Called every frame
void ASpaceShip::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (!bDead) {
if (bRightMove || bUpMove) {
ThrusterParticleComp->Activate();
}
else {
ThrusterParticleComp->Deactivate();
}
LookAtCursor();
Move();
}
else {
ThrusterParticleComp->Deactivate();
}
}
// Called to bind functionality to input
void ASpaceShip::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
PlayerInputComponent->BindAxis("MoveUp", this, &ASpaceShip::MoveUp);
PlayerInputComponent->BindAxis("MoveRight", this, &ASpaceShip::MoveRight);
PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &ASpaceShip::StartFire);
PlayerInputComponent->BindAction("Fire", IE_Released, this, &ASpaceShip::EndFire);
}
void ASpaceShip::NotifyActorBeginOverlap(AActor* OtherActor)
{
Super::NotifyActorBeginOverlap(OtherActor);
AEnemy* Enemy = Cast(OtherActor);
if (Enemy) {
Enemy->Destroy();
UE_LOG(LogTemp, Warning, TEXT("Player is Dead"));
onDeath();
//Destroy();
}
}
SpaceShip.h
#pragma once
#include "CoreMinimal.h"
#include "Gameframework/Pawn.h"
#include "SpaceShip.generated.h"
class USphereComponent;
class UCameraComponent;
class USpringArmComponent;
class ABullet;
class USoundCue;
UCLASS()
class SPACESHIPBATTLE_API ASpaceShip : public APawn
{
GENERATED_BODY()
public:
// Sets default values for this pawn's properties
ASpaceShip();
protected:
UPROPERTY(VisibleAnywhere, Category = "Component")
USphereComponent* CollisionComp;
UPROPERTY(VisibleAnywhere, Category = "Component")
UStaticMeshComponent* ShipSM;
UPROPERTY(VisibleAnywhere, Category = "Component")
UCameraComponent* CameraComp;
UPROPERTY(VisibleAnywhere, Category = "Component")
USpringArmComponent* SpringArmComp;
APlayerController* PC;
UPROPERTY(EditAnywhere, Category = "Fire")
TSubclassOf Bullet;
UPROPERTY(VisibleAnywhere, Category = "Component")
USceneComponent* SpawnPoint;
UPROPERTY(EditAnywhere, Category = "Move")
float Speed;
FTimerHandle TimerHandle_BetweenShot;
FTimerHandle TimerHandle_Restart;
UPROPERTY(EditAnywhere, Category = "Fire")
float TimeBetweenShot;
UPROPERTY(EditAnywhere, Category = "Souned")
USoundCue* GameOverCue;
UPROPERTY(EditAnywhere, Category = "Souned")
USoundCue* ShootCue;
UPROPERTY(VisibleAnywhere, Category = "Component")
UParticleSystemComponent* ThrusterParticleComp;
UPROPERTY(EditAnywhere, Category = "Particle")
UParticleSystem* ExplosionParticle;
bool bDead;
bool bUpMove;
bool bRightMove;
// Called when the game starts or when spawned
virtual void BeginPlay() override;
void LookAtCursor();
void MoveUp(float Value);
void MoveRight(float Value);
void Move();
void Fire();
void StartFire();
void EndFire();
void RestartLevel();
void onDeath();
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
virtual void NotifyActorBeginOverlap(AActor* OtherActor) override;
FORCEINLINE bool GetBDead() {
return bDead;
}
};
Enemy.cpp
#include "Enemy.h"
#include "Components/StaticMeshComponent.h"
#include "Components/SphereComponent.h"
#include "Kismet/GameplayStatics.h"
#include "SpaceShip.h"
#include "Kismet/KismetMathLibrary.h"
#include "ShipGameMode.h"
#include "EnemySpawner.h"
#include "Particles/ParticleSystem.h"
// Sets default values
AEnemy::AEnemy()
{
// Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
CollisionComp = CreateDefaultSubobject(TEXT("CollisionComp"));
RootComponent = CollisionComp;
ShipSM = CreateDefaultSubobject(TEXT("ShipSM"));
ShipSM->SetupAttachment(RootComponent);
}
// Called when the game starts or when spawned
void AEnemy::BeginPlay()
{
Super::BeginPlay();
SpaceShip = Cast(UGameplayStatics::GetPlayerPawn(this, 0));
SetColor();
MyGameMode = Cast(UGameplayStatics::GetGameMode(this));
TArray EnemySpawnerArray;
UGameplayStatics::GetAllActorsOfClass(this, AEnemySpawner::StaticClass(), EnemySpawnerArray);
EnemySpawner = Cast(EnemySpawnerArray[0]);
}
void AEnemy::MoveTowardsPlayer(float DeltaTime)
{
FVector Direction = (SpaceShip->GetActorLocation() - GetActorLocation()).GetSafeNormal();
AddActorWorldOffset(Direction * Speed * DeltaTime, true);
SetActorRotation(UKismetMathLibrary::FindLookAtRotation(GetActorLocation(), SpaceShip->GetActorLocation()));
}
void AEnemy::onDeath()
{
MyGameMode->IncreaseScore();
EnemySpawner->DecreaseEnemyCount();
SpawnExplosion();
Destroy();
}
// Called every frame
void AEnemy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (SpaceShip->GetBDead() == false) MoveTowardsPlayer(DeltaTime);
}
// Called to bind functionality to input
void AEnemy::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
Enemy.h
#pragma once
#include "CoreMinimal.h"
#include "Gameframework/Pawn.h"
#include "Enemy.generated.h"
class USphereComponent;
class ASpaceShip;
class AShipGameMode;
class AEnemySpawner;
UCLASS()
class SPACESHIPBATTLE_API AEnemy : public APawn
{
GENERATED_BODY()
public:
// Sets default values for this pawn's properties
AEnemy();
protected:
UPROPERTY(VisibleAnywhere, Category = "Component")
USphereComponent* CollisionComp;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Component")
UStaticMeshComponent* ShipSM;
// Called when the game starts or when spawned
virtual void BeginPlay() override;
void MoveTowardsPlayer(float DeltaTime);
ASpaceShip* SpaceShip;
AShipGameMode* MyGameMode;
float Speed = 300.0f;
AEnemySpawner* EnemySpawner;
UFUNCTION(BlueprintImplementableEvent)
void SetColor();
UFUNCTION(BlueprintImplementableEvent)
void SpawnExplosion();
UPROPERTY(EditAnywhere, Category = "Particle")
UParticleSystem* ExplosionParticle;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
void onDeath();
};
Bullet.cpp
#include "Bullet.h"
#include "Components/StaticMeshComponent.h"
#include "Components/SceneComponent.h"
#include "Gameframework/ProjectileMovementComponent.h"
#include "Enemy.h"
#include "Engine/BlockingVolume.h"
#include "Kismet/GameplayStatics.h"
#include "EnemySpawner.h"
// Sets default values
ABullet::ABullet()
{
// 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;
RootComp = CreateDefaultSubobject(TEXT("RootComp"));
RootComponent = RootComp;
BulletSM = CreateDefaultSubobject(TEXT("BulletSM"));
BulletSM->SetupAttachment(RootComponent);
ProjectileMovementComp = CreateDefaultSubobject(TEXT("ProjectileMovementComp"));
}
// Called when the game starts or when spawned
void ABullet::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void ABullet::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ABullet::NotifyActorBeginOverlap(AActor* OtherActor)
{
Super::NotifyActorBeginOverlap(OtherActor);
AEnemy* Enemy = Cast(OtherActor);
if (Enemy) {
Enemy->onDeath();
Destroy();
}
else if (Cast(OtherActor)) {
Destroy();
}
}
Bullet.h
#pragma once
#include "CoreMinimal.h"
#include "Gameframework/Actor.h"
#include "Bullet.generated.h"
class UProjectileMovementComponent;
UCLASS()
class SPACESHIPBATTLE_API ABullet : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ABullet();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
UPROPERTY(VisibleAnywhere, Category = "Component")
USceneComponent* RootComp;
UPROPERTY(VisibleAnywhere, Category = "Component")
UStaticMeshComponent* BulletSM;
UPROPERTY(VisibleAnywhere, Category = "Component")
UProjectileMovementComponent* ProjectileMovementComp;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
virtual void NotifyActorBeginOverlap(AActor* OtherActor) override;
};
ShipGameMode.cpp
#include "ShipGameMode.h"
AShipGameMode::AShipGameMode() {
Score = 0;
}
void AShipGameMode::IncreaseScore()
{
Score++;
}
ShipGameMode.h
#pragma once
#include "CoreMinimal.h"
#include "Gameframework/GameModebase.h"
#include "ShipGameMode.generated.h"
UCLASS()
class SPACESHIPBATTLE_API AShipGameMode : public AGameModebase
{
GENERATED_BODY()
protected:
AShipGameMode();
UPROPERTY(BlueprintReadOnly)
int Score;
public:
void IncreaseScore();
};
EnemySpawner.cpp
#include "EnemySpawner.h"
#include "Components/BoxComponent.h"
#include "Kismet/KismetMathLibrary.h"
#include "Kismet/GameplayStatics.h"
#include "SpaceShip.h"
#include "Engine/World.h"
#include "Enemy.h"
// Sets default values
AEnemySpawner::AEnemySpawner()
{
// 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;
SpawnArea = CreateDefaultSubobject(TEXT("SpawnArea"));
RootComponent = SpawnArea;
SpawnInterval = 2.0f;
MaxEnemyNum = 30;
CurrentEnemyCount = 0;
}
// Called when the game starts or when spawned
void AEnemySpawner::BeginPlay()
{
Super::BeginPlay();
SpaceShip = Cast(UGameplayStatics::GetPlayerPawn(this, 0));
GetWorldTimerManager().SetTimer(TimerHandle_Spawn, this, &AEnemySpawner::SpawnEnemy, SpawnInterval, true, 0.0f);
}
FVector AEnemySpawner::GetGenerateLocation()
{
float Distance = 0;
FVector Location;
while (Distance < MininumDistanceToPlayer) {
Location = UKismetMathLibrary::RandomPointInBoundingBox(SpawnArea->Bounds.Origin, SpawnArea->Bounds.BoxExtent);
Distance = (Location - SpaceShip->GetActorLocation()).Size();
}
return Location;
}
void AEnemySpawner::SpawnEnemy()
{
if (SpaceShip->GetBDead() == false && CurrentEnemyCount < MaxEnemyNum) {
FActorSpawnParameters SpawnParameters;
GetWorld()->SpawnActor(Enemy, GetGenerateLocation(), FRotator::ZeroRotator, SpawnParameters);
CurrentEnemyCount++;
}
}
// Called every frame
void AEnemySpawner::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AEnemySpawner::DecreaseEnemyCount()
{
if (CurrentEnemyCount > 0) {
CurrentEnemyCount--;
UE_LOG(LogTemp, Warning, TEXT("%s"), *FString::SanitizeFloat(CurrentEnemyCount));
}
}
EnemySpawner.h
#pragma once
#include "CoreMinimal.h"
#include "Gameframework/Actor.h"
#include "EnemySpawner.generated.h"
class AEnemy;
class UBoxComponent;
class ASpaceShip;
UCLASS()
class SPACESHIPBATTLE_API AEnemySpawner : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AEnemySpawner();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
UPROPERTY(EditAnywhere, Category = "Enemy")
TSubclassOf Enemy;
UPROPERTY(VisibleAnywhere, Category = "Component")
UBoxComponent* SpawnArea;
FVector GetGenerateLocation();
float MininumDistanceToPlayer = 1200.0f;
ASpaceShip* SpaceShip;
void SpawnEnemy();
FTimerHandle TimerHandle_Spawn;
float SpawnInterval;
UPROPERTY(EditAnywhere, Category = "Spawn")
int MaxEnemyNum;
int CurrentEnemyCount;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
void DecreaseEnemyCount();
};
以上就是编写的全部代码了,相关的在UE4中需要进行设置的在此就不再赘述,如有任何问题欢迎与我讨论。整体工程太大(10G左右),如果你想要的话私聊我,我可以网盘发给你。



