クラスを使う 6, 任意のオブジェクトをマウスで動かす

-- 任意のオブジェクトをマウスで動かす。
-- 参考: http://compasstech.com.au/TNS_Authoring/Scripting/script_tut11.html ~ tut14.html


require "color"

W = platform.window:width()
H = platform.window:height()

TrackedObject = nil
TrackOffsetx  = 0
TrackOffsety  = 0

Square = class()
function Square:init(x, y, sideLen, color)
   self.x        = x
   self.y        = y
   self.sideLen  = sideLen
   self.color    = color
   self.selected = false
end
function Square:contains(x, y)
   return isInside(self.x, x, self.x + self.sideLen) and
          isInside(self.y, y, self.y + self.sideLen)
end
function Square:move(dx, dy)
   self.x = median(0, self.x + dx, W - self.sideLen)
   self.y = median(0, self.y + dy, H - self.sideLen)
end
function Square:paint(gc)
   gc:setColorRGB(self.color)
   gc:fillRect(self.x, self.y, self.sideLen, self.sideLen, self.color)
   if self.selected then
      gc:setColorRGB(color.black)
      gc:setPen("thick")
      gc:drawRect(self.x, self.y, self.sideLen, self.sideLen)
   end
end



Objects = {
   Square(10, 80, 50, color.brown),
   Square(70, 80, 50, color.red),
   Square(130, 80, 50, color.orange),
   Square(190, 80, 50, color.yellow),
   Square(250, 80, 50, color.green)
}


function on.mouseDown(x, y)
   for i = 1, #Objects do
      if Objects[i]:contains(x, y) then
         if TrackedObject then
            TrackedObject.selected = false
         end
         TrackedObject = Objects[i]
         TrackedObject.selected = true
         TrackOffsetx = x - TrackedObject.x
         TrackOffsety = y - TrackedObject.y
         table.insert(Objects, table.remove(Objects, i)) -- クリックしたオブジェクトをリストの末尾に持ってくる。一番手前に表示されるようにするため。
         break
      end
   end
platform.window:invalidate()
end
function on.mouseUp()
   if TrackedObject then
      TrackedObject.selected = false
   end
   TrackedObject = nil -- マウスをリリースしたら、注目オブジェクトを空にする。
   platform.window.invalidate()
end
function on.mouseMove(x,y)
   if TrackedObject then
      TrackedObject.x = x - TrackOffsetx -- クリックしたときに取得した「クリック座標と描画始点とのずれ」を差し引いて新たな描画始点に設定する。
      TrackedObject.y = y - TrackOffsety -- クリックしたときに取得した「クリック座標と描画始点とのずれ」を差し引いて新たな描画始点に設定する。
      platform.window:invalidate()
   end   
end
function on.arrowKey(key)
   if TrackedObject then
      if     key == "up"    then TrackedObject:move( 0, -5)
      elseif key == "down"  then TrackedObject:move( 0,  5)
      elseif key == "left"  then TrackedObject:move(-5,  0)
      elseif key == "right" then TrackedObject:move( 5,  0)
      end
   end
end
function on.tabKey()
   if TrackedObject then
      TrackedObject.selected = false
   end
   for i = 1, #Objects do
      if Objects[i] == TrackedObject then
         TrackedObject = Objects[i+1]
         break
      end
   end
   if TrackedObject == nil then
       TrackedObject = Objects[1]
   end
   TrackedObject.selected = true
   platform.window:invalidate()
end
function on.backtabKey()
   if TrackedObject then
      TrackedObject.selected = false
   end
   for i = #Objects, 1, -1 do
      if Objects[i] == TrackedObject then
         TrackedObject = Objects[i-1]
         break
      end
   end
   if TrackedObject == nil then
       TrackedObject = Objects[#Objects]
   end
   TrackedObject.selected = true
   platform.window:invalidate()
end
function on.escapeKey()
   if TrackedObject then
      TrackedObject.selected = false
   end
   TrackedObject = nil
   platform.window:invalidate()
end
function on.paint(gc)
   for i = 1, #Objects do
      Objects[i]:paint(gc)
   end
end



-----------------------
-- general functions --
-----------------------
-- 中央値函数(下限値, 可変値, 上限値)
function median(lowerLimit, x, upperLimit) return math.max(lowerLimit, math.min(x, upperLimit)) end
-- 包含判定函数(下限値, 可変値, 上限値)
function isInside(lowerLimit, x, upperLimit) return lowerLimit <= x and x <= upperLimit end