P2 Common Ability & Career Abililty

P2_1 CharacterClassInfo.h

  • 调整一下全局信息表 , 让技能分为通用技能和职业技能.

P2_2  UAuraAbilitySystemLibrary::GiveStartupAbilities

  • 分别学习技能.

P2_3 DA_CharacterClassInfo

  • 配表 , 目前Enemy只有一个战士的近战攻击技能.

P2_4 BTTask Activate Melee Attack Ability

P3_Attack Montage

P3_1 Attack Motion Warping

P4_Combat Target 

P4_1 Set Combat Target

  • 从 BlackboardKeySelctor中获取黑板值 , TargetToFollow.

P4_2 Get Combat Target For Motion Warping

  • 从 EmeyInterface 中获取.

P5_Melee Attack Gameplay Event

P5_1 C++ Call BlueprintNativeEvent

  • C++ 不能直接调用 UFUNCTION(BlueprintNativeEvent)

  • Call Execite_XX instead.

P6_Get Live Players Within Radius

P6_1 UAuraAbilitySystemLibrary::GetLivePlayersWithinRadius

P6_2 GA_MeleeAttack SphereTrace

P7_ Causing Melee Damage

P7_1 UAuraDamageGameplayAbility::CauseDamage

  • 之前是在 UAuraProjectileSpel 中给 GE_Damage 赋予标签的(SetByCaller).

  • 现在我们想在蓝图中 应用 GE_Damage , 就必须 指定 SetByCaller 标签 , 才能统计伤害类型叠加值.(BPCallable)

P7_2 Casue Damage In GA_MeleeAttack

P7_3 Show Floating Text

  • Enemy 攻击 AuraPlayer 也应该显示伤害文本.

P8_Multiplayer Test

  • 对于 AIController 来说 , 它们仅存在于 Server上.

P9_ Montage Gameplay Tags

P9_1 Config Tag To Montage

  • 创建相应的 结构体 , 建立 标签和蒙太奇的对应关系.

P9_2 Random One From Array

P9_3 Config Tag In Montage

  • 指定标签 , 示意蒙太奇的类型 , 武器 , 左手, 右手啥的.

P10_ Attack Socket

P10_1 Select SocketLocation by Tag

  • 存在食尸鬼没有武器进行攻击 , 需要指定攻击检测的原点 , 也就是 SocketLocation.

P10_2 GA_MeleeAttack

P10_3 Assign SocketName


P11_GA Montage Conflict

  • 下面的例子

  • Ghoul 有两个攻击蒙太奇,会随机选取一个 , 有一种情况就是播放.
  • 当执行到 WaitGameplayEvent 的时候会再次执行随机 , 如果随机结果正确就会 ApplyDamgeGE , 反之就不行了.

P11_1 Store As Var

  • 将随机出来的结果存储为成员变量.
  • 这样就不会再执行一次随机逻辑了.

P12_Cannel Attack Ability 

  • 挨揍时 , 取消 Attack Ability

P34_Melee Impact Gameplay Cue

P34_1 Performace In EnemyGA

  • Enemy 在 GA 中播放声音和特效在客户端时看不见的 , 虽然GA自带复制 , 但是只复制给 OwningClient , 我们的AI Enemy 的所有权必然不属于 Client 端 Machine.所以这时候 Gameplay Cue 登场了.

P35_ Gameplay Cue Demo

P35_1 GA_MeleeAttack :  Execute GC

  • GC 的行为就会复制到所有端了.
  • 需要传入标签选定执行的GC.

P35_2 GC_MeleeImpact

  • 一定要配置标签.
  • 可以获取 传入的 PayLoad.

P35_3 问题

  • 使用 Play As Client 总是无法准确获取 WeaponTipSocket的位置 , 原因未知.
  • 本来在武器尖处,缺在头顶位置检测了.

P47_ FanShape Random Location Algorithm

  • 在角色前方扇形范围内随机点位算法.
