イニシャルッ E~ タンタンタン!
どうもNSZ山本です。
突然ですがいきなりゲーム作ってみました。
プレイ時間は30秒。クソゲーですが最小限の時間の浪費
やってみたかった
PHP+HTML+JSでレスポンシブ対応のロールプレイングゲーム作ってみた – Qiita
これを読んでしまった。すっげえかっけえ。
僕も作りたい!(中学生並みの感想)!
ブラウザゲームでこれ程できるのか。
unityとかぜったい触りたくないし(ボタン多すぎ)
というわけで作ってみました。
これがタイトル画面です。
遊び方
ここへアクセス。
ブラウザゲームなのでアクセスするだけです。
左右キー←→とエンターだけで動かせます。
車は見ればわかりますが私の手書きです。
車を選んでスタート。
制限時間は30秒
いらすとやさんの絵がポップです。
ルールは特に説明していませんが
おそらく「道に現れる歩行者や自転車を出来るだけREKI-SATSUすればハイスコア」だと思います。
あくまで暗黙のルールなので、よけるゲームとしてご利用いただいてもOK。
そんな物騒なの明言するわけにはいかんでしょ(すっとぼけ)
ほんとにどっちとしても遊べますからね?!
爆破音の効果音もつけました。
リザルト画面。
スコアを反映してあなたの運転レベルが出ます。ゴールドから免許返納レベルのステータスが与えられます。
更に上に隠しステータスもあります。
実装方法
ほぼjqueryなどのjs系で作ってます。
画面が3つ
- タイトル
- ゲーム
- リザルト
で構成しています。それぞれ使った技術を紹介します。まあこれをみてこれを作ろうなんて思う人は居ないと思うので、軽く書いておきます。
1タイトル
車の選択は実はスリックデス。
とりあえずスリック。みんな大好きSlick.jsを導入しておきます。
1 2 3 4 5 6 7 8 9 10 |
$(window).keydown(function(e){ if(e.keyCode == 37){$('.slick-prev').trigger('click')} if(e.keyCode == 39){$('.slick-next').trigger('click')} if(e.keyCode == 13){ var imgname = $('.slick-current').find('img').attr('src'); $("#formtext").val(imgname); $('button').trigger('click'); } }); |
キーダウンイベントでキーコード判定して左右に動かす。37が左で39が右。
Enterでクリックイベントにバインド。
1 2 3 |
form{ display: none; } |
画面遷移を起こして2のゲーム画面に移動するのですが、画像自体にA hrefしてません。
cssでhiddenでフォームをこっそり隠して、そこにエンター押した瞬間、真ん中にある要素の画像名を取得してドーン
初心者丸出しの実装だな。
2.ゲーム
Velocity.jsの出番です。
ヴェロシティじぇーえすは、jqueryのアニメーションよりも大幅に軽く、きれいなアニメーションを実現するとのこと。
構文も直感的で書きやすいと感じました。
敵
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
var images = [ 'iy/cardgame_man.png' // <只の画像の羅列なので省略> ]; function img(){ var a = Math.floor( Math.random() * 1801 ) ; if(a<901){ $('.iy').css({'margin-left':a}); }else{ $('.iy').css({'margin-right':a-900}); } $('.iy').velocity( { top: 1000 },{ duration:1500, delay:0, easing:'swing', complete: function(){ if (time < 1){ var fscore = $('h1').text() var fkill = $('h3').text() $("#fkill").val(fkill); $("#fscore").val(fscore); $("#fexext").val('gameend'); $('button').trigger('click'); } else { $('.iy').remove(); var rndImg = images[Math.floor(Math.random() * images.length)]; $('.dummy').after("<div class = 'iy'><img class='img' src='"+rndImg+"'></div>"); img() } } } ); } |
敵の出現位置は左右のみで管理。
乱数(1800の範囲)で数字を出し、margin-leftまたはmargin-rightのcssを上書きして左右に変化を付けて出現させます。
あとは.velocityでtop属性を、1.5秒間の間に1000px変化させることで下に落ちてくるようなアニメーションを表現。
自機
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
var clf = true; $(window).keydown(function(e){ if(clf){ var carp = parseInt($('.cary').css('margin-left'), 10); if(e.keyCode == 37){ clf = false; carp = carp -200; $('.cary').velocity( { 'margin-left':carp },{ duration:500, easing:'swing', complete:function(){ clf = true; } }); } if(e.keyCode == 39){ clf = false; carp = carp +200; $('.cary').velocity( { 'margin-left':carp },{ duration:500, easing:'swing', complete:function(){ clf = true; } }); } } }); |
自機フリウスは、現在の位置を取得、margin-left属性を変化。
右を押したらmargin-leftをプラス
左を押したらmargin-leftをマイナス
当たり判定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
var score = 0; var kill = 0; $(function () { setInterval(function(){ var iyp = $('.iy>img').offset(); var iytop = iyp.top; var iyleft = iyp.left; var caryp = $('.cary>img').offset(); var carlmax = caryp.left -200; var carrmax = caryp.left +200; var cartmax = caryp.top +100; var carbmax = caryp.top -100; if (carlmax < iyleft && iyleft < carrmax && cartmax > iytop && iytop > carbmax){ var src = $('.iy').children('img').attr('src'); //役人だったらgameover if(src =='iy/bad2.png' || src =='iy/bad.png' ){ var fscore = $('h1').text() var fkill = $('h3').text() $("#fkill").val(fkill); $("#fscore").val(fscore); $("#fexext").val('bad'); $('button').trigger('click'); } score+=100; kill+=1; if(kill==10){ //BOUNOUS POINTS score+=10000; $('h4').text('CONGRATULATION! U KILLED 10 FUTURE TAXPAYER!'); }else if(kill==20){ score+=100000; $('h4').text('R U CRAZY? SERIAL KILLER LAH.'); } $( '#sound' ).get(0).play(); $('h1').text('score:'+score); $('h3').text('kill:'+kill); $('body').css('background','red'); setTimeout(function(){ $('body').css('background','black'); },100); } },200); }); |
当たり判定は0.2秒(200mmsec)おきに敵画像とフリウスの座標を取得して、その数字が範囲以内だったらtrue
条件に入ったら、上級市民かどうか判定
①上級市民だったらゲームオーバー、リザルト画面に飛ばす(フォームに点数、kill数、上級市民フラグを詰めて、submitを押したことにする)
②庶民だったら、爆破音を鳴らす。画面を赤くする。.delayで遅らせて黒画面に戻す。
リザルト画面に飛ばす(タイトル画面と同様hiddenフォームに点数、kill数、上級市民フラグを詰めて、submitを押したことにする)
初心者丸出しの実装だな。
3.リザルト
フォームから受け取った点数、kill数、上級市民フラグを取得してエコーしてるだけ。
ここは単にphpです。あとは適当です。
問題点
①クオリティが低い:うるさい
②当たり判定が雑:敵の画像のwidthがフリウスの画像と異なるので、座標の基準値が異なり、当たり判定が雑。
クソゲーだしまあいいか。
おわりに
ブラウザでもこうした縦シューくらいなら簡単に出来るなあと思いました。
肝になる技術は、
- 自機と敵をなめらかにに動かす(velocity.js)
- 当たり判定の常時計算
で、あとはまあオマケみたいなもんだ。
ほんとはajaxで遷移無し読み込みしたいんですがめんどいので普通に画面遷移。僕は向上心の無いsiなのでこれくらいでいいよね。
スペシャルサンクス
参考URL
jquery – What’s the difference between keyup, keydown, keypress and input events? – Stack Overflow
jQuery キーボードによって要素を操作する方法 – キーの取得とその活用に関して | Stronghold Archive
Velocity.js のドキュメントを勝手に日本語にする – 1日ひとつ、強くなる。
CSS3のtransformで要素を斜めにしたり平行四辺形に画像をトリミング | CREATIVELOG【ホームページ制作・Web製作のクリエイティブ・ウェブ】
辺り判定
jQuery: 要素の表示位置を取得/設定するには?(offset) – Build Insider
jQueryのoffset() で表示位置の取得と要素の移動
jQueryでsetIntervalを使って特定の間隔でfunction処理を繰り返し行う(タイマー処理)方法 | BlackFlag
乱数
bgm
htmlのaudioを使用してサイト上でBGM音楽を流す – chocolat
【jQuery】遅延実行 – 数秒後にイベントを発生させる | じゆうだむ
爆破・爆発19
効果音 爆発・衝撃<『 戦闘系音 』 by On-Jin ~音人~
https://www.nxworld.net/tips/jquery-random-snippets.html
https://www.nxworld.net/tips/jquery-plugin-slick-current-class-examples.html
velocity.jsの使い方 記述方法とオプション機能 | un-Tech
javascript – Loop animation with velocity.js – Stack Overflow
javascript – Velocity.js animation delay – Stack Overflow
アニメーション最強のVelocity.jsの使い方 – Qiita
jQueryでつくる100秒タイマー | 福岡のホームページ制作会社・株式会社マグネッツ
jQuery でテキストボックスの値を設定/取得/追記/削除を行う方法
本当はこれくらい強くなりたい(ムリ)
PHP+HTML+JSでレスポンシブ対応のロールプレイングゲーム作ってみた – Qiita
//改修
JavaScript:連続クリック対応方法 | 覚え書き.com
jQueryでクリック(click)での、連打を防止して アニメーションが終わるまでクリックボタン無効にする | 9ineBB