2011/11/23

Corona SDKでのDrag & Drop基本サンプル

新しく取りかかり始めたアプリでタッチ操作によるDrag&Dropを実装しようと思い、以前にclipしておいたこのページのDrag&Dropのサンプルコードを動かしてみました。
-- create object
local myObject = display.newRect( 0, 0, 100, 100 )
myObject:setFillColor( 255 )

-- touch listener function
function myObject:touch( event )
  if event.phase == "began" then
    self.markX = self.x    -- store x location of object
    self.markY = self.y    -- store y location of object
  elseif event.phase == "moved" then
    local x = (event.x - event.xStart) + self.markX
    local y = (event.y - event.yStart) + self.markY
    self.x, self.y = x, y    -- move object based on calculations above
  end
  return true
end

-- make 'myObject' listen for touch events
myObject:addEventListener( "touch", myObject )
実際に動かしてみるとわかるのですが、タッチ操作(指の動き)にオブジェクトが追従してきません。最初はfpsが低いのかなとも思ったのですが、60fpsに設定しても変わりませんでした。

ソース的には何も間違っていないような印象があったのですが、別のサンプルコードを見つけて納得しました。上記のコードでは指の動きが少しでも早くなると、オブジェクトに対するイベントがすぐに外れてしまうため、操作に対する追従が悪かったのです。

実践的というか使えるコードとしては以下の様になります。
-- create object
local myObject = display.newRect( 0, 0, 100, 100 )
myObject:setFillColor( 255 )

-- touch listener function
function myObject:touch( event )
  local t = event.target
  local phase = event.phase
  if("began" == phase) then
    display.getCurrentStage():setFocus(t)
    t.isFocus = true
    t.x0 = event.x - t.x
    t.y0 = event.y - t.y
  elseif(t.isFocus) then
    if("moved" == phase) then
      t.x = event.x - t.x0
      t.y = event.y - t.y0
    elseif("ended" == phase or "cancelled" == phase) then
      display.getCurrentStage():setFocus(nil)
      t.isFocus = false
    end
  end
  return true
end

-- make 'myObject' listen for touch events
myObject:addEventListener( "touch", myObject )
オブジェクトに対する操作(イベント)が終わるまでフォーカスが外れないようになっています。
これで指をグリグリ動かしてもオブジェクトが追従してくれるようになりました。

せっかくタッチパネル向けにアプリをつくるなら、ボタンをタップするだけじゃなくて、指で操作させたい(したい)ですよね。