ue4基础入门(二)角色通信

本文想把四种通信方式在同一个项目中实现,主要是根据官方例程的修改版。代码是不断累积的,所以最后会有一份有四种通信方式的程序(第四种只是增加了一个接口的虚函数,按照官方例程即可,没有写出)。
官方例程:https://docs.unrealengine.com/4.27/zh-CN/ProgrammingAndScripting/ActorCommunication/

一、类型转换

1、整体流程

关键就是通过碰撞回调和cast获得特定角色的指针

第一步:创建一个立方体。写好旋转的内部功能函数,在tick函数中根据一个内部变量持续判断是否应该旋转。

第二步:设置碰撞回调函数。在回调函数中,通过cast函数获得碰撞范围内的角色指针并进行通信。

2、源码带注释

RotatingActor.h

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

#pragma once

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

UCLASS()
class ACTOR_COMUNICATION_API ARotatingActor : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ARotatingActor();
	void SetbCanRotate(bool value);         //设置旋转标志的函数

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	void RotateActor();                    //在tick中调用,每次根据标志位控制旋转与否
	bool bCanRotate;                       //旋转标志

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		UStaticMeshComponent* MeshComp;

	//Actor的旋转速度。
	const FQuat ActorRotationRate = (FQuat(FRotator(0, 2, 0)));

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

};

RotatingActor.c

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


#include "RotatingActor.h"

// Sets default values
ARotatingActor::ARotatingActor()
{
 	// 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;
	RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("SceneComponent"));
	MeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComp"));
	MeshComp->SetupAttachment(RootComponent);

	static ConstructorHelpers::FObjectFinder<UStaticMesh> CubeVisualAsset(TEXT("/Game/StarterContent/Shapes/Shape_Cube.Shape_Cube"));  //资产变量
	MeshComp->SetStaticMesh(CubeVisualAsset.Object);
	
	bCanRotate = false;
}
void ARotatingActor::SetbCanRotate(bool value)
{
	bCanRotate = value;
}
void ARotatingActor::RotateActor()
{
	AddActorLocalRotation(ActorRotationRate);
}
// Called when the game starts or when spawned
void ARotatingActor::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void ARotatingActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	if (bCanRotate)
	{
		RotateActor();
	}

}


actor_communicationCharacter.h

// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "actor_comunicationCharacter.generated.h"

UCLASS(config=Game)
class Aactor_comunicationCharacter : public ACharacter
{
	GENERATED_BODY()

	/** Camera boom positioning the camera behind the character */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
	class USpringArmComponent* CameraBoom;

	/** Follow camera */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
	class UCameraComponent* FollowCamera;
public:
	Aactor_comunicationCharacter();

	/** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
	float BaseTurnRate;

	/** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
	float BaseLookUpRate;

protected:
	virtual void NotifyActorBeginOverlap(AActor* OtherActor);  //通知角色进入判定范围
	virtual void NotifyActorEndOverlap(AActor* OtherActor);    //通知角色离开判定范围
	class USphereComponent* SphereComp;                        //设置碰撞的网格体
	/** Resets HMD orientation in VR. */
	void OnResetVR();

	/** Called for forwards/backward input */
	void MoveForward(float Value);

	/** Called for side to side input */
	void MoveRight(float Value);

	/** 
	 * Called via input to turn at a given rate. 
	 * @param Rate	This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
	 */
	void TurnAtRate(float Rate);

	/**
	 * Called via input to turn look up/down at a given rate. 
	 * @param Rate	This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
	 */
	void LookUpAtRate(float Rate);

	/** Handler for when a touch input begins. */
	void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location);

	/** Handler for when a touch input stops. */
	void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location);

protected:
	// APawn interface
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
	// End of APawn interface

public:
	/** Returns CameraBoom subobject **/
	FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
	/** Returns FollowCamera subobject **/
	FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; }
};


actor_communicationCharacter.cpp

// Copyright Epic Games, Inc. All Rights Reserved.

#include "actor_comunicationCharacter.h"
#include "HeadMountedDisplayFunctionLibrary.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/Controller.h"
#include "GameFramework/SpringArmComponent.h"
#include "RotatingActor.h"
#include "Components/SphereComponent.h"
//
// Aactor_comunicationCharacter

Aactor_comunicationCharacter::Aactor_comunicationCharacter()
{
	// Set size for collision capsule
	GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);

	// set our turn rates for input
	BaseTurnRate = 45.f;
	BaseLookUpRate = 45.f;

	// Don't rotate when the controller rotates. Let that just affect the camera.
	bUseControllerRotationPitch = false;
	bUseControllerRotationYaw = false;
	bUseControllerRotationRoll = false;

	// Configure character movement
	GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input...	
	GetCharacterMovement()->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // ...at this rotation rate
	GetCharacterMovement()->JumpZVelocity = 600.f;
	GetCharacterMovement()->AirControl = 0.2f;

	// Create a camera boom (pulls in towards the player if there is a collision)
	CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
	CameraBoom->SetupAttachment(RootComponent);
	CameraBoom->TargetArmLength = 300.0f; // The camera follows at this distance behind the character	
	CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller

	// Create a follow camera
	FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
	FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation
	FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm

	// Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character) 
	// are set in the derived blueprint asset named MyCharacter (to avoid direct content references in C++)
	SphereComp = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComp"));
	SphereComp->AttachToComponent(GetMesh(), FAttachmentTransformRules::KeepRelativeTransform);
	SphereComp->SetSphereRadius(200);

//	UE_LOG(LogTemp, Warning, TEXT("Hello"));
}

//
// Input

void Aactor_comunicationCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
	// Set up gameplay key bindings
	check(PlayerInputComponent);
	PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
	PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);

	PlayerInputComponent->BindAxis("MoveForward", this, &Aactor_comunicationCharacter::MoveForward);
	PlayerInputComponent->BindAxis("MoveRight", this, &Aactor_comunicationCharacter::MoveRight);

	// We have 2 versions of the rotation bindings to handle different kinds of devices differently
	// "turn" handles devices that provide an absolute delta, such as a mouse.
	// "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick
	PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
	PlayerInputComponent->BindAxis("TurnRate", this, &Aactor_comunicationCharacter::TurnAtRate);
	PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
	PlayerInputComponent->BindAxis("LookUpRate", this, &Aactor_comunicationCharacter::LookUpAtRate);

	// handle touch devices
	PlayerInputComponent->BindTouch(IE_Pressed, this, &Aactor_comunicationCharacter::TouchStarted);
	PlayerInputComponent->BindTouch(IE_Released, this, &Aactor_comunicationCharacter::TouchStopped);

	// VR headset functionality
	PlayerInputComponent->BindAction("ResetVR", IE_Pressed, this, &Aactor_comunicationCharacter::OnResetVR);
}


void Aactor_comunicationCharacter::OnResetVR()
{
	// If actor_comunication is added to a project via 'Add Feature' in the Unreal Editor the dependency on HeadMountedDisplay in actor_comunication.Build.cs is not automatically propagated
	// and a linker error will result.
	// You will need to either:
	//		Add "HeadMountedDisplay" to [YourProject].Build.cs PublicDependencyModuleNames in order to build successfully (appropriate if supporting VR).
	// or:
	//		Comment or delete the call to ResetOrientationAndPosition below (appropriate if not supporting VR)
	UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition();
}

void Aactor_comunicationCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location)
{
		Jump();
}

void Aactor_comunicationCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location)
{
		StopJumping();
}

void Aactor_comunicationCharacter::TurnAtRate(float Rate)
{
	// calculate delta for this frame from the rate information
	AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}

void Aactor_comunicationCharacter::LookUpAtRate(float Rate)
{
	// calculate delta for this frame from the rate information
	AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
}

void Aactor_comunicationCharacter::MoveForward(float Value)
{
	if ((Controller != nullptr) && (Value != 0.0f))
	{
		// find out which way is forward
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);

		// get forward vector
		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
		AddMovementInput(Direction, Value);
	}
}

