ゲーム的処理を実装する #04
前回で、ゲーム画面を遷移する処理は完成しました。
今回は、各画面の操作内容を保持するような、ゲーム的な処理を作っていきましょう。
カウント処理
この「数える」ボタンを押した時、カウントが進む処理を作っていきます。
// カウント処理 $(document).on('click', '.countButton', function(){ count++; });
以上です。めちゃめちゃ単純。
看板切り替え処理
左右の矢印で、看板をスライドさせて切り替える処理を実装します。先ほどとは打って変わって、めちゃめちゃ苦労しました。
1.まず、html上に看板を二つ用意します。片方にはdisplay: none;
を持たせたstandByクラスを付与し、非表示にしています。
2.左の矢印を押した時、transform: translate(-500px, 0);
という内容を持ったleftSlideクラスを、現在表示している看板に付与します。これで看板は左に飛んでいく。
3.左に飛んだ看板にdisplay: none;
を持たせたtempStandByを付与し、消し去ります。①で出てきたstandByを使わないのは、それぞれを区別するためです。ちなみに、この処理をすぐに行うと、スライドの途中で看板が消えてしまいます。よって、queueメソッドを用いて、時間差でこの処理を行いましょう。
4.standByクラスの付いている看板に、transform: translate(500px, 0);
を持ったrightSlideクラスを付けます。さらに、standByクラスを外します。これで、この看板は画面の右側に隠れてセットされます。
5.rightSlideクラスを外します。すると看板が、右から画面中央に飛んできます。
6.左に流した看板に付いている、leftSlideクラスとtempStandByクラスを外します。さらに、standByクラスを付与することで、①の状態に戻ります。
至極複雑な処理でしたが、実装できた時の喜びも大きかったです。
次の画面に移る時、ここで選択した看板名を保持しておき、次の画面のhtmlに表示させます。
看板記入処理
先ほど保持した看板名が表示されています。ここの処理は単純であり、val()でテキストボックスに入力された数値を保持するだけですね。
結果表示処理
「カウント」「看板名」「看板に記入した数値」、保持しているこれらの値が、正解と同じかどうか、if文で確かめていきます。
一つでも違うものがあれば、失敗。全て合っていれば成功です。結果に応じて、htmlに表示させる文章を変えていきましょう。
端折った部分もありますが、基本的に以上となります。ゲームとしての機能は完成しつつありますのでね。
画面の切り替えを実装する #03
前回は、ゲームを遊ぶための様々な画面を作り上げていきました。
今回は、それらの画面表示を切り替える処理を、実装していきましょう。
こちらはタイトル画面ですね。「スタート」というボタンを押すと
このような、カウント画面に移行するのが理想です。
どのように実装していくか?
まず、スタート画面、ゲーム画面、リザルト画面、それぞれを包括している親要素を、全てdisplay: none;
で非表示にします。非表示であることがデフォルト、という感じですね。
そしてnowShowという、些か適当な名前のクラスにdisplay: block;
を設定し、nowShowが付与された画面が表示されるようにしましょう。
ゲームスタート
$(document).on('click', '#startButton', function(){ $('#startScreen').removeClass('nowShow'); $('#gameScreen').addClass('nowShow'); });
スタート画面でスタートを押すと、スタート画面のnowShowが取り除かれ、ゲーム画面にnowShowが付与されます。
ゲーム進行
ゲーム画面において、上部の「制限時間表示」「検品物詳細表示」と、下部の「次へ」ボタンは、どの段階においても変わらず表示されています。故に、中核となる部分の表示だけをnowShowの移動で表現します。
// 現在nowShowがついてる番号を表示 // 0……カウント画面 // 1……看板選択画面 // 2……看板記入画面 index = $('.nowShow').index('.mainWrap');
mainWrapとは、ゲームの操作を行う画面に付与されたクラスです。ゲームの段階の数だけ、このクラスのついた要素は存在します。このクラスの中でnowShowクラスがついているもの(=現在表示されているもの)が何番目なのか、indexという変数に格納しておきます。
// 次へボタンを押すと次の画面を表示させる $(document).on('click', '.next', function(){ $('.mainWrap').eq(index).removeClass('nowShow'); $('.mainWrap').eq(index + 1).addClass('nowShow'); index++; // 最後のゲームなら、結果画面に遷移 if((index - 1) == 2){ $('.mainWrap').removeClass('nowShow'); $('#gameScreen').removeClass('nowShow'); $('#resultScreen').addClass('nowShow'); } });
nextクラスのついたボタンを押すことで、現在のindex番目のmainWrapに付与されているnowShowクラスを消し去り、次の番号のmainWrapにnowShowを分け与えます。
index - 1が最後のゲームの番号なら、リザルト画面に移行する分岐処理も召喚します。なぜindex - 1なのかというと、ボタンを押した時点でindexの番号が進んでしまうからです。
スタート画面へ
$(document).on('click', '#endButton', function(){ $('#resultScreen').removeClass('nowShow'); $('#startScreen').addClass('nowShow'); index = 0; $('.mainWrap').eq(index).addClass('nowShow'); });
リザルト画面にて、「タイトルへ」というボタンをクリックすると、スタート画面へと戻る処理です。この時点でindexをリセットし、mainWrapに降り直しております。
以上をもって、「スタート画面」→「ゲーム進行」→「結果表示」→「スタート画面」という画面ループを、クリック操作のみで実装することができました。
次回はいよいよ、各ゲームの処理を実装していきましょう。
各画面をマークアップする #02
現在の私は相も変わらず、地獄の業火で炙られているが如き猛暑の中、毎日アルバイトに勤しんでおります。
さて、今回は、HTMLとCSSを用いて、ゲームに必要な画面を作り上げていきましょう。
スタート画面
所謂タイトル画面です。
ゲームのタイトルは「THE・検品」です。基本的に、各作業を検品と呼ぶためです。現在の時給を表示しておき、ゲームをクリアするたびに時給が上がっていく仕組みにしたいと思います。ちなみに、初期設定である1250円は、私のガチな時給です。交通費は出ないのですが、それを差し引いても高めだと思います。いいアルバイトでした。
それはさておき、CSSを用いて各パーツに適切なレイアウトを設定しましょう。
至極シンプルです。とりわけ大変なこともありません。
カウント画面
画面上部に記されている「qty」という数だけ、ボタンを押すことを要求されます。
ボタンはクリックされた時、押されている感が出るといいですね。、擬似クラス:activeを用いて、それらしく設定します。基本的にスマホで遊ぶことを想定しているため、ontouchstart属性をボタンにセットしておきます。
看板選択画面
左右の矢印で看板を切り替え、適切な看板を選択する必要があります。適切な看板とは、画面上部に記載されている「Seller Id」と同じ看板のことです。
矢印で看板を切り替える処理は、この時点では実装されていません。
看板記入画面
こちらも、画面上部に記載されている「SKU」と同じ数字を打ち込む処理を求められます。先ほどと同じパーツを使っているため、すぐにできました。
リザルト画面
全ての工程を終えると、結果画面が表示されます。カウント、看板選択、看板記入を、時間内にこなすことができれば、成功です。
時給が50円アップします。超過大評価であることは否定できません。
ちなみに「よくやった!」と言ってるおじさんのイラストは、実際の現場のリーダーに酷似しています。バレたら多分殺されます。
「カウントを間違えたまま全ての工程を終える」「看板の選択でミスをする」「看板の記入でミスをする」「時間切れ」……いずれかの条件を満たすと、検品失敗となります。辛辣な言葉を撃たれ、解雇されます。そうはいっても、タイトル画面に戻れば普通にもう一度遊べます。ただし、時給はリセットされます。
画面の作成は、以上となります。次回はいよいよJavaScriptを用いて、これらの画面を同一ページ内で切り替えられるようにしていきましょう。
JavaScriptでシンプルなゲームを作成する #01
前回の美少女ポジティブ日記開発から数ヶ月。
無事に就職が決まった私でございますが、今回はJavaScriptの学習として、ブラウザで動く単純なゲームを作成したいと思います。
どのようなゲームか?
数を数えるゲームです。はい?と思われたことと存じますので、詳細に説明いたします。
アルバイトの作業をゲーム化
現在、私は、物流倉庫で派遣のアルバイトをしております。
夏は蒸しに蒸された灼熱の空間で、滝のような汗を撒き散らしながら、冬は搬入口より入りし北風が荒れ狂う極寒の空間で、小鹿のように震えながら、日々作業に勤しんでおります。
話が逸れましたが、そのアルバイトの作業を簡略化したものをゲームにしよう、という目論見です。
作業の流れは、以下のようになります。
①搬入された段ボールから商品を取り出す
②リストと照らし合わせて、数が合っているかを確認する。
③確認後、商品を箱に詰める。
④箱の外側に、商品判別用の看板を書いて、貼付。
この流れの中から、今回は「数が合っているかを確認する」「看板を書く」という項目のみをゲーム化しようと思います。
作成予定画面
作成すべきそれぞれの画面を、以下に設定します。
全てJSの処理で切り替わるので、単一のページ内に収めることとなります。こういうのをSPAと呼ぶのでしょうか?
スタート画面
タイトル画面です。スタートを押せばゲームが始まります。それと同時にカウントダウンがスタートするため、以下に記す工程を、できるだけ素早く行わなければいけません。
カウント画面
画面上部に、検品する商品の詳細が記されています。
この画面では「qty」に記されている数と同じ回数だけボタンを連打(=カウント)することが求められます。現在のカウント数は表示されないので、自分の中で数を数えながらボタンを押す必要があります。
「次へ」で次の工程へと移ります。
看板選択画面
この画面では正しい看板を選択する必要があります。
画面上部の「Seller Id」に記されている文字列と同じ看板を選択します。
ここで誤った看板を選ぶと、その時点でゲームオーバーです。シビア。
看板記入画面
この画面では、看板に商品判別用のコードを書きます。
画面上部の「SKU」に記されている数列を、入力欄に正しく記入します。
リザルト画面
制限時間内に、正確にカウントし、正確に看板を選び、正確に看板に記入を行えば、ゲームクリアです。
リザルトが画面に表示され、タイトルへと戻れます。
看板の選択を間違えたり、途中で時間切れになった場合も、強制的にこの画面が表示されます。
開発工程
①各画面のマークアップとレイアウト作成
スタート画面、カウント画面、看板選択画面、看板記入画面、リザルト画面、の計5つの画面を作成します。
ゲーム的処理は一旦置いておき、「次へ」を選択することで画面を移れるようにしておきましょう。
②ゲーム的処理の作成
カウント画面では、ボタンを押すことでカウントが進むように
看板選択画面では、選択した看板の情報が保持され、次の画面で表示されるように
看板記入画面では、テキストボックスに入力した情報が保持されるように
リザルト画面では、保持したそれぞれの情報を元に、結果が表示されるように
それぞれの処理を、作成して行きましょう。
③ゲーム的処理の作成Part2
カウントすべき数量、選択すべき看板名、記入すべき数列、制限時間……これらは、ゲーム開始と同時に、ランダムで設定される必要があります。
そういった処理を作成しましょう。
④制限時間処理の作成
スタートと同時にカウントダウンが始まり、0になれば強制的にリザルト画面へ移行する処理を作成します。
カウントすべき数量に応じて、制限時間が変動するように設定できればと思っております。
⑤完成
以上の工程を作りきることで、ゲームとしての機能は完成するはずです。細かなバグ等を調整していきましょう。
セリフ表示機能をグレードアップする #15【完結】
複数種類の台詞をランダムで表示させる
毎度毎度同じ台詞を喋られては、趣がないというもの。故に、同じページに対応する台詞を複数用意し、それをランダムで表示させる機能を作成していきましょう。
台詞を表示させる処理は、今見ているページ名を取得し、データベースからページ名に対応する台詞を引っ張って行われるものでした。複数の台詞をデータベースに登録しておくと、多次元配列の形で台詞が取り出されます。それに以下の処理をかけることで、ランダム抽出が可能となります。
// 複数種類あるセリフから一つのみ選別 private function _chooseSerifAndFase($tempSerifAndFace){ $i = mt_rand(0, count($tempSerifAndFace) - 1); return $tempSerifAndFace[$i]; }
後はこれを、従来の処理で表示させるだけです。 ページにアクセスする度に、違ったセリフが取り出されます。
日記をつける前と後でセリフが変わる
今日の日記をまだつけていないと「今日は日記を書いていませんね!」と表示される一方、日記をつけていると「日記を書いたんですね!偉い!」のように表示される処理を作っていきます。
表示されている日記が「今日」のものかどうかを識別
日記を見ているというとこは、必ずURLのパラメーターにその日付が表示されています。その日付と、DateTime('today')で取り出される日付(=今日の日付)を比較し、合致した場合は、その日記は今日のもの、ということになります。
今日、日記を書いたかどうかを識別
データベースから、今日の日記を取り出します。取り出せた場合は、日記がある。取り出せなければ、日記は無い。単純です。
$myDiary = new \MyApp\Model\DiaryModel(); // その日の日記が存在するか否かをチェック if($myDiary->issetTodayDiary($diaryDate)){ $res = 'doneEdit'; }else{ $res = 'yetEdit'; };
これによって返される「doneEdit」か「yetEdit」の文字列を鍵として、台詞を取り出します。 うまくいきました!
日記をつけた日数でセリフが変化する
「三日連続も日記をつけてますね!」「今日で連続三十日です!やばい!」のように、連続で日記を書いた日数に応じてセリフが変化する処理を作成します。
処理を挟む位置
一つ前の処理で、「表示されている日記が今日か否か」「今日、日記を書いたか否か」と、二つの条件分岐を重ねました。連続記録を褒めてくれる今回の処理は、「今日」かつ「日記を書いている」状態の時に行われるようにしましょう。
連続記録日数を取り出し、条件分岐
自分が連続でどれだけ日記を書いたのかは、データベースのユーザーテーブルに記されています。それを取り出し、日数に応じて条件分岐するのみです。
private function _diaryDaysCheck($keepDays, $allDays){ switch($keepDays){ case 3: return $keepDays; break; case 7: return $keepDays; break; default: // 総記録数が1日=初めて日記を書いた時に特別処理 switch($allDays){ case 1: return $allDays; break; default: return false; break; } break; } }
とりあえずということで、連続記録日数が3日と7日の時にのみ、その日数を返すようにしています。返された日数をキーとして、台詞を取り出します。ちなみに、初めて日記を書いた時にも特別なセリフが表示されるようにもしてあります。
うまくいきました!
ほぼ同様の処理を、マイページにも適用させます。マイページでは、連続記録日数ではなく、総日数に応じて台詞が変わる仕組みとしましょう。
さて、これにてこの日記アプリは、ほぼ完成です。
後は、セリフのレパートリーを増やしたり、細かい修正を加えて、完成品を納めることとします。
美少女のセリフ表示機能を作成する #14
さて、いよいよ美少女のセリフ表示機能を実装していきます。この日記アプリの最大最重要項目と言っても過言ではありません。緊張してきた。
データベースにテーブルを用意する
美少女のセリフはデータベースに保存されます。
create table serif( id int not null auto_increment primary key, genre varchar(90), face varchar(255), key1 varchar(90), key2 varchar(90), key3 varchar(90), serif varchar(420) );
”genre”には「トップページ」や「日記閲覧ページ」等のページ名を格納し、台詞を取り出す際の目印とします。
"key1"〜"key3"には、その他の細かい条件を格納します。例えば、トップページであれば、key1に「朝」「昼」「夜」という文字列を格納し、時間帯ごとに取り出されるセリフが変わる仕様となっております。keyを3つも使うのか、というのは些か疑問ですが、備あれば憂いなしというやつです。
"face"には「lara.png」や「lara_smile.png」といった、美少女の画像ファイル名を格納します。セリフに応じて、表示される表情が変わる仕組みです。その気になれば、立ち絵を切り替えることも可能ですね。複数の立ち絵を用意するのは、労力的に断念したのですが。
ページによって表示される台詞を変える
日記を見るページであれば「この日はこんなことがありました!」、日記を書くページであれば「日記を書きましょう!」のように、アクセスしているページに応じた台詞を取り出す仕様としたいです。
$_SERVER['PHP_SELF']
を用いて、現在表示しているスクリプトのファイル名を取得できます。これを鍵とし、データベースにアクセスしましょう。
ファイル名をそのままデータベースと照らし合わせてもよかったのですが、万一ファイル名を変えるようなことが起きた場合に手間が増えぬよう、ファイル名を独自のページ名に変換してからデータベースと照合します。(以下参照)
private function _validateCurrentPage($place){ switch($place){ case '/index.php': $this->genre = 'トップページ'; $tempSerifAndFace = $this->_topPageSerif(); break; case '/index_list.php': $this->genre = 'トップページ'; $tempSerifAndFace = $this->_topPageSerif(); break; case '/myDiary.php': $this->genre = '日記閲覧ページ'; $tempSerifAndFace = $this->_myDiarySerif(); break; case '/myDiary_edit.php': $this->genre = '日記編集ページ'; $tempSerifAndFace = $this->_myDiaryEditSerif(); break; case '/myPage.php': $this->genre = 'マイページ'; $tempSerifAndFace = $this->_MyPageSerif(); break; case '/myPage_edit.php': $this->genre = 'マイページ編集ページ'; $tempSerifAndFace = $this->_MyPageEditSerif(); break; default : $this->genre = 'その他'; break; }
トップページに台詞を表示させる
トップページには「朝」「昼」「夜」という三種類のキーが用意されているので、date('H')
によって現在時刻を24時間表記で取得し、時間帯を条件分岐します。これをキーとし、データベースにアクセスして台詞を取り出しましょう。
この日記には女の子からどう呼ばれるかと女の子の一人称を決定する機能があります。これらを実現するため、データベースに格納している女の子のセリフには工夫を加えてあります。
insert into serif(genre,face,key1,serif) values( "トップページ", "lara_smile.png", "夜", "<二人称>、こんばんは!\n今日も一日、お疲れ様です!よく頑張りましたね!" );
女の子の一人称及び二人称は別のテーブルに格納されているので、まず、それを取り出します。セリフの中に<一人称>や<二人称>という文字列が存在した場合、str_replace関数を用いて、文字列を変換しましょう。
できました!!!
これにて、ページ毎にセリフ表示を変え、またトップページでは時間帯によっても表示が変わる処理が完成しました。
次回はさらに深堀り、セリフ数を増やしたり、日記をつける前と後でセリフが変わったり、日記をつけた日数に応じてセリフが変わったりするような機能を増やしていきましょう。
それでは、今回はこの辺りで。
マイページ機能を作成する #13
さて、ユーザーに関連する項目を確認及び編集ができる機能(通称マイページ機能)を追加していきましょう。 当初の設計では、この画面で編集したい項目をクリックすれば、そのまま編集モードに切り替わる想定でした。手間を考慮し、編集画面を別ページに用意することとします。
マイページを作成する
日記をつけた日数などの計算は後で行うものとします。とりあえず、ユーザー名やララからの呼び方などの項目をデータベースから取り出し、表示します。
右上の編集ボタンを押すと、編集画面に移行します。テキストボックスのvalue要素に、引っ張ってきたデータを取り入れます。日記編集と同じようなシステムです。
ちなみに「ララの一人称」は思い付きで追加した機能です。文字通り、私でも僕でもオレでも、好きな一人称で喋ってくれます。
アイコン画像の変更は、ドットインストールのレッスンを踏襲しています。「アップロードした画像は必ず200×200にリサイズされる」「その前に使っていた画像は削除される」という機能を独自に追加しました。あとは画像のファイル名をデータベースに格納し、マイページで他の情報と共に表示させればOKです。
日記の記録を計算する
「日記をつけた日数」「現在連続記録日数」「最大連続記録日数」の三項目を計算し、データベースに格納する処理を作成しましょう。 処理が発生するタイミングは、日記を更新したタイミングがベストだと思われます。日記更新処理の最後に、これらの処理を割り込ませることにしましょう。
// 日記の日付のみを全て取り出す $tempDiaryDates = $myDiary->getDiaryDates($id); // 最大日記記録数を取得 $highScore = $users->getHighScore($id); // 日記を一日もつけてない場合は処理をスキップ if($tempDiaryDates){ // 日記の総日数を格納 $countDiary = count($tempDiaryDates); // 日付の後ろについている曜日を切り取る $diaryDates = $this->_validatediaryDates($tempDiaryDates); // 日付が連続かどうかを判定する $keepDays = $this->_checkContinuity($diaryDates); // 連続日記が最大連続日数を超えた場合更新 if($keepDays > $highScore){ $highScore = $keepDays; } // 諸々をデータベースに登録 $users->updateDiaryData([ 'NoteDays' => $countDiary, 'KeepNoteDays' => $keepDays, 'HighScoreNoteDays' => $highScore, 'id' => $id ]); }else{ $keepDays = 0; } // return $countDiary; } private function _validatediaryDates($values){ $res = []; foreach($values as $value){ $res[] = substr($value , 0, 10); } return $res; } private function _checkContinuity($values){ $keepDays = 1; // 日数の差が1なら連続カウント for($i = 0; $i < count($values) - 1; $i++){ $time1 = new \DateTime($values[$i]); $time2 = new \DateTime($values[$i + 1]); $diff = $time1->diff($time2); if($diff->format('%d') == 1){ $keepDays++; }else{ break; } } return $keepDays; }
頑張って自作した処理なので、載せておきます。こういうものを作っている時が一番楽しいですね。
日記をつけた総日数
これは単純です。データベースから日記を全て取り出し、count関数で計算するだけです。
現在連続記録日数
まず、データベースから日記の日付を、降順で全て取り出します。この日付を使ってDateTimeオブジェクトを作成したいですが、例の如く後ろについている曜日表記(-Mon等)が邪魔なので、substr関数でこれらを切り取ります。
foreachを回し、最新の日記と、その一つ前の日記の日数の差を、diff関数で計算します。非常に便利というか、この関数がなければ何も成り立ちませんでした。日付の差が1だった場合は、それらの日記は連続している、ということなので、連続日数を保持する変数に+1します。差が1でなかった場合、そこで処理をストップします。この方法により、最新の日記から連続でどれだけ日記をつけているのか、計算できました。
最大連続記録日数
データベースから、最大連続記録日数を取り出しておきます。初期値は0です。
上記の現在連続記録日数の処理が終わった段階で、その日数と、データベースから取り出した最大連続記録日数を比較します。最大記録を上回っているようなら、データを上書きします。
完璧です。目立ったバグが発生することもなく、非常に気持ちよく制作することができました。
さて、ユーザーが手を加える機能は、ひとまず完成といったところです。残すところは、画竜点睛とも言えるララのセリフ機能を実装するのみです。
それでは、今回はこのあたりで。