FreelyApps

個人によるアプリ開発の日記です。アプリの収入だけで生活できるようになるのが目標です。UnityでAndroid向けのゲームアプリを作成しています。


    ブログを
    https://freelyapps.net/
    に移転する予定です。
    リンク切れがある記事はこちらに移動した可能性もあります。

    カテゴリ: ゲーム

      このエントリーをはてなブックマークに追加 Clip to Evernote
    ゲーム開発は時間がかかります。やみくもに作ってみると、完成しなかったり延期になったりするのが普通です。開発時間の長い規模の大きいものほどそれは起こりやすいです。長い時間を管理するのは難しく、せいぜい把握できるのは数日くらいです。

    ゲームを作るときに数週間先に何の作業をやっていて、どれくらい完成しているかという予想ほど役に立たないものはありません。予定というのは目標であると理解してください。あなたがゲームを作ったことのないスポンサーだったら、「なぜ予定通りに進まないのか」と憤慨することでしょう。それはゲーム開発における予定というのがあやふやなものだからです。
    通常、予定というのはやるべきことが分かっています。 多くの場合、同じ作業の繰り返しです。したがって、1回の作業にかかる時間がわかるにつれてどれくらいの時間がかかるのかがはっきりしてきます。また、過去に行ったことであれば予定が立てやすいでしょう。わかりやすい例で言えば、事務作業です。定型的な作業であり、同じようなことを繰り返すものです。作業同士が関係が希薄になっているというのも重要です。これとこれは順序立ててとかセットであるというように関係があると、制限がつくのでやりにくくなります。
    やるべきことが明確でなく場当たりてきな対処の連続であり、過去の成果に影響され続けるというのがゲーム開発です。このような特性はスケジュールを立てるということに対し無理があります。おおまかな予想と少し先のことをどうするか決めるのが現実的なところでしょう。

    開発の初期はゲームは動きません。困ったことにゲームの一連の流れを確認できるのは始まってからずっと先のことです。こういったものを作りたいという仕様があり、実装できたのが1カ月後ということも普通です。その時に確認してみると、微妙なものになっているということもあります。他の部分の挙動の変更や予定通りにできなくなってしまったことがあったというように原因は様々です。当然これでは無意味な作業だったことになり、作り直しとなります。
    今あるゲームに何をすれば面白くなるのかというのは、ある程度形になってから最後まで悩まされ続けます。この通りに作れば面白くなるということは大抵ないです。最初から言うとおりに面白くはならず、ちょっとずつ加えたりなくしたり変更したりして、徐々に面白くなることが多いです。試行錯誤というのはスケジュールを遅延させます。品質のためには必要だと思いますが、非常に時間がかかることを許容できなければなりません。

    ゲームを作るのが難しく、またそのスケジュールを立てるのが難しいというのも理解できると思います。やるべきことがわかり、それが細分化されていくことでスケジュールは正確になります。細分化は一人で数日以内で終わる量の作業という程度までわけると見積もることができます。実際の作業はイラストを描いたり、BGMを作成したり、プログラムしたりと専門の人が見積もることになります。大きすぎる単位では見積もりができずあてにならないものになります。

    もしチームなど複数の人数で組んでゲームを作るなら、スケジュールの管理をあまり厳しくならないようにした方が良いです。スケジュールの管理を厳しくすることは、単純にやれることを減らしていくことになるだけだからです。
    作業にどれくらいの時間がかかるか聞かれた場合は、自分の見積もりの2倍程度(もっと多くても良い。少ないのはまずいです。)申告するのが良いでしょう。その作業に専念することは稀なので、それくらいはかかるものです。

      このエントリーをはてなブックマークに追加 Clip to Evernote
    ゲーム会社に就職してゲームを作りたいと思っている人は、ゲームをしたことがある人なら希望することが多いと思います。そんなわけでゲーム会社に応募する人はそれなりに多いです。会社の規模を考えたら倍率が高いことが多く、新卒なら100倍とかもありえるでしょう。

    ゲームを作りたいという人が多い(少なくともゲームが嫌いだと言う人はゲーム会社にいない)ため、仕事がきつい割に待遇が悪いです。この待遇というのも外からわかりづらいというのも問題です。
    内部にいる人に聞く機会があったら、必ず聞いておいた方が良いことを挙げてみます。
    • 給料
    • 残業時間
    • 休日の労働
    • 有給休暇の使用率
    • 職場環境
    とりあえず上記のことは聞いておくべきです。

    基本的にゲームというものはおもしろくさせるためにあるものなので、どう作れば良いという決まった方法がありません。工業製品でもありながら、芸術作品的な性質も持つものです。作ってみておもしろくなければ、やり直しとなります。それを繰り返しやすいので、働く時間は増えていきます。働く時間が増えると、健康に対する悪影響は加速度的に上がりますが、給料は大した割合では増えません。仮に給料が倍になったとしても、残業が100時間を超えるような労働を続けるのは割に合いません。(人によっては死にます。若いころは体力があるから大丈夫と言っていてもダメージは蓄積しています。視力だったり、腰だったり……)
    給料を聞くといっても「年収はいくらですか?」と聞いても気分を悪くさせるだけなので、「成果に見合った報酬を得られていると感じるか」とかでうまく聞きだしましょう。

    休日に働くというのは何の言葉遊びなのだろうかと思います。おかしくなってしまった人は、何連勤なのかを自嘲気味に自慢し始めます。

    日本は有給休暇の消化率が悪いそうですが、ゲーム会社もそうです。取ると他の人に迷惑だとか、作業が滞るだの言って取らない人が存在しますが、そういった人がどれくらいいるのかというのが大事です。そのような人が大勢いると非常に面倒です。有給休暇は働かないで給料がもらえる日です。使わないというのは実質給料が減っているのと同じです。手元に残るお金が減っているのではないため、なくなってもあまり文句を言う人がいないのかもしれません。

    職場環境は外部からは最もわかりづらいことです。具体的な例を質問するとかである程度は把握できるでしょうが、正確なことはわからないです。雰囲気が暗いとかは、現場に行ってみないとわからないことです。

    ゲームが好きだから、ゲーム会社で働くというのは素晴らしいことだと思います。ただ、ゲームが好きでもその会社が好きになれるかは関係ないです。
    知っておいた方が良いのは、労働条件を悪くしても人が多く集まってくる会社は労働条件を悪くすることがほとんどだということです。会社は営利目的なので、人件費を安くするというのが多くの経営者の考えるところだからです。(ごく稀に従業員の待遇を良くすることで生産性を上げるという経営者もいます。口だけの可能性もあるので、数値で見て待遇を良くしているか判断することが大事です。)

    最後に私の経験を元にした主観が入っているので、絶対に正しいとは言いません。異なる意見もあるでしょうし、それが正しいとも思います。

      このエントリーをはてなブックマークに追加 Clip to Evernote
    ゲームは一般的にセーブが存在します。セーブとは何らかの方法でメモリにある情報を保存する仕組みです。
    プログラムはメモリの情報を見て動作するので、通常は前回の実行には全く関係なく実行されます。プログラムの実行を終えたら、メモリの情報は破棄されます。メモリから情報が消されるので、再開とかは不可能なわけです。電源を落としたら最初から遊ぶようなゲームはごく普通のことなのです。

    そうはいっても今のゲームは続きから遊べるようになっています。以前遊んだステージをクリアしていたり、取得したアイテムを持っていたりするのが普通です。これは前回までのことが記憶されているということです。
    メモリに保存ができないなら、どこか別のところに保存すればいいということでセーブというものがあるのです。セーブにメモリのデータをしまっておいて、次のときにセーブからデータを読み込んでメモリ上に復元します。そうすると以前の続きから遊べるようになります。

    セーブの仕組みは端末によります。PCで言えばテキストファイルかバイナリファイルを実行ファイルのあるフォルダに作るとかになります。
    このデータをセーブ(データ)とも呼んだりするので、セーブが機能を表しているのか実体としての保存されているデータ形式を表しているのかを気をつけなくてはいけません。
    セーブデータを作る機能は扱う端末によりわかれます。ファイルの読み書きなどはOSに依存する低レベルの処理なので、かなり面倒なものです。このあたりは取り扱いが非常に面倒でありゲーム内容に依存しにくいことなので、ゲームエンジンには端末ごとの処理を書かずに何らかのAPIを呼び出すだけでセーブができるようになっています。 

    UnityではPlayerPrefsという関数でセーブが作れます。 
    PlayerPrefs.GetIntとPlayerPrefs.SetIntがセットであり、GetIntでセーブからの取得を行いSetIntでセーブへの書き込みを行います。(SetIntは厳密には書き込みではなく、書き込みのときの値を設定しているものです。しかし書き込みと考えていても基本的には問題ありません。)
    PlayerPrefsはキーバリュー型の保存方法であり、簡単に使うことができます。キーは文字列でGetInt、SetIntで同じ文字列を使うことでキーに対応する値(バリュー)を読み書きできます。
    別の値を表すのにも関わらずキーが同じものを用いてしまうと、値が上書きされます。エラーが発生することはないようです。SetFloatやSetStringで同じキーを用いても問題なく動作し、最後に呼ばれたものだけがセーブに残るみたいです。

    PlayerPrefs.SetInt("test", 100);
    PlayerPrefs.SetFloat("test", 0.5f);
    PlayerPrefs.SetString("test", "hello");
    というように同じキーで3回セットを呼んでいますが、3つ目のみがセーブされます。この後にPlayerPrefs.GetInt("test")を呼んでも、デフォルト値の0が返り100が返ることはありません。保存する型が異なってもそれらはキーによってしか区別されないということに注意が要ります。
    PlayerPrefsを使う時に最も重要なのは、意図せずキーを重複させないということにつきます。実はセーブにデータ(キーとバリューのペア)が存在してなかったみたいなことが起きても、PlayerPrefsのGet系の関数はデフォルト値を返すためにバグに気付きづらいのです。デフォルト値をいじれるので、明らかな無効値を返すようにしてしまうとかがバグを防ぐ唯一の方法な気がします。その方法も無効値が存在しないデータだと検出できないです。名前の通りキーの取り扱いにはご注意をということなら、良いネーミングセンスです。

    PlayerPrefsを直接呼び出すことで非常に簡単にセーブ機能が作れますが、セーブが大きくなってくると管理クラスなどを作った方が良いでしょう。

    オートセーブを使うゲームの増加によりユーザーにはその存在がわかりにくくなっていますが、 開発者にはセーブの存在は大きいままです。セーブに関する話題は結構あって、正解ってなんだろうかと考えさせられます。

      このエントリーをはてなブックマークに追加 Clip to Evernote
    多くのゲームでは対戦相手がいるはずで基本的にはその行動をプログラミングしなければいけません。この行動処理をゲームではAIと呼んだりします。

    実のところAIは考えているわけではなく、決まった処理を行っているだけです。ルール上決まった行動を自分の置かれた状況に合わせて実行することで考えているように見えるのです。状況というのはゲーム内で知れる情報の集まりです。自分の持っている手札であったり、すでに捨てられたカードが何かといったものです。イカサマがありなら、本来知りえない情報も追加できます。(個人的にはつまらないのでやめた方が良いと思いますが、強くするのが簡単でしょう。)
    状況が決まったら、あとはひたすら状況ごとにどうするかを書いておけば良いです。大富豪とかなら、自分の番であり最後の一枚を持っていて出せる状況であれば、とにかく出すべきです。そういったことをプログラム的に表現していくと大量のif文とswitch文によって場合分けしていけば良いでしょう。
    この場合分け(状況の種類)が多くなると、細やかな対応が可能なためAIがより人間らしく強くすることができます。場合分けが少ないと同じ行動を取りやすくなるので、なるべく状況を細かく分けるのが良いです。

    上に書いたことは言うのは簡単ですが、やるのは非常に難しいです。まずゲームのルールを熟知しなくてはなりません。どのようにしたときが最も良いのか、どうすることが悪いのかがわからなければ勝つための行動を作ることはできないからです。 
    特にゲームの序盤などは情報が少ないためにどういった行動をとるべきかは作り手の考えに大きく左右されることでしょう。終盤は取れる選択肢自体が少なくなることが多いので、そこまで悩むこともないはずです。

    こういったAIは固定された行動をとります。処理は早いし、プログラムの更新でAIが変更できるのが利点です。現在までのゲームではほとんどのゲームがこのような方法で作られています。

     

      このエントリーをはてなブックマークに追加 Clip to Evernote
    以前、同じ内容で記事を書いたのですが、より良い方法がUnity5.3では行えるようです。

    rn-custom_coroutine
    Unity5.3で新しく使えるようになったカスタムコルーチンというものを使います。 公式の説明を見るとCustomYieldInstructionクラスを継承して、keepWaitingプロパティのgetをオーバーライドすれば新しいyieldオペレーションが作れます。
    yieldオペレーションとは、yield return ~とするときの~の処理のことを言っているのだと思います。(この記事ではそうだと思って書くことにします。)
    keepWaitingがtrueであればyieldオペレーションが処理を返さず継続し、falseになると処理を抜けます。このプロパティにDebug.Logを仕込んだところ毎フレーム呼ばれていたので、コルーチンで無限ループ内にyield return 0;というような書き方で行うのと同じと考えて良いでしょう。

    以前の方法のあまり良くない点は、処理をクラス内に書いていなければいけなかったため、あるクラスのstaticメソッドにするかクラス内での利用しかできないようになっていたことです。色々なところから自由に呼び出すということを考えると、その処理は独立した1つのクラスになっている方が見通しが良いのでそうすべきだと思っていました。
    メソッドに処理がある場合は、呼び出し方がStartCoroutineを介するというのもいまいちだと思います。StartCoroutineを使うと、渡すパラメータの個数の制約があること、わずかにコードが増えること、文字列での呼び出しだとエディター上で編集しにくいことが良くないです。
    新たな方法では導入が手間ですが、その後の作業を減らしてくれるため良い方法だと思います。WaitUntilやWaitWhileを使っても同じことができますが、よくある同じ処理をいちいち書くのは無意味なので、以下のようにカスタムコルーチンを作りました。

    上のソースは、ある時間処理を待たせるがスキップも可能であるというyieldオペレーションになります。使い方は
    yield return new SkippableWaitForSeconds(10, () => Input.GetMouseButtonUp(0));
    のようにします。この例だと10秒待つ処理であり、もしその間にマウスの左ボタンが上げられたらスキップするということになります。
    スキップするかの判定を外から渡せるため、色々と使えるようになっています。

    このページのトップヘ