专栏首页前端儿无聊的人用JS实现了一个简单的打地鼠游戏

无聊的人用JS实现了一个简单的打地鼠游戏

直入正题,用JS实现一个简单的打地鼠游戏

因为功能比较简单就直接裸奔JS了,先看看效果图,或者 在线玩玩 吧 

如果点击颜色比较深的那个(俗称坏老鼠),将扣分50;如果点击颜色比较浅的那个(俗称好老鼠),将得分100

实现

老鼠好像有点难画,又不想用图片,就直接用CSS画个简单的图代表老鼠和坑吧

html结构

挺简单,用9个 li 标签代表坑,用9个 div 标签代表老鼠

  <div class="container">
        <h4>无聊打打地鼠</h4>

        <div class="game-top">
            <p><input type="button" value="开始游戏" id="game-start"><p>
            <p>得分:<span id="game-score">0</span></p>
            <p>剩余时间:<span id="game-time">60</span> s</p>
        </div>
        <div class="game-content">
            <ul>
                <li><div></div></li>
                <li><div></div></li>
                <li><div></div></li>
                <li><div></div></li>
                <li><div></div></li>
                <li><div></div></li>
                <li><div></div></li>
                <li><div></div></li>
                <li><div></div></li>
            </ul>
        </div>
    </div>

CSS的实现

有点小技巧

对于坑,加个box-shadow: ... inset 美化一下样式

        .game-content li {
            float: left;
            margin-top: 50px;
            margin-left: 30px;
            width: 100px;
            height: 50px;
            border-radius: 50%;
            background-color: #67d0b4;
            box-shadow: 0 0 50px #706565 inset;
        }

对于老鼠,用 border-radius:50%/40% 绘制,第二个参数还是有点使用价值的

        .game-content div {
            position: relative;
            margin-top: -15px;
            margin-left: 25px;
            width: 50px;
            height: 70px;
            border-radius: 50%/40%;
            background-color: #dfb25d;
            opacity: 0;
        }

而要让老鼠动起来,这里的处理方式就是用动画了,老鼠运动的时候,先往上再往下即可,控制好相对位置看起来和谐一点就行

        @keyframes mouse-move {
            50% {
                margin-top: -40px;
                opacity: 1;
            }
            100% {
                margin-top: -15px;
                opacity: 0;
            }
        }
        .game-content div.active {
            animation: mouse-move 2s ease-in-out infinite;
        }

注意 animation: ... infinite 的使用,让动画能一直进行下去,我们使用JS控制好时间差判断应该显示那个老鼠,应该显示多少只老鼠即可

不然的画,会发现动画完成了再也无法让它继续进行了

点击的是好老鼠还是坏老鼠,应该给出提示如:

可以直接用CSS的伪元素::after置入对错,在点击的时候,根据不同的性质设置不同的值及颜色

.game-content div.good {
    background-color: #dfb25d;
}
.game-content div.good[clicked="1"]::after {
    content: "✓";
    line-height: 70px;
    font-size: 40px;
    color: #0ad845;
}

