Unityでインディゲーム道!

プログラム、Unity初心者がインディゲーム制作を目指して日々思うことなどを書き綴ります。

オブジェクト指向とは単なる分割、縮小、連携のための手段だ!

 オブジェクト指向は思想のように捉えることは混乱を生みます。エレガントな手段!なんてものではなく、タイトルの通り、それなりの規模のプログラミングに対する妥当で、現実的な手段ではないのでしょうか。オブジェクト指向の本質を理解した気がするので、考えをまとめたいと思います!(理解できてなかったらゴメンなさい。)

 

むしろ補助的な機能

 オブジェクト指向に振り回されがちな初心者プログラマですが、自分も最初は掴み所がなくて困惑しました。クラスは設計図のようなもの・・・ようなものってなんだよ!?みたいな。

 Unityでやることを含め、最初の言語としてC#を選択する人が少くないと思いますが、C#オブジェクト指向の言語です。そのためオブジェクト志向な考え方にどっぷり浸かることになります。
 つまり、オブジェクト指向がプログラミングにおける本分のように錯覚してしまうわけですね、自分も最初そう思いましたし、同時に初歩的なこととオブジェクト指向的なもののが噛み合ってこないので、そこで要領を掴めなかったりしました。
 
 それもそのはずで、オブジェクト指向はむしろ補助的な機能に他ならないわけで、実は初心者はそれほど気にすべきことでもない、といってしまっていいと思います。

コーディングにおける二つの目的とは?

 プログラミングには、いろんな機能やテクニックがありますが、それらは主に二つの目的のために存在していると思われます。つまり・・・
可読性のための分割 & 読む量を減らすための縮小、の二つです。

 例えば、関数やメソッドというのはこの2つが組み合わさったもの、と説明できます。
 複数行の処理を関数化することで、他のコードと切り離し、区別できるようにし、読みやすくします。また、その処理が繰り返し使われる場合、関数を呼び出せばよくなるので、総合的なコードの量は減ります。関数の再利用というものですね!

 For文なども繰り返し処理を効率的に書き表すためのテクニックですし、縮小のための道具と言えそうです。

クラスも単なる道具である。

 というわけで、クラスもこの分割&縮小のための道具に他なりません。オブジェクト指向は現実世界に近い形でコードを書けるエレガントな方法だー!みたいなのは結果的にそう解釈できるに過ぎず、本来の目的は大きなプログラムを分割して、読みやすく扱いやすくし、また大きくなりすぎないようにするためのものなはずです。

 カプセル化とはコードを意味のある塊にまとめる、ということであり、機能や分野ごとにまとめるというのはその方がわかりやすいから、ということになります。
 難しく考える必要はなく、ただ単に分けて管理しよう、別々に考えよう、というものに過ぎないはずで、言葉遊びに付き合う必要はありません。
 
 継承、ポリモーフィズムはコードの量を減らすためのものです。継承は関連あるクラスの重複部をひとまとめにするためのもの、ポリモーフィズムは各クラスをひとまとめにし、いろんな動作を共通のメソッドで表現し、やはりコードを少なく、簡潔にするためのテクニックです。

自分でデータ・タイプを作るための器

 分割&縮小はトラブル回避のための消極的な目的ではありますが、積極的にクラスを使う目的もあります。それはデータ・タイプを自分で作れるということです。

 データ・タイプとは、いわゆるInt, float, char, bool などのデータの形式や種類を表すものですが、基本的なタイプは単純なデータしか扱えません。

 世の中にある様々なモノは複雑な構造、概念によって形成されており、そうした単純なタイプでは表現不可能です。正確に言えば、多くの単純なタイプが組み合わさって、初めて高度て複雑な表現ができます。
 要するにクラスとは、そうした数多くのデータタイプをひとまとめにし、抽象化するための入れ物になるわけです。抽象化とは、細かい事柄をざっくりと捉えることで、高度な理解、表現をするための手段です。

 また、クラスはメソッドも含めることができるので、振る舞いも表すことができ、クラスから作られるモノ(インスタンス)に主体性を与えることができます。これはクラスによる分業の面から見て、とても重要です。

 これにより複雑な構造を持つ、人間を含めた生き物などをコンピュータ上でデータとして、扱えるようになる、ということになります。
 つまり、高度で複雑なデータを表すタイプを自分で定義できるということです。

