[WP]no.018 HTML5でシューティングゲーム

本当は全く別で正規表現書いていたのですが、途中混乱したので。
触ろうと思って結局触っていなかったHTML5をやってみました。

htmlでjavascriptを書いてゲームを作る・弄るというのは「まさおコンストラクションFX」を思い出します。
現在Javaのセキュリティ対策によって潰されてしまいましたが。

福田直人のホームページ
http://www.t3.rim.or.jp/~naoto/naoto.html
(旧トップページ→まさおコンストラクション FX Update 16)


中学生ぐらいの時、ボスとか移動床の挙動作って遊んでいた記憶があります。

シューティングゲームはまさおとは殆ど関係ないのでお話はこれまで


ここで作成したシューティングゲームは、やっていることはPythonで作成したシューティングゲームと全く同じ。
具体的なパラメータは適当に決めたものなので挙動は異なりますが、Javascriptでも結構できるものですね…



canvasタグで描画領域を作成することができます。
そしてjavascriptでgetContext()関数を呼び出せば、絵の具と筆が手に入ります。


ゲームループはタイマーのsetIntervalを使い、周期的に関数を呼び出せばおk。


キーボード入力はonkeydownでもいいのですが、addEventListenerという手法があったので、こちらを使ってみた。
でもやっぱり、getkey(code)っぽく扱いたいので、そんな感じのコードになってます。って他に方法あるんですかね?


JavascriptオブジェクトなんていうJSONっぽいのがあるらしいので、こちらも初めて使ってみた。しゅごーい。

player = { x:50 , y:100};

と記述すれば、

alert( "("+player.x+","+player.y+")");

と使うことができます。しゅごーい。


functionを利用したオブジェクト指向っぽい記述ができるらしいのですが、ここではやってないです。


しょうゆ
<!DOCTYPE html>

<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=shift_jis">

<title>hello shooting</title>

<script type="text/javascript">
<!--
// グローバル変数的な何か
var canvasmain; // キャンバス要素
var contextmain; // キャンバスのコンテキスト

var gametimer; // インターバルタイマーID

var gamemode = 0;// ゲームの状態
var gamecounter; // カウンタ

var player; // プレイヤーの情報
var enemy; // 敵
var bulletp; // プレイヤーの弾
var bullete; // 敵の弾

var score; // 点数

var gamekey={ // キー情報
left:0,
right:0,
up:0,
down:0,
fire:0
};

// onloadのイベントリスナー
addEventListener("load",call_onload,true);

// 初期化
function initialize(){
// プレイヤーの情報をセット
player={
x:180,
y:400,
bullet_reload:0,
alive:-1 // 生存していたら負、死んだら死んだ時のゲームカウンタ値
};
// ほか
enemy = new Array(20);
bulletp = new Array(20);
bullete = new Array(100);

score=0;
gamecounter=0;
}

// 画面読み込み時に呼び出し
function call_onload(){
// 要素や必要な情報の取得
canvasmain = document.getElementById("canvasMain");
if (!canvasmain){alert("error:onload:canvasMain");return;}
contextmain = canvasmain.getContext("2d");
if (!contextmain){alert("error:onload:getcontext");return;}

// イベントリスナーを追加
addEventListener("keydown",call_keydown,true);
addEventListener("keyup",call_keyup,true);

// ゲームループ開始
gametimer = setInterval("game_mainLoop()",20);

// ヒラギノ角ゴは甘え
contextmain.font = "15px 'MS ゴシック'";

// 変数初期化
initialize();

// タイトルに遷移する
gamemode = 10;
}

// ゲームループ
function game_mainLoop(){
switch(gamemode){
case 10:
// タイトル
gametitle();
break;
case 20:
// ゲーム画面
gameupdate();
drawgamescreen();
break;
}
}

// タイトル
function gametitle(){
// 背景
contextmain.fillStyle="#FFFFFF";
contextmain.fillRect(0,0,480,480);

// ショットキーを押したら
if (gamekey.fire){
gamemode=20; // ゲーム開始へ遷移
initialize();// 初期化
}
contextmain.fillStyle="#000000";
contextmain.fillText("hit z key",20,20);
}