.game-content div.bad {
    background-color: #a48f5c;
}
.game-content div.bad[clicked="1"]::after {
    content: "✕";
    line-height: 70px;
    font-size: 40px;
    color: #db1536;
}
  1 .container {
  2     width: 500px;
  3     height: 300px;
  4     margin: 50px auto;
  5     border: 1px solid #ddd;
  6     text-align: center;
  7 }
  8 
  9 .game-top {
 10     padding-top: 10px;
 11     width: 100%;
 12     height: 90px;
 13 }
 14 .game-top p {
 15     margin: 5px;
 16 }
 17 
 18 .game-content {
 19     overflow: auto;
 20     width: 100%;
 21     border-top: 1px solid #ddd;
 22     background-color: #ddf;
 23 }
 24 
 25 .game-content ul {
 26     list-style: none;
 27 }
 28 .game-content li {
 29     float: left;
 30     margin-top: 50px;
 31     margin-left: 30px;
 32     width: 100px;
 33     height: 50px;
 34     border-radius: 50%;
 35     background-color: #67d0b4;
 36     box-shadow: 0 0 50px #706565 inset;
 37 }
 38 .game-content li:last-child {
 39     margin-bottom: 50px;
 40 }
 41 
 42 .game-content div {
 43     position: relative;
 44     margin-top: -15px;
 45     margin-left: 25px;
 46     width: 50px;
 47     height: 70px;
 48     border-radius: 50%/40%;
 49     background-color: #dfb25d;
 50     opacity: 0;
 51 }
 52 
 53 .game-content div.good {
 54     background-color: #dfb25d;
 55 }
 56 .game-content div.good[clicked="1"]::after {
 57     content: "✓";
 58     line-height: 70px;
 59     font-size: 40px;
 60     color: #0ad845;
 61 }
 62 
 63 .game-content div.bad {
 64     background-color: #a48f5c;
 65 }
 66 .game-content div.bad[clicked="1"]::after {
 67     content: "✕";
 68     line-height: 70px;
 69     font-size: 40px;
 70     color: #db1536;
 71 }
 72 
 73 @media screen and (max-width: 500px) {
 74     .container {
 75         width: 290px;
 76     }
 77     .game-content ul {
 78         padding: 0;
 79     }
 80     .game-content li {
 81         margin-left: 5px;
 82         width: 90px;
 83     }
 84     .game-content div {
 85         margin-left: 20px;
 86     }
 87 }
 88 
 89 @-webkit-keyframes mouse-move {
 90     50% {
 91         margin-top: -40px;
 92         opacity: 1;
 93     }
 94     100% {
 95         margin-top: -15px;
 96         opacity: 0;
 97     }
 98 }
 99 @keyframes mouse-move {
100     50% {
101         margin-top: -40px;
102         opacity: 1;
103     }
104     100% {
105         margin-top: -15px;
106         opacity: 0;
107     }
108 }
109 
110 .game-content div.active {
111     -webkit-animation: mouse-move 2s ease-in-out infinite;
112         animation: mouse-move 2s ease-in-out infinite;
113 }

JS的处理

逻辑是点击开始游戏,倒计时开始,同时好坏老鼠不断运动,控制好坑中好坏老鼠及其数量的随机性,点击好老鼠加分,点击坏老鼠减分,时间到结束游戏。

先看看老鼠的运动

          // 运动操作
            moveUpAndDown: function() {
                var that = this;

                // 定时器随机定义good|bad老鼠个数,以及需要显示的个数
                that.moveTime = setInterval(function() {

                    for (var i = 0, j = that.mouses.length; i < j; ++i) {
                        that.mouses[i].setAttribute('clicked', '0');
                        that.mouses[i].className = 'good active';
                        that.mouses[i].style.display = 'none';
                    }

                    // bad 的个数
                    var badNum = that.getRandom(0, 8);
                    for (var i = 0; i < badNum; i++) {
                        that.mouses[that.getRandom(0, 8)].className = 'bad active';
                    }

                    // 要显示的个数
                    var showNum = that.getRandom(0, 8);
                    for (var i = 0; i < showNum; i++) {
                        that.mouses[that.getRandom(0, 8)].style.display = 'block';
                    }
                }, 2000);
            },

使用定时器,定时器的循环与CSS中的动画设置一致,保证循环连贯性

设置class为good 即可定义出一只好老鼠,同理bad 为坏老鼠

在开始游戏,进行调用时,设置class为active 即可让老鼠运动起来

