首页 > 编程语言 >自己动手开发小程序版俄罗斯方块

自己动手开发小程序版俄罗斯方块

时间:2023-12-07 18:23:38浏览次数:31  
标签:function map status 程序 动手 let 方块 data block

最近自己写了一个俄罗斯方块的小程序,基本处理完了所有BUG,尽量做到了代码简洁、功能完善,目前感觉唯一不太完美的地方是下键的短按和长按效果,完整源码如下:

 

WXML(使用了weui组件库的图标)

 1 <view class='container'>
 2   <view class="flex output">
 3     <view>分数:{{score}}</view>
 4     <view>等级:{{speed}}</view>
 5     <view>最高分:{{maxScore}}</view>
 6   </view>
 7   <view class='map'>
 8     <view wx:for="{{newMap}}" wx:for-item="rows" class='flex'>
 9       <view wx:for="{{rows}}" class='block block{{item}}'></view>
10     </view>
11   </view>
12   <view class="flex control">
13     <view>
14       <view class="flex button">
15         <mp-icon type="field" icon="back2" color="#FF0000" size="{{80}}" data-dir="left" bindlongpress="longPress" bindtap="horTap" bindtouchend="touchEnd" />
16         <mp-icon extClass="icon-right" type="field" icon="back2" color="#FF0000" size="{{80}}" data-dir="right" bindlongpress="longPress" bindtap="horTap" bindtouchend="touchEnd" />
17       </view>
18       <view class="center">
19         <mp-icon extClass="icon-down" type="field" icon="back2" color="#FF0000" size="{{80}}" data-dir="down" bindlongpress="longPress" bindtap="downTap" bindtouchend="touchEnd" />
20       </view>
21     </view>
22     <view>
23       <view class="center">
24         <mp-icon type="field" icon="{{icon}}" color="#FF0000" size="{{60}}" bindtap="play" />
25       </view>
26       <view>
27         <view wx:for="{{newNextMap}}" wx:for-item="rows" class='flex'>
28           <view wx:for="{{rows}}" class='block-next block{{item}}'></view>
29         </view>
30       </view>
31     </view>
32     <view>
33       <mp-icon type="field" icon="refresh" color="#FF0000" size="{{100}}" bindtap="rotateBlock" />
34     </view>
35   </view>

 

WXSS

 1 .map {
 2   margin-top: 30rpx;
 3 }
 4 .flex {
 5   display: flex;
 6 }
 7 .output {
 8   width: 90%;
 9   justify-content: space-between;
10 }
11 .block {
12   width: 50rpx;
13   height: 50rpx;
14   border: 1px solid #eee;
15   background: #000;
16 }
17 .block1 {
18   background: green;
19 }
20 .control {
21   margin-top: 20rpx;
22   justify-content: space-between;
23   align-items: center;
24 }
25 .center {
26   text-align: center;
27 }
28 .button {
29   justify-content: space-between
30 }
31 .icon-right {
32   transform: rotate(180deg);
33 }
34 .icon-down {
35   transform: rotate(-90deg);
36 }
37 .block-next {
38   width: 30rpx;
39   height: 30rpx;
40   border: 1px solid #eee;
41 }

 