連携という、ネック

 分けた、ということはバラバラになったコード群が一つの仕事を成し遂げるために連携しなければならないということになります。どう連携するかの管理のためのアイデアがアクセス修飾子です。つまり、公開、非公開にすることでクラス間の連携を制限するというものです。

 連携はむしろクラスを利用するために支払わなければならないコストのようになります。なぜなら、上手く連携をするような構造になっていないと、かえってコードが複雑になってしまうからです。
 プログラミング言語が人間のためのものなのに、読みにくくなってしまうのと同じように、クラス分けのせいで、プログラム全体の構造が複雑になって、把握しにくくなるのは本末転倒です。
 しかし、クラス設計とは単純なコーディング以上に、物事の本質を見極める能力が求められ、難しいわけです。
 ここらへんがオブジェクト指向が必要以上に叩かれる原因なのではないでしょうか。しかし、オブジェクト指向は単なる方法論であり、使わなければならないなら慎重に使わざるを得ず、他にいい方法があるなら、その方法を使えばいいだけです。

まとめ

 というわけで、クラスは分割や縮小、連携、そして、自分でデータ・タイプを定義するためのもの、という説明を書いてみました。
 少し、長くなりましたが、かなり分かりやすく書けたかと思います。自分で言うのもなんですが。

 ポリモーフィズムに関しては、Unity上の実践含めて、また改めて記事を書きたいと思います。画面中の敵を全部・・・みたいな内容です!

マリオオデッセイという名のロードムービー | ゲームクリア後感想

 少し遅いかもですが、マリオオデッセイをクリアしたので、その感想をまとめたいと思います。
 パワームーンを500個以上集め、「長い旅の終着点」までクリアしたので、一通りは遊んだと言えると思います。

インタラクティブ・ムービーとしてのマリオ

 ムービーゲーをマリオ64で否定したのが任天堂だったと思いますが、本作は思いの外、観るということに意識を置いたゲームになっていると思います。オープニングを始めとした各ムービーは、昨今の洋ゲーを意識した出来で、かっこよかったですね。
 
 というか、単純にクリアだけを目指した場合、つまりメインストーリーのゲーム体験はかなり映画的な流れになっていると思います。

クッパを追いかけて、各国を飛び回り、戦ったり、打ち落とされたり、でも這い上がってまた頑張ったり・・・(二回目の撃墜は少し冗長かな、とは思いましたが)

アクションゲームの集大成

 20年ほど前ですね、マリオ64を死ぬほどやった少年もオッサンになりました。この長い年月の間にゲームは様々な進化を遂げ、一時期ゲームを離れた時もありましたが、その変容はそれなりに見てきたつもりです。
 マリオ64革新、驚きとするなら、本作は洗練、成熟と言えると思います。この20年のゲームの進化を内含した一作と言うべきかもしれません。

 マリオの集大成というよりは、ここ20年くらいのアクションゲームの集大成なのかなと。いろんな国を飛び回り、旅をするというコンセプトは、また多様なゲームを取り入れる、という風にも解釈できます。
 個人的にクッパ城が好きなんですが、そこでのキツツキっぽい敵のツックンにキャプチャした時の壁にくちばしを刺すアクションって忍者っぽいんですよ。それもあって、がんばれゴエモンっぽいんですよね。

 また、黄金のリングとジェット花による高速ダッシュセガソニックっぽい・・・

 メカハナちゃんはメトロイドっぽさもあるし・・・。そもそもマリオがモーフボール出来るようのなってる!

 なんというか、キャプチャのなんでもアリさも合わせて、アクション・ゲームの集大成と感じました。
 64以降の3Dマリオをベースに様々なゲームを破綻しないように乗っけているという感じでしょうか。

マリオの冒険は続く

 なんで、あまりマリオ最終章という気はしなかったですね、やりたい放題やったオデッセイの後に、マリオにどんな新たな冒険があるのかが楽しみです。
 というか、オデッセイのエンジンで64をリメイクして欲しい!!!

唯一の欠点

1つだけ文句言わせてください。
ゲームの止め時がない!!

 オデッセイに限りませんが、今どきのゲームはどこでもセーブでき、いつでも中断できます。今どきセーブポイントでしかセーブできないのは時代遅れ!というのは正しいかと思いますが、しかし止めるタイミングがない!
 特にオデッセイは一つ一つのステージはそこまで長くないし、楽しいし、いくらでも出来てしまうんですよね。
 だから、ケツが痛くなったら止めるみたいな感じでした。昔はゲームオーバーになったら止める、みたいに出来たんですけどねー

ゲームにおける統一感

 なんでもありに、なってしまうと結果的にゲームとしての統一感を取るのは難しくなると思います。

 最初は結構戸惑ったり、特にブルータスのデザインに関しては最初はどうだろうと思ったりもしたんですが、まぁ慣れましたし、最後の方は愛着沸きましたね。

 というかゲームとしての面白さが全てを許してしまうというか。結果的に良く出来たゲームだなぁと。成熟したゲームを体現した出来ですね。

バルーンファインドが何気によい!

 いわゆるエンド・コンテンツのようなモノだと思うんですが、バルーンファインドが意外と、というかかなり面白かったですね。
 ほどよい、緩いオンライン要素で遊びやすく、みんな思いもよらない所に隠してるので、奥深さもありやす。