void Aactor_comunicationCharacter::MoveRight(float Value)
{
	if ( (Controller != nullptr) && (Value != 0.0f) )
	{
		// find out which way is right
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);
	
		// get right vector 
		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
		// add movement in that direction
		AddMovementInput(Direction, Value);
	}
}
void Aactor_comunicationCharacter::NotifyActorBeginOverlap(AActor* OtherActor)
{
	//有任何角色之间的碰撞都会进入这里
	if (ARotatingActor* RotatingActorCheck = Cast<ARotatingActor>(OtherActor))//获取相关角色的指针
	{
		UE_LOG(LogTemp, Warning, TEXT("yes"));
		RotatingActorCheck->SetbCanRotate(true);
	}
	else {
		UE_LOG(LogTemp, Warning, TEXT("no"));
	}
}

void Aactor_comunicationCharacter::NotifyActorEndOverlap(AActor* OtherActor)
{
	if (ARotatingActor* RotatingActorCheck = Cast<ARotatingActor>(OtherActor))
	{
		RotatingActorCheck->SetbCanRotate(false);
	}
}

3、重点解读

这种方法的核心就是通过碰撞回调函数和cast获得特定角色的指针。

二、直接通信

1、整体流程

第一步:创建电灯actor,并实现相关功能

第二步:在玩家角色中,增加电灯类变量,并进行相关操作

第三步:在编辑器中将电灯类指定到场景中的角色

2、源码带注释

CeilingLight.h

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

#pragma once

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

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

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
    UPROPERTY(EditInstanceOnly, BlueprintReadWrite)
        USceneComponent* SceneComp;

    UPROPERTY(EditInstanceOnly, BlueprintReadWrite)
        class UPointLightComponent* PointLightComp;

    UPROPERTY(EditInstanceOnly, BlueprintReadWrite)
        UStaticMeshComponent* StaticMeshComp;

    UPROPERTY(EditInstanceOnly, BlueprintReadWrite)
        float Brightness;

    UPROPERTY(EditInstanceOnly, BlueprintReadWrite)
        float SourceRadius;

    UPROPERTY(EditInstanceOnly, BlueprintReadWrite)
        FLinearColor Color;

    UPROPERTY(EditInstanceOnly, BlueprintReadWrite)
        bool IsLightOn;

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

CeilingLight.cpp

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


#include "CeilingLight.h"
#include "Components/PointLightComponent.h"
// Sets default values
ACeilingLight::ACeilingLight()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
 // 将此Actor设置为每帧调用Tick()函数。如果你不需要此特性,你可以关闭它以提升性能。
    PrimaryActorTick.bCanEverTick = true;
    SceneComp = CreateDefaultSubobject<USceneComponent>(TEXT("SceneComp"));
    PointLightComp = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLightComp"));
    StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMeshComp"));
    SceneComp = RootComponent;
    PointLightComp->AttachToComponent(SceneComp, FAttachmentTransformRules::KeepRelativeTransform);
    StaticMeshComp->AttachToComponent(SceneComp, FAttachmentTransformRules::KeepRelativeTransform);
    PointLightComp->SetWorldLocation(FVector(0, 0, -130));
    Brightness = 1700.f;
    Color = FLinearColor(1.f, 0.77f, 0.46f);
    SourceRadius = 3.5f;
    PointLightComp->SetIntensity(Brightness);
    PointLightComp->SetLightColor(Color);
    PointLightComp->SetSourceRadius(SourceRadius);
    PointLightComp->SetVisibility(true);

}

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

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

}

void ACeilingLight::TurnOffLight()
{
    if (IsLightOn)
    {
        PointLightComp->SetVisibility(false);
        IsLightOn = false;
    }
    else
    {
        PointLightComp->SetVisibility(true);
        IsLightOn = true;
    }
}

actor_comunicationCharacter.h

// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "actor_comunicationCharacter.generated.h"

UCLASS(config=Game)
class Aactor_comunicationCharacter : public ACharacter
{
	GENERATED_BODY()

	/** Camera boom positioning the camera behind the character */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
	class USpringArmComponent* CameraBoom;

	/** Follow camera */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
	class UCameraComponent* FollowCamera;
public:
	Aactor_comunicationCharacter();

