0

0

聊聊如何利用uniapp开发一个贪吃蛇小游戏!

青灯夜游

青灯夜游

发布时间:2022-05-20 19:56:18

|

6011人浏览过

|

来源于掘金社区

转载

如何利用uniapp开发一个贪吃蛇小游戏?下面本篇文章就手把手带大家在uniapp中实现贪吃蛇小游戏,希望对大家有所帮助!

聊聊如何利用uniapp开发一个贪吃蛇小游戏!

第一次玩贪吃蛇还隐约记得是?️后父亲给我玩的第一个游戏

该小游戏使用uniapp开发

前置详细内容就不细说了详细看:https://juejin.cn/post/7085727363547283469#heading-14

游戏演示

1.gif

代码结构

详细代码结构如果需要请到github查看

主要分为:开始游戏、地块、蛇身、虫子、污染地块,游戏音效

<template>
	<view ref="body" class="content">
		<view>蛇蛇目前:{{snakes.length}}米长</view>
		<view class="game-field">
                <!-- 地面板块 -->
		  <view class="block"  v-for="(x, i) in blocks" :key="i"></view>
		</view>
                    <view v-show="!started || ended" class="game-board-wrap">
                        <view v-show="!started" class="game-board">
                            <view class="title">选择游戏难度</view>
                            <radio-group name="radio" @change="bindLevelChange">
                                <label class="label">
                                    <radio value="1" :checked="level==1" /><text>简单模式</text>
                                </label>
                                <label class="label">
                                    <radio value="2" :checked="level==2" /><text>正常模式</text>
                                </label>
                                <label class="label">
                                    <radio value="3" :checked="level==3" /><text>困难模式</text>
                                </label>
                                <label class="label">
                                    <radio value="4" :checked="level==4" /><text>地狱模式</text>
                                </label>
                            </radio-group>
                            <button type="primary" @click="start">开始游戏</button>
                        </view>
			<view v-show="ended" class="settle-board">
                            <view class="title">游戏结束</view>
                            <view class="result">您的蛇蛇达到了{{snakes.length}}米</view>
                            <view class="btns">
                                <button type="primary" @click="reStart">再次挑战</button>
                                <button type="primary" plain @click="rePick">重选难度</button>
                            </view>
			</view>
		</view>
	</view>
</template>
<script>
export default {
    data() {
            return {
                blocks: [], // 板块
                worms: [], // 虫子
                snakes: [0, 1, 2, 3], // 蛇身
                direction: "right", // 蛇移动方向
            };
    },
    onLoad() {
        this.initGame();
    },
    methods: {
        initGame() {
            this.blocks = new Array(100).fill(0); // 生成100个地面板块
            this.worms = [Math.floor(Math.random() * 96) + 4]; // 随机生成虫子
            this.snakes = [0, 1, 2, 3]; // 初始化蛇身位置
        }
    }
}
</script>

渲染蛇身

给我们的蛇穿上他的外衣 蛇身的渲染根据snakes(里边放着蛇的身体)来匹配地面板块的索引 从而找到对应的格格并修改背景图来渲染蛇身 蛇头和蛇尾就是取snakes第0位和最后一位 并找到对应的格格修改当前背景图

<template>
    <view class="game-field">
        <view class="block" :style="`background-image: ${bg(x, i)}" v-for="(x, i) in blocks" :key="i">
        </view>
    </view>
</template>
<script>
import worm from "worm.png";
import snakeBody from "snake_body.png";
import snakeHead from "snake_head.png";
import snakeTail from "snake_tail.png";
import polluteBlock from "pollute.png";
import wormBoom from "worm_4.png";
export default {
    methods: {
        bg(type, index) {
            let bg = "";
            switch (type) {
                case 0: // 地板
                    bg = "unset";
                    break;
                case 1: // 虫子
                    if (this.boom) {
                            bg = `url(${wormBoom})`;
                    } else {
                            bg = `url(${worm})`;
                    }
                    break;
                case 2: // 蛇
                    let head = this.snakes[this.snakes.length - 1];
                    let tail = this.snakes[0];
                    if (index === head) {
                            bg = `url(${snakeHead})`;
                    } else if (index === tail) {
                            bg = `url(${snakeTail})`;
                    } else {
                            bg = `url(${snakeBody})`;
                    }
                    break;
                case 3: // 污染的地块
                    bg = `url(${polluteBlock})`;
                    break;
            }
            return bg;
        },
    }
}
</scipt>

控制蛇的方向

控制蛇的方向pc端我们通过监听键盘事件找到对应的键盘键的编码上下左右来改变蛇的方向 而手机端我们通过touch时间手指触摸点及滑动点的XY轴值来判断蛇的方向

<template>
<view ref="body" class="content" @keyup.left="bindLeft" @keyup.right="bindRight" @keyup.down="bindDown"
@keyup.up="bindUp" @touchstart="handleTouchStart" @touchmove="handleTouchMove">
    <view>蛇蛇目前:{{snakes.length}}米长</view>
    <view class="game-field">
        <view class="block" :style="`background-image: ${bg(x, i)}; v-for="(x, i) in blocks" :key="i"></view>
    </view>
</view>
</template>
<script>
    export default {
        data(){
            return {
                direction: "right",
                started: false, // 游戏开始了
                ended: false, // 游戏结束了
                level: 1, // 游戏难度
                lastX: 0,
                lastY: 0,
            }
        },
        onLoad() {
            this.initGame();
        },
        methods:{
            initGame() {
                this.blocks = new Array(100).fill(0); // 生成100个地面板块
                this.worms = [Math.floor(Math.random() * 96) + 4]; // 随机生成虫子
                this.snakes = [0, 1, 2, 3]; // 初始化蛇身位置
                document.onkeydown = (e) => {
                    switch (e.keyCode) { // 获取当前按下键盘键的编码
                        case 37: // 按下左箭头键
                            this.bindLeft();
                            break;
                        case 39: // 按下右箭头键
                            this.bindRight();
                            break;
                        case 38: // 按下上箭头键
                            if (!this.started) {
                                    this.level--;
                            } else {
                                    this.bindUp();
                            }
                            break;
                        case 40: // 按下下箭头键
                            if (!this.started) {
                                    this.level++;
                            } else {
                                    this.bindDown();
                            }
                            break;
                    }
                }
            },
            handleTouchStart(e) {
                // 手指开始位置
                this.lastX = e.touches[0].pageX;
                this.lastY = e.touches[0].pageY;
            },
            handleTouchMove(e) {
                let lastX = e.touches[0].pageX; // 移动的x轴坐标
                let lastY = e.touches[0].pageY; // 移动的y轴坐标

                let touchX = lastX - this.lastX;
                let touchY = lastY - this.lastY
                if (Math.abs(touchX) > Math.abs(touchY)) {
                if (touchX < 0) {
                    if(this.direction === "right") return;
                    this.direction = 'left'
                    } else if (touchX > 0) {
                        if(this.direction === "left") return;
                        this.direction = 'right'
                    }
                } else {
                    if (touchY < 0) {
                        if(this.direction === "down") return;
                        this.direction = 'up'
                    } else if (touchY > 0) {
                        if(this.direction === "up") return;
                        this.direction = 'down'
                    }
                }
                this.lastX = lastX;
                this.lastY = lastY;
            },
            bindUp() {
                if (this.direction === "down") return;
                this.direction = "up";
            },
            bindDown() {
                if (this.direction === "up") return;
                this.direction = "down";
            },
            bindLeft() {
                if (this.direction === "right") return;
                this.direction = "left";
            },
            bindRight() {
                if (this.direction === "left") return;
                this.direction = "right";
            },
        }
    }
</script>

给贪吃蛇添加音效

添加游戏音效游戏代入感就强了很多 现在我们要给蛇加上背景音乐、点击交互音乐、蛇隔儿屁的音乐、蛇吃掉食物的音乐、虫子爆炸倒计时的音乐和虫子爆炸的音乐

Text-To-Song
Text-To-Song

免费的实时语音转换器和调制器

下载

先给添加上背景音乐 总有刁民可以玩到地图满为止 背景音乐的话要loop播放 我们只需要 使用uni.createInnerAudioContext来创建并返回内部 audio 上下文 innerAudioContext 对象 拿到音乐的路径并且设置自动播放

<script>
import bgm from 'bgm.mp3';
export default {
    data(){
        return {
            bgmInnerAudioContext:null,
        }
    },
    methods:{
        start() { // 开始游戏
            this.initGame();
            this.handleBgmVoice()
        },
        handleBgmVoice() {
            // 背景音乐
            this.bgmInnerAudioContext = uni.createInnerAudioContext() // 创建上下文
            this.bgmInnerAudioContext.autoplay = true; // 自动播放
            this.bgmInnerAudioContext.src= bgm; // 音频地址
            this.bgmInnerAudioContext.loop = true; // 循环播放
        }
    }
}
<script>

背景音乐确实响起来了 蛇gameover后还一直响 顿时我听着就不耐烦 这时我们在蛇gameover后暂停背景音乐pause音乐会暂停而不会清楚

