在某些应用中,您需要在用户触摸屏幕时执行一些持续动作。这可能包括玩家按住“开火”按钮时太空飞船发射激光,或者
对于初学者来说,这个过程可能比较难以理解,所以让我们探索一些实现持续动作的技术。
大多数需要持续动作的游戏也需要多点触控,允许多个手指同时操作屏幕上的多个控件。例如,一个同时具有“移动”按钮和“跳跃”按钮的 2D 平台游戏通常会让玩家用左手拇指控制一组按钮,用右手拇指控制另一组按钮。
如点击/触摸/多点触控指南中所述,默认情况下多点触控是禁用的,但启用它很简单
-- Activate multitouch system.activate( "multitouch" )
根据您的游戏设计,您应该仔细考虑在哪里调用此命令。虽然它可以作为 `main.lua` 中的第一行代码之一调用,但这可能不是最佳选择 — 例如,如果您的游戏以菜单场景开始
现在让我们探索一些可能应用持续动作的常见元素
另一个常见的 UI 元素是**虚拟方向键**。这些通常由
在 Solar2D 中创建这样的控件集可以类似于上面的虚拟按钮方法,但在这种情况下,玩家通常会将手指放在控制键区域的屏幕上,只需滑动(不释放)即可激活另一个方向按钮。因此,除了
这次,让我们使用**两张**图片
local buttonGroup = display.newGroup() local leftButton = display.newImageRect( buttonGroup, "leftButton.png", 64, 64 ) leftButton.x, leftButton.y = 60, display.contentHeight-60 leftButton.canSlideOn = true leftButton.ID = "left" local rightButton = display.newImageRect( buttonGroup, "rightButton.png", 64, 64 ) rightButton.x, rightButton.y = 136, display.contentHeight-60 rightButton.canSlideOn = true rightButton.ID = "right" local groupBounds = buttonGroup.contentBounds local groupRegion = display.newRect( 0, 0, groupBounds.xMax-groupBounds.xMin+200, groupBounds.yMax-groupBounds.yMin+200 ) groupRegion.x = groupBounds.xMin + ( buttonGroup.contentWidth/2 ) groupRegion.y = groupBounds.yMin + ( buttonGroup.height/2 ) groupRegion.isVisible = false groupRegion.isHitTestable = true local function detectButton( event ) for i = 1,buttonGroup.numChildren do local bounds = buttonGroup[i].contentBounds if ( event.x > bounds.xMin and event.x < bounds.xMax and event.y > bounds.yMin and event.y < bounds.yMax ) then return buttonGroup[i] end end end
此代码与上面的虚拟按钮示例类似,但有两个非常重要的区别。
对于每个按钮,我们设置一个布尔值 canSlideOn
属性,初始设置为 true
。因为操作方向键的玩家通常会将他们的触摸从一个按钮滑动到另一个按钮,这将让我们处理
我们为每个按钮分配一个 ID
属性,值为 "left"
或 "right"
— 稍后,这将帮助我们识别它代表的“方向”。
响应与方向按钮的交互可能与典型按钮不同。通常,如果按下方向按钮,则应发生稳定且一致的动作,直到释放按钮(或与相邻按钮交互)。
连续移动角色/对象的一种方法是在运行时 "enterFrame"
函数中简单地更新其**x** 或**y** 位置。我们可以将这种方法与我们的方向控制器结合起来,创建一个简单的测试对象,编写一个基本的监听器函数,并在 handleController()
函数中包含一些“控制”代码。
local testObj = display.newRect( display.contentCenterX, display.contentCenterY, 20, 20 ) testObj.deltaPerFrame = { 0, 0 } local function frameUpdate() testObj.x = testObj.x + testObj.deltaPerFrame[1] testObj.y = testObj.y + testObj.deltaPerFrame[2] end Runtime:addEventListener( "enterFrame", frameUpdate ) local function handleController( event ) local touchOverButton = detectButton( event ) if ( event.phase == "began" ) then if ( touchOverButton ~= nil ) then if not ( buttonGroup.touchID ) then -- Set/isolate this touch ID buttonGroup.touchID = event.id -- Set the active button buttonGroup.activeButton = touchOverButton -- Take proper action based on button ID if ( buttonGroup.activeButton.ID == "left" ) then testObj.deltaPerFrame = { -2, 0 } elseif ( buttonGroup.activeButton.ID == "right" ) then testObj.deltaPerFrame = { 2, 0 } end end return true end elseif ( event.phase == "moved" ) then
elseif ( event.phase == "ended" and buttonGroup.activeButton ~= nil ) then -- Release this touch ID buttonGroup.touchID = nil -- Set that no button is active buttonGroup.activeButton = nil -- Stop the action testObj.deltaPerFrame = { 0, 0 } return true end end
让我们更详细地探讨突出显示的代码。
在deltaPerFrame
,它是一个包含两个值的表,0
。
在frameUpdate()
) 来更新对象的 **x** 和 **y** 位置,基于其 deltaPerFrame
属性中的值。然后,在第 42 行,我们通过添加一个 "enterFrame"
事件监听器来启动该函数在每个运行时帧上运行/执行。
在deltaPerFrame
属性值。如果按下**左**按钮,则第一个值 (**x**) 设置为 -2
,这意味着对象将在每个运行时帧上开始向左移动 2 个像素。类似地,如果按下**右**按钮,我们将第一个值设置为 2
,以便对象每帧向右移动 2 个像素。请注意,如果希望对象移动得更快或更慢,可以增加/减少这些值。
最后,在第 86 行,如果玩家的触摸从方向按钮上漂移,我们将 deltaPerFrame
值重置为 0
以停止对象的移动。
连续移动角色/对象的另一种方法是通过**物理引擎**。当然,这假设对象是由物理引擎管理的物理对象,这超出了本教程的范围(如果您需要物理方面的帮助,请从物理设置指南开始)。
在集成
让我们调整代码以使用物理和线性速度。
-- Set up physics engine local physics = require( "physics" ) physics.start() local testObj = display.newRect( display.contentCenterX, display.contentCenterY, 20, 20 ) physics.addBody( testObj, "kinematic" ) local function handleController( event ) local touchOverButton = detectButton( event ) if ( event.phase == "began" ) then if ( touchOverButton ~= nil ) then if not ( buttonGroup.touchID ) then -- Set/isolate this touch ID buttonGroup.touchID = event.id -- Set the active button buttonGroup.activeButton = touchOverButton -- Take proper action based on button ID if ( buttonGroup.activeButton.ID == "left" ) then testObj:setLinearVelocity( -100, 0 ) elseif ( buttonGroup.activeButton.ID == "right" ) then testObj:setLinearVelocity( 100, 0 ) end end return true end elseif ( event.phase == "moved" ) then
elseif ( event.phase == "ended" and buttonGroup.activeButton ~= nil ) then -- Release this touch ID buttonGroup.touchID = nil -- Set that no button is active buttonGroup.activeButton = nil -- Stop the action testObj:setLinearVelocity( 0, 0 ) return true end end
更深入地探讨突出显示的代码,我们执行以下操作:
在require()
物理引擎并启动它运行。
在
在-100
,使对象开始向左移动。类似地,如果按下 **右** 按钮,我们为 **x** 参数分配一个值 100
,使对象开始向右移动。请注意,如果希望对象移动得更快或更慢,可以增加/减少这些值。
最后,在第 84 行,如果玩家的触摸从方向按钮上漂移,我们将对象的线性速度值重置为 0
以停止其移动。
希望本教程为在 Solar2D 中处理持续动作提供了一个基础。这种做法可能适用于许多超出所介绍的情况,你会发现,只要 немного 创造力,天空才是极限!