通过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="\"\'," InvalidTagCharacters="\"\',"
NumBitsForContainerSize=6 NumBitsForContainerSize=6
NetIndexFirstBitSegment=16 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.AttributeConsume",DevComment="角色属性损耗debuff")
+GameplayTagList=(Tag="Ability.Role.EatFood",DevComment="干饭") +GameplayTagList=(Tag="Ability.Role.EatFood",DevComment="干饭")
+GameplayTagList=(Tag="Ability.Role.Pick",DevComment="角色采集物品") +GameplayTagList=(Tag="Ability.Role.Pick",DevComment="角色采集物品")
+GameplayTagList=(Tag="Ability.Role.Recover",DevComment="角色状态恢复技能") +GameplayTagList=(Tag="Ability.Role.Recover",DevComment="角色状态恢复技能")
+GameplayTagList=(Tag="Ability.Role.Roll",DevComment="角色无敌翻滚") +GameplayTagList=(Tag="Ability.Role.Roll",DevComment="角色无敌翻滚")
+GameplayTagList=(Tag="Ability.Role.Ultimate",DevComment="角色大招")
+GameplayTagList=(Tag="Buff.Indispersible.HungerConsume",DevComment="饥饿值消耗,不可被驱散") +GameplayTagList=(Tag="Buff.Indispersible.HungerConsume",DevComment="饥饿值消耗,不可被驱散")
+GameplayTagList=(Tag="Buff.RoleConsume.Health",DevComment="角色因饥饿掉血的debuff") +GameplayTagList=(Tag="Buff.RoleConsume.Health",DevComment="角色因饥饿掉血的debuff")
+GameplayTagList=(Tag="Buff.RoleConsume.Hunger",DevComment="角色每秒钟的饥饿消耗") +GameplayTagList=(Tag="Buff.RoleConsume.Hunger",DevComment="角色每秒钟的饥饿消耗")
@ -25,6 +28,8 @@ NetIndexFirstBitSegment=16
+GameplayTagList=(Tag="CookProcess.Diced",DevComment="切丁") +GameplayTagList=(Tag="CookProcess.Diced",DevComment="切丁")
+GameplayTagList=(Tag="CookProcess.Mashed",DevComment="切泥") +GameplayTagList=(Tag="CookProcess.Mashed",DevComment="切泥")
+GameplayTagList=(Tag="CookProcess.Sliced",DevComment="切片操作") +GameplayTagList=(Tag="CookProcess.Sliced",DevComment="切片操作")
+GameplayTagList=(Tag="Effect.Duration",DevComment="效果的持续时长")
+GameplayTagList=(Tag="Effect.Factor",DevComment="效果的乘法系数")
+GameplayTagList=(Tag="GameItem.Building",DevComment="建筑物") +GameplayTagList=(Tag="GameItem.Building",DevComment="建筑物")
+GameplayTagList=(Tag="GameItem.Food",DevComment="游戏内的可食用物品") +GameplayTagList=(Tag="GameItem.Food",DevComment="游戏内的可食用物品")
+GameplayTagList=(Tag="Ingredient",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 --- @class BusyGameplayLibrary
--- @field K2_GetWorld fun(obj:table):table --- @field K2_GetWorld fun(obj:table):table
--- @field RequestGameplayTag fun(TagName:string):GameplayTag
local BusyGameplayLibrary = {} local BusyGameplayLibrary = {}

View File

@ -29,7 +29,14 @@ KismetSystemLibrary = {
} }
--- @class GameplayTag
local GameplayTag
--- @class GameplayStatics --- @class GameplayStatics
--- @field GetPlayerController fun(uobj:table,idx:number):table --- @field GetPlayerController fun(uobj:table,idx:number):table
--- @field GetGameState fun(uobj:table):table --- @field GetGameState fun(uobj:table):table
local GameplayStatics 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){ bool UBusyGameplayLibrary::GetCookMaterialStateConfig(const FName& RowName, FBusyCookMaterialStateConfig& RowData){
return GetTableConfig<FBusyCookMaterialStateConfig>(TEXT("CookMaterialStateConfig"), RowName, 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" #include "LuaCppBinding.h"
using namespace slua; 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) { static int LuaBinding_FindRow(lua_State* L) {
UDataTable* DataTable = LuaObject::checkUD<UDataTable>(L, 1); UDataTable* DataTable = LuaObject::checkUD<UDataTable>(L, 1);
@ -37,24 +13,13 @@ static int LuaBinding_FindRow(lua_State* L) {
LuaStruct* luaStruct = new LuaStruct(); LuaStruct* luaStruct = new LuaStruct();
luaStruct->Init((uint8*)TableRow, rowStruct->GetStructureSize(), (UScriptStruct*)rowStruct, true); 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); //auto ret = LuaObject::push(L, luaStruct);
return LuaObject::pushReference<LuaStruct*>(L, luaStruct, TableRow); 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() { extern void RegisterDataTableExtension() {
REG_EXTENSION_METHOD_IMP(UDataTable, "FindRow", { return LuaBinding_FindRow(L); }); 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 "Level/Actor/BusyPawnBase.h"
#include "BusyGameplayLibrary.h"
#include "Components/SphereComponent.h" #include "Components/SphereComponent.h"
#include "SpineSkeletonRendererComponent.h" #include "SpineSkeletonRendererComponent.h"
#include "SpineSkeletonAnimationComponent.h" #include "SpineSkeletonAnimationComponent.h"
#include "Gas/BusyGameAbility.h"
#include "Level/Actor/Components/BusyPawnMovement.h" #include "Level/Actor/Components/BusyPawnMovement.h"
#include "Tables/BusyPawnConfig.h"
DEFINE_LOG_CATEGORY(LogBusyPawn) DEFINE_LOG_CATEGORY(LogBusyPawn)
@ -30,38 +34,46 @@ void ABusyPawnBase::BeginPlay()
{ {
Super::BeginPlay(); Super::BeginPlay();
// for (UClass* AbilityClass : Row->DefaultAbilities) { if (const UDataTable* DataTable = UBusyGameplayLibrary::GetGameDataTable("LevelRoleBaseConfig"))
// if (AbilityClass) { {
// AbilitySystemComponent->GiveAbility(FGameplayAbilitySpec(AbilityClass)); 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 float ABusyPawnBase::GetSpeed_Implementation()const
{ {
if (Attribute) if (Attributes)
{ {
return Attribute->GetMoveSpeed(); return Attributes->GetMoveSpeed();
} }
return 0.f; 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); AbilitySystemComponent->GiveAbility(FGameplayAbilitySpec(Ability));
Attribute->InitMaxHealth(MaxHealth);
} }
} }

View File

@ -19,46 +19,31 @@ ABusyPlayerRole::ABusyPlayerRole()
SpringArmComponent->SetRelativeRotation(FRotator(0, -90.0, 0.0)); SpringArmComponent->SetRelativeRotation(FRotator(0, -90.0, 0.0));
Attribute = CreateDefaultSubobject<UBusyPlayerRoleAttributeSet>(TEXT("Attribute")); Attributes = CreateDefaultSubobject<UBusyPlayerRoleAttributeSet>(TEXT("Attribute"));
InitMoveSpeed(200);
InitHealth(100, 100);
} }
void ABusyPlayerRole::BeginPlay() void ABusyPlayerRole::BeginPlay()
{ {
Super::BeginPlay(); Super::BeginPlay();
InitRoleAttributes();
} }
bool ABusyPlayerRole::InitRoleAttributes() void ABusyPlayerRole::InitPawnAttributes(const struct FBusyPawnBaseConfig& Config)
{ {
if (!PawnName.IsValid()) return false; Super::InitPawnAttributes(Config);
const UDataTable* ConfigTable = UBusyGameplayLibrary::GetGameDataTable(TEXT("LevelRoleBaseConfig")); UBusyPlayerRoleAttributeSet* RoleAttributes = Cast<UBusyPlayerRoleAttributeSet>(Attributes);
if (!ConfigTable)
if (RoleAttributes && Config.StaticStruct() == FBusyRoleBaseConfig::StaticStruct())
{ {
UE_LOG(LogBusyPawn, Log, TEXT("ABusyPlayerRole::InitRoleAttributes Can't find config table: LevelRoleBaseConfig")) const FBusyRoleBaseConfig* RoleConfig = static_cast<const FBusyRoleBaseConfig*>(&Config);
return false; RoleAttributes->InitHunger(RoleConfig->Hunger);
RoleAttributes->InitMaxHunger(RoleConfig->Hunger);
RoleAttributes->InitHungerConsume(RoleConfig->HungerConsume);
} }
else
const FBusyRoleBaseConfig* Result = ConfigTable->FindRow<FBusyRoleBaseConfig>(
PawnName,
*FString::Printf(TEXT("ABusyPlayerRole::InitRoleAttributes, PawnName: %ls"), *PawnName.ToString())
);
if (Result)
{ {
UBusyPlayerRoleAttributeSet* RoleAttributes = Cast<UBusyPlayerRoleAttributeSet>(Attribute); UE_LOG(LogBusyPawn, Warning, TEXT("ABusyPlayerRole::InitPawnAttributes Failed, RoleAttribute: %p, ConfigName: %s"),
RoleAttributes->InitHealth(Result->Health); RoleAttributes, *Config.StaticStruct()->GetFName().ToString()
RoleAttributes->InitMaxHealth(Result->Health); );
RoleAttributes->InitMoveSpeed(Result->MoveSpeed);
RoleAttributes->InitHunger(Result->Hunger);
RoleAttributes->InitMaxHunger(Result->Hunger);
RoleAttributes->InitHungerConsume(Result->HungerConsume);
RoleAttributes->InitDamage(Result->Damage);
RoleAttributes->InitDefense(Result->Defense);
return true;
} }
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 FVector2D UBusyPawnMovement::GetMoveDirection()const
{ {
if (AActor *Owner = GetOwner()) if (AActor *Owner = GetOwner())
@ -119,14 +135,24 @@ void UBusyPawnMovement::SprintTick(const float DeltaTime)
const FVector CurrentLocation = Owner->GetActorLocation(); const FVector CurrentLocation = Owner->GetActorLocation();
const FVector2D CurrentLocation2D = FVector2D(CurrentLocation); const FVector2D CurrentLocation2D = FVector2D(CurrentLocation);
const float MoveDistance = DeltaTime * Movable->Execute_GetSpeed(Owner) * SprintSpeedRate; float SprintDeltaTime = DeltaTime;
const FVector2D NewLocation = CurrentLocation2D + ForwardDirection * MoveDistance; 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); 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/LevelPlayerController.h"
#include "Level/Actor/BusyPlayerRole.h" #include "Level/Actor/BusyPlayerRole.h"
#include "AbilitySystemBlueprintLibrary.h"
#include "EnhancedInput/Public/EnhancedInputSubsystems.h" #include "EnhancedInput/Public/EnhancedInputSubsystems.h"
#include "Level/LevelPlayerState.h" #include "Level/LevelPlayerState.h"
#include "EnhancedInput/Public/EnhancedInputComponent.h" #include "EnhancedInput/Public/EnhancedInputComponent.h"
@ -52,6 +53,14 @@ void ALevelPlayerController::SetupInputComponent()
BindEnhancedInputAction(EnhancedInput, PrimarySkillAction, this, "OnPrimarySkill"); BindEnhancedInputAction(EnhancedInput, PrimarySkillAction, this, "OnPrimarySkill");
BindEnhancedInputAction(EnhancedInput, UltimateSkillAction, this, "OnUltimateSkill"); BindEnhancedInputAction(EnhancedInput, UltimateSkillAction, this, "OnUltimateSkill");
BindEnhancedInputAction(EnhancedInput, SwitchRoleAction, this, "OnSwitchRole"); 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) void ALevelPlayerController::Tick(float DeltaTime)
@ -107,6 +116,20 @@ bool ALevelPlayerController::GetCursorPosition(FVector2D& Position) const
return false; 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 void ALevelPlayerController::GetCursorHitResult(TArray<AActor*>& Results) const
{ {
} }
@ -192,3 +215,14 @@ void ALevelPlayerController::OnSwitchRole(const FInputActionValue& Value)
SwitchControlledRole(ControlledRole); 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) UFUNCTION(BlueprintPure)
static bool GetCookMaterialStateConfig(const FName& RowName, FBusyCookMaterialStateConfig& RowData); 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; class USphereComponent;
struct FBusyPawnBaseConfig;
class USpineBoneFollowerComponent; class USpineBoneFollowerComponent;
class USpineSkeletonRendererComponent; class USpineSkeletonRendererComponent;
class USpineSkeletonAnimationComponent; class USpineSkeletonAnimationComponent;
@ -63,14 +64,9 @@ public:
virtual float GetSpeed_Implementation()const override; virtual float GetSpeed_Implementation()const override;
public: 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: protected:
UPROPERTY(EditDefaultsOnly) UPROPERTY(EditDefaultsOnly)
@ -111,7 +107,7 @@ public:
protected: protected:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<UBusyPawnAttributeSet> Attribute = nullptr; TObjectPtr<UBusyPawnAttributeSet> Attributes = nullptr;
protected: protected:

View File

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

View File

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

View File

@ -54,6 +54,23 @@ public:
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
void SprintTo(const float Distance, const float SpeedRate); 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) * @return 返回朝向的单位向量,如果没动返回(0,0)
@ -98,9 +115,16 @@ protected:
UPROPERTY(EditAnywhere, BlueprintReadOnly) UPROPERTY(EditAnywhere, BlueprintReadOnly)
FVector2D ForwardDirection; FVector2D ForwardDirection;
// 冲刺相关
protected:
FVector2D SprintDirection; // 冲刺的方向
float SprintTotalTime; // 冲刺总时长
float SprintRemainTime; // 冲刺的剩余时间
float SprintSpeed; // 指定的冲刺速度, 为0表示使用自己的速度
protected: // 冲刺相关
float SprintSpeedRate = 1.f; float SprintSpeedRate = 1.f;
float SprintDistance = 100.f; float SprintDistance = 100.f;
FVector2D SprintStartLocation; FVector2D SprintStartLocation;

View File

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