2017-02-02 2 views
2

Я создал игру змеи, и когда змея ударила по стене или к ней, она все равно не перестает двигаться. Я понял, использовал ли clearTimeout(), это поможет. но это не так. Есть ли способ остановить цикл? или это еще одна проблема? остановка setTimeout цикл в моей игре змей?

jQuery(document).ready(function($) { 
 
    init(); 
 
}); 
 

 
var move; 
 
function init() { 
 
    board.initBoard(); 
 
    drawSnake(); 
 
    food.createFood(); 
 
} 
 

 
function play() { 
 
    $('.newGame').css('visibility', 'hidden'); 
 
    $('.playgame').css('visibility', 'hidden'); 
 
    moveSnake(); 
 
    getSnakeDir(); 
 
} 
 

 
function gameover() { 
 
    clearTimeout(move); 
 
    $('.newGame').css('visibility', 'visible'); 
 
} 
 

 
function playGame() { 
 
    $('#gameboard').empty(); 
 
    $('.newGame').hide(); 
 
    init(); 
 
    play(); 
 
} 
 

 
var board = { 
 
    DIM: 20, 
 
    initBoard: function() { 
 
     for (var i = 0; i < board.DIM; i++) { 
 
      var row = $('<div class="row-' + i + '"></div>'); 
 
      
 
      for (var j = 0; j < board.DIM; j++) { 
 
       var col = ('<div class="col-' + j + '-' + i + '"></div>'); 
 
       $(row).append(col); 
 
      } 
 
      $("#gameboard").append(row); 
 
     } 
 
    } 
 
} 
 

 
var snake = { 
 
    position: ['10-10', '10-11', '10-12'], 
 
    direction: 'r', 
 
    speed: 200, 
 
}; 
 

 
function drawSnake() { 
 
    $('.col-10-10').addClass('snake'); 
 
    $('.col-11-10').addClass('snake'); 
 
} 
 

 
function getSnakeDir() { 
 
    $(document).keydown(function(event) { 
 
     //event.preventDefault(); 
 
     if (event.which == 38) { 
 
      snake.direction = 'u'; 
 
     } else if (event.which == 39) { 
 
      snake.direction = 'r'; 
 
     } else if (event.which == 40) { 
 
      snake.direction = 'd'; 
 
     } else if (event.which == 37) { 
 
      snake.direction = 'l'; 
 
     } 
 
    }); 
 
} 
 

 
function moveSnake() { 
 
    var tail = snake.position.pop(); 
 
    $('.col-' + tail).removeClass('snake'); 
 

 
    var coords = snake.position[0].split('-'); 
 
    var x = parseInt(coords[0]); 
 
    var y = parseInt(coords[1]); 
 

 
    if (snake.direction == 'r') { 
 
     x = x + 1; 
 
    } else if (snake.direction == 'd') { 
 
     y = y + 1; 
 
    } else if (snake.direction == 'l') { 
 
     x = x - 1; 
 
    } else if (snake.direction == 'u') { 
 
     y = y - 1; 
 
    } 
 
    
 
    var currentcoords = x + '-' + y; 
 
    snake.position.unshift(currentcoords); 
 

 
    $('.col-' + currentcoords).addClass('snake'); 
 

 
    //when snake eats food 
 
    if (currentcoords == food.coords) { 
 
     console.log('true'); 
 
     $('.col-' + food.coords).removeClass('food'); 
 
     snake.position.push(tail); 
 
     food.createFood(); 
 
    } 
 

 
    //game over 
 
    if (x < 0 || y < 0 || x > board.DIM || y > board.DIM) { 
 
     gameover(); 
 
    
 
    } 
 

 
    //if snake touch itself 
 
    if (hitItself(snake.position) == true) { 
 
     gameover(); 
 
    } 
 
    
 
    move=setTimeout(moveSnake, 200); 
 
} 
 

 
var food = { 
 
    coords: "", 
 

 
    createFood: function() { 
 
     var x = Math.floor(Math.random() * (board.DIM-1)) + 1; 
 
     var y = Math.floor(Math.random() * (board.DIM-1)) + 1; 
 
     var fruitCoords = x + '-' + y; 
 
     $('.col-' + fruitCoords).addClass('food'); 
 
     food.coords = fruitCoords; 
 
    }, 
 
} 
 

 
function hitItself(array) { 
 
    var valuesSoFar = Object.create(null); 
 
    for (var i = 0; i < array.length; ++i) { 
 
     var value = array[i]; 
 
     if (value in valuesSoFar) { 
 
      return true; 
 
     } 
 
     valuesSoFar[value] = true; 
 
    } 
 
    return false; 
 
}
.buttonnewgame { 
 
    position: relative; 
 
} 
 

 
.newGame { 
 
    position: absolute; 
 
    top: 45%; 
 
    left: 25%; 
 
    padding: 15px; 
 
    font-size: 1em; 
 
    font-family: arial; 
 
    visibility: hidden; 
 
} 
 

 
.gameContainer{ 
 
    width: 100%; 
 
} 
 

 
#gameboard { 
 
    background-color:#eee; 
 
    padding:3px; 
 
} 
 

 
.playgame { 
 
    position: absolute; 
 
    top: 45%; 
 
    left: 20%; 
 
    padding: 15px; 
 
    font-size: 1em; 
 
    font-family: arial;  
 
} 
 

 
/* styling the board */ 
 