	/** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
	float BaseTurnRate;

	/** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
	float BaseLookUpRate;

protected:
	UPROPERTY(EditInstanceOnly, BlueprintReadWrite , Category = "chose_light")
	class ACeilingLight* CeilingLightToToggle;        //点灯类对象
	void ToggleCeilingLight();                        //切换灯
	
	virtual void NotifyActorBeginOverlap(AActor* OtherActor);  //通知角色进入判定范围
	virtual void NotifyActorEndOverlap(AActor* OtherActor);    //通知角色离开判定范围
	class USphereComponent* SphereComp;                        //设置碰撞的网格体
	/** Resets HMD orientation in VR. */
	void OnResetVR();

	/** Called for forwards/backward input */
	void MoveForward(float Value);

	/** Called for side to side input */
	void MoveRight(float Value);

	/** 
	 * Called via input to turn at a given rate. 
	 * @param Rate	This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
	 */
	void TurnAtRate(float Rate);

	/**
	 * Called via input to turn look up/down at a given rate. 
	 * @param Rate	This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
	 */
	void LookUpAtRate(float Rate);

	/** Handler for when a touch input begins. */
	void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location);

	/** Handler for when a touch input stops. */
	void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location);

protected:
	// APawn interface
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
	// End of APawn interface

public:
	/** Returns CameraBoom subobject **/
	FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
	/** Returns FollowCamera subobject **/
	FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; }
};


actor_comunicationCharacter.cpp

// Copyright Epic Games, Inc. All Rights Reserved.

#include "actor_comunicationCharacter.h"
#include "HeadMountedDisplayFunctionLibrary.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/Controller.h"
#include "GameFramework/SpringArmComponent.h"
#include "RotatingActor.h"
#include "Components/SphereComponent.h"
#include "CeilingLight.h"
//
// Aactor_comunicationCharacter

Aactor_comunicationCharacter::Aactor_comunicationCharacter()
{
	// Set size for collision capsule
	GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);

	// set our turn rates for input
	BaseTurnRate = 45.f;
	BaseLookUpRate = 45.f;

	// Don't rotate when the controller rotates. Let that just affect the camera.
	bUseControllerRotationPitch = false;
	bUseControllerRotationYaw = false;
	bUseControllerRotationRoll = false;

	// Configure character movement
	GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input...	
	GetCharacterMovement()->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // ...at this rotation rate
	GetCharacterMovement()->JumpZVelocity = 600.f;
	GetCharacterMovement()->AirControl = 0.2f;

	// Create a camera boom (pulls in towards the player if there is a collision)
	CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
	CameraBoom->SetupAttachment(RootComponent);
	CameraBoom->TargetArmLength = 300.0f; // The camera follows at this distance behind the character	
	CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller

	// Create a follow camera
	FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
	FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation
	FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm

	// Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character) 
	// are set in the derived blueprint asset named MyCharacter (to avoid direct content references in C++)
	SphereComp = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComp"));
	SphereComp->AttachToComponent(GetMesh(), FAttachmentTransformRules::KeepRelativeTransform);
	SphereComp->SetSphereRadius(200);

//	UE_LOG(LogTemp, Warning, TEXT("Hello"));
}

//
// Input

void Aactor_comunicationCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
	// Set up gameplay key bindings
	check(PlayerInputComponent);
	PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
	PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);

	PlayerInputComponent->BindAxis("MoveForward", this, &Aactor_comunicationCharacter::MoveForward);
	PlayerInputComponent->BindAxis("MoveRight", this, &Aactor_comunicationCharacter::MoveRight);

	// We have 2 versions of the rotation bindings to handle different kinds of devices differently
	// "turn" handles devices that provide an absolute delta, such as a mouse.
	// "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick
	PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
	PlayerInputComponent->BindAxis("TurnRate", this, &Aactor_comunicationCharacter::TurnAtRate);
	PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
	PlayerInputComponent->BindAxis("LookUpRate", this, &Aactor_comunicationCharacter::LookUpAtRate);

	// handle touch devices
	PlayerInputComponent->BindTouch(IE_Pressed, this, &Aactor_comunicationCharacter::TouchStarted);
	PlayerInputComponent->BindTouch(IE_Released, this, &Aactor_comunicationCharacter::TouchStopped);

	// VR headset functionality
	PlayerInputComponent->BindAction("ResetVR", IE_Pressed, this, &Aactor_comunicationCharacter::OnResetVR);
	//点灯的控制键
	PlayerInputComponent->BindAction("Use", IE_Pressed, this, &Aactor_comunicationCharacter::ToggleCeilingLight);
}


