问题复现
小于 1 分钟
在UE5中,往往有一些定时的需求,比如一段时间内开启护盾(当然这里咱们不考虑使用GAS的GE等效果来实现),这时候往往需要自己设定一个定时器, 给定一个时间用来开启关闭特效。
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="DoodleJump")
bool bHasShield = false;
UFUNCTION()
void RemoveShield();
void ADoodleJumpCharacter::GenerateShield_Implementation(float Time)
{
// 如果之前没有护盾才播放护盾开启特效
if (!bHasShield)
{
ShowShieldEffect(true);
}
bHasShield = true;
// 重置计时器(重新计时 / 延长)
GetWorldTimerManager().ClearTimer(ShieldTimerHandle);
GetWorldTimerManager().SetTimer(
ShieldTimerHandle,
this,
&ADoodleJumpCharacter::RemoveShield,
Time,
false
);
UE_LOG(LogTemp, Log, TEXT("Shield %s for %.2f seconds"),
bHasShield ? TEXT("extended") : TEXT("activated"),
Time);
}
void ADoodleJumpCharacter::RemoveShield()
{
bHasShield = false;
ShowShieldEffect(false);
UE_LOG(LogTemp, Log, TEXT("Shield Expired"));
}
UE 的碰撞系统由三部分组成:
碰撞通道(Collision Channel)
用于标记对象所属类型。
UE 内置两种类型:
Pawn
、WorldStatic
、WorldDynamic
。 // 设置光照模式
UFUNCTION(BlueprintCallable)
void SetViewMode(EViewModeIndex ViewMode) {
ApplyViewMode(ViewMode, false, GEngine->GameViewport->EngineShowFlags);
GEngine->GameViewport->ViewModeIndex = ViewMode;
}
最近在做道具轮盘,大致流程是按下某个按键,弹出一个轮盘,使用鼠标或者手柄来选择某个插槽。 本篇记录一下实现中的一些坑。
FVector2D URadialWheelWidget::GetWheelCenterPosition()
{
if (!WheelOverlay)
{
return FVector2D::ZeroVector;
}
// 获取 Overlay 的几何信息
const FGeometry& Geometry = WheelOverlay->GetCachedGeometry();
// 本地中心点
const FVector2D LocalCenter = Geometry.GetLocalSize() * 0.5f;
// 转换到绝对屏幕坐标
FVector2D PixelPosition;
FVector2D ViewportPosition;
USlateBlueprintLibrary::LocalToViewport(this, Geometry, LocalCenter, PixelPosition, ViewportPosition);
// 加上DPI缩放
return ViewportPosition * UWidgetLayoutLibrary::GetViewportScale(this);
}
void URadialWheelWidget::CalcAngleAndDistanceFromDir(const FVector2D& Dir, float& OutAngle, double& OutDistance) const
{
OutDistance = Dir.Size();
if (!Dir.IsNearlyZero())
{
// Y 翻转
OutAngle = FMath::RadiansToDegrees(FMath::Atan2(Dir.Y, Dir.X)) + 90.f;
OutAngle = FRotator::ClampAxis(OutAngle);
}
else
{
OutDistance = 0.0;
OutAngle = 0.f;
}
}
FVector2D URadialWheelWidget::GetMousePosition()
{
float Angle = 0.f;
double Distance = 0.0;
//1. 获取鼠标在屏幕中的绝对位置(考虑DPI缩放)
const FVector2D MousePos = UWidgetLayoutLibrary::GetMousePositionOnViewport(this) *
UWidgetLayoutLibrary::GetViewportScale(this);
//2.获取轮盘中心坐标
const FVector2D Center = GetWheelCenterPosition();
//3.计算偏移向量
const FVector2D Dir = MousePos - Center;
//4.计算角度和距离
CalcAngleAndDistanceFromDir(Dir, Angle, Distance);
}
PinA->LinkedTo.Add(PinB);
PinB->LinkedTo.Add(PinA);
UCLASS( )
class XXX_API UXXXNode : public UEdGraphNode
{
GENERATED_BODY()
public:
/*初始化时用到引脚*/
virtual void AllocateDefaultPins() override;
/*节点工具提示*/
virtual FText GetTooltipText() const override;
/*节点标题*/
virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override;
/*颜色和图标*/
virtual FLinearColor GetNodeTitleColor() const override;
virtual FSlateIcon GetIconAndTint(FLinearColor& OutColor) const override;
};
AssetDefinitionDefault
注册我们的资产。ToolMenus
扩展编辑器的菜单和工具栏。FSlateStyleSet
自定义了一些图标。一个封装了“UE 编辑器中资产编辑器所需基础功能(如菜单、工具栏、面板注册、布局、命令系统)的一套可扩展基类框架”。
virtual EAssetCommandResult OpenAssets(const FAssetOpenArgs& OpenArgs) const override;
void UExorcistGameInstance::Init()
{
Super::Init();
if(Request.IsEmpty()) return;
UAsyncMultiDataCollectionLoader* Loader = UAsyncMultiDataCollectionLoader::AsyncMultiDataCollectionLoader(this,Request,LoadBundles);
if(!Loader) return;
Loader->OnSuccess.AddDynamic(this, &UExorcistGameInstance::OnDataCollectionLoaded);
Loader->Activate();
}
void UExorcistGameInstance::OnDataCollectionLoaded(const TArray<FDataCollectionInstance>& DefinitionCollections)
{
if(DefinitionCollections.IsEmpty()) return;
UExorcistSaveGame* SaveSettings = UExorcistDataStorageLibrary::LoadSaveData(this);
if (!SaveSettings) return;
UUserDataSubsystem *UserData = GetSubsystem<UUserDataSubsystem>();
if(!UserData) return;
for(auto DataCollection : DefinitionCollections)
{
if(DataCollection.DefinitionInstance && DataCollection.PrimaryAssetType == TEXT("Inventory"))
{
UExorcistSaveDataValidatorLibrary::ValidateInventoryData(SaveSettings, DataCollection.DefinitionInstance);
}
else if(DataCollection.DefinitionInstance && DataCollection.PrimaryAssetType == TEXT("Hero"))
{
UExorcistSaveDataValidatorLibrary::ValidateHeroData(SaveSettings, DataCollection.DefinitionInstance);
}
UserData->AddDefinitionCollection(DataCollection.PrimaryAssetType, DataCollection.DefinitionInstance);
}
UExorcistDataStorageLibrary::SaveGameData(this, SaveSettings);
UserData->MarkDataReady();
}