div[class^='row'] { 
 
    height: 15px; 
 
    text-align: center; 
 
} 
 

 
div[class*='col']{ 
 
    display: inline-block; 
 
    border: 1px solid grey; 
 
    width: 15px; 
 
    height: 15px; 
 
} 
 

 
/*display the snake*/ 
 
.snake { 
 

 
    background-color: blue; 
 
    z-index: 99; 
 
} 
 

 
.food { 
 
    background: red; 
 
    z-index: 99; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<div class="game"> 
 
    <div class="buttonnewgame"> 
 
     <input type="button" name="new game" value="new game" class="newGame" onclick="playGame()" /> 
 
     <button class="playgame" onclick="play()">Play Game</button> 
 
     <div class="gameContainer"> 
 
      <div id="gameboard"> 
 
       <!-- snake game in here --> 
 
      </div> 
 
     </div> 
 
    </div> 
 
</div>

ответ

1

Были некоторые проблемы, но здесь есть 'рабочая версия' (там больше ошибок) ,

1) Я переименовал drawSnake в createSnake. Вы не полностью переинициализировали змею, когда вы позвонили init(). Позиция змей не сбрасывалась в предыдущем методе drawSnake, поэтому казалось, что игра не воспроизводится.

После этого было еще 2 ошибки.

2) Вы должны вернуть после того, как вы позвоните gameOver или игра никогда не заканчивается? Как только вы очистите тайм-аут в gameover, вы сразу же установите другой тайм-аут в последней строке moveSnake(), потому что вы не вернулись, как только игра закончилась. Это приводит к странным результатам, из-за которых казалось, что игра не реагирует.

3) Вы использовали комбинацию visibilitynone или visible и $.hide(). $.hide() использует display: none, поэтому, когда вы попытались показать его снова с изменением стиля visibility, его по-прежнему display: none, чтобы новая кнопка игры перестала появляться.

Мой совет любому игровому кодеру состоит в том, чтобы узнать, как отделить код, который обрабатывает работу игры (логика игры, как тикает часы, инициализация состояния игры и т. Д.) И как она отображается (html и css). Моделирование логики игры после чисто письменной системы легко читается и отлаживается. Код становится сложнее понять и изменить, когда код дисплея смешивается с логикой игры. Теоретически, наша игра должна работать отлично без какого-либо рендеринга. Затем мы могли бы написать рендерер, который создает HTML-холст, html DOM, текст в командной строке или OpenGL.

Heres старый проект, который я никогда не заканчивал, который должен иллюстрировать разделение между моделью и видом.

http://tando.us/ganix/ganix.htm

jQuery(document).ready(function($) { 
 
    init(); 
 
}); 
 

 
var move; 
 
