プログラミング・スキルの普及のために、 この記事の内容は 改変・転載許可
成果物: 📖 Tic tac toe
コード: 📖 Tic-Tac-Toe
「 👆 ジェフ・ペゾスは モックアップの時点で完成度高くないと 企画も通さないらしいぜ。迷惑だよな」
「 モックアップ作りから妥協しない姿勢が Amazon の強さの秘訣だ、みたいな論調の記事を読むと
だったら もう モックアップ作るの いいかな、 弱くていいや、 と なにもかも 嫌になってしまう」
「 個人サークルの1人が言う モックアップ と、
140万人ほどの社員がいる企業の社長が言う モックアップ を同じように扱おうとするのが 性格が意固地なのよ。
モックアップに完成度を求めていないケースだってあるのだから、
特定の社長に最適化せず もっと言葉を適当に使えばいいのよ」
「 これより Unity を使って 〇×ゲームの やっつけモックアップ を作る。
今回の趣旨は 技術 を何も説明せず、 雰囲気 で書く ヒカルの碁方式 だぜ」
「 Qiita と Zenn で規約違反になるから Crieit でやるのか」
「 ガイドラインぐらい 程度は違えど どこにでもあるのだから 守ればいいのよ」
「 👆 これ、 Unity Hub (ユニティ ハブ)。
なんか並んでる1つ1つは レッスンの残骸とか、 手指の練習の残骸とか、 まあゲーム1個分の何かだぜ」
「 なるほど 画面を見せていくわけか YouTube でやれだぜ」
「 👆 最初は とにかく プロジェクト名 を付けろだぜ。
偉いさんは SEO や name conventions を考えた いい感じの名前を 付けたいと考えるかもしれないが
わたしの流儀は 『あの世に持っていけるものは何もなし』 だぜ。 ひねらず 付けて 進め」
「 👆 プロジェクトを開くと Unity Editor(ユニティー・エディター)が出てくる。
わたしは 4K(よんけー)ディスプレイ を使っているので 大きな添付画像になってしまうから、
以降は 適当にウィンドウを縮めて スクリーンショットを貼っていくぜ」
「 そこらへんの You Tube で ゲーム開発動画が たくさんあるから 読者諸君は 詳しくは勝手にググれだぜ」
「 👆 〇×ゲーム作るんだったら 盤が要るだろ。 平面(へいめん;Plane プレーン)を置こうぜ?」
「 ぜったい Unity Learn で 企画書を書けだの、設計を練れだの レッスン受けたのにな。
プログラマー・スキル・レベル剥奪だぜ」
「 設計を 信じて ないのよ。 プロジェクトは 崩壊 すると思ってるから」
「 じゃあ お父んは何を信じて Unity Editor なんか開いたのか?」
「 👆 わたしには モデルを作るスキル無いので Windows Paint で描くぜ」
「 お父んの頭の中に 効率 と 戦略 が無いことは 分かった」
「 👆 画像を プレーンに ドラッグ&ドロップ すれば テクスチャーを貼るの完了だぜ」
「 Unity、 3Dが得意なのに ペラペラの平面に Windows Paint の画像 貼り付けるの
Unity の無駄遣いだよな」
「 まだ 行動の途中 で、 考える ところまで 行ってませんからね」
「 そう言えば、盤に 黒くて太い線を引きたいけど、 黒い太線を引くのも めんどくさいんだよな。
それに 盤のマスをクリックしたかどうか 範囲を調べるのも めんどくさい……」
「 👆 そこで プレーンを9枚 置いて、マスの代わりとしようぜ!」
「 お父んの優先順位の中で、 アートワーク の順位は下の方にあることが分かった」
「 花より団子 の人ですからね。 〇×ゲームができれば なんでもいいのよ」
「 しかし どういう感じにすりゃ 〇×ゲーム を作れるのか よく分からんな」
「 👆 ここで一旦 プロジェクトを保存して Unity Editor を終了するぜ」
「 👆 クラウド上に リポジトリを作るぜ。 リポジトリというのは ファイル置き場 ぐらいの意味だぜ」
「 👆 GitHub Desktop for Windows というデスクトップ・アプリケーションと連動するんで、
ローカルPCの さっきの Tic-Tac-Toe のファイルを、
いったんローカルPC側のリポジトリで コミットし、
続いて クラウド上のリポジトリへ プッシュするぜ」
「 本当は コード・レビュー を入れて、コメントをちゃんと書いてコミットして使うものなんだけど、
やらないのよ」
「 Git Hub にソースをプッシュしたから、
ソースを壊してしまったときは それより前のバージョンへ 巻き戻すことが可能になったわね」
「 👆 マス(※英語でSquare スクウェア)をマウスでクリックしたときに 〇×を付けたいんだろ。
とりあえず Square という名前で C#(しーしゃーぷ)スクリプトを作ろうぜ?」
「 Git Hub で、いつでもリセットできるから お父んの とりあえず進もうぜ、困ったら戻ろうぜ法 が完成だな」
補足:📖Unity 2020でスクリプトの日本語が文字化けするのを修正する
「 👆 これが Visual Studio 2022 (びじゅある すたじお にせんにじゅうに)というデスクトップ・アプリケーションだぜ。
こんな画面出てきても、これから何かけばいいか分からないだろ」
「 👆 そう!
何もないところのうち いい感じのところに mouse
と打鍵すれば、
わたしが書きたいものを予測して候補が出てくる。 これが Visual Studio の利点である インテリセンス(IntelliSense) という AI だぜ。
1990年代後半にはすでにあった」
「 👆 そしてその候補で合ってたら、キーボード上の tab
キーを1回押せだぜ。
スケルトン・コードを書いてくれる。
スケルトンというのは、穴埋め文章の穴じゃない方だな」
「 いい感じのところ がどこなのか説明してくれないから 真似するの無理よ」
「 👆 何書けばいいか分からないから、とりあえず Debug.Log("なんちゃら")
を書けだぜ。
このテクは デバッグ・ライト(Debug write)と言う」
「 👆 で、スクリプトは書いただけでは動かない。
マス(※画面上では Square 0 ~ Square 8)というゲーム・オブジェクトに Square
スクリプトを持たせる。
この操作を アタッチ (Attach) と呼ぶ」
「 👆 カメラの位置も あんまりだったので、 Main Camera の位置を調整する」
「 👆 ゲーム・ビューも好きなようにいじって、 Unity Editor の上の方に置いてある再生ボタンを押せだぜ」
「 👆 するとゲーム画面になる。
黄緑色のマスをクリックしたら、 Unity Editor の左下に 『マウスボタンを押しました』と出てきた。
これで動作確認完了だぜ」
「 マスがクリックできることまでは 分かったな。
そこから どうするのか 分からんけど」
「 クリックしたマスの上に 〇のカード が飛んでくりゃ よくない?」
「 じゃあ 〇のカード 5枚、 ×のカード 4枚を予め作っておけばいいのかだぜ?」
「 めんどくさ……。 マスの表面のテクスチャーを貼り替えりゃよくないかだぜ?」
「 あらゆる発想が めんどくささに 飲み込まれて 消えていくわね」
「 お父ん ぜったい あらゆる企画マンと 会話 合わないよな」
「 👆 とりあえず GameManager
C#スクリプトをアタッチした Game Manager
ゲーム・オブジェクトを作れだぜ」
「 👆 GameManager
C#スクリプトの いい感じのところに、 いい感じに マテリアルを3つ書くと」
「 👆 マテリアルを ドラッグ&ドロップで 設定できる欄が できるから」
「 👆 Nought
ゲーム・オブジェクトと、 Cross
ゲーム・オブジェクトは 結局使わないので 消せだぜ」
「 バーチャル空間だから 無駄な発注を やりたい放題よ 徒労が増えるだけで」
「 👆 GameObject
C#スクリプトに 実質5行ほど コードを書き足したぜ」
「 👆 Square
C#スクリプトに 実質4行ほど コードを書き足したり、編集したりしたぜ」
「 👆 もう印を置いてあるところを またクリックして 印を変えることができるぜ」
「 👆 イリーガル・ムーブ(非合法手)のチェックはしてないからな」
「 プロフェッショナルなプログラマーなら 必ず 修正するし、
レッスン中なら 不具合の修正は ほっといて 後回しにしろだぜ。
不具合の修正は 気持ちが乗らないからな」
「 不具合の修正より、気持ちがノるか ノらないかが 優先されるのね」
「 👆 勝ったとき 『勝ち!』 って出てくれば 気持ちがノるだろ。
まずは その前に 勝ったかどうか判定するプログラムを書こうぜ?」
「 👆 テキストをまず作っておこうぜ。
普段は非表示にしておいて、必要な時に表示すればいい」
「 👆 勝敗判定を どこに どういう風に書けばいいのか分からない。
分からなかったら なんとかManager
C# スクリプトを作って、 なんとか Manager
ゲーム・オブジェクトにアタッチすればいいぜ」
「 お父んは『いいぜ』と言うが、 ダメだったら戻ればいいスタイルだからな」
「 👆 Position
(ポジション) C# スクリプトもいるかもしれない。スケルトンを置いておこう」
「 要るか 要らないか 分からなくても スケルトンを置くのが お父んの開発スタイルだよな」
「 👆 Piece
(ピース;駒)イナム(enum;列挙)型も作っとこ。 あとで使うだろ」
「 どんどんタネを仕込んで あとで 組み合わせる やり方か」
「 ちゃんと 組み合わさるか 事前に検討して 必要なものだけを洗い出すステップを やらないのよ、 ノらないから」
「 👆 ポジションに Piece
型の配列を持たせようぜ。
これ、 Unity Editor で いじれるようにしようかな、 [SerializeField]
アノテーション付けたろ」
「 👆 やっぱ Position Manager
ゲーム・オブジェクトも作って Position
C#スクリプトをアタッチしようぜ?
盤を編集でけて お得だろ」
「 お得かどうかは関係ないんじゃないか? 損だったら戻ればいいのだから 進めば」
「 最後に まとめ切れるかどうか 関係無いですからね、この開発手法」
「 👆 Position は Clear
関数や、 SetPiece
関数を使うだろ。
class の public 修飾子も消して internal アクセスにしておこうぜ。
Linq
は パフォーマンスが心配なんで使わないぜ」
「 👆 GameManager
C#スクリプトに入ってた movesCount
フィールドは、 Position
クラスにあった方がいいので 移動した。
MovesCount
アクセッサ―も追加したぜ」
「 👆 movesCount
フィールドを Position
クラスに持っていかれた GameManager
クラスの方には、
Position
インスタンスにアクセスできるように プロパティを用意し、参照箇所も Position
プロパティに変更するぜ」
「 👆 Square 0
ゲーム・オブジェクトの 0
の部分だけ取るように 正規表現(せいきひょうげん;RegularExpression)を書き、
Position インスタンスにセットするように書いてみた」
「 👆 これで、マスをクリックすると、○と×が入っているのが分かるな」
「 👆 Position
インスタンスが盤を表している。
Element 1
と Element 4
と Element 7
に Nought
が入っていれば、3つの○が並んだということだぜ」
「 タテ、ヨコ、ナナメに同じピースが3つ並んでいることを判定できる数式があるの?」
「 ○×ゲームぐらいの 盤サイズの小ささなら 全パターン網羅して ハードコーディングしたった方が早いぜ」
「 👆 Position
クラスに GetPiece
メソッドが無いと 盤のマスを見れないので追加する」
「 👆 例えば 3つ並んだケースの一覧とか 要るだろ。
要ると思ったものを 予め 作っておくんだぜ」
「 👆 勝敗判定を書いている途中に思ったんだが、負けかどうかは判定してないな」
「 👆 対局結果から 負け を削除しとこ。
GameResult
も こっそり GameResults
に変えた」
「 勝ち しか無かったら、どっちが勝ったのか 分からなくない?」
「 👆 まさか Lose
を使う必要がないとは 思わなかったぜ」
「 👆 JudgeManager
で対局結果を見れたら デバッグが楽だと思ったから フィールドと プロパティ付けたろ。
winPatterns
も こっそり static readonly
付けたろ」
「 👆 対局結果を返すのではなく、対局結果を フィールドに入れるように変更。
名前も DoJudge
から SetupJudge
に変更」
「 👆 GameManager
クラスの中で JudgeManager
インスタンスの SetupJudge
メソッドを使ってみよう」
「 👆 でも Draw
判定が 10手目にされたので 1 引いとこ」
「 👆 対局結果のゲーム・オブジェクトのアクティベートのチェックを外して、存在していないことにしよ」
「 👆 存在しないゲーム・オブジェクトだったら、 Unity は見つけられないので、
[SerializeField]
アノテーションを利用して ゲーム・オブジェクトにアクセスする仕組みを 仕込むぜ。
ついでに SetActive( )
メソッドを使って、ゲーム・オブジェクトのアクティベートのチェックを入れるコードも書いておくぜ」
「 他の 盤ゲームが 対局結果を どう表示しているか 見てこいだぜ」
「 👆 わたしに美術はできないので、終局時に 半透明のフロント・カバーが かかるようにしよう!」
「 ビデオゲームは 見た目のできが 内容のできだと 思われるのよ」
「 他の人はむしろ 目に付く 見た目を いじりたがるんだけどな」
📅2023-01-21 sat 00:31 end
「 👆 2020年代の GUI というと Web クライアントや、 Windows デスクトップ・アプリケーションでは 進歩、淘汰の激戦区だが、
Unity に付いてる GUI は 1990年代かな、というぐらいクラシックなものなので あまり気合を入れずに使うぜ」
「 👆 リスタート・ボタンの見た目は こんなんでいいんじゃないか?」
「 👆 JudgeManager
に Clear
メソッドを付けるぜ」
「 👆 Position
の Clear
メソッドで moveCount
フィールドを ゼロ初期化してなかったので するぜ」
「 👆 GameManager
に Clear
メソッドを付けるぜ。
この中で Position
インスタンスと、 JudgeManager
インスタンスの Clear
メソッドを呼び出すとともに、
対局結果のテキストと、盤に被せた半透明の幕のアクティベートのチェックを外して、ゲーム中に存在しない扱いにするぜ」
「 👆 また、 Start
メソッドで Clear
メソッドを呼び出した」
「 シーン・ビューで テキストの表示のアクティベートのチェックを外すの忘れたりしたまま リリース したくないだろ」
「 👆 ボタンを押したら、 Game Manager
ゲーム・オブジェクトの持っている GameManager
C#スクリプトの Clear
メソッドが
呼び出されるように マウス操作で紐づけるぜ。
この技術の名前は イベント・リスナー(Event Listener)だぜ」
「 👆 リスタート・ボタン自体のアクティベートのチェックを オン/オフする仕組みを忘れてた 追加しよ」
「 WPF (ダブリュー・ピー・エフ)の MVVM (エム・ブイ・ブイ・エム)の ViewModel (ビュー・モデル)に慣れた癖で忘れていたが、
Unity では データをクリアーしても、 シーンは連動していないのだった」
「 これは ゲーム・プログラミングなのよ。
デスクトップ・アプリケーションのような 処理が重たい技術は 流行らないのよ」
「 👆 じゃあ バリデーター(Validator)を作ればいいだろ。
そのマスに置けるかどうかだけ チェックすればいいのかだぜ?」
「 👆 あっ、 Square 0
みたいなゲーム・オブジェクトの名前しか取れね。 0
みたいなマス番号取れね」
「 👆 じゃあ ヘルパー関数 作ればいいんだぜ。
GameManager
で 似たようなコード前に作ったから 引っこ抜いて 共通利用できるようにするぜ」
「 Nought win
のあとに まだ X
を置けるんじゃない?」
「 👆 半透明の青い膜が被っていて、 マスはクリックできないから
対局終了後に マスをクリックすることは でけないぜ」
「 コード・レビュー しようぜ?
プログラミングの へたくそなところがある」
「 👆 例えば 『駒を置く』は入力だが、 『対局結果を表示する』は出力だぜ。
入力メソッドが 出力してるなんて イケてないぜ」
「 プログラマーの気分 を 重要視してるんだな。 その点では Ruby に似ているな。お父んのポリシーが 分かってきたぜ」
「 👆 『出力』の部分を DoMove
メソッドから外に出したいが、
piece
変数が DoMove
メソッドに束縛されているから、 piece
変数を 自由変数に変える方法を考えようぜ」
「 👆 Position
クラスに 手番(Turn)を持たせようぜ。
初期値は Nought
」
「 👆 手番を追加する NextTurn
メソッドもいるや。追加しとこ」
「 👆 インクリメントも NextTurn
メソッドの中で やってまお。
MovesCount
プロパティーのセッター(set)も要らなくなったから、短く書いたろ」
「 👆 これで DoMove
の中から piece
変数が消えた。 代わりに Position
に依存するようになったぜ」
「 👆 こうやって UpdateGameResultView
メソッドに切り分けることがでけたな。
しかし DoMove
メソッドを実行すると UpdateGameResultView
メソッドまで 実行されてしまうのは イケてないな」
「 👆 あっ いけね!
対局が終了しているときは NextTurn
しないように バリデーション・チェックしようぜ」
「 👆 JudgeManagement
クラスの SetupJudge
メソッドを、
変更があったかどうか返すように 変更するぜ」
「 👆 判定に変更があれば dirtyJudgement
フラグを立て、
dirtyJudgement
フラグが立っているときだけ UpdateGameResultView
メソッドは働き、
働いたら dirtyJudgement
フラグは下ろす、という風に作るぜ」
「 👆 これで UpdateGameResultView
メソッドの呼び出しを
DoMove
メソッドの外に出して、
Update
メソッドの中へ 引っ越すことがでけたぜ」
「 👆 そんなけ コードをいじっても ゲームは何にも変わらないじゃない。
コードを イケてるようにすることに 何の意味があんの?」
「 ワザを安定して出せるようになると、
もっと 大きなワザ を出せるようになる。大きなワザ を出せるようにするために コードを掃除してるんだぜ」
「 👆 GameManager
クラスの Clear
メソッドの中で 画面表示を切り替えているのは 掃除しないのかだぜ?」
「 👆 Position
クラスの SetPiece
メソッドも、変更があったかどうか返すようにしようぜ?」
「 👆 マスをクリックして、絵柄に変化があったときだけ dirtySquares
セットに マス番号を追加することにするぜ」
「 👆 これで DoMove
メソッドの中から 表示をコントロールするコードは 消えてなくなっただろ」
「 dirtyなんちゃら
フラグが 入力メソッドと 出力メソッドの 橋渡しをしているのね」
「 👆 GameManager
クラスの Clear
メソッドの中にあったコードも、 dirty
フラグを立てるだけで よくなったぜ」
「 これで 表示周りのコードの クリーンナップ は終わりか?」
「 👆 GameObject.Find
メソッドは 処理に時間がかかるらしい。
できれば Start
メソッドで1回使ったあとは 使わなくて済むようにしたいぜ」
「 👆 GameManager
クラスの Start
メソッドが呼び出された時点で、GameObject.Find
を先にしてしまって、
ゲーム・オブジェクトをメモリに入れておけばいいぜ」
「 👆 例えば get
アクセッサ―で 変数をリターンしているだけのプロパティなんかは……」
「 👆 ラムダ式と同じなんだったら、書き方が短いラムダ式にするとかかな。
パフォーマンスに違いがでるのか 知らんけど」
「 パフォーマンスの測定をするほどの 速度が必要なアプリケーションじゃないから
ちょっとぐらいパフォーマンスが違っても 違いは分かんないわねえ」
📅2023-01-22 sun 06:45
「 👆 WebGL 形式で 実行ファイルを出力してみようぜ?」
「 👆 Visual Studio Code に Live Server
エクステンション入れてると ローカルWebサーバー起ちあがるんで、
Tic Tac Toe の index.html
を開いてみようぜ?」
「 ○×ゲームできても ビデオゲームって感じ しないけどな」
「 2か月 Unity Lesson でビギナーコースを受けて、○×ゲームを作るのに 3日間かかるようでは 気が遠くなるわよね」
「 仕込みが なんにも無いからな。
重要なのは 制作進行を覚えて 素材の発注を見積もることだぜ」
「 UI も タイトル画面も 何もかもがなくて ゲーム開発の全体像はまだ見えないわね」
「 👆 Unity Play
という Web サイトがある」
「 👆 ここには、作ったゲームをアップロードするページがある」
「 👆 というわけで、 WebGL のファイルが入ったフォルダーを .zip
圧縮し……」
「 👆 アップロード完了。 Play Unity に置いたぜ」
📅2023-01-22 sun 07:22 end
<おわり>
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント