通过GAS实现狐狸的技能,还差碰撞、参数配置化、消耗和冷却

This commit is contained in:
2025-10-18 04:37:34 +08:00
parent f8a05026d5
commit e0d7329905
31 changed files with 465 additions and 102 deletions

View File

@ -8,11 +8,14 @@ FastReplication=False
InvalidTagCharacters="\"\',"
NumBitsForContainerSize=6
NetIndexFirstBitSegment=16
+GameplayTagList=(Tag="Ability.Block.UltimatePlaying",DevComment="大招正在释放中")
+GameplayTagList=(Tag="Ability.Flags.Recast",DevComment="可以再次释放技能的标记")
+GameplayTagList=(Tag="Ability.Role.AttributeConsume",DevComment="角色属性损耗debuff")
+GameplayTagList=(Tag="Ability.Role.EatFood",DevComment="干饭")
+GameplayTagList=(Tag="Ability.Role.Pick",DevComment="角色采集物品")
+GameplayTagList=(Tag="Ability.Role.Recover",DevComment="角色状态恢复技能")
+GameplayTagList=(Tag="Ability.Role.Roll",DevComment="角色无敌翻滚")
+GameplayTagList=(Tag="Ability.Role.Ultimate",DevComment="角色大招")
+GameplayTagList=(Tag="Buff.Indispersible.HungerConsume",DevComment="饥饿值消耗,不可被驱散")
+GameplayTagList=(Tag="Buff.RoleConsume.Health",DevComment="角色因饥饿掉血的debuff")
+GameplayTagList=(Tag="Buff.RoleConsume.Hunger",DevComment="角色每秒钟的饥饿消耗")
@ -25,6 +28,8 @@ NetIndexFirstBitSegment=16
+GameplayTagList=(Tag="CookProcess.Diced",DevComment="切丁")
+GameplayTagList=(Tag="CookProcess.Mashed",DevComment="切泥")
+GameplayTagList=(Tag="CookProcess.Sliced",DevComment="切片操作")
+GameplayTagList=(Tag="Effect.Duration",DevComment="效果的持续时长")
+GameplayTagList=(Tag="Effect.Factor",DevComment="效果的乘法系数")
+GameplayTagList=(Tag="GameItem.Building",DevComment="建筑物")
+GameplayTagList=(Tag="GameItem.Food",DevComment="游戏内的可食用物品")
+GameplayTagList=(Tag="Ingredient",DevComment="烹饪食材")

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,3 +1,4 @@
--- @class BusyGameplayLibrary
--- @field K2_GetWorld fun(obj:table):table
--- @field RequestGameplayTag fun(TagName:string):GameplayTag
local BusyGameplayLibrary = {}

View File

@ -29,7 +29,14 @@ KismetSystemLibrary = {
}
--- @class GameplayTag
local GameplayTag
--- @class GameplayStatics
--- @field GetPlayerController fun(uobj:table,idx:number):table
--- @field GetGameState fun(uobj:table):table
local GameplayStatics
--- @class AbilitySystemBlueprintLibrary
--- @field AssignTagSetByCallerMagnitude fun(SpecHandle:table, DataTag:GameplayTag, Magnitude:number)
local AbilitySystemBlueprintLibrary

View File

@ -0,0 +1,4 @@
local MoveAbility = {}
return Class(nil, nil, MoveAbility)

View File

