gl5_progのメモ

自分のためのメモとかまとめとか

コルーチン未使用のコードをコルーチン使用するように書き換えてみた。

コルーチン未使用
http://ideone.com/JeeKuQ

コルーチン使用
http://ideone.com/qo9ujQ

ちなみにこのコードはLoveの勉強をかねて作っている自分用の英語勉強ゲームです。公開予定はありませんよー。
ゲーム内容を簡単に説明すると、

問題選択画面で問題を選び…

f:id:gl5_prog:20121023215701p:plain

表示された日本語の英訳文をキーボードで入力するゲームです。

f:id:gl5_prog:20121023215729p:plain

この本の内容をゲームにして楽に学習しようという魂胆で作ってます。 自分用なんですごく適当な出来です。

まぁゲームの中身はどうでもいいです。
今回の趣旨はコルーチンを使わない場合と使った場合のコードの比較です。

シーケンスが分かりやすくなる

コルーチンを使用することでゲームのシーケンスが分かりやすくなったと思います。

	function Game:CoMain()
		-- 初期化
		self.Font = love.graphics.newFont( 'RictyDiscord-Regular.ttf', 20 )
		love.graphics.setFont( self.Font )
		self.EnglishDataLst = {}
		for i=1, #EnglishData_SyunkanEisakubun do
			self.EnglishDataLst[i] = EnglishData.new( EnglishData_SyunkanEisakubun[i] )
		end

		self:CoYield()

		while true do
			-- モードセレクト画面
			local selectIndex, is_shuffle = self:CoModeSelect()
		
			-- 項目出現順番を決定
			local ItemOrder            = GenerateTableOrder( self.EnglishDataLst[selectIndex]:GetItemCount(), is_shuffle )
			local CurrentItemIndex     = 1

			-- 問題回答ループ
			while true do
				local CurrentItemIndexRaw  = ItemOrder[CurrentItemIndex]
				local japaneseString       = self.EnglishDataLst[selectIndex]:GetItemTextJapanese( CurrentItemIndexRaw )
				local englishString        = self.EnglishDataLst[selectIndex]:GetItemTextEnglish ( CurrentItemIndexRaw )
				local result = self:CoInputAnswer( japaneseString, englishString )
				if result == 'Next' then
					-- 次の問題へ
					CurrentItemIndex = CurrentItemIndex + 1

					-- 終了チェック
					if CurrentItemIndex > self.EnglishDataLst[selectIndex]:GetItemCount() then
						break
					end
				elseif result == 'Escape' then
					-- 中止
					break
				end
			end

		end
	end

上から順に眺めるだけでシーケンスがわかります。わかってください。 間に演出を挟むといったシーケンスの追加もたぶん楽に行えるでしょう。

メンバ変数が減る

コルーチン未使用

function Game:init()
	self.State                = Game.State.GameReady
	self.StateBeginTime       = love.timer.getTime()
	self.ThisFrameInputString = ''
	self.CurrentItemIndex     = 0
	self.CurrentItemIndexRaw  = 0
	self.CurrentGroupIndex    = 1
	self.Ready_CursorPos      = 1
	self.Ready_IsShuffle      = false
	self.ItemOrder            = {}
	-- self.Font
	-- self.EnglishDataLst
end

コルーチン使用

function Game:init()
	-- self.Font
	-- self.EnglishDataLst
	-- self.LastResumeParam
	-- self.Coroutine
end

※コメントアウトされてるものはinit関数外で設定されるメンバ変数です。

状態ごとのコードが1箇所にまとまる

例えば、問題選択画面のコードはfunction Game:CoModeSelect()関数内にすべて収まってます。( ちょっとUtil関数が外にあるけど )
ただ、コルーチン未使用の場合でも書き方を工夫すればコードはまとまります。

まとめ

今回書いてみた感じ、コルーチンはとても良いように思えます。
ただ規模が大きくなった場合どうなるのかは未知数です。 簡潔に書くことはできるのか、余計に複雑にならないか、処理コストが…など。

またコルーチンを使用する場合と使用しない場合ではコードの書き方が大きく変わってくることがわかりました。 コルーチンを使用したい場合はコルーチンを意識してコードを書きましょう。 たぶん普通に書いたら状態変数を使用した書き方になってしまうと思います。