見出し画像

【0067】アイテム画面を作る⑦

アイテムの最大所持数考えてなかったんですよね。

画像1

※エラーアイテム、の表記はわざと出してるものなので正常系エラーです。

一応このまま使うのであれば縦に16個並ぶようですが
そもそもアイテムっていくつ持てればいいんでしょうか。

「トルネコの不思議なダンジョンは20」

という情報をwebで見つけました。
今更どうでもいい情報なので
不思議のダンジョン系のアイテム所持数についての言及は少ないです。
チョコボのみアイテム所持数が増えるため書かれていることがありました。

まあ少なくとも16じゃたらんということですよね。
一応上部には機能こそしていませんがページを意識する表記があります。

とはいえ、2ページあれば十分でしょうか。
あんまり少ないとつまんないですし、多いと簡単になってしまいます。

どちらにせよページめくりは必要ということでしょうか。

……ってその前に、そもそもカーソル移動がまだ作れていません。
今は一番上に「>」がおいてありますけど固定出力しているだけで動かすことも出来ません。

メニュー画面と同じ感じで動かせるようにしていきます。

: 'アイテムカーソル移動' && {
	##################################################
	##movItemCsr
	## アイテム画面のカーソルを移動する
	##   $1:方向指示。8=上、2=下
	##################################################
	function movItemCsr(){
		declare dir="$1"

	 #現在のカーソル位置から >マークを消去
		lnSeed[$((selCrsrID+2))]=${lnSeed[$((selCrsrID+2))]:0:2}' '${lnSeed[$((selCrsrID+2))]:3}

		case $dir in
		 #上移動 
			$CNST_CSR_MVTO_UP)
			 #現在の持ち物番号 (カーソル位置)が1の場合は、一番下の行(持ち物番号15)に>マークを表示する
				if [ $selCrsrID -eq 1 ] ; then
					lnSeed[18]=${lnSeed[18]:0:2}'>'${lnSeed[18]:3}
					selCrsrID=16

				else
			 #1じゃなければ 、普通通り持ち物番号を1つデクリメントして>を表示する
					selCrsrID=$((selCrsrID-1))
					lnSeed[$((selCrsrID+2))]=${lnSeed[$((selCrsrID+2))]:0:2}'>'${lnSeed[$((selCrsrID+2))]:3}
				fi;;
		 #下移動 
			$CNST_CSR_MVTO_DN)
			 #現在の持ち物番号 (カーソル位置)が一番下(持ち物番号15)の場合は、一番上の行に>マークを表示する
				if [ $selCrsrID -eq 16 ] ; then
					lnSeed[3]=${lnSeed[3]:0:2}'>'${lnSeed[3]:3}
					selCrsrID=1

				else
			 #18じゃなければ 、普通通りに持ち物番号を1つインクリメントして>を表示する
					selCrsrID=$((selCrsrID+1))
					lnSeed[$((selCrsrID+2))]=${lnSeed[$((selCrsrID+2))]:0:2}'>'${lnSeed[$((selCrsrID+2))]:3}
				fi;;

		 #エラー 
			*) 	dspCmdLog "[MenuCsrMvERR]dir:$dir/no:$selCrsrID";;
		esac
		}
	}

メニュー画面での実装とほぼ同じです。
違うのは「>」を置く座標くらいでしょうか。

やってることは
・今のカーソル位置を保存しておき
・「W」もしくは「X」に反応する1文字コマンドを用意し
・それが押されたらカーソル行の3文字目だけ空白にしてカーソルを消し
・移動先の3文字目だけを「>」に変更する
・もし一番上でもう一度上に移動する操作だったら一番下に移動する
・もし一番下でもう一度下に移動する操作だったら一番上に移動する
という感じです。

このコマンド入力を有効にするために、
アイテム画面が表示中はコマンド体系を切り替えます。

