使用前端原生 js,贪吃蛇小游戏

好久好久,真的是好久好久没来写过了,因为最近有点小忙。不过即使是忙,也也还是写了两个小游戏,其中一个就是这个,贪吃蛇啦。

算是一个小练手了,这个是在有点太简单了,只是第一次写这种小游戏,还是零零星星花了三五天时间,下面就是这个小游戏的gif小动画,比较简单,对比过网上其他用来写出来练手的贪吃蛇作品,这个在颜值还是功能上,都还是不错的,霍霍。

这里讲解一下功能:

  1. 空格控制开始和暂停。
  2. 方向键控制移动方向。
  3. Q 键加速,再按一次恢复常规速度(在加速状态时,按下或者方向键,或者吃到了白色小食物,速度自动恢复正常)。

这次我研究了 github,一个用来管理代码版本的国外网站,不过使用它不需要FQ,它的一个功能,就是可以用来展示网站,比如我就把贪吃蛇放在里 github 中,可以点击后面的链接访问,也就是可以直接玩耍:点击这里打开贪吃蛇

想描述一下技术要点。。。发现有点小忘了,不过一个难点还是记得的,当蛇的身子比较长后,容易和自己挨住,会连成一块,看上去很不方便,所以我在中间添加了这条缝隙,如下图所示,为添加前和添加后的效果:

这条缝隙的添加还是比较麻烦的,我的思路是,给组成蛇身的每个 li 元素小块,都设置个 1px 的border背景色边框,接着每一个 li 的后面跟一个宽度为 2px,高度和 li 等高的 span 标签,背景颜色和li相同,再通过css设置好位置,正好可以补上蛇身中两个正常相连的 li 小块之间,那个 2px 的缝隙,为什么是 2px 呢?因为前一个 li 和后一个 li,各都有 1px 的 border。

源代码也放在下面吧,免得以后啥时候我改了 github 配置,上面那个链接不能使用了。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>贪吃蛇</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        body {
            background-color: #090e20;
        }

        .big {
            width: 1000px;
            height: 600px;
            border: 1px dashed #fff;
            margin: 30px auto 0;
            position: relative;
        }
        p {
            margin-bottom: 10px;
        }
        .right span {
            position: absolute;
            width: 20px;
            height: 20px;
            background-color: #fff;
            border-radius: 30%;
        }
        ul li {
            list-style: none;
            position: absolute;
            width: 20px;
            height: 20px;
            background-color: #b5cad5;
            box-sizing: border-box;
            border: 1px solid #090e20;
        }
        ul li b {
            display:block;
            z-index: 100;
            width: 2px;
            height: 18px;
            background-color: #b5cad5;
            position: absolute;
            top: 0;
            left: 8px;
            transform-origin: 11px 9px;
            transform: translate(-10px,0) rotate(0deg);
        }
        ul li:first-child b {
            width: 4px;
            transform: translate(-12px,0) rotate(0deg);
        }
        ul li:last-child b {
            background-color: transparent;
        }

        ul li:nth-child(1) {
            border-radius: 0 50% 50% 0;
            /*transform:scale(2,2);*/
        }

        ul li:nth-child(1):before {
            content: ‘‘;
            display: block;
            background-color: #090e20;
            width: 2px;
            height: 2px;
            position: absolute;
            bottom: 5px;
            right: 10px;
            z-index: 2;
        }

        ul li:nth-child(1):after {
            content: ‘‘;
            display: block;
            background-color: #090e20;
            width: 2px;
            height: 2px;
            position: absolute;
            top: 5px;
            right: 10px;
        }
        .explain {
            float: left;
            box-sizing: border-box;
            border-right: 1px dashed #fff;
            height: 100%;
            width: 260px;
            color: #fff;
        }
        .explain em {
            color: #b3c6ff;
            font-style: normal;
        }

        ol li {
            margin-left: 25px;
        }

        .right {
            width: 740px;
            float: right;
            height: 100%;
            position: relative;
            box-sizing: border-box;
        }
    </style>
</head>
<body>
<div class="big">
    <div class="explain">
        <p>点击<em>空格</em>开始或暂停</p>
        <p>可通过<em>WASD</em>或者<em>方向键</em>控制方向</p>
        <p>可通过<em>回车键</em>或者<em>Q</em>加速</p>
        <p>当改变方向,或者吃到小球,速度自动恢复正常</p>
        <br>
        <p>以下为每局吃掉的小球个数</p>
        <ol></ol>
    </div>
    <div class="right">
        <span></span>
        <ul>
        </ul>
    </div>
