LoginSignup
0
1

More than 5 years have passed since last update.

ゲームプログラミング入門~その4~【シューティングゲーム】完成

Posted at

「シューティングゲーム」がやっと完成しました!!

2度目のプログラミングチャレンジで、1か月ほどかけて、やっと「シューティングゲーム」が完成しました。
test.jpg
今回の学習では、エンジニアの友人にいろいろと教わりながら勉強&作成できたので、途中で挫折しかけたのですが、何とか完成までたどり着くことができました。

URL

今回作成したシューティングゲームのコードを下に書いておきたいと思います。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <meta name="robots" content="noindex,nofollow">
        <title>WEB SCREEN GAME</title>
        <style>
            #screen {
                border: solid 1px #000000;
                background-color: #000000;
            }

        </style>
    </head>
    <body>
        <canvas id="screen" width="860" height="485"></canvas>
        <h2>操作方法</h2>
    <p>自機の操作 → 矢印キー</p>
        <p>ミサイルの発射 → Sキー</p>
        <p>※ゲームの時間制限はありません。自機と敵が衝突したらゲームオーバーになります。</p>
        <p>再度プレイする場合は、ブラウザの表示を更新してください。
        <script>
            //canvas要素のDOM(Document Object Model)を取得
            var canvas = document.getElementById('screen');
            var context;

            var bgImg1; // 背景画像1
            var bgImg2; // 背景画像2 
            var bgImgs; // 背景画像配列

            var score = 0; // スコア
            var scoreImg;  // スコア画像
            var selfBody;  // 自機データ
            var selfPosX = 20;      // 自機の画面横方向の位置
            var selfPosY = 190;     // 自機の画面縦方向の位置
            var selfCenterPos = []; // 自機中心座標配列
            var selfSpeed = 10;     // 自機のスピード            
            var enemyBody; //敵データ

            var gameOverImg; // ゲームオーバー画像

            var playFlag = true; // ゲームプレイフラグ

            var frameWidth = 860;   // CANVAS横サイズ
            var frameHeight = 485;  // CANVAS縦サイズ

            //  キーボードの状態
            //              [ 上  ,   下 ,   右 ,   左 ] 
            var keyStatus = [false, false, false, false]

            // ミサイル
            var missiles = [];        // ミサイルデータ配列
            var missileSpeed = 30;    // ミサイルスピード
            var maxMissileCount = 5;  // ミサイル最大同時発射数

            // ミサイルデータの初期化
            for ( var i = 0; i < maxMissileCount; i++ ){
                //             状態 , x, y
                missiles[i] = [false, 0, 0];
            }

            var enemies = [];        // 敵データ配列
            var enemyCenterPos = []; // 敵データ中心座標配列
            var maxEnemyCount = 1;   // 最大表示敵数

            var enemyType = [];      // 敵タイプデータ配列
            //            X有効範囲, Y有効範囲, 画像file名, 獲得スコア
            enemyType[0] = [ 20, 20, "enemy_20x20.png", 1000];
            enemyType[1] = [ 50, 50, "enemy_50x50.png", 500];
            enemyType[2] = [ 80, 80, "enemy_80x80.png", 200];

            // 敵データの初期化
            for ( var i = 0; i < maxEnemyCount ; i++ ){
                enemies[i] = createEnemy();
            }            

            document.onkeydown = keyDown;   //キーダウンの検知設定
            document.onkeyup = keyUp;       //キーアップの検知設定

            //コンテキストの取得可否チェック
            if(canvas.getContext){

                context = canvas.getContext('2d');

                window.onload = function() {
                    // 画像オブジェクト作成
                    selfBody = new Image();
                    enemyBody = new Image();
                    gameOverImg = new Image();
                    scoreImg = new Image();
                    bgImg1 = new Image();
                    bgImg2 = new Image();

                    // 画像ファイル名設定
                    selfBody.src = "rocket.png";
                    gameOverImg.src = "gameover.png";
                    scoreImg.src = "score.png";
                    bgImg1.src = "space1.jpg";
                    bgImg2.src = "space2.jpg";

                    // 背景画像データ設定
                    bgImgs = [ [bgImg1, 0], [bgImg2, 860], [bgImg1, 1720] ] ;

                    selfBody.onload = function(){
                        draw(context);    //描画処理
                        startAnimation(); // 描画更新開始処理
                    }
                }
            }

            // 描画更新処理
            function startAnimation(){
                setInterval(draw, 33);
            }

            // 描画処理
            function draw(){
                if ( playFlag ){
                    // CANVASをクリア 
                    context.fillStyle = "rgb(255, 255, 255)";
                    context.fillRect(0, 0, frameWidth, frameHeight);
                    context.clearRect(0, 0, frameWidth, frameHeight);

                    drawSpace();   // 背景(宇宙)を描画

                    drawMissile(); // ミサイルを描画

                    move();        // ロケットの移動と描画
                    context.drawImage(selfBody, selfPosX, selfPosY);

                    drawEnemy();   // 敵の描画

                    judgementHitMissile(); // 当たり判定

                    drawScore(score); // スコアを描画

                    // ゲームオーバー判定
                    if( playFlag === false ){
                        // ゲームオーバー画像表示
                        context.drawImage(gameOverImg, (frameWidth/2)-(gameOverImg.width/2), (frameHeight/2)-(gameOverImg.height/2));
                    }
                }
            }

            // ロケットの移動
            function move(){
                if ( keyStatus[0] ){  // UP
                    if ( selfPosY > 0 ){ selfPosY -= selfSpeed; }
                }

                if ( keyStatus[1] ){  // DOWN
                    if ( selfPosY < 400 ){ selfPosY += selfSpeed; }
                }

                if ( keyStatus[2] ){  // RIGHT
                    if ( selfPosX < 775 ){ selfPosX += selfSpeed; }
                }

                if ( keyStatus[3] ){  // LEFT
                    if ( selfPosX > 0 ){ selfPosX -= selfSpeed; }
                }
            }

            // キーダウン
            function keyDown(e){
                if ( playFlag ){
                    if(e.keyCode === 38 ){ keyStatus[0] = true; } //UP KEY
                    else if(e.keyCode === 40 ){ keyStatus[1] = true; } //DOWN KEY
                    else if(e.keyCode === 39 ){ keyStatus[2] = true; } //RIGHT KEY
                    else if(e.keyCode === 37 ){ keyStatus[3] = true; } //LEFT KEY
                    else if(e.keyCode === 83 ){ missileLaunch(); } // ミサイルを発射
                }
            }

            // キーアップ
            function keyUp(e){
                if(e.keyCode === 38 ){ keyStatus[0] = false;} //UP KEY
                else if(e.keyCode === 40 ){ keyStatus[1] = false;} //DOWN KEY
                else if(e.keyCode === 39 ){ keyStatus[2] = false;} //RIGHT KEY
                else if(e.keyCode === 37 ){ keyStatus[3] = false;} //LEFT KEY
            }

            // 敵の描画
            function drawEnemy(){
                for( var i = 0; i < enemies.length; i++ ){
                    if( enemies[i][0] < -100 || enemies[i][1] < -100){
                        enemies[i] = createEnemy();
                    }
                    enemies[i][0] -= enemies[i][2];
                    enemies[i][1] += enemies[i][3];
                    enemyBody.src = enemies[i][4][2];
                    context.drawImage(enemyBody, enemies[i][0], enemies[i][1]);
                }
            }

            // 敵データを初期化
            function createEnemy(){
                return [
                    getRandVal(910, 1000),       // posX
                    getRandVal(10, 600),         // posY
                    getRandVal(3, 15),           // moveXspeed
                    -1 * getRandVal(1, 5),       // moveYspeed
                    enemyType[getRandVal(0, 2)]  // enemyTypeNum
                ];
            }

            // ミサイルを描画
            function drawMissile(){
                for ( var i = 0; i < missiles.length; i++ ){
                    if ( missiles[i][0] ){ // ミサイルが有効かどうか?
                        if( missiles[i][1] < 830 ){
                            missiles[i][1] += missileSpeed;

                            context.beginPath();

                            var missile = new Path2D();

                            missile.rect( missiles[i][1], missiles[i][2], 20, 2 );
                            context.fillStyle = "rgb(255, 255, 255)";
                            context.stroke(missile);
                            context.fill(missile);
                        } else {
                            missiles[i][0] = false; // ミサイルを無効化
                        }
                    }
                }
            }

            // ミサイルを発射
            function missileLaunch(){
                for ( var i = 0; i < missiles.length; i++ ){
                    if( missiles[i][0] === false ){ // ミサイルが有効かどうか?
                        missiles[i][0] = true; // ミサイルを有効化
                        missiles[i][1] = selfPosX + 60;
                        missiles[i][2] = selfPosY + 40;

                        return;
                    }
                }
            }

            // 乱数取得
            function getRandVal(min, max){
                return (Math.floor(Math.random() * (max - min + 1))) + min;
            }

            // 当たり判定(ミサイルと敵)
            function judgementHitMissile(){
                for ( var i = 0; i < enemies.length; i++ ){
                    // ミサイルと敵の当たり判定
                    for( var j = 0; j < missiles.length; j++ ){
                        if ( missiles[j][0] === true ){
                            // ミサイルのposXからエネミーのposXの差の絶対値が当たり判定値以内かどうか?
                            if( (enemies[i][0] < (missiles[j][1] + 20 )) && (missiles[j][1] < (enemies[i][0] + enemies[i][4][0]))){
                                // ミサイルのposYからエネミーのposYの差の絶対値が当たり判定値以内かどうか?
                                if( (missiles[j][2] > enemies[i][1]) && (missiles[j][2] < (enemies[i][1] +  enemies[i][4][1]))){
                                    // 当たり判定
                                    missiles[j][0] = false;
                                    score += enemies[i][4][3];
                                    enemies[i] = createEnemy();
                                }
                            }
                        }

                        // 自機と敵の当たり判定
                        // 自機と敵の中心座標を計算
                        selfCenterPos[0] = selfPosX + 40;
                        selfCenterPos[1] = selfPosY + 40;
                        enemyCenterPos[0] = enemies[i][0] + (enemies[i][4][0] / 2); // center X
                        enemyCenterPos[1] = enemies[i][1] + (enemies[i][4][1] / 2); // center Y

                        if ( enemies[i][0] > 0 && enemies[i][1] > 0 ){
                            if(abs(abs(selfCenterPos[0]) - abs(enemyCenterPos[0])) < 100){
                                // ミサイルのposYからエネミーのposYの差の絶対値が当たり判定値以内かどうか?
                                if(abs(abs(selfCenterPos[1]) - abs(enemyCenterPos[1])) < 100){
                                    // 当たり判定
                                    // 厳密な当たり判定
                                    var hitRange = ((enemies[i][4][0] / 2) + 40) * 0.7;
                                    if(strictHitJudge(selfCenterPos, enemyCenterPos , hitRange)){
                                         playFlag = false;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // スコアを表示
            function drawScore(score){
                // スコアラベルを描画
                context.drawImage(scoreImg, 0, 0);
                context.font = "30px Arial"; //フォントにArial,40pxを指定
                context.fillStyle = "white"; 
                context.fillText((("00000000"+score).slice(-8)),137,43);      //テキストを塗り潰しで描画
            }

            // スコアを表示
            function drawSpace(){
                // スコアラベルを描画
                for ( var i = 0; i < bgImgs.length; i++ ){
                    if( bgImgs[i][1] === -860){
                        if(bgImgs[i][0] === bgImg1 ){
                            bgImgs[i][0] = bgImg2;
                        } else if(bgImgs[i][0] === bgImg2 ){
                            bgImgs[i][0] = bgImg1;
                        }
                        bgImgs[i][1] = 1720;
                    }
                    context.drawImage(bgImgs[i][0], bgImgs[i][1], 0);
                    bgImgs[i][1]--;
                } 
            }

            // 絶対値を取得
            function abs(value){
                return Math.abs(value);
            }

            // 自機と敵の厳密当たり判定
            function strictHitJudge(selfCenterPos, enemyCenterPos , hitRange){
                var x = abs(abs(selfCenterPos[0]) - abs(enemyCenterPos[0]));
                var y = abs(abs(selfCenterPos[1]) - abs(enemyCenterPos[1]));
                var distance = Math.sqrt(Math.pow(x,2) + Math.pow(y,2));                
                if( hitRange > distance){ return true; } else { return false; };
            }
        </script>
        <div id="link"></div>
    </body>
</html>

遊んでみたい方はこちら

→シューティングゲーム

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1