// ゲーム更新
function gameupdate(){

// キー入力反映
if (player.alive<0){
if (gamekey.left && 0<player.x){
player.x-=5;
}
if (gamekey.right && player.x<360){
player.x+=5;
}
if (gamekey.up && 0<player.y){
player.y-=5;
}
if (gamekey.down && player.y<480){
player.y+=5;
}
if (gamekey.fire && player.bullet_reload<=0){
generateBulletPlayer(player.x,player.y);

// 再発射時間
player.bullet_reload=20;
}
// 再発射時間をカウントする
if (0<player.bullet_reload)player.bullet_reload--;
}

// 自弾の動き
for (var i=0;i<bulletp.length;i++){
if (!(i in bulletp)) continue; // 使われていないならスルー
// 移動
bulletp[i].y -=8.5;

// 画面外判定 上方向にしか飛ばないので上だけ
if (bulletp[i].y < -20){
delete bulletp[i];
continue;
}

// 存在する全ての敵と当たり判定チェック
for (var j=0;j<enemy.length;j++){
if (!(j in enemy)) continue; // 使われていないならスルー
if ((enemy[j].x-bulletp[i].x)*(enemy[j].x-bulletp[i].x)+(enemy[j].y-bulletp[i].y)*(enemy[j].y-bulletp[i].y)<400){
// 敵と自弾を削除
delete bulletp[i];
delete enemy[j];
// 点数加算
score += 10;
break;
}
}
}
// 敵の動き
for (var i=0;i<enemy.length;i++){
var arg;
if (!(i in enemy)) continue; // 使われていないならスルー

// プレイヤーの方向
arg = Math.atan2(player.y-enemy[i].y,player.x-enemy[i].x);

switch (enemy[i].type){
case 0:
enemy[i].y += 3;
if (enemy[i].lifetime%45 == 10)
generateBulletEnemy(enemy[i].x,enemy[i].y,arg,4);
break;
case 1:
if (enemy[i].lifetime < 40){
enemy[i].y += 4;
}else{
enemy[i].x += enemy[i].random<0.5 ? 4:-4;
if (enemy[i].lifetime%25 == 0){
generateBulletEnemy(enemy[i].x,enemy[i].y,arg,5);
generateBulletEnemy(enemy[i].x,enemy[i].y,arg+Math.PI/6,5);
generateBulletEnemy(enemy[i].x,enemy[i].y,arg-Math.PI/6,5);
}
}
break;
case 2:
enemy[i].y += 7;
if (enemy[i].lifetime%25 == Math.floor(enemy[i].random*25)){
generateBulletEnemy(enemy[i].x,enemy[i].y,0,3);
generateBulletEnemy(enemy[i].x,enemy[i].y,Math.PI,3);
}
break;
}

enemy[i].lifetime++;
// 画面外に出たら消す
if (enemy[i].x < -20 || 380 < enemy[i].x || enemy[i].y < -60 || 500 < enemy[i].y){
delete enemy[i];
}
}
// 敵弾の動き
for (var i=0;i<bullete.length;i++){
if (!(i in bullete)) continue; // 使われていないならスルー
bullete[i].x += bullete[i].vx;
bullete[i].y += bullete[i].vy;
// プレイヤーとの衝突判定
if ((player.x-bullete[i].x)*(player.x-bullete[i].x)+(player.y-bullete[i].y)*(player.y-bullete[i].y)<250){
// 死ぬ
if (player.alive<0) player.alive=gamecounter;
}

}
// 敵の出現
if (gamecounter%40 == 30){
generateEnemy();
}

// ゲーム終了
if (0<player.alive && player.alive+120 < gamecounter){ // 判定はもっと改善できる
gamemode = 10; // タイトルへ
}

// プレイ時間
gamecounter++;
}

// 敵弾を生成する
function generateBulletEnemy(gx,gy,r,v){
var i;
for (i=0;i<bullete.length;i++){
if (!(i in bullete))break;
}
// TODO:例外処理(すべて埋まっている)
// 弾を生成する
bullete[i]={x:gx, y:gy, vx:Math.cos(r)*v, vy:Math.sin(r)*v};
}