void Aactor_comunicationCharacter::OnResetVR()
{
	// If actor_comunication is added to a project via 'Add Feature' in the Unreal Editor the dependency on HeadMountedDisplay in actor_comunication.Build.cs is not automatically propagated
	// and a linker error will result.
	// You will need to either:
	//		Add "HeadMountedDisplay" to [YourProject].Build.cs PublicDependencyModuleNames in order to build successfully (appropriate if supporting VR).
	// or:
	//		Comment or delete the call to ResetOrientationAndPosition below (appropriate if not supporting VR)
	UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition();
}

void Aactor_comunicationCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location)
{
		Jump();
}

void Aactor_comunicationCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location)
{
		StopJumping();
}

void Aactor_comunicationCharacter::TurnAtRate(float Rate)
{
	// calculate delta for this frame from the rate information
	AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}

void Aactor_comunicationCharacter::LookUpAtRate(float Rate)
{
	// calculate delta for this frame from the rate information
	AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
}

void Aactor_comunicationCharacter::MoveForward(float Value)
{
	if ((Controller != nullptr) && (Value != 0.0f))
	{
		// find out which way is forward
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);

		// get forward vector
		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
		AddMovementInput(Direction, Value);
	}
}

void Aactor_comunicationCharacter::MoveRight(float Value)
{
	if ( (Controller != nullptr) && (Value != 0.0f) )
	{
		// find out which way is right
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);
	
		// get right vector 
		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
		// add movement in that direction
		AddMovementInput(Direction, Value);
	}
}
void Aactor_comunicationCharacter::NotifyActorBeginOverlap(AActor* OtherActor)
{
	//有任何角色之间的碰撞都会进入这里
	if (ARotatingActor* RotatingActorCheck = Cast<ARotatingActor>(OtherActor))//获取相关角色的指针
	{
		UE_LOG(LogTemp, Warning, TEXT("yes"));
		RotatingActorCheck->SetbCanRotate(true);
	}
	else {
		UE_LOG(LogTemp, Warning, TEXT("no"));
	}
}

void Aactor_comunicationCharacter::NotifyActorEndOverlap(AActor* OtherActor)
{
	if (ARotatingActor* RotatingActorCheck = Cast<ARotatingActor>(OtherActor))
	{
		RotatingActorCheck->SetbCanRotate(false);
	}
}


void Aactor_comunicationCharacter::ToggleCeilingLight()
{

	if (CeilingLightToToggle)
	{
		CeilingLightToToggle->TurnOffLight();
	}
}

3、重点解读

在类内部声明一个要控制的角色的对象变量,通过蓝图定义该变量,将要控制的角色的指针引用到玩家类内部

三、委托

1、整体流程

第一步:创建用于触发的盒体角色。声明委托类型,定义委托变量。用委托变量的ExecuteIfBound()发出委托用于触发相关actor。

第二步:创建一个响应委托的角色。在begin函数中绑定相关函数,在接收到广播后运行被绑定的函数。

2、源码带注释

BossActor.h

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

#pragma once

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

DECLARE_DELEGATE(FOnBossDiedDelegate);   //宏定义委托类型

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

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

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

protected:
	UFUNCTION()
	void HandleBossDiedEvent();                        

	UPROPERTY(EditInstanceOnly, BlueprintReadWrite)
	class UBoxComponent* BoxComp;                             //碰撞盒
	virtual void NotifyActorBeginOverlap(AActor* OtherActor); //碰撞回调函数

public:
	FOnBossDiedDelegate OnBossDied;  //声明委托类型

};

BossActor.cpp

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


#include "BossActor.h"
#include "Components/BoxComponent.h"

