高専を中退してゲームを作っている

 
この記事はKosen Advent Calendar 2015 19日目の記事です。
 
 
 
◇始めに
タイトルの通り、私は今ゲーム制作に携わっている。
職種はプランナー。
 
高専情報工学科に入学したが、3年終了時に辞め、上京した。
ゲームの専門学校に入った後、この業界に潜り込んだ。
 
エンジニアではなくプランナーなので、今はプログラミング等技術的な仕事はやっていない。
だが、高専生活で得たものは今でも役に立っているので、それについて書こうと思う。
 
 
◇勉強
3年までとはいえ、情報科として基本的な勉強はした。
それは少なからず役に立っている。
 
特に、プログラミングの構造や簡単なアルゴリズムを知っていると、バグを見つけやすくなる。
エンジニアが見逃しそうなポイントを突くのが、デバッグでは重要だ。
 
また、スクリプト等のデータを作る場合でも、プログラミングをしたことがあるかないかで、理解度は大きく変わるだろう。
 
プランナーには大きく分けて「エンジニア寄りのプランナー」と「デザイナー寄りのプランナー」がいるが、私は完全にエンジニア寄りのプランナーだし、それに合った仕事をやってこれた。
 
 
◇趣味
高専時代に何に時間を費やしたかと問われれば、間違いなくゲームと答えるだろう。
授業中に、休み時間に、寮で、友達の家で。
 
色々なジャンルの、色々なゲームで遊んだことは、ゲームプランナーとしての大きな糧となっている。
むしろそれが無ければ、私はポケモンスマブラしか知らないままだったかもしれない。
 
ちょうどニコニコ動画が流行り始めた時期でもあり、動画編集にも手を出した。
ファイル変換や画像・音声編集などは、直接仕事に役立っている。
 
反対に、アニメやラノベには全くハマらなかった。
なので今でも声優をあまり知らず、時々不便である。
 
娯楽であるゲームを作るならば、様々な娯楽に触れることは大切なことだ。
 
 
◇集団生活
高専で最も鍛えられた事。それは集団生活の術である。
私が通っていた某高専は一年生は全員寮に入ることになっており、先輩と同じ部屋で暮らした。
 
食堂も風呂も学年ごとに区切られ、一年時は窮屈な思いをした。
門限なども厳しく、自習時間もあったし、夜には電気が全部消された。
 
寮生活は大変だったが、その分友人達と仲良くなることもできた。
夜遅くまでレポートを書いたり、鍋いっぱいのスパゲティにレトルトカレーをかけて食べたりしたもんである。
 
そして更に集団生活を鍛えるものがあった。
それは挨拶運動と応援団である。
 
一年生は伝統として、朝礼後に校庭に集められ、大声で「おはようございます!」を繰り返す。これが挨拶運動だ。
四年の先輩が監督しており、ちゃんと声が出ている人から順に開放される。
 
これが苦痛で苦痛で仕方なかった。体罰に近い。
喉が枯れてもOKが出るまでは繰り返さなければいけない。田舎ならではの風習と言えよう。
 
応援団は体育祭で演舞を披露するのだが、その練習を3ヶ月くらいやる。
毎日放課後暗くなるまで、休日は一日中練習している。
 
応援団も上級生と共に行うので、嫌でも協調性が養われる。
このような体育会系スピリッツは工業高専では珍しいのでは無いだろうか。
 
ゲーム制作を独りで行うことは稀だ。
どうしても他人とのやりとりが必要になる。
 
特にプランナーはコミュニケーションが重要になる。
私は高専生活のおかげでそれが苦ではなくなった、と思う。
 
 
◇友人
三年間通った高専で得たもので、最も役に立っているのは友人である。
このアドベントカレンダーを教えてくれたしゃのんはもちろん、今でも遊んでくれる人々は本当に貴重だ。
 
ゲームを一緒にやったり、テスト勉強をしたり、レポートのまとめを手伝ってくれたり、カルピスソーダを奢ってくれたり、寒空の下でラーメンを食ったりしてくれた彼らには感謝してもしきれぬだろう。
 
私は一足先に上京し、社会人となったが、今では多くの元クラスメイトが東京や全国で働いている。
私も彼らに負けぬように、日々働いていこうと思う。
 
 
◇最後に
長々と書いたが、私がこの業界に入れた理由は簡単である。
高専出身なら数学得意でしょ?」と言われて面接を通り、メダルゲームの開発に携わったのである。
 
つまるところ、高専に行ったことそのものが、私が今こうしてゲームを作っていられる全てなのであった。
 
平凡な少年が、平凡なままプランナーをやるのは中々難しい。
だから何かに特化した方がいいし、そのためには高専はピッタリな場所では無いかと思う。
 
でもやっぱり、ちゃんと卒業はしておいた方がいいよ。
 

久々の冬考

日々寒くなって冬が近付くにつれ、考え事をすることが増えてきた。

昔何かで読んだのだが、冬は計画的な犯罪が増加し、反対に夏は衝動的な犯罪が増加するらしい。
別に犯罪を計画している訳では無いが、確かに冬は物思いが捗るようだ。