TArray<FVector> UAuraSummonAbility::GetSpawnLocations()
{

	const FVector Forward = GetAvatarActorFromActorInfo()->GetActorForwardVector();
	const FVector Location = GetAvatarActorFromActorInfo()->GetActorLocation();
	const float DeltaSpread = SpawnSpread / NumMinions;
	

	const FVector LeftOfSpread= Forward.RotateAngleAxis(-SpawnSpread / 2.0f , FVector::UpVector);
	TArray<FVector> SpawnLocations;
	for (int32 i = 0; i < NumMinions; i++)
	{
		const FVector Direction = LeftOfSpread.RotateAngleAxis(DeltaSpread * i , FVector::UpVector);
		const FVector ChosenSpawnLocation = Location + Direction * FMath::FRandRange(MinSpawnDistance, MaxSpawnDistance);
		SpawnLocations.Add(ChosenSpawnLocation);
	}
	
	return SpawnLocations;
}

P48_Array Shuffle

  • 打乱数组顺序非复制直接改引用.

P60_Texture Streaming Pool Over Budget

  • Too Many Textures which is too large all on the Screen At the same time.
  • what we want to do is compress them.

P60_1 Compress the texture

  • 调整纹理的 MaximumTextureSize.
  • 用于表面的纹理可以去批量处理.

P60_2 Change Budget Limit

  • DefaultEngine.ini

P62_Fade Actor

P62_1 Fade Actor Material 

  • BlendMode = Masked
  • 连接带有 Dither TemporalAA 节点.

  • 修改 Fade 参数值来改变透明程度.

P62_1 Dynamic Recover

  • 从当前透明度回复到初始透明度时,需要利用一下 Timeline的技巧 , 就是进入从Play进入 , 一定不能从 PlayFromStart 进入 , 这样才能利用 Reverse 从当前值进行恢复.

P69_ Ability Info Data Asset

P69_1 const member variable

  • const 修饰成员变量 表示在运行中不能修改.

P69_2 Custom LogType

  • 自定义 Log类型.

P69_2_1 AuraLogChannel

  • .h

  • .cpp

P69_2_2 Use Custom LogType

P70_ Handle Broacast Before BindDelegate

  • 学习技能的时候进行广播给 OverlayWidgetController , WidgetController 绑定代理.
  • 可能出现先广播再绑定的情况 ,需要特殊处理一下.

P70_1 UAuraAbilitySystemComponent::AddCharacterAbilities

  • 设置 bStartupAbilitiesGive = false by defalut , 当学习进成功的时候设置 Flag , 并且广播.

P70_2 UOverlayWidgetController::BindCallbacksToDependencies

  • 先 Broadcast 了 , 我们就绑定不了 , 所以我们直接调用方法.
  • 正常的执行顺序 , 先 Bind , 再 Broadcast , 我们就可以绑定代理了.

P70_3 UOverlayWidgetController::OnInitializeStartupAbilities

  • 加个判断条件保证一定要先学习了技能.

P71_For Each Ability Delegate

P71_1 Assign AbilityTag To GA_FireBolt

  • 这里是我提前加的啊 , 为了演示我就提前加了.
  • 需要注意的是,只有玩家的技能加了标签,Enemy的技能比如 MeleeAttack并没有.
  • 所以下文提到的 GetActivatableAbilities() 会获取 当前 ASC Owner 的所有 GivenAbility
  • 到这里我们得主角只会一个火球术.

P71_2 UAuraAbilitySystemComponent::GetAbilityTagFromSpec

  • 传入技能获取以获取标签.
  • 标签以 Ability 为第一层,这个项目中每个技能只有一个标签,所以找到就直接返回了.

P71_3 UAuraAbilitySystemComponent::GetInputTagFromSpec

  • 获取技能的 Input 标签 , 这个标签我们在运行时自动分配了.在这里分配的.

  • 获取技能的 InputTag ,没有就返回空的构造函数.

