クリック画像の実寸表示

段ボール箱を机にした猫 ファイルメーカー(filemaker)のちらしの裏のメモ書き

TOP  >  FileMakerでカードゲームを楽しもう!(2)
作成日:2025年02月17日

FileMakerでカードゲームを楽しもう!(2)

イメージイラスト
にゃん太

どうも、にゃん太です

FileMakerでカードゲームを楽しもう!(1)の続きです

今回は、予定通り「ハイアンドロー」を作っていきましょう


ハイアンドローってどんなゲーム?

まず、ハイアンドローのルールです
地域によって細かい点などは色々違いがある様ですが、ここでは下記の通りとします

こんな所ですね
後はシステム要件として、プレイヤー1人とコンピュータの対戦とする設計とし、またファイルはローカル利用で1対戦が処理できれば良いとしましょう

カードを用意する

では、カード52枚を用意しましょう
まずはカードの管理用に、マークと数字、それからカードの画像が最低限必要となります
あとは、ハイアンドロー用としてカードの大きさやカードの保持者、使用したかどうかの判別するフィールドがあると良いでしょう
以上の事から、下図の様にテーブルを作成します

カード用テーブル構造
カード用テーブルデータ

カードを配る

次に、カード52枚を26枚ずつ配る処理を考えます
単純な処理として、52枚のカードを乱数でソートし、上から26枚をプレイヤー、残りをコンピュータの持ち札とします
後は、ゲームとしてカードを配っているイメージのエフェクトもあった方がそれっぽく見えます
あまり複雑な動きは難しいので、横からスライドさせて山を作る感じとしましょう
横から順番にスライドし、カード山の位置でカードを停止させます
26枚ずつ配るので、それを26枚分実行します
しかし、26枚が単独で動くと時間が掛かりすぎるので、同時に複数枚が移動するイメージとします

カード配布用レイアウト
カード配布用のレイアウトイメージ

カードを配る

# ################################################## # カードを半分ずつランダムに配る # ################################################## ウインドウの固定 レイアウト切り替え [「card」(card); アニメーション: なし] # 過去データの破棄 全レコードを表示 フィールド内容の全置換 [ダイアログあり: オフ; card::holder; ""] フィールド内容の全置換 [ダイアログあり: オフ; card::used; ""] # 1~13のカードを検索 検索モードに切り替え [一時停止: オフ] フィールド設定 [card::cardNo; "1...13"] エラー処理 [オン] 検索実行 [] エラー処理 [オフ] # 乱数を設定 フィールド内容の全置換 [ダイアログあり: オフ; card::holder; Random] # 乱数で並べ替え、上半分をプレイヤー、下半分をコンピューターの持ち札とする レコードのソート [記憶する; ダイアログあり: オフ] フィールド内容の全置換 [ダイアログあり: オフ; card::holder; If (Get ( レコード番号 ) > 26; "c"; "p")] レイアウト切り替え [「カードを配る」(card); アニメーション: なし] # カードを配るエフェクト フィールド設定 [global::key; "back"] 変数を設定 [$$timer; 値: 0] OnTimerスクリプトをインストール [「timer_カードを配る」; 間隔: .01]

timer_カードを配る