@ -0,0 +1,153 @@
local GameplayStatics = import("GameplayStatics")
local AbilitySystemBlueprintLibrary = import("AbilitySystemBlueprintLibrary")
local BusyGameplayLibrary = import("BusyGameplayLibrary")
--- @class FoxUltimate
--- @field RecastWindow number
local FoxUltimate = {}
function FoxUltimate:ctor()
self.ultimate_phase = 1 -- 大招阶段
self.active_recast_handle = nil
self.active_accelerate_handle = nil
end
function FoxUltimate:K2_ActivateAbilityFromEvent(EventData)
print("FoxUltimate:K2_ActivateAbilityFromEvent", self.ultimate_phase)
local owner = self:GetOwningActorFromActorInfo()
self.movement = owner.MovementComponent
self.animation = owner.SpineAnimationComponent
self.asc = AbilitySystemBlueprintLibrary.GetAbilitySystemComponent(owner)
self.recast_tag = BusyGameplayLibrary.RequestGameplayTag("Ability.Flags.Recast")
local asc = self.asc
if self.ultimate_phase == 1 or asc:HasMatchingGameplayTag(self.recast_tag) then
print("triggered")
self:TriggerUltimate(asc)
else
self:K2_EndAbility()
end
end
function FoxUltimate:TriggerUltimate(asc)
if self.ultimate_phase == 1 then
-- 第一次释放大招添加一个可以再次释放的Tag
local _, recast_effect = self:GetAbilityEffectSpecHandle("Recast", asc, 1, nil)
self.active_recast_handle = asc:BP_ApplyGameplayEffectSpecToSelf(recast_effect)
elseif self.ultimate_phase == 2 then
-- 第二次激活移除可重复释放的tag
self.asc:RemoveActiveGameplayEffect(self.active_recast_handle, -1)
local _, recast_effect = self:GetAbilityEffectSpecHandle("Recast", asc, 1, nil)
self.active_recast_handle = asc:BP_ApplyGameplayEffectSpecToSelf(recast_effect)
elseif self.ultimate_phase == 3 then
self.asc:RemoveActiveGameplayEffect(self.active_recast_handle, -1)
end
-- 播放动画,并监听动画完成的事件
self:PlayAnimation()
end
function FoxUltimate:GetAnimationName(direction)
local animation_name_prefix
if direction.X >= 0 then
animation_name_prefix = "Ultimate/Right/"
else
animation_name_prefix = "Ultimate/Left/"
end
if self.ultimate_phase == 1 then
return animation_name_prefix .. "UltimateStage1"
elseif self.ultimate_phase == 2 then
return animation_name_prefix .. "UltimateStage2"
elseif self.ultimate_phase == 3 then
return animation_name_prefix .. "UltimateStage3"
end
return nil
end
function FoxUltimate:K2_OnEndAbility(bWasCancelled)
print("FoxUltimate:K2_OnEndAbility")
end
function FoxUltimate:GetSprintSpeedFactor()
if self.ultimate_phase == 1 then
return 2.5
elseif self.ultimate_phase == 2 then
return 2.8
elseif self.ultimate_phase == 3 then
return 3.0
end
end
function FoxUltimate:PlayAnimation()
local animation = self.animation
local PC = GameplayStatics.GetPlayerController(self, 0)
local result, ability_direction = PC:GetCursorDirection(nil) -- 获取技能的朝向
if not result then
print("FoxUltimate:TriggerPrimaryPhase can't find direction")
return
end
local anim_name = self:GetAnimationName(ability_direction) -- 获取技能动画名称
if not anim_name then
print("FoxUltimate:TriggerPrimaryPhase can't get animation", self.ultimate_phase)
return
end
local anim_entry = animation:SetAnimation(0, anim_name, false)
anim_entry.AnimationComplete:Add(function(entry) self:OnAnimationComplete(entry) end)
anim_entry.AnimationEvent:Add(function(entry, event) self:OnAnimationEvent(entry, event) end)
local anim_total_time = anim_entry:GetAnimationEnd() -- 获取技能动画时长
-- 附加加速buff
self:MakeAccelerate(self:GetSprintSpeedFactor(), anim_total_time)
self.movement:ActivateSprint(ability_direction, anim_total_time)
end
function FoxUltimate:MakeAccelerate(speed_factor, total_time)
local _, accelerate_effect = self:GetAbilityEffectSpecHandle("Accelerate", self.asc, 1, nil)
AbilitySystemBlueprintLibrary.AssignTagSetByCallerMagnitude(
accelerate_effect,
BusyGameplayLibrary.RequestGameplayTag("Effect.Factor"),
speed_factor
)
AbilitySystemBlueprintLibrary.AssignTagSetByCallerMagnitude(
accelerate_effect,
BusyGameplayLibrary.RequestGameplayTag("Effect.Duration"),
total_time
)
return self.asc:BP_ApplyGameplayEffectSpecToSelf(accelerate_effect)
end
function FoxUltimate:OnAnimationComplete(entry)
self.ultimate_phase = self.ultimate_phase + 1
entry.AnimationComplete:Clear()
entry.AnimationEvent:Clear()
self:K2_EndAbility()
end
function FoxUltimate:OnAnimationEvent(entry, event)
if event.Name == "OnSpeedChange" then
self.active_accelerate_handle = self:MakeAccelerate(8.0, 0.5)
elseif event.Name == "OnSpeedReset" then
self.asc:RemoveActiveGameplayEffect(self.active_accelerate_handle, -1)
end
end
return Class(nil, nil, FoxUltimate)

