Python turtle Tron游戏光轨碰撞检测实现咨询
实现方案
你原本的4个while循环独立存储坐标的方案无法正常运行:while True属于阻塞逻辑,会直接卡死turtle的事件主循环,程序启动后会直接无响应;拆分x、y坐标单独存储也没有必要,直接存储(x坐标, y坐标)格式的元组,读写效率更高。
不建议使用颜色检测实现碰撞判定:Python turtle没有原生提供高性能的屏幕像素取色接口,依赖底层tkinter抓屏取色的方案运行效率低、跨平台兼容问题多,稳定性远不如坐标点匹配方案。
正确实现逻辑如下:
- 初始化两个列表,分别存储红、蓝玩家光轮摩托驶过的所有轨迹坐标
- 每次游戏循环内,玩家完成移动后,将当前坐标追加到对应玩家的轨迹列表中;开局前5个坐标点跳过碰撞检测,避免误判玩家撞到自身出发位置
- 碰撞检测环节新增轨迹碰撞判断:将红方当前坐标与蓝方历史轨迹点逐一比对,距离小于容差则判定红方撞线,蓝方获胜;反之判定蓝方撞线,红方获胜
- 修复原有代码的已知问题:修正
collisions()函数永远返回False的bug、修正换行符错写为/n的问题、碰撞触发后直接终止游戏循环,避免程序继续运行。
修改后完整代码
import turtle import math import time width = 800 height = 600 game_running = True def TronGame(): global blue_direction, red_direction blue_direction = 'right' red_direction = 'left' # 蓝方移动控制 def blue_up(): global blue_direction if blue_direction != 'down': blue_direction = 'up' def blue_down(): global blue_direction if blue_direction != 'up': blue_direction = 'down' def blue_left(): global blue_direction if blue_direction != 'right': blue_direction = 'left' def blue_right(): global blue_direction if blue_direction != 'left': blue_direction = 'right' # 红方移动控制 def red_up(): global red_direction if red_direction != 'down': red_direction = 'up' def red_down(): global red_direction if red_direction != 'up': red_direction = 'down' def red_left(): global red_direction if red_direction != 'right': red_direction = 'left' def red_right(): global red_direction if red_direction != 'left': red_direction = 'right' # 玩家移动逻辑 def move_player(player, direction): if direction == 'up': player.setheading(90) player.forward(5) elif direction == 'down': player.setheading(270) player.forward(5) elif direction == 'left': player.setheading(180) player.forward(5) elif direction == 'right': player.setheading(0) player.forward(5) # 游戏结束提示 def game_over(message): global game_running game_running = False TurtleCrash = turtle.Turtle(visible=False) TurtleCrash.color("white") style = ('Arial', 25, 'italic') TurtleCrash.write(f"{message}\nGame over!", font=style, align='center') # 碰撞检测 def collisions(blue_trail, red_trail): x_blue, y_blue = blue_player.xcor(), blue_player.ycor() x_red, y_red = red_player.xcor(), red_player.ycor() # 两车直接相撞 if(math.isclose(x_blue, x_red, abs_tol=5.0) and math.isclose(y_blue, y_red, abs_tol=5.0)): game_over("Red and Blue Crashed!") return True # 边界碰撞 if x_blue > width/2 or x_blue < -width/2 or y_blue > height/2 or y_blue < -height/2: game_over("Blue went out of bounds.\nRed wins!") return True if x_red > width/2 or x_red < -width/2 or y_red > height/2 or y_red < -height/2: game_over("Red went out of bounds.\nBlue wins!") return True # 轨迹碰撞 跳过前5个点避免开局误判 for (tx, ty) in red_trail[5:]: if math.isclose(x_blue, tx, abs_tol=3.0) and math.isclose(y_blue, ty, abs_tol=3.0): game_over("Blue hit Red's trail.\nRed wins!") return True for (tx, ty) in blue_trail[5:]: if math.isclose(x_red, tx, abs_tol=3.0) and math.isclose(y_red, ty, abs_tol=3.0): game_over("Red hit Blue's trail.\nBlue wins!") return True return False def MainTron(): global screen global blue_player global red_player screen = turtle.Screen() screen.setup(width, height) screen.bgcolor('black') # 有自定义素材时取消下面三行注释即可 # screen.bgpic('TronBg.png') # screen.addshape('BlueBike.gif') # screen.addshape('RedBike.gif') blue_player = turtle.Turtle() # 无自定义素材时默认使用蓝色方块 blue_player.shape('square') blue_player.color("blue") # blue_player.shape('BlueBike.gif') blue_player.pencolor("blue") blue_player.pensize(3) blue_player.pu() blue_player.goto(-1*(width)/3, height/8) blue_player.pd() red_player = turtle.Turtle() # 无自定义素材时默认使用红色方块 red_player.shape('square') red_player.color("red") # red_player.shape('RedBike.gif') red_player.pencolor("red") red_player.pensize(3) red_player.pu() red_player.goto(width/3, height/8) red_player.pd() # 初始化轨迹存储列表 blue_trail = [] red_trail = [] # 开局倒计时 for x in range(5): count_turtle = turtle.Turtle(visible=False) count_turtle.color("white") style = ('Arial', 25, 'italic') count_turtle.write(5-x, font=style, align='center') time.sleep(1) count_turtle.undo() screen.listen() # 红方键位WASD screen.onkey(red_up, "w") screen.onkey(red_down, "s") screen.onkey(red_left, "a") screen.onkey(red_right, "d") # 蓝方键位方向键 screen.onkey(blue_up, "Up") screen.onkey(blue_down, "Down") screen.onkey(blue_left, "Left") screen.onkey(blue_right, "Right") def gameloop(): if not game_running: return move_player(red_player, red_direction) move_player(blue_player, blue_direction) # 记录当前坐标到轨迹列表 red_trail.append((red_player.xcor(), red_player.ycor())) blue_trail.append((blue_player.xcor(), blue_player.ycor())) # 碰撞检测 触发则结束游戏 if collisions(blue_trail, red_trail): return # 约60帧刷新率 screen.ontimer(gameloop, 16) screen.ontimer(gameloop, 250) gameloop() screen.mainloop() MainTron() TronGame()
代码额外做了优化:增加方向反向锁,避免玩家按反方向键直接掉头撞到自己的轨迹;没有自定义gif素材时默认用彩色方块代替,可直接运行测试。
内容的提问来源于stack exchange,提问作者Ian
相关产品推荐
相关产品推荐