function init() { 
 
    board.initBoard(); 
 
    createSnake(); 
 
    food.createFood(); 
 
} 
 

 
function play() { 
 
    $('.newGame').hide(); 
 
    $('.playgame').hide(); 
 
    moveSnake(); 
 
    getSnakeDir(); 
 
} 
 

 
function gameover() { 
 
    clearTimeout(move); 
 
    $('.newGame').show(); 
 
} 
 

 
function playGame() { 
 
    $('#gameboard').empty(); 
 
    $('.newGame').hide(); 
 
    init(); 
 
    play(); 
 
} 
 

 
var board = { 
 
    DIM: 20, 
 
    initBoard: function() { 
 
     for (var i = 0; i < board.DIM; i++) { 
 
      var row = $('<div class="row-' + i + '"></div>'); 
 
      
 
      for (var j = 0; j < board.DIM; j++) { 
 
       var col = ('<div class="col-' + j + '-' + i + '"></div>'); 
 
       $(row).append(col); 
 
      } 
 
      $("#gameboard").append(row); 
 
     } 
 
    } 
 
} 
 

 
var snake = { 
 
    position: ['10-10', '10-11', '10-12'], 
 
    direction: 'r', 
 
    speed: 200, 
 
}; 
 

 
function createSnake() { 
 
    $('.col-10-10').addClass('snake'); 
 
    $('.col-11-10').addClass('snake'); 
 
    snake.position = ['10-10', '10-11', '10-12']; 
 
} 
 

 
function getSnakeDir() { 
 
    $(document).keydown(function(event) { 
 
     //event.preventDefault(); 
 
     if (event.which == 38) { 
 
      snake.direction = 'u'; 
 
     } else if (event.which == 39) { 
 
      snake.direction = 'r'; 
 
     } else if (event.which == 40) { 
 
      snake.direction = 'd'; 
 
     } else if (event.which == 37) { 
 
      snake.direction = 'l'; 
 
     } 
 
    }); 
 
} 
 

 
function moveSnake() { 
 
    var tail = snake.position.pop(); 
 
    $('.col-' + tail).removeClass('snake'); 
 

 
    var coords = snake.position[0].split('-'); 
 
    var x = parseInt(coords[0]); 
 
    var y = parseInt(coords[1]); 
 

 
    if (snake.direction == 'r') { 
 
     x = x + 1; 
 
    } else if (snake.direction == 'd') { 
 
     y = y + 1; 
 
    } else if (snake.direction == 'l') { 
 
     x = x - 1; 
 
    } else if (snake.direction == 'u') { 
 
     y = y - 1; 
 
    } 
 
    
 
    var currentcoords = x + '-' + y; 
 
    snake.position.unshift(currentcoords); 
 

 
    $('.col-' + currentcoords).addClass('snake'); 
 

 
    //when snake eats food 
 
    if (currentcoords == food.coords) { 
 
     console.log('true'); 
 
     $('.col-' + food.coords).removeClass('food'); 
 
     snake.position.push(tail); 
 
     food.createFood(); 
 
    } 
 

 
    //game over 
 
    if (x < 0 || y < 0 || x > board.DIM || y > board.DIM) { 
 
     gameover(); 
 
     return; 
 
    
 
    } 
 

 
    //if snake touch itself 
 
    if (hitItself(snake.position) == true) { 
 
     gameover(); 
 
     return; 
 
    } 
 
    
 
    move=setTimeout(moveSnake, 200); 
 
} 
 

 
var food = { 
 
    coords: "", 
 

 
    createFood: function() { 
 
     var x = Math.floor(Math.random() * (board.DIM-1)) + 1; 
 
     var y = Math.floor(Math.random() * (board.DIM-1)) + 1; 
 
     var fruitCoords = x + '-' + y; 
 
     $('.col-' + fruitCoords).addClass('food'); 
 
     food.coords = fruitCoords; 
 
    }, 
 
} 
 

 
function hitItself(array) { 
 
    var valuesSoFar = Object.create(null); 
 
    for (var i = 0; i < array.length; ++i) { 
 
     var value = array[i]; 
 
     if (value in valuesSoFar) { 
 
      return true; 
 
     } 
 
     valuesSoFar[value] = true; 
 
    } 
 
    return false; 
 
}
.buttonnewgame { 
 
    position: relative; 
 
} 
 

 
.newGame { 
 
    position: absolute; 
 
    top: 45%; 
 
    left: 25%; 
 
    padding: 15px; 
 
    font-size: 1em; 
 
    font-family: arial; 
 
} 
 

 
.gameContainer{ 
 
    width: 100%; 
 
} 
 

 
#gameboard { 
 
    background-color:#eee; 
 
    padding:3px; 
 
} 
 

 
.playgame { 
 
    position: absolute; 
 
    top: 45%; 
 
    left: 20%; 
 
    padding: 15px; 
 
    font-size: 1em; 
 
    font-family: arial;  
 
} 
 

 
/* styling the board */ 
 
div[class^='row'] { 
 
    height: 15px; 
 
    text-align: center; 
 
} 
 

 
div[class*='col']{ 
 
    display: inline-block; 
 
    border: 1px solid grey; 
 
    width: 15px; 
 
    height: 15px; 
 
} 
 

 
/*display the snake*/ 
 
.snake { 
 

 
    background-color: blue; 
 
    z-index: 99; 
 
} 
 

 
.food { 
 
    background: red; 
 
    z-index: 99; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<div class="game"> 
 
    <div class="buttonnewgame"> 
 
     <input type="button" name="new game" value="new game" class="newGame" style="display:none;" onclick="playGame()" /> 
 
     <button class="playgame" onclick="play()">Play Game</button> 
 
     <div class="gameContainer"> 
 
      <div id="gameboard"> 
 
       <!-- snake game in here --> 
 
      </div> 
 
     </div> 
 
    </div>

+0

Благодарим вас за подробное объяснение. И это сработало! Чтобы отметить, я сделал эту игру около 5 месяцев назад, прежде чем узнавать о MVC. и ты прав. это беспорядок кода. но я пытаюсь включить его, поскольку это для портфеля, чтобы показать недостатки и прогресс. еще раз, спасибо :) – Ndx

+0

Рабочий беспорядочный код предпочтительнее по сломанному коду. Вы на правильном пути. – GantTheWanderer

1

Вы можете попробовать не инициировать новый setTimeout заходящих в и функции moveSnake, но вместо того, чтобы использовать.

function play() { 
    $('.newGame').css('visibility', 'hidden'); 
    $('.playgame').css('visibility', 'hidden'); 
    move = setInterval(moveSnake, 200); 
    getSnakeDir(); 

} 

и удалить

move = setTimeout(moveSnake, 200) 

из функции moveSnake и сделать

function gameover() { 
    clearInterval(move); 
    $('.newGame').css('visibility', 'visible'); 
} 
+0

Я сделал это, и она работала. Но змея не движется после того, как вы нажмете новую игру. – Ndx

+0

@Nordax, вам нужно будет сбросить свою игру при нажатии кнопки и снова запустить функцию setTimeout. – Ibu

+0

То, что я сделал в функции playGame(). почему это не работает? – Ndx

Смежные вопросы