View File

@ -0,0 +1,4 @@
local RabbitUltimate = {}
return Class(nil, nil, RabbitUltimate)

View File

@ -78,3 +78,20 @@ bool UBusyGameplayLibrary::GetItemDescription(const FName& RowName, FBusyItemDes
bool UBusyGameplayLibrary::GetCookMaterialStateConfig(const FName& RowName, FBusyCookMaterialStateConfig& RowData){
return GetTableConfig<FBusyCookMaterialStateConfig>(TEXT("CookMaterialStateConfig"), RowName, RowData);
}
FGameplayTag UBusyGameplayLibrary::RequestGameplayTag(const FName& TagName)
{
return FGameplayTag::RequestGameplayTag(TagName);
}
#pragma optimize("",off)
FGameplayTagContainer UBusyGameplayLibrary::RequestGameplayTags(const TArray<FName>& TagNames)
{
TArray<FGameplayTag> GameplayTags;
for (const FName& TagName : TagNames)
{
GameplayTags.Add(FGameplayTag::RequestGameplayTag(TagName));
}
return FGameplayTagContainer::CreateFromArray(GameplayTags);
}
#pragma optimize("",on)

View File

@ -0,0 +1,27 @@
#include "LuaCppBinding.h"
#include "AbilitySystemComponent.h"
#include "GameplayTagContainer.h"
using slua::lua_State, slua::LuaObject, slua::LuaStruct;
using namespace slua;
#pragma optimize( "", off )
bool HasMatchingGameplayTag(const UAbilitySystemComponent& Asc, const FName& TagName)
{
// return Asc.HasMatchingGameplayTag(FGameplayTag::RequestGameplayTag(TagName));
return true;
}
extern void RegisterAbilitySystemComponentExtension() {
REG_EXTENSION_METHOD_LAMBDA(UAbilitySystemComponent, "AHasMatchingGameplayTag", false,
[](UAbilitySystemComponent* ASC, const FName& Tag) -> bool {
return true;
}
);
}
#pragma optimize( "", on)

View File

@ -1,30 +1,6 @@
#include "LuaCppBinding.h"
using namespace slua;
//static int LuaBinding_FindRow(lua_State* L) {
// UDataTable* DataTable = LuaObject::checkUD<UDataTable>(L, 1);
// FName RowName = LuaObject::checkValue<FName>(L, 2);
//
// UScriptStruct* RowStruct = (UScriptStruct*)DataTable->GetRowStruct();
//
// uint8* RowData = DataTable->FindRowUnchecked(RowName);
//
// if (RowData && RowStruct) {
// // <20><><EFBFBD><EFBFBD> LuaStruct <20><>װ<EFBFBD><D7B0>
// uint32 size = RowStruct->GetStructureSize() ? RowStruct->GetStructureSize() : 1;
// uint8* buf = (uint8*)FMemory::Malloc(size);
// RowStruct->InitializeStruct(buf);
// RowStruct->CopyScriptStruct(buf, RowData);
//
// LuaStruct* ls = new LuaStruct();
// ls->Init(buf, size, RowStruct, false);
// return LuaObject::push(L, ls);
// }
// else {
// return LuaObject::pushNil(L);
// }
//}
static int LuaBinding_FindRow(lua_State* L) {
UDataTable* DataTable = LuaObject::checkUD<UDataTable>(L, 1);
@ -37,24 +13,13 @@ static int LuaBinding_FindRow(lua_State* L) {
LuaStruct* luaStruct = new LuaStruct();
luaStruct->Init((uint8*)TableRow, rowStruct->GetStructureSize(), (UScriptStruct*)rowStruct, true);
LuaObject::addLink(L, TableRow); // ȷ<><C8B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
LuaObject::addLink(L, TableRow);
//auto ret = LuaObject::push(L, luaStruct);
return LuaObject::pushReference<LuaStruct*>(L, luaStruct, TableRow);
}
//FTableRowBase* tableRow = DataTable->FindRow<FTableRowBase>(RowName, TEXT(""));
//
//UScriptStruct* rowStruct = DataTable->GetRowStruct();
//
//LuaStruct* luaStruct = new LuaStruct();
//luaStruct->Init((uint8*)tableRow, rowStruct->GetStructureSize(), rowStruct, true);
//
//int ret = LuaObject::push(L, luaStruct);
extern void RegisterDataTableExtension() {
REG_EXTENSION_METHOD_IMP(UDataTable, "FindRow", { return LuaBinding_FindRow(L); });
}

View File

@ -0,0 +1,33 @@
#include "Gas/BusyGameAbility.h"
#include "AbilitySystemBlueprintLibrary.h"
#include "AbilitySystemComponent.h"
UBusyGameAbility::UBusyGameAbility()
{
bHasBlueprintActivateFromEvent = true;
}
FString UBusyGameAbility::GetLuaFilePath_Implementation()const
{
return LuaFilePath;
}
bool UBusyGameAbility::GetAbilityEffectSpecHandle(const FName& EffectName, const UAbilitySystemComponent* Asc, const int32 Level,
FGameplayEffectSpecHandle& Handle) const
{
// 1. 查找对应的GameplayEffectClass
const TSubclassOf<UGameplayEffect> *EffectClass = AbilityEffects.Find(EffectName);
if (!EffectClass) return false;
// 2. 创建并设置GameplayEffect上下文
FGameplayEffectContextHandle EffectContextHandle = Asc->MakeEffectContext();
// 3. 将当前对象设置为效果来源
EffectContextHandle.AddSourceObject(this);
// 4. 创建GameplayEffectSpecHandle
Handle = Asc->MakeOutgoingSpec(*EffectClass, 1.f, EffectContextHandle); // 这里的1.f是等级
return Handle.IsValid();
}

View File

@ -1,8 +1,12 @@
#include "Level/Actor/BusyPawnBase.h"
#include "BusyGameplayLibrary.h"
#include "Components/SphereComponent.h"
#include "SpineSkeletonRendererComponent.h"
#include "SpineSkeletonAnimationComponent.h"
#include "Gas/BusyGameAbility.h"
#include "Level/Actor/Components/BusyPawnMovement.h"
#include "Tables/BusyPawnConfig.h"
DEFINE_LOG_CATEGORY(LogBusyPawn)
@ -30,38 +34,46 @@ void ABusyPawnBase::BeginPlay()
{
Super::BeginPlay();
// for (UClass* AbilityClass : Row->DefaultAbilities) {
// if (AbilityClass) {
// AbilitySystemComponent->GiveAbility(FGameplayAbilitySpec(AbilityClass));
// }
// }
if (const UDataTable* DataTable = UBusyGameplayLibrary::GetGameDataTable("LevelRoleBaseConfig"))
{
const FBusyPawnBaseConfig* Config = DataTable->FindRow<FBusyPawnBaseConfig>(
PawnName, FString::Printf(TEXT("ABusyPawnBase::BeginPlay Find %s in LevelRoleBaseConfig"), *PawnName.ToString())
);
if (Config)
{
InitPawnAbilities(*+Config);
InitPawnAttributes(*Config);
}
}
}
float ABusyPawnBase::GetSpeed_Implementation()const
{
if (Attribute)
if (Attributes)
{
return Attribute->GetMoveSpeed();
return Attributes->GetMoveSpeed();
}
return 0.f;
}
void ABusyPawnBase::InitMoveSpeed(const float MoveSpeed)const
void ABusyPawnBase::InitPawnAttributes(const FBusyPawnBaseConfig& Config)
{
if (Attribute)
if (Attributes)
{
Attribute->InitMoveSpeed(MoveSpeed);
Attributes->InitHealth(Config.Health);
Attributes->InitMaxHealth(Config.Health);
Attributes->InitMoveSpeed(Config.MoveSpeed);
Attributes->InitDamage(Config.Damage);
Attributes->InitDefense(Config.Defense);
}
}
void ABusyPawnBase::InitHealth(const float Health, const float MaxHealth) const
void ABusyPawnBase::InitPawnAbilities(const FBusyPawnBaseConfig& Config)const
{
if (Attribute)
for (const TSubclassOf<UGameplayAbility>& Ability : Config.DefaultAbilities)
{
Attribute->InitHealth(Health);
Attribute->InitMaxHealth(MaxHealth);
AbilitySystemComponent->GiveAbility(FGameplayAbilitySpec(Ability));
}
}

View File

@ -19,46 +19,31 @@ ABusyPlayerRole::ABusyPlayerRole()
SpringArmComponent->SetRelativeRotation(FRotator(0, -90.0, 0.0));
Attribute = CreateDefaultSubobject<UBusyPlayerRoleAttributeSet>(TEXT("Attribute"));
InitMoveSpeed(200);
InitHealth(100, 100);
Attributes = CreateDefaultSubobject<UBusyPlayerRoleAttributeSet>(TEXT("Attribute"));
}
void ABusyPlayerRole::BeginPlay()
{
Super::BeginPlay();
InitRoleAttributes();
}
bool ABusyPlayerRole::InitRoleAttributes()
void ABusyPlayerRole::InitPawnAttributes(const struct FBusyPawnBaseConfig& Config)
{
if (!PawnName.IsValid()) return false;
const UDataTable* ConfigTable = UBusyGameplayLibrary::GetGameDataTable(TEXT("LevelRoleBaseConfig"));
if (!ConfigTable)
{
UE_LOG(LogBusyPawn, Log, TEXT("ABusyPlayerRole::InitRoleAttributes Can't find config table: LevelRoleBaseConfig"))
return false;
}
const FBusyRoleBaseConfig* Result = ConfigTable->FindRow<FBusyRoleBaseConfig>(
PawnName,
*FString::Printf(TEXT("ABusyPlayerRole::InitRoleAttributes, PawnName: %ls"), *PawnName.ToString())
);
if (Result)
{
UBusyPlayerRoleAttributeSet* RoleAttributes = Cast<UBusyPlayerRoleAttributeSet>(Attribute);
RoleAttributes->InitHealth(Result->Health);
RoleAttributes->InitMaxHealth(Result->Health);
RoleAttributes->InitMoveSpeed(Result->MoveSpeed);
RoleAttributes->InitHunger(Result->Hunger);
RoleAttributes->InitMaxHunger(Result->Hunger);
RoleAttributes->InitHungerConsume(Result->HungerConsume);
Super::InitPawnAttributes(Config);
UBusyPlayerRoleAttributeSet* RoleAttributes = Cast<UBusyPlayerRoleAttributeSet>(Attributes);
RoleAttributes->InitDamage(Result->Damage);
RoleAttributes->InitDefense(Result->Defense);
return true;
if (RoleAttributes && Config.StaticStruct() == FBusyRoleBaseConfig::StaticStruct())
{
const FBusyRoleBaseConfig* RoleConfig = static_cast<const FBusyRoleBaseConfig*>(&Config);
RoleAttributes->InitHunger(RoleConfig->Hunger);
RoleAttributes->InitMaxHunger(RoleConfig->Hunger);
RoleAttributes->InitHungerConsume(RoleConfig->HungerConsume);
}
else
{
UE_LOG(LogBusyPawn, Warning, TEXT("ABusyPlayerRole::InitPawnAttributes Failed, RoleAttribute: %p, ConfigName: %s"),
RoleAttributes, *Config.StaticStruct()->GetFName().ToString()
);
}
return false;
}

View File

@ -24,6 +24,22 @@ void UBusyPawnMovement::SprintTo(const float Distance, const float SpeedRate)
}
}
void UBusyPawnMovement::ActivateSprint(const FVector2D& Direction, const float TotalTime)
{
SprintSpeed = 0.f;
SprintDirection = Direction;
SprintTotalTime = SprintRemainTime = TotalTime;
BusyMoveState = EBusyMoveState::Sprint;
}
void UBusyPawnMovement::ActivateSprintWithSpeed(const FVector2D& Direction, const float TotalTime, const float Speed)
{
SprintSpeed = Speed;
SprintDirection = Direction;
SprintTotalTime = SprintRemainTime = TotalTime;
BusyMoveState = EBusyMoveState::Sprint;
}
FVector2D UBusyPawnMovement::GetMoveDirection()const
{
if (AActor *Owner = GetOwner())
@ -119,14 +135,24 @@ void UBusyPawnMovement::SprintTick(const float DeltaTime)
const FVector CurrentLocation = Owner->GetActorLocation();
const FVector2D CurrentLocation2D = FVector2D(CurrentLocation);
const float MoveDistance = DeltaTime * Movable->Execute_GetSpeed(Owner) * SprintSpeedRate;
const FVector2D NewLocation = CurrentLocation2D + ForwardDirection * MoveDistance;
float SprintDeltaTime = DeltaTime;
if (SprintRemainTime <= DeltaTime)
{
SprintDeltaTime = SprintRemainTime;
SprintRemainTime = 0.f;
}
else
{
SprintRemainTime -= DeltaTime;
}
const float MoveDistance = SprintDeltaTime * (SprintSpeed == 0.f ? Movable->Execute_GetSpeed(Owner) : SprintSpeed);
const FVector2D NewLocation = CurrentLocation2D + SprintDirection * MoveDistance;
Owner->SetActorLocation(FVector(NewLocation, CurrentLocation.Z), true);
if (FVector2D::Distance(NewLocation, SprintStartLocation) >= SprintDistance)
if (SprintRemainTime == 0.f)
{
BusyMoveState = EBusyMoveState::None; // 这里不对,需要栈来做
BusyMoveState = EBusyMoveState::None;
}
}

