上一节我们画好了游戏的初始界面,本节我们让蛇动起来。
先实现开始按“→”之后,蛇一直往右走的功能,实际上是每一帧拼接而成,这里需要用到Tkinter 的 after()
方法来设置一个定时器,以便在一定的时间间隔后运行一个函数或方法,代码如下:
loop_id = window.after(FPS, game_loop)
window
是一个 Tkinter 窗口对象。after(FPS, game_loop)
是 Tkinter 的一个方法,用于在指定的毫秒数后调用一个函数。FPS
是游戏更新的时间间隔(以毫秒为单位),game_loop
是需要定时运行的函数。loop_id =
是将定时器的 ID 存储在loop_id
属性中,以便将来可能需要停止这个定时器。
蛇头一直往右走,蛇身体当成一个队列,每次蛇头移动之后,加上一个的蛇头位置计入队列中,当队列数量超过蛇身最大值的时候,就把队列第一个元素删掉
例如:
初始蛇头在(0,0)点,蛇身列表为空,snake_body = [],蛇身最大长度为3,此时蛇身长度为1.
当蛇头向右行进一步,此时蛇头在(0,1)点,snake_body = [[0,0]],此时蛇身长度为2;
继续向右行进一步,此时蛇头在(0,2)点,snake_body = [[0,0],[0,1]],此时蛇身长度为3;
继续向右行进一步,此时蛇头在(0,3)点,snake_body = [[0,0],[0,1],[0,2]],此时蛇身长度为4,超过最大长度,所以把蛇身第一个点(0,0)删掉,此时snake_body = [[0,1],[0,2]],此时蛇身长度为3,以此类推。
代码如下:
def print_map(snake_x,snake_y):
canvas.delete('all') #每一帧的打印都需要把之前的界面清除
tmp = [snake_x,snake_y]
snake_body.append(tmp) #把上一次的蛇头加到蛇身列表
snake_x = snake_x + 0
snake_y = snake_y + 1 #蛇一直往右走,每一步新的蛇头坐标
game_map[snake_x][snake_y] = 3 #蛇头标记为红色
if len(snake_body) <= 3:
#如果蛇身小于等于3,那么可以增加长度,就把蛇身最后一节设为黑色,意思是初始蛇身+蛇头=4
game_map[snake_body[-1][0]][snake_body[-1][1]] = 1
else:
#如果蛇身大于3,那么就把最开始加入蛇身的坐标(也就是蛇尾)删掉(颜色置位0),新加的一节设为黑色
game_map[snake_body[-1][0]][snake_body[-1][1]] = 1
game_map[snake_body[0][0]][snake_body[0][1]] = 0
del snake_body[0]
#循环打印地图所有元素
for i in range(0, height//bodyWidth):
for j in range(0, width//bodyWidth):
if game_map[i][j] == 1:
#从界面左上角为0,0,不是从屏幕开始
canvas.create_rectangle(j*bodyWidth, i*bodyWidth, (j+1)*bodyWidth, (i+1)*bodyWidth, outline='white', width=1, fill='black')
#print('1')
if game_map[i][j] == 2:
canvas.create_rectangle(j*bodyWidth, i*bodyWidth, (j+1)*bodyWidth, (i+1)*bodyWidth, outline='black', width=1, fill='gray')
#print('2')
if game_map[i][j] == 3:
canvas.create_rectangle(j*bodyWidth, i*bodyWidth, (j+1)*bodyWidth, (i+1)*bodyWidth, outline='black', width=1, fill='red')
#每一帧循环调用
window.after(1000, print_map, snake_x,snake_y)#print_map后面不需要加(),有参数的往后加
#执行该任务
print_map(snake_x,snake_y)
#无限循环主窗口直到用户关闭窗口或程序终止
window.mainloop()
效果演示
QQ录屏20231026103759
下一节,让我们用键盘让蛇转动起来吃食物!