You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:为Python Turtle版Pacman游戏添加边框碰撞检测

解决Turtle库中Pacman角色无法穿过蓝色边框的碰撞检测问题

我正在用Python的turtle库开发Pacman游戏,已经完成蓝色游戏边框的绘制,现在要实现黄色控制turtle不能穿过蓝色边框的功能,但遇到了困难。之前尝试通过计算turtle坐标和边框坐标的差值来判断碰撞,没成功,而且不能用turtle以外的第三方库,求可行的代码解决方案。

以下是修改后的完整代码,核心通过颜色检测实现碰撞判断,无需额外记录边框坐标:

import turtle 
import random
import math

# 初始化画布和画笔
sam=turtle.Turtle()
score=turtle.Turtle()
screen=turtle.Screen()
sam.pensize(10)
sam.speed(0)
sam.penup()
sam.goto(-400,-400)
sam.pendown()
sam.speed(0)
sam.color("blue")
screen.bgcolor("black")

# 绘制外部边框
sam.penup()
sam.fd(200)
sam.pendown()
sam.fd(600)
sam.lt(90)
sam.fd(130)
sam.lt(90)
sam.fd(30)
sam.rt(90)
sam.fd(20)
sam.rt(90)
sam.fd(30)
sam.lt(90)
sam.fd(130)
sam.lt(90)
sam.fd(75)
sam.rt(90)
sam.fd(75)
sam.rt(90)
sam.fd(200)
sam.lt(90)
sam.fd(30)
sam.lt(90)
sam.fd(200)
sam.rt(90)
sam.fd(100)
sam.rt(90)
sam.fd(75)
sam.lt(90)
sam.fd(200)
sam.lt(90)
sam.fd(300)
sam.lt(90)
sam.fd(75)
sam.rt(90)
sam.fd(20)
sam.rt(90)
sam.fd(75)
sam.lt(90)
sam.fd(300)
sam.lt(90)
sam.fd(200)
sam.lt(90)
sam.fd(75)
sam.rt(90)
sam.fd(100)
sam.rt(90)
sam.fd(200)
sam.lt(90)
sam.fd(30)
sam.lt(90)
sam.fd(200)
sam.rt(90)
sam.fd(75)
sam.rt(90)
sam.fd(75)
sam.lt(90)
sam.fd(130)
sam.lt(90)
sam.fd(30)
sam.rt(90)
sam.fd(20)
sam.rt(90)
sam.fd(30)
sam.lt(90)
sam.fd(130)
sam.lt(90)
sam.fd(30)

# 定义各种形状类
class lshape:
    def __init__(self,turtle):
        self.turtle=turtle
    def draw(self):
        sam.fd(100)
        sam.lt(90)
        sam.fd(50)
        sam.lt(90)
        sam.fd(20)
        sam.lt(90)
        sam.fd(30)
        sam.rt(90)
        sam.fd(80)
        sam.lt(90)
        sam.fd(20)
        sam.lt(90)

class lshape2:
    def __init__(self,turtle):
        self.turtle=turtle
    def draw(self):
        self.turtle.fd(150)
        self.turtle.lt(90)
        self.turtle.fd(20)
        self.turtle.lt(90)
        self.turtle.fd(40)
        self.turtle.rt(90)
        self.turtle.fd(70)
        self.turtle.lt(90)
        self.turtle.fd(20)
        self.turtle.lt(90)
        self.turtle.fd(70)
        self.turtle.rt(90)
        self.turtle.fd(90)
        self.turtle.lt(90)
        self.turtle.fd(20)

class lshape3:
    def __init__(self,turtle):
        self.turtle=turtle
    def draw(self):
        self.turtle.fd(150)
        self.turtle.rt(90)
        self.turtle.fd(20)
        self.turtle.rt(90)
        self.turtle.fd(65)
        self.turtle.lt(90)
        self.turtle.fd(70)
        self.turtle.rt(90)
        self.turtle.fd(20)
        self.turtle.rt(90)
        self.turtle.fd(70)
        self.turtle.lt(90)
        self.turtle.fd(65)
        self.turtle.rt(90)
        self.turtle.fd(20)

class lshape4:
    def __init__(self,turtle):
        self.turtle=turtle
    def draw(self): 
        for i in range(2):
            self.turtle.fd(100)
            self.turtle.rt(90)
            self.turtle.fd(20)
            self.turtle.rt(90)

class lshape5:
    def __init__(self,turtle,l):
        self.l=l
        self.turtle=turtle
    def draw(self): 
        for i in range(2):
            self.turtle.fd(self.l)
            self.turtle.rt(90)
            self.turtle.fd(40)
            self.turtle.rt(90)

class Wshape:
    def __init__(self,turtle):
        self.turtle=turtle
    def draw(self):
        self.turtle.fd(150)
        self.turtle.lt(90)
        self.turtle.fd(20)
        self.turtle.lt(90)
        self.turtle.fd(90)
        self.turtle.rt(90)
        self.turtle.fd(70)
        self.turtle.lt(90)
        self.turtle.fd(20)
        self.turtle.lt(90)
        self.turtle.fd(70)
        self.turtle.rt(90)
        self.turtle.fd(40)
        self.turtle.lt(90)
        self.turtle.fd(20)

class Wshape2:
    def __init__(self,turtle):
        self.turtle=turtle
    def draw(self):
        sam.fd(100)
        sam.rt(90)
        sam.fd(50)
        sam.rt(90)
        sam.fd(20)
        sam.rt(90)
        sam.fd(30)
        sam.lt(90)
        sam.fd(80)
        sam.rt(90)
        sam.fd(20)
        sam.lt(90)

class Box:
    def __init__(self,turtle,x,y):
        self.turtle=turtle
        self.x=x
        self.y=y
    def draw(self):
        for i in range(2):
            self.turtle.fd(200)
            self.turtle.lt(90)
            self.turtle.fd(100)
            self.turtle.lt(90)
        self.turtle.penup()
        self.turtle.goto(self.x-5,self.y-5)
        self.turtle.pendown()
        for i in range(2):
            self.turtle.fd(210)
            self.turtle.lt(90)
            self.turtle.fd(110)
            self.turtle.lt(90)

# 绘制所有内部形状
shape=lshape(sam)
shape2=lshape2(sam)
shape3=lshape3(sam)
shape4=lshape4(sam)
shape5=lshape5(sam,100)
wshape=Wshape(sam)
wshape2=Wshape2(sam)
box=Box(sam,-5,-80)

sam.penup()
sam.goto(-120,-270)
sam.lt(90)
sam.pendown()
shape.draw()

sam.penup()
sam.goto(-140,-350)
sam.rt(90)
sam.pendown()
shape2.draw()

sam.penup()
sam.goto(25,-260)
sam.lt(90)
sam.pendown()
shape3.draw()

sam.penup()
sam.goto(190,-350)
sam.rt(90)
sam.pendown()
wshape.draw()

sam.penup()
sam.goto(310,-270)
sam.rt(180)
sam.pendown()
wshape2.draw()

sam.penup()
sam.goto(150,-200)
sam.lt(90)
sam.pendown()
shape4.draw()

sam.penup()
sam.goto(-50,-200)
sam.pendown()
shape4.draw()

sam.penup()
sam.goto(25,-120)
sam.pendown()
shape3.draw()

sam.penup()
sam.goto(-100,-120)
sam.pendown()
shape4.draw()

sam.penup()
sam.goto(265,-120)
sam.pendown()
shape4.draw()

sam.penup()
sam.goto(-5,-80)
sam.pendown()
sam.rt(90)
box.draw()

sam.penup()
sam.goto(-100,20)
sam.pendown()
sam.lt(90)
shape3.draw()

sam.penup()
sam.goto(20,170)
sam.pendown()
sam.rt(180)
shape3.draw()

sam.penup()
sam.goto(280,170)
sam.pendown()
sam.lt(180)
shape3.draw()

sam.penup()
sam.goto(150,250)
sam.pendown()
shape5.draw()
shape5=lshape5(sam,70)

sam.penup()
sam.goto(300,250)
sam.pendown()
shape5.draw()
shape5=lshape5(sam,100)

sam.penup()
sam.goto(-70,250)
sam.pendown()
shape5.draw()
shape5=lshape5(sam,70)

sam.penup()
sam.goto(-190,250)
sam.pendown()
shape5.draw()

# 初始化玩家角色
j=turtle.Turtle()
j.shape("turtle")
j.color("yellow")
j.penup()
j.goto(200,-370)

# 获取画布对象用于颜色检测
canvas = screen.getcanvas()

# 碰撞检测辅助函数:判断目标位置是否为蓝色边框
def is_collision(x, y):
    # 转换Turtle坐标为Canvas坐标(y轴方向相反)
    canvas_x = canvas.canvasx(x)
    canvas_y = canvas.canvasy(y)
    # 获取该点的RGB颜色值(tkinter返回16位值,范围0-65535)
    rgb = canvas.winfo_rgb(canvas.getpixel((canvas_x, canvas_y)))
    # 蓝色边框的RGB值为(0, 0, 65535)
    return rgb == (0, 0, 65535)

# 移动控制函数,加入碰撞检测
def right():
    j.rt(90)

def left():
    j.lt(90)

def up():
    # 计算移动后的目标位置
    angle = math.radians(j.heading())
    new_x = j.xcor() + math.cos(angle) * 10
    new_y = j.ycor() + math.sin(angle) * 10
    # 检查目标位置是否碰撞边框,无碰撞则移动
    if not is_collision(new_x, new_y):
        j.fd(10)

def down():
    # 计算移动后的目标位置
    angle = math.radians(j.heading())
    new_x = j.xcor() - math.cos(angle) * 10
    new_y = j.ycor() - math.sin(angle) * 10
    # 检查目标位置是否碰撞边框,无碰撞则移动
    if not is_collision(new_x, new_y):
        j.bk(10)

# 绑定键盘事件
screen.onkey(up,"Up")
screen.onkey(down,"Down")
screen.onkey(right,"Right")
screen.onkey(left,"Left")
screen.listen()

turtle.done()

关键实现说明

  1. 颜色检测原理:利用turtle底层的tkinter画布获取目标位置的颜色,若为蓝色边框则禁止移动,无需手动记录所有边框坐标。
  2. 坐标转换:Turtle的y轴向上,而tkinter画布的y轴向下,需用canvasx()和canvasy()转换坐标。
  3. 16位颜色值:tkinter的winfo_rgb()返回16位RGB值,蓝色对应(0, 0, 65535)而非8位的(0,0,255)。
  4. 预判移动位置:每次移动前先计算目标坐标,检测无碰撞后再执行移动,避免角色穿过边框。

内容的提问来源于stack exchange,提问作者jayash patnaik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 17:17:02