<script>
import bgm from 'bgm.mp3';
export default {
    data(){
        return {
            bgmInnerAudioContext:null,
        }
    },
    methods:{
        start() { // 开始游戏
            this.initGame();
            this.handleBgmVoice()
        },
        handleBgmVoice() {
            // 背景音乐
            this.bgmInnerAudioContext = uni.createInnerAudioContext() // 创建上下文
            this.bgmInnerAudioContext.autoplay = true; // 自动播放
            this.bgmInnerAudioContext.src= bgm; // 音频地址
            this.bgmInnerAudioContext.loop = true; // 循环播放
        }
        checkGame(direction, next) {
            let gameover = false;
            let isSnake = this.snakes.indexOf(next) > -1;
            let isPollute = this.pollutes.indexOf(next) > -1;
            // 撞到蛇和被污染的地块游戏结束
            if (isSnake || isPollute) {
                gameover = true;
            }
            // 撞到边界游戏结束
            switch (direction) {
                case "up":
                    if (next < 0) {
                            gameover = true;
                    }
                    break;
                case "down":
                    if (next >= 100) {
                            gameover = true;
                    }
                    break;
                case "left":
                    if (next % 10 === 9) {
                            gameover = true;
                    }
                    break;
                case "right":
                    if (next % 10 === 0) {
                            gameover = true;
                    }
                    break;
            }
            return gameover;
        },
        toWards(direction) {
            let gameover = this.checkGame(direction, next);
            if (gameover) {
                this.ended = true;
                this.handleDieVoice()
                this.bgmInnerAudioContext.pause() // 游戏结束 暂停背景音乐
                clearInterval(this.timer);
                clearInterval(this.boomTimer);
            } else {
                // 游戏没结束
                this.snakes.push(next);
                let nextType = this.blocks[next];
                this.blocks[next] = 2;
                // 如果是空白格
                if (nextType === 0) {
                    this.snakes.shift();
                } else {
                    // 如果是虫子格
                    this.handleEatVoice() // 吃掉虫子后的音乐
                    this.worms = this.worms.filter((x) => x !== next);
                    let nextWorm = this.createWorm();
                    this.worms.push(nextWorm);
                }
                this.blocks[tail] = 0;
                this.paint();
            }
        },
    }
}
<script>

首个音乐添加成功其他的也就简单多了 虫子爆炸倒计时也需要爆炸或者gameover后需要清楚倒计时音效stop(下次播放会从头开始) 剩余的不需要清楚音效和循环播放 下面附上剩余的代码