View File

@ -1,5 +1,6 @@
#include "Level/LevelPlayerController.h"
#include "Level/Actor/BusyPlayerRole.h"
#include "AbilitySystemBlueprintLibrary.h"
#include "EnhancedInput/Public/EnhancedInputSubsystems.h"
#include "Level/LevelPlayerState.h"
#include "EnhancedInput/Public/EnhancedInputComponent.h"
@ -52,6 +53,14 @@ void ALevelPlayerController::SetupInputComponent()
BindEnhancedInputAction(EnhancedInput, PrimarySkillAction, this, "OnPrimarySkill");
BindEnhancedInputAction(EnhancedInput, UltimateSkillAction, this, "OnUltimateSkill");
BindEnhancedInputAction(EnhancedInput, SwitchRoleAction, this, "OnSwitchRole");
for (const FBusySkillActionConfig& ActionConfig : RoleSkillActions)
{
EnhancedInput->BindAction(ActionConfig.InputAction, ETriggerEvent::Triggered, this,
&ALevelPlayerController::OnRoleSkillTriggered,
ActionConfig.ActionTag
);
}
}
void ALevelPlayerController::Tick(float DeltaTime)
@ -107,6 +116,20 @@ bool ALevelPlayerController::GetCursorPosition(FVector2D& Position) const
return false;
}
bool ALevelPlayerController::GetCursorDirection(FVector2D& Direction) const
{
const AActor *ControlledRole = GetControlledRole();
if (!ControlledRole) return false;
if (FVector2D CursorPosition; GetCursorPosition(CursorPosition))
{
FVector2D &&RoleLocation = FVector2D(ControlledRole->GetActorLocation());
Direction = (CursorPosition - RoleLocation).GetSafeNormal();
return true;
}
return false;
}
void ALevelPlayerController::GetCursorHitResult(TArray<AActor*>& Results) const
{
}
@ -192,3 +215,14 @@ void ALevelPlayerController::OnSwitchRole(const FInputActionValue& Value)
SwitchControlledRole(ControlledRole);
}
}
void ALevelPlayerController::OnRoleSkillTriggered(FGameplayTag GameplayTag)
{
AActor* ControlledRole = GetControlledRole();
if (!ControlledRole) return;
if (UAbilitySystemComponent* Asc = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(ControlledRole))
{
FGameplayEventData EventData = FGameplayEventData();
Asc->HandleGameplayEvent(GameplayTag, &EventData);
}
}