对于打老鼠的操作,要注意到只有运动的老鼠才能点击,每只老鼠只能点击一次

              // 打地鼠操作
                that.mousesWrap[0].addEventListener('click', function(e) {
                    e = e || window.event;
                    var elem = e.target || e.srcElement;
                    // 如果当前项被隐藏则不操作,多次点击只取第一次分数
                    if (elem.style.display !== 'block' || elem.getAttribute('clicked') === '1') {
                        return;
                    }
                    // 扣分
                    if (elem.className.indexOf('bad') !== -1) {
                        that.score -= that.badScore;
                    }
                    // 加分
                    else {
                        that.score += that.goodScore;
                    }

                    elem.setAttribute('clicked', '1');
                    that.text(that.gameScore[0], that.score);
                }, false);

倒计时结束之后,清除两个计时器,同时将所有老鼠项display都设为none 即可(否则动画会一直循环展示出来)

            // 倒计时,当前剩余游戏时间
            countDown: function() {
                var that = this;

                var t = setInterval(function() {
                    that.text(that.gameTime[0], --that.totalTime);

                    if (that.totalTime === 0) {
                        clearInterval(t);
                        clearInterval(that.moveTime);

                        for (var i = 0, j = that.mouses.length; i < j; ++i) {
                            that.mouses[i].style.display = 'none';
                        }

                        alert('游戏结束,得分为:' + that.score);
                    }
                }, 1000);
            },
  1     function MouseGame() {
  2             this.mousesWrap = this.$('.game-content');
  3             this.mouses = this.$('.game-content div');
  4             this.gameStart = this.$('#game-start');
  5             this.gameTime = this.$('#game-time');
  6             this.gameScore = this.$('#game-score');
  7             this.goodScore = 100;
  8             this.badScore = 50;
  9 
 10             this.bindEvent();
 11         }
 12 
 13         MouseGame.prototype = {
 14             constructor: MouseGame,
 15 
 16             /**
 17              * 获取元素
 18              * @param  {String} elem 元素的字符串标识
 19              * @example
 20              * $('div') | $('p.active')
 21              * @return {NodeList}      获取的元素集
 22              */
 23             $: function(elem) {
 24                 return document.querySelectorAll(elem);
 25             },
 26 
 27             /**
 28              * 获取给定范围的随机数
 29              * @param  {Number} from 起始
 30              * @param  {Number} to   结束
 31              * @return {Number}      随机数
 32              */
 33             getRandom: function(from, to) {
 34                 return Math.floor(Math.random() * (to - from + 1)) + from;
 35             },
 36 
 37             /**
 38              * 设置元素内容
 39              * @param  {HTMLElement} elem 要设置的元素
 40              * @param  {String} val  设置的内容
 41              * @return {String}      设置好的内容|元素本身的内容
 42              */
 43             text: function(elem, val) {
 44                 if (elem.textContent) {
 45                     return val !== undefined ? elem.textContent = val : elem.textContent;
 46                 } else if (elem.innerText) {
 47                     return val !== undefined ? elem.innerText = val : elem.innerText;
 48                 }
 49             },
 50 
 51             // 运动操作
 52             moveUpAndDown: function() {
 53                 var that = this;
 54 
 55                 // 定时器随机定义good|bad老鼠个数,以及需要显示的个数
 56                 that.moveTime = setInterval(function() {
 57 
 58                     for (var i = 0, j = that.mouses.length; i < j; ++i) {
 59                         that.mouses[i].setAttribute('clicked', '0');
 60                         that.mouses[i].className = 'good active';
 61                         that.mouses[i].style.display = 'none';
 62                     }
 63 
 64                     // bad 的个数
 65                     var badNum = that.getRandom(0, 8);
 66                     for (var i = 0; i < badNum; i++) {
 67                         that.mouses[that.getRandom(0, 8)].className = 'bad active';
 68                     }
 69 
 70                     // 要显示的个数
 71                     var showNum = that.getRandom(0, 8);
 72                     for (var i = 0; i < showNum; i++) {
 73                         that.mouses[that.getRandom(0, 8)].style.display = 'block';
 74                     }
 75                 }, 2000);
 76             },
 77 
 78             // 打地鼠操作
 79             bindEvent: function() {
 80                 var that = this;
 81 
 82                 // 监听游戏开始/重新开始
 83                 that.gameStart[0].addEventListener('click', function() {
 84                     that.startGame();
 85                 }, false);
 86 
 87                 // 打地鼠操作
 88                 that.mousesWrap[0].addEventListener('click', function(e) {
 89                     e = e || window.event;
 90                     var elem = e.target || e.srcElement;
 91                     // 如果当前项被隐藏则不操作,多次点击只取第一次分数
 92                     if (elem.style.display !== 'block' || elem.getAttribute('clicked') === '1') {
 93                         return;
 94                     }
 95                     // 扣分
 96                     if (elem.className.indexOf('bad') !== -1) {
 97                         that.score -= that.badScore;
 98                     }
 99                     // 加分
100                     else {
101                         that.score += that.goodScore;
102                     }
103 
104                     elem.setAttribute('clicked', '1');
105                     that.text(that.gameScore[0], that.score);
106                 }, false);
107             },
108 
109             // 倒计时,当前剩余游戏时间
110             countDown: function() {
111                 var that = this;
112 
113                 var t = setInterval(function() {
114                     that.text(that.gameTime[0], --that.totalTime);
115 
116                     if (that.totalTime === 0) {
117                         clearInterval(t);
118                         clearInterval(that.moveTime);
119                         
120                         for (var i = 0, j = that.mouses.length; i < j; ++i) {
121                             that.mouses[i].style.display = 'none';
122                         }
123 
124                         alert('游戏结束,得分为:' + that.score);
125                     }
126                 }, 1000);
127             },
128 
129             // 开始游戏
130             startGame: function() {
131                 this.score = 0;
132                 this.totalTime = 60;
133                 this.text(this.gameTime[0], this.totalTime);
134                 this.text(this.gameScore[0], this.score);
135 
136                 this.countDown();
137                 this.moveUpAndDown();
138             }
139         };
140 
141         new MouseGame();

