ARTICLE · 1060210
节日源码:pygame版嫦娥奔月动画
节日源码:pygame版嫦娥奔月动画

两阶段:预生成贴图(背景/光晕/云/星)→ 主循环拼接 柔光贴图:从外到内画同心圆,透明度递增,得到径向渐变。 嫦娥绘制:几何分层,从后往前 柔光 → 飘带 → 裙摆 → 上身 → 腰带 → 手臂 → 水袖 → 脖子 → 后发 → 脸 → 发髻 → 眼睛 所有坐标经 P(x,y) = (cx + x*scale, cy + y*scale),改 scale 整体缩放。 飘动感:飘带和裙摆的每个点加 sin(t*频率 + 位置) 偏移。 飞行路径:二次贝塞尔 飞远效果:scale = lerp(1.15, 0.62, progress) —— 越飞越小。 跟随粒子:用 while 补足粒子,SPARK.set_alpha() 复用同一张贴图淡出。 云:预生成一张低透明度椭圆叠加图,横向平移,出界回绕。 


Python,速成心法
敲代码,查资料,问度娘
练习,探索,总结,优化

★★★★★博文创作不易,使用代码的过程中,如有疑问的地方,欢迎大家指正留言交流。喜欢的老铁可以多多点赞+收藏分享+置顶,小红牛在此表示感谢。★★★★★
-------★Pygame经典游戏★-------
pygame 版嫦娥奔月动画:嫦娥用几何图形分层绘制:飘带、裙摆(正弦摆动)、水袖、发髻、发簪,整体沿贝塞尔曲线从画面外飞向月亮,并伴随金色粒子。
B(t) = (1-t)²P0 + 2(1-t)t·P1 + t²P2P0 起点(画面外),P1 控制点(决定弧度),P2 终点(月亮旁)

