地方学生の就活について(ゲーム業界編)
DSLアドベントカレンダーに記事を書いて欲しいと頼まれて、ついOKしてしまいました。というわけで12日目の記事になります。
適当に「猫のことでも書いて投稿するよ」とか言って引き受けましたが、
OBが研究や技術に関わること,大学や教育に関わること,学生生活のライフハックなどを投稿します!
というアドベントカレンダーでした。既に卒業した身であり大学にいないし、研究もしてないし、技術的なことはDSLと関係ないようなことしかやってないし…
と悩んでいましたが、他の人が就職活動の話を書こうとしているのを見たので、私も就職活動について書くことにしました。
私は現在とあるゲーム会社でプログラマーとして働いています。私は1社から内定を頂いた時点で就職活動をやめたので、私の就職活動の経験が乏しくあまり参考にならないかもしれませんが、この記事が少しでもゲーム業界を目指す方のためになれば幸いです。
----
DSLアドベントカレンダーの記事であることからおわかりでしょうが、当時の私の居住地は北海道室蘭市です。東京に行くには飛行機に乗る交通費がかかります。
私が就きたい職種はゲーム開発者です。ゲーム開発者が無理なら、その他IT職に就こうと考えていました。
----
私が就職活動を始めたのは情報系の学生としては遅めのM1の2月頃でした。友人が利用していた「逆求人フェスティバル」に登録したのが(ほんのちょっとしたことを除いて)最初の就職活動でした。
今はなくなってしまったのかもしれませんが、当時はゲーム会社の逆求人がありました。このサイトにプロフィールを書いて間もなく、私のプロフィールを見た逆求人フェスティバル運営会社の方がお声をかけてくださり、ゲーム業界逆求人フェスティバルへの参加が決まりました。
会場は東京の両国にあるホテルの一室でした。曖昧な記憶ですが、参加学生は確か20人ほどで参加企業は参加者より少なかったです。学生は長机に並んで座り、興味を持ってくださった企業に5分の自己アピールと20分面談を8回行いました。企業の方が少ないので、余った学生同士で雑談したりもしました。
私は今までにC/C++で作ったゲーム9作品をもとに自己アピールをしましたが、どの作品を重点的にアピールするかを考えておらず浅いアピールになってしまったことが反省点でした。この時は2社に気に入っていただき面接に進むこととなりました。
逆求人フェスティバルはスマホゲームの会社が多かったです。大手コンシューマーゲームメーカーも来ていましたが、サーバーエンジニアやアーケードゲーム人員を求めている感じでコンシューマーゲームの開発者の募集はしていませんでした。最初に面接に進めた2社もスマホゲームの開発を主に行っている会社でした。私はどちらかというとコンシューマーゲームの開発の方がいいと思っていたので、リクナビやマイナビでコンシューマーゲームの開発をしている会社を中心に説明会を探して参加予約をし始めました。この時期(2月3月らへん)からでは最大手クラスのコンシューマーゲームの募集には間に合わない場合がほとんどでした。私はそういった会社に入るのは無理だと思っていたので、手遅れでもあまり気にしませんでしたが、困難でも挑戦してみるべきだったと思います。なので就職活動を始めるのはお早めに。
どちらかというとコンシューマーゲーム開発を希望していますが、スマホゲーム開発も視野に入れていたので逆求人フェスティバルにも複数回参加しました。
説明会はまず交通費が出ませんし、一時面接も交通費が出ない会社がほとんどです。なので、一度東京に向かったときに複数社の説明会や面接に行くことは必須だと思います。有り難いことに逆求人フェスティバルは交通費の支給があったので、逆求人フェスティバルに行く足で説明会や面接を受けることで交通費を浮かせました。まあ、全ての説明会や面接と逆求人フェスティバルを合わせることはできませんでしたが、なるべくまとめていけるように日程を組みました。
逆求人フェスティバルに参加したのが最初の就職活動だったため、就活序盤はスマホゲーム会社数社の面接を続けて受けていました。今思えば技術者としての活躍が期待されていたであろう会社に、ゲーム作りへの熱意や今までの成果を中心にアピールしてしまったり、今思えば人の繋がりを重視しているであろう会社に、ゲームでどのように楽しませるかという視点で答えてしまっていたりと散々であり、なかなか二次面接へ進めませんでした。
それと平行してコンシューマーゲーム会社の説明会に参加したり筆記試験を受けたりしました。とある会社が第一希望だったのですが、採用人数が3人程度なのに対して説明会に20人以上の人が集まっており、最大手クラスでなくともこの業界に入るのは厳しいのだと痛感しました。その会社の一次面接では、第一志望になった理由がある会社なのでミスマッチなくアピールできましたが、バカ正直に質問に答えてダメなところが出て落ちてしまったと思いました。そこで危機感を覚えて、とにかく参加できそうな説明会はひたすら参加し、説明会に参加できなくともエントリーするようにしました。
しかし、嬉しいことに予想が外れて第一志望の1次面接に受かっていて、2次面接にもトントン拍子で受かりました。
まとまってなくてすいません。アドベントカレンダーの日付ギリギリなので一旦投稿します。後日追記します。たぶん。
ゲーム作りでImageクラスを活かす
本記事は Siv3D Advent Calendar 2017 24日の記事です。
SIv3Dで画像を描画するにはTextureクラスを使用しますが、これとは別に画像を扱うImageクラスがあります。Imageクラスはそのまま画面に描画することはできませんが、画像を編集することができます。本記事では、ゲーム制作でImageクラスを使用したことについて書いていきます。
マップチップを用いたマップ描画
私が今年の大学祭で展示したゲームでは、マップチップを敷き詰めてマップを表示しました。
これの最も単純な実装は、マップチップ一つ一つテクスチャで描画する方法です。
# include <Siv3D.hpp> void Main() { Window::Resize(1280, 720); const int MAPCHIP_SIZE = 32; // マップチップのサイズ Array<Texture> mapchipTextures = { Texture(L"ground.png"), Texture(L"wall.png")}; Grid<int> map; CSVReader reader(L"map.csv"); // 床を表示する箇所に0, 壁を表示にする箇所に1が書かれたCSV map.resize(reader.columns(0), reader.rows); for (unsigned y = 0; y < reader.rows; y++) { for (unsigned x = 0; x < reader.columns(0); ++x) { map.at(y,x) = reader.get<int>(y, x); } } reader.close(); while (System::Update()) { for (unsigned y = 0; y < map.height; y++) { for (unsigned x = 0; x < map.width; ++x) { mapchipTextures[map.at(y, x)].draw(Point( x * MAPCHIP_SIZE, y * MAPCHIP_SIZE ) ); } } } }
しかし、この方法では一度に大量のテクスチャを描画することになってしまいます。私のゲームでは、1280*720の画面に32*32のサイズのマップチップでマップを描画したので、マップの表示に880つのテクスチャを使用することになります。さらに、16*16のサイズのマップチップを拡大して32*32のマップチップとして使ったり、アイテムやキャラクターを合計200個以上出したりしたので、この方法では処理が重くなってしまいました。
この問題は、プログラム上で画像を編集し、マップを1つのテクスチャで表示することで解決しました。これにImageクラスを使用しました。
以下のようにImageクラスのoverwrite関数を使うと fuga という画像の{ 10,10 }の位置に hoge という画像を描き込むことができます。
Image hoge, fuga; hoge.overwrite(fuga, { 10,10 });
この要領で、マップを1枚の画像に書き込み、その画像からテクスチャを生成することでマップの描画回数を880回から1回まで削減することができました。
# include <Siv3D.hpp> void Main() { Window::Resize(1280, 720); const int MAPCHIP_SIZE = 32; Array<Image> mapchipImages = { Image(L"ground.png"), Image(L"wall.png") }; CSVReader reader(L"Map.csv"); // 床を表示する箇所に0, 壁を表示にする箇所に1が書かれたCSV // このImageにマップ画像を描き込む Image mapImage(reader.columns(0) * MAPCHIP_SIZE, reader.rows * MAPCHIP_SIZE); for (unsigned y = 0; y < reader.rows; y++) { for (unsigned x = 0; x < reader.columns(0); ++x) { mapchipImages[reader.get<int>(y, x)] .overwrite(mapImage, { x * MAPCHIP_SIZE, y * MAPCHIP_SIZE }); } } reader.close(); Texture mapTexture(mapImage); // Imageからテクスチャを生成する while (System::Update()) { mapTexture.draw(); } }
ゲーム作成で大量の画像を表示にする際は、Imageクラスの存在を思い出すとゲームのパフォーマンスを向上させることができるかもしれません。
ちなみに、私が大学祭で展示したゲームはこちらです。4人対戦用ゲームで、ゲームパッド4つの接続を前提としております。
ux.getuploader.com
背景が透過されていない画像を扱う
Siv3Dでは、背景の透過色を指定して透過させて表示することはできません。なので、特定の色をプログラム側で透過することを想定して作られている、背景が透過されていない画像をそのまま使うことができません。
しかし、Siv3Dは画像自体を容易に編集することができます。画像にピクセル単位でアクセスできるので、
という操作をすることで簡単に背景を透過させることができます。
ダイアログで開いた画像の背景を、上記の手法で透過させるプログラムが次になります。
# include <Siv3D.hpp> void Main() { // 画像を開く Image image = Dialog::OpenImage(); if ( image.isEmpty ) { return; } // 画像の左上の点を背景色とする const Color background_color = image[0][0]; // 背景色と同じ色のピクセルのアルファ値(不透明度)を0にする for (Color& pixel : image) { if (pixel == background_color) { pixel.a = 0; } } // ダイアログで保存するファイル名を決定 const Optional<String> save = Dialog::GetSaveImage(); if ( !save.has_value() ) { return; } const FilePath filepath = save.value(); image.save(filepath); }
しかし、一つ一つ保存するのは大変なので、ドロップされた画像を変換するように改造したのが次のプログラムです。拡張子はPNG, 保存場所はConvertedという名前のフォルダ内としています。
void Main() { Window::SetTitle(L"ドロップされた画像を透過PNGに変換します"); while (System::Update()) { // 何かがドロップされたら if (Dragdrop::HasItems()) { // ドロップされたすべてのアイテムを取得 const Array<FilePath> items = Dragdrop::GetFilePaths(); for (const auto& item : items) { Image image(item); const Color background_color = image[0][0]; // 画像の左上の点を背景色とする for (Color& pixel : image) { if (pixel == background_color) { pixel.a = 0; // 背景色と同じ色のピクセルのアルファ値(不透明度)を0にする } } // 保存ファイル名を決定 String pictureName = item.substr(item.lastIndexOf(L"/")); Println(pictureName); const String saveFilePath(Format(L"Converted", pictureName.substr(0, pictureName.lastIndexOf(L".")), L".png")); image.encodePNG().save(saveFilePath); } } } }
本記事では、背景を透過させた後に画像として保存する例を載せていますが、当然背景を透過させてからテクスチャを生成することもできます。
この手法の問題点は、画像の左上の点が背景でない場合に対応できないことです。私が使用した画像ではこのようなことが起こりませんでしたが、もし左上の点が背景じゃない画像を処理するならば、背景色の取得方法に工夫が必要になります。
この背景透過処理プログラムは、このゲームの敵キャラクターのために作成しました。
ux.getuploader.com
今年作ったゲーム( 2017 )
この記事は、 Muroran Institute of Technology Advent Calendar2017 21日目の記事です。
今年完成させられたゲームについて書いていきます。
魔導銃士ジュノと囚われの姫君
2月21日~3月7日 / WOLF RPGエディター / アクションゲーム
ウディフェスというWOLF RPGエディター(以下ウディタ)の作品を投稿するお祭りが、去年まで開催されていました。友人とウディフェスに出すことを目標にゲームの開発を考えていたのですが、それが叶わないままウディフェスは終了してしまいました。その友人達と、身内限定公開のウディフェスのようなものを開催することとなりました。この企画に向けて制作したのが「魔導銃士ジュノと囚われの姫君」です。
この企画の開発期間は2週間しかありませんでした。そこで、2週間で作ったと思えないゲームを作り、友人を驚かせてみたいという思いで制作しました。当時ウディタ正式版では未対応の16:9の画面にする、RPGのように戦闘が始まるが戦闘はアクションゲームにする、クオリティの高いキャラクターイラストを使う、短い開発期間で複数のダンジョンと複数のエネミーを作る、などしました。
その後しばらくこのゲームは公開しませんでしたが、そのことが幸いしてWOLF RPGエディターコンテスト(以下ウディコン)の応募条件である「未発表のWOLF RPGエディター製のゲーム」を満たしました。応募条件を満たしているので、記念に応募してみたら思った以上に好評でした。総合順位は65作品中39位でした。私自身が思っているよりも、このゲームは高く評価されたので少し自信を持てました。
あと、来年ウディフェスが一度だけ復活するらしいので、是非参加したいなと思ってます。
騎士と魔物の山道
2016年下旬 & 2017年3月10日~3月13日 / Siv3D / ローグライクゲーム
去年の秋頃、他の人のローグライク制作の話を聞き、私も作りたくなったことが制作のきっかけです。ローグライクゲームの開発を経験は全く無かったので、手探りで1つ1つ機能を作っていきましたが、途中で飽きて制作を中断してました。しかし、基本的な部分は幾つか機能しているので、今年の3月頃に画像・音声・ストーリーを追加して完成としました。また、私が所属しているサークルの新入生勧誘で展示しました。
ゲーム内容はランダムに生成される10階層ダンジョンを抜ければクリアの短編です。敵は2種類、アイテムは3種類、レベルアップの概念はないです。
【ダウンロード】
±ZERO
4月4日~7月16日 / WOLF RPGエディター / パズルゲーム / 共同制作
「離れた状態で一定歩数歩いたら死ぬ設定の2人のキャラを操作して、仕掛けのあるステージをクリアするパズルゲーム」という構想が去年からありました。このゲームを完成させるには、ステージをたくさん作る必要があることがネックでした。そこで、友人たちの力を借りれば完成させられるだろうと考え、ウディコンに向けて開発を始めたのがこのゲームです。
制作メンバーは、私がシステム全般を担当し、マップ作成が( 私を除いて )5人、シナリオ1人、キャラクターイラスト1人の計8人。フリーゲームとしては大規模な開発だったと思います。しかし、制作メンバーのほとんどがウディタを触ったこともない人でした。しかもウディフェスやウディコンにゲーム出した経験があるJumpakuさんはイラスト担当だし…。そこで、私以外のメンバーはあまりウディタの使い方がわからなくても開発できる環境を構築しました。
マップ制作のために、マップチップの配置のみで制作できる環境を作りました。ウディタでは、マップ上にイベントを置き、イベントに接触した場合にギミックが発動するような作り方が一般的であると思います。しかし、この作り方ではマップ制作者はある程度ウディタの使い方を知っている必要があるうえ、制作効率も悪いです。そこで、「プレイヤーが移動した場合、プレイヤーがいるマスのマップチップ情報を取得し、ギミックが発動するマップチップだった場合にギミックを発動させる」というコモンイベントを常に並列で実行させるようにしました。これでマップ制作者はマップチップを配置するだけで、ギミックのあるマップを作成することができます。
シナリオ作成のために、スクリプトで会話シーンを作れるシステムを開発しました。このようなシステムを作ったのは初めてなので、必要となった機能を随時追加する感じでの開発となりました。当初は文章表示とキャラクターの表情変化、背景の変更の機能しか備えていませんでした。小物表示、キャラクターの移動、効果音再生、といった機能は必要になってから後付で追加していきました。結果シナリオ担当がスクリプトで演出するのではなく、「このような演出が欲しい」とだけ書いてもらって、システム担当の私が演出を作るという形になりました。
開発環境を整え、余裕を持った計画を立てたことで期限に余裕を持って完成させることができ、無事ウディコンに応募することが出来ました。結果は19位/65作品となかなか良い結果を残すことが出来ました。
室天堂Smitch
7月末 / Arduino言語 / 謎解きゲーム
今年のオープンキャンパスでは、グループごとに対話ロボットを改造して展示しました。私達のグループは対話ロボットを「ゲームの攻略法を教えてくれるロボット」に改造しました。
その展示のために作ったゲーム&ゲーム機が「室天堂Smitch」です。名前の由来は◯天堂S◯itch。攻略法を教えてくれるロボットの名前は「ナビィ」。ナビが由来であって某時のオカリナの妖精とは一切関係ありません。
本体はArduino Groveにジョイスティック、ボタン、タッチセンサ、液晶ディスプレイを繋いだだけのものです。実際はほとんどNGC氏が作った物で、私は操作しやすいようにボタンやスティックの位置を調整したりしただけです。液晶ディスプレイは文字のみ表示できるもので、表示可能な文字数は16文字×2列。自作の文字を登録できるので人の形の文字やドアの形の文字を作成し、それを表示することでゲーム画面を表現しました。
ゲームの内容は6つのオーブを集めるというものです。操作方法は、ジョイスティックでプレイヤーキャラの移動、決定ボタンで調べる、です。液晶のバックライトの色を変更できるので、「バックライトの色によって仕掛けが解ける」というギミックを入れました。ゲーム内に色のヒントは無いですが、タッチセンサに触れるとナビィちゃんにヒントを求める事ができます。ナビィちゃんは音声でヒントというかほぼ答えを教えてくれます。音声認識でヒントを求めることができるような実装は間に合いませんでした。対話ロボットとは……
実際の展示ではどんなものを作ったのかの説明でほぼ時間が無くなり、実際に遊んでもらえた人が少なかったのは残念でした。
よこどりトレジャーズ
3月28日, 9月9日~9月21日 / Siv3D / 対戦アクションゲーム
私が所属しているサークルでは、工大祭でゲーム展示をおこなっています。今までの経験から、工大祭では対戦ゲームが人気となる傾向があるので、私は4人対戦アクションゲーム制作し展示しました。
その4人対戦ゲームがよこどりトレジャーズです。獲得したコインの枚数を4人競いあうゲームです。弾を撃たれたプレイヤーはコインを落とすので、他の人からコインを奪う事ができます。操作は移動と弾の発射のみです。操作をシンプルにした理由は、工大祭のお客さんは子供が多いこと、ゲームパッドによるボタン配置の違いの影響を出さないためです。
工大祭での人気投票では展示した9作品中1位でした。この作品のみプロジェクターでスクリーンに映していて有利だったこともあるのであまり誇れませんが、子どもたちを楽しませるということは十分にできたと思います。
展示スペースに余裕があったので、「±ZERO」と「魔導銃士ジュノと囚われの姫君」も工大祭に展示しました。±ZEROは全てのステージを開放した状態で展示しました。アクション性がなくゆっくり考えて遊べるゲームとしてそこそこ人気でした。魔導銃士ジュノと囚われの姫君は、工大祭の展示作品として長かったことからかあんまり遊んでもらえませんでした。
【ダウンロード】( 遊ぶには人数分のゲームパッドが必要です )
Dual Cast
11月2日~11月30日 / Siv3D / RPG
Dual Cast は第2回2分ゲーコンテストに応募するノンフィールドRPGです。おそらくこの記事の公開とほぼ同時に公開されると思います。
このゲームは魔導書を2つ組み合わせて唱える魔法で攻撃するシステムのRPGです。魔導書は使ったらなくなり、敵に勝利するか逃げると手に入ります。敵に勝利すると進行度が10%増加し、逃げると10%減少、進行度100%で敵に勝利するとゲームクリアです。
【ダウンロード】