# ################################################## # カードを配る処理 # ################################################## 変数を設定 [$$timer; 値: $$timer + 1] 変数を設定 [$step; 値: Mod ( $$timer - 1; 5 ) + 1] If [$step = 1] # 上側のカード処理 フィールド設定 [global::card1[16]; ""] フィールド設定 [global::card1[11]; ""] フィールド設定 [global::card1[6]; ""] フィールド設定 [global::card1[20]; If ( $$timer <= 135; card::cardImage; "" )] フィールド設定 [global::card1[15]; If ( $$timer > 5 and $$timer <= 140; card::cardImage; "" )] フィールド設定 [global::card1[10]; If ( $$timer > 10 and $$timer <= 145; card::cardImage; "" )] フィールド設定 [global::card1[5]; If ( $$timer > 15 and $$timer <= 150; card::cardImage; "" )] # 下側のカード処理 フィールド設定 [global::card2[16]; ""] フィールド設定 [global::card2[11]; ""] フィールド設定 [global::card2[6]; ""] フィールド設定 [global::card2[20]; If ( $$timer <= 135; card::cardImage; "" )] フィールド設定 [global::card2[15]; If ( $$timer > 5 and $$timer <= 140; card::cardImage; "" )] フィールド設定 [global::card2[10]; If ( $$timer > 10 and $$timer <= 145; card::cardImage; "" )] フィールド設定 [global::card2[5]; If ( $$timer > 15 and $$timer <= 150; card::cardImage; "" )] Else If [$step = 2] # 上側のカード処理 フィールド設定 [global::card1[20]; ""] フィールド設定 [global::card1[15]; ""] フィールド設定 [global::card1[10]; ""] フィールド設定 [global::card1[5]; ""] フィールド設定 [global::card1[19]; If ( $$timer <= 135; card::cardImage; "" )] フィールド設定 [global::card1[14]; If ( $$timer > 5 and $$timer <= 140; card::cardImage; "" )] フィールド設定 [global::card1[9]; If ( $$timer > 10 and $$timer <= 145; card::cardImage; "" )] フィールド設定 [global::card1[4]; If ( $$timer > 15 and $$timer <= 150; card::cardImage; "" )] # 下側のカード処理 フィールド設定 [global::card2[20]; ""] フィールド設定 [global::card2[15]; ""] フィールド設定 [global::card2[10]; ""] フィールド設定 [global::card2[5]; ""] フィールド設定 [global::card2[19]; If ( $$timer <= 135; card::cardImage; "" )] フィールド設定 [global::card2[14]; If ( $$timer > 5 and $$timer <= 140; card::cardImage; "" )] フィールド設定 [global::card2[9]; If ( $$timer > 10 and $$timer <= 145; card::cardImage; "" )] フィールド設定 [global::card2[4]; If ( $$timer > 15 and $$timer <= 150; card::cardImage; "" )] Else If [$step = 3] # 上側のカード処理 フィールド設定 [global::card1[19]; ""] フィールド設定 [global::card1[14]; ""] フィールド設定 [global::card1[9]; ""] フィールド設定 [global::card1[4]; ""] フィールド設定 [global::card1[18]; If ( $$timer <= 135; card::cardImage; "" )] フィールド設定 [global::card1[13]; If ( $$timer > 5 and $$timer <= 140; card::cardImage; "" )] フィールド設定 [global::card1[8]; If ( $$timer > 10 and $$timer <= 145; card::cardImage; "" )] フィールド設定 [global::card1[3]; If ( $$timer > 15 and $$timer <= 150; card::cardImage; "" )] # 下側のカード処理 フィールド設定 [global::card2[19]; ""] フィールド設定 [global::card2[14]; ""] フィールド設定 [global::card2[9]; ""] フィールド設定 [global::card2[4]; ""] フィールド設定 [global::card2[18]; If ( $$timer <= 135; card::cardImage; "" )] フィールド設定 [global::card2[13]; If ( $$timer > 5 and $$timer <= 140; card::cardImage; "" )] フィールド設定 [global::card2[8]; If ( $$timer > 10 and $$timer <= 145; card::cardImage; "" )] フィールド設定 [global::card2[3]; If ( $$timer > 15 and $$timer <= 150; card::cardImage; "" )] Else If [$step = 4] # 上側のカード処理 フィールド設定 [global::card1[18]; ""] フィールド設定 [global::card1[13]; ""] フィールド設定 [global::card1[8]; ""] フィールド設定 [global::card1[3]; ""] フィールド設定 [global::card1[17]; If ( $$timer <= 135; card::cardImage; "" )] フィールド設定 [global::card1[12]; If ( $$timer > 5 and $$timer <= 140; card::cardImage; "" )] フィールド設定 [global::card1[7]; If ( $$timer > 10 and $$timer <= 145; card::cardImage; "" )] フィールド設定 [global::card1[2]; If ( $$timer > 15 and $$timer <= 150; card::cardImage; "" )] # 下側のカード処理 フィールド設定 [global::card2[18]; ""] フィールド設定 [global::card2[13]; ""] フィールド設定 [global::card2[8]; ""] フィールド設定 [global::card2[3]; ""] フィールド設定 [global::card2[17]; If ( $$timer <= 135; card::cardImage; "" )] フィールド設定 [global::card2[12]; If ( $$timer > 5 and $$timer <= 140; card::cardImage; "" )] フィールド設定 [global::card2[7]; If ( $$timer > 10 and $$timer <= 145; card::cardImage; "" )] フィールド設定 [global::card2[2]; If ( $$timer > 15 and $$timer <= 150; card::cardImage; "" )] Else If [$step = 5] # 上側のカード処理 フィールド設定 [global::card1[17]; ""] フィールド設定 [global::card1[12]; ""] フィールド設定 [global::card1[7]; ""] フィールド設定 [global::card1[2]; ""] フィールド設定 [global::card1[16]; If ( $$timer <= 135; card::cardImage; "" )] フィールド設定 [global::card1[11]; If ( $$timer > 5 and $$timer <= 140; card::cardImage; "" )] フィールド設定 [global::card1[6]; If ( $$timer > 10 and $$timer <= 145; card::cardImage; "" )] フィールド設定 [global::card1[1]; If ( $$timer > 15 and $$timer <= 150; card::cardImage; "" )] # 下側のカード処理 フィールド設定 [global::card2[17]; ""] フィールド設定 [global::card2[12]; ""] フィールド設定 [global::card2[7]; ""] フィールド設定 [global::card2[2]; ""] フィールド設定 [global::card2[16]; If ( $$timer <= 135; card::cardImage; "" )] フィールド設定 [global::card2[11]; If ( $$timer > 5 and $$timer <= 140; card::cardImage; "" )] フィールド設定 [global::card2[6]; If ( $$timer > 10 and $$timer <= 145; card::cardImage; "" )] フィールド設定 [global::card2[1]; If ( $$timer > 15 and $$timer <= 150; card::cardImage; "" )] End If