まとめ!

 頑張った自分に感動するのがゲーム、というのは宮本茂氏の言葉らしいですが、確かに長い旅の終着点をクリアした際には、少し涙が潤んでしまいました。
 少し駆け足気味にプレイしたのが勿体無いくらいでしたね。まだ更に遊べるので、ゆっくりやっていきたいと思います。

関数とは再利用よりも抽象化するためのもの?

 関数といえば、プログラミングにおいては、なんらかの仕事をする「機械」のようなものであり、C#上だとメソッドとも言われます。

 関数とはコードを部品化、あるいはモジュール化して再利用しやすくするためのものだ、というような説明がなされます。それはその通りなのですが、初心者からすれば、コードを書いた経験もないので、再利用による恩恵が実感できず、結果的に関数というものの存在意義が掴みづらいのではないのか?と思います。(自分がそうでした。)

 久々の投稿になりますが、リハビリも兼ねて、今回はプログラミングの基本的な部分である「関数」について、書いてみたいと思います。

数学の関数とは違う?

 まず名前がややこしいですよね。数学における関数というのは、y = 2xみたいなもので、一定の処理をする計算式です。
 プログラミングは究極的には、計算の集合ではあるので、一定の仕事をするコードを関数というのは間違ってはいないと思います。しかし、文脈上のニュアンスが異なるということを、初心者は気をつけるべきです。
 では本題に入っていきます。

名前をつけることの重さ

 名は体をなす。という言葉があります。名前というものはプログラミングに限らず、実際、とても重要なものです。名前にこそ魂が宿る、という考えもありますよね。

 と同時に、いかなる名前を付けるべきか?という問題も存在します。そのモノの本質を表すような名前をつけなければいけないからです。

 プログラミングにおいても、この「名前付け」こそ、もっとも重要で困難な作業であったりします。可読性や、コードの働きへの認識に大きな影響を与えるからです。

「処理」に名前をつける。

 プログラムはなんらかの問題を解決するための「処理」の集合体とも言えます。複数の「処理」を積み重ねることにより、大きな「処理」をしている、ということです。(実際には、クラスも分割の単位にいれるべきですが、ここでは省略します。)

 小さな処理もまたより細かい「処理」により、構成されています。もっとも小さな処理の一単位を一行のコード、実行文とします。

 つまり、関数とは一定の処理をする、複数行のコードに対して、名前を与えて、まとめあげるためのものだということです。一言で言うならば、ある処理を抽象化するもの、ということになります。

抽象化とは?

 プログラミングにおける抽象化とは、人間の考え方、認識の仕方に近づける、ということです。
 つまりは、物事を漠然と捉える、余計な細かいことは気にしない、ということになります。

 プログラミング言語というのは、人間のためのものであり、人間が読みやすいように書かれるべきですが、それは人間側の都合です。

 コンピュータ側の都合で、コードは必ずしも人間に分かりやすいものではないかもしれません。例えば、次のようなコードがあります。

int numMAX = array[0];
for(int i = 1; i < array.Length; i++)
if( array[i] > numMAX)
numMAX = array[i];

 これは整数の配列(集合)の最大値を見つけるための処理です。つまり、やっていることをそのまま名前にして、関数化してしまえばいいんです。
つまり・・・

int FindMAXinArray(int[] array){
int numMAX = array[0];
for(int i = 1; i < array.Length; i++){
if( array[i] > numMAX)
numMAX = array[i];
}
return numMAX;
}

FindMAXinArray(配列の最大値を見つける)、というストレートな名前ですが、これで具体的にどんな細かい処理をやっているかを無視して、どんな目的のことをやっているかにだけ注目できます。

 つまり、人間の認識、思考能力には限界があるので、目の前に出される情報量を制限しよう、というのが抽象化であり、そのための手段に関数があるということになります。(より高度な抽象化のためのツールとして、「クラス」があります。)
 細かいことを意識から外すことで、より高度なことが出来るのが人間、ということになるかと思います。(細かいことを正確に早く出来るのがコンピュータ)

再利用よりも抽象化

 再利用という考え方は大事ですが、再利用というのは関数化したことによる結果論であり、再利用を前提としなくとも、関数化した方がよい場合もあります。
 自身の経験談としても、抽象化するために関数を作る、という風に意識を変えていった頃から、コードをより良く書けるようになった記憶があります。つまり、必要な処理がどんなものかを考え、先にその処理の名前を考える、というプロセスです。

 再利用するかもしれないし、するかもしれない。たくさん再利用するかもしれないし、二回しかしないかもしれない。そんなあやふやなメリットを強調するよりも、こっちの方がより分かりやすいのではないかと思います。(もちろんコード全体に散らばる重複部分を関数化するというのも、立派な再利用の恩恵といえますが。これはリファクタリングの範疇ですかね?)