View File

@ -53,4 +53,12 @@ public:
UFUNCTION(BlueprintPure)
static bool GetCookMaterialStateConfig(const FName& RowName, FBusyCookMaterialStateConfig& RowData);
public:
UFUNCTION(BlueprintPure)
static FGameplayTag RequestGameplayTag(const FName& TagName);
UFUNCTION(BlueprintCallable)
static FGameplayTagContainer RequestGameplayTags(const TArray<FName>& TagNames);
};

View File

@ -0,0 +1,30 @@
#pragma once
#include "slua.h"
#include "Abilities/GameplayAbility.h"
#include "BusyGameAbility.generated.h"
UCLASS(Blueprintable, BlueprintType)
class UBusyGameAbility : public UGameplayAbility, public ILuaOverriderInterface
{
GENERATED_BODY()
public:
UBusyGameAbility();
virtual FString GetLuaFilePath_Implementation()const override;
public:
UFUNCTION(BlueprintCallable)
bool GetAbilityEffectSpecHandle(const FName& EffectName, const UAbilitySystemComponent* Asc, const int32 Level, FGameplayEffectSpecHandle& Handle)const;
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
FString LuaFilePath;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, DisplayName="技能效果")
TMap<FName, TSubclassOf<UGameplayEffect>> AbilityEffects;
};

