Python生成无碰撞随机圆时出现'CreaCir'无radio属性错误排查
错误根源
- 列表元素类型混乱:
Ventana类的figs列表同时混入了CreaCir(圆创建器)和Circulo(圆实例)对象。当CreaCir的update方法遍历figs时,第一个元素是CreaCir实例,调用colisionC方法时,该方法试图访问c2.radio,但CreaCir无此属性,直接触发报错。 - 绘制与碰撞检测圆心不匹配:
Circulo类绘制圆时用(self.x, self.y)作为圆心,但碰撞检测用self.cx = x+r、self.cy = y+r作为圆心,导致实际绘制位置和碰撞逻辑位置不一致,即使修复类型问题,碰撞检测也会失效。
修复代码
1. 修正Ventana类
将圆创建器与圆实例列表分离,figs仅存储Circulo对象:
class Ventana: def __init__(self, Ven_Tam= (700, 500)): pg.init() self.ven_tam = Ven_Tam pg.display.set_caption("Linea") # 修正原重复赋值self.ven的错误 self.ven = pg.display.set_mode(self.ven_tam) self.ven.fill(pg.Color('#404040')) self.figs = [] # 仅存储Circulo实例 self.creador = CreaCir(self.figs) # 单独保存圆创建器 self.reloj = pg.time.Clock() def check_events(self): for event in pg.event.get(): if event.type == pg.QUIT or (event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE): pg.quit() # 用pg.quit()替代quit(),避免资源泄漏 exit() pg.display.flip() def run(self): while True: self.check_events() self.creador.update() # 仅调用创建器的update方法 self.ven.fill(pg.Color('#404040')) # 每次循环重绘背景,清除残留 for fig in self.figs: fig.dibujar(self.ven) self.reloj.tick(30)
2. 修正Circulo类
统一绘制和碰撞检测的圆心坐标:
from math import sqrt, pow class Circulo(PosGeo): def __init__(self, x, y, r): self.x = x # 圆的左上角x坐标 self.y = y # 圆的左上角y坐标 self.radio = r self.cx = x + r # 圆心x坐标 self.cy = y + r # 圆心y坐标 def dibujar(self, ventana): # 用圆心坐标绘制圆,与碰撞检测逻辑对齐 pg.draw.circle(ventana, "white", (self.cx, self.cy), self.radio, 1) def update(self): pass def colisionC(self, c2): distancia = sqrt(pow(self.cx - c2.cx, 2) + pow(self.cy - c2.cy, 2)) return self.radio + c2.radio > distancia
3. 调整CreaCir类
优化循环逻辑,确保遍历对象均为Circulo实例:
from random import randint class CreaCir: def __init__(self, figs): self.figs = figs self.i = 0 # 创建第一个圆并加入列表 self.figs.append(self.crear_circulo()) self.i += 1 def crear_circulo(self): r = randint(5, 104) # 确保圆不会超出窗口边界(基于左上角坐标计算) x = randint(r, 700 - r) y = randint(r, 500 - r) return Circulo(x, y, r) def update(self): if self.i < 100: choca = False nuevo_circulo = self.crear_circulo() # 遍历已存在的所有圆,检查碰撞 for circulo in self.figs: choca = nuevo_circulo.colisionC(circulo) if choca: break if not choca: self.figs.append(nuevo_circulo) self.i += 1 def dibujar(self, ventana): pass
额外优化点
- 修复
Ventana类中self.ven = pg.display.set_caption("Linea")的错误,set_caption无返回值,需单独调用。 - 添加窗口边界检查,避免生成的圆超出可视区域。
- 用
pg.quit()替代quit(),规范退出流程,防止资源泄漏。
内容的提问来源于stack exchange,提问作者Moy
相关产品推荐
相关产品推荐

