网站竞价,女生学软件工程很难吗,网站用什么服务器,服务器建网站教程这一篇#xff0c;我们实现敌人被击败后#xff0c;掉落战利品的功能。首先#xff0c;我们将创建一个新的结构体#xff0c;用于定义掉落体的内容#xff0c;方便我们设置掉落物。然后#xff0c;我们实现敌人死亡时的掉落函数#xff0c;并在蓝图里实现对应的逻辑我们实现敌人被击败后掉落战利品的功能。首先我们将创建一个新的结构体用于定义掉落体的内容方便我们设置掉落物。然后我们实现敌人死亡时的掉落函数并在蓝图里实现对应的逻辑在场景里生成掉落物。最后让掉落物动起来显得掉落物需要玩家赶紧去拾取的感觉。
添加新的资产结构体
为了实现对敌人掉落战利品的配置我们需要创建一个新的类作为配置掉落物的新的资产类。 命名为战利品类 在类里我们首先添加一个结构体用于设置一种物品的掉落内容和几率。
USTRUCT(BlueprintType)
struct FLootItem
{GENERATED_BODY()//战利品在场景中的显示效果UPROPERTY(EditAnywhere, BlueprintReadOnly, CategoryLootTiers|Spawning)TSubclassOfAActor LootClass;//战利品生成几率UPROPERTY(EditAnywhere, CategoryLootTiers|Spawning)float ChanceToSpawn 0.f;//物品生成的最大数量UPROPERTY(EditAnywhere, CategoryLootTiers|Spawning)int32 MaxNumberToSpawn 0.f;//修改物品生成等级false则使用敌人等级UPROPERTY(EditAnywhere, BlueprintReadOnly, CategoryLootTiers|Spawning)bool bLootLevelOverride true;
};然后在类里我们增加一个数组开发者可以配置多个掉落物然后添加一个函数用于获取当前可以生成的战利品数组。
UCLASS()
class RPG_API ULootTiers : public UDataAsset
{GENERATED_BODY()public://获取需要生成的战利品数据UFUNCTION(BlueprintCallable)TArrayFLootItem GetLootItems();UPROPERTY(EditDefaultsOnly, CategoryLootTiers|Spawning)TArrayFLootItem LootItems;
};在函数实现这里我们创建了一个新的数组用于根据概率计算每个物品的是否可掉落物品可以设置多个所以我们需要两层嵌套循环如果当前可掉落那么我们将其添加到返回数组里。最后返回。
TArrayFLootItem ULootTiers::GetLootItems()
{TArrayFLootItem ReturnItems;for(const FLootItem Item : LootItems){for(int32 i0; iItem.MaxNumberToSpawn; i){if(FMath::RandRange(1.f, 100.f) Item.ChanceToSpawn){FLootItem NewItem;NewItem.LootClass Item.LootClass;NewItem.bLootLevelOverride Item.bLootLevelOverride;ReturnItems.Add(NewItem);}}}return ReturnItems;
}实现配置和触发掉落逻辑
然后我们需要一个能够去获取配置好的数据资产的地方最方便的就是放到GameMode里我们在GameMode类里添加一个配置可以在蓝图配置使用哪一个数据资产 //战利品数据配置UPROPERTY(EditDefaultsOnly, CategoryLoot Tiers)TObjectPtrULootTiers LootTiers;
为了方便获取数据资产我们在蓝图函数库里增加一个函数用于获取数据资产 /*** 获取生成的战利品数据资产此数据会配置到GameMode上* param WorldContextObject 一个世界场景的对象用于获取当前所在的世界* return 战利品数据** note 敌人死亡后所需生成的战利品*/UFUNCTION(BlueprintCallable, CategoryRPGAbilitySystemLibrary|CharacterClassDefaults, meta(DefaultToSelf WorldContextObject))static ULootTiers* GetLootTiers(const UObject* WorldContextObject);函数实现我们将获取到GameMode并从GameMode身上获取到数据资产
ULootTiers* URPGAbilitySystemLibrary::GetLootTiers(const UObject* WorldContextObject)
{//获取到当前关卡的GameMode实例const ARPGGameMode* GameMode CastARPGGameMode(UGameplayStatics::GetGameMode(WorldContextObject));if(GameMode nullptr) return nullptr;//返回敌人战利品配置需要设置到GameMode上return GameMode-LootTiers;
}最后我们要在敌人类里实现掉落逻辑我们增加一个函数这个函数需要在蓝图里实现逻辑 //生成战利品UFUNCTION(BlueprintImplementableEvent)void SpawnLoot();然后在触发死亡逻辑时我们调用此函数来生成战利品 添加蓝图
代码方便我们完成了接着我们要在编辑器里添加一个新的数据资产 资产类型使用我们创建的战利品资产 我们将其和之前的资产放到一块 然后在资产里我们将之前制作的药瓶和水晶持续回血添加到战利品里掉落概率设置为100并且要使用敌人等级掉落。 接着将其设置到GameMode蓝图里 我们在敌人蓝图基类里实现统一的掉落战利品机制首先通过蓝图库函数获取到数据资产实例然后通过GetLootItems获取到需要生成的掉落物 然后创建一个蓝图函数用于通过蓝图函数库来设置掉落物的转向。 然后我们将其设置为纯函数这样不需要通过执行箭头调用。 然后将转向存储起来方便后续使用 然后我们通过一个定时器让物品掉落持续生成这样可以防止卡顿并且物品有一个个生成的效果我们在设置定时器时直接调用一次此事件。 接着就是生成战利品的自定义事件我们通过索引从返回的数组里获取到需要生成的对应的数据并计算出物品掉落位置最后生成Actor 我们创建获取变换的纯函数通过转向对敌人位置进行一个朝向在一定范围内随机偏移并使用旋转的朝向。 在创建Actor后我们需要更新掉落物的等级如果此物品需要修改等级那么我们将通过此函数内的逻辑进行修改 函数内我们首先判断是否需要修改然后将其转换为场景物品的基类然后判断当前物品是否存在最后将敌人等级应用到掉落物身上。 最后一步就是修改索引每调用一次我们将索引1下次再调用此事件时将会生成下一个坐标的物品如果索引超过或等于数组长度时我们将结束定时器完成掉落物的生成。 最后展示一下完成的蓝图连线 然后进入关卡打怪测试效果
关于掉落物的一些扩展
如果后续扩展的话我考虑对于每个大关卡创建单独的一套掉落然后在数组资产里增加几个数组比如效果使用小怪的一套掉落而精英怪使用精英怪的一套掉落最后是boss的掉落使用boss的一套掉落逻辑。 然后获取掉落时可以根据敌人品质去获取不同的掉落我们当然没必须单独为敌人去配置掉落。BOSS除外我们当然可以对一些特殊BOSS去配置单独的掉落比如关卡的最终BOSS掉落以及一些特殊怪物掉落。
实现掉落物自动旋转和悬浮效果
为了实现这个效果我们要在掉落物的基类RPGEffectActor里增加一些属性和函数用于实现此效果 要实现这个功能我们增加一批函数用于实现此功能 // 计算后的Actor所在的位置UPROPERTY(BlueprintReadWrite)FVector CalculatedLocation;// 计算后的Actor的旋转UPROPERTY(BlueprintReadWrite)FRotator CalculatedRotation;// Actor是否帧更新旋转UPROPERTY(BlueprintReadWrite, CategoryPickup Movement)bool bRotates false;// Actor每秒旋转的角度UPROPERTY(EditAnywhere, BlueprintReadWrite, CategoryPickup Movement)float RotationRate 45.f;// Actor是否更新位置UPROPERTY(BlueprintReadWrite, CategoryPickup Movement)bool bSinusoidalMovement false;// 正弦值-1到1此值为调整更新移动范围UPROPERTY(EditAnywhere, BlueprintReadWrite, CategoryPickup Movement)float SineAmplitude 1.f;// 此值参与正弦运算默认值为1秒一个循环2PI走完一个正弦的循环乘以时间就是一秒一个循环可用于调整位置移动速度UPROPERTY(EditAnywhere, BlueprintReadWrite, CategoryPickup Movement)float SinePeriod 1.f; //2 * PI//调用此函数Actor开始自动更新上下位置UFUNCTION(BlueprintCallable)void StartSinusoidalMovement();//调用此函数Actor开始自动旋转UFUNCTION(BlueprintCallable)void StartRotation();
private://当前掉落物的存在时间可以通过此时间实现动态效果float RunningTime 0.f;// Actor生成的默认初始位置在Actor动态浮动时需要默认位置作为基础位置FVector InitialLocation;// 每一帧更新Actor的位置和转向void ItemMovement(float DeltaSeconds);我们还需要用到帧更新函数
virtual void Tick(float DeltaSeconds) override;在事件开始时我们将掉落物的默认位置和旋转保存并设置计算后的属性我们需要在后续使用它更新Actor
void ARPGEffectActor::BeginPlay()
{Super::BeginPlay();//设置初始位置InitialLocation GetActorLocation();CalculatedLocation InitialLocation;CalculatedRotation GetActorRotation();
}我们需要在帧更新了去保存当前效果的执行时间并调用更新函数
void ARPGEffectActor::Tick(float DeltaSeconds)
{Super::Tick(DeltaSeconds);//更新当前Actor的存在时间RunningTime DeltaSeconds;ItemMovement(DeltaSeconds);
}在更新函数里我们根据变量判断是否需要更新来对转向和位置更新这里需要提到的是位置更新用到了正弦三角函数进行更新
void ARPGEffectActor::ItemMovement(float DeltaSeconds)
{//更新转向if(bRotates){const FRotator DeltaRotation(0.f, DeltaSeconds * RotationRate, 0.f);CalculatedRotation UKismetMathLibrary::ComposeRotators(CalculatedRotation, DeltaRotation);}//更新位置if(bSinusoidalMovement){const float Sine SineAmplitude * FMath::Sin(RunningTime * SinePeriod * 6.28318f);CalculatedLocation InitialLocation FVector(0.f, 0.f, Sine);}
}你会发现上面的变量无法在蓝图面板直接设置那么如何将其设置为true呢我们通用函数将其设置为true
void ARPGEffectActor::StartSinusoidalMovement()
{bSinusoidalMovement true;InitialLocation GetActorLocation();CalculatedLocation InitialLocation;
}void ARPGEffectActor::StartRotation()
{bRotates true;CalculatedRotation GetActorRotation();
}后续效果我们需要在蓝图里实现所以我们创建一个拾取的基类然后将所有可掉落物都继承此蓝图没必要在每个蓝图里实现一遍 我们在拾取物基类里创建一个时间轴来实现掉落物的从无到有的效果并通过时间轴的更新实现一些位置更新和缩放效果。在时间轴播放完成后我们调用开始旋转和开始移动的默认效果。 时间轴里我们增加了两个轨道用于分别更新位置和缩放使用 在帧更新里我们通过计算后的位置和旋转更新Actor即可
以下是拾取物的表现效果 添加音效
最后一个功能我们在Actor里添加一些音效来实现一些点缀效果。 首先在Actor增加一个变量设置音效基础类型 然后找到对应的音效 设置给变量 在更新位置和缩放后我折叠成了一个函数我们通过修改位置的值判断如果大于0.3时执行一次模拟触碰到地面的音效 然后在事件开始时增加一个生成的音效 在销毁时播放一个拾取的音效。