IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> UE4中触摸屏的拖动/缩放功能——lua实现 -> 正文阅读

[游戏开发]UE4中触摸屏的拖动/缩放功能——lua实现

UE4中触摸屏的拖拽缩放功能——lua实现

1.简述

在移动端的触摸场景案例参考非常少,对于触摸的各种手势操作不好参考,然鹅这种需求对于各种应用或是需求最平常不过的了 ,这里仅针对UE4的开发提供几种思路:
我们先来看下官方的推荐操作:
1、根据设备DPI缩放规则的自动缩放
DPI缩放适应
2、使用 Drag & Drop Operation
DragAndDrop
可以看出,官方对这类操作已经做了不少友好的封装供我们使用,可以参考以上应用到自己的项目中。
以下示例演示了脚本语言对UI拖动/缩放功能的控制

2.代码示例

废话不多说,上代码~

注意:以下所有伪代码仅作参考,可以使用蓝图、C++、或任意脚本语言完全重写实现,重点理会思路

--使用override的方法实现,内部使用自己封装的函数即可
function YourPanel:OnTouchStarted(InGeometry, InGestureEvent)
    return self:MouseButtonDown(InGeometry, InGestureEvent)
end

function YourPanel:OnTouchMoved(InGeometry, InGestureEvent)
    return self:MouseMove(InGeometry, InGestureEvent)
end

function YourPanel:OnTouchEnded(InGeometry, InGestureEvent)
    return self:MouseButtonUp(InGeometry, InGestureEvent)
end

subpage为该页面的子页面,可以理解为实际拖拽和缩放的对象
PixelSeries 为自定义的放大比例因子

--处理鼠标/触摸按下事件
function YourPanel:MouseButtonDown(InGeometry, InGestureEvent)
    local PointerIndex = UE4.UKismetInputLibrary.PointerEvent_GetPointerIndex(InGestureEvent)
    local control = UE4.UGameplayStatics.GetPlayerController(self:GetOwningPlayerPawn(), 0)
    local scale = UE4.UWidgetLayoutLibrary.GetViewportScale(control)
    local CanvasSlot = UE4.UWidgetLayoutLibrary.SlotAsCanvasSlot(self.subpage)
    curPos = CanvasSlot:GetPosition()
    self.startPos = curPos
    m_MoveFlag = true
    --单指或两指的处理
    if #self.m_LastPosTable < 2 then
        local ScreenSpacePosition = UE4.UKismetInputLibrary.PointerEvent_GetScreenSpacePosition(InGestureEvent)
        local thisPos = UE4.USlateBlueprintLibrary.AbsoluteToLocal(InGeometry, ScreenSpacePosition)
        self.m_LastPosTable[PointerIndex + 1] = thisPos

        if #self.m_LastPosTable == 1 then
            CanLimitRange = true
            self.m_IsTap = true --单指按下
            self.m_HasTriggered = false
            self.m_DragStartPos = thisPos
            local ScreenSpacePosition = UE4.UKismetInputLibrary.PointerEvent_GetScreenSpacePosition(InGestureEvent)
            Offset = UE4.USlateBlueprintLibrary.AbsoluteToLocal(InGeometry, ScreenSpacePosition) --+FVector2D(120,120)
        elseif #self.m_LastPosTable == 2 then
            CanLimitRange = false
            Offset = FVector2D(0, 0)
            local otherPos = FVector2D(0, 0)

            for i = 1, #self.m_LastPosTable do
                if i ~= PointerIndex + 1 then --第二指按下的位置
                    otherPos = self.m_LastPosTable[i]
                end

                self.m_ZoomStartLength = UE4.UKismetMathLibrary.Vector_Distance2D(thisPos, otherPos) / scale
                self.m_IsTap = false
                self.m_OriginPoint = (thisPos + otherPos) / 2
                self:CalcZoomRatio()
                self.startPixelSeries = self.subpage.PixelSeries
            end
        end
        local Handled = UE4.UWidgetBlueprintLibrary.Handled()
        return UE4.UWidgetBlueprintLibrary.CaptureMouse(Handled, self)
    end

    return UE4.UWidgetBlueprintLibrary.UnHandled()
