javascript - 停止我的贪吃蛇游戏中的 setTimeout 循环?

标签 javascript jquery

我创建了一个贪吃蛇游戏,当蛇撞到墙壁或撞到自己时,它仍然不会停止移动。我发现如果我使用clearTimeout(),它会有所帮助。但事实并非如此。 有没有办法停止循环?或者这是另一个问题?

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) 我将drawSnake重命名为createSnake。当您调用 init() 时,您并没有完全重新初始化蛇。在之前的 drawSnake 方法中,蛇的位置没有被重置,所以看起来游戏无法玩。

之后又出现了 2 个错误。

2)你必须在调用gameOver后返回,否则游戏永远不会真正结束,不是吗?一旦您清除了 gameover 中的超时,您就立即在 moveSnake() 的最后一行设置另一个 Timeout,因为游戏结束后您没有返回。这会导致奇怪的结果,让游戏看起来没有响应。

3) 您使用了visibility nonevisible$.hide() 的组合。 $.hide() 使用 display: none,因此当您尝试通过 visibility 样式更改再次显示它时,它仍然是 display: none 因此新的游戏按钮将停止出现。

我对任何游戏编码员的建议是学习如何分离处理游戏如何工作的代码(游戏的逻辑,时钟如何走动,游戏状态的初始化等),以及它如何显示(html和CSS)。在清晰编写的系统之后对游戏逻辑进行建模很容易阅读和调试。当显示代码与游戏逻辑混合时,代码变得更难以理解和修改。理论上,我们的游戏应该在没有任何渲染的情况下完美运行。然后我们可以编写一个渲染器来生成 HTML Canvas 、html DOM、命令行中的文本或 OpenGL。

这是一个我从未完成的旧项目,它应该说明模型和 View 之间的分离。

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>

关于javascript - 停止我的贪吃蛇游戏中的 setTimeout 循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42012577/

相关文章:

javascript - 如何从主题标签转换的字符串中删除起始逗号 - ES6

javascript - Angularjs 在表插入期间递增和递减

javascript - 使用 jQuery 获取第一个以 <td> 为子级的 N <tr>

javascript - jQuery 从多维数组中获取值

javascript - 如何取消图像模糊?

php - 菜鸟: display err_msg on page (pt. 2)

javascript - 默认情况下取消选中复选框

javascript - 如何从 jquery 更新 Controller 变量?

javascript - 如果我想使用 jquery-ui 1.12.0 将两个图标添加到一个按钮怎么办

javascript - 如何防止此 transitionend 事件运行两次/多次?