まとめ!

 というわけで、今回は関数というものについて書きました。何らかの処理に対して、適切な名前を授ける、という意識で関数を作る、という考え方の方が初心者にとっても、分かりやすいんではないか?という主張でした。

"正規表現"が面白い!!

正規表現という字面を見ると、なんだかお堅い感じがして尻込みしていましたが、分かってみるとこんなに便利なモノもないなと感動しました。

 

このページが分かりやすいです。

サルにもわかる正規表現入門 

やっぱ、2000年前後の個人の方が真面目に作ったページは面白いですね。 


 

 メタ文字と呼ばれる特殊な記号を使って文字列の形態を書き表すためのもので、パターン検索であったり、表記ブレにも対応できる、というものらしいです。(勉強中)

 例えば、ケータイの番号を検索したいなら、"\d{3}-\d{4}-"\d{4}という風に書き表すと、数字3桁ハイフン数字4桁ハイフン数字4桁で表記された、文字列を引っ張って来ることが出来ると。めっちゃくちゃ便利じゃん!!と驚嘆しました。

 

 ゲームなどで使うとなると、テキストの多いアドベンチャーゲームなのかなぁと初心者考えでは思うのですが、どうなんでしょうか。でも、単純に正規表現で出来ることは実務上でものすごい便利なので、プログラムを勉強し始めて一年越しではありますが、ここらでしっかり身につけようかなーと思います。

 

 一説によると、プログラムを勉強し始める前に正規表現を学んだほうがいい、という主張もあるそうです。ネットでチラチラと"正規表現"という単語を見てはいたんですが、プログラミング以外にも使えるようなのでもっと早くにやっとくべきだったなぁ、と少し反省・・・。

 というわけで、正規表現面白いなぁという日記でした。

 

 

プログラミングにおける様々な記号の読み方!プログラミング入門

意外とスルーされがちな、プログラミングにおける様々な記号の読み方についてまとめていきます。

 

. , ; : [] {}  _ * | () <> ! " '  = + - % / \ ^

 

周知の事実?

 自分を含む、ズブの素人というのは、プログラマの人が初めから分かっているようなことすら分かっていないことが多いです。そして、記号というのは見たまんまな存在ではあるので、読み方はおざなりになってしまったりします。

 

 各々の記号は当然見分けは付きますが、読み方が分からないとモヤモヤとした認識になってしまいます。自分も最初は;(セミコロン):(コロン)の見分けがついてもどっちがどっちだか分からない状態からのスタートでした。名前を知ることによってこそ本質に近づけるのであり、ヴォルデモート卿もそれを恐れたわけです。

 

 はっきりいって、多くのプログラミング初心者向けの本は知ってて当然のことをスルーすることが多いです。でもそれはおかしいですよね、知ってて当然のことを知るために入門書を買うわけですから。ググレば済む?ほー、じゃあこのページでまとめちゃいますぜ。英語での読み方などを参考に編み出した我流になりますので、その点ご了承ください。

 

様々なカッコ

  一番ややこしいカッコについて先にまとめます。

( ) カッコ

 英語ではParenthesesと呼ばれたりもしますが、単純にカッコでいいでしょう。丸カッコでも良いかもしれません。

[ ]  角カッコ

 英語だとSquare bracketと呼ばれます。角カッコと読んでいます。

{ }  ひげカッコ

 Curly brace, Curly bracketと呼ばれます。クネクネしてる、カールしているから、ですね。日本語ならひげカッコで良いと思います。

<>  矢カッコ

 英語だとダイヤモンドらしいです。仰々しすぎるし長いので矢カッコでいいかなーと。genericにおけるタイプ宣言、比較演算子として活躍。

 

少しややこしいやつ

&  アンド(アンパサンド)

 ラテン語でandを意味するetを併せて作った文字なので、アンド読みで。

%  mod(モッド)

 確立を表すパーセンテージではなく、剰余算を表すオペレータです。mod(モッド)と読んでいます。

"  ダブルクォテーション

 ややこしい、というより長い。二重引用符ですが、これも長い。ダブルかなぁ?

'  シングルクォテーション

 シングルで良いのかなぁ。(適当)引用を意味するquoteの頭文字をとってシングルキューとかがいいんですかね?

アスタリスク

 C言語系では様々な役目を任され、混乱の元凶だったりする。(掛け算、ポインタの宣言、間接参照・・・)

|  タテボー、パイプ

 馴染みがない記号代表!比較演算子においてORの意味で使われます。 縦のラインのなので、Vertical Line(バーティカル・ライン)でもありますが、タテボーか海外にならってパイプで良いと思います。

^  カレット

 本来は校正用の記号らしい。C#だと論理排他的 OR 演算子となる。

 

御馴染みの記号

.  ドット

 C#だとクラスのメンバーにアクセスするためのアクセス演算子ですね。

,  コンマ

 表記を区切ったり、引数を区切ったり。

