回退至简易刀光实现
刀光扭曲视觉表现不佳,笔直的刀光可能视觉感受更好,先不让材质扭曲,后续如果还需要实现扭曲效果,可以在这个版本的基础上继续研究
This commit is contained in:
		| @ -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 | ||||
|  | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user