2017-02-23 14 views
1

私は単純なゲームを作った。目標は、レーザーを避けることによって生き続けることです。しかし、プレーヤーがレーザー警告を通過するたびにレーザーを消して奇妙に見えます。私はすでに警告を再描画しようとしましたが、それが起こるたびにうまく動作せず、バグが発生します。ここ私の単純なゲームでは、プレーヤーは常にレーザーの警告を消すので、私はそれを修正するように見えません。

<!DOCTYPE html> 
<html> 
<head> 
<title> 
    Drift 2 
</title> 
</head> 
<body> 
<center> 
<h1>Drift 2</h1> 
<h2>by Milesman34</h2> 
<canvas id="canvas" width="400" height="400"></canvas> 
<strong><p id="score">Score</p></strong> 
</center> 
<script src="https://code.jquery.com/jquery-2.1.0.js"></script> 
<script> 
    //MARK: Set up the canvas + canvas variables and draws the border + background 
    var canvas = document.getElementById("canvas"); 
    var ctx = canvas.getContext("2d"); 

    var width = canvas.width; 
    var height = canvas.height; 

    var blockSize = 20; 
    var widthInBlocks = width/blockSize; 
    var heightInBlocks = height/blockSize; 

    ctx.fillStyle = "rgb(225, 225, 225)"; 
    ctx.fillRect(0, 0, width, height); 
    //MARK: Defines arrays and variables 
    var shooterArray = []; 
    var score = 0; 
    //MARK: Defines functions 
    function getRandomFromInterval(interval) { 
     return Math.floor(Math.random() * interval); 
    }; 
    //MARK: Defines game over function 
    var gameEnd = 0; 
    function gameOver() { 
     setTimeout (function() { 
      gameEnd = 1; 
      clearInterval (scoreEffects); 
      clearInterval (fireEffects); 
      ctx.clearRect(blockSize, blockSize, width - (blockSize * 2), height - (blockSize * 2)) 
      ctx.fillStyle = "rgb(225, 225, 225)"; 
      ctx.fillRect(blockSize, blockSize, width - (blockSize * 2), height - (blockSize * 2)); 
      ctx.font = "60px Courier"; 
      ctx.fillStyle = "Black"; 
      ctx.textAlign = "center"; 
      ctx.textBaseline = "middle"; 
      ctx.fillText("Game Over", width/2, height/2); 
     }, 149); 
    }; 
    //MARK: Defines the player 
    function Player (x, y) { 
     this.x = x; 
     this.y = y; 
    }; 
    //MARK: Defines the function that draws the player 
    Player.prototype.draw = function() { 
     ctx.fillStyle = "rgb(185, 185, 185)"; 
     ctx.fillRect(this.x, this.y, blockSize, blockSize); 
    }; 
    var player = new Player(width/2, height/2); 
    player.draw(); 
    //MARK: Defines the functions that move the player 
    Player.prototype.moveLeft = function() { 
     ctx.clearRect(this.x, this.y, blockSize, blockSize); 
     this.x = this.x - 20; 
     ctx.fillStyle = "rgb(225, 225, 225)"; 
     ctx.fillRect(this.x + 20, this.y, blockSize, blockSize); 
    }; 
    Player.prototype.moveRight = function() { 
     ctx.clearRect(this.x, this.y, blockSize, blockSize); 
     this.x = this.x + 20; 
     ctx.fillStyle = "rgb(225, 225, 225)"; 
     ctx.fillRect(this.x - 20, this.y, blockSize, blockSize); 
    }; 
    Player.prototype.moveUp = function() { 
     ctx.clearRect(this.x, this.y, blockSize, blockSize); 
     this.y = this.y - 20; 
     ctx.fillStyle = "rgb(225, 225, 225)"; 
     ctx.fillRect(this.x, this.y + 20, blockSize, blockSize); 
    }; 
    Player.prototype.moveDown = function() { 
     ctx.clearRect(this.x, this.y, blockSize, blockSize); 
     this.y = this.y + 20; 
     ctx.fillStyle = "rgb(225, 225, 225)"; 
     ctx.fillRect(this.x, this.y - 20, blockSize, blockSize); 
    }; 
    Player.prototype.checkWallCollision = function() { 
     if (this.x === 0 || this.x === width - 20 || this.y === 0 || this.y === height - 20) { 
      gameOver(); 
     }; 
    }; 
    //MARK: Defines the Shooter 
    function Shooter (x, y, direction) { 
     this.x = x; 
     this.y = y; 
     if (["left", "right", "up", "down"].indexOf(direction) != -1) { 
      this.direction = direction; 
     }; 
     shooterArray.push(this); 
    }; 
    //MARK: Defines the function that draws the Shooter 
    Shooter.prototype.draw = function() { 
     ctx.fillStyle = "rgb(185, 185, 185)"; 
     ctx.fillRect(this.x, this.y, blockSize, blockSize); 
    }; 
    //MARK: Defines the function that fires the Shooter 
    var timeoutID = null; 
    function fireLeftRight(y) { 
     if (gameEnd === 0) { 
      ctx.fillStyle = "Red"; 
      ctx.fillRect(blockSize, y, width - (blockSize * 2), blockSize); 
      if (player.y === y) { 
       gameOver(); 
      }; 
     }; 
    }; 
    function fireLeftRightWarn(y) { 
     ctx.fillStyle = "Red"; 
     for (i = 1;i < widthInBlocks - 1;i++) { 
      ctx.fillRect(i * blockSize + (blockSize/4), y + (blockSize/4 * 1.5), blockSize/2, blockSize/4); 
     }; 
     timeoutID2 = setTimeout (function() { 
      clearTimeout (timeoutID); 
      timeoutID = setTimeout (fireLeftRight(y), 100); 
     }, 600); 
    }; 
    function fireUpDown(x) { 
     if (gameEnd === 0) { 
      ctx.fillStyle = "Red"; 
      ctx.fillRect(x, blockSize, blockSize, height - (blockSize * 2)); 
      if (player.x === x) { 
       gameOver(); 
      }; 
     }; 
    }; 
    function fireUpDownWarn(x) { 
     ctx.fillStyle = "Red"; 
     for (i = 1;i < heightInBlocks - 1;i++) { 
      ctx.fillRect(x + (blockSize/4 * 1.5), i * blockSize + (blockSize/4), blockSize/4, blockSize/2); 
     }; 
     timeoutID2 = setTimeout (function() { 
     clearTimeout (timeoutID); 
     timeoutID = setTimeout (fireUpDown(x)) 
     }, 600); 
    }; 
    Shooter.prototype.fire = function() { 
     if (this.direction === "left" || this.direction === "right") { 
      timeoutID = setTimeout (fireLeftRightWarn(this.y), 1); 
     } else { 
      timeoutID = setTimeout (fireUpDownWarn(this.x), 1) 
     }; 
    }; 
    //MARK: Creates the required shooters 
    for (i = 1;i < heightInBlocks - 1;i++) { 
     new Shooter(0, i * blockSize, "right"); 
    }; 
    for (i = 1;i < heightInBlocks - 1;i++) { 
     new Shooter(width - blockSize, i * blockSize, "left"); 
    }; 
    for (i = 1;i < widthInBlocks - 1;i++) { 
     new Shooter(i * blockSize, 0, "down"); 
    }; 
    for (i = 1;i < widthInBlocks - 1;i++) { 
     new Shooter(i * blockSize, height - blockSize, "up") 
    }; 
    for (i = 0;i < shooterArray.length;i++) { 
     shooterArray[i].draw(); 
    }; 
    ctx.fillStyle = "rgb(185, 185, 185)"; 
    ctx.fillRect(0, 0, blockSize, blockSize); 
    ctx.fillRect(width - blockSize, 0, blockSize, blockSize); 
    ctx.fillRect(0, height - blockSize, blockSize, blockSize); 
    ctx.fillRect(width - blockSize, height - blockSize, blockSize, blockSize); 
    //MARK: Draws the score 
    function drawScore() { 
     $("#score").text("Score: " + Math.floor(score)); 
    }; 
    //MARK: Convert keycodes to directions 
    var directions = { 
     37: "left", 
     38: "up", 
     39: "right", 
     40: "down" 
    }; 
    //MARK: This is the interval loop 
    var scoreEffects = setInterval (function() { 
     score += 0.1; 
     drawScore(); 
     player.draw(); 
     player.checkWallCollision(); 
    }, 100); 
    $("body").keyup(function (event) { 
      if (gameEnd != 1) { 
       var moveDir = directions[event.keyCode]; 
       if (moveDir === "left") { 
        player.moveLeft(); 
       } else if (moveDir === "right") { 
        player.moveRight(); 
       } else if (moveDir === "up") { 
        player.moveUp(); 
       } else if (moveDir === "down") { 
        player.moveDown(); 
       }; 
      }; 
     }); 
    var fireEffects = setInterval (function() { 
     ctx.clearRect(blockSize, blockSize, width - (blockSize * 2), height - (blockSize * 2)) 
     ctx.fillStyle = "rgb(225, 225, 225)"; 
     ctx.fillRect(blockSize, blockSize, width - (blockSize * 2), height - (blockSize * 2)); 
     ctx.fillStyle = "rgb(185, 185, 185)"; 
     ctx.fillRect(0, 0, blockSize, blockSize); 
     ctx.fillRect(width - blockSize, 0, blockSize, blockSize); 
     ctx.fillRect(0, height - blockSize, blockSize, blockSize); 
     ctx.fillRect(width - blockSize, height - blockSize, blockSize, blockSize); 
     for (i = 0;i < shooterArray.length;i++) { 
      if (getRandomFromInterval(30) === 0) { 
       shooterArray[i].fire(); 
      }; 
     }; 
    }, 750); 