;  セミコロン

 C#だと文の最後に必ずつける大事な記号です。

:  コロン

 継承したクラスを示したり、switch文などのラベルを示したり。

_  アンダーバー

 下にある線だから、アンダーバー。安直。

=  イコール

 プログラミングだとイコールであってイコールじゃない!アサイナー(asigner)とかで呼び分ける必要あるのでは? ==(ダブルイコール)で本来のイコールの意味になる。

+  プラス

 足し算

-  マイナス、ハイフン

 引き算

/  スラッシュ

 割り算

\  バックスラッシュ、あるいはエン

 同じ働きをするが、キーボードや環境などの事情で入れ替わる、ややこしい奴ら。ハテナだとエン・マークで表示されています。

!  ノット(ビックリ)

 否定の意味で使われるからややこしい。もう意味に合わせてNOTと読んでます。

?  ハテナ

 三項演算子などに使われる。ハテナでいいんじゃないでしょうか。

 

まとめ!

 というわけで、一通りまとめてみました。やっぱ名前をきちんと認識していることが大事です。それを踏まえた上で本を読めば、理解の深さが違ってきます。といっても、自分もまだまだ曖昧なところがあるので、精進していきますよ!!

 

 

 

"Cuphead" Unity製の注目インディゲームの初感レビュー!!

いよいよ期待のインディゲーム、Cupheadが発売されました!

 ぶっ続けで3時間ほどプレイし、第一、第二エリアをクリアするかしないかの所までいったので、ひとまずその初感をザックリと書いておきたいと思います。

f:id:miur-us:20171003211414g:plain

以下全ての画像は実際のゲーム画面のスクショです。

いやー、おもしろい!!あと良い意味で難しい! 

 やる前に想定していたゲーム性とは少し違ったデザインでしたが、なぜそうしたかを考察すると、インディだからこその割りきりがあり、そこがプレイ面にも良い影響をあたえていると思いました。そこらへんの考察は後ほど。では順にまとめていきます!

※ゲーム製作者的観点の考察を多く含みます! 

 

どんなゲーム?

ガンシューティング2Dアクションです。主人公であるカップヘッドは悪魔の経営するカジノで魂を賭けたギャンブルに負け、見逃してもらう代わりにカジノへの借金滞納者の魂を回収するように命じられます。(ヘビーだ・・・)

 

 自分はPVを見た感じ、メタルスラッグのようなゲームなのかなー?と思っていました。つまり、ステージを進んでいって、ボスを倒して・・・という構成です。また同じく2Dガンアクションの名作、魂斗羅を思い浮かべた人もいるようです。(実はやったこと無いです、恥ずかしながら。ミニスーファミでやりますぜ!)

f:id:miur-us:20171003211529j:plain

 しかし、実際には通常ステージはあるにせよ、それは決して本筋ではなく、マップ各地に偏在する、ボス(つまり滞納者)を訪ねて直接対決を繰り返していく、という言わば、ボスラッシュ的な構成だったのです。(各ステージに一体なので直後に連続ではありません。が実質的にボス戦が続きます。)

 

 ある意味、予想を裏切られた形ではありますが、しかし、やってみるとその絶妙な難易度で死んで、覚える、そしてボスを打ち負かすという明確かつシンプルな目標と素晴らしい映像、アップテンポなスイングジャズが融合した、かなりの高揚感を味わえるゲームになっています。

  

個性的なゲーム

 まずヴィジュアル、グラフィックから唯一無二の個性を放っていますよね。PVの時点でスゴいな!という印象でしたが、実際やるとさらに良いです。というか、ゲームとしても気が抜けないゲームなので、その映像に気を取られてしまうとクリアできないです。アニメーションに見とれている暇はありません(笑)

 

 1930年代のカトゥーンアニメ調のグラは群を抜いたクオリティです。そこは説明する必要は無いでしょう!問題は、じゃあゲームとしてはどうなのか?ということになります。見た目も大事だけど中身も大事ですから!

 

 インディゲームの場合、どうしても『~っぽい』とか『~の影響うけてるなー』という印象を持つことが良くも悪くも多くあります。繰り返しますが、自分はメタルスラッグっぽい感じなのかな?と想像してました。

 

 しかし、実際のゲームとしてのデザインは、スーパー・マリオブラザーズを初めとした往年の2Dゲームからの影響をもちろん感じさせながらも、Cupheadとしての独自性をきちんと打ち出せている、と感じました。つまりボスを倒すということに重きをおいたゲーム性が、CupHeadらしさを生んでいるのではないか?ということです。

f:id:miur-us:20171003211610j:plain

ドラゴン、そして宙に浮かぶ足場。これはまさしくロックマンのメカドラゴン!

今のところ、一番好きなボスかもしれません。

 

