1.给物体施加一个径向力
定义一个径向力:
URadialForceComponent* RadialForceComp;
在构造函数里赋默认值:
RadialForceComp = CreateDefaultSubobject<URadialForceComponent>(TEXT("RadialForceComp"));
RadialForceComp->SetupAttachment(MeshComp);
RadialForceComp->Radius = 250.0f; //力影响的半径范围
RadialForceComp->bImpulseVelChange = true;//作用力速率变化为真
RadialForceComp->bAutoActivate = false;//prevent component from ticking, and only use fireImpulse() instead把自动激活关闭,用fireimpulse的方法来代替
RadialForceComp->bIgnoreOwningActor = true;//是否忽略自身
触发:
RadialForceComp->FireImpulse();
2.创建一个ActorComponent处理主角掉血事件
新建一个类 继承自UActorComponent:
class COOPGAME_API USHealthComponent : public UActorComponent
定义一个OnHealthChanged的事件:
UPROPERTY(BlueprintAssignable,Category = "Events")
FOnHealthChangedSignature OnHealthChanged;
在UCLASS的上面声明这个事件:
DECLARE_DYNAMIC_MULTICAST_DELEGATE_SixParams(FOnHealthChangedSignature, USHealthComponent*, HealthComp, float, Health, float, HealthDelta, const class UDamageType*, DamageType, class AController*, InstigatedBy, AActor*, DamageCauser);//定义一个动态、多播、委托、六个参数的事件
定义一个HandleTakeAnyDamage的事件来处理受到的伤害:
UFUNCTION()
void HandleTakeAnyDamage(AActor* DamagedActor ,float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser);
将主角受到的伤害动态绑定到HandleTakeAnyDamage上:
AActor* MyOwner = GetOwner();
if (MyOwner)
{
MyOwner->OnTakeAnyDamage.AddDynamic(this, &USHealthComponent::HandleTakeAnyDamage);
}
实现HandleTakeAnyDamage方法:
void USHealthComponent::HandleTakeAnyDamage(AActor * DamagedActor, float Damage, const UDamageType * DamageType, AController * InstigatedBy, AActor * DamageCauser)
{
if (Damage <= 0.0f)
{
return;
}
//update helth clamped
Health = FMath::Clamp(Health - Damage, 0.0f, DefaultHealth);
UE_LOG(LogTemp, Warning, TEXT("Health Changed: %s"),*FString::SanitizeFloat(Health));
OnHealthChanged.Broadcast(this, Health, Damage, DamageType, InstigatedBy, DamageCauser);//将参数广播给OnHealthChanged
}
3.若要让服务器和客户端同时表现一样的效果,需要让服务器通知客户端该做什么,但代码依然在服务器端执行
将是否爆破的UPROPERTY加上ReplicatedUsing = OnRep_Exploded:
UPROPERTY(ReplicatedUsing = OnRep_Exploded)
bool bExploded;
定义一个事件OnRep_Exploded将上述实现
UFUNCTION()
void OnRep_Exploded();
在血量为0时,同时执行 OnRep_Exploded() 函数,目的是为了让客户端表现和服务器端一样的状态:
void ASExplosiveBarrel::OnHealthChanged(USHealthComponent * OwningHealthComp, float Health, float HealthDelta, const UDamageType * DamageType, AController * InstigatedBy, AActor * DamageCauser)
{
if (bExploded)
{
return;
}
if (Health <= 0.0f)
{
bExploded = true;
OnRep_Exploded();
FVector BoostIntensity = FVector::UpVector * ExplosionImpulse;
MeshComp->AddImpulse(BoostIntensity, NAME_None, true);
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ExplosionEffect, GetActorLocation());
MeshComp->SetMaterial(0, ExplodedMaterial);
RadialForceComp->FireImpulse();
}
}
void ASExplosiveBarrel::OnRep_Exploded()
{
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ExplosionEffect, GetActorLocation());
MeshComp->SetMaterial(0, ExplodedMaterial);
}
接下来记得在生命周期中复制bExploded给客户端,在cpp中引入头文件#include"Net/UnrealNetwork.h"后即可直接添加GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const 方法,后面的参数可保持不变:
void ASExplosiveBarrel::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ASExplosiveBarrel,bExploded);
}
4.客户端服务器端同步
在构造函数中设置可重复为true:
SetReplicates(true);
定义一个服务器开火的事件,设置UFUNCTION里面的内容:
UFUNCTION(Server, Reliable, WithValidation)
void ServerFire();
接着在cpp里添加服务器开火函数的_Implementation和_Validate,直接在ServerFire后添加(Validate有时候不需要):
void ASWeapon::ServerFire_Implementation()
{
Fire();
}
bool ASWeapon::ServerFire_Validate()
{
return true;
}
判断Role是否在服务器上:
if (Role < ROLE_Authority) //判断Role是否在服务器上
{
ServerFire(); //Role < ROLE_Authority,说明不在服务器上,让Server处理这个开火
}
else{} //在服务器上,自己处理开火
源码贴:
1 // Fill out your copyright notice in the Description page of Project Settings. 2 3 #pragma once 4 5 #include "CoreMinimal.h" 6 #include "GameFramework/Character.h" 7 #include"Public/SWeapon.h" 8 #include "SCharacter.generated.h" 9 10 class UCameraComponent; 11 class USpringArmComponent; 12 class ASWeapon; 13 class USHealthComponent; 14 15 UCLASS() 16 class COOPGAME_API ASCharacter : public ACharacter 17 { 18 GENERATED_BODY() 19 20 public: 21 // Sets default values for this character's properties 22 ASCharacter(); 23 24 protected: 25 // Called when the game starts or when spawned 26 virtual void BeginPlay() override; 27 28 void MoveForward(float value); 29 30 void MoveRight(float value); 31 32 void BeginCrouch(); 33 34 void EndCrouch(); 35 UFUNCTION(BlueprintImplementableEvent) 36 void JumpFromAction(); 37 38 UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "Components") 39 UCameraComponent* CameraComp; 40 41 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components") 42 USpringArmComponent* SpringArmComp; 43 44 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components") 45 USHealthComponent* HealthComp; 46 47 bool bWantsToZoom; 48 49 50 UPROPERTY(EditDefaultsOnly, Category = "Player") 51 float ZoomedFOV; 52 53 UPROPERTY(EditDefaultsOnly, Category = "Player",meta = (ClampMin = 0.1,ClampMax = 100)) 54 float ZoomInterpSpeed; 55 56 /*default FOV set during begin play*/ 57 float DefaultFOV; 58 59 void BeginZoom(); 60 61 void EndZoom(); 62 63 UPROPERTY(Replicated) 64 ASWeapon* CurrentWeapon; 65 66 UPROPERTY(EditDefaultsOnly,Category = "Player") 67 TSubclassOf<ASWeapon> StarterWeaponClass; 68 69 UPROPERTY(VisibleDefaultsOnly,Category = "Player") 70 FName WeaponAttachSocketName; 71 void StartFire(); 72 73 void StopFire(); 74 75 UFUNCTION() 76 void OnHealthChanged(USHealthComponent* OwingHealthComp, float Health, float HealthDelta, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser); 77 78 UPROPERTY(Replicated,BlueprintReadOnly,Category = "Player") 79 bool bDied ; 80 public: 81 // Called every frame 82 virtual void Tick(float DeltaTime) override; 83 84 // Called to bind functionality to input 85 virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override; 86 87 virtual FVector GetPawnViewLocation() const; 88 89 };