TI-Basic编写俄罗斯方块:落地后行列表更新及绘制优化问询
嘿,我来帮你搞定TI-Basic俄罗斯方块的这两个核心需求,还给你完善了完整代码,直接能用!
一、方块落地时高效更新行列表的最优方法
首先得把屏幕上的方块坐标和你的行列表(ʟTR1、ʟTR2这些)对应起来,不然没法准确更新。
1. 坐标转行列的映射公式
你的游戏区域是x∈[-15,15]、y∈[-31,31],行列表是21行(对应y方向)、每行11个元素(对应x方向),所以可以用这两个公式把屏幕坐标转换成行号和列索引:
- 列索引:
(x + 15) // 3 + 1。解释下:x从-15到15,加15后变成0到30,除以3得到0-10,加1后刚好是1-11,对应每行列表的11个位置。 - 行号:
(31 - y) // 3 + 1。y从31(顶部)到-31(底部),31-y是0到62,除以3得到0-20,加1后是1-21,建议把ʟTRA、ʟTRB统一改成ʟTR3到ʟTR21,方便循环处理。
2. 落地检测与行更新逻辑
当方块没法继续下落(要么碰到底部,要么下面有已经落地的方块),就遍历方块的四个小方块,把每个小方块对应的行列表位置设为1:
- 先给每个方块定义相对坐标列表(相对于方块的原点(x,y)),比如L型的四个小方块相对坐标是
[(0,0), (8,0), (8,-6), (8,-12)](和你之前的绘制尺寸匹配)。 - 遍历每个相对坐标,算出绝对坐标
(x + x_off, y + y_off),再用上面的公式转成行号和列索引,然后执行1→ʟTR[row][col]就行。
3. 消行与重置
遍历所有21行,检查每行的总和是不是11(因为每行11个元素,全是1的话总和就是11),如果是就用Fill(0,ʟTR[row])把整行重置为0,然后把上面的所有行依次往下移一行,最顶部的行填充0。
二、用坐标列表绘制方块的实现方式
完全不需要外部库,给每个方块做个相对坐标列表,然后写个通用的绘制子程序循环画就行:
1. 给每个方块定义相对坐标
比如:
- L型(p=1):
{0,0, 8,0, 8,-6, 8,-12}(每两个数一组,前一个是x偏移,后一个是y偏移,对应四个小方块) - 镜像L型(p=2):
{0,0, 8,0, 0,-6, 0,-12} - 直线型(p=3):
{0,0, 0,-6, 0,-12, 0,-18} - 方块型(p=4):
{0,0, 8,0, 0,-6, 8,-6} - S型(p=5):
{0,0, 8,0, 8,-6, 16,-6} - Z型(p=6):
{8,0, 16,0, 0,-6, 8,-6} - T型(p=7):
{8,0, 0,-6, 8,-6, 16,-6}
2. 通用绘制子程序
写一个DRAW标签的子程序,接收原点(x,y)和坐标列表,循环绘制每个小方块的空心矩形:
Lbl DRAW For(I,1,Dim(ʟCOORDS),2) X_OFF=ʟCOORDS[I] Y_OFF=ʟCOORDS[I+1] // 画空心矩形的四条边 Line(X+X_OFF, Y+Y_OFF, X+X_OFF+8, Y+Y_OFF) Line(X+X_OFF+8, Y+Y_OFF, X+X_OFF+8, Y+Y_OFF-6) Line(X+X_OFF+8, Y+Y_OFF-6, X+X_OFF, Y+Y_OFF-6) Line(X+X_OFF, Y+Y_OFF-6, X+X_OFF, Y+Y_OFF) End // 重新画边框(因为ClrDraw会清掉) Line(15,-31,-15,-31) Line(-15,-31,-15,31) Line(15,-31,15,31) Line(15,31,-15,31) Return
然后每个方块的标签里,只要把对应的坐标列表存到ʟCOORDS,调用Gosub DRAW就行,比如:
Lbl 3 // L型 {0,0, 8,0, 8,-6, 8,-12}→ʟCOORDS Gosub DRAW Goto 10
三、完善后的完整代码
把上面的逻辑整合到你的代码里,还加了按键移动、碰撞检测、消行的完整逻辑:
// 初始化21行,每行11个0(如果计算器不支持&连接变量,手动定义ʟTR1到ʟTR21) For(I,1,21) 11→Dim(ʟTR&I) Fill(0,ʟTR&I) End ZoomRcl 11 ClrDraw // 绘制游戏边框 Line(15,-31,-15,-31) Line(-15,-31,-15,31) Line(15,-31,15,31) Line(15,31,-15,31) Lbl MAIN -5→X // 方块初始x坐标 30→Y // 方块初始y坐标 randInt(1,7)→P // 随机生成方块类型 // 给每个方块绑定坐标列表 If P=1: Then {0,0,8,0,8,-6,8,-12}→ʟCOORDS: End If P=2: Then {0,0,8,0,0,-6,0,-12}→ʟCOORDS: End If P=3: Then {0,0,0,-6,0,-12,0,-18}→ʟCOORDS: End If P=4: Then {0,0,8,0,0,-6,8,-6}→ʟCOORDS: End If P=5: Then {0,0,8,0,8,-6,16,-6}→ʟCOORDS: End If P=6: Then {8,0,16,0,0,-6,8,-6}→ʟCOORDS: End If P=7: Then {8,0,0,-6,8,-6,16,-6}→ʟCOORDS: End Lbl FALL ClrDraw // 清除上一帧的方块 Gosub DRAW // 绘制当前方块 // 按键处理(左、右移动,按键码根据你的计算器调整) getKey→K If K=24: X-3→X // 左移 If K=26: X+3→X // 右移 // 检测是否可以下落 Dim(ʟCOORDS)→N CAN_FALL=1 // 检查每个小方块下方是否有障碍 For(I,1,N,2) X_OFF=ʟCOORDS[I] Y_OFF=ʟCOORDS[I+1] CURRENT_Y=Y+Y_OFF-3 // 下落后的y坐标 CURRENT_X=X+X_OFF // 转换为行号和列索引 ROW=(31 - CURRENT_Y)//3 +1 COL=(CURRENT_X +15)//3 +1 // 超出边界或者下方有方块,就不能下落 If ROW>21 or COL<1 or COL>11: CAN_FALL=0 If CAN_FALL=1 and ʟTR&ROW[COL]=1: CAN_FALL=0 End // 可以下落就更新y坐标 If CAN_FALL=1: Y-3→Y // 不能下落就更新行列表,然后生成新方块 If CAN_FALL=0: Then // 把当前方块的每个小方块标记到行列表 For(I,1,N,2) X_OFF=ʟCOORDS[I] Y_OFF=ʟCOORDS[I+1] CURRENT_X=X+X_OFF CURRENT_Y=Y+Y_OFF ROW=(31 - CURRENT_Y)//3 +1 COL=(CURRENT_X +15)//3 +1 If ROW>=1 and ROW<=21 and COL>=1 and COL<=11: 1→ʟTR&ROW[COL] End // 消行处理:从下往上检查 For(ROW,21,1,-1) If sum(ʟTR&ROW)=11: Then // 整行填满 Fill(0,ʟTR&ROW) // 上面的行依次下移 For(UP_ROW,ROW-1,1,-1) ʟTR&UP_ROW→ʟTR&(UP_ROW+1) End Fill(0,ʟTR1) // 顶部行重置为0 End End Goto MAIN // 生成新方块 End Pause 100 // 控制下落速度(数值越小越快) Goto FALL Lbl DRAW // 通用绘制子程序 For(I,1,Dim(ʟCOORDS),2) X_OFF=ʟCOORDS[I] Y_OFF=ʟCOORDS[I+1] Line(X+X_OFF, Y+Y_OFF, X+X_OFF+8, Y+Y_OFF) Line(X+X_OFF+8, Y+Y_OFF, X+X_OFF+8, Y+Y_OFF-6) Line(X+X_OFF+8, Y+Y_OFF-6, X+X_OFF, Y+Y_OFF-6) Line(X+X_OFF, Y+Y_OFF-6, X+X_OFF, Y+Y_OFF) End // 重绘边框 Line(15,-31,-15,-31) Line(-15,-31,-15,31) Line(15,-31,15,31) Line(15,31,-15,31) Return
注意事项
- 如果你的TI计算器不支持
ʟTR&I这种动态变量名,就手动把21个行列表定义好(比如11→Dim(ʟTR1)到11→Dim(ʟTR21)),然后把循环里的ʟTR&ROW改成对应的ʟTR1、ʟTR2等,用条件判断处理。 - 按键码
24和26是TI-84的左右箭头,如果你的计算器按键码不同,需要调整成对应的数值。
内容的提问来源于stack exchange,提问作者Virtual Ghost
相关产品推荐
相关产品推荐

