跳至主要內容
F23.Blueprintable|TimeHandle定时任务

导言

在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"));
}


Mr.Si小于 1 分钟u++
EXP14.单向跳跃平台(碰撞体积)

提要

响应通道(Collision Response Channels)


UE 的碰撞系统由三部分组成:

  1. 碰撞通道(Collision Channel)

    • 用于标记对象所属类型。

    • UE 内置两种类型:

      • Object Channels(对象通道):标记对象类别,比如 PawnWorldStaticWorldDynamic
      • Trace Channels(射线通道):用于射线/扫描(LineTrace、SphereTrace)检测。

Mr.Si大约 6 分钟u++
EXP13.无光模式

问题描述

	// 设置光照模式
	UFUNCTION(BlueprintCallable)
	void SetViewMode(EViewModeIndex ViewMode) {
	ApplyViewMode(ViewMode, false, GEngine->GameViewport->EngineShowFlags);
	GEngine->GameViewport->ViewModeIndex = ViewMode;
}

Mr.Si小于 1 分钟u++
Umg.UI焦点问题

UI焦点问题

导言

最近在做道具轮盘,大致流程是按下某个按键,弹出一个轮盘,使用鼠标或者手柄来选择某个插槽。 本篇记录一下实现中的一些坑。

实现原理


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);
}
	

Mr.Si大约 1 分钟unreal
ED09.EdGraph|序

导言

UEdGraph 系统结构

UEdGraph

UEdGraphNode

UEdGraphPin

UEdGraphSchema

PinA->LinkedTo.Add(PinB);
PinB->LinkedTo.Add(PinA);

Mr.Si大约 3 分钟u++
ED10.EdGraph|K2Node节点

UEdGraphNode

UEdGraphNode|基础接口

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;
};

Mr.Si大约 2 分钟u++
ED06.Config|属性持久化

温故

1️⃣ 用 AssetDefinitionDefault注册我们的资产。

2️⃣ 用 ToolMenus扩展编辑器的菜单和工具栏。

3️⃣ 用 FSlateStyleSet自定义了一些图标。

属性持久化

Config

Config|类内方法


Mr.Si大约 3 分钟u++
ED08.FAssetEditorToolkit|自定义资源编辑器

省流

FAssetEditorToolkit

一个封装了“UE 编辑器中资产编辑器所需基础功能(如菜单、工具栏、面板注册、布局、命令系统)的一套可扩展基类框架”。

	virtual EAssetCommandResult OpenAssets(const FAssetOpenArgs& OpenArgs) const override;

Mr.Si大约 7 分钟u++
Error17. GameInstanceInit阶段过早触发异步加载导致崩溃

问题描述

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();
}

Mr.Si小于 1 分钟u++