ゲームデザインについて

  いわゆる伝統的な2Dアクションというのは、マリオしかりロックマンしかり、障害物レースのように様々な仕掛け、ザコ敵を避けながら(あるいは倒して)ステージを進み、中ボスを倒していき、各ステージを走破して、最終的にラスボスを倒す、というような構成になっています。つまり、アスレチックを攻略していくようなゲームです。

 

f:id:miur-us:20171003211715j:plain

 しかし、CupHeadというゲームは明らかにボス戦そのものをゲーム体験の主軸においています。Cupheadにはコインがありますが、その数は限られており、通常ステージの中に置かれています。しかし、通常ステージは少なく、1つのエリアにそれぞれ2ステージずつしかありませんでした。(この後のエリアでは増えるかもしれません。)ボス戦ステージの方が数が多いのです。

f:id:miur-us:20171003211854j:plain

  コインは主人公キャラの新たな技を買うために存在しており、それが必要ないのであれば、別に通常ステージをクリアする必要もない、という扱いです。初見プレイでは間違いなく、買っていかないとツライです。チャージショットがお気に入り。(一方、マリオでのコインの扱いは100枚集めれば一機増えるという救済措置的な存在)

 

f:id:miur-us:20171003212357j:plain

  これってなかなか画期的ではないでしょうか?ボスは与えたダメージによって、基本第三段階まで変化します。(上写真はスライムの第二段階)これはよくあるパターンですよね。親切なことにプレイヤーが負けると、どこまで行ったかをリトライ画面で示してくれます。 難しいけど何度も死んで覚えていき、馴れると遅くとも三分以内に倒せる、という短い時間に密度の高いゲーム体験が出来るというデザインになっています。

f:id:miur-us:20171003211805j:plain


 思ったのは、ダークソウルシリーズのような良い意味での死にゲーです。しかし、このゲームには、ダクソにもあった探検要素はほとんどなく、ボス戦の死んで覚えて打開する、という部分を凝縮した、割り切ったゲームであると言えます。

 

 つまり、このゲームは伝統的な2Dアクションではなく、各地に潜む個性豊かなキャラクター達に殴り込みをかけて、その命を奪うという非常にシンプルなゲームです。もちろんボスを倒すのには一筋縄ではいきませんので物足りなさは一切無いです。

 

 あとやりこみ要素がきちんと用意されています。各ステージにはスコアが設定されており、プレイによってFからA(A以上もあるらしいです。)までの成績がもらえます。ただクリアするだけでも大変なのですが、よりやりこみたい人への準備も怠っておりません! 繰り返し遊べる良いゲームだと思います。

 

インディならではの割り切り

  インディゲーム開発というのは、資金面においても、作業人数においても、そう工数を多く取れるものではありません。アニメに関しては、手描きということで手は掛かっているとはいえ、ゲーム全体における一貫したレベルデザインというのは、インディにとって困難な作業です。

 

 なので、ボス戦という通常のゲームであれば、合間の要所にあるモノをゲームのど真ん中に据えることで、レベルデザインの負担を押さえているのではないのかと思います。(おそらくステージ構成よりもボスの攻撃パターンを考えるほうが負担は少ない?)とは言っても、アニメ的演出は各ボスごとに相当凝っているので、手を抜いているというわけではありません。そちらの方を優先した、ということだと思います。

 

  これはリソースの限られたインディならではの割り切りだと思います。しかし、大事なことは、その割り切りがゲーム性そのものにおいても、良い影響を与え、個性を獲得しているということです。

  

Unityやるじゃん!

 間違いなく、Unity製のゲームの中での現時点でのトップクラスの作品に入ると思います。世界観の大切さだけでなく、ゲーム性をも両立させる、という言わばインディにおける最大の課題というものをクリアしているように思えるからです。

 

 もはや、Unityは単に手軽にゲームを作るための汎用ゲームエンジンではなくなりつつあるのではないでしょうか?もちろん、そういう用途でも今後使われるとは思いますが、これだけのゲームが作れるのですから!!

  

 間違いなく多くのUnityユーザーの指針となるゲームだと思います!

 

 

神ゲー"じゃんけん"でプログラミングを考える!!

神ゲーの1つである、ジャンケンをプログラミングで再現することで、プログラミングの最初から終わりまでの一連の流れをステップごとに追って説明していきます。それによりプログラミングとはなんだろうということを考察する内容です。

 ジャンケンは分かりやすいゲームではありますが、それをちゃんとプログラミングするとなると、初心者にとってそれほど簡単ではありません。 

f:id:miur-us:20171001211150g:plain

 完成したプログラムはこんな感じです。コンソールアプリになります。コンソールはとっつきにくいかもしれませんが、馴れてしまえば純粋にコードにだけ集中できるので練習にはふさわしいフォーマットだと思います。

 文字だけとは言え、最低限のジャンケンとしての体裁は整っています。こんなんでも、ちゃんとするにはそれなりに考えないとだめですからね。逆に人間はコレだけのことを『なんとなく』できるわけで人間もなかなかやるじゃん!という気になります。

 

 以前に書いた"プログラミングにおける5つの手順"に沿って、順を追って各工程ごとに書いていくことで、プログラミングという作業の流れというものも考えていきたいと思います。 それも本稿における重要な狙いです。

 