JS

  1 Page({
  2   data: {
  3     //地图大小
  4     mapSize: [18, 10],
  5     //地图
  6     map: [],
  7     newMap: [],
  8     nextMap: [],
  9     newNextMap: [],
 10     //方块
 11     block: [],
 12     nextBlock: [],
 13     //游戏状态
 14     icon: '',
 15     status: '',
 16     timer: null,
 17     quickTimer: null,
 18     speed: 1,
 19     score: 0,
 20     maxScore: 0,
 21     //方块位置
 22     blockPos: [0, 0],
 23     //七种方块
 24     blocks: [
 25       [[1, 0], [1, 1], [1, 2], [2, 1]],
 26       [[1, 1], [2, 1], [3, 1], [3, 2]],
 27       [[1, 2], [2, 2], [3, 1], [3, 2]],
 28       [[1, 0], [1, 1], [2, 1], [2, 2]],
 29       [[1, 1], [1, 2], [2, 0], [2, 1]],
 30       [[1, 1], [1, 2], [2, 1], [2, 2]],
 31       [[0, 1], [1, 1], [2, 1], [3, 1]]
 32     ]
 33   },
 34   onl oad(options) {
 35     let maxScore = 0
 36     if (wx.getStorageSync("tetrisScore")) {
 37       maxScore = wx.getStorageSync("tetrisScore")
 38     }
 39     //初始化地图
 40     let map = this.initMap(this.data.mapSize)
 41     let nextMap = this.initMap([4, 4])
 42     //随机一个方块
 43     let nextBlock = this.data.blocks[Math.floor(Math.random() * 7)]
 44     this.setData({
 45       map: map,
 46       newMap: map,
 47       nextMap: nextMap,
 48       newNextMap: nextMap,
 49       nextBlock: nextBlock,
 50       icon: 'play',
 51       status: 'stop',
 52       score: 0,
 53       speed: 1,
 54       maxScore: maxScore
 55     })
 56   },
 57   //初始化地图
 58   initMap: function (size) {
 59     let map = []
 60     for (let i = 0; i < size[0]; i++) {
 61       let rows = []
 62       for (let j = 0; j < size[1]; j++) {
 63         rows.push(0)
 64       }
 65       map.push(rows)
 66     }
 67     return map
 68   },
 69   //初始化方块
 70   initBlock: function () {
 71     //随机方向
 72     let block = this.rotateFun(this.data.nextBlock, Math.floor(Math.random() * 4))
 73     //移到中间
 74     this.moveFun(block, [-3, 3], 0)
 75     //生成下一个方块
 76     let nextBlock = this.data.blocks[Math.floor(Math.random() * 7)]
 77     //更新小图
 78     let newNextMap = JSON.parse(JSON.stringify(this.data.nextMap))
 79     for (let item of nextBlock) {
 80       newNextMap[item[0]][item[1]] = 1
 81     }
 82     this.setData({
 83       block: block,
 84       nextBlock: nextBlock,
 85       newNextMap: newNextMap
 86     })
 87   },
 88   play: function () {
 89     let icon, status = this.data.status
 90     if (status == 'play') {
 91       icon = 'play'
 92       status = 'pause'
 93       clearInterval(this.data.timer)
 94     } else {
 95       if (status == 'stop') {
 96         this.initBlock()
 97       }
 98       this.fallFun()
 99       icon = 'pause'
100       status = 'play'
101     }
102     this.setData({
103       icon: icon,
104       status: status
105     })
106   },
107   //下落方法
108   fallFun: function () {
109     let that = this
110     this.data.timer = setInterval(function () {
111       that.moveFun(that.data.block, that.posFun(that.data.blockPos, 'down'), 1)
112     }, (21 - that.data.speed) * 50)
113   },
114   //左、右短按
115   horTap: function (e) {
116     if (this.data.status == 'play') {
117       this.moveFun(this.data.block, this.posFun(this.data.blockPos, e.currentTarget.dataset.dir))
118     }
119   },
120   //下短按
121   downTap: function () {
122     if (this.data.status == 'play') {
123       let that = this
124       let i = 0
125       let timer = setInterval(function () {
126         that.moveFun(that.data.block, that.posFun(that.data.blockPos, 'down'))
127         i++
128         if (i >= 5) clearInterval(timer)
129       }, 10)
130     }
131   },
132   //长按
133   longPress: function (e) {
134     if (this.data.status == 'play') {
135       let that = this
136       this.data.quickTimer = setInterval(function () {
137         that.moveFun(that.data.block, that.posFun(that.data.blockPos, e.currentTarget.dataset.dir))
138       }, 10)
139     }
140   },
141   //按键手指移开
142   touchEnd: function (e) {
143     clearInterval(this.data.quickTimer)
144   },
145   //计算移动后坐标
146   posFun: function (pos, dir) {
147     let newPos = []
148     switch (dir) {
149       case 'left':
150         newPos = [pos[0], pos[1] - 1]
151         break;
152       case 'right':
153         newPos = [pos[0], pos[1] + 1]
154         break;
155       case 'down':
156         newPos = [pos[0] + 1, pos[1]]
157         break;
158     }
159     return newPos
160   },
161   //移动方法,type:0初始移到中间,1正常下落
162   moveFun: function (block, pos, type) {
163     let m = pos[0], n = pos[1]
164     let mapSize = this.data.mapSize
165     let maxX = m, reLoop = true
166     let map = JSON.parse(JSON.stringify(this.data.map))
167     for (let index = 0; index < block.length; index++) {
168       let i = block[index][0] + m, j = block[index][1] + n
169       //超出边界,或已有方块,取消移动
170       if (i >= mapSize[0] || j < 0 || j >= mapSize[1] || (i >= 0 && map[i][j] == 1) == 1) {
171         if (type == 1) {
172           clearInterval(this.data.timer)
173           //游戏结束
174           if (map[0][j] == 1) {
175             let scroe = this.data.score
176             wx.showModal({
177               title: '游戏结束',
178               content: '得分:' + scroe,
179               showCancel: false,
180             })
181             if (scroe > this.data.maxScore) wx.setStorageSync("tetrisScore", scroe)
182             this.onLoad()
183             return false
184           }
185           //消除
186           let newMap = this.data.newMap
187           loop: for (let a = mapSize[0] - 1; a >= 0; a--) {
188             for (let val of newMap[a]) {
189               if (val == 0) continue loop
190             }
191             newMap.splice(a, 1)
192           }
193           let len = mapSize[0] - newMap.length
194           for (let a = 0; a < len; a++) {
195             let row = []
196             for (let b = 0; b < mapSize[1]; b++) {
197               row.push(0)
198             }
199             newMap.unshift(row)
200           }
201           //初始化方块
202           let score = this.data.score
203           if (len > 0) score += (len * 100 - 50)
204           let speed = parseInt(score / 1000) + 1
205           if (speed > 20) speed = 20
206           this.setData({
207             map: newMap,
208             score: score,
209             speed: speed
210           })
211           this.initBlock()
212           this.fallFun()
213         }
214         return false
215       }
216       if (type == 0) {
217         if (reLoop) {
218           //计算方块最大横坐标
219           if (i > maxX) maxX = i
220           //开始下一次循环
221           if (index == block.length - 1) {
222             index = -1
223             reLoop = false
224           }
225           continue
226         }
227         if (maxX > m) i -= maxX
228       }
229       //移动到新位置
230       if (i >= 0) map[i][j] = 1
231     }
232     this.setData({
233       blockPos: [(maxX > m ? m - maxX : m), n],
234       newMap: map
235     })
236     return true
237   },
238   //按键转动
239   rotateBlock: function (e) {
240     if (this.data.status == 'play') {
241       let block = this.rotateFun(this.data.block, 1)
242       if (this.moveFun(block, this.data.blockPos)) {
243         this.setData({
244           block: block
245         })
246       }
247     }
248   },
249   //顺时针旋转方块
250   rotateFun: function (block, m) {
251     if (m > 0) {
252       let newBlock = []
253       for (let i in block) {
254         newBlock.push(this.rotateRe(block[i], m))
255       }
256       return newBlock
257     }
258     return block
259   },
260   rotateRe: function (arr, m) {
261     arr = [arr[1], 3 - arr[0]]
262     if (m == 1)
263       return arr
264     return this.rotateRe(arr, m - 1)
265   },
266   onUnload() {
267     clearInterval(this.data.timer)
268   }
269 })

 

