具体太麻烦了,我直接贴代码了
SPowerUp_Actor
.h
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "SGameplayInterface.h" #include "Components/SphereComponent.h" #include "GameFramework/Actor.h" #include "SPowerUp_Actor.generated.h" UCLASS() class ACTIONROUGELIKE_API ASPowerUp_Actor : public AActor , public ISGameplayInterface { GENERATED_BODY() public: // Sets default values for this actor's properties ASPowerUp_Actor(); protected: // Called when the game starts or when spawned UPROPERTY(EditAnywhere,Category="Powerup") float RespawnTime; UFUNCTION() void ShowPowerup(); void HideAndCooldownPowerup(); void SetPowerupState(bool bNewIsActive); UPROPERTY(VisibleAnywhere,Category="Component") USphereComponent* SphereComp; public: // Called every frame void Interact_Implementation(APawn* InstigationPawn) override; };
.cpp
// Fill out your copyright notice in the Description page of Project Settings. //药水Base #include "SPowerUp_Actor.h" // Sets default values ASPowerUp_Actor::ASPowerUp_Actor() { // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. SphereComp = CreateDefaultSubobject<USphereComponent>("SphereComp"); // SphereComp->SetCollisionProfileName("Powerup"); RootComponent = SphereComp; RespawnTime = 10.0f; } void ASPowerUp_Actor::ShowPowerup() { SetPowerupState(true); } void ASPowerUp_Actor::HideAndCooldownPowerup() { SetPowerupState(false); FTimerHandle TimerHandle_RespawnTimer; GetWorldTimerManager().SetTimer(TimerHandle_RespawnTimer,this,&ASPowerUp_Actor::ShowPowerup,RespawnTime); } void ASPowerUp_Actor::SetPowerupState(bool bNewIsActive) { SetActorEnableCollision(bNewIsActive); RootComponent->SetVisibility(bNewIsActive,true); } void ASPowerUp_Actor::Interact_Implementation(APawn* InstigationPawn) { ISGameplayInterface::Interact_Implementation(InstigationPawn); }
SPowerUp_HealthPotion
.h
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "SPowerUp_Actor.h" #include "SPowerUp_HealthPotion.generated.h" class UStaticMeshComponent; /** * */ UCLASS() class ACTIONROUGELIKE_API ASPowerUp_HealthPotion : public ASPowerUp_Actor { GENERATED_BODY() public: ASPowerUp_HealthPotion(); protected: UPROPERTY(VisibleAnywhere,Category = "Components") UStaticMeshComponent* StaticMeshComp; public: void Interact_Implementation(APawn* InstigationPawn) override; };
.cpp
// Fill out your copyright notice in the Description page of Project Settings. #include "SPowerUp_HealthPotion.h" #include "SAttributeComponent.h" ASPowerUp_HealthPotion::ASPowerUp_HealthPotion() { StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>("StaticMeshComp"); StaticMeshComp->SetCollisionEnabled(ECollisionEnabled::NoCollision); StaticMeshComp->SetupAttachment(RootComponent); } void ASPowerUp_HealthPotion::Interact_Implementation(APawn* InstigationPawn) { if(!ensure(InstigationPawn)) { return; } USAttributeComponent* AttributeComp = Cast<USAttributeComponent>(InstigationPawn->GetComponentByClass(USAttributeComponent::StaticClass())); //如果不是最大的血量 if(ensure(AttributeComp && !AttributeComp->IsFullHealth())) { //只有有ApplyHealthChange这个函数的才可以回复血量 if(AttributeComp -> ApplyHealthChange(AttributeComp->GetMaxHealth() )) { HideAndCooldownPowerup(); } } }
SCharacter
.h
// Fill out your copyright notice in the Description page of Project Settings. //这是角色 #pragma once #include "CoreMinimal.h" #include "SAttributeComponent.h" #include "SInteractionComponent.h" #include "Camera/CameraComponent.h" #include "GameFramework/Character.h" #include "GameFramework/SpringArmComponent.h" #include "SCharacter.generated.h" class UCameraComponent; class USpringArmComponent; class USInteractionComponent; UCLASS() class ACTIONROUGELIKE_API ASCharacter : public ACharacter { GENERATED_BODY() public: // Sets default values for this character's properties ASCharacter(); protected: //在这里设置需要的指针 //设置了一个弹簧臂 UPROPERTY(VisibleAnywhere) USpringArmComponent* SpringArmComp;//定义一个结构体指针 //设置了一个相机 UPROPERTY(VisibleAnywhere) UCameraComponent* CameraComp; //设置了一个接口 UPROPERTY(VisibleAnywhere) USInteractionComponent* InteractionComp; //设置了一个可以随时编辑的叫做ProjectileClass类,类型是Actor UPROPERTY(EditAnywhere, Category="Attack")//迭代器分类为Attack TSubclassOf<AActor> ProjectileClass; UPROPERTY(EditAnywhere, Category = "Attack") TSubclassOf<AActor> BlackHoleProjectileClass; UPROPERTY(EditAnywhere, Category = "Attack") TSubclassOf<AActor> DashProjectileClass; //添加一个动画蒙太奇 UPROPERTY(EditAnywhere, Category="Attack") UAnimMontage* AttackAnim; //定时器 FTimerHandle TimeHandle_PrimaryAttack; FTimerHandle TimerHandle_BlackholeAttack; FTimerHandle TimerHandle_Dash; //角色属性 UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category="Components") USAttributeComponent * AttributeComp; UPROPERTY(VisibleAnywhere, Category = "Effects") FName TimeToHitParamName; UPROPERTY(VisibleAnywhere, Category = "Effects") FName HandSocketName; /* Particle System played during attack animation */ UPROPERTY(EditAnywhere, Category = "Attack") UParticleSystem* CastingEffect; //动画间隔时间 float AttackAnimDelay; //在这里设置需要的函数 // Called when the game starts or when spawned virtual void BeginPlay() override; //移动 void MoveForward(float Value); void MoveRight(float Value); //射线 void PrimaryInteraction(); //子弹 void PrimaryAttack(); void PrimaryAttack_TimeElapsed(); void BlackHoleAtt(); void BlackholeAtt_TimeElapsed(); void Dash(); void Dash_TimeElapsed(); //生成子弹 void SpawnProjectile(TSubclassOf<AActor> ClassToSpawn); //开始攻击特效 void StartAttackEffects(); //血量变化 UFUNCTION() void OnHealthChanged(AActor* InstigatorActor,USAttributeComponent* OwningComp,float NewHealth,float Delta); 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 PostInitializeComponents() override; };
.cpp
// Fill out your copyright notice in the Description page of Project Settings. //这是角色 #include "SCharacter.h" #include "GameFramework/CharacterMovementComponent.h" #include "Kismet/GameplayStatics.h" // Sets default values ASCharacter::ASCharacter() { // Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it. PrimaryActorTick.bCanEverTick = true; //这里设置初始组件 //SpringArmComp为RootComponent的子物体 SpringArmComp = CreateDefaultSubobject<USpringArmComponent>("SpringArmComp"); //命名为SpringArmComp SpringArmComp->bUsePawnControlRotation = true; //If this component is placed on a pawn, should it use the view/control rotation of the pawn where possible? When disabled, the component will revert to using the stored RelativeRotation of the component. SpringArmComp->SetupAttachment(RootComponent); //标记为子物体 //CameraComp为SpringArmComp的子物体 CameraComp = CreateDefaultSubobject<UCameraComponent>("CameraComp"); CameraComp->SetupAttachment(SpringArmComp); //将创建的InteractionComp绑定在角色上 InteractionComp = CreateDefaultSubobject<USInteractionComponent>("InteractionComp"); //将创建的AttributeComp绑定在角色上 AttributeComp = CreateDefaultSubobject<USAttributeComponent>("AttributeComp"); //设置了chara在旋转的时候会跟着鼠标视角进行旋转 GetCharacterMovement()->bOrientRotationToMovement = true; //设置了角色不能Z轴移动 bUseControllerRotationYaw = false; AttackAnimDelay = 0.2f; TimeToHitParamName = "TimeToHit"; HandSocketName = "Muzzle_01"; } void ASCharacter::PostInitializeComponents() { //初始化的时候绑定事件 Super::PostInitializeComponents(); AttributeComp->OnHealthChanged.AddDynamic(this,&ASCharacter::OnHealthChanged); } // Called to bind functionality to input 输入绑定 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); //设置了一个攻击的Action PlayerInputComponent->BindAction("PrimaryAttack",IE_Pressed,this,&ASCharacter::PrimaryAttack); PlayerInputComponent->BindAction("PrimaryInteraction",IE_Pressed,this,&ASCharacter::PrimaryInteraction); PlayerInputComponent->BindAction("SecondaryAttack", IE_Pressed, this, &ASCharacter::BlackHoleAtt); PlayerInputComponent->BindAction("Dash", IE_Pressed, this, &ASCharacter::Dash); //设置了跳跃 PlayerInputComponent->BindAction("Jump",IE_Pressed,this,&ASCharacter::Jump); } //移动 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; FVector RightVector = FRotationMatrix(ControlRot).GetScaledAxis(EAxis::Y); AddMovementInput(RightVector,Value); } //攻击动画 void ASCharacter::PrimaryAttack() { //动画蒙太奇 StartAttackEffects(); //设置定时器 GetWorldTimerManager().SetTimer(TimeHandle_PrimaryAttack, this,&ASCharacter::PrimaryAttack_TimeElapsed,0.2f); //GetWorldTimerManager().ClearTimer(TimeHandle_PrimaryAttack);//清除定时器 } //子弹类型 void ASCharacter::PrimaryAttack_TimeElapsed() { SpawnProjectile(ProjectileClass); } void ASCharacter::BlackHoleAtt() { StartAttackEffects(); GetWorldTimerManager().SetTimer(TimeHandle_PrimaryAttack,this,&ASCharacter::BlackholeAtt_TimeElapsed,AttackAnimDelay); } void ASCharacter::BlackholeAtt_TimeElapsed() { SpawnProjectile(BlackHoleProjectileClass); } void ASCharacter::Dash() { StartAttackEffects(); GetWorldTimerManager().SetTimer(TimeHandle_PrimaryAttack,this,&ASCharacter::Dash_TimeElapsed,AttackAnimDelay); } void ASCharacter::Dash_TimeElapsed() { SpawnProjectile(DashProjectileClass); } //统一动作 void ASCharacter::StartAttackEffects() { PlayAnimMontage(AttackAnim); UGameplayStatics::SpawnEmitterAttached(CastingEffect, GetMesh(), HandSocketName, FVector::ZeroVector, FRotator::ZeroRotator, EAttachLocation::SnapToTarget); } //按E发出射线 void ASCharacter::PrimaryInteraction() { if(InteractionComp) { InteractionComp->PrimaryInteract(); } } //新的射击 void ASCharacter::SpawnProjectile(TSubclassOf<AActor> ClassToSpawn) { if(ensure(ProjectileClass)) { //触发函数的时候从手部位置生成一个魔法球的模型 FVector HandLocation = GetMesh()->GetSocketLocation(HandSocketName); FActorSpawnParameters SpawnParameters; SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; SpawnParameters.Instigator=this; //球形碰撞体 FCollisionShape Shape; Shape.SetSphere(20.0f); // FCollisionQueryParams Params; Params.AddIgnoredActor(this); //三种类型 FCollisionObjectQueryParams QueryParams; QueryParams.AddObjectTypesToQuery(ECC_WorldDynamic); QueryParams.AddObjectTypesToQuery(ECC_WorldStatic); QueryParams.AddObjectTypesToQuery(ECC_Pawn); // FVector TraceStart = CameraComp->GetComponentLocation(); FVector TraceEnd = CameraComp->GetComponentLocation() + (GetControlRotation().Vector() * 5000); FHitResult Hit; if(GetWorld()->SweepSingleByObjectType(Hit,TraceStart,TraceEnd,FQuat::Identity,QueryParams,Shape,Params)) { TraceEnd = Hit.ImpactPoint; } //让手部总是朝着十字准星的方向射击,准确的说是跟随射线的终点,这一段的逻辑是终点的Location位置减去手部位置在世界中的Location,用MakeFromX计算出旋转的量 FRotator ProRotator = FRotationMatrix::MakeFromX(TraceEnd - HandLocation).Rotator(); // FTransform Transform = FTransform(ProRotator, HandLocation); //发射 GetWorld()->SpawnActor<AActor>(ClassToSpawn,Transform,SpawnParameters); } } void ASCharacter::Tick(float DeltaTime) { Super::Tick(DeltaTime); } // Called when the game starts or when spawned void ASCharacter::BeginPlay() { Super::BeginPlay(); } void ASCharacter::OnHealthChanged(AActor* InstigatorActor, USAttributeComponent* OwningComp, float NewHealth, float Delta) { if (Delta < 0.0f) { GetMesh()->SetScalarParameterValueOnMaterials(TimeToHitParamName, GetWorld()->TimeSeconds); } //当血量少于0的时候清除控制器的输入 if(NewHealth < 0.0f && Delta<0.0f) { APlayerController * PC = Cast<APlayerController>(GetController()); DisableInput(PC); } } // Called every frame