何かと整理したくなるのも冬だ。
web上に転がってるアカウントを整理したくなったり、メールもそろそろ仕分けたくなったり、要らないものは捨てたくなったりする。

このように、何ヶ月も書いてないブログを更新するのも、冬だからです。

タッチイベントをforループで作った場合

最近は勉強も兼ねてjavascriptを触っている。

 

今日試したのは以下の文。

for(var i = 0; i < 16; i++){

   document.getElementById('id'+i).addEventListener('click', function() {

      checkPosition(i);

   });

}

 こんな風にしたときに、関数に渡したiが上手くいかない模様。

要はそのidがタッチされたらその位置を調べて欲しいんだが、良く分からない状態になっている。

 

コンソールに表示してみたら、i=16になっていた。

なんじゃそりゃ。

 

横着せずに1つずつタッチイベントを作るべきか。

 

フレーム毎の処理、衝突時の処理

またメモ。

 

◇フレーム毎の処理

init()内

this->schedule(schedule_selector(HelloWorld::maiFrame));

 

こうすると、フレーム毎にHelloWorld::maiFrameが呼ばれる。

(綴りはわざとね

 

キャラがゴールに到達したときの判定や、時間を測りたいときなんかに。

秒数指定も出来るので、一定間隔で処理させることも可能。

 

 

◇衝突時の判定

init内

auto contactListener = EventListenerPhysicsContact::create();

contactListener->onContactBeginCC_CALLBACK_1(HelloWorld::onContactBegin, this);

this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(contactListener, this);

物理演算世界で使用。

物体がぶつかるとHelloWorld::onContactBeginが呼ばれる。

 

bool HelloWorld::onContactBegin(PhysicsContact& contact)

関数の頭はこんな感じ。

PhysicsContact型というのに色々ステータスが入っているのだろうか。

 

ちなみにこれだけではここまで来ない。

衝突時に処理させたい2つのパーマネントに以下の仕込みを行う。

 

pBall1->setContactTestBitmask(1);

pBall2->setContactTestBitmask(1);

こうすると衝突時にHelloWorld::onContactBeginが走る。

ただし、物理的にはぶつからなくなる様子。

ボールがすり抜けてしまう。

 

解決策知ってる方いたら教えて。

 

タッチ処理や物理演算絡みメモ

◇タッチ処理

init内

auto listener = EventListenerTouchOneByOne::create();

listener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);

this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);

この辺誰かに解説してほしい。

「listener」(りすなー)はタッチイベントを受信している様子。

で、タッチ開始時(onTouchBegan)に「HelloWorld::onTouchBegan」を呼ぶように仕込まれている?

最後に現在のシーンにイベントとして追加されているのかもしれない。

違ったら誰か教えて。

 

関数側

bool HelloWorld::onTouchBegan(cocos2d::Touch* pTouch, cocos2d::Event* pEvent)

「pTouch」にはタッチした位置が入ってくるはず。「pEvent」は何やろうね。

 

 

◇壁や床の作成

void HelloWorld::wallsCast()に分離。

 

PhysicsBodyは一つのパーマネントに一つ作った方が良いようだ。

使い回そうとしたら当たり判定消えた。

 

auto material = PHYSICSBODY_MATERIAL_DEFAULT;

こっちは使い回せた。

 

 

◇ボールの作成

球状の当たり判定。

auto pBall = PhysicsBody::createCircle(10.0f);

数値は半径。

球状に色塗りは出来ないため、別途pngを用意。

 

上手く飛ばすため

pBall->setMass(1.0f);

で重さを追加。

 

ball->setTag(1);

タグを仕込んどくと幸せになれる。

 

 

◇ボール動かす処理

 onTouchBegan内

Sprite* ball = (Sprite*)this->getChildByTag(1);

これでさっきタグをセットしたボールを呼べる。

 

ball->getPhysicsBody()->applyImpulse(force);

ボールに「force」分の力積をかける。

連打でボールが吹っ飛ばないように、位置を見てforceを0にしてみた。

あまりスマートでは無い。

 

 

◇クリア処理

ボールがある位置よりも下に行くとクリアに。

 

auto *retryLabel = MenuItemFont::create("Retry", CC_CALLBACK_1(HelloWorld::menuRetryButton, this));

リトライ用ボタンを作る。

「Retry」という文字。

押されると「HelloWorld::menuRetryButton」を呼び出す。

 

auto menu = Menu::create(retryLabel, NULL);

上記ボタンは「MenuItemFont」を使用しているからか、このMenuの中に入れて表示する様子。

ただし位置はretryLabelにセットする。

 

 

◇リトライ処理

menuRetryButton内

Director::getInstance()->getEventDispatcher()->removeAllEventListeners();

auto gameScene = (Scene*)HelloWorld::createScene();

Director::getInstance()->replaceScene(gameScene);

 全てのイベントを一度抹消。

「gameScene」に最初のシーンをセット。

そして最初のシーンに移動。

 

 

 

いつもの通り中途半端。

ver3.0 iOS