回退至简易刀光实现

刀光扭曲视觉表现不佳,笔直的刀光可能视觉感受更好,先不让材质扭曲,后续如果还需要实现扭曲效果,可以在这个版本的基础上继续研究
This commit is contained in:
2025-09-01 01:14:17 +08:00
parent 11896c87b1
commit 4e7f89bd38
9 changed files with 154 additions and 104 deletions

View File

@ -4,13 +4,18 @@ local SlateBlueprintLibrary = import("SlateBlueprintLibrary")
local WidgetLayoutLibrary = import("WidgetLayoutLibrary")
local BusyGamePlayLibrary = import("BusyGamePlayLibrary")
local CUT_MASK_DISPLAY_TIME = 1.2 -- 刀光显示的时长
local CUT_MASK_FADEOUT_TIME = 0.6 -- 刀光开始渐隐的时间点
--- @class PreCookCenterWidget
--- @field ImgContainer table
--- @field ImgCookMaterial table
--- @field BtnMain table
local PreCookCenterWidget = {}
function PreCookCenterWidget:ctor()
self.mouse_tracks = {}
self.mouse_tracks = {} -- 记录当前鼠标的轨迹
self.rendering_tracks = {} -- 正在被渲染的刀光
self.is_pressed = false
end
@ -18,22 +23,20 @@ end
function PreCookCenterWidget:OnInitialized()
self.bHasScriptImplementedTick = true
self.BtnMain.OnReleased:Add(function()
-- self.bHasScriptImplementedTick = false
self.is_pressed = false
print("release")
end)
self.BtnMain.OnPressed:Add(function()
self.mouse_tracks = {}
self:BP_BindLuaEnhancedInput(self.IA_TouchBegin, function()
self.is_pressed = true
-- self.bHasScriptImplementedTick = true
print("pressed")
self.mouse_tracks = {}
self.rendering_tracks = {self.mouse_tracks}
print("new track start")
end)
-- self.BtnMain.OnClicked:Add(function()
-- print("onclicked")
-- end)
self.DataTexture = BusyGamePlayLibrary.CreateTextureBuffer(self)
self:BP_BindLuaEnhancedInput(self.IA_TouchEnd, function()
self.is_pressed = false
self.mouse_tracks = {}
print("track end")
end)
self.BtnMain:SetVisibility(ESlateVisibility.Collapsed)
end
function PreCookCenterWidget:Construct()
@ -67,43 +70,6 @@ function PreCookCenterWidget:AddCookMaterial(pre_cook_material_id)
self.ImgCookMaterial:SetVisibility(ESlateVisibility.SelfHitTestInvisible)
end
local function UpdateOldMouseTrack(old_mouse_tracks, delta_time)
local new_mouse_tracks = {}
for _, track in pairs(old_mouse_tracks) do
track.remain = track.remain - delta_time
if track.remain > 0 then
table.insert(new_mouse_tracks, track)
end
end
return new_mouse_tracks
end
local function UpdateCutMaskByTracks(widget, mouse_tracks)
local FVector2D = import("Vector2D")
local FWidgetTransform = import("WidgetTransform")
if #mouse_tracks < 2 then return end
local translation, scale = FVector2D(), FVector2D()
local render_transform = FWidgetTransform()
local first_point, last_point = mouse_tracks[1], mouse_tracks[#mouse_tracks]
local delta_x = last_point.X - first_point.X
local delta_y = last_point.Y - first_point.Y
local mask_length = (delta_x^2 + delta_y^2)^0.5
translation.X, translation.Y = first_point.X, first_point.Y
scale.X, scale.Y = mask_length / 512, 1
render_transform.Scale = scale
render_transform.Translation = translation
render_transform.Angle = (math.atan(delta_y, delta_x) / (2 * math.pi)) * 360
widget:SetRenderTransform(render_transform)
end
--- 从起点到终点画一条线以这条线为新的x坐标轴将所有的点坐标映射到新坐标系下
local function TransformCurveToEndpointAxes(points)
local A = points[1]
@ -152,39 +118,105 @@ local function NormalizeCurveYToHalfRange(points)
end
local function UpdateCutMaskData(rendering_tracks, delta_time)
local new_visible_tracks = {}
for _, track in ipairs(rendering_tracks) do
local is_visible = false
for _, point in pairs(track) do
local remain = math.max(point.remain - delta_time, 0)
point.remain = remain
if remain > 0 then is_visible = true end
end
if is_visible then
table.insert(new_visible_tracks, track)
end
end
return new_visible_tracks
end
local function DrawCutMaskImage(widget, mouse_tracks)
local FVector2D = import("Vector2D")
local FWidgetTransform = import("WidgetTransform")
-- 设置图片合理的位移、旋转、缩放的参数
local translation, scale = FVector2D(), FVector2D()
local render_transform = FWidgetTransform()
local first_point, last_point = mouse_tracks[1], mouse_tracks[#mouse_tracks]
local delta_x = last_point.X - first_point.X
local delta_y = last_point.Y - first_point.Y
local mask_length = (delta_x^2 + delta_y^2)^0.5 -- 轨迹长度,确定缩放参数
translation.X, translation.Y = first_point.X, first_point.Y -- 第一个点确定图片唯一
scale.X, scale.Y = mask_length / 512, 1
render_transform.Scale = scale
render_transform.Translation = translation
render_transform.Angle = (math.atan(delta_y, delta_x) / (2 * math.pi)) * 360 -- 第一个点与最后一个点连线确定图片旋转角度
widget:SetRenderTransform(render_transform)
end
-- 更新刀痕的材质
local function UpdateCusMaskMaterial(widget, texture, mouse_track)
local transformed_tracks = TransformCurveToEndpointAxes(mouse_track)
local normalize_tracks = NormalizeCurveYToHalfRange(transformed_tracks)
local offsets = {}
for _, track in ipairs(normalize_tracks) do
table.insert(offsets, track.Y)
end
BusyGamePlayLibrary.UpdateTextureBuffer(texture, offsets)
local material = widget:GetDynamicMaterial()
material:SetTextureParameterValue("Param", texture)
material:SetScalarParameterValue("VertexCount", #offsets)
material:SetScalarParameterValue("SourceWidth", 512)
end
function PreCookCenterWidget:GetValidCutMaskWidget()
return self.ImgMask
end
function PreCookCenterWidget:ResetAllCutMaskWidget()
end
function PreCookCenterWidget:Tick(geometry, delta_time)
-- 计算鼠标点被限定在该区域下的坐标
local size = SlateBlueprintLibrary.GetLocalSize(geometry)
local cursor_pos = WidgetLayoutLibrary.GetMousePositionOnViewport(self)
local left_top = SlateBlueprintLibrary.GetLocalTopLeft(geometry)
local fixed_x = math.min(math.max(cursor_pos.X - left_top.X, 0), size.X)
local fixed_y = math.min(math.max(cursor_pos.Y - left_top.Y, 0), size.Y)
local mouse_tracks = UpdateOldMouseTrack(self.mouse_tracks, delta_time)
-- local fixed_x = math.min(math.max(cursor_pos.X - left_top.X, 0), size.X)
-- local fixed_y = math.min(math.max(cursor_pos.Y - left_top.Y, 0), size.Y)
local fixed_x, fixed_y = cursor_pos.X - left_top.X, cursor_pos.Y - left_top.Y
if fixed_x < 0 or fixed_x > size.X or fixed_y < 0 or fixed_y > size.Y then return end
-- 更新鼠标移动轨迹
if self.is_pressed then
table.insert(mouse_tracks, {X=fixed_x, Y=fixed_y, remain=0.5})
end
-- 计算样条参数
if #mouse_tracks > 2 then
local transformed_tracks = TransformCurveToEndpointAxes(mouse_tracks)
local normalize_tracks = NormalizeCurveYToHalfRange(transformed_tracks)
local offsets = {}
for _, track in pairs(normalize_tracks) do
table.insert(offsets, track.Y)
local last_point = self.mouse_tracks[#self.mouse_tracks]
if not last_point or math.abs(last_point.X - fixed_x) > 1 or math.abs(last_point.Y - fixed_y) > 1 then
table.insert(self.mouse_tracks, {X=fixed_x, Y=fixed_y, remain=0.5})
end
BusyGamePlayLibrary.UpdateTextureBuffer(self.DataTexture, offsets)
local mi = self.ImgMask:GetDynamicMaterial()
mi:SetTextureParameterValue("Param", self.DataTexture)
mi:SetScalarParameterValue("VertexCount", #offsets)
mi:SetScalarParameterValue("SourceWidth", 512)
UpdateCutMaskByTracks(self.ImgMask, mouse_tracks)
end
self.mouse_tracks = mouse_tracks
-- 更新正在渲染的轨迹数据
local rendering_tracks = UpdateCutMaskData(self.rendering_tracks, delta_time)
-- 绘制刀迹
for _, track in ipairs(rendering_tracks) do
if #track > 2 then
local widget = self:GetValidCutMaskWidget()
DrawCutMaskImage(widget, track)
-- UpdateCusMaskMaterial(widget, self.DataTexture, track)
end
end
-- print("Ticking", #rendering_tracks)
self.rendering_tracks = rendering_tracks
end

View File

@ -4,6 +4,8 @@
#include "Core/PW_UserWidget.h"
#include "Core/UI/PW_UIHud.h"
#include "slua.h"
#include "EnhancedInput/Public/EnhancedInputSubsystems.h"
#include "EnhancedInput/Public/EnhancedInputComponent.h"
UPW_SimpleWidget::UPW_SimpleWidget():bVisible(true){
bVisible = true;
@ -36,7 +38,6 @@ FLuaWidgetEventHandle UPW_SimpleWidget::BP_BindLuaEvent(const FName& EventName,
TMap<int32, slua::LuaVar>& FunctionPool = LuaFuncMappings.FindOrAdd(EventName);
HandleIndex += 1;
FunctionPool.Add(HandleIndex, InLuaFunction.value);
//FunctionPool[HandleIndex] = InLuaFunction.value;
Handle.EventName = EventName;
Handle.HandleIndex = HandleIndex;
return Handle;
@ -65,29 +66,22 @@ void UPW_SimpleWidget::BP_EmitLuaEvent(const FName& EventName, const FLuaBPVar&
}
}
FReply UPW_SimpleWidget::NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent){
slua::LuaVar SelfTable = GetSelfTable();
if (SelfTable.isTable()) {
slua::LuaVar LuaCallback = SelfTable.getFromTable<slua::LuaVar, FString>(TEXT("LuaMouseButtonDown"));
if (LuaCallback.isFunction()) {
LuaCallback.call();
}
}
return FReply::Unhandled();
//return Super::NativeOnMouseButtonDown(InGeometry, InMouseEvent);
void UPW_SimpleWidget::BP_BindLuaEnhancedInput(UInputAction* Action, FLuaBPVar Callback) {
UEnhancedInputComponent* EnhancedInput;
if (!Action) return;
EnhancedInput = CastChecked<UEnhancedInputComponent>(GetOwningPlayer()->InputComponent);
if (!EnhancedInput) return;
EnhancedInput->BindActionInstanceLambda(Action, ETriggerEvent::Triggered, [Callback](const FInputActionInstance& ActionInstance) {
slua::LuaVar LuaCallback = Callback.value;
if (!LuaCallback.isFunction()) return;
LuaCallback.call();
});
}
FReply UPW_SimpleWidget::NativeOnMouseButtonUp(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent){
slua::LuaVar SelfTable = GetSelfTable();
if (SelfTable.isTable()) {
slua::LuaVar LuaCallback = SelfTable.getFromTable<slua::LuaVar, FString>(TEXT("LuaMouseButtonUp"));
if (LuaCallback.isFunction()) {
LuaCallback.call();
}
}
return FReply::Unhandled();
//return Super::NativeOnMouseButtonUp(InGeometry, InMouseEvent);
}
void UPW_UserWidget::BP_Close(){
APW_UIHud* Hud = Cast<APW_UIHud>(GetPlayerContext().GetHUD());
@ -105,12 +99,33 @@ void UPW_UserWidget::FrameWorkSetVisible(bool InVisible){
_RefreshVisible();
}
void UPW_UserWidget::_UpdateInputState(bool bNeedRegister) {
APlayerController* PC;
UEnhancedInputLocalPlayerSubsystem* Subsystem;
if (!InputMappingContext) return;
PC = GetOwningPlayer();
if (!PC) return;
Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer());
if (!Subsystem) return;
if (bNeedRegister) {
Subsystem->AddMappingContext(InputMappingContext, 0);
}
else {
Subsystem->RemoveMappingContext(InputMappingContext);
}
}
void UPW_UserWidget::_RefreshVisible(){
bool FinalVisible = bFrameWorkVisible && bVisible;
if (FinalVisible) {
bool bFinalVisible = bFrameWorkVisible && bVisible;
if (bFinalVisible) {
SetVisibility(ESlateVisibility::SelfHitTestInvisible);
}
else {
SetVisibility(ESlateVisibility::Collapsed);
}
_UpdateInputState(bFinalVisible);
}

View File

@ -65,6 +65,7 @@ void UPW_UILayer::PopWidget(const UPW_UserWidget* WidgetInst){
}
}
for (i = 0; i < NeedRemoveWidgets.Num(); ++i) {
NeedRemoveWidgets[i]->FrameWorkSetVisible(false);
NeedRemoveWidgets[i]->RemoveFromParent();
}
if (NeedShowWidget) {

View File

@ -51,10 +51,8 @@ public:
UFUNCTION(BlueprintCallable)
void BP_EmitLuaEvent(const FName& EventName, const FLuaBPVar& InLuaArgs);
public:
virtual FReply NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent)override;
virtual FReply NativeOnMouseButtonUp(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent)override;
UFUNCTION(BlueprintCallable)
void BP_BindLuaEnhancedInput(class UInputAction* Action, FLuaBPVar Callback);
public:
@ -73,8 +71,7 @@ protected: // lua相关
*
*/
UCLASS()
class BUSYRABBIT_API UPW_UserWidget : public UPW_SimpleWidget
{
class BUSYRABBIT_API UPW_UserWidget : public UPW_SimpleWidget{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, DisplayName="是否全局唯一")
@ -84,6 +81,9 @@ public:
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly)
EWidgetLayoutType LayoutType;
UPROPERTY(EditDefaultsOnly, Category = "Input")
TObjectPtr<class UInputMappingContext> InputMappingContext;
public:
UFUNCTION(BlueprintCallable)
void BP_Close();
@ -95,6 +95,8 @@ public:
void FrameWorkSetVisible(bool InVisible);
protected:
void _UpdateInputState(bool bNeedRegister);
void _RefreshVisible();
protected: