Python:海龟图形中浮点取整优化集合碰撞检测方案问询
解决Turtle库贪吃蛇游戏的碰撞检测与食物重叠问题
问题背景
开发基于Turtle库的贪吃蛇时,遇到两个核心问题:
- 蛇身自撞检测因浮点数精度失效:Turtle的
.position()返回10位小数的浮点数,即使位置相同数值也可能存在微小差异,直接转整数会有精度偏差,用保留两位小数的方式仍存在隐患。 - 食物生成时偶尔与蛇身重叠:现有食物刷新逻辑中,坐标格式与蛇身坐标不统一,导致重叠判断失效。
优化方案
1. 统一整数坐标系统
由于蛇每次固定移动20单位,所有有效位置必然是20的整数倍,直接将坐标转为整数即可彻底规避浮点数精度问题,无需保留小数。
2. 简化蛇身坐标更新逻辑
不再从Turtle对象读取位置,而是通过逻辑计算直接更新坐标列表,既提升效率又避免精度误差。
3. 修复食物生成的坐标匹配
食物生成时直接生成20的整数倍坐标,与蛇身坐标格式统一,确保重叠判断准确。
修改后的代码
gamesetup.py
import turtle as t class FullSnake: def __init__(self) -> None: self.snake_part_list = [] # 初始坐标全部使用整数 self.snake_coord_list = [(-40, 0), (-60, 0), (-80, 0)] self.moment_prior_coord_list = [(-40, 0), (-60, 0), (-80, 0)] for nums in range(3): new_segment = t.Turtle("circle") new_segment.penup() new_segment.color("white") self.snake_part_list.append(new_segment) new_segment.goto(self.snake_coord_list[nums]) self.snake_head = self.snake_part_list[0] self.headingverification = 0 def add_segment(self): """在蛇尾添加新段""" new_segment = t.Turtle("circle") new_segment.penup() new_segment.color("white") self.snake_part_list.append(new_segment) current_final_seg_pos = self.moment_prior_coord_list[-1] new_segment.goto(current_final_seg_pos) self.snake_coord_list.append(current_final_seg_pos) def right(self): if self.headingverification != 180: self.snake_head.setheading(0) def up(self): if self.headingverification != 270: self.snake_head.setheading(90) def left(self): if self.headingverification != 0: self.snake_head.setheading(180) def down(self): if self.headingverification != 90: self.snake_head.setheading(270) def move_snake(self): """移动蛇:头部前进,后续段跟随前一段位置""" self.moment_prior_coord_list = self.snake_coord_list.copy() # 先更新身体坐标与位置 for seg_num in range(len(self.snake_part_list)-1, 0, -1): self.snake_coord_list[seg_num] = self.snake_coord_list[seg_num-1] self.snake_part_list[seg_num].goto(self.snake_coord_list[seg_num]) # 移动头部并更新坐标为整数 self.snake_head.forward(20) head_x = int(self.snake_head.xcor()) head_y = int(self.snake_head.ycor()) self.snake_coord_list[0] = (head_x, head_y)
food.py
from turtle import Turtle import random screensize = (340, 340) class Food(Turtle): def __init__(self) -> None: super().__init__() self.shape("square") self.penup() self.color("red") self.speed("fastest") self.refresh([(20,0),(0,0), (-20,0)]) def refresh(self, positionlist): # 直接生成20的整数倍坐标,与蛇身格式统一 while True: randomx = random.randint(-7, 7) * 20 randomy = random.randint(-7, 7) * 20 newloc = (randomx, randomy) if newloc not in positionlist: break self.goto(randomx, randomy) print(f"{randomx} and {randomy}")
main.py
import turtle as t from gamesetup import FullSnake import time import food import score_board as sb screen = t.Screen() screen.setup(food.screensize[0],food.screensize[1]) screen.bgcolor("Black") screen.title("My Snake Game") screen.tracer(0) snakefood = food.Food() snake = FullSnake() scoreboard = sb.ScoreBoard() screen.listen() screen.onkey(snake.up,"Up") screen.onkey(snake.down,"Down") screen.onkey(snake.right,"Right") screen.onkey(snake.left,"Left") def snakemovefct(): snake.move_snake() screen.update() if snake.snake_head.distance(snakefood) <5: snake.add_segment() snakefood.refresh(snake.snake_coord_list) scoreboard.score_event() screen.update() time.sleep(0.1) # 边界碰撞检测,使用整数坐标判断 head_x, head_y = snake.snake_coord_list[0] if head_x > 150 or head_x < -150 or head_y > 150 or head_y < -150: scoreboard.game_over() return # 蛇身自撞检测:直接检查头部坐标是否在身体坐标列表中 if snake.snake_coord_list[0] in snake.snake_coord_list[1:]: scoreboard.game_over() return snake.headingverification = snake.snake_head.heading() screen.ontimer(snakemovefct,150) screen.update() screen.ontimer(snakemovefct,150) screen.mainloop()
scoreboard.py
代码无需修改,保持原逻辑即可。
内容的提问来源于stack exchange,提问作者Dragnipur
相关产品推荐
相关产品推荐