###########################################
##getCmdInMain
## mainLoopから呼び出される任意長コマンド受付
## 各種コマンド割り振りと制御
##  $1:メニュー内コマンド選択で呼び出された場合の引数
###########################################
function getCmdInMain(){

	case "$cmdMode" in

	 #通常時は続けてコマンドを取得し 、各種コマンドを起動する
		##通常時はコマンド数が多いためdispallコマンドは各ケースごとに記述する。
		##コマンドによって引数を変えるため。
		$CNST_CMDMODE_NRML0	)<<<<<<<<<<<<<<普段のコマンド体系
			inKey2="$inKey"
			printf "$inKey2"
			getChrV

			inKey="$inKey2$inKey"
			case "$inKey" in
				'ma can')	ma can;;
				*'can'	)	dspCmdLog 'OK、キャンセルしたよ:)'
							dispAll $CNST_YN_Y;;
				'te'	)	te;;
				'??'	)	viewHelp;; 
				'man '*	)	ma "${inKey:4}";;
				'mv '*	)	mv "${inKey:3}";;
				'op '*	)	op "${inKey:3}";;
				'cl '*	)	cl "${inKey:3}";;
				'da '*	)	da "${inKey:3}";;
				'pk '*	)	pk;;
				'qq'	)	da 7;;
				'ww'	)	da 8;;
				'ee'	)	da 9;;
				'aa'	)	da 4;;
				'dd'	)	da 6;;
				'zz'	)	da 1;;
				'xx'	)	da 2;;
				'cc'	)	da 3;;
				'mn'	)	mn;;
				'it'	)	it;;<<<<<<<<<<<<<<<アイテム画面開くコマンド
……略……
				''		)	dspCmdLog '入力してください。'
							dispAll $CNST_YN_Y;;
				*		)	dspCmdLog "[${inKey// /}...]は無効、または引数が必要です"
							dispAll $CNST_YN_Y;;
			esac
			;;
……略……
	 #アイテム表示時 <<<<<<<<<<<<<<<<アイテム画面表示中のコマンド体系
		$CNST_CMDMODE_ITEM1	)
			inKey2="$inKey"
			printf "$inKey2"
			getChrV
			inKey="${inKey2}${inKey}"

			case "$inKey" in
				'ma can')	ma can;;
				*'can'	)	dspCmdLog 'OK、キャンセルしたよ:)';;
				'man '*	)	ma "${inKey:4}";;
				'??'	)	viewHelp;;
				'ci'	)	ci;;
				'qqq'	)	quitGame;;
				*		)	dspCmdLog "[${inKey:0:2}...]は無効または引数が必要です。";;
			esac
			;;
	esac
}

アイテム画面を開くには通常時に「it」と入力しているわけですが
アイテム画面表示時に受け付けるコマンドを別の体系にするために上のようにしています。
ただ、アイテム画面表示時でも、再び1文字コマンドを先に受け付けるため、下の処理を通過します。

###########################################
##mainLoop
## 主処理の基幹
## 移動とコマンド呼び出しを反復し続ける。
###########################################
mainLoop(){
	jmpPosWrgl 20 6
	dspCmdLog 'リグルくん爆誕!!'
	dispAll $CNST_YN_Y
	while :
	do
		tput cup $CNST_POS_CMDWIN
		getChrH
	 #移動入力として1文字受け付ける 。移動を指示しない入力だった場合
	 #任意長のコマンド受付にリダイレクトされる
		case "$cmdMode" in
		 #通常時はmvコマンドのショートカットが有効 
		 #画面更新はmvコマンド内で行われている
			$CNST_CMDMODE_NRML0	)
				case "$inKey" in
					[1Z]	)	mv 1;;
					[2X]	)	mv 2;;
					[3C]	)	mv 3;;
					[4A]	)	mv 4;;
					[5S]	)	mv 5;;
					[6D]	)	mv 6;;
					[7Q]	)	mv 7;;
					[8W]	)	mv 8;;
					[9E]	)	mv 9;;
					''		)	dspCmdLog '入力してください。'
								dispAll $CNST_YN_Y;;
					*		)	getCmdInMain;;
				esac
				;;
