UE4 C++ ActionRoguelike开发记录

本文详细介绍了虚幻引擎中角色、子弹和AI系统的实现。角色类包括设置摄像机、弹簧臂、人物移动和动作绑定,以及不同类型的攻击效果。子弹类基于SProjectileBase,具有碰撞检测、爆炸效果和不同攻击类型如普通攻击、闪现攻击。AI系统涉及行为树、导航网格体、环境查询系统,以及角色间的交互逻辑。此外,还涵盖了交互组件、血条显示、游戏时间等UI元素的实现。

目录

角色类:SCharacter

设置摄像机

弹簧臂和摄像机设置

设置人物移动和动作绑定

移动与朝向:MoveForward/MoveRight、Turn/LoopUp

为人物绑定设置子弹类:SpawnProjectile适配器类

设置攻击动画以及攻击特效

普通攻击

黑洞攻击

闪现攻击

❗为角色添加属性组件:USAttributeComponent

为角色添加交互组件接口:USInteractionComponent* InteractionComp;

子弹类:SProejctileBase

胶囊碰撞体:USphereComponent* SphereComp;

子弹移动组件:UProjectileMovementComponent* MoveComp;

粒子系统组件(平A效果):UParticleSystemComponent* EffectComp;

粒子系统组件(爆炸效果):UParticleSystem* ImpactVFX;

子弹爆炸音效组件:USoundCue* ImpactSound;

?子弹播放声音组件:UAudioComponent* AudioComp;

子弹击中画面震动效果:TSubclassOf ImpactShake;

⭐碰撞事件&爆炸(虚函数):void Explode();(BlueprintNativeEvent)

普通攻击:SMagicProjectile

设置并重写OnActorOverlap逻辑:

设置子弹伤害:DamageAmount

❗闪现:SDashProjectile

重写BeginPlay:设置子弹存活时间

重写爆炸逻辑Explode_Implementation

实现闪现传送效果:TeleportInstigator

设置定时器:FTimerHandle

黑洞攻击(蓝图):Proj_BlackHole

径向力Force Strength

可影响物体Object Types to Affect

吸进黑洞后要杀掉物体:

❗接口类:USGameplayInterface

USInteractionComponent

世界中的物体

爆炸油桶:ASExplosiveBarrel

设置StaticMesh,径向力

初始化Actor组件(添加碰撞事件)

宝箱(实现交互接口):ASItemChest

血包(实现交互接口):ASPowerupActor

血包有很多种,因此接口实现逻辑由子类实现:

吃掉后隐藏血包(计时器):

血包子类:ASPowerup_HealthPotion

UI:Widget

十字准星

创建Widget并设置:

游戏开始时添加到屏幕上

人物血条、Credits、游戏进行时间:Main_HUD

血条

Credits:

游戏进行时间:

AI

UE中的AI系统

行为树:

添加导航网格体:NavMeshBoundsVolume​编辑

游戏AI角色:SAICharacter

游戏AI控制器:SAIController

设置行为树

为SAICharacter设置控制器

游戏AI逻辑-范围内攻击:USBTService_CheckAttackRange(UBTService)

范围查询逻辑

在行为树添加此Service

游戏AI范围内攻击任务结点:USBTTask_RangedAttack

AI朝向玩家:Set default focus

环境查询系统:

创建EQS

在玩家周围半径内设置EQS生成移动目的地

AI死亡


角色类:SCharacter

设置摄像机

弹簧臂和摄像机设置

	UPROPERTY(VisibleAnywhere)
	USpringArmComponent* SpringArmComp;

	UPROPERTY(VisibleAnywhere)
	UCameraComponent* CameraComp;

在构造函数中创建这两个类,并设置依赖关系:

弹簧臂附着在RootComponent,摄像机附着在弹簧臂上

	SpringArmComp = CreateDefaultSubobject<USpringArmComponent>("SpringArmComp");
	SpringArmComp->bUsePawnControlRotation = true;
	SpringArmComp->SetupAttachment(RootComponent);

	CameraComp = CreateDefaultSubobject<UCameraComponent>("CameraComp");
	CameraComp->SetupAttachment(SpringArmComp);

    GetCharacterMovement()->bOrientRotationToMovement = true;
	bUseControllerRotationYaw = false;