View File

@ -6,6 +6,7 @@
class USphereComponent;
struct FBusyPawnBaseConfig;
class USpineBoneFollowerComponent;
class USpineSkeletonRendererComponent;
class USpineSkeletonAnimationComponent;
@ -63,14 +64,9 @@ public:
virtual float GetSpeed_Implementation()const override;
public:
virtual bool InitRoleAttributes() { return false; }
virtual void InitPawnAttributes(const FBusyPawnBaseConfig& Config);
virtual void InitPawnAbilities(const FBusyPawnBaseConfig& Config) const;
protected:
UFUNCTION(BlueprintCallable)
void InitMoveSpeed(const float MoveSpeed)const;
UFUNCTION(BlueprintCallable)
void InitHealth(const float Health, const float MaxHealth)const;
protected:
UPROPERTY(EditDefaultsOnly)
@ -111,7 +107,7 @@ public:
protected:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<UBusyPawnAttributeSet> Attribute = nullptr;
TObjectPtr<UBusyPawnAttributeSet> Attributes = nullptr;
protected:

View File

@ -46,7 +46,8 @@ public:
virtual void BeginPlay() override;
virtual bool InitRoleAttributes()override;
virtual void InitPawnAttributes(const struct FBusyPawnBaseConfig& Config)override;
protected:

