0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Roblox】メタテーブルを最小構成のクラス風コードで理解する

0
Last updated at Posted at 2026-05-07

メタテーブル(metatable)とは

メタテーブルは、テーブルの動きをカスタマイズするための特別な設定用のテーブルです。
メタテーブルを別のテーブルに紐づけることで、そのテーブルに特殊な振る舞いを追加できます。

👇メタテーブルを使うと、こういったことがカスタマイズできます。

  • 存在しないキーを読んだときにどうするか
  • 値を書き込んだときにどうするか
  • + などの演算子をどう振る舞わせるか
  • 文字列化をどうするか

今回は「存在しないキーを読んだときにどうするか」を設定するメタメソッド「__index」を使ってみます。

最小構成のクラス風コード

:closed_book:PlayerClass(ModuleScript)

ModuleScript で、プレイヤー用のクラス風のコード(テーブル)を用意します。

PlayerClass(ModuleScript)
local PlayerClass = {}
PlayerClass.__index = PlayerClass

function PlayerClass.new(name)
	local self = setmetatable({}, PlayerClass)
	self.Name = name
	self.HP = 100
	return self
end

function PlayerClass:TakeDamage(amount)
	self.HP -= amount
	print(self.Name .. " は " .. amount .. " ダメージを受けた!")
	print("残りHP: " .. self.HP)
end

function PlayerClass:IsDead()
	return self.HP <= 0
end

return PlayerClass

PlayerClass.__index = PlayerClass

  • PlayerClass をメタテーブルとして持つテーブル(例:player)で、指定したキーが見つからなければ、PlayerClass から探す

__index は、 存在しないキーにアクセスしたときにどこを参照するかを決めるメタメソッド です。

メタメソッド
「メソッド」と付きますが、__index = PlayerClass のように、関数のほかにもテーブルを入れることもできます。
「特別なキー」「特殊な振る舞いを決める仕組み」というイメージです。

PlayerClass.new(name)

  • setmetatable({}, PlayerClass) は新しい空のテーブルを作り、 PlayerClass(メタテーブル)を紐づける(⇒ self
  • NameHP のフィールドを設定する
  • PlayerClass をメタテーブルとして持つテーブル self を返す(⇒ return self

つまり、new() は、 PlayerClass をメタテーブルとして持つ新しいテーブルを作って返します。
(オブジェクト指向プログラミング的な見方では、この返ってきた実体を「インスタンス」と呼びます)

PlayerClass:TakeDamage(amount)

  • selfPlayerClass から作られたテーブル)の HP を減らす
  • ダメージ量と、self の残り HP を表示する

PlayerClass:IsDead()

  • self の HP が 0 以下か判定して返す

:green_book:GameScript(Script)

GameScript(Script)
local PlayerClass = require(script.Parent.PlayerClass)

local player = PlayerClass.new("勇者")

print(player.Name .. " の冒険が始まる!")
print("初期HP: " .. player.HP)

player:TakeDamage(30)
player:TakeDamage(50)
player:TakeDamage(30)

if player:IsDead() then
	print(player.Name .. " は倒れた…")
else
	print(player.Name .. " はまだ生きている!")
end

local player = PlayerClass.new("勇者")

  • PlayerClass からプレイヤー用のテーブル player を作る

print(player.Name .. " の冒険が始まる!")
print("初期HP: " .. player.HP)

  • player テーブルの名前と HP を表示する

player:TakeDamage(30)

  • player 自身には TakeDamage がないため、PlayerClassTakeDamage を使って player の HP を削る

PlayerClass:TakeDamage(amount) が実行される理由
player 自身には NameHP はありますが、TakeDamage がありません。
そこで PlayerClass.__index = PlayerClass の設定により、player に存在しないキーは PlayerClass から探されます。
その結果、PlayerClass.TakeDamage を参照します。
そして、: により playerself として渡されて実行されます。

実行結果
勇者 の冒険が始まる!
初期HP: 100
勇者 は 30 ダメージを受けた!
残りHP: 70
勇者 は 50 ダメージを受けた!
残りHP: 20
勇者 は 30 ダメージを受けた!
残りHP: -10
勇者 は倒れた…

player:TakeDamage(30) が実行されるまでの流れ

player:TakeDamage(30) から PlayerClass.TakeDamage が参照され、実行されるまでの流れです。

  1. player:TakeDamage(30) を実行しようとする
  2. まず、 player.TakeDamage を探す。(player 自身のキーから探す)
  3. player.TakeDamage が見つからないので PlayerClass.TakeDamage を探す。(PlayerClass のキーから探す)
  4. PlayerClass.TakeDamage が見つかる。TakeDamage キーには、関数が入っている
  5. : での呼び出しなので、player が第1引数 self として渡される
  6. PlayerClass.TakeDamage(player, 30) のような形で実行される

: でメソッドを定義すると何が起こるか

次のように : を使ってメソッドを定義すると、

function PlayerClass:TakeDamage(amount)
	self.HP -= amount
end

これは次のコードとほぼ同じ意味です。

PlayerClass.TakeDamage = function(self, amount)
	self.HP -= amount
end

つまり、
function PlayerClass:TakeDamage(amount)(メソッド)を定義すると、 PlayerClass テーブルに TakeDamage というキーが作られ、その値には関数が入ります。その関数の第1引数には self が自動で追加されます。

このため、player.TakeDamage を参照したときに関数が見つかり、player:TakeDamage(30) のように実行できるようになっています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?