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 が好きな人にとっても喜ばしい話なのではなかろうか。
[ ツッコむ ]
#2 [ruby] mrubyの実行バイナリをビルドしてみた
mruby は実際にどんなAPIを持っているのか今一つ分からないので、ローカルで動作確認しつつ使ってみたいなとそのためには実行バイナリ(.exe)が欲しい。ビルドしてみようかなと。環境は Windows10 x64 21H2。
以下の記事が参考になった。ありがたや。
_Windows上でmrubyをビルドし動かしてみる - Qiita
ビルドには、Visual Studio Community 2015 を使用。ちなみに、Visual Studio Community 2019 も使ってみたけど、そちらはビルドに失敗した。
ビルドに必要なツールは以下。
_Bison for Windows
VS2015 と Ruby 2.6 はインストール済みだったけど、Bison はインストールしてなかったのでインストール。
bison-2.4.1-setup.exe を入手して実行。今回は、D:\Dev\GnuWin32\ にインストールしておいた。インストール場所\bin にパスを通しておく必要があるけれど、addbison.bat を作成して、実行すればパスが通るようにしておいた。
mrubyのソースを入手。
_mruby/mruby: Lightweight Ruby
今回は zip でダウンロードした。D:\home\USERNAME\prg\mruby\mruby\ に置いた。
スタートメニューから、「VS2015 x86 Native Tools Command Prompt」を起動。bison にパスを通しつつ、カレントディレクトリを mruby のソースのある場所にする。
ビルド開始。
ビルドに成功すると、bin というディレクトリが作成されて、中に以下のファイルが入っている。
C:\Ruby\mruby-3.1.0\ というディレクトリを作成して、そこにコピーしておいた。
mruby のバージョンを確認。
その場で実行して動作確認するなら、mirb.exe を実行する。
以下の記事が参考になった。ありがたや。
_Windows上でmrubyをビルドし動かしてみる - Qiita
ビルドには、Visual Studio Community 2015 を使用。ちなみに、Visual Studio Community 2019 も使ってみたけど、そちらはビルドに失敗した。
ビルドに必要なツールは以下。
- Visual Studio 2015 (VS2019はビルドに失敗)
- Ruby 2.6.10p210 i386-mingw32
- bison for Windows 2.4.1
_Bison for Windows
VS2015 と Ruby 2.6 はインストール済みだったけど、Bison はインストールしてなかったのでインストール。
bison-2.4.1-setup.exe を入手して実行。今回は、D:\Dev\GnuWin32\ にインストールしておいた。インストール場所\bin にパスを通しておく必要があるけれど、addbison.bat を作成して、実行すればパスが通るようにしておいた。
set PATH=D:\Dev\GnuWin32\bin;%PATH%
mrubyのソースを入手。
_mruby/mruby: Lightweight Ruby
今回は zip でダウンロードした。D:\home\USERNAME\prg\mruby\mruby\ に置いた。
スタートメニューから、「VS2015 x86 Native Tools Command Prompt」を起動。bison にパスを通しつつ、カレントディレクトリを mruby のソースのある場所にする。
addbison.bat cd /d D:\home\USERNAME\prg\mruby\mruby
ビルド開始。
ruby .\minirake
ビルドに成功すると、bin というディレクトリが作成されて、中に以下のファイルが入っている。
mirb.exe mrbc.exe mruby.exe mruby-config.bat mruby-strip.exe
C:\Ruby\mruby-3.1.0\ というディレクトリを作成して、そこにコピーしておいた。
mruby のバージョンを確認。
> mruby.exe --version mruby 3.1.0 (2022-05-12)
その場で実行して動作確認するなら、mirb.exe を実行する。
> mirb.exe mirb - Embeddable Interactive Ruby Shell > RUBY_VERSION => "3.1" > puts "Hello World" Hello World => nil > exit
[ ツッコむ ]
以上、1 日分です。