こんな画像ぶっぱして何が楽しいの


※ソースの通り、1つ1つが一定速度で回転しつつ、微振動してます。
※自機がうにょうにょになりました


stage1.lua

module("stage1", package.seeall)

local function test_func(self)
	-- self.imgindex = 2
	while true do
		--local vel = vector2.new(math.random() - 0.5, math.random() - 0.5)
		--vector2.add(self.pos, vel)
		self.pos[1] = self.pos[1] + math.random() - 0.5;
		self.pos[2] = self.pos[2] + math.random() - 0.5;
		self.rot = self.rot + 0.1
		coroutine.yield(true)
	end
end

function advance(add_enemy)
	for i = 1, 1000 do
		if i % 100 == 0 then
			trace("Frame", i)
		end
		local pos = vector2.new(math.random() * 640, math.random() * 480)
		add_enemy("ball", pos, test_func)
		coroutine.yield(true)
	end
	return false
end

ステージファイルはadvance()関数をエクスポートします。とりあえず敵を出現させる関数だけ渡してみました。他にはボス戦セットとか背景スクロールくらいだからテーブルにまとめなくていいかな、と(どうなっても知らんぞ…)。引数は画像リストの識別文字列・座標・行動コルーチンです。コルーチン中ではEnemyクラスのインスタンスがselfとして渡され、pos(座標)・rot(回転角)・imgindex(画像リスト中のインデックス)などを変更します。
というわけでコルーチンに手を出してみました。コルーチンとは中断可能な関数で、resume(再開)するとyield(中断)するまで実行し、その後再びresumeすると前回yieldしたところから実行されます。というかステージだとか敵や弾の動きだとかを関数内に直列に書けるため、ほとんどこれだけのためにLuaを使ってます。

for i = 1, 60 do
  x = x - 1
  coroutine.yield()
end

60フレーム左へ動く、などというコードをこのように書けて非常に便利です。

Frame500
FPS: 60.164730072021
FPS: 60.003959655762
Frame600
FPS: 60.004322052002
Frame700
FPS: 59.784656524658
FPS: 60.215148925781
Frame800
FPS: 58.407234191895
FPS: 54.427101135254
Frame900
FPS: 51.038070678711
Frame1000
FPS: 47.070858001709

1Fに1つずつ追加しているので700〜800個あたりで速度低下が来ていますね。画像サイズを1/2(面積1/4)にしてもあまり変わらず、コメントアウトで書きなおされているガーベジコレクション対策である程度処理落ちラインが移動したのでLua実行のCPU負荷の方に強く来るみたいです。まあ仮に弾幕を作りたいならこういうホットスポット*1C/C++に移した方がいいと思います。そういうことが比較的楽に行えるのもLuaの利点だと思います。ちなみにこのゲームは弾幕シューティングではなく世紀末シューティングアクションゲームらしいので100〜300発もあれば十分なんじゃないでしょうか。

*1:一番きついところ。JavaVM用語?それとも一般用語?