代码有注释应该不难看懂了

那么..快来fork吧..

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 如何实现同等间隙的卡片布局

    在列表展示中,经常会使用卡片的内容展示形式,为了美观,常常要求各卡片间的间隙是一致的。

    书童小二
  • SASS用法指南

    SASS是ruby写的,所以要想将sass编译成css文件,就给配上ruby环境。

    书童小二
  • 卡片列表项缓缓往下展示 效果实现

    似乎项目中也有类似的卡片列表,列表的展示是直接显示出来的,加上动效之后应该更有活力,便照着样子实现了一下

    书童小二
  • 【答疑释惑】固定菜单滚动

    分享一下滚动菜单源码,可以直接用,希望对盟友有帮助 <!DOCTYPE html> <html> <head> <meta charset="utf-8...

    程序员互动联盟
  • 制作自己的“疫情地图”

    布局采用一张图的思路,将疫情信息以浮动框的形式飘在地图上,分别为:图例,置于左下角;统计数据,置于右下角;汇总数据以及数据源说明,置于右上角;左上角区域,添加地...

    lzugis
  • 自定义按钮~自适应布局~常见bug

    超然
  • 基于Qt的类QQ气泡聊天的界面开发(二)

    http://blog.csdn.net/esonpo/article/details/25974999

    bear_fish
  • 来来来,手把手教你做大白!

    这个东西也是经常被拿来玩的一个小东西,就是通过border-radius 去自己切一个图形。

    疯狂的技术宅
  • RN性能优化(重新探索react吧)

    <!-- p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; line-height: 19.0px; font: 13.0px 'H...

    windseek
  • 一个CSS画的灰太狼,IE下属于重口味,慎看!

    还有几个不错的,比如一个小日本制作的多啦A梦,一个Twitter的当机页面等等,大家可以搜下看看.不得不感叹做前端的哥们闲起来还真是可怕啊.Firefox是正常...

    练小习

扫码关注云+社区

领取腾讯云代金券