以上です
このスクリプトを動かしたイメージが次の動画となります


ちょっと不満もありますが、カードが配られていく感じにはなっているとは思います
カードを配る処理はこれで良しとしましょう

攻守を決める

カードを配ったら、次は初期の攻守を決めます
画面にユーザーのステータスウインドウを配置し、その中に攻守を表示するスペースを用意します
そして、攻守を交互に切り替えながら表示させ、最後に乱数で決めた攻守が表示された状態で停止する様に動かしましょう

攻守決定用レイアウト
攻守決定用のレイアウトイメージ

攻守の決定

# ################################################## # ゲーム開始時はランダムで攻守を決定する # ################################################## # メッセージの表示 フィールド設定 [global::message; "攻守の抽選中..."] # 攻守決定エフェクト 変数を設定 [$$timer; 値: 0] OnTimerスクリプトをインストール [「timer_攻守の決定」; 間隔: .2]

timer_攻守の決定

# ################################################## # 攻守を乱数で決定 # ################################################## 変数を設定 [$$timer; 値: $$timer + 1] # 既定階数を進めたら決定 If [$$timer > 20] OnTimerスクリプトをインストール [] If [Random < .5] フィールド設定 [global::offense_defense; "攻"] フィールド設定 [global::offense_defense[2]; "守"] End If フィールド設定 [global::message; "攻守決定!!¶カード山をタップしてください"] Else If [Mod ( $$timer; 2 )] フィールド設定 [global::offense_defense; "攻"] フィールド設定 [global::offense_defense[2]; "守"] Else フィールド設定 [global::offense_defense; "守"] フィールド設定 [global::offense_defense[2]; "攻"] End If End If

以上となります
簡単な処理ですが、念のため動かして確認してみましょう


想定どおりの動きです
問題なく攻守の割り振りができている様ですね

場にカードを出す

では勝負をする処理の開始です
攻守ともに、手持ちから1枚カードを場に出し、守り手側はカードをめくります
そこまでの処理を作成しましょう
先ほどの攻守を決めるスクリプトの最後のメッセージにも書いた通り、カード山をタップして場にカードを出す処理を開始します
カード山で直接カードをめくってもいけませんので、画面中央側にカードをスライドさせます
そこで攻守を判定し、守り手側のカードをめくって表を見せます
何のカードなのかはこのタイミングで決めればよいでしょう
また、手持ちカードの枚数を減らす処理も必要です

カードを出すレイアウト
場にカードを出す用のレイアウトイメージ

スクリプト

# ################################################## # 場にカードを出す # ################################################## # メッセージを消す フィールド設定 [global::message; ""] ウインドウ内容の再表示 [] # カード残数を減らす フィールド設定 [global::rest; global::rest - 1] # 場にカードを出すエフェクト 変数を設定 [$$timer; 値: 0] OnTimerスクリプトをインストール [「timer_場にカードを出す」; 間隔: .1]

timer_場にカードを出す

