手把手教你用Excel编写俄罗斯方块
我相信看到这个题目你会很惊讶什么,Excel居然能开发游戏没错,Excel的强弱取决于用户强则强,弱则弱但本文并不是为了展示Excel使用中的巧思,主要是写给准备学习编程但计算机基础不多的人,或者对Excel感兴趣的人
对于正在学习编程的人,尤其是从其他领域进入这个领域的人,兴趣是最大的动力从事计算机编程这么久,感觉编程是一件很有意义的事情但是,我经常听到一些人,尤其是那些在校的学生,抱怨编程太枯燥,坚持不下去我觉得这群人一方面是方向不对,另一方面是在实际学习过程中对自己的成绩没有任何成就感,而后者往往占据了重要的原因
我认为对于编程初学者来说,选择第一语言应该具备以下两个特点:
1),尽可能简单,尽可能少与底层硬件相关联(如内存管理等)。),调试方便,IDE接口简单,
2)比较强大,可以开发各种插件工具,
目前业界常用的编程语言中,只有Python,Office for VBA和Java能够同时满足以上两个特性不过Python虽然简单强大,但是需要配置环境,安装臃肿的IDE,无形中增加了初学者的学习成本,更别说Java了,剩下的就是VBA了VbA是visual basic语言的子集除了继承了一些VB的功能,还特别封装了一些软件接口,使用起来很方便有人说VBA语法太随意,这对初学者来说不是一件好事如果学了C,以后学C++就容易多了我不同意这种观点对于前者,不同的人有不同的看法,但后者是无稽之谈,因为C++是一门极其复杂的编程语言,它不仅继承了C语言繁琐的指针,还衍生出了多重继承,类模板,智能指针等恐怖的编程范式所以,对于初学者来说,我不建议直接学习C++
你为什么选择VBA语作为初学者的语言。因为除了满足上述两个特征之外,它还有一些其他的优点,如:
1),简单易用:不需要安装开发工具,也不需要安装环境和语言包,只要电脑里有office软件即可。
2)应用广泛:几乎所有工程软件和办公软件都支持用VBA进行二次开发比如财务人员发现Excel自己的公式有局限性,完全可以用VBA开发自己需要的控件,如果机械设计师学习VBA,可以开发一些自己需要的代码块,这将大大提高自己CAD的绘图速度如果不了解VBA,很难想象Excel的重度用户,尤其是财务人员的工作量有多可怕
3),调试简单方便。
所以,这一次,我也选择了VBA作为编写演示的语言为了照顾更多的初学者,我尽可能的呈现了每一步的细节由于每个Excel版本都不一样,我的电脑用的是2010版,所以我就用2010版来解释其他版本相同,只是界面可能略有不同我相信只要你亲手制作了这个游戏,你不仅会体会到Excel的强大,也会逐渐体会到编程的乐趣鉴于时间有限,内容可能会有所疏漏希望大家指正
下面是正文:
先来看看游戏最终的大致效果图:
我们先来思考一下俄罗斯方块的总体架构:
1),初始化界面:创建广场所需的地图。
2)随机生成俄罗斯方块:俄罗斯方块共有7种形式,每种形式由4帧组成,每个方块对应一种颜色您可以创建一个数组来存储每个正方形的坐标,然后使用另一个数组来存储正方形的相应颜色
3),移动旋转方块:分左,右,下擦拭后重画,产生移动旋转的效果
4)如果没有新的方块产生,它们都以一定的速度下落一旦碰到障碍物,就不能掉下来,然后生成新的方块
5),不断扫描是否有行被填充如果是真的,这条线就删了,顶掉了每条线有10个点
首先创建一个Excel文件,随意命名。打开后,因为office默认隐藏了开发工具的状态栏,所以我们需要选择Excel选项gt,自定义功能区以调出,检查并确认:
随后,我们发现主界面有更多的开发工具选项:
然后,在Sheet1表格中,我们将A~K列的列宽调整为与行高大致相同,并让它大致称为正方形区域:
我们点击Visual Basic菜单打开写代码的界面,我们插入一个代码模块来写我们自己的代码:
因为正方形有7个形状,为了让程序绘图方便,我用一个三维数组来存储所有形状的坐标,每个形状都有一个中心坐标,其他三个正方形的坐标都是根据中心坐标计算出来的,比如一个T型正方形:
如果中心的坐标为,剩下的三个坐标从右到左分别是(0,1),(—1,0),和(0,1)之所以把垂直方向作为X轴,是因为Excel坐标的固有属性例如,单元格(1,2)表示单元格的第一行和第二列每个方块的对象都有中心坐标,颜色,形状等属性
optixplicitdimysheetworksheetlimitcentercentowasinteger '正方形中心行DimcenterColasinteger '正方形中心列Dimcolorar ' 7种正方形DimShapeArr 7种正方形DimiColorIndexAsInteger '颜色索引dimmyblock (4,2) as integer '每个正方形的坐标数组将伴随着正方形的移动而变化DimbIsObjectEndAsBoolean '此正方形是否降到最低点DimiScoreAsInteger '分数
考虑到每个方块坐标不一样,我用一个三维数组来存储方块坐标为了方便起见,我使用VBA自己接口的数组函数来给我的ShapeArr赋值
' Initialize by yaxi _ liurivatesubinitsetmysheet = sheets( " sheet 1 ")color = Array(3,4,5,6,7,8,9) shapearr = array (array (0,0),array (0,1),array (0,1),Array(0,—1),Array(—1),Array(0,0),Array(0,1),Array(0,—1),Array(—1,1),_Array(Array(0,0Range("B1:K20 "),Interior.Pattern=xlNoneBorders.LineStyle=xlNone边框(xlEdgeBottom)重量=xlMedium边框(xlEdgeRight)重量=xlMedium边框(xlEdgeLeft)Weight=xlMediumEndWith '设置纵横比mysheet.columns ( "a: l ")列宽= 2mesheet.rows ( "1: 30 ")
这时候我们初始化变量和函数的功能就基本实现了接下来,我们将编写一个函数来生成一个新的正方形为了实现程序的模块化和低耦合,我们把这个功能封装成一个独立的功能
由于绘图函数DrawBlock需要根据传递的标记数组进行绘制,并且我们需要知道这个正方形的中心坐标在哪里以及对应的颜色,所以需要传递四个参数,其中数组需要被寻址(ByRef)。代码如下:
'画一个正方形,by yaxi _ liurivatesubdrawblock integer,byvalicolasinteger)dimrowasininteger,colasinteger = 0 to 3 row = center _ row+block(I,0) col = center _ col+block (I,1) mysheet.cells (row,col)interior . colorindex = icolor ' color index my sheet . cells(row,col)borders . line style = XL continuous '带大纲线NextEndSub
至此,绘图功能已经完成为了防止bug,我们需要测试它我们会定义一个入口函数,Start,同时定义一个临时的方形数组,调用DrawBlock进行测试
启动功能代码如下:
substartcalliniticertrow = 5 iCenterCol = 6 iColorIndex = 4 dimiasintegerfori = 0 to 3 MyBlock(I,0)= shape arr(iColorIndex)(I)(0)my block(I,1)= shape arr(iColorIndex)(I)(1)NextCallDrawBlock(iCenterRow,iCenterCol,my block,ColorArr(iColorIndex))EndSub
让我们运行它,看看效果:
好的,检测结果显示完全没有问题。
后期需要在表格顶部的固定位置随机生成新的方块,所以要把这个函数重新包装成一个独立的函数为了防止伪随机数的产生,我们使用Timer作为当前种子,随机生成0到6之间的数组,每个数组对应形状数组和颜色数组的索引
'由yaxi _ liurivatesubgetblockrandomize(timer)dimasintegericolor index = int(7 * rnd)ice interrow = 2 icenter col = 6 fori = 0 to 3 myblock(I,0)= ShapeArr(iColorIndex)(I)(0)my block(I,1)= ShapeArr(iColorIndex)(I)(1)NextCallDrawBlock(ice interrow,iCenterCol,my block,colorrar(iColorIndex))EndSub
现在正方形生成了,我们要让正方形左右移动,分成三个方向移动的方法是先擦除当前的方块,然后按照指定的移动方向计算新的坐标,再按照新的坐标重新绘制,这样就产生了移动的现象但是,在搬家之前,我们需要判断自己是否可以搬家
首先我们需要写函数CanMoveRotate来判断它是否可以移动或者旋转这个函数很简单,就是我们可以通过移动或者旋转后的坐标来判断是否越界或者当前位置是否有其他颜色
'函数是否可以移动或旋转,由yaxi _ liurivatefunctioncanmoverotateasinteger)作为boolean '此函数的参数是变换后的坐标 '首先判断是否越界,DimRowAsInteger,colasintegercanmoverotate = true fori = 0 to 3 row = center _ row+block(I,0)Col=center_col+block(i,1)IfRowgt,20OrRowlt0OrColgt11或收集,2Then '出界可以移动rotate = false endifmyshet . cells(row,col)interior.patternltgt,XLONETHEN '只要有一种颜色,它就是blocking can move rotate = false endifnextendfunction
我们还需要一个函数EraseBlock来擦除当前的方块,可以根据传递过来的坐标直接擦除。代码如下:
' Erase block by yaxi _ liurivateseuberaselblocksetter)dimrowasinterer,colas interdimisinterfori = 0 to 3 row = center _ row+block(I,0) col = center _ col+block (i,1)MySheetCells(Row,Col). interior . pattern = xlNoneMySheet
我们来写移动块的函数MoveBlock我们规定参数direction代表方向,—1代表左,0代表下,1代表右注意,移动后需要保存当前坐标
'移动框by yaxi _ liurivatessubmoveblocksetter,byvalicolosetter,byvaldirectionassetter)dimrowasininteger,colas integer dimold _ row为整数,old _ colasinteger '保存最早的中心坐标old _ row = Center _ row old _ col = center _ col '首先擦除caller seblock(Center _ row,Center _ col,block)'—1为左,1为右,0代表农村selectcasedirectioncases =—1 Center _ col = Center _ col—1 case 然后画ifcanmovestate (center _ row,center _ col,block)然后画calldrawblock (center _ row,center _ col,block,icolor) 保存中心坐标ice interrow = center _ rowicentercol = center _ collsecalldrawblock(old _ row,old _ col,block,icolor) 保存中心坐标ice interrow = old _ rowicentercol = old _ colifdirection = 0 thenbibjectend = true endfendif '保存平方坐标fori = 0to3myblock (I,0) = block (I
移动块实现后,我们就写RotateBlock函数,定义为逆时针旋转就像移动函数一样,方法是先擦除旧坐标,然后根据新坐标画一个新方块只是旋转起来有点麻烦
如果一个向量逆时针旋转90度后坐标为(—y,x),就不难计算了根据这个公式,写出旋转函数但需要注意的是,要提前判断是否满足轮换的条件
' Rotate block function by yaxi _ liurivatesubrotateBlockasinteger,byvalicorasinteger)dimiasinteger ' Erase block(center _ row,center _ col,block) dimtemparr (4,2)as integer ' save array for I = 0 to 3 temparr(I,0) = block (i,0)= block(I,1) next '重新分配旋转后的坐标fori = 0to3block (i,0) =—temparr (i,0) icolor) '保存平方坐标Fori=0To3MyBlock(i,0)=block(i,0) myblock (I,1) = block (I,1)nextelsecalldrawblock(center _ row,center _ col,temparr,icolor) '保存平方坐标fori = 0to3 myblock (I,0) = temparr (I,0) myblock (I,1) 1)NextEndIf '保存中心坐标ice interrow = center _ rowice intercol = center _ colend sub。
这时,旋转和移动函数已经写好了为了让游戏对应键盘事件,我们需要在对应的工作表代码层添加事件函数注意,这里我们需要调用Windows API我们规定键盘左键为方形向左移动对象,右键为方形向右移动对象(1),下键为方形向下移动对象(0),上键为方形旋转对象()
'键盘事件代码,byyaxi _ Liu # ifvba 7 and win 64 thenrivateclareptsafeffunction getkeyboardstatelib " user 32 " AsLong # elsepropivatedclairefunction getkeyboardstatelib " user 32 " AsLong # EndIfPrivateSubWorksheet _ selection change(ByValTargetAsRange)dim key code(0到255)asbytegetkeyboardstatekey code(0)if key code(38)gt,127 then ' callrotateobjectelsifkeycode(39)gt,27然后 ' right callmoveobject(1)else if keycode(40)gt,127Then,callmoveobject(0)else if keycode(37)gt,127 then ' left CallMoveObject(—1)EndIfEndSub
因为我们自己定义的MoveBlock和RotateBlock包类对象的形参,所以不能在事件响应中直接调用这里我们将再次在类模块中封装两个公共的MoveObject和RotateObject函数,方便事件调用
' Move object by yaxi _ liuppublicsubmoveobjectcallmoveblock(icenterrow,icentercol,myblock,color (icon index),dir) end sub
'旋转对象by yaxi _ liuppublicsubrotateobjectcallrotateblock(ice interrow,icentercol,myblock,color (icolor index)) endsub。
至此,平方功能已经完全实现。我们随机生成一个用于测试:
为了方便起见,我们将按钮1中的文本改为开始游戏的四个词:
然后,开始编写程序自动运行的代码伴随着俄罗斯方块的生成,它以一定的速度下降一旦碰到障碍物,俄罗斯方块结束,然后生成新的俄罗斯方块,以此类推因为VBA不支持定时器,我们使用while循环方法来连续生成方块为了避免对CPU资源的过度占用,我们在循环之间增加了一个延迟函数,用于循环调用
' Delay function by yaxi _ liurivatesubdelaydimt 1 assinglet1 = timerdodoeventslopwhiletimer—t1lt,TEndSub
在下降的过程中,我们需要知道某条线是否已满判断的方法很简单,只需检查整条线是否上色即可如果满了,我们就删除这一行,把第一行填到这一行同时更新分数
'消除整行函数by yaxi _ liurivatesubdeletefullrowdimiasinger,jasintegerfori = 1 to 20 forj = 2 to 11 if my shet . cells(I,j)interior.colorindexlt0 thenexitforelseifj = 11 thenmysheet范围(单元格(1,2),单元格(i—1,j))CutDestination:=MySheetRange(Cells(2,2),Cells(i,j)) ' Range( " B2:K18 ")is core = is core+10 endifnextjnextimyshet . Range( " n1 ")value = " fraction " my shet . range( " O1 ")
在Start函数中添加while循环,上述两个函数添加的代码相同,如下所示:
'启动函数by yaxi _ liussubstartcalnitwhile(true)callgetblocksobjectend = false '此方块的对象是否结束while(bisobjectend = false)call delay(0.5)callmoveblock(icenterrow,iCenterCol,MyBlock,colorrar(iColorIndex),0)MySheetrange( " L21 "). selectwithmysheet . range( " B1:K20 ")边框(xlEdgeBottom)重量=xlMedium边框(xlEdgeRight)重量=xlMedium边框(xlEdgeLeft)
至此,这个游戏的编写就算完全完成了,点击Sheet1界面上的按钮1按钮开始游戏让我们再试一次左键代表左,右键代表右,上键代表旋转,下键代表下降
哈哈,试玩结束没问题,很完美虽然过程漫长,但值得你认真学习,希望你能从中体会到编程的乐趣如果你认为你学到了知识,我希望你能把这篇文章分享给更多的人
声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多企业信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。投资有风险,需谨慎。
您可能还喜欢:
- 猜您喜欢