手把手教你用JS写一个贪食蛇小游戏

本文阅读时间10分钟,要求你有一定的html5+css3+es6基础。打开编辑器跟着我一起把代码敲一遍,效果更佳。

        首先我们要有一个蛇的类,它要移动自己的身体,吃到果子;移动的时候撞了墙,或者咬到了自己的身体,会死;吃到了果子,身长会增加。

        所以这个蛇的类,要有一个Move的方法,Move里包含Eat,还有控制Move方向的Controller。

        那么怎么让它Move呢?是通过不断往蛇前进的方向添加DOM,并在尾巴处删除DOM?还是通过不断地改变蛇头和蛇尾的背景色来实现移动的效果?我选择了后者。

        把蛇的活动区域(300px * 500px)打上格子,每个格子是一个div(20px * 20px)。每个div的ID按照自己所在的位置编号:比如第一排的第一个,编号为”grid-1-1“。

 
 
 1 <div class="game-container">
 2     <h1>SUPER SNAKE</h1>
 3     <p class="first-one">
 4         <span>CURRENT SCORE:</span>
 5         <strong class="score"></strong>
 6     </p>
 7     <p>
 8         <span>HISTORY SCORE:</span>
 9         <strong class="history-score"></strong>
10     </p>
11     <div class="statement"></div>
12     <section class="snake-area"></section>
13 </div>
const initializeGrids = (height = 500, width = 300) => {
        for (let i = 1; i < height / 20 + 1; i++) {
            for (let j = 1; j < width / 20 + 1; j++) {
                const grid = document.createElement('div');
                grid.setAttribute('id', `grid-${i}-${j}`);
                grid.classList.add('grid');
                const con = document.querySelector('.snake-area').appendChild(grid);
            }
        }
        const showSnake = new Snake(height, width);
        const showScore = new Score();
    };
    initializeGrids();

        这样我们就能通过编号来记录并控制蛇运动的路线了。我们给蛇设置的初始身长为3个格子的长度(背景色为粉色);初始位置是第一排从左边起的前三个(把这三个位置保存在数组里:['grid-1-1', 'grid-1-2', 'grid-1-3']);初始的移动方向是从左到右。

        为了实现从左到右的移动,每隔500ms,给蛇头右边的第一个div添加粉色背景,并去掉蛇尾的背景色。同时移除蛇身体数组的第一个元素,并添加新的蛇头位置。

 1 class Snake {
 2 
 3             constructor(height, width) {
 4 
 5                 this.y_edge = height / 20;
 6 
 7                 this.x_edge = width / 20;
 8 
 9                 this.body = ['grid-1-1', 'grid-1-2', 'grid-1-3'];
10 
11                 this.interval = null;
12 
13                 this.wrapper = document.querySelector('.statement')
14 
15                 this.addColor();
16 
17                 this.move();
18 
19             }
20 
21             addColor() {
22 
23                 this.body.forEach(item => {
24 
25                     document.querySelector(`#${item}`).classList.add('snake');
26 
27                 })
28 
29             };
30 
31             removeColor() {
32 
33                 const uncolored = this.body.shift()
34 
35                 document.querySelector(`#${uncolored}`).classList.remove('snake');
36 
37             };
38 
39             move(to = 'right') {
40 
41                 this.interval = setInterval(() => {
42 
43                     const headId = this.body.slice(-1)[0],
44 
45                         headY = headId.split('-')[1],
46 
47                         headX = headId.split('-')[2],
48 
49                         directions = {
50 
51                             right: [`${headY}`, +headX + 1, this.x_edge],
52 
53                             left: [`${headY}`, +headX - 1, this.x_edge],
54 
55                             down: [+headY + 1, `${headX}`, this.y_edge],
56 
57                             up: [+headY - 1, `${headX}`, this.y_edge]
58 
59                         };
60 
61                     this.body.push(`grid-${directions[to][0]}-${directions[to][1]}`);
62 
63                     this.removeColor();
64 
65                     this.addColor();
66 
67                     };
68 
69                 }, 500);
70 
71             };
72 
73     };

        取出蛇头的id,并用headY和headX分别保存蛇头在Y轴和X轴上的位置;y_edge和x_edge分别为蛇活动区域的下边界和有边界;directions主要保存蛇的位移和位置,为了方便后面使用,把y_edge和x_edge也放在了里面。

        接下来我们来写controller方法,即通过控制键盘的上下左右键,来实现蛇前进方向的转变:

controller() {

                document.addEventListener('keyup', e => {

                    if (this.moveTo !== e.keyCode &&

                        this.moveTo !== e.keyCode + 2 &&

                        this.moveTo !== e.keyCode - 2 &&

                        !this.stopGame) {

                        this.moveTo = e.keyCode;

                        clearInterval(this.interval);

                        switch (e.keyCode) {

                            case 40:

                                this.move('down');

                                break;

                            case 38:

                                this.move('up');

                                break;

                            case 37:

                                this.move('left');

                                break;

                            case 39:

                                this.move('right');

                                break;

                            default:

                                break;

                        }

                    }

                }, false);

  

扫描二维码关注公众号,回复: 976147 查看本文章

        绑定keyup事件。this.moveTo用来保存当前按键的值,避免重复按键或按下方向相反的键。this.stopGame后面会讲到。

        keyup事件触发之后,清除当前interval(停止蛇在当前方向上的运动),改变方向后(this.moveTo取得了新的值)继续移动。

        蛇的移动到这里告一段落。下面讲吃果子且身体长度增加的部分。

        果子的出现位置是随机的,且每次蛇吃完以后需要重新生成。于是我们写一个Food的类:

class Food {

            constructor() {

                if (!document.querySelector('.food')) {

                    this.x = Math.floor(13 * Math.random() + 2);

                    this.y = Math.floor(23 * Math.random() + 2);

                    document.querySelector(`#grid-${this.y}-${this.x}`).classList.add('food');

                    return {

                        X: this.x,

                        Y: this.y

                    };

                }

            }

        };

再在蛇的类里添加一个吃的方法:

 1 eat(x, y) {
 2 
 3                 if (x == this.food.X && y == this.food.Y) {
 4 
 5                     document.querySelector(`#grid-${y}-${x}`).classList.remove('food');
 6 
 7                     this.shouldRemove = false;
 8 
 9                     this.showScore.addScore();
10 
11                     this.food = new Food();
12 
13                 }
14 
15             };

到这里为止核心的部分就完成了。最后我们再添加一个得分的类。

 1 class Score {
 2 
 3             constructor() {
 4 
 5                 try {
 6 
 7                     localStorage.getItem('historyScore') ? 
 8 
 9                         this.historyScore = localStorage.getItem('historyScore') :
10 
11                         this.historyScore = 0;
12 
13                     document.querySelector('.history-score').innerHTML = this.historyScore;
14 
15                 } catch {
16 
17                     alert('Your localStorage is not functioning, open this page in another browser!')
18 
19                 }
20 
21                 this.score = 0;
22 
23                 document.querySelector('.score').innerHTML = this.score;
24 
25             };
26 
27             addScore() {
28 
29                 this.score++;
30 
31                 document.querySelector('.score').innerHTML = this.score;
32 
33             };
34 
35             updateHistory() {
36 
37                 if (this.score > this.historyScore) {
38 
39                     try {
40 
41                         localStorage.setItem('historyScore', this.score);
42 
43                         document.querySelector('.history-score').innerHTML = this.score;
44 
45                     } catch {
46 
47                         alert('Your localStorage isn't functioning, open this page in another browser!')
48 
49                     }
50 
51                 }
52 
53             }
54 
55         };

完整的代码可点此阅读:https://gist.github.com/PengHoliday/65029f78f385b5884c1b9dfd2162c611

猜你喜欢

转载自www.cnblogs.com/holiday-peng/p/9070373.html