どんな構造なのか?

その前に、まず最初に概略について。

 たかがジャンケンですが、コンソールアプリとはいえ150行ほどになりました。コードは一応載せますが、分かりやすさのためにも先にプログラムの全体図を示したいと思います。 一枚の図にやるべきことをまとめています。 

f:id:miur-us:20171001223107p:plain 

 この図では、おおよその流れと各々の動作とそのための解決策をざっくりと書き表しています。ある意味では、リアルなジャンケンもこの図のような処理をしていることになります。いろんな機能を加えようとすれば、いくらでもできるとは思いますが(例えば、アスキーアートで手の形を表す、など)とりあえず最低限の機能のみのプログラムにしました。では5つの手順に沿って、考えていきたいと思います。

 

要件定義

まずはどんな設計、ルールにするかを考えます。(第一工程)

  • プログラム上のNPCとジャンケン勝負。
  • ベーシックに先に三回勝った方が勝ち。

 シンプルにコレだけになります。せめてwindowsアプリにしてグラフィカルにやった方がいいとは思いますが、プログラミングすることが目的だし、めんどくさいのでコンソール・アプリでの開発としました。

 

ファクタリング

次の第二工程は、"じゃんけん"というものの分析になります。

 ジャンケンは一対一、あるいは複数人が同時に『手の形』を出し合い、その優劣によって勝敗を決めるゲームです。手の形はそれぞれグー、チョキ、パーでいわゆる三すくみの関係(絶対的な強者がいない)になっています。

同じ手が出た場合は、『あいこ』となり、勝敗つかずのやり直しになります。

 

道具の選定 其の一

 分析も終わったので、その結果に基づき、ジャンケンをプログラム上で再現するために必要な道具を考えます。

 

 まずは互いの勝敗数を数えるための変数が必要です。単純な数を数えるだけなのでintタイプが二個あれば十分です。

int playerScore = enemyScore = 0;

 次は重要な『手の形』をどう表現するか?そして、二つの手をどう比較するかの問題です。プログラミングですので、つまりは数字に置き換わるわけですが、数字自体に意味はなく、自動的に振り分けられるような番号であり、プログラム中は変化することは無いので、(定数)つまりenum(列挙体)がちょうど良いということになります。

enum HandForm {

Goo = 1,

Choki = 2,

Pah = 3

}

 という風にかけます。数字を直接的に割り振ることもできますが、そうすると人間側がいちいち「1はなんだっけ?」という風に、その都度思い出さないといけなくなる可読性の低いコードになってしまいます。なので、列挙体を使って言葉に置き換えた方がより分かりやすいコードになります。

 

そして、勝敗の判定方法です。

まずはプレイヤーとNPCの手の形を記憶するオブジェクトが必要です。

HandForm playerHand, enemyHand

このように列挙体変数を作り、そこにそれぞれデータを格納します。

 

 この変数をintにキャスト変換し、その数字を使ってswitch文で勝負の判定を行います。それについては、後ほど説明します。

  

道具の選定 其の二

次は実際の勝負を何回行うか?という問題です。つまりループ処理になります。

 今回のゲームはどちらかが勝つまで続きます。ここで問題なのが、じゃんけんはあいこがあるので、何回勝負が続くかわからないということです。

つまり、どちらかが三回勝つまで勝負は延々と続くことになります。

 

 回数が決まってない、条件がtrueな限り処理が実行される、ということでwhile文がこの場合に適しています。条件は・・・

"どちらの勝ち星も共に2以下の限り"

とします。

while( playScore < 3 && enemyScore < 3 ){

//ジャンケン勝負の処理

}

 上記のように、プレイヤーの勝ちが3より小さい、"かつ" 敵の勝ち星も3より少ない、という風に書き表せます。これはつまり、どちらが3回勝った時点"false"偽となるのでループは終了するということになります。

 

道具の選定 其の三

 ところで、敵の手はどうやって決める?という問題がありました。普通に考えればランダムに出すのがゲームとしては親切でしょう。

 

 C#のライブラリにはRandomクラスがあるので、それをつかって1から3までの乱数を出します。それによって、列挙体から手を選ぶという方式になります。 

Random rnd = new Random();

 

 rndはインスタンスです。手の形に振り分けられた数字は1から3なので、rnd.Next(1, 4)とします。これにより、1から3までの整数がランダムに生成されます。

で、今回入力された整数にしたがって、手の形を返す関数を作りました。それに乱数を入力します。