P71_4 UOverlayWidgetController::OnInitializeStartupAbilities

  • 这个方法就相对于在学习技能时调用.
  • 这里的代码逻辑十分特殊 , 可以理解为这段代理相当于一个方法,只不过定义在方法里了.

  • AuraASC->ForEachAbility会多次循环传入 AbilitySpec 多次调用 Lambda.

P71_5 UOverlayWidgetController::OnInitializeStartupAbilities

  • GetActivatableAbilities() 会获取 当前 ASC Owner 的所有 GivenAbility
  • 到这里我们得主角只会一个火球术.

P71_5_1 FScopedAbilityListLock ActiveScopeLock(*this);

  • AS we loopingOver Abilies we have to be careful because abilities can change status become no longer activatable , may be blocked.
  • A Good practice when looping throng the container , is to lock that activatable ability container until the for loop is done.
  • 解释一下上锁的原因.

P71_6 Final Test

P72_Binding Widget Events to the Ability Info Delegate

P72_1 Bind Call Back

  • 别忘记设置 InputTag标签和WidgetController 这里就不赘述了.

P72_2 OnRep_ActivaterAbilites

  • 当 GiveAbility()时 , ActivateAbilities会变化 , 这个变量是复制的 , 利用其OnRep方法来让客户端也设置好技能图标.

  • 个人觉得不加改加入 DoOnceGate, 如果在游戏进行中学习技能,那么就不应该 DoOnce了, 当然我目前不知道他之后是怎么设计的.

P73_GA - Cost

P73_1 Create GE

  • 没啥说的.

P73_2 Config Cost GE To GA

P73_3 Commit Ability

  • 选择在合适的地方 Commit Ability.
  • 一些技能比如剑魔和瑞文的Q是技能只要释放就 Commit Ability.
  • 也有些技能持续时间解释才进入CD.

P73_4 Apply Cost Level

  • 无需额外设置,技能消耗的等级就等于技能的等级.

P74_ GA - Cooldown

P74_1 Apply Cooldown Level

  • 与 Cost 同理 , 技能冷却的等级就等于技能的等级.

P74_2 GE Cooldown

  • 一定要 Grant Tags To Target Actor Component.
  • 原理就是给 ASC 添加 Block标签 , 标签存在于 ASC 中时阻止技能释放 , 待GE 结束后失去 阻止标签 : Grant Tags To Target Actor. 

P74_3 Assign CD GE To GA

P75_ Cooldown AsyncTask

P75_1 WaitCooldownChange.h

  • CooldownStart : CD 开始时的Broadcast.
  • CooldownEnd : CD 结束时的Broadcast.
  • WaitForCooldownChange() : 用于绑定 代理.
  • EndTask : 用于结束技能事宜和Unbind代理.
  • CooldownTagChaned() : CD 开始时的 Broadcast 绑定代理回调.
    • 当 ASC 被 granted Cooldown 标签时.
  • OnActiveEffectAdd() : CD 结束时的 Broadcast 绑定代理回调.
    • 当 ASC 被应用 Cooldown GE 时.

P75_2 WaitCooldownChange.cpp

UWaitCooldownChange* UWaitCooldownChange::WaitForCooldownChange(
	class UAbilitySystemComponent* AbilitySystemComponent,
	const struct FGameplayTag& InCooldownTag)
{
	UWaitCooldownChange* WaitCooldownChange = NewObject<UWaitCooldownChange>();
	WaitCooldownChange->ASC = AbilitySystemComponent;
	WaitCooldownChange->CooldownTag = InCooldownTag;

	if (!IsValid(AbilitySystemComponent) || !InCooldownTag.IsValid())
	{
		WaitCooldownChange->EndTask();
		return nullptr;
	}
	//ASC Cooldown Tag Changed
	AbilitySystemComponent->RegisterGameplayTagEvent(InCooldownTag,EGameplayTagEventType::NewOrRemoved).
	AddUObject(WaitCooldownChange,&UWaitCooldownChange::CooldownTagChanged);

	//ASC Apply GE Delegate Callback , Only Work for duration GE , Work Both On Server And Client
	AbilitySystemComponent->OnActiveGameplayEffectAddedDelegateToSelf.AddUObject(WaitCooldownChange,&UWaitCooldownChange::OnActiveEffectAdded);

	return WaitCooldownChange;
}

void UWaitCooldownChange::EndTask()
{
	if (!IsValid(ASC)){return;}
	ASC->RegisterGameplayTagEvent(CooldownTag,EGameplayTagEventType::NewOrRemoved).RemoveAll(this);
	
	SetReadyToDestroy(); //Call when the action is completely done, this makes the action free to delete , and will  unregister it with the game instance.
	MarkAsGarbage();
}

void UWaitCooldownChange::CooldownTagChanged(const FGameplayTag InCooldownTag, int32 NewCount)
{
	if (NewCount == 0) //Cooldown has been finished
	{
		CooldownEnd.Broadcast(0.0f);
	}
}

void UWaitCooldownChange::OnActiveEffectAdded(
	class UAbilitySystemComponent* TargetASC,
	const FGameplayEffectSpec& SpecApplied,
	struct FActiveGameplayEffectHandle ActiveEffectHandle)
{
	FGameplayTagContainer AssetTags;
	SpecApplied.GetAllAssetTags(AssetTags);

	FGameplayTagContainer GrantedTags;
	SpecApplied.GetAllGrantedTags(GrantedTags);
	
	if (AssetTags.HasTagExact(CooldownTag) || GrantedTags.HasTagExact(CooldownTag))
	{																				//Match Given Tag And GE's Owning Tags Exactly
		FGameplayEffectQuery GameplayEffectQuery = FGameplayEffectQuery::MakeQuery_MatchAnyOwningTags(CooldownTag.GetSingleTagContainer());
		//Return the CooldownTime(Duration Magnitude - Scalable float magnitude)
		//We Assign the Cooldown GE Only One GrantedTagToActor so it's only valid on Array[0]
		TArray<float> TimesRemaining = ASC->GetActiveEffectsTimeRemaining(GameplayEffectQuery);
		if (TimesRemaining.Num() > 0)
		{
			//ensure we find the longest time in the array
			float TimeRemaining = TimesRemaining[0];
			for (int32 i = 0 ; i < TimesRemaining.Num() ; i++)
			{
				if (TimesRemaining[i] > TimeRemaining)
				{
					TimeRemaining = TimesRemaining[i];
				}
			}
			CooldownStart.Broadcast(TimeRemaining);
		}
	}
}

P75_3 WBP_SpellGlobe : Widget Controller Set

  • 先硬编码一下标签.

P76_ Cooldown Tags in Ability Info

P76_1 Create New Item In AbilityInfo Struct

  • 我们需要技能信息中包含冷却标签.

P76_2 WBP_SpellGlobe::ReceiveAbilitInfo

  • Widget 的 InputTag 和 技能的 Input 需要一样 , 否则 CooldownTag = NotValid.下面有用.

P76_3 WBP_SpellGlobe::WaitforCooldownChange

  • 一定要在 CooldownTag有值之后调用.
  • 如果 CooldownTag == Valid , 那么 WaitForCooldownChange方法就会提前返回 , CooldownStart和CooldownEnd 出口则不会有行为.

P76_4 meta = (ExposedAsyncProxy = "AsyncTask")

  • 目前只知道其可以返回自身的一个 Instance.

P78_ Modeling Mode

  • 自制一个 1 x 1 x 4 + 1 x 1 x1 = 1 x 1 x 5 的 StaticMesh.

  • 先摆放好.

  • 进入 ModelingMode

  • Accept

  • Ctrl + B

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