| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  | local DataTableUtils = require("Utils.DataTableUtils") | 
					
						
							|  |  |  |  | local ESlateVisibility = import("ESlateVisibility") | 
					
						
							|  |  |  |  | local SlateBlueprintLibrary = import("SlateBlueprintLibrary") | 
					
						
							|  |  |  |  | local WidgetLayoutLibrary = import("WidgetLayoutLibrary") | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:54 +08:00
										 |  |  |  | local BusyGamePlayLibrary = import("BusyGamePlayLibrary") | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 01:14:17 +08:00
										 |  |  |  | local CUT_MASK_DISPLAY_TIME = 1.2  -- 刀光显示的时长 | 
					
						
							|  |  |  |  | local CUT_MASK_FADEOUT_TIME = 0.6  -- 刀光开始渐隐的时间点 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  | --- @class PreCookCenterWidget | 
					
						
							|  |  |  |  | --- @field ImgContainer table | 
					
						
							|  |  |  |  | --- @field ImgCookMaterial table | 
					
						
							| 
									
										
										
										
											2025-09-01 01:14:17 +08:00
										 |  |  |  | --- @field BtnMain table | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  | local PreCookCenterWidget = {} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function PreCookCenterWidget:ctor() | 
					
						
							| 
									
										
										
										
											2025-09-01 01:14:17 +08:00
										 |  |  |  |     self.mouse_tracks = {}      -- 记录当前鼠标的轨迹 | 
					
						
							|  |  |  |  |     self.rendering_tracks = {}  -- 正在被渲染的刀光 | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  |     self.is_pressed = false | 
					
						
							|  |  |  |  | end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function PreCookCenterWidget:OnInitialized() | 
					
						
							|  |  |  |  |     self.bHasScriptImplementedTick = true | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 01:14:17 +08:00
										 |  |  |  |     self:BP_BindLuaEnhancedInput(self.IA_TouchBegin, function() | 
					
						
							|  |  |  |  |         self.is_pressed = true | 
					
						
							|  |  |  |  |         self.mouse_tracks = {} | 
					
						
							|  |  |  |  |         self.rendering_tracks = {self.mouse_tracks} | 
					
						
							|  |  |  |  |         print("new track start") | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  |     end) | 
					
						
							| 
									
										
										
										
											2025-09-01 01:14:17 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     self:BP_BindLuaEnhancedInput(self.IA_TouchEnd, function() | 
					
						
							|  |  |  |  |         self.is_pressed = false | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  |         self.mouse_tracks = {} | 
					
						
							| 
									
										
										
										
											2025-09-01 01:14:17 +08:00
										 |  |  |  |         print("track end") | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  |     end) | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:54 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 01:14:17 +08:00
										 |  |  |  |     self.BtnMain:SetVisibility(ESlateVisibility.Collapsed) | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  | 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 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:54 +08:00
										 |  |  |  | --- 从起点到终点画一条线,以这条线为新的x坐标轴,将所有的点坐标映射到新坐标系下 | 
					
						
							|  |  |  |  | local function TransformCurveToEndpointAxes(points) | 
					
						
							|  |  |  |  |     local A = points[1] | 
					
						
							|  |  |  |  |     local B = points[#points] | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:54 +08:00
										 |  |  |  |     -- 计算向量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 | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:54 +08:00
										 |  |  |  |     return new_points | 
					
						
							|  |  |  |  | end | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:54 +08:00
										 |  |  |  | --- 将曲线的Y坐标规范到(-0.5,0.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 | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  | end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:54 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 01:14:17 +08:00
										 |  |  |  | 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 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  | function PreCookCenterWidget:Tick(geometry, delta_time) | 
					
						
							| 
									
										
										
										
											2025-09-01 01:14:17 +08:00
										 |  |  |  |     -- 计算鼠标点被限定在该区域下的坐标 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  |     local size = SlateBlueprintLibrary.GetLocalSize(geometry) | 
					
						
							|  |  |  |  |     local cursor_pos = WidgetLayoutLibrary.GetMousePositionOnViewport(self) | 
					
						
							|  |  |  |  |     local left_top = SlateBlueprintLibrary.GetLocalTopLeft(geometry) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 01:14:17 +08:00
										 |  |  |  |     -- 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) | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 01:14:17 +08:00
										 |  |  |  |     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 | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 01:14:17 +08:00
										 |  |  |  |     -- 更新鼠标移动轨迹 | 
					
						
							|  |  |  |  |     if self.is_pressed then | 
					
						
							|  |  |  |  |         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}) | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:54 +08:00
										 |  |  |  |         end | 
					
						
							| 
									
										
										
										
											2025-09-01 01:14:17 +08:00
										 |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 01:14:17 +08:00
										 |  |  |  |     -- 更新正在渲染的轨迹数据 | 
					
						
							|  |  |  |  |     local rendering_tracks = UpdateCutMaskData(self.rendering_tracks, delta_time) | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 01:14:17 +08:00
										 |  |  |  |     -- 绘制刀迹 | 
					
						
							|  |  |  |  |     for _, track in ipairs(rendering_tracks) do | 
					
						
							|  |  |  |  |         if #track > 2 then | 
					
						
							|  |  |  |  |             local widget = self:GetValidCutMaskWidget() | 
					
						
							|  |  |  |  |             DrawCutMaskImage(widget, track) | 
					
						
							|  |  |  |  |             -- UpdateCusMaskMaterial(widget, self.DataTexture, track) | 
					
						
							|  |  |  |  |         end | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:54 +08:00
										 |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 01:14:17 +08:00
										 |  |  |  |     -- print("Ticking", #rendering_tracks) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     self.rendering_tracks = rendering_tracks | 
					
						
							| 
									
										
										
										
											2025-08-27 00:56:05 +08:00
										 |  |  |  | end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | return Class(nil, nil, PreCookCenterWidget) |