end
--处理鼠标/触摸移动事件
function YourPanel:MouseMove(InGeometry, InGestureEvent)
    if m_MoveFlag then
        m_MoveFlag = false
        --new
        local CanvasSlot = UE4.UWidgetLayoutLibrary.SlotAsCanvasSlot(self.subpage)
        local scale = UE4.UWidgetLayoutLibrary.GetViewportScale(self)
        local ScreenSpacePosition = UE4.UKismetInputLibrary.PointerEvent_GetScreenSpacePosition(InGestureEvent)
        local PointerIndex = UE4.UKismetInputLibrary.PointerEvent_GetPointerIndex(InGestureEvent)
        local thisPos = UE4.USlateBlueprintLibrary.AbsoluteToLocal(InGeometry, ScreenSpacePosition)
        local changepos = (thisPos - Offset)

        if self.m_LastPosTable[PointerIndex + 1] ~= nil then
            if #self.m_LastPosTable == 1 then --单指处理拖动
                local lastPos = self.m_LastPosTable[PointerIndex + 1]
                if UpdatePosFlag == true then
                    curPos = self.startPos + changepos
                    self.m_LastPosTable[PointerIndex + 1] = thisPos
                    CanvasSlot:SetPosition(curPos)
                end
            elseif #self.m_LastPosTable == 2 then --两指处理缩放
                if false then
                    CanLimitRange = false
                    local otherPos
                    for i = 1, #self.m_LastPosTable do
                        if i ~= PointerIndex + 1 then
                            otherPos = self.m_LastPosTable[i]
                        end
                    end
                    local MoveDist = UE4.UKismetMathLibrary.Vector_Distance2D(thisPos, otherPos) / scale
                    if self.m_ZoomStartLength <= MoveDist then --扩大
                        newPixelSeries = (MoveDist - self.m_ZoomStartLength) / 20
                        self.subpage.PixelSeries = self.startPixelSeries + newPixelSeries
                        if self.subpage.PixelSeries > 80 then --限制扩大的最大范围
                            self.subpage.PixelSeries = 80
                        end
                    else
                        newPixelSeries = (self.m_ZoomStartLength - MoveDist) / 20
                        self.subpage.PixelSeries = self.startPixelSeries - newPixelSeries
                        if self.subpage.PixelSeries < 30 then
                            self.subpage.PixelSeries = 30
                        end
                    end
                    --子页面的PixelSeries更改 可以调用自己封装的AdjustSize()来更新该控件的大小
                    self.subpage:AdjustSize()
                    self:SetZoomPos()
                    self.m_LastPosTable[PointerIndex + 1] = thisPos
                end
            end
            m_MoveFlag = true
            local Handled = UE4.UWidgetBlueprintLibrary.Handled()
            return Handled
        end
    end
    local UnHandled = UE4.UWidgetBlueprintLibrary.UnHandled()
    return UnHandled
end
--处理鼠标、触摸抬起事件
function YourPanel:MouseButtonUp(InGeometry, InGestureEvent)
    self.m_IsTap = false
    local PointerIndex = UE4.UKismetInputLibrary.PointerEvent_GetPointerIndex(InGestureEvent)
    if UpdatePosFlag == true then
        UpdatePosFlag = false
        self.UpdatePosTimerHandle =
            UE4.UKismetSystemLibrary.K2_SetTimerDelegate({self, self.OnUpdatePosFlag}, 0.05, true)
    end
    if self.m_LastPosTable[PointerIndex + 1] ~= nil then
        table.remove(self.m_LastPosTable, PointerIndex + 1)
        if #self.m_LastPosTable == 0 then
            if CanLimitRange then
                self:LimitRange()
            end
        elseif #self.m_LastPosTable == 1 then
            self.m_DragStartPos = self.m_LastPosTable[1]
        else
            self.m_LastPosTable = {}
        end
        local Handled = UE4.UWidgetBlueprintLibrary.Handled()
        return UE4.UWidgetBlueprintLibrary.ReleaseMouseCapture(Handled)
    end
    return UE4.UWidgetBlueprintLibrary.UnHandled()
end

接下来处理缩放比例和位置,以下示例控件锚点为左上,在缩放时还需要实时移动子控件的位置,以达成跟随手势位置缩放的效果:

--计算缩放比例
function YourPanel:CalcZoomRatio()
    self.m_OriginPoint = self.m_OriginPoint + FVector2D(math.abs(curPos.X), math.abs(curPos.Y))
    self.m_LeftPointPoint = FVector2D(BackgroundPlateOffset, BackgroundPlateOffset)
    self.m_RelativePos = self.m_OriginPoint - self.m_LeftPointPoint
	--计算按下位置相对于控件长宽的位置比例
    local W = self.subpage.SizeX
    local H = self.subpage.SizeY
    self.m_RelativePosRatio = FVector2D(self.m_RelativePos.X / W, self.m_RelativePos.Y / H)
end

--计算设置缩放后的偏移位置
function YourPanel:SetZoomPos()
    local CanvasSlot = UE4.UWidgetLayoutLibrary.SlotAsCanvasSlot(self.subpage)
    local newW = self.subpage.SizeX
    local newH = self.subpage.SizeY
    self.m_newRelativePos = FVector2D(newW * self.m_RelativePosRatio.X, newH * self.m_RelativePosRatio.Y)
    local newPos = curPos - self.m_newRelativePos + self.m_RelativePos
    CanvasSlot:SetPosition(newPos)
end

至此完成了基本的拖拽/缩放,细节还可以根据实际情况进行调整,也可以后续加入滑动、边界限制等功能
这里举例使用定时器,对限制位置和松开手的位置两个变量进行线性插值的运算来模拟回弹效果

--限制拖动范围
function YourPanel:LimitRange()
    local CanvasSlot = UE4.UWidgetLayoutLibrary.SlotAsCanvasSlot(self.subpage)
    curPos = CanvasSlot:GetPosition()
    local viewport_geometry = UWidgetLayoutLibrary.GetViewportWidgetGeometry(self:GetOwningPlayerPawn())
    viewportlocalsize = UE4.USlateBlueprintLibrary.GetLocalSize(viewport_geometry)
    --限制范围
    if (curPos.X + self.subpage.SizeX < viewportlocalsize.X / 2 ) then
        m_SavePrePos.X = curPos.X
        m_SaveTarPos.X = -self.subpage.SizeX  + viewportlocalsize.X / 2 
        if m_UpdateTimerFlag_X == true then
            m_UpdateTimerFlag_X = false
            self.TimerHandle_X =
                UE4.UKismetSystemLibrary.K2_SetTimerDelegate({self, self.OnUpdateEdgeLerpTimer_X}, 0.02, true)
        end
    end
    if (curPos.Y + self.subpage.SizeY < 0) then
        m_SavePrePos.Y = curPos.Y
        m_SaveTarPos.Y = -self.subpage.SizeY
        if m_UpdateTimerFlag_Y == true then
            m_UpdateTimerFlag_Y = false
            self.TimerHandle_Y =
                UE4.UKismetSystemLibrary.K2_SetTimerDelegate({self, self.OnUpdateEdgeLerpTimer_Y}, 0.02, true)
        end
    end
    CanvasSlot:SetPosition(curPos)
end

--X方向的拖拽回弹
function YourPanel:OnUpdateEdgeLerpTimer_X()
    Updatetime_X = Updatetime_X + 0.1
    curPos.X = UE4.UKismetMathLibrary.Lerp(m_SavePrePos.X, m_SaveTarPos.X, Updatetime_X)
    self:UpdateEdgeLerp()
    if (Updatetime_X > 1) then --超时,关闭定时器
        Updatetime_X = 0
        m_UpdateTimerFlag_X = true
        UE4.UKismetSystemLibrary.K2_ClearAndInvalidateTimerHandle(self, self.TimerHandle_X)
    end
end

--Y方向的拖拽回弹
function YourPanel:OnUpdateEdgeLerpTimer_Y()
    Updatetime_Y = Updatetime_Y + 0.1
    curPos.Y = UE4.UKismetMathLibrary.Lerp(m_SavePrePos.Y, m_SaveTarPos.Y, Updatetime_Y)
    self:UpdateEdgeLerp()
    if (Updatetime_Y > 1) then
        Updatetime_Y = 0
        m_UpdateTimerFlag_Y = true
        UE4.UKismetSystemLibrary.K2_ClearAndInvalidateTimerHandle(self, self.TimerHandle_Y)
    end
end

--更新回弹的位置
function YourPanel:UpdateEdgeLerp()
    local CanvasSlot = UE4.UWidgetLayoutLibrary.SlotAsCanvasSlot(self.subpage)
    CanvasSlot:SetPosition(FVector2D(curPos.X, curPos.Y))
end
  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-11-25 08:26:52  更:2021-11-25 08:27:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 23:46:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码