</div>
</body>
<script>
    window.onload = function () {
        //获取元素节点
        var big = document.querySelector(".big");
        var span = document.querySelector("span");
        var ul = document.querySelector("ul");
        var ol = document.querySelector("ol");
        var ol_lis; //预留的ol中的li标签
        var lis;//预留的ul中的li标签,即贪吃蛇的身子
        var times;//速度,初始为150
        var arrall;//二维数组,每一项为一个数组,其中保存每个li的x轴y轴坐标和方向
        var timer;//蛇运动时的定时器
        var timers;//数组,蛇吃到小球,小球白点顺着身子流动的定时器,之所以是数组,是因为可能上一个小球白点还没到尾部,蛇又吃了一个
        var index;//数组,和times绑定的
        var direction; //现在蛇运动的方向
        var flag; //判断是否按下了方向键
        var num;//用来记忆最初始有几个li,计数吃掉几个小球时减去
        var stars = false;//判断是否游戏中true或者false
        var spanX;//保存食物小球的坐标
        var spanY;
        star();
        //初始化函数
        function star() {
            times = 200;
            arrall = [];
            timers = [];
            index = [];
            ul.innerHTML = "<li></li><li></li><li></li><li></li>";
            lis = document.querySelectorAll("ul li");
            num = lis.length;
            //给每一个li定位,且记录到arrall中
            for (var i = lis.length - 1; i >= 0; i--) {
                var arr = [0, 20 * i, "right"];
                arrall[arrall.length] = arr;
                lis[i].style.top = 0;
                lis[i].style.left = 20 * (lis.length - 1 - i) + "px";
                var b = document.createElement(‘b‘);
                lis[i].appendChild(b);
            }
            //给arrall多造一个子元素,用来为吃到小点后新增的身子赋值;
            arrall[arrall.length] = [0, 20 * lis.length - 1, "right"];
            spanPosition();//生成span小球事物
            timer = null;
            direction = ‘right‘;
            flag = null;
        }
        //生成小白球函数
        function spanPosition() {
            var temp;
            do {
                temp = false;
                spanX = Math.floor(Math.random() * 36) * 20;
                spanY = Math.floor(Math.random() * 29) * 20;
                //for循环来保证小白球不会出现在蛇身体的内部
                for (var i = 0; i < lis.length; i++) {
                    if (spanX == arrall[i][1] &&
                        spanY == arrall[i][0]) {
                        temp = true;
                        break;
                    }
                }
            } while (temp);
            span.style.left = spanX + "px";
            span.style.top = spanY + "px";
            span.style.display = "block";
        }
        //按下键盘按键
        document.onkeydown = function (e) {
        	//如果是红的,则屏蔽所有按键
            if (lis[0].style.backgroundColor === "red") return;
            //如果是空格键
            if (e.keyCode == 32) {
                if (timer) {
                    clearInterval(timer);
                    timer = null;
                    flag = true;
                } else {
                    timer = setInterval(move, times);
                    flag = false;
                    //如果游戏没有运行,也就是初次启动,而不是暂停后的启动
                    if (!stars) {
                    	//如果是失败了,蛇头为红色,此时也屏蔽空格
                        var li = document.createElement(‘li‘);
                        li.innerHTML = "吃掉小球数量为:" + (arrall.length - 1 - num) + "枚!";
                        ol.appendChild(li);
                        ol_lis = document.querySelectorAll("ol li");
                        stars = true;
                    }
                }
                return;
            }
            //如果游戏没有开始开,则其他按键失效
            if (!stars) return;
            //如果是回车或者Q
            if (e.keyCode == 13 || e.keyCode == 81) {
                if (timer) {
                    clearInterval(timer);
                    if (times == "50") times = 200;
                    else times = 50;
                    timer = setInterval(move, times);
                } else {
                    if (times == "50") times = 200;
                    else times = 50;
                }
                return;
            }
            if (flag) return;
            if (e.keyCode == 38 || e.keyCode == 87) {
                if (direction == "bottom" || direction == "top") {
                    return;
                }
                flag = ‘top‘;
            } else if (e.keyCode == 37 || e.keyCode == 65) {
                if (direction == "right" || direction == "left") {
                    return;
                }
                flag = ‘left‘;
            } else if (e.keyCode == 39 || e.keyCode == 68) {
                if (direction == "left" || direction == "right") {
                    return;
                }
                flag = ‘right‘;
            } else if (e.keyCode == 40 || e.keyCode == 83) {
                if (direction == "top" || direction == "bottom") {
                    return;
                }
                flag = ‘bottom‘;
            } else {
                returnValue = false;
                return;
            }
            times = 200;
            clearInterval(timer);
            move();
        }
        //移动函数
        function move() {
            //如果安了方向键,那么为direction赋flag的值
            if (flag) {
                direction = flag;
            }
            //用for循环依次移动每一个li
            for (var i = arrall.length - 1; i >= 0; i--) {
                if (i == arrall.length - 1) {
                    var arrs = [];
                    arrs[0] = arrall[i - 1][0];
                    arrs[1] = arrall[i - 1][1];
                    arrs[2] = arrall[i - 1][2];
                    arrall[i] = arrs;
                } else {
                    //如果是第一个li,把它的方向信息及时更新
                    if (i == 0) {
                        arrall[i][2] = direction;
                    } else {
                        //如果不是,把li移动的方向设置为前一个的
                        arrall[i][2] = arrall[i - 1][2];
                    }
                    //根据方向来更新位置
                    switch (arrall[i][2]) {
                        case "top" :
                            arrall[i][0] -= 20;
                            lis[i].style.top = arrall[i][0] + "px";
                            lis[i].querySelector(‘b‘).style.transform = "translate(-10px,0) rotate(270deg)";
                            break;
                        case "right" :
                            arrall[i][1] += 20;
                            lis[i].style.left = arrall[i][1] + "px";
                            lis[i].querySelector(‘b‘).style.transform = "translate(-10px,0) rotate(0deg)";
                            break;
                        case "bottom" :
                            arrall[i][0] += 20;
                            lis[i].style.top = arrall[i][0] + "px";
                            lis[i].querySelector(‘b‘).style.transform = "translate(-10px,0) rotate(90deg)";
                            break;
                        case "left" :
                            arrall[i][1] -= 20;
                            lis[i].style.left = arrall[i][1] + "px";
                            lis[i].querySelector(‘b‘).style.transform = "translate(-10px,0) rotate(180deg)";
                            break;
                    }
                }
            }
            lis[0].querySelector(‘b‘).style.transform= "translate(-12px,0) rotate(0deg)";
            //再判断是不是按下了方向键,用来转动蛇头
            if (flag) {
                if (flag == "bottom") {
                    lis[0].style.transform = "rotate(90deg)";
                } else if (flag == "right") {
                    lis[0].style.transform = "rotate(0deg)";
                } else if (flag == "left") {
                    lis[0].style.transform = "rotate(180deg)";
                } else if (flag == "top") {
                    lis[0].style.transform = "rotate(270deg)";
                }
                flag = null;
                timer = setInterval(move, times);
            }
            //判断是否吃掉了小球
            if (arrall[0][0] == spanY && arrall[0][1] == spanX) {
                clearInterval(timer);
                times = 200;
                timer = setInterval(move, times);
                //新产生一枚小球点
                span.style.display = "none";
                spanPosition();
                //下面两个是启动产生小白点的函数定时器
                index[index.length] = 1;
                timers[timers.length] = setInterval(dingshi,20,timers.length);
            }
            //判断有没有碰到墙壁或自己
            for (var i = 1; i < lis.length; i++) {
                if (arrall[0][0] == arrall[i][0] &&
                    arrall[0][1] == arrall[i][1] ||
                    arrall[0][0] < 0 ||
                    arrall[0][0] == 600 ||
                    arrall[0][1] < 0 ||
                    arrall[0][1] == 740) {
                    clearInterval(timer);
                    lis[0].style.zIndex = lis.length;
                    lis[0].style.backgroundColor = "red";
                    stars = false;
                    var tempTimer = setTimeout(function(){
                        lis[0].style.backgroundColor = "#b5cad5";
                        star();
                    },1000);
                    break;
                }
            }
        }
        //吃掉小球,出现顺着蛇身子移动的白点的函数
        function dingshi(temp){
            lis[index[temp]].style.backgroundColor = "#b5cad5";
            if (index[temp] == lis.length-1) {
                clearInterval(timers[temp]);
                //新生成的li的数组,其位置和方向信息等于之前的最后一个li
                var arr = [arrall[arrall.length - 1][0], arrall[arrall.length - 1][1], arrall[arrall.length - 1][2]];
                arrall[arrall.length] = arr;
                //创建新的li元素,并且用另一个函数,给这个li赋值位置和方向信息
                var li = document.createElement("li");
                var b = document.createElement(‘b‘);
                li.appendChild(b);
                ul.appendChild(li);
                lis = document.querySelectorAll("ul li");
                lis[lis.length - 1].style.top = arr[0] + "px";
                lis[lis.length - 1].style.left = arr[1] + "px";
                ol_lis[ol_lis.length - 1].innerHTML = "吃掉小球数量为:" + (arrall.length - 1 - num) + "枚!";
                return ;
            };
            lis[index[temp]+1].style.backgroundColor = "#fff";
            index[temp]++;
        }
    }
