基于Pygame的篮球游戏抛体运动实现问题求助
篮球游戏抛体运动实现问题
我正在开发一款篮球游戏,用户可控制篮球的投射方向与施加力度。目前尚未完成篮筐模块,卡在抛体运动(Projectile Motion)的实现环节。设计逻辑为:按下键盘"r"键设置投射力度,按下"w"键旋转向量以确定抛物线运动方向,但球既不沿向量方向运动,也未呈现正确的抛物线轨迹。参考网上代码仍未解决问题,完整代码如下:
import pygame import math BLACK = (0, 0, 0) WHITE = (255, 255, 255) FPS = 60 clock = pygame.time.Clock() screen_x = 900 screen_y = 500 ball_x = 40 ball_y = 40 time = 0 screen = pygame.display.set_mode((screen_x, screen_y)) pygame.display.set_caption("Basketball Game") jumping = False X_POSITION = 400 Y_POSITION = 375 Y_GRAVITY = 1 JUMP_HEIGHT = 20 Y_VELOCITY = JUMP_HEIGHT VEL_BALL = 15 ARROW_X = 500 ARROW_Y = 300 LENGHT_FORCE = 49 ANGLE = 0 ball = pygame.image.load("ball.svg.png") ball = pygame.transform.scale(ball, (80, 80)) ball_rect = ball.get_rect(center = (X_POSITION, Y_POSITION)) ball_width = ball.get_width() def ball_path(): Vx = math.cos(angle)* JUMP_HEIGHT Vy = math.sin(angle)* JUMP_HEIGHT distx = Vx * time disty = (Vy * time) +((-4.9 * (time)**2)/2) newx = round(distx + X_POSITION) newy = round(Y_POSITION-disty) return(newx, newy) #X_POSITION = newx #Y_POSITION = newy def find_angle(pos): sX = X_POSITION sY = Y_POSITION try: angle = math.pi / 2 except: angle = math.pi / 2 if pos[1] < sY and pos[0] > sX: angle = abs(angle) elif pos[1] < sY and pos[0] < sX: angle = math.pi - angle elif pos[1] > sY and pos[0] < sX: angle = math.pi + abs(angle) elif pos[1] > sY and pos[0] > sX: angle = (math.pi * 2) - angle return angle run = True while run: VECTOR_STARTPOINT = pygame.math.Vector2(X_POSITION, Y_POSITION) VECTOR_ENDPOINT = pygame.math.Vector2(100, 100) CURRENT_ENDPOINT = VECTOR_STARTPOINT + VECTOR_ENDPOINT.rotate(ANGLE) screen.fill(BLACK) for event in pygame.event.get(): if event.type == pygame.QUIT: run = False keys_pressed = pygame.key.get_pressed() if keys_pressed[pygame.K_SPACE]: jumping = True if keys_pressed[pygame.K_d] and X_POSITION < screen_x-ball_width//2: X_POSITION += VEL_BALL if keys_pressed[pygame.K_a] and X_POSITION > 0 + ball_width//2: X_POSITION -= VEL_BALL screen.fill(BLACK) #draw force line, red below, white above FORCE_MAX = pygame.draw.line(screen, (255, 0, 0) , (400, 50), (50, 50), 5) FORCE = pygame.draw.line(screen, WHITE , (LENGHT_FORCE, 50), (50, 50), 5) if keys_pressed[pygame.K_r] and LENGHT_FORCE <= 400: LENGHT_FORCE += 5 #coould do it with no hard coding if LENGHT_FORCE <= 200 and LENGHT_FORCE > 99: print("low") JUMP_HEIGHT = 20 Y_VELOCITY = JUMP_HEIGHT if LENGHT_FORCE > 200 and LENGHT_FORCE < 300: print("medium") JUMP_HEIGHT = 25 Y_VELOCITY = JUMP_HEIGHT if LENGHT_FORCE >= 300 and LENGHT_FORCE < 400: print("strong") JUMP_HEIGHT = 30 Y_VELOCITY = JUMP_HEIGHT if LENGHT_FORCE == 399: print("maximum") JUMP_HEIGHT = 35 Y_VELOCITY = JUMP_HEIGHT #start moving vector if keys_pressed[pygame.K_w]: ANGLE = (ANGLE + 5) % 360 VECTOR_LINE = pygame.draw.line(screen, WHITE, VECTOR_STARTPOINT, CURRENT_ENDPOINT, 4) #stop moving vector if event.type == pygame.KEYUP : if event.key == pygame.K_w : if Y_POSITION < screen_y and Y_POSITION >= 0: pos = CURRENT_ENDPOINT[0], CURRENT_ENDPOINT[1] angle = find_angle(pos) VECTOR_LINE = pygame.draw.line(screen, (255, 0, 0), VECTOR_STARTPOINT, CURRENT_ENDPOINT, 4) time += 0.05 po = ball_path() X_POSITION = po[0] Y_POSITION = po[1] else: time = 0 Y_POSITION = 375 if jumping: Y_POSITION -= Y_VELOCITY Y_VELOCITY -= Y_GRAVITY if Y_VELOCITY < -JUMP_HEIGHT: jumping = False Y_VELOCITY = JUMP_HEIGHT ball_rect = ball.get_rect(center = (X_POSITION, Y_POSITION)) screen.blit(ball, ball_rect) else: ball_rect = ball.get_rect(center = (X_POSITION, Y_POSITION)) screen.blit(ball, ball_rect) pygame.display.flip() clock.tick(FPS)
核心问题梳理
- 角度计算完全失效:
find_angle函数未实际计算向量夹角,仅返回固定值,导致投射方向完全错误。 - 三角函数单位不匹配:
math.cos/math.sin需要弧度值,但ANGLE是角度值,未做转换,方向计算彻底错误。 - 抛体运动仅触发一次:仅在松开"w"键瞬间更新一次位置,未在每一帧持续计算轨迹,球无法呈现连续抛物线运动。
- 重力公式逻辑混乱:未适配Pygame坐标系(Y轴向下为正),竖直方向运动不符合物理规律。
- 变量作用域错误:局部
angle变量未关联到全局使用,ball_path函数无法获取正确角度。
修正方案及代码
import pygame import math BLACK = (0, 0, 0) WHITE = (255, 255, 255) FPS = 60 clock = pygame.time.Clock() screen_x = 900 screen_y = 500 screen = pygame.display.set_mode((screen_x, screen_y)) pygame.display.set_caption("Basketball Game") # 篮球基础状态 X_POSITION = 400 Y_POSITION = 375 ball = pygame.image.load("ball.svg.png") ball = pygame.transform.scale(ball, (80, 80)) ball_width = ball.get_width() ball_rect = ball.get_rect(center=(X_POSITION, Y_POSITION)) # 运动参数 Y_GRAVITY = 0.5 JUMP_HEIGHT = 20 VEL_BALL = 15 LENGTH_FORCE = 49 # 修正拼写错误 FORCE_MAX_LENGTH = 400 # 投射状态 ANGLE = 0 is_shooting = False shoot_time = 0.0 shoot_angle = 0.0 def ball_path(): # 计算水平/竖直初速度 vx = math.cos(shoot_angle) * JUMP_HEIGHT vy = math.sin(shoot_angle) * JUMP_HEIGHT # 适配Pygame坐标系的抛体公式 dist_x = vx * shoot_time dist_y = vy * shoot_time + 0.5 * Y_GRAVITY * (shoot_time ** 2) new_x = X_POSITION + dist_x new_y = Y_POSITION + dist_y return (round(new_x), round(new_y)) def find_angle(end_pos): # 通过向量差计算正确弧度角度 dx = end_pos[0] - X_POSITION dy = end_pos[1] - Y_POSITION return math.atan2(dy, dx) run = True while run: VECTOR_STARTPOINT = pygame.math.Vector2(X_POSITION, Y_POSITION) VECTOR_ENDPOINT = pygame.math.Vector2(100, 0) CURRENT_ENDPOINT = VECTOR_STARTPOINT + VECTOR_ENDPOINT.rotate(ANGLE) screen.fill(BLACK) # 事件处理 for event in pygame.event.get(): if event.type == pygame.QUIT: run = False # 松开w键触发投射 if event.type == pygame.KEYUP: if event.key == pygame.K_w and not is_shooting: is_shooting = True shoot_time = 0.0 shoot_angle = find_angle(CURRENT_ENDPOINT) # 重置篮球位置 if event.key == pygame.K_s: is_shooting = False X_POSITION = 400 Y_POSITION = 375 keys_pressed = pygame.key.get_pressed() # 非投射状态下的移动、力度调整 if not is_shooting: if keys_pressed[pygame.K_SPACE]: Y_POSITION -= 20 if keys_pressed[pygame.K_d] and X_POSITION < screen_x - ball_width//2: X_POSITION += VEL_BALL if keys_pressed[pygame.K_a] and X_POSITION > 0 + ball_width//2: X_POSITION -= VEL_BALL # 调整投射力度 if keys_pressed[pygame.K_r] and LENGTH_FORCE <= FORCE_MAX_LENGTH: LENGTH_FORCE += 5 if LENGTH_FORCE <= 200: JUMP_HEIGHT = 20 elif LENGTH_FORCE <= 300: JUMP_HEIGHT = 25 elif LENGTH_FORCE <= FORCE_MAX_LENGTH: JUMP_HEIGHT = 30 if LENGTH_FORCE == FORCE_MAX_LENGTH: JUMP_HEIGHT = 35 # 旋转方向向量 if keys_pressed[pygame.K_w]: ANGLE = (ANGLE + 5) % 360 # 投射状态下持续更新轨迹 if is_shooting: shoot_time += 0.1 new_pos = ball_path() X_POSITION, Y_POSITION = new_pos # 落地后停止投射 if Y_POSITION >= screen_y - ball_width//2: is_shooting = False Y_POSITION = screen_y - ball_width//2 # 绘制力度条 pygame.draw.line(screen, (255, 0, 0), (50, 50), (FORCE_MAX_LENGTH, 50), 5) pygame.draw.line(screen, WHITE, (50, 50), (LENGTH_FORCE, 50), 5) # 绘制方向向量 if not is_shooting: pygame.draw.line(screen, WHITE, VECTOR_STARTPOINT, CURRENT_ENDPOINT, 4) else: pygame.draw.line(screen, (255, 0, 0), VECTOR_STARTPOINT, CURRENT_ENDPOINT, 4) # 绘制篮球 ball_rect = ball.get_rect(center=(X_POSITION, Y_POSITION)) screen.blit(ball, ball_rect) pygame.display.flip() clock.tick(FPS)
内容的提问来源于stack exchange,提问作者Proton
相关产品推荐
相关产品推荐

