読者です 読者をやめる 読者になる 読者になる

Minecraftとタートルと僕

PCゲームMinecraftのMOD「ComputerCraft」の情報を集めたニッチなブログです。

Luaでオブジェクト指向(2)―ピクセル・四角形・ボタンオブジェクトを作ろう

(2014/02/08、表記法について一部修正しました。)

はじめに

前回は、オブジェクト指向プログラミングの紹介とともに、
座標オブジェクトを作るプログラムを紹介しました。
今回はこれを応用して、以下のオブジェクトを作る関数を作ってみましょう。

  • ピクセル(Pixel)オブジェクト
    • point: 座標
    • bgcolor: そのピクセルの色
    • 【メソッド】draw(): ターミナル画面にこのピクセルを描画
    • 【メソッド】pp(): 座標と色を画面表示(例: (1,1), 8)
  • 四角形(Rectangle)オブジェクト
    • start: 四角形の左上の始点座標
    • goal: 四角形の右下の終点座標
    • bgcolor: 四角形の色
    • 【メソッド】draw(): ターミナル画面にこの四角形を描画
    • 【メソッド】pp(): 座標と色を画面表示(例: (1,1)-(10,10), 8)
  • ボタン(Button)オブジェクト
    • 四角形オブジェクトを継承
    • label: ボタンの中心に表記するラベル
    • 【メソッド】draw(): ターミナル画面に四角形を描画し、中央にラベルを記載
    • 【メソッド】pp(): 座標とラベルと色を画面表示(例: (1,1)-(10,10), down, 8)

前回の座標オブジェクト作成プログラム

前回示したプログラムは以下のとおりです。

Coordinate = {}
Coordinate.pp = function(self) print(string.format("(%d,%d)", self.x, self.y)) end
Coordinate.new = function(_x,_y)
  local obj = {}
  obj.x = _x
  obj.y = _y
  setmetatable(obj,{__index = Coordinate})
  return obj 
end

しかし今後は、僕の好みに合わせて、newメソッドだけ外に出しそれ以外のプロトタイプ変数・メソッドは全てテーブルコンストラクタ「{}」で囲むことにします。
今後は、僕の好みに合わせて、newメソッドを先頭に置き、それ以外のプロトタイプ変数・メソッドはその後に記述することにします。
これはnewメソッド(newコンストラクタ)が要であることを強調するためです。


また、setmetable()関数は返値として第1引数であるテーブルを返すため、次のようにまとめて省略することができます。

--以下の2つをまとめて
  setmetatable(obj,{__index = Coordinate})
  return obj
--次のように記述
  return setmetatable(obj,{__index = Coordinate})


以上の2つの記述法により、今後は次のように書いていきます*1

Coordinate = {}
Coordinate.new = function(_x,_y)
  local obj = {}
  obj.x = _x
  obj.y = _y
  return setmetatable(obj,{__index = Coordinate})
end
Coordinate.pp = function(self) print(string.format("(%d,%d)", self.x, self.y)) end

ピクセル(Pixel)オブジェクトの作成

色のついた1個の点。これがピクセルオブジェクトです。
このオブジェクトのプロパティとして、以下の2つを想定します。
特に座標については前述の座標オブジェクトを利用します。

  • point: 座標オブジェクト
  • bgcolor: そのピクセルの色

また2つのメソッド、特にdraw()については具体的な実装を次回に回します。

  • 【メソッド】draw(): ターミナル画面にこのピクセルを描画
  • 【メソッド】pp(): 座標と色を画面表示(例: (1,1), 8)
Pixel = {}
Pixel.new = function(_x, _y, _color)
  local obj = {}
  obj.point = Coordinate.new(_x, _y)
  obj.bgcolor = _color
  return setmetatable(obj,{__index = Pixel})
end

Pixel.pp = function(self) 
  print(string.format("(%d,%d), %d", self.point.x, self.point.y, self.bgcolor)) 
end

Pixel.draw = function(self, mon)
    -- 省略
end

四角形(Rectangle)オブジェクトの作成

中を一色で塗りつぶした四角形。これを四角形オブジェクトとします。
このオブジェクトのプロパティとして以下の3つを想定します。

  • start: 四角形の左上の始点座標
  • goal: 四角形の右下の終点座標
  • bgcolor: 四角形の色

また2つのメソッド、特にdraw()については具体的な実装を次回に回します。

  • 【メソッド】draw(): ターミナル画面にこのピクセルを描画
  • 【メソッド】pp(): 座標と色を画面表示(例: (1,1)-(10,10), 8)
Rectangle= {}
Rectangle.new = function(_startX, _startY, _goalX, _goalY, _color)
  local obj = {}
  obj.start = Coordinate.new(_startX, _startY)
  obj.goal = Coordinate.new(_goalX, _goalY)
  obj.bgcolor = _color
  return setmetatable(obj,{__index = Rectangle})
end
Rectangle.pp = function(self) 
  print(string.format("(%d,%d)-(%d,%d), %d", self.start.x, self.start.y, self.goal.x, self.goal.y,self.bgcolor)) 
end

Rectangle.draw = function(self,mon)
    -- 省略
end

ボタン(Button)オブジェクトの作成

ボタンオブジェクトは一言で言うと、四角形オブジェクト+ボタンラベルです。
よって、ボタンオブジェクトのプロパティを継承した上で以下のプロパティを1つ用意します。

  • label: ボタンの中心に表記するラベル

メソッドはとりあえず以下の2つを用意します。

  • 【メソッド】draw(): ターミナル画面にこのピクセルを描画
  • 【メソッド】pp(): 座標と色とラベルを画面表示(例: (1,1)-(10,10), 8, down)

メソッドについては、ppは自分で定義しなくてはなりませんが、
draw()については、(1)まず四角形を描画し、(2)中央にラベルを表記という手順を踏むため、
Rectangle.draw()メソッドを組み込むことで楽ができます。

Button = {}
Button.new = function(_startX, _startY, _goalX, _goalY, _label, _color)
  -- Rectangleオブジェクトからプロパティをごっそり参照(つまり、継承)
  local obj = Rectangle.new(_startX, _startY, _goalX, _goalY, _color)
  -- プロパティ「label」は独自に追加
  obj.label = _label
  return setmetatable(obj,{__index = Button})
end

Button.pp = function(self) 
  print(string.format("(%d,%d)-(%d,%d), %s, %d", self.start.x, self.start.y, self.goal.x, self.goal.y, self.label, self.bgcolor)) 
end

Button.draw = function(self,mon)
  -- 四角形描画のためにRectangleのメソッドを参照
  Rectangle.draw(self, mon)

  -- そして中央にラベル描画
  -- 省略
end
}

まとめ

ピクセル、四角形、ボタンオブジェクトを作ることができるようになりました。
メタテーブルを使って、柔軟に他のオブジェクトのメソッドやプロパティを参照するようにしています。
あとは個々のオブジェクトについて、メソッドを充実させなくてはなりません。

まずは、ターミナル画面やモニタにピクセル・四角形・ボタンを描画するdrow()メソッドをそれぞれ作成します。

そのついでに、ターミナル画面やモニタにどのような仕組みで描画していくのかについても説明しましょうね。

それでは。

*1:このコードを最初から提示しても意味不明ですよね。え? すでにもうわからないって? すみません。