UE4 C++代码实现碰撞小游戏

2022年05月14日 阅读数:4
这篇文章主要向大家介绍UE4 C++代码实现碰撞小游戏,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

 新建项目选择空项目git

复制Materials和Meshes到Content目录app

从新构建关卡ide

添加SM_Backdrop,SM_Wall,并做以下修改:函数

添加C++类,并取名为Paddlethis

在Paddle.h中添加属性:spa

在类上声明:3d

FloatingPawnMovement是一个运动组件,为任何Pawn类提供简单的运动。code

在Paddle.h中继续添加移动处理的函数orm

Paddle.cpp中添加头文件blog

构造函数中添加UStaticMeshComponent与UFloatingPawnMovement组件

实现MoveHorizontal函数:

在Paddle_BP蓝图设置SM_Padle的mesh

把Paddle_BP放入场景中

在场景中新建GameMode并更名为ArkanoidGameMode_BP

对GameMode进行设置

添加Camera

新建PlayerController的基类,并取名为Paddle_Player_Controller

Paddle_Player_Controller.h添加函数声明

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "Paddle_Player_Controller.generated.h"

//class ABall
/**
 * 
 */
UCLASS()
class PLAYBALL_API APaddle_Player_Controller : public APlayerController
{
	GENERATED_BODY()

		APaddle_Player_Controller();

	UFUNCTION()
		virtual void SetupInputComponent() override;

protected:
	virtual void BeginPlay() override;

	void MoveHorizontal(float AxisValue);

	//ball reerences
};

Paddle_Player_Controller.cpp中设置相机为主视角

// Fill out your copyright notice in the Description page of Project Settings.


#include "Paddle_Player_Controller.h"

#include "Kismet/GameplayStatics.h"
#include "Camera/CameraActor.h"

#include "Paddle.h"
//#include "Ball.h"

APaddle_Player_Controller::APaddle_Player_Controller()
{

}

void APaddle_Player_Controller::SetupInputComponent()
{
}

void APaddle_Player_Controller::BeginPlay()
{
	TArray<AActor*> CameraActors;
	UGameplayStatics::GetAllActorsOfClass(GetWorld(), ACameraActor::StaticClass(), CameraActors);

	FViewTargetTransitionParams params;
	SetViewTarget(CameraActors[0], params);
}

void APaddle_Player_Controller::MoveHorizontal(float AxisValue)
{
}

新建蓝图类,基类为Paddle_Player_Controller

而后设置游戏控制类为刚刚新建的蓝图类:

设置完以后运行游戏,能够看到:

添加输入

在Paddle_Player_Controller.h中绑定SetupInputComponent:

void APaddle_Player_Controller::SetupInputComponent()
{
	Super::SetupInputComponent();

	EnableInput(this);

	InputComponent->BindAxis("MoveHorizontal", this, &APaddle_Player_Controller::MoveHorizontal);

}

实现MoveHorizontal

void APaddle_Player_Controller::MoveHorizontal(float AxisValue)
{
	auto MyPawn = Cast<APaddle>(GetPawn());

	if (MyPawn) {
		MyPawn->MoveHorizontal(AxisValue);
	}
}

这里须要注意的是,在关卡中只须要放PlayerStart便可,不须要放Paddle_BP,不然会不能移动。

添加球体

在ball.h添加属性:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Ball.generated.h"

class UProjectileMovementComponent;

UCLASS()
class PLAYBALL_API ABall : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ABall();

	virtual void Launch();

	bool BallLaunched;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
		UStaticMeshComponent* SM_Ball;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
		UProjectileMovementComponent* ProjectileMovement;

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	UFUNCTION()
		UStaticMeshComponent* GetBall();

};

在Ball.cpp的构造函数中添加:

	SM_Ball = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Ball"));
	RootComponent = SM_Ball;

	SM_Ball->SetSimulatePhysics(true);
	SM_Ball->SetEnableGravity(false);
	SM_Ball->SetConstraintMode(EDOFMode::XZPlane);
	SM_Ball->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
	SM_Ball->SetCollisionProfileName(TEXT("PhysicsActor"));

设置PhysicsActor的缘由是Paddle_BP中StaticMesh的碰撞预设设置的是PhysicsActor

在构造函数中继续添加

	ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("Projectile Movement"));
	ProjectileMovement->bShouldBounce = true;
	ProjectileMovement->Bounciness = 1.1f;
	ProjectileMovement->Friction = 0.0f;
	ProjectileMovement->Velocity.X = 0.0f;

实现Launch函数

void ABall::Launch()
{
	if (!BallLaunched) {
		SM_Ball->AddImpulse(FVector(140.0f, 0.0f, 130.0f), FName(), true);

		BallLaunched = true;
	}
}

添加函数绑定

在蓝图中实现:

修改Paddle_Player_Controller.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"

#include "Ball.h"

#include "Paddle_Player_Controller.generated.h"


/**
 * 
 */