# ################################################## # 場にカードを出すエフェクト # ################################################## 変数を設定 [$$timer; 値: $$timer + 1] If [$$timer > 5] # 場に出たカードを表にする(守りのみ) 変数を設定 [$$timer; 値: 0] 変数を設定 [$$target; 値: If ( Exact ( global::offence_defense; "攻" ); "p"; "c" )] OnTimerスクリプトをインストール [「timer_カードをめくる」; 間隔: .1] Else # 場に出す処理 フィールド設定 [global::card3[$$timer - 1]; ""] フィールド設定 [global::card4[$$timer - 1]; ""] フィールド設定 [global::card3[$$timer]; card::cardImage] フィールド設定 [global::card4[$$timer]; card::cardImage] If [$$timer = 1] # 最初の処理 If [global::rest = 0] # 残数がなくなったならカード山を消す フィールド設定 [global::card1; ""] フィールド設定 [global::card2; ""] End If End If End If

timer_カードをめくる

# ################################################## # カードをめくる処理 # ################################################## 変数を設定 [$$timer; 値: $$timer + 1] 変数を設定 [$field; 値: "global::card" & If ( Exact ( $$target; "p" ); "4"; "3" )] If [$$timer = 11] OnTimerスクリプトをインストール [] 変数を設定 [$$timer; 値: ""] フィールド設定 [global::key; "back"] If [$$target = "p"] フィールド設定 [global::message; "考え中……"] 変数を設定 [$$timer; 値: 0] # ここでCOM側の選択処理を呼び出す OnTimerスクリプトをインストール [「timer_com選択」; 間隔: .2] Else # プレイヤーに選択を促す フィールド設定 [global::message; "選択してください"] 変数を設定 [$$status; 値: 4] ウインドウ内容の再表示 [] End If Else If [$$timer > 5] # カードの表側を見せる フィールドを名前で設定 [$field & "[" & 16 - $$timer & "]"; ""] フィールドを名前で設定 [$field & "[" & 15 - $$timer & "]"; card::cardImage] Else If [$$timer = 5] # カードが裏から表に切り替わるタイミングでカードを決定 フィールドを名前で設定 [$field & "[" & $$timer + 4 & "]"; ""] ウインドウの固定 レイアウト切り替え [「card」(card); アニメーション:なし] 検索モードに切り替え [一時停止: オフ] フィールド設定 [card::holder; $$target] フィールド設定 [card::used; "=="] 検索実行 [] 変数を設定 [$count; 値: Get ( 対象レコード数 )] 変数を設定 [$recordNo; 値: Int ( Random * $count ) + 1] レコード/検索条件/ページへ移動 [ダイアログあり:オフ; $recordNo] フィールド設定 [card::used; 1] フィールド設定 [global::key; card::key] # カードの大きさを保持 変数を設定 [$$size1; 値: card;;cardSize] レイアウト切り替え [元のレイアウト; アニメーション:なし] Else フィールドを名前で設定 [$field & "[" & $$timer + 4 & "]"; ""] フィールドを名前で設定 [$field & "[" & $$timer + 5 & "]"; card::cardImage] End If

カードをめくった後、コンピュータ側が攻め手の場合はそのままHighかLowの選択を行う必要がありますが、カードをめくるまでの処理はここまでとなります
やはり、動かして動作を確認してみます


製作時間の割にあっという間に終わる動作ですね
まぁ、短いだけに粗も目立たずいい感じに出来たと思っておきましょう

High or Lowの選択と勝敗判定

それでは最後にHigh or Lowの選択と勝負の結果を判定する処理を作成します
プレイヤー側の処理では選択用のボタンを用意し、引数で選択内容を引渡ます
コンピュータ側は自動判定ですが、単純に中央値より大きいカードならLow、そうでなければHighを選択する様にします

timer_com選択

# ################################################## # コンピュータのHigh or Low選択 # ################################################## 変数を設定 [$$timer; 値: $$timer + 1] # 開かれているカードの大きさで停止タイミングを制御 If [$$timer > 9 + If ( $$size1 > 26; 1; 0 )] スクリプト一時停止/続行 [間隔(秒): .5] 変数を設定 [$$target; 値: "c"] 変数を設定 [$$select; 値: If ( $$size1 > 26; "L"; "H" )] フィールド設定 [global::message; If ( $$size1 > 26; "Low"; "High" ) & "を選択!"] # 結果判定 変数を設定 [$$timer; 値: 0] OnTimerスクリプトをインストール [「timer_結果判定」; 間隔: .1] Else If [Mod ( $$timer; 2 )] # 選択状態の表示制御 変数を設定 [$$status; 値: 6] Else # 選択状態の表示制御 変数を設定 [$$status; 値: 7] End If ウインドウ内容の再表示

プレイヤー選択

