🐋「なでしこで、トランプゲームを作りたい時があります!(もちろん、ありますよね?)」
😺「はい先生! もちろんです!!」
日本語プログラミング言語「なでしこ」 Advent Calendar 2025 4日目は、クジラ飛行机さまによる『なでしこで絵柄の綺麗なカードゲームを作るには?』でした。
著作権フリー(CC0)の画像を用いて簡単にトランプカードの表示ができるライブラリが紹介されていますので、さっそくお試ししてみましょう。
とりあえずつかう
!「貯蔵庫:playing_card.nako3」を取り込む。
Mハートの1を[0,0]にカード表示。
こんだけで、画面上にハートのエースが表示されました!
直感的にわかりやすく、おそろしく初心者ライクですね✨️
でもですよ。
ゲームを作る際、プログラム中であらかじめどのカードを出すか指定して表示することは稀です。
フツーは一組のトランプからランダムにカードを出していくものでしょう。
シャッフルしたトランプから一枚引く
とゆうわけで、自分で「ハートの1を表示したい!」と思った場合には分かりやすくて簡単便利ですが、シャッフルされたカードをランダムに一枚引いて表示したい場合には?
トランプを作成
トランプのカードを一組作るなら、だいたい通し番号の配列を使うのが普通です。
こちらにトランプの作り方の分かりやすい解説がありますから、ぜひご覧くださいねぇ~。
で、こんな感じ?
0から51までの配列連番作成して、トランプに代入。
トランプを配列シャッフル。
今は、配列連番作成という超便利な命令があります🎶
シャッフルするのも、配列シャッフルというまさにそれ! な命令があります。
絵柄と番号
この状態だとハートのAは26番です。
コレを絵柄と番号にしてやらなきゃなりません。
こんなかんじ?
C=26の絵柄番号取得。
C.絵柄のC.番号を[0,0]にカード表示。
●(Noの)絵柄番号取得
絵柄=No/13を切り捨て。
番号=No%13+1。
{絵柄:絵柄,番号:番号}を戻す。
ここまで。
番号が配列と違い分かりやすいよう1スタートになっているので、+1してやる必要があります。
どうしようかと思いましたが、辞書型で戻すことにしました。
表示して確認しようかとおもったら、配列と違ってJSONエンコードが必要というめんどくささがありますが、使う分にはわかりやすくて間違いない。
自前でカードを表示する命令を作るなら、この部分も入れ込んで、No.だけでしゅっと表示できるようにするところですが……
でででもこれはタブンわざとですよね?
一次元配列を二次元に変換するのは、重要な課題の一つですから?
一枚引いて表示
配列ポップは、配列Aの末尾をいっこ取り出して返す命令です。
Aの内容を書き換える、とあり、取り出した分は配列から消えますので、まさにシャッフルして伏せておいた山札から一枚引いて捨てるといったことができるワケです。
トランプから配列ポップして絵柄番号取得。
それ.絵柄のそれ.番号を[0,0]にカード表示
辞書型で管理する?
うーん、毎回絵柄番号取得するのはめんどくさい。
いっそ、あらかじめ変換しちゃう?
トランプは空配列。
0から51までの配列連番作成して反復:
トランプ[対象キー]は空辞書。
トランプ[対象キー]["絵柄"]=対象/13を切り捨て。
トランプ[対象キー]["番号"]=対象%13+1。
トランプを配列シャッフル。
トランプから配列ポップ。
それ.絵柄のそれ.番号を[0,0]にカード表示。
これで、トランプ配列の中身は、
[{"絵柄":0,"番号":1},{"絵柄":0,"番号":2},...(中略)...{"絵柄":3,"番号":12},{"絵柄":3,"番号":13}]]
ということになりました。
うーん、先の解説記事の逆をいっていますね😅️
でもま、このライブラリのカード表示を使うなら、こっちのが楽そう?
👇️動作確認
毎回違ったカードが表示されるのが確認できます。
カード大きすぎ問題
このライブラリに読み込まれている画像のカードサイズは、
カードW=150
カードH=210
となっています。
貯蔵庫の標準キャンバスに、2枚しか並びませんよ。
このサイズで七並べなんて、デスクトップに表示しきれませんよよよ~💧️
自前でカード表示命令を作るなら、画像部分描画で任意のサイズに縮小して描画することができるのですが、このライブラリのカード表示では、
カードIMGの[XX,YY,カードW,カードH+1]を[XY[0],XY[1],カードW,カードH]へ画像部分描画。
と、等倍決め打ちで描画することになっているんですからどうしょうもない。
オプションとかで表示倍率が変えられるようになっていたりすると助かるような気がしますけれどねぇ~。
でもま、どうせカードを反転させるのに描画変換マトリクス設定したりする予定だから、そこで縮小もできますがね。
でも、コレ系使うとなると途端に初心者ライクじゃなくなりますよね~?
縮小して表示するだけなら、描画拡大だけでできそうですが🤔️
!「貯蔵庫:playing_card.nako3」を取り込む
# キャンバスのサイズを設定
倍率=0.6。
画面幅=1950*倍率。
画面高さ=840*倍率。
描画中キャンバス.幅属性=画面幅。
描画中キャンバス.高さ属性=画面高さ。
F絵柄を0から3まで繰り返す:
F番号を0から12まで繰り返す:
XX=F番号×カードW
YY=F絵柄×カードH
キャンバス状態保存。
# ---
[倍率,倍率]だけ描画拡大。
F絵柄の(F番号+1)を[XX,YY]にカード表示。
# ---
キャンバス状態復元。
あるいは、大きなキャンバスにフツーに描画して、スタイル設定でキャンバスごと縮小表示するとか?🤔️
!「貯蔵庫:playing_card.nako3」を取り込む
# キャンバスのサイズを大きく設定して
画面幅=1950。
画面高さ=840。
描画中キャンバス.幅属性=画面幅。
描画中キャンバス.高さ属性=画面高さ。
# 表示を縮小
描画中キャンバスの「幅」に画面幅*0.6&「px」をDOMスタイル設定。
描画中キャンバスの「高さ」に画面高さ*0.6&「px」をDOMスタイル設定。
F絵柄を0から3まで繰り返す:
F番号を0から12まで繰り返す:
XX=F番号×カードW
YY=F絵柄×カードH
F絵柄の(F番号+1)を[XX,YY]にカード表示。
キャンバスの属性の幅と高さは、キャンバスそのもののサイズを変更しますが、スタイルの幅と高さは表示サイズを変更します。
カードはくるんとめくりたい
ようやく本題。
昨年DOM部品を使ってトランプを作った際には、transformやtransitionのスタイル設定するだけで簡単にめくるアニメーションができました。
キャンバスの場合は?
描画命令の中には描画変換マトリクス追加(transform)などの描画を変化させる命令がありますので、もちろんできるハズです。
設定
とりあえず伏せて置いた一枚のカードをくるんとひっくり返して表向きにします。
元画像を見ると、53と55に当たる位置がカードの裏側、52と54がジョーカーとなっているようです。
表カード=26の絵柄番号取得。# {"絵柄":2,"番号":1}
裏カード=55の絵柄番号取得。# {"絵柄":4,"番号":4}
そして、画面中央にあらかじめ裏カードを表示しておきます。
画面幅=描画中キャンバス.幅属性。
画面高さ=描画中キャンバス.高さ属性。
カードX=(画面幅-カードW)/2。
カードY=(画面高-カードH)/2。
裏カード.絵柄の裏カード.番号を[カードX,カードY]にカード表示。
反転させる
描画変換マトリクス追加の引数[a,b,c,d,e,f]の内容は、[伸縮x, 傾斜y, 傾斜x, 伸縮y, 移動x, 移動y]となっており、角度に応じて「伸縮x」(カード幅)を変化させ、半分までは裏側がだんだん細くなっていき、次に表側がだんだん太くなっていくことでカードがひっくり返るように見せかけます。
これだけでも割とそれっぽく見えるんですが、少し傾斜を与えて奥行きを表現すると良いそうです。
この伸縮の起点がカードの中央になるように、描画の起点をカード幅の半分だけ右にずらして伸縮を行い、実際の描画の前に元に戻します。
角度=0。
●(角度で)カード反転描画
cos=COS((角度をラジアン変換))の絶対値。
sin=SIN((角度をラジアン変換))*0.15。
キャンバス状態保存。
[カードW/2,0]に描画起点設定。
//[cos,0,0,1,カードX,カードY]だけ描画変換マトリクス追加。
[cos,sin,0,1,カードX,カードY]だけ描画変換マトリクス追加。
[-1*カードW/2,0]に描画起点設定。
もし、角度≦90ならば、
[0,0]に裏カード.絵柄の裏カード.番号をカード表示。
違えば、
[0,0]に表カード.絵柄の表カード.番号をカード表示。
ここまで。
キャンバス状態復元。
ここまで
あとは、キャンバスをクリックしたら、角度を0から180まで増やしながら繰り返しカード反転描画するよう画面更新時実行で再帰します。
●カード反転
[0,0,画面幅,画面高さ]に四角描画。
角度=角度+6。
角度でカード反転描画。
もし、角度≧180ならば:
角度=0。戻る。
「カード反転」を画面更新時実行。
ここまで。
描画中キャンバスをクリックした時には、カード反転。。。
できました!
👇動作確認
こちらでは、クリックごとに裏から表、表から裏へとトグルするようにしています。
続くかも知れないし続かないかも知れない
今回は雑にグローバルに角度を用意して、一枚だけひっくり返しましたが、複数のカードを次々ひっくり返したりできるよう、カードそれぞれに角度や状態を持たせたらどうかなあ?
絵柄や番号を辞書型にしたのも実はそのためでした。
でも、そーなると移動のアニメーションもとか、角度の増加量決め打ちじゃなく、画面更新時実行のタイムスタンプを取って、CSSのと同じように何秒かけて変化するか指定できるようにしたい? とかとか、やっぱなんかゲームっぽいもの作りたいとかとかとか、いろいろ考えちゃうけど、そんな時間はにゃいのだ~😹️
しかし、カレンダーが埋まらなくてぴんちだと、雑な感じで続くかも?
