JavaScript小游戏系列之贪吃蛇

    趁着周末,再赶一篇。这篇是关于贪吃蛇的。贪吃蛇的移动算法改了好几次,一开始出现了很搞笑的移动轨迹,调整了几次,总算是能够正常的爬了。

   首先,还是说一下总体的思路。

1.游戏开始,生成游戏区,同样是个二维数组--m,我用的是20*20的。随机挑选坐标生成小蛇,用head对象记录蛇头,用tail对象记录蛇尾坐标(我设定的开局时蛇头蛇尾时同一个点),并把这个点放进记录蛇身的snake数组中。在界面中展示就是0。

//startPoint
var rx = Math.floor(Math.random() *this.x),
    ry = Math.floor(Math.random() *this.y),
    rb = $('.box[x='+ rx + '][y='+ ry +']');
this.head.hx = rx;
this.head.hy = ry;
this.tail.tx = rx;
this.tail.ty = ry;
this.m[rx][ry] = 1;
rb.text('0');
this.snake.push([rx,ry]);


2.生成食物。nullBox数组用来记录空白区域,即数组m中去掉数组snake中保存的坐标。其实就是数组m中值为0的坐标。然后在nullBox中随机找一个点,这个点就是新食物所在坐标。界面展示时我用的‘*’代替食物。
this.createFood = function () {
    this.nullBox = [];
    for(var i = 0;i < this.x;i++){
        for(var j = 0;j < this.y;j++){
           if(this.m[i][j] == 0){
               this.nullBox.push([i,j]);
           }
        }
    }
    if(this.nullBox.length > 0){
        var f = Math.floor(Math.random() *this.nullBox.length);
        this.food.fx = this.nullBox[f][0];
        this.food.fy = this.nullBox[f][1];
    }
}

3.监听方向变化。初始四个方向up,down,left,right都为false。当用户按下方向键时,改变方向状态。
window.addEventListener('keydown',function (e) {
    switch (e.which){
        case 37:
            _this.left = true;
            _this.up = false;
            _this.right = false;
            _this.down = false;
            break;
        case 38:
            _this.left = false;
            _this.up = true;
            _this.right = false;
            _this.down = false;
            break;
        case 39:
            _this.left = false;
            _this.up = false;
            _this.right = true;
            _this.down = false;
            break;
        case 40:
            _this.left = false;
            _this.up = false;
            _this.right = false;
            _this.down = true;
            break;
    }
})

4.移动。移动我设置了个定时器,每隔0.5秒去检查移动方向的变化。show函数就是用来渲染界面的。
this.move = setInterval(function () {
    if(_this.up){
        _this.moveUp();
    }else if(_this.down){
        _this.moveDown();
    }else if(_this.left){
        _this.moveLeft();
    }else if(_this.right){
        _this.moveRight();
    }
    _this.show();
},500)

5.具体的某个方向移动。以右移为例。第一步检查是否可移动。右移,所以检查蛇头的下一个坐标,也就是(head.hx,head.hy+1)是否还在游戏区,如果不在,就结束,清除定时器;如果还在游戏区,就向右移动。移动有两种情况:①下一个点是食物,则把食物点添加到snake数组的首位,更新蛇头坐标(head.hx,head.hy),生成新食物点。②下一个点不是食物,更新蛇头蛇尾坐标,更新snake数组。
 
this.moveRight = function () {
    if(_this.goOn(_this.head.hx,_this.head.hy+1)){
        if(_this.stepForward(_this.head.hx,_this.head.hy+1)){

        }
    }else {
        _this.gameOver();
    }
}
this.goOn = function (i,j) {
    if(i >= 0 && i < _this.x && j >= 0 && j < _this.y && this.m[i][j] == 0){
        return true;
    }
    return false;
}
this.stepForward = function (i,j) {
    if(i == _this.food.fx && j == _this.food.fy){
        //eat
        _this.snake.unshift([i,j]);
        _this.m[i][j] = 1;
        _this.head.hx = i;
        _this.head.hy = j;
        _this.createFood();
    }else{
        //step
        _this.snake.unshift([i,j]);
        var len = _this.snake.length;
        var empty = _this.snake[len-1];
        _this.snake.pop();
        _this.m[empty[0]][empty[1]] = 0;
        _this.head.hx = _this.snake[0][0];
        _this.head.hy = _this.snake[0][1];
        _this.m[_this.head.hx][_this.head.hy] = 1; 
    }
}

基本上就是这样了。谢谢大家的观看,欢迎提出宝贵意见。

最后还是附上所有代码吧,也可以访问我的GitHub

JS:

/**
 * Created by PC on 2017/12/7.
 */
$(function () {
    var start = true;
    window.addEventListener('keydown',function () {
        if(start){
            var game = new Game();
            game.start();
            start = false;
        }
    })
})

