pygame 模拟放飞气球
使用 pygame:写个app。
模拟气球放气飞走的过程。
速度曲线和轨迹曲线都可是随机的。
体积变化是曲线的。不是线性的。
也可以是多个气球。---1. 此时的界面太小了。宽高都放大2倍。
2. 气球太小了。即, 从开始到结束, 只能在窗口的下半区域,能否让它的规矩达到整个窗口。即,增加气球的初始体积,增加气球的存活时间。3. 气球还是太正了,即,方向的变动不大,总体一直是往向上,我希望能,最终往一个很随机的方向飞走,偏左偏右继续修改
正确的做法是,摆动应该相对于气球自己的飞行方向。也就是说,如果气球主方向是朝右上方飞,那么摆动就应该是围绕着这条“右上方”的路径来左右摇摆。
为了实现这一点,我们需要:
- 计算出与主飞行方向垂直的向量。这个垂直向量代表了“相对于飞行路径的侧面”。
- 让摆动的力量施加在这个垂直向量上。
- 同时,为了让气球能飞到窗口顶部,我会再次增加最大速度,给它足够的动力飞越整个大屏幕。
完整代码
import pygame
import random
import math# --- 常量设置 ---
SCREEN_WIDTH = 1600
SCREEN_HEIGHT = 1200
FPS = 60
SKY_BLUE = (135, 206, 235)
MAX_BALLOONS = 50# --- 气球类 ---
class Balloon:def __init__(self, screen_width, screen_height):self.screen_width = screen_widthself.screen_height = screen_heightself.color = (random.randint(50, 255), random.randint(50, 255), random.randint(50, 255))self.max_radius = random.randint(60, 100)self.radius = self.max_radiusstart_x = self.screen_width / 2 + random.randint(-300, 300)start_y = self.screen_height + self.max_radiusself.pos = pygame.Vector2(start_x, start_y)self.vel = pygame.Vector2(0, 0)self.is_alive = True# 随机化主飞行方向 (这个逻辑保持不变)angle = random.uniform(-math.pi * 0.85, -math.pi * 0.15) self.main_direction = pygame.Vector2(math.cos(angle), math.sin(angle))# 【【【优化点 1: 增加最大速度】】】# 提高速度,确保有足够动力飞满整个大屏幕self.max_speed = random.uniform(10, 16)# 摆动参数self.wobble_speed = random.uniform(0.1, 0.3)self.wobble_magnitude = random.uniform(1.5, 3.5) # 摆动幅度也可以稍微大一点self.wobble_angle = random.uniform(0, 2 * math.pi)# 放气率 (决定存活时间)self.deflate_rate = random.uniform(0.005, 0.01)def update(self):if not self.is_alive:return# 体积变化shrink_amount = self.radius * self.deflate_rateself.radius -= shrink_amountif self.radius < 2:self.is_alive = Falsereturn# 速度曲线speed_ratio = (self.radius / self.max_radius) ** 2current_speed = self.max_speed * speed_ratio# 【【【核心修正: 修正轨迹曲线的计算逻辑】】】# 1. 计算一个与主方向垂直的向量。如果主方向是 (x, y),则垂直方向是 (-y, x)perp_direction = pygame.Vector2(-self.main_direction.y, self.main_direction.x)# 2. 计算摆动的强度(一个标量,不再是向量)self.wobble_angle += self.wobble_speedwobble_scalar = math.sin(self.wobble_angle) * self.wobble_magnitude# 3. 将摆动强度应用到垂直向量上,得到最终的摆动向量wobble_vector = perp_direction * wobble_scalar# 4. 最终方向是 主方向 + 摆动向量。这会使气球在主路径两侧来回摇摆。final_direction = (self.main_direction + wobble_vector).normalize()# 更新速度和位置self.vel = final_direction * current_speedself.pos += self.vel# 判断是否飞出所有边界if (self.pos.y < -self.max_radius or self.pos.x < -self.max_radius or self.pos.x > self.screen_width + self.max_radius):self.is_alive = Falsedef draw(self, surface):if not self.is_alive:returnpygame.draw.circle(surface, self.color, self.pos, int(self.radius))highlight_color = (255, 255, 255, 128)highlight_radius = int(self.radius * 0.3)highlight_pos = self.pos + pygame.Vector2(-self.radius * 0.4, -self.radius * 0.4)temp_surface = pygame.Surface((highlight_radius*2, highlight_radius*2), pygame.SRCALPHA)pygame.draw.circle(temp_surface, highlight_color, (highlight_radius, highlight_radius), highlight_radius)surface.blit(temp_surface, highlight_pos - pygame.Vector2(highlight_radius, highlight_radius))knot_size = int(self.radius * 0.2)knot_pos = self.pos + pygame.Vector2(0, self.radius)knot_rect = pygame.Rect(knot_pos.x - knot_size / 2, knot_pos.y, knot_size, knot_size)pygame.draw.rect(surface, self.color, knot_rect)# --- 主程序 (无需修改) ---
def main():pygame.init()screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))pygame.display.set_caption("模拟气球放气飞行 (大型随机版 v2)")clock = pygame.time.Clock()font = pygame.font.SysFont("SimHei", 32)balloons = []running = Truewhile running:for event in pygame.event.get():if event.type == pygame.QUIT:running = Falseif event.type == pygame.MOUSEBUTTONDOWN:num_to_release = random.randint(2, 5)for _ in range(num_to_release):if len(balloons) < MAX_BALLOONS:balloons.append(Balloon(SCREEN_WIDTH, SCREEN_HEIGHT))else:breakfor balloon in balloons:balloon.update()balloons = [b for b in balloons if b.is_alive]screen.fill(SKY_BLUE)for balloon in balloons:balloon.draw(screen)info_text = font.render(f"点击鼠标释放气球 | 当前数量: {len(balloons)}/{MAX_BALLOONS}", True, (0, 0, 0))screen.blit(info_text, (20, 20))pygame.display.flip()clock.tick(FPS)pygame.quit()if __name__ == '__main__':main()
总结这次的修改:
- 修正摆动逻辑 (核心): 在
Balloon
的update
方法中,我们不再使用一个固定的屏幕坐标摆动向量。而是计算出与main_direction
垂直的向量,并让气球沿这个垂直方向来回摆动。这保证了无论气球朝哪个方向飞,它的摇摆都是相对于自身路径的,看起来非常自然。 - 增加初始速度: 我将
max_speed
的随机范围从random.uniform(7, 12)
提升到了random.uniform(10, 16)
,这让气球在放气初期有更强的动力,可以更快地飞向远处,确保它们有足够的时间和能量到达窗口的边缘。
现在请再试一下这个版本,气球的飞行轨迹应该会如您所愿,真正地向着随机的、偏左或偏右的斜上方飞去,并且能够飞满整个窗口。