// Sets default values
ABossActor::ABossActor()
{
 	// 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;
	BoxComp = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComp"));
	BoxComp->SetBoxExtent(FVector(128, 128, 64));
	BoxComp->SetVisibility(true);

}

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

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

}

void ABossActor::HandleBossDiedEvent()
{
	OnBossDied.ExecuteIfBound();     //发送广播,让设置委托的actor被触发
}

void ABossActor::NotifyActorBeginOverlap(AActor* OtherActor)
{
	HandleBossDiedEvent();     //碰撞后发送广播
}

DoorActor.h

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components/TimelineComponent.h"
#include "DoorActor.generated.h"


UCLASS()
class ACTOR_COMUNICATION_API ADoorActor : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ADoorActor();
	// 用于保留曲线资产的变量
	UPROPERTY(EditInstanceOnly)
		UCurveFloat* DoorTimelineFloatCurve;

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

    void BossDiedEventFunction();
    UPROPERTY(EditInstanceOnly, BlueprintReadWrite)
        class ABossActor* BossActorReference;

    //表示门的网格体组件
    UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
        UStaticMeshComponent* DoorFrame;
    UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
        UStaticMeshComponent* Door;

    //用于对门网格体进行动画处理的时间轴组件
    UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
        UTimelineComponent* DoorTimelineComp;

    //用于处理我们的更新轨道事件的浮点轨道签名
    FOnTimelineFloat UpdateFunctionFloat;

    //用于使用时间轴图表更新门相对位置的函数
    UFUNCTION()
        void UpdateTimelineComp(float Output);

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

};

DoorActor.cpp

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


#include "DoorActor.h"
#include "BossActor.h"
// Sets default values
ADoorActor::ADoorActor()
{
 	// 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;
    //创建我们的默认组件
    DoorFrame = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorFrameMesh"));
    Door = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorMesh"));
    DoorTimelineComp = CreateDefaultSubobject<UTimelineComponent>(TEXT("DoorTimelineComp"));

    //设置绑定
    DoorFrame->SetupAttachment(RootComponent);
    Door->AttachToComponent(DoorFrame, FAttachmentTransformRules::KeepRelativeTransform);
    Door->SetRelativeLocation(FVector(0, 35, 0));

}

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

    //将浮点轨道绑定到UpdateTimelineComp函数的输出
    UpdateFunctionFloat.BindDynamic(this, &ADoorActor::UpdateTimelineComp);

    //如果有浮点曲线,将其图表绑定到我们的更新函数
    if (DoorTimelineFloatCurve)
    {
        DoorTimelineComp->AddInterpFloat(DoorTimelineFloatCurve, UpdateFunctionFloat);
    }

    if (BossActorReference)
    {
        BossActorReference->OnBossDied.BindUObject(this, &ADoorActor::BossDiedEventFunction);   //绑定回调函数
    }
}

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

}

void ADoorActor::BossDiedEventFunction()
{
    DoorTimelineComp->Play();
}

void ADoorActor::UpdateTimelineComp(float Output)
{
    // 基于时间轴曲线的输出,创建并设置门的新相对位置
    FRotator DoorNewRotation = FRotator(0.0f, Output, 0.f);
    Door->SetRelativeRotation(DoorNewRotation);
}

3、重点解读

(1)宏定义委托类型

DECLARE_DELEGATE(FOnBossDiedDelegate);   //宏定义委托类型

(2)主动发送广播

OnBossDied.ExecuteIfBound();  

(3)初始化时将接收到广播的回调函数绑定好

        BossActorReference->OnBossDied.BindUObject(this, &ADoorActor::BossDiedEventFunction);   //绑定回调函数

四、接口

这个就是一种封装技巧,一个相同作用的功能在不同的actor中会有不同的实现方法,比如同样是开关,在面对电灯和门实现方法肯定不同,但在玩家类的调用中希望可以使用同一个叫做“打开”函数用于控制灯和门的开关。

整体流程

第一步:定义接口类。在接口类中,声明虚函数。

第二步:在被触发函数中定义虚函数

第三步:在主动的角色中使用cast引用角色后,即可调用统一的虚函数。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值