Files
BusyRabbit/Content/Lua/HomeLand/UI/Hearth/Widgets/PreCookCenterWidget.lua
wyatt 11896c87b1 技术方向可行
使用鼠标轨迹生成偏移应用到材质上实现扭曲技术可行
2025-08-29 00:51:54 +08:00

191 lines
6.1 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

local DataTableUtils = require("Utils.DataTableUtils")
local ESlateVisibility = import("ESlateVisibility")
local SlateBlueprintLibrary = import("SlateBlueprintLibrary")
local WidgetLayoutLibrary = import("WidgetLayoutLibrary")
local BusyGamePlayLibrary = import("BusyGamePlayLibrary")
--- @class PreCookCenterWidget
--- @field ImgContainer table
--- @field ImgCookMaterial table
local PreCookCenterWidget = {}
function PreCookCenterWidget:ctor()
self.mouse_tracks = {}
self.is_pressed = false
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.is_pressed = true
-- self.bHasScriptImplementedTick = true
print("pressed")
end)
-- self.BtnMain.OnClicked:Add(function()
-- print("onclicked")
-- end)
self.DataTexture = BusyGamePlayLibrary.CreateTextureBuffer(self)
end
function PreCookCenterWidget:Construct()
-- self.bHasScriptImplementedTick = true
end
function PreCookCenterWidget:Destruct()
end
function PreCookCenterWidget:SetEmpty()
self.ImgContainer:SetVisibility(ESlateVisibility.Collapsed)
self.ImgCookMaterial:SetVisibility(ESlateVisibility.Collapsed)
end
function PreCookCenterWidget:AddContainer(pre_cook_contianer_id)
local row = DataTableUtils.GetDataTableRow("PreCookItemConfig", pre_cook_contianer_id)
if not row then return end
self.ImgContainer:SetBrushFromSoftTexture(row.CenterDisplayResource, true)
self.ImgContainer:SetVisibility(ESlateVisibility.SelfHitTestInvisible)
end
function PreCookCenterWidget:RemoveContainer()
self.ImgContainer:SetVisibility(ESlateVisibility.Collapsed)
end
function PreCookCenterWidget:AddCookMaterial(pre_cook_material_id)
local row = DataTableUtils.GetDataTableRow("PreCookItemConfig", pre_cook_material_id)
if not row then return end
self.ImgCookMaterial:SetBrushFromSoftTexture(row.CenterDisplayResource, true)
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]
local B = points[#points]
-- 计算向量AB
local dx = B.X - A.X
local dy = B.Y - A.Y
local len = math.sqrt(dx * dx + dy * dy)
if len == 0 then
return {}
-- error("Start and end points are the same, cannot define X-axis.")
end
-- 计算X轴单位向量
local ux = dx / len
local uy = dy / len
-- 计算Y轴单位向量逆时针旋转90度
local vx = -uy
local vy = ux
-- 映射所有点到新坐标系
local new_points = {}
for i, point in ipairs(points) do
local apx = point.X - A.X
local apy = point.Y - A.Y
local new_x = apx * ux + apy * uy -- 点积与X轴单位向量
local new_y = apx * vx + apy * vy -- 点积与Y轴单位向量
new_points[i] = {X = new_x, Y = new_y}
end
return new_points
end
--- 将曲线的Y坐标规范到(-0.50.5)的范围内,供材质使用
local function NormalizeCurveYToHalfRange(points)
if #points < 2 then return end
local length = points[#points].X - points[1].X
for _, point in pairs(points) do
point.Y = - point.Y / length -- 临时加个取反
point.X = point.X / length
end
return points
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)
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)
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
end
return Class(nil, nil, PreCookCenterWidget)