<script>
export default {
    data() {
        return {
             bgmInnerAudioContext:null,
             clockInnerAudioContext:null,
        }
    },
    watch: {
        boomCount(val) {
            if (val === 0) {
                // 超过爆炸时间还没吃到,则将虫子格子变成被污染的土地,并且重置爆炸状态,同时生成一只新的虫子:
                this.handleExplodeVoice() // 爆炸的音乐
                this.clockInnerAudioContext.stop() // 清楚倒计时音乐
                const boomWorm = this.worms.pop();
                this.pollutes.push(boomWorm);
                this.blocks[boomWorm] = 3; // 被污染的地方我们用3表示
                this.boom = false;
                this.worms.push(this.createWorm());
            }
        }
    },
    methods:{
        // 蛇吃到食物后的声音
        handleEatVoice() {
            const innerAudioContext = uni.createInnerAudioContext();
            innerAudioContext.autoplay = true;
            innerAudioContext.src = eatVoice;
        },
        // 虫子污染爆炸后的声音
        handleExplodeVoice(){
            const innerAudioContext = uni.createInnerAudioContext();
            innerAudioContext.autoplay = true;
            innerAudioContext.src = explodeVoice;
        },
        // 游戏背景音乐
        handleBgmVoice() {
            this.bgmInnerAudioContext = uni.createInnerAudioContext()
            this.bgmInnerAudioContext.autoplay = true;
            this.bgmInnerAudioContext.src= bgm;
            this.bgmInnerAudioContext.loop = true;
        },
        // 按钮点击的声音
        handleClickVoice() {
            const innerAudioContext = uni.createInnerAudioContext()
            innerAudioContext.autoplay = true;
            innerAudioContext.src= click;
        },
        // 爆炸倒计时的声音
        handleClockVoice() {
            this.clockInnerAudioContext = uni.createInnerAudioContext()
            this.clockInnerAudioContext.autoplay = true;
            this.clockInnerAudioContext.src= clock;
        },
        // 蛇gameover后的声音
        handleDieVoice() {
            const innerAudioContext = uni.createInnerAudioContext()
            innerAudioContext.autoplay = true;
            innerAudioContext.src= die;
        },
        checkGame(direction, next) {
            let gameover = false;
            let isSnake = this.snakes.indexOf(next) > -1;
            let isPollute = this.pollutes.indexOf(next) > -1;
            // 撞到蛇和被污染的地块游戏结束
            if (isSnake || isPollute) {
                gameover = true;
            }
            // 撞到边界游戏结束
            switch (direction) {
                case "up":
                    if (next < 0) {
                            gameover = true;
                    }
                    break;
                case "down":
                    if (next >= 100) {
                            gameover = true;
                    }
                    break;
                case "left":
                    if (next % 10 === 9) {
                            gameover = true;
                    }
                    break;
                case "right":
                    if (next % 10 === 0) {
                            gameover = true;
                    }
                    break;
            }
            return gameover;
        },
        paint() {
            this.worms.forEach((x) => {
                this.blocks[x] = 1;
            });
            this.snakes.forEach((x) => {
                this.blocks[x] = 2;
            });
            this.$forceUpdate();
        },
        toWards(direction) {
            let gameover = this.checkGame(direction, next);
            if (gameover) {
                this.ended = true;
                this.handleDieVoice()
                this.bgmInnerAudioContext.pause() // 游戏结束 暂停背景音乐
                this.clockInnerAudioContext && this.clockInnerAudioContext.stop() // 清楚倒计时音乐
                clearInterval(this.timer);
                clearInterval(this.boomTimer);
            } else {
                // 游戏没结束
                this.snakes.push(next);
                let nextType = this.blocks[next];
                this.blocks[next] = 2;
                // 如果是空白格
                if (nextType === 0) {
                    this.snakes.shift();
                } else {
                    // 如果是虫子格
                    this.handleEatVoice() // 吃掉虫子后的音乐
                    this.worms = this.worms.filter((x) => x !== next);
                    let nextWorm = this.createWorm();
                    this.worms.push(nextWorm);
                }
                this.blocks[tail] = 0;
                this.paint();
            }
        },
        // 生成下一只虫子
        createWorm() {
            this.boom = false;
            let blocks = Array.from({
                    length: 100
            }, (v, k) => k);
            // 在不是蛇和被污染的地方生成虫子
            let restBlocks = blocks.filter(x => this.snakes.indexOf(x) < 0 && this.pollutes.indexOf(x) < 0);
            let worm = restBlocks[Math.floor(Math.random() * restBlocks.length)];
            // 根据游戏难度,概率产出会爆炸的虫子:
            this.boom = Math.random() / this.level < 0.05;
            // 生成了新虫子说明吃到了那个爆炸的虫子,重置下爆炸
            if (this.boom) {
                this.boomCount = 10;
                this.boomTimer && clearInterval(this.boomTimer);
                this.handleClockVoice()
                this.boomTimer = setInterval(() => {
                        this.boomCount--;
                }, 1000)
            } else {
                this.clockInnerAudioContext && this.clockInnerAudioContext.stop()
                clearInterval(this.boomTimer);
            }
            return worm;
        },
    }
}
<script>

结语

特别鸣谢@大帅老猿@末世未然 感谢大帅老师的带队及指导以及每天的督促,也特别的感谢队友的帮助及支持

源码地址:https://github.com/MothWillion/snake_eat_worm

原文地址:https://juejin.cn/post/7087525655478272008

作者:Sophora

推荐:《uniapp教程

相关文章

在线游戏
在线游戏

海量精品小游戏合集,无需安装即点即玩,休闲益智、动作闯关应有尽有,秒开即玩,轻松解压,快乐停不下来

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
github中文官网入口 github中文版官网网页进入
github中文官网入口 github中文版官网网页进入

github中文官网入口https://docs.github.com/zh/get-started,GitHub 是一种基于云的平台,可在其中存储、共享并与他人一起编写代码。 通过将代码存储在GitHub 上的“存储库”中,你可以: “展示或共享”你的工作。 持续“跟踪和管理”对代码的更改。

4046

2026.01.21

http与https有哪些区别
http与https有哪些区别

http与https的区别:1、协议安全性;2、连接方式;3、证书管理;4、连接状态;5、端口号;6、资源消耗;7、兼容性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2901

2024.08.16

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

22

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

48

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

93

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

216

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

413

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

143

2026.03.04

Swift iOS架构设计与MVVM模式实战
Swift iOS架构设计与MVVM模式实战

本专题聚焦 Swift 在 iOS 应用架构设计中的实践,系统讲解 MVVM 模式的核心思想、数据绑定机制、模块拆分策略以及组件化开发方法。内容涵盖网络层封装、状态管理、依赖注入与性能优化技巧。通过完整项目案例,帮助开发者构建结构清晰、可维护性强的 iOS 应用架构体系。

221

2026.03.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Java 教程
Java 教程

共578课时 | 80.3万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号