注意 bUseControllerRotationYaw =false;其效果为:

bUseControllerRotationYaw=true;

bUseControllerRotationYaw=false; 

应该设置为false, 

同时注意GetCharacterMovement()->bOrientRotationToMovement = true;

GetCharacterMovement()->bOrientRotationToMovement = false;如下

 GetCharacterMovement()->bOrientRotationToMovement = true;如下

类似黑暗之魂这种第三人称的移动朝向方式。

设置人物移动和动作绑定

void ASCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

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

	PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
	PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);

	PlayerInputComponent->BindAction("PrimaryAttack", IE_Pressed, this, &ASCharacter::PrimaryAttack);
	// Used generic name 'SecondaryAttack' for binding
	PlayerInputComponent->BindAction("SecondaryAttack", IE_Pressed, this, &ASCharacter::BlackHoleAttack);
	PlayerInputComponent->BindAction("Dash", IE_Pressed, this, &ASCharacter::Dash);
	PlayerInputComponent->BindAction("PrimaryInteract", IE_Pressed, this, &ASCharacter::PrimaryInteract);

	PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
}

移动与朝向:MoveForward/MoveRight、Turn/LoopUp

void ASCharacter::MoveForward(float Value)
{
	FRotator ControlRot = GetControlRotation();
	ControlRot.Pitch = 0.0f;
	ControlRot.Roll = 0.0f;

	AddMovementInput(ControlRot.Vector(), Value);
}


void ASCharacter::MoveRight(float Value)
{
	FRotator ControlRot = GetControlRotation();
	ControlRot.Pitch = 0.0f;
	ControlRot.Roll = 0.0f;

	// X = Forward (Red)
	// Y = Right (Green)
	// Z = Up (Blue)

	FVector RightVector = FRotationMatrix(ControlRot).GetScaledAxis(EAxis::Y);

	AddMovementInput(RightVector, Value);
}

 其中Turn和LookUp绑定的函数是由APawn中已经写好的内容。

&APawn::AddControllerYawInput
&APawn::AddControllerPitchInput

这里附上Yaw、Roll、Pitch的内容,结合代码理解:

UE是左手坐标系:拇指X,食指Y,中指Z(中指向上摆放)
X:Roll翻滚角
Y:Pitch俯仰角
Z:Yaw偏航角

动图:

1.俯仰:(Pitch)

2.翻滚:(Roll)

3.偏航:(Yaw)

所以,MoveForward和MoveRight只与Yaw有关,控制偏航角度;Turn也和Yaw有关,控制偏航角度;而LoopUp与Pitch有关,控制上下移动视角。

为人物绑定设置子弹类:SpawnProjectile适配器类

  • 生成位置:手部Socket(HandLocation)
  • Actor生成:设置碰撞,instigator为角色自身
  • 碰撞预设:
  • 子弹轨迹:起点为手部,终点为十字准星方向
void ASCharacter::SpawnProjectile(TSubclassOf<AActor> ClassToSpawn)
{
	if (ensureAlways(ClassToSpawn))
	{
		FVector HandLocation = GetMesh()->GetSocketLocation(HandSocketName);

		FActorSpawnParameters SpawnParams;
		SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
		SpawnParams.Instigator = this;

		FCollisionShape Shape;
		Shape.SetSphere(20.0f);

		// Ignore Player
		FCollisionQueryParams Params;
		Params.AddIgnoredActor(this);

		FCollisionObjectQueryParams ObjParams;
		ObjParams.AddObjectTypesToQuery(ECC_WorldDynamic);
		ObjParams.AddObjectTypesToQuery(ECC_WorldStatic);
		ObjParams.AddObjectTypesToQuery(ECC_Pawn);

		FVector TraceStart = CameraComp->GetComponentLocation();

		// endpoint far into the look-at distance (not too far, still adjust somewhat towards crosshair on a miss)
		FVector TraceEnd = CameraComp->GetComponentLocation() + (GetControlRotation().Vector() * 5000);

		FHitResult Hit;
		// returns true if we got to a blocking hit
		if (GetWorld()->SweepSingleByObjectType(Hit, TraceStart, TraceEnd, FQuat::Identity, ObjParams, Shape, Params))
		{
			// Overwrite trace end with impact point in world
			TraceEnd = Hit.ImpactPoint;
		}

		// find new direction/rotation from Hand pointing to impact point in world.
		FRotator ProjRotation = FRotationMatrix::MakeFromX(TraceEnd - HandLocation).Rotator();

		FTransform SpawnTM = FTransform(ProjRotation, HandLocation);
		GetWorld()->SpawnActor<AActor>(ClassToSpawn, SpawnTM, SpawnParams);
	}
}

