PyGame移动圆形鼠标停留时长统计异常及命中识别问题
鼠标在移动圆形区域内停留时长统计问题
我想统计鼠标在移动圆形区域内的停留时长,当前逻辑是记录鼠标离开圆形的时间,与上次离开时间(首次则与开始时间)做差累加,但最终结果始终接近程序运行总时长(10秒)。另外,注释掉move_circle函数使用静止圆形时,无法识别任何命中。
原代码
import pygame import time import random import math from time import perf_counter_ns as timer pygame.init() # Define the background colour # using RGB color coding. black = (0, 0, 0) red = (255, 10, 75) # Define the dimensions of # screen object(width,height) screenx = 1200 screeny = 1000 screen = pygame.display.set_mode((screenx, screeny)) # Set the caption of the screen pygame.display.set_caption('Geeksforgeeks') # Fill the background colour to the screen screen.fill(black) # Update the display using flip pygame.display.flip() # Variable to keep our game loop running running = True end = 10 nano = 1000000000 def clear_screen(): screen.fill(black) pygame.display.flip() class circle(): def __init__(self, radius): self.velocity = random.randint(1, 10) self.theta = random.randint(0, 360) self.radius = radius self.alive = False def draw_circle(self, radius): self.x = random.randint(0, screenx) self.y = random.randint(0, screeny) pygame.draw.circle(screen, red, (random.randint(0, 1200), random.randint(0, 1200)), radius) pygame.display.update() self.alive = True def move_circle(self): clear_screen() self.x += self.velocity * math.cos(self.theta) self.y += self.velocity * math.sin(self.theta) pygame.draw.circle(screen, red, (self.x, self.y), self.radius) pygame.display.update() time.sleep(0.1) def change_velocity(self): self.velocity = random.randint(1, 1) self.theta = random.randint(0, 360) def check_collision(self): if (self.x - self.radius) < 0 or (self.x + self.radius) > screenx: self.x = random.randint(0, screenx) if (self.y - self.radius) < 0 or (self.y + self.radius) > screeny: self.y = random.randint(0, screeny) def mouse_in_red(self, mouse_x, mouse_y): if (mouse_x - self.x)**2 + (mouse_y - self.y)**2 < self.radius**2: return True else: return False target = circle(25) # game loop start = timer() crnt_time = start times = [start] target.draw_circle(25) while running: if target.alive == False: target.draw_circle(25) time.sleep(1) else: if random.randint(0, 100) == 1: target.change_velocity() target.move_circle() target.check_collision() if target.mouse_in_red(pygame.mouse.get_pos()[0], pygame.mouse.get_pos()[1]): print('hit') continue else: print(f'miss',{(timer() - crnt_time)/nano}) times.append(timer() - crnt_time) crnt_time = timer() if (timer() - start)/nano > end: running = False print(f'total time spent on target(out of ',{end},'seconds):', {(sum(times[1:]))/nano}) print(f'average time spent on target:', {(sum(times[1:])/len(times[1:]))/nano}) #for i in range(len(times[1:])): # print(f'time spent on target {i}:', {(times[i])/nano}) # for loop through the event queue for event in pygame.event.get(): # Check for QUIT event if event.type == pygame.QUIT: running = False
原输出结果
total time spent on target(out of {10} seconds): {10.0042299} average time spent on target: {0.22736886136363638}
问题根源
- 统计逻辑完全颠倒:当前代码累加的是鼠标不在圆形内的时间,却误当成停留时长,结果自然接近总运行时间。
- 静止圆形命中失效:
draw_circle方法中,先给self.x/self.y赋值随机数,但绘制时又用了新的随机坐标,导致鼠标命中判断的位置和屏幕实际显示的圆形位置完全不一致。 - 其他隐性问题:
- 传入
math.cos/math.sin的是角度而非弧度,导致圆形移动方向错误。 time.sleep(0.1)阻塞游戏循环,影响时间统计准确性和交互流畅度。- 碰撞检测直接重置坐标,不符合物理移动逻辑。
- 传入
修复后的代码
import pygame import random import math from time import perf_counter_ns as timer pygame.init() black = (0, 0, 0) red = (255, 10, 75) screenx = 1200 screeny = 1000 screen = pygame.display.set_mode((screenx, screeny)) pygame.display.set_caption('Geeksforgeeks') screen.fill(black) pygame.display.flip() running = True end = 10 nano = 1000000000 def clear_screen(): screen.fill(black) pygame.display.flip() class circle(): def __init__(self, radius): self.velocity = random.randint(1, 10) # 初始角度转为弧度 self.theta = math.radians(random.randint(0, 360)) self.radius = radius self.alive = False def draw_circle(self, radius): self.x = random.randint(radius, screenx - radius) self.y = random.randint(radius, screeny - radius) # 用self.x/self.y绘制,保证显示与判断位置一致 pygame.draw.circle(screen, red, (self.x, self.y), radius) pygame.display.update() self.alive = True def move_circle(self): clear_screen() self.x += self.velocity * math.cos(self.theta) self.y += self.velocity * math.sin(self.theta) pygame.draw.circle(screen, red, (self.x, self.y), self.radius) pygame.display.update() def change_velocity(self): self.velocity = random.randint(1, 10) self.theta = math.radians(random.randint(0, 360)) def check_collision(self): # 碰到边界反弹,而非重置坐标 if (self.x - self.radius) < 0 or (self.x + self.radius) > screenx: self.theta = math.pi - self.theta if (self.y - self.radius) < 0 or (self.y + self.radius) > screeny: self.theta = -self.theta # 确保圆形不超出边界 self.x = max(self.radius, min(self.x, screenx - self.radius)) self.y = max(self.radius, min(self.y, screeny - self.radius)) def mouse_in_red(self, mouse_x, mouse_y): return (mouse_x - self.x)**2 + (mouse_y - self.y)**2 < self.radius**2 target = circle(25) start = timer() in_circle_start = None total_in_time = 0 target.draw_circle(25) clock = pygame.time.Clock() # 用帧率控制替代sleep while running: clock.tick(60) # 限制帧率为60fps current_time = timer() if not target.alive: target.draw_circle(25) else: if random.randint(0, 100) == 1: target.change_velocity() target.move_circle() target.check_collision() mouse_pos = pygame.mouse.get_pos() is_in = target.mouse_in_red(mouse_pos[0], mouse_pos[1]) if is_in: if in_circle_start is None: # 记录进入圆形的时间点 in_circle_start = current_time print('hit') else: if in_circle_start is not None: # 计算停留时长并累加 duration = current_time - in_circle_start total_in_time += duration in_circle_start = None print(f'miss') # 检查是否到达结束时间 if (current_time - start)/nano > end: running = False # 补上最后一段在圆内的时间(如果未离开) if in_circle_start is not None: total_in_time += current_time - in_circle_start print(f'总停留时长(总运行时长{end}秒): {total_in_time/nano:.3f}秒') # 事件处理 for event in pygame.event.get(): if event.type == pygame.QUIT: running = False pygame.quit()
修复说明
- 修正统计逻辑:
- 新增
in_circle_start变量记录鼠标进入圆形的时间点 - 鼠标离开圆形时计算停留时长并累加,程序结束时补全最后一段停留时间
- 新增
- 修复静止圆形命中问题:
draw_circle方法中,绘制圆形使用self.x/self.y,保证显示位置与判断位置一致
- 其他优化:
- 将角度转为弧度,修正圆形移动方向
- 用
pygame.time.Clock()替代time.sleep,保证帧率稳定且不阻塞循环 - 修改碰撞检测为边界反弹,符合物理移动逻辑
- 限制圆形坐标范围,避免超出屏幕边界
内容的提问来源于stack exchange,提问作者Gulliver Brower
相关产品推荐
相关产品推荐