……略……
			$CNST_CMDMODE_ITEM1	)<<<<<<<<<<<<<<<<<<アイテム画面表示中の1文字コマンド
			 #アイテム表示時はショートカットが無効化され 
			 #アイテム表示時特有の操作系になる 
				##画面更新は自キャラカーソルを更新しない。
				case "$inKey" in
					''		)	dspCmdLog "アイテムを使用する?"
								;;
					[2X]	)	movItemCsr $CNST_CSR_MVTO_DN
								dispAll $CNST_YN_N;;
					[8W]	)	movItemCsr $CNST_CSR_MVTO_UP
								dispAll $CNST_YN_N;;
					[46AD]	)	movItemPge
								dispAll $CNST_YN_N;;
					*		)	getCmdInMain;;
				esac
				;;
		esac
		clrCmdLog
	done
	}
}

これらの1文字コマンドに該当しなかった場合に、
最初に上げたコマンド受付に到達します。

メニュー画面のカーソル移動と同じように、ここでも
[2X]、[8W]を受け付けると
先に作った上下に動かすための関数を呼び出します。

で、[46AD]つまり横を押すとページ切り替えの関数を呼ぶようにします。
2ページしか作るつもりがないので、
加算減算はせず、「今表示されていない方」を表示する感じなので
[4A]と[6D]を分離していません。

ここまではメニュー画面でやったことの改造だけなので
特に語ることはありません(その割に作るのには時間がかかったけど)

動かしてみましょう。

画像2

動きました。

さて、ページめくりの実装です。

表示中のページを確保するグローバル値を設けます。
これはメニュー画面のときに使ったカーソル値と一緒の扱いなので
同じあたりに並べときます。
カーソル値はアイテム画面でも使っています。

##ページID<<<<<<<<<<<<<<<<<追加
declare -g selPageID=''<<<<<<<<<<<<<<<<<追加

##カーソルID
declare -g selCrsrID=''

さて、とりあえずページの概念を導入するので、
アイテム画面を開く「it」コマンド呼び出し時にも
ページを1とするように追記します。

: 'itコマンド' && {
	###########################################
	##it
	## アイテムを開く
	##  引数なし
	###########################################
	function it(){

	 #コマンド体系をアイテム表示時に変更 
		cmdMode=$CNST_CMDMODE_ITEM1
	 #退避 
		escLnSeed
	 #カーソル位置は1ページ目1番 <<<<<<<<<<これ
		selPageID=1<<<<<<<<<<<<<これ
		selCrsrID=1<<<<<<<<<<これ
	 #lnseed上書き 
		joinFrameOnItem
	 #更新_自キャラカーソルは描写しない 
		dispAll $CNST_YN_N
	}
	}

前まではカーソル位置を1にするのも
アイテム表示レイヤー結合関数の中でやっていましたが
こっちに出してしまいます。

さて、呼び出される「movItemPge」関数を作っていきます。

: 'アイテムページ切り替え' && {
	##################################################
	##movItemPge
	## アイテム画面のページを切り替える
	##   引数なし
	##################################################
	function movItemPge(){
		if [ $selPageID = 1 ] ; then
			selPageID=2
		else
			selPageID=1
		fi
		joinFrameOnItem
	}
	}

はい。

「selPageID」変数を、
・1ページ目だったら2に
・そうじゃなかったら(つまり2だったら)1に
・してから、アイテム画面を再表示する(joinFrameOnItemを呼び出す)
だけです。

ページ切り替えの本丸は結局「joinFrameOnItem」でした。

ページ切り替えの実装に際して大幅に改修が入りました。