</script> 

+0

これは[JSFiddle](https://jsfiddle.net/2keb9930/)で意図した機能が何であるかはわかりません。 – leigero

+0

プレーヤを別のキャンバスレイヤーに描画してみませんか?お互いの上に2つのキャンバスを置いてください。プレーヤーのキャンバスを上に置き、クリアな背景にします。 'fillStyle =" rgba(0,0,0,0) ";' レーザー警告の描画をクリアするプレーヤーの動きを心配する必要はありません。 – bobjoe

答えて

1

作業するプロジェクト:https://jsfiddle.net/ay7kp7yb/1/

私はこの問題を解決するための最善のアプローチは、古典的なパターンで動作するようにだと思います。そうすることで、ゲームで発生するすべてのイベントをメインループに連結する必要があります(Game Loop参照)。以下のような

何か:あなたのコードで

while (true) 
{ 
    processInputs(); 
    updateObjects(); 
    render(); 
} 

のsetTimeout /のsetIntervalで独立して起こっていくつかのイベントは、それがイベント "を合わせる" ことが非常に複雑になります。

2つの組み合わせのテクニックを使用することをお勧めします。まず、すべてのイベントを1つのループ(メインゲームループ)に集中させ、2つ目はゲームを制御する一連の状態を作成することです。

ゲームの状態:

// game states 
var STATE_TITLE_SCREEN = 0; 
var STATE_GAME_STARTING = 1; 
var STATE_RUNNING = 2; 
var STATE_PLAYER_DYING = 3; 
var STATE_GAME_OVER_SCREEN = 4; 

// current state 
var gameState = STATE_TITLE_SCREEN; 

// time of the current state 
var gameStateTime = 0; 

// change the state and reset the time of last state 
function setGameState(state) { 
    gameState = state; 
    gameStateTime = 0; 
} 

メインループ:

var minIteractionTime = 10; 
var mainGameLoop = setInterval (function() { 

    switch (gameState) { 

     case STATE_TITLE_SCREEN: 
      // Title screen (on press space bar, change gameState to STATE_GAME_STARTING) 
     break; 

     case STATE_GAME_STARTING: 
      // Starting game, reset variables, countdown to start, etc... 
      score = 0.0; 

      // run the game after 5s 
      if (gameStateTime>5000) 
       setGameState(STATE_RUNNING); 

     break; 

     case STATE_RUNNING: 
      score += (0.1/100.0); // 0.1 points after 100 miliseconds 

      // CLEAR THE SCREEN HERE 

      drawScore(); 
      player.draw(); // draw the player ONLY here 
      laserWarning.draw(); // Draws the warnings AFTER draw the player 
      laserbeam.burn(player); // try to burn the player 
     break; 



     case STATE_PLAYER_DYING: 
      // player dying animation.. 

      // after 5s, change show the game over screen 
      if (gameStateTime>5000) 
       setGameState(STATE_GAME_OVER_SCREEN); 
     break; 

     case STATE_GAME_OVER_SCREEN: 
      // draw the game over screen here 

      // after 5s returns to the title screen 
      if (gameStateTime>5000) 
       setGameState(STATE_TITLE_SCREEN); 
     break; 
    } 

    // add the loop time in the gameStateTime variable 
    gameStateTime += minIteractionTime; 

}, minIteractionTime); 

LaserWarningクラス:

LaserWarning.prototype.draw = function() { 
    this.warningTime += minIteractionTime; 

    if (this.warningTime>100) { 
     // draw the warning only after firsts 100ms 
    } 

    if (this.warningTime>=750) { // warning time 
     // timer reset 
     this.warningTime = 0; 
    } 

} 

レーザ光クラス:

Laserbeam.prototype.burn = function (player) { 
    this.warmingUpTime += minIteractionTime; 

    if (this.warmingUpTime>=750) { // same time of warning 

     // draw the laser 

     // check if burns the player 
     if (player.checkWallCollision()) { 
      setGameState(STATE_PLAYER_DYING); 
     } 
    } 
} 

入力iteractions:

var gameKeys = { 
    37: "left", 
    38: "up", 
    39: "right", 
    40: "down", 
    32: "space" 
}; 

// for all iteractions, check the current state 
$("body").keyup(function (event) { 

    var lastKey = gameKeys[event.keyCode]; 

    switch (gameState) { 
     case STATE_RUNNING: 
      if (lastKey === "left") { 
       player.moveLeft(); 
      } else if (lastKey === "right") { 
       player.moveRight(); 
      } else if (lastKey === "up") { 
       player.moveUp(); 
      } else if (lastKey === "down") { 
       player.moveDown(); 
      }; 
     break; 

     case STATE_TITLE_SCREEN: 
      if (lastKey=="space") 
       setGameState(STATE_GAME_STARTING); 
     break; 
    } 
}); 

あなたがプレーヤーを移動するときにのみ、位置決め変数を調整する必要があり、これは(player.drawに起こるのだろう、新しい位置でそれを再描画しません)。をSTATE_RUNNINGに入れてから、警告を表示してください。

ユーザーが右矢印を10ms(minIteractionTime)未満で2回押すと、プレーヤーは1回だけ描​​画されます。もっと正確にする必要がある場合は、minIteractionTimeの値を減らしてください。

変数minIteractionTimeがフレームレートを制御します。

+0

私はこれをやってみました。ただし、GAME_RUNNING状態になるとフリーズします。コード: http:// pastebin。com/tmCDA7jj – milesman34

+0

こんにちは@ melesman34、私はいくつかの変更を加え、今は正しく動作していると思います。コメントを残しておいて、私が行った変更を理解することができます。 [link](https://jsfiddle.net/ay7kp7yb/1/) – dreadnought

関連する問題