设置攻击动画以及攻击特效

void ASCharacter::StartAttackEffects()
{
	PlayAnimMontage(AttackAnim);

	UGameplayStatics::SpawnEmitterAttached(CastingEffect, GetMesh(), HandSocketName, FVector::ZeroVector, FRotator::ZeroRotator, EAttachLocation::SnapToTarget);
}

普通攻击

void ASCharacter::PrimaryAttack()
{
	StartAttackEffects();

	GetWorldTimerManager().SetTimer(TimerHandle_PrimaryAttack, this, &ASCharacter::PrimaryAttack_TimeElapsed, AttackAnimDelay);
}


void ASCharacter::PrimaryAttack_TimeElapsed()
{
	SpawnProjectile(ProjectileClass);
}

黑洞攻击

void ASCharacter::BlackHoleAttack()
{
	StartAttackEffects();

	GetWorldTimerManager().SetTimer(TimerHandle_BlackholeAttack, this, &ASCharacter::BlackholeAttack_TimeElapsed, AttackAnimDelay);
}


void ASCharacter::BlackholeAttack_TimeElapsed()
{
	SpawnProjectile(BlackHoleProjectileClass);
}

闪现攻击

void ASCharacter::Dash()
{
	StartAttackEffects();

	GetWorldTimerManager().SetTimer(TimerHandle_Dash, this, &ASCharacter::Dash_TimeElapsed, AttackAnimDelay);
}


void ASCharacter::Dash_TimeElapsed()
{
	SpawnProjectile(DashProjectileClass);
}

❗为角色添加属性组件:USAttributeComponent

为角色添加交互组件接口:USInteractionComponent* InteractionComp;

子弹类:SProejctileBase

ASProjectileBase::ASProjectileBase()
{
	SphereComp = CreateDefaultSubobject<USphereComponent>("SphereComp");
	SphereComp->SetCollisionProfileName("Projectile");
	SphereComp->OnComponentHit.AddDynamic(this, &ASProjectileBase::OnActorHit);
	RootComponent = SphereComp;

	EffectComp = CreateDefaultSubobject<UParticleSystemComponent>("EffectComp");
	EffectComp->SetupAttachment(RootComponent);

	AudioComp = CreateDefaultSubobject<UAudioComponent>("AudioComp");
	AudioComp->SetupAttachment(RootComponent);

	MoveComp = CreateDefaultSubobject<UProjectileMovementComponent>("ProjectileMoveComp");
	MoveComp->bRotationFollowsVelocity = true;
	MoveComp->bInitialVelocityInLocalSpace = true;
	MoveComp->ProjectileGravityScale = 0.0f;
	MoveComp->InitialSpeed = 8000;

	ImpactShakeInnerRadius = 0.0f;
	ImpactShakeOuterRadius = 1500.0f;

}

胶囊碰撞体:USphereComponent* SphereComp;

  • 设置名称
  • 设置碰撞预设
  • 设置碰撞触发事件
  • 将RootComponent设为碰撞体

子弹移动组件:UProjectileMovementComponent* MoveComp;

  • 初始化相关移动属性,比如速度

粒子系统组件(平A效果):UParticleSystemComponent* EffectComp;

在cpp中构造函数进行初始化,只需要设置名称与挂载RootComponent。

因为子弹效果必然要跟随着子弹,故需要附着在RootComponent上。

粒子系统组件(爆炸效果):UParticleSystem* ImpactVFX;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值