var Game = function () {

    this.x = 20;
    this.y = 20;
    this.m = [];
    this.snake = [];
    this.head = {
        hx : 0,
        hy : 0
    }
    this.tail = {
        tx : 0,
        ty : 0
    }
    //direction
    this.up = false;
    this.down = false;
    this.left = false;
    this.right = false;
    this.food = {
        fx : 0,
        fy : 0
    }
    this.nullBox = [];
    _this = this;

    this.start = function () {
        this.createBox();
        this.createFood();
        
        window.addEventListener('keydown',function (e) {
            switch (e.which){
                case 37:
                    _this.left = true;
                    _this.up = false;
                    _this.right = false;
                    _this.down = false;
                    break;
                case 38:
                    _this.left = false;
                    _this.up = true;
                    _this.right = false;
                    _this.down = false;
                    break;
                case 39:
                    _this.left = false;
                    _this.up = false;
                    _this.right = true;
                    _this.down = false;
                    break;
                case 40:
                    _this.left = false;
                    _this.up = false;
                    _this.right = false;
                    _this.down = true;
                    break;
            }
        })

        this.move;
        
    }
    
    this.createBox = function () {
        for(var i = 0;i < this.x;i++){
            this.m[i] = [];
            for(var j = 0;j < this.y;j++){
                this.m[i][j] = 0;
                var box = "<div class='box' x='"+ i +"' y='"+ j +"'></div>";
                $('#container').append(box);
            }
            $('#container').append("<br>")
        }

        //startPoint
        var rx = Math.floor(Math.random() *this.x),
            ry = Math.floor(Math.random() *this.y),
            rb = $('.box[x='+ rx + '][y='+ ry +']');
        this.head.hx = rx;
        this.head.hy = ry;
        this.tail.tx = rx;
        this.tail.ty = ry;
        this.m[rx][ry] = 1;
        rb.text('0');
        this.snake.push([rx,ry]);

    }
    
    this.createFood = function () {
        this.nullBox = [];
        for(var i = 0;i < this.x;i++){
            for(var j = 0;j < this.y;j++){
               if(this.m[i][j] == 0){
                   this.nullBox.push([i,j]);
               }
            }
        }
        if(this.nullBox.length > 0){
            var f = Math.floor(Math.random() *this.nullBox.length);
            this.food.fx = this.nullBox[f][0];
            this.food.fy = this.nullBox[f][1];
        }
    }

    this.move = setInterval(function () {
        if(_this.up){
            _this.moveUp();
        }else if(_this.down){
            _this.moveDown();
        }else if(_this.left){
            _this.moveLeft();
        }else if(_this.right){
            _this.moveRight();
        }
        _this.show();
    },500)

    this.moveUp = function () {
        if(_this.goOn(_this.head.hx-1,_this.head.hy)){
            if(_this.stepForward(_this.head.hx-1,_this.head.hy)){

            }
        }else {
            _this.gameOver();
        }
    }

    this.moveDown = function () {
        if(_this.goOn(_this.head.hx+1,_this.head.hy)){
            if(_this.stepForward(_this.head.hx+1,_this.head.hy)){

            }
        }else {
            _this.gameOver();
        }
    }

    this.moveLeft = function () {
        if(_this.goOn(_this.head.hx,_this.head.hy-1)){
            if(_this.stepForward(_this.head.hx,_this.head.hy-1)){

            }
        }else {
            _this.gameOver();
        }
    }

    this.moveRight = function () {
        if(_this.goOn(_this.head.hx,_this.head.hy+1)){
            if(_this.stepForward(_this.head.hx,_this.head.hy+1)){

            }
        }else {
            _this.gameOver();
        }
    }
    
    this.stepForward = function (i,j) {
        if(i == _this.food.fx && j == _this.food.fy){
            //eat
            _this.snake.unshift([i,j]);
            _this.m[i][j] = 1;
            _this.head.hx = i;
            _this.head.hy = j;
            _this.createFood();
        }else{
            //step
            _this.snake.unshift([i,j]);
            var len = _this.snake.length;
            var empty = _this.snake[len-1];
            _this.snake.pop();
            _this.m[empty[0]][empty[1]] = 0;
            _this.head.hx = _this.snake[0][0];
            _this.head.hy = _this.snake[0][1];
            _this.m[_this.head.hx][_this.head.hy] = 1;
            // _this.tail.tx = _this.snake[len-1][0];
            // _this.tail.ty = _this.snake[len-1][1];
            // _this.m[_this.tail.tx][_this.tail.ty] = 1;
        }
    }
    
    this.goOn = function (i,j) {
        if(i >= 0 && i < _this.x && j >= 0 && j < _this.y && this.m[i][j] == 0){
            return true;
        }
        return false;
    }

    this.gameOver = function () {
        alert('Over');
        clearInterval(_this.move);
    }
    
    this.show = function () {
        for(var i = 0;i < this.x;i++){
            for(var j = 0;j < this.y;j++){
                if(this.m[i][j] != 0){
                    $('.box[x='+ i +'][y='+ j +']').text('0');
                }else {
                    $('.box[x='+ i +'][y='+ j +']').text('');
                }
            }
        }
        var fx = this.food.fx,
            fy = this.food.fy;
        $('.box[x='+ fx +'][y='+ fy +']').text('*');
    }




}


html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Game-snake</title>
    <style>
        .box { display: inline-block; width: 40px; height: 40px; line-height: 40px; border: 1px solid #fff; background: #eee; cursor: pointer; text-align: center; vertical-align: middle; }
    </style>
</head>
<body style="text-align:center">
<div style="margin: 10px;">
    <div id="container"></div>
</div>

<script src="jquery.min.js"></script>
<script src="snake.js"></script>
</body>
</html>





1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值