2022/11/04(金) [n年前の日記]
#1 [tic80][ruby] TIC-80用スクリプトをRubyで書いてみる
TIC-80 は、元々Lua言語でプログラムを書いて動かすことを前提にしているけれど。TIC-80 1.0.2164 では、Ruby (mruby) を使って書くこともできるらしい。なんだかちょっと興味が湧いたので、そのあたりを試してみた。
環境は、Windows10 x64 21H2 + TIC-80 1.0.2164。
環境は、Windows10 x64 21H2 + TIC-80 1.0.2164。
◎ Hello World を眺める。 :
TIC-80 1.0 で、Ruby を使った Hello World 相当を新規作成するには、TIC-80のコンソールで以下を打つ。
F1キーを押すと、スクリプトソースが見れる。引用してみる。
Lua版の Hello World 相当も引用してみる。ちなみにLua版の場合は、「new lua」で新規作成できる。
見比べると、言語仕様の違いが少し分かるかなと。また、他の違いについても、ちょっとだけ調べてみた。
それと、TIC-80 の場合、最初のほうのコメント行に、スクリプトが何の言語で書かれているのか記述しておいたほうが良いのかもしれないなと…。
new ruby
F1キーを押すと、スクリプトソースが見れる。引用してみる。
# title: game title # author: game developer, email, etc. # desc: short description # site: website link # license: MIT License (change this to your license of choice) # version: 0.1 # script: ruby $t=0 $x=96 $y=24 def TIC $y-=1 if btn 0 $y+=1 if btn 1 $x-=1 if btn 2 $x+=1 if btn 3 cls 13 spr 1+(($t%60)/30|0)*2,$x,$y,14,3,0,0,2,2 print "HELLO WORLD!",84,84 $t+=1 end
Lua版の Hello World 相当も引用してみる。ちなみにLua版の場合は、「new lua」で新規作成できる。
-- title: game title
-- author: game developer, email, etc.
-- desc: short description
-- site: website link
-- license: MIT License (change this to your license of choice)
-- version: 0.1
-- script: lua
t=0
x=96
y=24
function TIC()
if btn(0) then y=y-1 end
if btn(1) then y=y+1 end
if btn(2) then x=x-1 end
if btn(3) then x=x+1 end
cls(13)
spr(1+t%60//30*2,x,y,14,3,0,0,2,2)
print("HELLO WORLD!",84,84)
t=t+1
end
見比べると、言語仕様の違いが少し分かるかなと。また、他の違いについても、ちょっとだけ調べてみた。
| 言語仕様 | Ruby | Lua |
|---|---|---|
| コメント文 | 「#」から始まる | 「--」から始まる |
| グルーバル変数 | $x | x |
| ローカル変数 | x | local x |
| 関数定義 | def hoge 〜 end | function hoge() 〜 end |
| 関数呼び出し | hoge 0, 0, 0 | hoge(0, 0, 0) |
| if文 | if x == 0 then 〜 end | if x == 0 then 〜 end |
| if文(1行タイプ) | $y -= 1 if btn 0 | if btn(0) then y = y - 1 end |
| インクリメント | $t += 1 | t = t + 1 |
それと、TIC-80 の場合、最初のほうのコメント行に、スクリプトが何の言語で書かれているのか記述しておいたほうが良いのかもしれないなと…。
# script: ruby
-- script: lua
◎ classを使ってみる。 :
Rubyはオブジェクト指向を意識してる言語なので class も用意されてる。class が無い Lua と比べるとそのあたり楽になりそうなので、試しに使ってみたい。
とりあえず、昔書いた、以下のような動作をするスクリプトをRubyで書き直してみたい。正直この程度の処理ならクラスを使うほどではないのだけど、そこはまあ、無理矢理使ってみるということで…。
Lua版のソースは以下。
_movecircle.lua
使用画像は以下。

_tiles.png
TIC-80 のコンソール上で以下を打てば、タイル画像領域(tiles)にインポートできる。
今度は Ruby(mruby)版を書いてみる。
_movecircleruby.rb
Lua版とRuby(mruby)版を見比べていけば、Ruby風の書き方も分かるかなと。
とりあえず、昔書いた、以下のような動作をするスクリプトをRubyで書き直してみたい。正直この程度の処理ならクラスを使うほどではないのだけど、そこはまあ、無理矢理使ってみるということで…。
Lua版のソースは以下。
_movecircle.lua
-- script: lua
Obj = {}
Obj.new = function(cx, cy, ang, r)
local o = {
id=0, x=0, y=0, t=0,
cx=cx, cy=cy, ang=ang, r=r
}
o.update = function(self,dr)
self.id = 1 + (self.t % 32 // 16)
local rad = math.rad(self.ang)
local r = self.r
self.x = r*math.cos(rad)+self.cx
self.y = r*math.sin(rad)+self.cy
self.ang = self.ang + 1.5
self.r = self.r + dr
self.t = self.t + 1
end
o.draw = function(self)
spr(self.id,self.x-4,self.y-4,0)
end
setmetatable(o, {__index=Obj})
return o
end
scrw, scrh = 240, 136
cx, cy = scrw/2, scrh/2
t=0
-- init objs
objs = {}
n = 24
for i=1,n do
local o = Obj.new(cx, cy, i*360/n, 60)
table.insert(objs, o)
end
-- main loop
function TIC()
local r = 0
if btn(0) then r=-1 end
if btn(1) then r=1 end
-- update
for i, o in ipairs(objs) do
o:update(r)
end
-- draw
cls(0)
for i, o in ipairs(objs) do
o:draw()
end
print("Lua: " .. _VERSION,4,8*1,12)
print("count: " .. t,4,8*2,12)
print(t//60 .. " sec",4,8*3,12)
t=t+1
end
使用画像は以下。

TIC-80 のコンソール上で以下を打てば、タイル画像領域(tiles)にインポートできる。
import tiles tiles.pngその後、F2キーを押せばドットエディタが開くので、画像を読み込めたことが確認できる。
今度は Ruby(mruby)版を書いてみる。
_movecircleruby.rb
# script: ruby
class StarObj
def initialize(cx, cy, ang, r)
@id = 0
@x = 0
@y = 0
@t = 0
@cx = cx
@cy = cy
@ang = ang
@r = r
end
def update(dr)
@id = 1 + (@t % 32).div(16)
rd = @ang * 3.14159 / 180.0
r = @r
@x = r * Math.cos(rd) + @cx
@y = r * Math.sin(rd) + @cy
@ang += 1.5
@r += dr
@t += 1
end
def draw
spr @id, @x-4, @y-4, 0
end
end
$scrw, $scrh = 240, 136
$cx, $cy = $scrw / 2, $scrh / 2
$t = 0
# init objs
$objs = []
n = 24
n.times do |i|
o = StarObj.new($cx, $cy, i*360/n, 60)
$objs.push(o)
end
# main loop
def TIC
r = 0
r -= 1 if btn 0
r += 1 if btn 1
# update
$objs.each {|o| o.update(r)}
# draw
cls 0
$objs.each_with_index {|o,i| o.draw}
print "mruby: #{RUBY_VERSION}",4,8*1,12
print "count: #{$t}",4,8*2,12
print ($t.div(60)).to_s+" sec",4,8*3,12
$t+=1
end
Lua版とRuby(mruby)版を見比べていけば、Ruby風の書き方も分かるかなと。
◎ HTML + JavaScriptでエクスポートしてみる。 :
ブラウザ上でも動作させられるように、HTML + JavaScript でエクスポートしてみる。TIC-80 のコンソール上で以下を打つ。
_movecirclerb.zip というファイルが生成された。解凍すると、中には以下のファイルが入っていた。
これをWebサーバからアクセスできるようにしておけば…。
_movecirclerb/index.html
さて、どうだろう。ブラウザ上でも動くだろうか。手元の環境、Firefox 106.0.4 と Google Chrome 107.0.5304.88 では動いてるけれど…。
上記ページを開いて、動いてることを確認出来たら、ESCキー → F1キーと押すとソースコードが見れるので、本当に Ruby で書かれていることが分かるかと。
Luaで書かないとhtml生成できないのかなと思ってたけど、Ruby(mruby)で書いてもhtml生成できるのだな…。素晴らしい。
実行ファイル1つだけで、Ruby(mruby)を使ってファミコンライクな2Dゲームを作れて、しかもブラウザ上で動かせるように HTML + JavaScript でエクスポートまでできるなんて…。これは Ruby が好きな人にとっても喜ばしい話なのではなかろうか。
export html movecirclerb
_movecirclerb.zip というファイルが生成された。解凍すると、中には以下のファイルが入っていた。
cart.tic index.html tic80.js tic80.wasm
これをWebサーバからアクセスできるようにしておけば…。
_movecirclerb/index.html
さて、どうだろう。ブラウザ上でも動くだろうか。手元の環境、Firefox 106.0.4 と Google Chrome 107.0.5304.88 では動いてるけれど…。
上記ページを開いて、動いてることを確認出来たら、ESCキー → F1キーと押すとソースコードが見れるので、本当に Ruby で書かれていることが分かるかと。
Luaで書かないとhtml生成できないのかなと思ってたけど、Ruby(mruby)で書いてもhtml生成できるのだな…。素晴らしい。
実行ファイル1つだけで、Ruby(mruby)を使ってファミコンライクな2Dゲームを作れて、しかもブラウザ上で動かせるように HTML + JavaScript でエクスポートまでできるなんて…。これは Ruby が好きな人にとっても喜ばしい話なのではなかろうか。
[ ツッコむ ]
以上です。