# ################################################## # プレイヤーのHigh or Low選択 # ################################################## 変数を設定 [$$select; 値: Get ( スクリプト引数 )] # 結果判定 変数を設定 [$$timer; 値: 0] 変数を設定 [$$target; 値: "p"] OnTimerスクリプトをインストール [「timer_結果判定」; 間隔: .1]

timer_結果判定

# ################################################## # 結果判定 # ################################################## 変数を設定 [$$timer; 値: $$timer + 1] 変数を設定 [$field; 値: "global::card" & If ( Exact ( $$target; "p" ); "4"; "3" )] If [$$timer = 11] OnTimerスクリプトをインストール [] # 開かれたカードの大きさ 変数を設定 [$size2; 値: card::cardSize] # 結果判定 If [$$size1 < $size2 and $$select = "H"] If [$$target = "p"] カスタムダイアログを表示 ["正解しました¶プレイヤーに1ポイント!"] フィールド設定 [global::point[2]; global::point[2] + 1] Else カスタムダイアログを表示 ["正解しました¶コンピュータに1ポイント!"] フィールド設定 [global::point; global::point + 1] End If Else If [$$size1 > $size2 and $$select = "L"] If [$$target = "p"] カスタムダイアログを表示 ["正解しました¶プレイヤーに1ポイント!"] フィールド設定 [global::point[2]; global::point[2] + 1] Else カスタムダイアログを表示 ["正解しました¶コンピュータに1ポイント!"] フィールド設定 [global::point; global::point + 1] End If Else カスタムダイアログを表示 ["不正解です¶ポイント獲得ならず!"] End If 変数を設定 [$$target; 値: ""] フィールド設定 [global::key; "back"] フィールド設定 [global::card3[5]; ""] フィールド設定 [global::card4[5]; ""] フィールド設定 [global::offense_defense; If ( Exact ( global::offense_defense; "守" ); "攻"; "守" )] フィールド設定 [global::offense_defense[2]; If ( Exact ( global::offense_defense[2]; "守" ); "攻"; "守" )] If [global::rest = 0] If [global::point > global::point[2]] カスタムダイアログを表示 ["ゲーム終了!¶コンピューターの勝利です"] Else If [global::point = global::point[2]] カスタムダイアログを表示 ["ゲーム終了!¶引き分けです"] Else If [global::point < global::point[2]] カスタムダイアログを表示 ["ゲーム終了!¶プレイヤーの勝利です"] End If Else 変数を設定 [$$status; 値: 2] フィールド設定 [global::message; If (Exact ( global::offense_defense[2]; "攻" ); "攻め手番です"; "守り手番です" ) & "¶カード山をタップしてください"] End If Else If [$$timer > 5] # カードの表側を見せる フィールドを名前で設定 [$field & "[" & 16 - $$timer & "]"; ""] フィールドを名前で設定 [$field & "[" & 15 - $$timer & "]"; card::cardImage] Else If [$$timer = 5] # カードが裏から表に切り替わるタイミングでカードを決定 フィールドを名前で設定 [$field & "[" & $$timer + 4 & "]"; ""] ウインドウの固定 レイアウト切り替え [「card」(card); アニメーション:なし] 検索モードに切り替え [一時停止: オフ] フィールド設定 [card::holder; $$target] フィールド設定 [card::used; "=="] 検索実行 [] 変数を設定 [$count; 値: Get ( 対象レコード数 )] 変数を設定 [$recordNo; 値: Int ( Random * $count ) + 1] レコード/検索条件/ページへ移動 [ダイアログあり:オフ; $recordNo] フィールド設定 [card::used; 1] フィールド設定 [global::key; card::key] # カードの大きさを保持 変数を設定 [$$size1; 値: card;;cardSize] レイアウト切り替え [元のレイアウト; アニメーション:なし] Else フィールドを名前で設定 [$field & "[" & $$timer + 4 & "]"; ""] フィールドを名前で設定 [$field & "[" & $$timer + 5 & "]"; card::cardImage] End If

以上で必要な機能の作成は完了です
これらの機能を説明を省いた部分も含めて連結すると、High & Lowのゲームは完成です
ご興味がありましたら是非こちらからダウンロードしてご確認ください

次回は「ブラックジャック」を作ってみたいと思います

メモ書き終了の案内イラスト

以上で今日のメモ書きは終了です

内容はいかがでしたか?

もしご意見やご要望、誤りの指摘などありましたら、下記フォームよりお気軽にご連絡ください

ご連絡フォーム