</script>
</html>

  

时间: 2024-11-05 13:28:33

使用前端原生 js,贪吃蛇小游戏的相关文章

JS贪吃蛇小游戏

效果图展示: 具体实现代码如下: (1)html部分 1 !DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <title>贪吃蛇</title> 6 <link rel="stylesheet" type="text/css" href="main.css"> 7 </h

使用Html5+JS做的贪吃蛇小游戏

学习了Html5的Canvas的使用,和JS创建对象,做了一个贪吃蛇小游戏,来巩固JS面向对象编程和Canvas的用法. Node.js 1 /** 2 * 格子类,组成贪吃蛇和舞台 3 */ 4 function Node(x,y){ 5 this.x=x; 6 this.y=y; 7 /** 8 * 比较两个格子是否重合 9 */ 10 this.equals=function(x,y){ 11 return this.x==x&&this.y==y; 12 } 13 } Snake.

一个简单的“贪吃蛇”小游戏

一个简单的“贪吃蛇”小游戏 页面结构 简单的21x21的方块,页面结构 id为container的div包含所21个class名为row的div,每个row代表贪吃蛇的一整行,每个row中又包含21个div,代表这一行的每一个div方格,如果这个方格是空的话,div的类名为blank,如果这一个方格表示“贪吃蛇”的“食物”,div的类名为food,如果这一个方格表示“蛇”,div的类名为snake. CSS JS 然后我们思考下一个贪吃蛇游戏需要那些参数, 首先,界面中可见的元素无非就是空方格,

