電脳麻将 は HTML5 + CSS3 + JavaScript で動作しています。手牌もHTML5とCSS3だけで表示しています。今回は以下の手牌を例に、どのように表示しているか説明します。
手順は以下の流れになります。
牌譜形式 → JavaScript形式 に変換
上記の牌姿を電脳麻将の牌譜でも使用している 文字列表記 で表すと、
"m05z11z2,p5550,s550=5,m12-3"
となります。まずこの文字列をプログラム内部で使用している Majiang.Shoupai
オブジェクトの形式に変換します。
{ // 手牌全体 _bingpai: { // 副露していない部分 m: [1,0,0,0,0,2,0,0,0,0], // 各牌の枚数(萬子) p: [0,0,0,0,0,0,0,0,0,0], // 各牌の枚数(筒子) s: [0,0,0,0,0,0,0,0,0,0], // 各牌の枚数(索子) z: [0,2,1,0,0,0,0,0] // 各牌の枚数(字牌) }, _fulou: [ "p5550", "s550=5", "m12-3" ], // 副露メンツ _zimo: "z2", // ツモ牌 _lizhi: false // リーチフラグ }
詳細は 麻雀の手牌のJavascript表現 - koba::blog で説明しています*1。この変換は以下のプログラムで行うことができます。
let shoupai = Majiang.Shoupai.fromString("m05z11z2,p5550,s550=5,m12-3");
具体的なプログラムは以下の通りです。
JavaScript形式 → HTML に反映
次に、JavaScriptの内部表現をDOMに反映します。
<div class="shoupai"> <!-- 手牌全体 --> <div class="bingpai"> <!-- 副露していない部分 --> <img class="pai" data-pai="m0" src="img/m0.gif"> <!-- 五萬(赤) --> <img class="pai" data-pai="m5" src="img/m5.gif"> <!-- 五萬 --> <img class="pai" data-pai="z1" src="img/z1.gif"> <!-- 東 --> <img class="pai" data-pai="z1" src="img/z1.gif"> <!-- 東 --> <span class="zimo"> <!-- ツモ牌 --> <img class="pai" data-pai="z2" src="img/z2.gif"> <!-- 南 --> </span> </div> <div class="fulou"> <!-- 副露牌全体 --> <span class="mianzi"> <!-- 副露メンツ --> <img class="pai" data-pai="_" src="img/pai.gif"> <!-- (裏向き) --> <img class="pai" data-pai="p5" src="img/p5.gif"> <!-- 五筒 --> <img class="pai" data-pai="p0" src="img/p0.gif"> <!-- 五筒(赤) --> <img class="pai" data-pai="_" src="img/pai.gif"> <!-- (裏向き) --> </span> <span class="mianzi"> <!-- 副露メンツ --> <img class="pai" data-pai="s5" src="img/s5.gif"> <!-- 五索 --> <span class="rotate"> <!-- (横向き) --> <img class="pai" data-pai="s0" src="img/s0.gif"> <!-- 五索(赤) --> <img class="pai" data-pai="s5" src="img/s5.gif"> <!-- 五索 --> </span> <img class="pai" data-pai="s5" src="img/s5.gif"> <!-- 五索 --> </span> <span class="mianzi"> <!-- 副露メンツ --> <span class="rotate"> <!-- (横向き) --> <img class="pai" data-pai="m2" src="img/m2.gif"> <!-- 二萬 --> </span> <img class="pai" data-pai="m1" src="img/m1.gif"> <!-- 一萬 --> <img class="pai" data-pai="m3" src="img/m3.gif"> <!-- 三萬 --> </span> </div> </div>
この処理は以下のプログラムで行うことができます。
new Majiang.View.Shoupai($('.shoupai'), shoupai, true).redraw();
$('.shoupai')
は手牌を配置するDOMノード、shoupai
は先ほど文字列から変換した手牌のJavaScript表現、true
は手牌を表向きに表示する指示です。
具体的なプログラムは以下の通りです。
プログラム中では牌画像のURLを意識していません。HTML中に雛形があり、それを参照しています。牌画像のURLを変更する場合、プログラムの変更は不要でHTMLのみを変更すればよいです。
HTML を CSS で実際に表示されるイメージに調整
上のHTMLのままでは牌が順に並んでいるだけですので、CSSで場所を調整します。キモは CSS3で加槓を表現する - koba::blog で説明した牌の回転です*2。これさえできればあとは簡単で、副露牌を float: right; で右側に配置し、副露メンツはその内側でさらに float: right; で右から順に配置すればよいです*3。
原理はこれでよいのですが、手牌は様々な大きさで様々な場所に表示する必要があります*4。そこで Stylus の Mixin の機能を使って部品化しました。
shoupai-size($width, $height, $bingpai-height, $fulou-height)
各パラメータの意味は以下の通りです。
- $width
- 表示領域の幅
- $height
- 表示領域の高さ
- $bingpai-height
- 手牌(副露していない部分)の高さ
- $fulou-height
- 副露牌の高さ
Mixin はあたかも既存のCSSプロパティのように透過的に使うことができます。
パラメータを調節すれば以下のような表示が可能になります。
shoupai-size: 520px 50px 49px 35px
副露牌をひとまわり小さくし、表示幅は固定サイズとする。これが通常の表示方法。
shoupai-size: auto 70px 49px 49px
表示領域の幅を auto にすると、手牌と副露牌が接近して表示される。和了役の表示の際はこちらの方が見やすい。
shoupai-size: 460px 120px 42px 42px
表示領域の高さが十分にある場合は、副露牌は下段に表示される。スマートフォン画面での下家・上家など表示領域の幅が不十分なときに適した表示方法。