↓ 源码如下 ↓
# -*- coding: utf-8 -*-# @Author : 小红牛# 微信公众号:wdPythonimport pygameimport mathimport randomimport syspygame.init()W, H = 960, 640screen = pygame.display.set_mode((W, H))pygame.display.set_caption("嫦娥奔月 · 中秋")clock = pygame.time.Clock()TAU = math.taudef lerp(a, b, t):return a + (b - a) * tdef get_font(size, bold=False):for name in ("microsoftyahei", "simhei", "pingfangsc", "hiraginosansgb","notosanscjksc", "wenquanyimicrohei", "arialunicodems"):path = pygame.font.match_font(name, bold=bold)if path:return pygame.font.Font(path, size)return pygame.font.SysFont(None, size)FONT_TITLE = get_font(36, bold=True)FONT_TIP = get_font(18)# ───────── 资源预生成 ─────────def make_gradient(w, h, top, bottom):surf = pygame.Surface((w, h))for y in range(h):f = y / max(1, h - 1)col = tuple(int(lerp(top[i], bottom[i], f)) for i in range(3))pygame.draw.line(surf, col, (0, y), (w, y))return surfdef make_glow(radius, color, strength=120, power=2.2):"""径向柔光"""size = radius * 2surf = pygame.Surface((size, size), pygame.SRCALPHA)for r in range(radius, 0, -1):f = 1 - r / radiusa = int(strength * (f ** power))pygame.draw.circle(surf, (*color, a), (radius, radius), r)return surfdef make_spark(size=28, color=(255, 240, 200)):"""粒子光点"""surf = pygame.Surface((size, size), pygame.SRCALPHA)c = size // 2for r in range(c, 0, -1):a = int(255 * (1 - r / c) ** 2)pygame.draw.circle(surf, (*color, a), (c, c), r)return surfdef make_cloud(w, h, tint=(180, 195, 235)):surf = pygame.Surface((w, h), pygame.SRCALPHA)for _ in range(24):cx = random.uniform(w * 0.15, w * 0.85)cy = random.uniform(h * 0.3, h * 0.7)rx = random.uniform(w * 0.10, w * 0.24)ry = random.uniform(h * 0.20, h * 0.40)pygame.draw.ellipse(surf, (*tint, random.randint(6, 16)),(cx - rx, cy - ry, rx * 2, ry * 2))return surfBG = make_gradient(W, H, (8, 10, 34), (34, 16, 54))MOON_X, MOON_Y, MOON_R = W - 260, 200, 84MOON_GLOW = make_glow(MOON_R * 3, (255, 240, 190), 120, 2.0)HALO = make_glow(140, (170, 200, 255), 70, 2.4)SPARK = make_spark(28)stars = [{"x": random.uniform(0, W),"y": random.uniform(0, H),"r": random.choice((1, 1, 1, 2, 2, 2, 3)),"phase": random.uniform(0, TAU),"speed": random.uniform(0.6, 2.2),} for _ in range(170)]clouds = [{"surf": make_cloud(460, 170), "x": -80.0, "y": 430.0, "v": 14.0},{"surf": make_cloud(360, 140), "x": 560.0, "y": 520.0, "v": -10.0},{"surf": make_cloud(320, 130), "x": 250.0, "y": 330.0, "v": 20.0},]CH = 480 # 嫦娥绘制画布尺寸change_layer = pygame.Surface((CH, CH), pygame.SRCALPHA)# ───────── 嫦娥绘制 ─────────def draw_change(layer, t, scale):"""在 layer 中心绘制嫦娥,scale 为整体缩放"""cx = cy = CH / 2def P(x, y):return (cx + x * scale, cy + y * scale)def Pi(x, y):px, py = P(x, y)return (int(px), int(py))skin = (255, 227, 203)hair = (34, 28, 48)robe = (238, 244, 255)belt = (152, 182, 238)# 背后柔光layer.blit(HALO, (int(cx - HALO.get_width() / 2),int(cy - 10 - HALO.get_height() / 2)))# ── 飘带(两侧长丝带,正弦摆动)──for side in (-1, 1):def ribbon(offset):pts = []for i in range(28):f = i / 27x = side * 168 * fy = (-12 + 48 * f+ math.sin(t * 2.1 + f * 5.5 + side * 1.6) * 26 * f+ offset)pts.append(Pi(x, y))return ptsup, dn = ribbon(-7), ribbon(7)pygame.draw.polygon(layer, (206, 226, 255, 160), up + dn[::-1])pygame.draw.lines(layer, (255, 255, 255, 190), False, ribbon(0),max(1, int(1.5 * scale)))# ── 裙摆(底部正弦飘动)──N = 22left, right = [], []for i in range(N):f = i / (N - 1)y = 6 + 86 * fhw = 12 + 44 * (f ** 1.35)wob = math.sin(t * 3.0 - f * 4.2) * 12 * fleft.append(Pi(-hw + wob * 0.7, y))right.append(Pi(hw + wob, y))pygame.draw.polygon(layer, (230, 239, 255), left + right[::-1])pygame.draw.lines(layer, (255, 255, 255), False, left, max(1, int(1.3 * scale)))pygame.draw.lines(layer, (255, 255, 255), False, right, max(1, int(1.3 * scale)))# ── 上身 ──pygame.draw.polygon(layer, robe, [Pi(-11, 8), Pi(-14, -30), Pi(-9, -48),Pi(9, -48), Pi(14, -30), Pi(11, 8)])# 腰带pygame.draw.polygon(layer, belt, [Pi(-12, 2), Pi(12, 2), Pi(10, 11), Pi(-10, 11)])# ── 手臂(上扬姿态)──aw = max(2, int(4 * scale))pygame.draw.line(layer, skin, Pi(-12, -42), Pi(-34, -70), aw)pygame.draw.line(layer, skin, Pi(-34, -70), Pi(-48, -98), max(2, aw - 1))pygame.draw.line(layer, skin, Pi(12, -44), Pi(32, -74), aw)pygame.draw.line(layer, skin, Pi(32, -74), Pi(46, -104), max(2, aw - 1))# 水袖pygame.draw.polygon(layer, (215, 232, 255),[Pi(-48, -98), Pi(-62, -112), Pi(-52, -84)])pygame.draw.polygon(layer, (215, 232, 255),[Pi(46, -104), Pi(62, -118), Pi(50, -90)])# ── 脖子 ──pygame.draw.line(layer, skin, Pi(0, -46), Pi(0, -56), max(2, int(5 * scale)))# ── 后发 ──pygame.draw.circle(layer, hair, Pi(0, -72), max(2, int(16 * scale)))pygame.draw.line(layer, hair, Pi(-13, -66), Pi(-18, -40), max(2, int(5 * scale)))pygame.draw.line(layer, hair, Pi(13, -66), Pi(18, -40), max(2, int(5 * scale)))# ── 脸 ──pygame.draw.circle(layer, skin, Pi(0, -70), max(2, int(13 * scale)))# ── 发髻 + 发簪 ──pygame.draw.circle(layer, hair, Pi(0, -87), max(2, int(8 * scale)))pygame.draw.circle(layer, hair, Pi(-9, -83), max(2, int(5 * scale)))pygame.draw.circle(layer, hair, Pi(9, -83), max(2, int(5 * scale)))pygame.draw.circle(layer, (255, 216, 120), Pi(11, -89), max(1, int(3 * scale)))# ── 眼睛 ──if scale > 0.55:pygame.draw.circle(layer, (58, 44, 62), Pi(-5, -70), max(1, int(1.6 * scale)))pygame.draw.circle(layer, (58, 44, 62), Pi(5, -70), max(1, int(1.6 * scale)))# ───────── 主循环 ─────────def main():progress = 0.0elapsed = 0.0spark_timer = 0.0particles = []running = Truep0 = (-180.0, H + 150.0) # 起点(画面外左下)p1 = (W * 0.20, H * 0.70) # 控制点p2 = (MOON_X - 150.0, MOON_Y + 90.0) # 终点(月亮左下)while running:dt = min(clock.tick(60) / 1000.0, 0.05)elapsed += dtfor event in pygame.event.get():if event.type == pygame.QUIT:running = Falseelif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:running = False# 背景screen.blit(BG, (0, 0))# 星星闪烁for s in stars:b = 0.5 + 0.5 * math.sin(elapsed * s["speed"] + s["phase"])v = int(120 + 135 * b)pygame.draw.circle(screen, (v, v, min(255, v + 25)),(int(s["x"]), int(s["y"])), s["r"])# 月亮 + 光晕 + 环形山screen.blit(MOON_GLOW, (MOON_X - MOON_GLOW.get_width() // 2,MOON_Y - MOON_GLOW.get_height() // 2))pygame.draw.circle(screen, (255, 249, 222), (MOON_X, MOON_Y), MOON_R)for dx, dy, r in ((-26, -20, 13), (20, -32, 9), (10, 24, 16),(-34, 26, 8), (40, 10, 6)):pygame.draw.circle(screen, (240, 232, 198), (MOON_X + dx, MOON_Y + dy), r)# 云for c in clouds:c["x"] += c["v"] * dtcw = c["surf"].get_width()if c["v"] > 0 and c["x"] > W:c["x"] = -cwelif c["v"] < 0 and c["x"] + cw < 0:c["x"] = Wscreen.blit(c["surf"], (int(c["x"]), int(c["y"])))# 嫦娥位置:二次贝塞尔插值progress += dt * 0.12if progress > 1.0:progress = 0.0u = 1 - progresscxp = u * u * p0[0] + 2 * u * progress * p1[0] + progress * progress * p2[0]cyp = u * u * p0[1] + 2 * u * progress * p1[1] + progress * progress * p2[1]scale = lerp(1.15, 0.62, progress)change_layer.fill((0, 0, 0, 0))draw_change(change_layer, elapsed, scale)screen.blit(change_layer, (int(cxp - CH / 2), int(cyp - CH / 2)))# 跟随的金色粒子spark_timer += dtwhile spark_timer > 0.03:spark_timer -= 0.03particles.append({"x": cxp + random.uniform(-40, 40),"y": cyp + random.uniform(-40, 40),"vx": random.uniform(-25, 25),"vy": random.uniform(-55, -15),"age": 0.0,"life": random.uniform(0.7, 1.6),})alive = []for p in particles:p["age"] += dtif p["age"] >= p["life"]:continuep["x"] += p["vx"] * dtp["y"] += p["vy"] * dtp["vy"] += 10 * dta = 1 - p["age"] / p["life"]SPARK.set_alpha(int(210 * a))screen.blit(SPARK, (int(p["x"] - 14), int(p["y"] - 14)))alive.append(p)particles = alive# 文字title = FONT_TITLE.render("嫦 娥 奔 月", True, (255, 240, 205))screen.blit(title, (52, 42))tip = FONT_TIP.render("但愿人长久,千里共婵娟 ESC 退出",True, (160, 172, 214))screen.blit(tip, (54, 96))pygame.display.flip()pygame.quit()sys.exit()if __name__ == "__main__":main()
完毕!!感谢您的收看
--------★★历史博文集合★★--------