View File

@ -9,7 +9,7 @@ class UBusyAbilitySystemComponent : public UAbilitySystemComponent, public ILuaO
{
GENERATED_BODY()
public:
virtual FString GetLuaFilePath_Implementation() const override;
virtual FString GetLuaFilePath_Implementation() const override;
protected:

View File

@ -54,6 +54,23 @@ public:
UFUNCTION(BlueprintCallable)
void SprintTo(const float Distance, const float SpeedRate);
/**
* 以角色自身的速度向某个方向进行冲刺,受角色速度变化的影响
* @param Direction 冲刺方向
* @param TotalTime 冲刺的时间(s)
*/
UFUNCTION(BlueprintCallable)
void ActivateSprint(const FVector2D &Direction, const float TotalTime);
/**
* 以指定速度向某个方向冲刺,无视角色速度
* @param Direction
* @param TotalTime
* @param Speed
*/
UFUNCTION(BlueprintCallable)
void ActivateSprintWithSpeed(const FVector2D &Direction, const float TotalTime, const float Speed);
/**
* 获取当前移动的方向
* @return 返回朝向的单位向量,如果没动返回(0,0)
@ -97,10 +114,17 @@ protected:
UPROPERTY(EditAnywhere, BlueprintReadOnly)
FVector2D ForwardDirection;
// 冲刺相关
protected:
protected: // 冲刺相关
FVector2D SprintDirection; // 冲刺的方向
float SprintTotalTime; // 冲刺总时长
float SprintRemainTime; // 冲刺的剩余时间
float SprintSpeed; // 指定的冲刺速度, 为0表示使用自己的速度
float SprintSpeedRate = 1.f;
float SprintDistance = 100.f;
FVector2D SprintStartLocation;

View File

@ -1,16 +1,18 @@
#pragma once
#include "LuaPlayerController.h"
#include "GameplayTagContainer.h"
#include "InputAction.h"
#include "LevelPlayerController.generated.h"
UINTERFACE(MinimalAPI, Blueprintable)
class UBusyControllable: public UInterface
{
GENERATED_BODY()
};
class IBusyControllable
{
GENERATED_BODY()
@ -29,8 +31,22 @@ public:
};
struct FInputActionValue;
class ABusyPlayerRole;
struct FInputActionValue;
USTRUCT(BlueprintType)
struct FBusySkillActionConfig
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadOnly)
FGameplayTag ActionTag;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
UInputAction* InputAction;
};
UCLASS()
class ALevelPlayerController : public ALuaPlayerController
@ -48,6 +64,14 @@ public:
UFUNCTION(BlueprintCallable, Category = "Controller")
bool GetCursorPosition(FVector2D& Position) const;
/**
* 获取光标相对于所控制的人物的方向
* @param Direction
* @return false -> 获取失败, 没有角色或者鼠标不在游戏内
*/
UFUNCTION(BlueprintCallable, Category = "Controller")
bool GetCursorDirection(FVector2D& Direction) const;
UFUNCTION(BlueprintCallable, Category = "Controller")
ABusyPlayerRole* GetControlledRole() const;
@ -88,6 +112,10 @@ public: // 输入相关
UPROPERTY(EditDefaultsOnly, Category = "Input")
TObjectPtr<class UInputAction> SwitchRoleAction; // 切换控制的角色
UPROPERTY(EditDefaultsOnly, Category = "Input")
TArray<FBusySkillActionConfig> RoleSkillActions;
public:
UFUNCTION()
void OnMove(const FInputActionValue& Value)const;
@ -104,6 +132,9 @@ public:
UFUNCTION()
void OnSwitchRole(const FInputActionValue& Value);
UFUNCTION()
void OnRoleSkillTriggered(FGameplayTag GameplayTag);
protected:
UPROPERTY()