如何利用uniapp開發一個貪吃蛇小游戲?下面本篇文章就手把手帶大家在uniapp中實現貪吃蛇小游戲,希望對大家有所幫助!
第一次玩貪吃蛇還隱約記得是??后父親給我玩的第一個游戲
該小游戲使用uniapp
開發
前置詳細內容就不細說了詳細看:https://juejin.cn/post/7085727363547283469#heading-14
游戲演示
代碼結構
詳細代碼結構如果需要請到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>
給貪吃蛇添加音效
添加游戲音效游戲代入感就強了很多 現在我們要給蛇加上背景音樂、點擊交互音樂、蛇隔兒屁的音樂、蛇吃掉食物的音樂、蟲子爆炸倒計時的音樂和蟲子爆炸的音樂
先給添加上背景音樂 總有刁民可以玩到地圖滿為止 背景音樂的話要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