enemyHand = DecisionHand(rnd.Next(1, 4));

これでランダムにNPCの手を決めたことになります。

 

ロジックを組み上げる

 概略図で示したようなロジックを考える作業です。コードを見ながらの方が説明しやすいので、コードは随時示していきながら、どういう風にロジックを組み上げていくかを考えていきます。コードの冒頭はコチラです。enumを最初に書いてます。

f:id:miur-us:20171001220332p:plain

 

まずは、敵の手を決めます。それについては具体的な内容は先に書いたとおりです。

 

 次にプレイヤーの手を決めます。数字キーを押してもらい、そこから整数を取得して、手を決定するための関数に入力します。

f:id:miur-us:20171001213837p:plain

 それがその関数です。HandForm列挙体を返します。(行数からも分かるとおり、一番下に記述しています。)switch文で入力された数字に基づいて対応した手の形を返す、という構造です。

 ちなみに数字のキーボードに振り分けられた数字は1のキーで49、2のキーで50ということになっているので、数値化する際は48を引かないとダメです。

f:id:miur-us:20171001214237p:plain 

 その後は、実際に手の形を互いが見せ合って勝負するのですが、何もせずに画面上に表示されると、入力した瞬間結果が見えるのでジャンケンらしくなりません。

 『じゃん!けん!ぽん!』というコールとリズムがなによりもジャンケンらしさを生みます。なのでThread.Sleepを使って、リズムを表現しています。コール部を再現するためのものが、上部写真のしたの方のコードになります。

Thread.Sleepを使うにはusing System.Threadが必要です。)

 

f:id:miur-us:20171001214919p:plain

 その後、瞬時に互いの手を表示させますが、色が着いていた方が見やすいので、Console.ForegoudundColor = ConsoleColor.Redという風に文字の色を変えます。

 見やすいインターフェイスというのは、実際のUnityでゲームを作る上でも大事なわけで、こういう細かな気配りの重要性を改めて感じます。

 

そして、いよいよ勝負の判定です。

 二人の場合、その手の組み合わせは9通りになります。なので見易さからいってもswitich文を二つ使って羅列するのがいいのかなと判断しました。

f:id:miur-us:20171001215840p:plain

 ここはもう愚直に書いているという感じで、本当ならもう少し短く書ける工夫があるのかなと思いますが、ひとまず。結果の判定文とスコアの処理をしています。アイコの場合は、スコアは動かさず無効試合となります。

 

 ここまでがいわゆる1ゲームの流れで、while文の中身になります。前述したようにどちらかが三回勝つまではこの流れが延々と繰り返されます。最初に貼ったGIFは自分が上手いことストレート勝ちしていますが、普通はけっこう続きます。

 

ループを抜けたら、最終的な勝者を判断して、勝者を称えます。

f:id:miur-us:20171001220813p:plain

  ループを抜けた時点では、どちらかのスコアが3を超えたという判断しか行っていません。なのでプレイヤーが勝ったかどうかを判断し、勝者の宣言をします。

 

コードを書く!

 実際のプログラミングの5つの手順の最後は、実際にコードを書く!ということになりますが、前項にてコードがあった方が分かりやすいのでそっちで出しちゃってますので、ここは省略します。

 

 要はコードを書くということは、コレまで書いてきたような作業を経て、初めて取り掛かれることであり、つまりはプログラミングという作業全体のうちの一部に過ぎないと言うことです。

 

 これは本ブログでは度々書いていることですが、今回考察したプログラミングはどういう作業で、どんなことを考えないといけないのか?ということは市販の本にはほぼ書かれていないことです。なんでなんですかね?やっぱちゃんと説明するのが大変だからでしょうか?自分を含めた初心者が望む説明ってこういうことだと思うんですが。

 

拡張性について

 というわけで、じゃんけんプログラムを作ってみました。がやろうと思えば、いろんな拡張機能が追加できそうです。

 例えば、今回のNPCは完全ランダムですが、プレイヤーが入力した後に自分の手を決めるという仕組みにすれば絶対勝てないゲームに出来ます。(ずるい!)

 

 それは現実的ではないですが、ほぼ完全ランダムゆえそれに気づくと確立論的な戦術をプレイヤーが立てやすくなってしまうので、場合によっては手の出し方を少し偏らせることでプレイヤーを惑わす、そんなAIも作れるかもしれません。

 

 まずそもそも文字だけじゃつまらん!という場合にはGUIアプリを作った方がいいですし、じゃんけんと言えども試せることはいろいろある!ということになります。

 

まとめ!

 以上でジャンケンを題材にプログラミングの一連の作業、流れを考察してみる!ということをやってみました。やっぱ丁寧にやるとなると、ジャンケンですらかなりの文量になりますね。でも、実際こうした記事を書いてみると、プログラミングをするにはどういう風に考えないといけないかを改めて考えることが出来てよかったです。