: 'アイテムレイヤー結合' && {
	##################################################
	## joinFrameOnItem
	##  画面フレームと、アイテム表示枠を結合する
	##   lnSeedのマップ枠の中にlnItemInfoをはめ込む。
	##   また、所持アイテムの情報をはめ込んでいく。		
	##################################################
	function joinFrameOnItem (){
		
		declare spCnt1=0 #アイテム名称の後の半角相当SP数 
		declare spCnt2=0 #アイテム説明の後の半角相当SP数 
		declare maxItemLine=0
		declare itemName=''
		declare itemExplain=''

	 #現在の表示内容を退避し 、アイテム枠を表示する。
		##アイテム枠で上書き
		for ((i = 0; i <= 19; i++)) {
			lnSeed[i]="${lnItemInfo[i]}"
		}

	 #テスト持ち物リスト 
		psnItemList=(9001 9002 9003 9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 9019 9020 9021)
		
	 #ページ数表示のはめ込み 
		lnSeed[1]="${lnSeed[1]:0:9}$selPageID${lnSeed[1]:10}"

	 #アイテム所持数とページ数で
	 #アイテム情報上書きの反復数が異なるため
	 #その回数を取得する 
		if [ ${#psnItemList[*]} -gt 16 ] ; then #アイテムが16個以上手持ちにある場合 
			if [ $selPageID = 1 ] ; then        #1ページめであれば16個全て表示対象 
				maxItemLine=16
			else
				maxItemLine=$(( ${#psnItemList[*]} - 16 ))  #2ページ目なら所持数から16を引いたものがそのページでの反復数 
			fi
		else                                    #アイテムが15個以下のとき 
			if [ $selPageID = 1 ] ; then        #1ページめであればアイテムの所持数分のみ反復すれば良い 
				maxItemLine=${#psnItemList[*]}
			else                                #2ページ目はアイテムの表示がないはずなので0 
				maxItemLine=0
			fi
		fi

	 #上記で設定した反復数だけ 、アイテム情報のはめ込みを行う
		for ((i=0; i<$maxItemLine; i++)) {
		 #アイテム情報取得関数 
			itemID=${psnItemList[$(( i + ( 16 * ($selPageID-1) ) ))]}   #ページ数に応じた持ち物番号を対象とする 
			itemName="$(getItemDisp 0 $itemID)"
			itemExplain="$(getItemDisp 1 $itemID)"

			spCnt1=$(( (24-(${#itemName}))*2 ))
			spCnt2=$(( (23-${#itemExplain})*2 ))
			
			eval 'lnSeed[i+3]="${lnSeed[i+3]:0:4}$itemName`printf %${spCnt1}s`|$itemExplain`printf %${spCnt2}s`|`printf "%2s" '$((i+1))'`|"'
		}

	 #カーソル設置 
		lnSeed[3]="${lnSeed[3]:0:2}>${lnSeed[3]:3}"

		}
	}

あとこれの確認のためにテスト用の持ち物リストが変わっています。
アイテムID9001〜9021のテストアイテムを実装します。

: 'アイテムテーブル' && {
 #暫定 
	##アイテムテーブルはn個の半角スペースで区切られた要素で構成される。
	##各要素に半角スペースを含めることはできない(区切れてしまうので)。
	##あくまでも暫定なのでもうちょっとちゃんとした形に変わるかも。
	###アイテムIDは0000~FFFFとする。
	
	declare -g -a TBL_ITM_INFO=()
							#   0    1   2   3                      4                    5
							#   ID   CAT CRR 修飾_全角11文字        名称_全角10文字      説明_全角23文字 #TBL_ITM_INFO +=('FFFF CSM +00 12345678901 1234567890 12345678901234567890123')
 TBL_ITM_INFO+=('0000 CSM 000 nomod                  八卦炉               激しくマーライオンする'                      )
	TBL_ITM_INFO+=('0001 CSM 000 永遠亭謹製の           おくすり             あなたはもう死ねなくなる'                    )
	TBL_ITM_INFO+=('0002 CSM +02 紅魔館メイド手製の     毒弁当               瀟洒!'                                      )
	TBL_ITM_INFO+=('0003 CSM +01 魔法の森でとれた       キノコ               エッチな形をしている+1'                    )
	TBL_ITM_INFO+=('0004 CSM +02 魔法の森でとれた       キノコ               エッチな形をしている+2'                    )
	TBL_ITM_INFO+=('0005 CSM +03 nomod                  キノコ               エッチな形をしている+3'                    )
	TBL_ITM_INFO+=('0006 CSM +04 魔法の森でとれた       キノコ               エッチな形をしている+4'                    )
	TBL_ITM_INFO+=('0007 CSM -10 アロマ臭のする         陰陽玉               いいにおいがする。霊夢愛用。'                )
	TBL_ITM_INFO+=('0008 CSM 000 七色に光る             壊れた人形           血がついている'                              )
	TBL_ITM_INFO+=('0009 CSM 000 nomod                  宝塔                 おでん'                                      )

	TBL_ITM_INFO+=('9001 CSM +01 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9002 CSM +02 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9003 CSM +03 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9004 CSM +04 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9005 CSM +05 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9006 CSM +06 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9007 CSM +07 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9008 CSM +08 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9009 CSM +09 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9010 CSM +10 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9011 CSM +11 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9012 CSM +12 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9013 CSM +13 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9014 CSM +14 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9015 CSM +15 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9016 CSM +16 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9017 CSM +17 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9018 CSM +18 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9019 CSM +19 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9020 CSM +20 nomod                  宝塔                 おでん'                                      )
	TBL_ITM_INFO+=('9021 CSM +21 nomod                  宝塔                 おでん'                                      )

 #エラーアイテム 
TBL_ITM_INFO_ERR=('ZZZZ ERR ERR エラーアイテム       ID:ZZZZ     ID:ZZZZのアイテムは存在しません')

……雑か。
テストアイテムだからいいの。

一気に書いてきましたが、
メニュー画面の拡張的改造追加似すぎない割に
かなり大変でした。

いざ、動かしてみましょう。

画像3

(……ん?)

画像4

ああ。はい。とりあえず1ページ目はうまくいってますね。
「D」を入力してみます。

……んん……

画像5

はい、表示自体は、うまくいってるっぽいですね。

ただですね

くっそ重い!!

アイテム表示の度にこんなに待たされてたら
間違いなくイライラする。

思い当たるフシはあります。

アイテム画面の表示する際に、
「アイテムID」と「アイテムマスタの要素番号」を分離するために
アイテムIDでアイテムマスタを検索するときに
全件舐めて文字列でマッチするようにしたからに違いありません。

やっぱりおもかった。

とはいえ、
論理的なIDであるアイテムIDと、
コーディング上の都合で決まるアイテムマスタの要素番号を
一致させて作っていくのはあまりにも都合が悪い。

やはり持ち物リストは
アイテムIDだけではなくすべての情報を保持するようにすべきでしょうか。

性能問題については、
このゲームを起動するデバイスの標準的な性能
つまり、巷に存在するLinux環境の相場、
がわからないので断言できませんが

開発機であるchromebook上でLinuxを動かすcrostiniでは
「コーディングミスって無限ループさせちゃったか?」
と思うほどの重さです。

試しに、
このコードを自宅のwindows機のWSLとして
Debianをいれて動かしてみたのですが
やはり重かったです(WSL2は試していません)。

android上のLinuxエミュレータであるtermuxで実行しても重かったです。

Azure上に作ったDebian仮想機で実行した場合は
許容範囲かなという動きでした。

やはりOS上に別OS動かすのは、仮想化にせよコンテナにせよ重いのだなと痛感します。
ネイティブなLinux機を使えるAzureではリモート上なのに良好なレスポンスであったのは意外でしたが、そういうことなのでしょう。
(Azure上に作ったDebian機は、
 MSが用意している最低最弱のプランのマシン構成なのに…)

この性能問題については一旦指しおきます。
解決方法としては上記の通り持ち物リストを非正規化して
アイテムIDだけでなく全情報を格納するようにすることと考えています。

今日ところはこれで終わり。

この記事が気に入ったらサポートをしてみませんか?