贪吃蛇小游戏 (一)

贪吃蛇是一款儿时爱不释手的游戏.近日修行,想玩玩游戏开发.便简单写了个控制台版的贪吃蛇. 程序的简单框架: 建立一张固定大小的MAP,保存输出信息. 当信息有变动时,用system("cls")进行清屏操作,再重新输出实现伪动态. 重点算法在蛇身的移动,转向与增长.三者均基于链表实现. 移动与转向:通过判定移动方向,确定下一步移动的位置后,新建表头结点.将新表头结点置为表头.删除末尾结点. 增长:通过判断尾部移动方向,确定位置后在尾部添加节点. 熟练运用链表的同学,相信也是小菜一碟了.

贪吃蛇小游戏的初步尝试制作

这里利用二维数组做为地图,利用集合来存放蛇头和蛇尾的位置坐标,初步实现一个需要键盘控制的贪吃蛇小游戏. 首先,Main函数下面需要一个大循环来让游戏失败的时候能够重新开始,这里我们用了定义了一个bool型的sc,判断sc的true和flase来确定游戏是否开始: static void Main(string[] args)        { bool sc = true; while (sc) //大循环,用于游戏失败重新开始            { 下面是定义一个集合snake_x来存放蛇

Java版贪吃蛇小游戏的实现

使用的IDE eclipse JDK版本 1.6 辅助类 Coordinate.java package com.nn.util; /** *坐标点 */ public class Coordinate { public int x; public int y; public Coordinate(int newX, int newY) { x = newX; y = newY; } public boolean equals(Coordinate other) { if (x == other

原生js打飞机小游戏

最近为了巩固一下原生的知识,然后拿了一个js小游戏来入手.主要也是为了学习和练手. js代码如下: 1 window.onload = function(){ 2 var oBtn = document.getElementById('gameBtn'); 3 oBtn.onclick = function(){ 4 this.style.display = 'none'; 5 Game.init('div1');//把父级传进去 6 }; 7 }; 8 //创建Game单体 9 10 var

贪吃蛇小游戏java实现代码分析

贪吃蛇小游戏java实现代码分析 贪吃蛇的小游戏,网上的代码比较多,今天周五,在教研室没啥事做,在电脑中发现了一个贪吃蛇的小游戏,于是就看了下实现的源码,发现别人写的代码确实挺好的,自己也是边加注释边进行理解的去看别人实现的游戏源码,发现还是挺有意思的.自己花了一个下午的时间看了源码,也加了一点小小的功能,于是,不写篇博客觉得对不起自己也,哈哈哈. 此游戏代码的思路非常的清晰,也相当好理解,没有太多难的地方,不过有很多值得学习的地方,因为,这份源码中,对java.awt包中的很多类的很多方法都进

用C写一个功能较为完善的贪吃蛇小游戏

主要功能: 方向控制-食物与增长-变速 1 #include<stdio.h> 2 #include<time.h>//种子-随机数 3 #include<windows.h>//system函数,控制台句柄 4 #include<conio.h>//按键 5 //界面(欢迎界面-游戏界面-结束得分界面)-驱动-方向控制-食物 6 //位置锁定-打印-删除 7 int snake_x[520]={0}; 8 int snake_y[520]={0}; 9 i