// 自弾を生成する
function generateBulletPlayer(gx,gy){
var i;
for (i=0;i<bulletp.length;i++){
if (!(i in bulletp))break;
}
// TODO:例外処理(すべて埋まっている)
// 弾を生成する
bulletp[i]={x:gx,y:gy};
}

// 敵を生成する
function generateEnemy(){
var i;
// 使われていない要素を探す
for (i=0;i<enemy.length;i++){
if (!(i in enemy))break;
}
// TODO:例外処理(すべて埋まっている場合)
// 生成
enemy[i]={
type:Math.floor(Math.random()*3), // 種類
x:40+Math.random()*160,
y:-30,
lifetime:0, // 生存時間
random:Math.random() // 個体乱数値
}
}

// ゲーム画面描画
function drawgamescreen(){
// 背景
contextmain.fillStyle="#0080FF";
contextmain.fillRect(0,0,360,480);

// プレイヤーの描画
if (player.alive<0){ // 生きていたら
contextmain.fillStyle="#FFFF00";
contextmain.fillRect(player.x-15,player.y-15,30,30);
}

// プレイヤー弾描画
contextmain.fillStyle="#FFFF00";
for (var i=0;i<bulletp.length;i++){
if (!(i in bulletp)) continue; // 使われていないならスルー
contextmain.fillRect(bulletp[i].x-5,bulletp[i].y-5,10,10);
}

// 敵
contextmain.fillStyle="#FF8000";
for (var i=0;i<enemy.length;i++){
if (!(i in enemy)) continue; // 使われていないならスルー
contextmain.fillRect(enemy[i].x-15,enemy[i].y-15,30,30);
}
// 敵弾
contextmain.fillStyle="#FF0000";
for (var i=0;i<bullete.length;i++){
if (!(i in bullete)) continue; // 使われていないならスルー
contextmain.fillRect(bullete[i].x-5,bullete[i].y-5,10,10);
}

// 情報画面
contextmain.fillStyle="#000000";
contextmain.fillRect(360,0,120,480);
contextmain.fillStyle="#FFFFFF";
contextmain.fillText(""+score,380,60);

}

// キーダウン時に呼び出し
function call_keydown(e){
switch (e.keyCode){
case 37:
gamekey.left=1;
break;
case 38:
gamekey.up=1;
break;
case 39:
gamekey.right=1;
break;
case 40:
gamekey.down=1;
break;
case 90: // zキー
gamekey.fire=1;
break;
}
}
// キーアップ時に呼び出し
function call_keyup(e){
switch (e.keyCode){
case 37:
gamekey.left=0;
break;
case 38:
gamekey.up=0;
break;
case 39:
gamekey.right=0;
break;
case 40:
gamekey.down=0;
break;
case 90:
gamekey.fire=0;
break;
}
}

// -->
</script>

</head>
<body>
<h3>hello shooting</h3>
<canvas id="canvasMain" width="480" height="480" style="border-width:1px;border-style:solid;"></canvas>

</body>
</html>
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

tag : HTML5

コメントの投稿

非公開コメント

プロフィール

舞葉(ぶよう)

Author:舞葉(ぶよう)
github.io
はてなブログ(競プロ)

古い記事のソースコードは色分けしていないので、高機能テキストエディタに貼り付けたほうが見やすいかも。

検索フォーム
このブログについて
自分がつまづいた話題、なんとなく書きたいと思ったこと、ググったけど殆ど資料なかったぞオイ な話等をアップする予定。通りすがりでも、参考になっていただければと。プログラムの例外入力、メモリリークは責任負いません。投稿された記事は修正・削除する場合があります。
カテゴリ
タグ

HSP3アルゴリズムとデータ構造c++RubyJavaUnity画像解析C機械学習C#LinuxcodeIQKinectMinecraftTonyuSystemraspberrypiPythonHTML5音声制御Simulinkruby俺ルール通信制御Javascriptシミュレーション

counter-shinobi
固定記事
最新記事
最新コメント
月別アーカイブ
ブロとも申請フォーム

この人とブロともになる

アクセスランキング
[ジャンルランキング]
コンピュータ
1467位
アクセスランキングを見る>>

[サブジャンルランキング]
プログラミング
265位
アクセスランキングを見る>>