标签:function,map,status,程序,动手,let,方块,data,block
From: https://www.cnblogs.com/desertion/p/17883631.html

相关文章

  • 技术精要:开发流畅的同城O2O外卖小程序
    时下,O2O(OnlinetoOffline)模式在各个行业蓬勃兴起,尤其是在外卖服务领域。为了更好地满足用户需求,许多企业纷纷投入同城O2O外卖小程序的开发。在本文中,我们将深入探讨开发流畅的同城O2O外卖小程序的技术精要,包括关键特性、技术架构、用户体验等方面。一、关键特性1.1实时定位和跟踪同......
  • 开发APP应用程序到底是选ios好还是Android好?
    哈喽大家好,我是咕噜老尼,现在我们都知道,APP应用已经覆盖了我们的生活,成为我们生活中不可缺少的一部分,手机系统主要分两种,分别是安卓和ios系统,不少APP开发公司在制作手机APP时,都需要将同一款APP做成两种,分别适应安卓和iOS系统。那么,开发APP应用程序到底是选ios好还是Android好,我们一......
  • 如何使用Visual Studio 2022创建基本Vue.js.Web应用程序
    最近接了个物联网项目,需要用到   VUEAnt-Design 对于vue没有概念 只能查找相关  vue.js的知识。 了解vue.js的前提条件 是要对  HTML+CSS+Jscript有一定的知识储备。所以又去看了看对应的三剑客(HTML+CSS+Jscript)。跟着vue.js官网学习了一下,就......
  • 微信号上传附件小程序
    微附件是一个旨在简化公众号附件管理的实用工具。它为运营人员提供了一个轻松上传和管理多种文件格式(包括Word、Excel、PPT、PDF、TXT等)的平台,并使得用户能够直接下载这些文件。鉴于微信公众号本身并不内置此类功能,微附件的应用因此变得极为重要。首先,要访问微附件的官方网页,您可以......
  • 8051微控制器的程序用于控制LED的闪烁
    这段代码是一个基于8051微控制器的程序,用于控制LED的闪烁。程序使用了定时器中断来实现LED的闪烁效果。首先,定义了一个全局变量`TimerTick`来计数中断次数,以及一个标志位`TimeOver`用于在主函数中切换端口引脚的状态。然后,定义了一个名为`timer0`的中断服务例程,该例程在定时器0中......
  • 运行 jar 程序
    运行jar程序运行jar程序一、java.exe启动jar程序 (会显示console黑窗口)1、一般用法:java-jarXXX.jarjava-server-Xms1024m-Xmx20480m-jar$JAR_NAME.jar2、重命名进程名称启动:@echooffcopy"%JAVA_HOME%\bin\java.exe""%JAVA_HOME%\bin\myProcess.ex......
  • codegeex 程序员代码工具
    一、codegeex简介CodeGeeX是清华和智谱AI联合打造的多语言代码生成模型。官网地址:https://codegeex.cn/二、安装方法1、支持IDE如下:vscode、GoLand、IntelliJIDEA等2、支持语言如下:python、C++、Go、Java等3、以vscode为例,只需安装插件即可三、功能1、AskCodeGee......
  • 2023-2024-120231329《计算机基础与程序设计》第11周学习总结
    作业信息这个作业属于哪个课程https://edu.cnblogs.com/campus/besti这个作业要求在哪里https://www.cnblogs.com/rocedu/p/9577842.html#WEEK11这个作业的目标计算机科学概论第15,16章并完成云班课测试《C语言程序设计》第10章并完成云班课测试作业正文https:/......
  • 用Haskell写一个采集统计数据的程序
     在日常生活中我们需要统计一些人文地理相关数据,一条一条人工收集显然非常困难,而且不现实,那么今天,我就试着用haskell写一个采集统计数据的程序,测试了一下速度还不错,稳定性还不确定,至少目前还没有什么问题,一起来看看吧。```haskellimportNetwork.HTTPimportNetwork.HTTP.Condu......
  • 用Python写的一个采集快手直播间的程序
    今天给大家分享的是一个用python写的一个采集快手直播间的程序,内容非常简单,并且每个代码都有详细的中文解释,让我们一起来学习一下吧。```pythonimportrequestsfrombs4importBeautifulSoup#设置代理信息proxy_host="https://www.duoip.cn/get_proxy"proxy_port=8000......