UCLASS()
class PLAYBALL_API APaddle_Player_Controller : public APlayerController
{
	GENERATED_BODY()

		APaddle_Player_Controller();

	UFUNCTION()
		virtual void SetupInputComponent() override;

protected:
	virtual void BeginPlay() override;

	void MoveHorizontal(float AxisValue);

	void Launch();

	UPROPERTY(EditAnywhere)
		TSubclassOf<ABall> BallObj;

	ABall* MyBall=nullptr;

	FVector SpawnLocation = FVector(10.0f, 0.0f, 40.0f);
	FRotator SpawnRotation = FRotator(0.0f, 0.0f, 0.0f);
	FActorSpawnParameters SpawnInfo;

public:
	void SpawnNewBall();

	//ball reerences
};

在Paddle_Player_Controller.h实现SpawnNewBall()函数

void APaddle_Player_Controller::SpawnNewBall()
{
	if (!MyBall) {
		MyBall = nullptr;
	}

	if (BallObj) {
		MyBall = GetWorld()->SpawnActor<ABall>(BallObj, SpawnLocation, SpawnRotation, SpawnInfo);
	}
}

开始游戏的时候调用SpawnNewBall

设置Ball Obj

新建Material

双击作以下设置

完成以上步骤后作以下步骤:

建立砖块,并命名为Brick.h:

在Brick.h中建立属性与函数:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Brick.generated.h"

class UBoxComponent;

UCLASS()
class PLAYBALL_API ABrick : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ABrick();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

	UPROPERTY(VisibleAnywhere,BlueprintReadOnly)
		UStaticMeshComponent* SM_Brick;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
		UBoxComponent* Box_Collision;

	float SpeedModifierOnBounce = 1.0f;

	UFUNCTION()
		void OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor,
			class UPrimitiveComponent* OtherComp, int32 OtherBodyIndexType, bool bFromSweep,
			const FHitResult& SweepResult);

	void DestroyBrick();

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

};

初始化,以及绑定碰撞函数

新建Brick的蓝图类并作以下设置:

把Brick蓝图类拖入level中

添加Tag

实现碰撞函数

void ABrick::OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndexType, bool bFromSweep, const FHitResult& SweepResult)
{
	UE_LOG(LogTemp, Warning, TEXT("OnOverlapBegin"));
	if (OtherActor->ActorHasTag("Ball"))
	{
		UE_LOG(LogTemp, Warning, TEXT("OnOverlapBegin  OtherActor"));
		ABall* MyBall = Cast<ABall>(OtherActor);

		FVector BallVelocity = MyBall->GetVelocity();
		BallVelocity *= (SpeedModifierOnBounce + 1.0001f);

		MyBall->GetBall()->SetPhysicsLinearVelocity(BallVelocity, true);

		FTimerHandle UnusedHandle;
        //先弹走,而后0.1s后再destroy形成视觉差
		GetWorldTimerManager().SetTimer(UnusedHandle, this, &ABrick::DestroyBrick, 0.1f, false);
	}
}

void ABrick::DestroyBrick()
{
	this->Destroy();
}

到这里,游戏基本功能已经实现,可是若是小球弹到下面了该怎么处理呢?

添加基类为Actor的ABallBoound C++类

BallBoound.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "BallBoound.generated.h"

class UBoxComponent;
class APaddle_Player_Controller;

UCLASS()
class PLAYBALL_API ABallBoound : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ABallBoound();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
		UBoxComponent* Box_Collision;

	APaddle_Player_Controller* PlayerController_REF;

	UFUNCTION()
		void OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor,
			class UPrimitiveComponent* OtherComp, int32 OtherBodyIndexType, bool bFromSweep,
			const FHitResult& SweepResult);

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

};

BallBound.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "BallBoound.h"
#include "Components/BoxComponent.h"
#include "Kismet/GameplayStatics.h"
#include "Paddle_Player_Controller.h"

// Sets default values
ABallBoound::ABallBoound()
{
 	// 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;

	Box_Collision = CreateDefaultSubobject<UBoxComponent>(TEXT("Box Collision"));
	RootComponent = Box_Collision;

}

// Called when the game starts or when spawned
void ABallBoound::BeginPlay()
{
	Super::BeginPlay();

	Box_Collision->OnComponentBeginOverlap.AddDynamic(this, &ABallBoound::OnOverlapBegin);

	PlayerController_REF = Cast<APaddle_Player_Controller>(
		UGameplayStatics::GetPlayerController(GetWorld(), 0)
		);
	
}

// Called every frame
void ABallBoound::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

void ABallBoound::OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndexType, bool bFromSweep, const FHitResult& SweepResult)
{
	if (OtherActor->ActorHasTag("Ball"))
	{
		OtherActor->Destroy();

		PlayerController_REF->SpawnNewBall();
	}
}


新建该类的蓝图类,并调整好大小,放入蓝图中

运行截图:

 代码连接:CodingInn/UE4 Basic Tutorial