Python游戏开发:外星人入侵项目Bug修复与优化实战
1. 项目概述从“能跑”到“好用”的蜕变如果你跟着《Python编程从入门到实践》这本书敲完了外星人入侵这个项目恭喜你你已经迈出了游戏开发的第一步。但很多朋友在完成第一版后会发现游戏虽然能运行却总有些“小毛病”外星人舰队有时会卡在屏幕边缘抽搐、子弹和外星人的碰撞检测偶尔失灵、或者游戏在特定操作下会意外崩溃。这些就是所谓的“Bug”它们不影响程序的主体流程却严重破坏了游戏体验的流畅性和稳定性。今天要聊的就是如何为这个经典项目进行一次系统的“第二版Bug修复”目标是让我们的外星人入侵从一个“教学演示”升级为一个“真正能玩”的、健壮的小游戏。这个过程远比单纯跟着教程敲代码更有价值。它模拟了一个真实项目从原型开发到迭代优化的完整周期。你会接触到如何定位那些难以复现的偶发性问题如何设计更严谨的游戏逻辑以及如何通过代码重构来提升项目的可维护性。无论你是想巩固Python基础还是对游戏开发背后的逻辑感兴趣这次修复之旅都将是一次绝佳的实践。我们将聚焦于几个最常见的核心Bug并深入探讨其成因与解决方案最终让你的外星人舰队“服服帖帖”地被消灭。2. 核心Bug诊断与修复思路拆解在动手修改代码之前我们必须先像医生一样对项目进行“体检”准确诊断出病灶所在。外星人入侵项目基于Pygame库其核心循环是“事件处理 - 状态更新 - 画面绘制”。Bug往往就隐藏在这个循环的某个环节尤其是状态更新和边界条件判断中。2.1 常见Bug分类与根源分析根据社区反馈和常见问题我们可以将Bug归纳为以下几类运动逻辑Bug外星人舰队到达屏幕边缘后下移和反向移动的逻辑出现混乱可能导致舰队抖动、卡顿或移出屏幕。碰撞检测Bug子弹击中外星人后有时未能正确移除外星人或者一颗子弹同时“消灭”多个外星人这听起来是好事但源于检测不精确。资源管理Bug游戏元素如子弹、外星人的生命周期管理不当可能导致内存泄漏或意外引用在长时间游戏或频繁重新开始时引发问题。状态同步Bug游戏状态如游戏是否激活、飞船是否还有命与屏幕绘制、事件处理不同步导致画面冻结或逻辑错乱。这些Bug的根源通常在于初版代码为了突出教学重点在健壮性上做了简化。例如外星人的移动可能只在主循环中简单判断没有考虑帧率波动带来的误差碰撞检测可能使用了过于宽松的矩形检测没有处理“一帧内穿过”的情况。2.2 修复策略从“打补丁”到“优化设计”我们的修复策略不应该是在原有代码上到处if...else“打补丁”而应该追求更优雅的设计增强边界检测的鲁棒性不仅检查外星人个体是否碰壁更要基于整个舰队的移动意图进行判断。引入更精确的碰撞检测虽然Pygame的rect.colliderect是基础但我们可以通过优化发射逻辑和检测时机来提升体验。明确游戏对象生命周期清晰地定义子弹何时创建、何时销毁外星人何时被移除并确保相关资源被释放。重构游戏状态机将游戏运行、暂停、结束等状态抽象出来用明确的状态变量控制避免逻辑交织。接下来我们将深入代码层面看看如何具体实施这些策略。3. 核心Bug修复详解与代码实操我们假设你的项目结构已经建立拥有alien_invasion.py主文件、ship.py、bullet.py、alien.py、game_stats.py等模块。修复将围绕这些文件展开。3.1 修复外星人舰队运动异常这是最经典的Bug。初版代码中检查舰队是否到达屏幕边缘的逻辑通常放在更新每个外星人位置之后并且是遍历所有外星人找到一个最靠边的。这里有两个潜在问题问题一舰队抖动或移动迟缓。有时你会发现舰队触边后下移的速度很慢或者有轻微的左右抖动。这通常是因为边界判断的“容错”没做好。外星人的移动速度alien.x是浮点数而屏幕坐标是整数判断alien.rect.right screen_rect.right时可能因为浮点数精度问题在边界附近反复横跳。修复方案使用更宽容的边界判断并基于舰队方向决策。我们修改alien_invasion.py中更新外星人的部分或者更好的做法是在Alien类或管理外星人群的模块中增加一个专门的方法来检查是否需要改变方向。# 在 alien_invasion.py 的更新外星人部分或者在一个新的 Fleet 类中 def _check_fleet_edges(self): 检查是否有外星人到达了屏幕边缘并据此决定整个舰队的行动 for alien in self.aliens.sprites(): # 使用更宽松的判断避免浮点精度导致的抖动 if alien.check_edges(): self._change_fleet_direction() break # 只要有一个外星人触边整个舰队就改变方向 def _change_fleet_direction(self): 将整个舰队下移并改变其水平移动方向 for alien in self.aliens.sprites(): alien.rect.y self.fleet_drop_speed self.fleet_direction * -1 # 改变方向标志同时在alien.py中完善check_edges方法def check_edges(self): 如果外星人位于屏幕边缘就返回True screen_rect self.screen.get_rect() # 判断右边缘时用 (screen_rect.right - 10) 提供一个小的缓冲区间 # 判断左边缘时用 (screen_rect.left 10) if self.rect.right (screen_rect.right - 10): return True elif self.rect.left (screen_rect.left 10): return True return False注意这里的缓冲值10像素是个经验值你可以根据外星人的大小和移动速度调整。它的目的是在视觉上外星人“碰到”屏幕边缘之前就触发舰队转向避免图像贴边。问题二舰队最下方外星人触底后游戏未结束。初版逻辑可能只检查了外星人与飞船的碰撞但按照经典玩法任何外星人触底都意味着游戏失败。修复方案在更新外星人位置后增加触底检测。# 在 alien_invasion.py 的 _update_aliens 方法中 def _update_aliens(self): 更新外星人群中所有外星人的位置并检查碰撞 self._check_fleet_edges() self.aliens.update() # 检查是否有外星人到达了屏幕底端 if self._check_aliens_bottom(): self._ship_hit() # 像处理飞船被撞一样处理触底 return # ... 原有的飞船与外星人碰撞检测代码 ... def _check_aliens_bottom(self): 检查是否有外星人到达了屏幕底端 screen_rect self.screen.get_rect() for alien in self.aliens.sprites(): # 当外星人的底端 屏幕底端时认为到达底部 if alien.rect.bottom screen_rect.bottom: return True return False3.2 修复子弹碰撞检测不精确碰撞检测不准确通常表现为两种现象1. 子弹明明穿过了外星人但外星人没事2. 一颗子弹同时消灭了一整列外星人。根源分析Pygame的sprite.groupcollide()方法在默认情况下当两个精灵组的精灵发生矩形碰撞时会从各自组中删除发生碰撞的精灵。如果一颗子弹在一帧内其矩形与多个外星人的矩形重叠它就会“同时”消灭所有这些外星人。此外如果子弹速度过快可能在一帧内就从外星人的“前面”移动到了“后面”错过了碰撞检测的时机。修复方案一优化子弹速度与碰撞检测顺序。确保子弹的移动速度bullet_speed_factor不要设置得过高通常不超过屏幕高度的1/10。在主循环中确保先更新子弹位置再进行碰撞检测。修复方案二使用更精细的碰撞检测可选针对高速子弹。对于高速子弹可以使用pygame.sprite.spritecollide()并设置collided参数为一个更精确的回调函数或者使用pygame.Rect.colliderect并手动处理。但为了简单和性能调整速度通常是首选。修复方案三确保碰撞后正确移除精灵。这是最关键的。检查你的_update_bullets方法def _update_bullets(self): 更新子弹位置并删除已消失的子弹检查碰撞 # 更新子弹位置 self.bullets.update() # 删除已飞出屏幕顶端的子弹 for bullet in self.bullets.copy(): if bullet.rect.bottom 0: self.bullets.remove(bullet) # 检查是否有子弹击中了外星人 # 使用 pygame.sprite.groupcollide并设置两个 True 参数以删除发生碰撞的子弹和外星人 collisions pygame.sprite.groupcollide( self.bullets, self.aliens, True, True ) # 如果外星人群被清空了就创建一群新的外星人进入下一关 if not self.aliens: self.bullets.empty() self._create_fleet()实操心得pygame.sprite.groupcollide(self.bullets, self.aliens, True, True)这里的两个True至关重要。第一个True表示碰撞后从bullets组中删除子弹第二个True表示从aliens组中删除外星人。务必确认你的代码中这两个参数是正确的。我曾经因为这里写成了False, True导致子弹无限存在很快内存就爆了。3.3 修复游戏状态管理与资源泄漏一个常见的体验Bug是游戏结束后飞船生命用尽点击关闭按钮没有反应或者重新开始游戏后画面残留着上一局的外星人或子弹。问题根源游戏状态是否活跃没有与事件循环和绘制循环完全同步。此外精灵组pygame.sprite.Group在清空empty()或重新赋值时如果旧的精灵没有被正确释放可能会造成引用残留。修复方案建立清晰的状态机并规范资源重置。首先在game_stats.py中明确游戏状态class GameStats: 跟踪游戏统计信息 def __init__(self, ai_settings): self.ai_settings ai_settings self.reset_stats() # 游戏启动时处于非活动状态等待玩家点击开始 self.game_active False self.game_paused False # 可以增加暂停状态 def reset_stats(self): 初始化在游戏运行期间可能变化的统计信息 self.ships_left self.ai_settings.ship_limit self.score 0 self.level 1然后在主文件alien_invasion.py中严格根据game_active状态来控制游戏逻辑def run_game(self): 开始游戏主循环 while True: self._check_events() # 始终检查事件如退出、开始、暂停 if self.stats.game_active and not self.stats.game_paused: self.ship.update() self._update_bullets() self._update_aliens() self._update_screen() # 始终更新屏幕但绘制内容由状态决定 def _check_events(self): for event in pygame.event.get(): if event.type pygame.QUIT: sys.exit() elif event.type pygame.KEYDOWN: self._check_keydown_events(event) elif event.type pygame.KEYUP: self._check_keyup_events(event) # 可以增加鼠标事件来处理游戏开始 elif event.type pygame.MOUSEBUTTONDOWN: mouse_pos pygame.mouse.get_pos() self._check_play_button(mouse_pos) def _check_play_button(self, mouse_pos): 在玩家单击Play按钮时开始新游戏 # 假设你有一个 play_button 的矩形 if self.play_button.rect.collidepoint(mouse_pos) and not self.stats.game_active: # 重置游戏设置和统计信息 self.ai_settings.initialize_dynamic_settings() self.stats.reset_stats() self.stats.game_active True # 清空外星人列表和子弹列表 self.aliens.empty() self.bullets.empty() # 创建一群新的外星人并将飞船居中 self._create_fleet() self.ship.center_ship() # 隐藏鼠标光标 pygame.mouse.set_visible(False)在游戏结束飞船生命为0时除了设置game_active False还要记得让鼠标光标重新可见。关于资源重置在重新开始游戏时务必使用.empty()方法清空精灵组而不是直接创建一个新组除非旧组已无引用。.empty()会移除组内所有精灵有助于Python垃圾回收器清理内存。4. 进阶优化与体验提升修复了主要Bug后我们可以进一步优化游戏体验这能让你的项目从“及格”走向“优秀”。4.1 增加游戏难度渐进与关卡系统初版游戏可能只有一波外星人。我们可以实现一个简单的关卡系统每当清空一波外星人就提升游戏难度如加快外星人移动速度、子弹速度并生成新的一波。在alien_invasion.py中def _update_bullets(self): # ... 之前的碰撞检测代码 ... # 如果外星人群被清空了 if not self.aliens: # 删除现有的所有子弹防止残留 self.bullets.empty() # 创建一群新的外星人下一关 self._create_fleet() # 提升游戏速度增加难度 self.ai_settings.increase_speed() # 提升等级 self.stats.level 1在settings.py中增加increase_speed方法def increase_speed(self): 提高游戏速度设置和外星人点数 self.ship_speed_factor * self.speedup_scale self.bullet_speed_factor * self.speedup_scale self.alien_speed_factor * self.speedup_scale self.alien_points int(self.alien_points * self.score_scale) # 每关得分也增加4.2 实现游戏暂停功能暂停是一个非常有用的功能它涉及到游戏状态的管理。我们之前已经在GameStats中增加了game_paused状态。在_check_keydown_events方法中增加暂停快捷键例如按p键def _check_keydown_events(self, event): # ... 其他按键处理 ... elif event.key pygame.K_p: # 切换暂停状态 self.stats.game_paused not self.stats.game_paused在_update_screen方法中可以根据game_paused状态在屏幕上绘制“Paused”文字提示。4.3 优化视觉效果与反馈击中反馈当子弹击中外星人时可以播放一个简短的声音效果使用pygame.mixer.Sound或在击中位置显示一个小型爆炸动画使用精灵图序列。生命值显示在屏幕角落绘制剩余飞船图标直观显示生命数。平滑移动确保飞船的移动是持续的而不是每帧跳跃。这通常已经在ship.update()中通过持续检查按键状态实现了。5. 调试技巧与常见问题排查实录即使按照上述步骤修复在整合过程中你仍可能遇到新问题。这里分享一些实用的调试技巧和常见坑位。5.1 Pygame调试常用手段打印大法好在怀疑的函数里打印关键变量如alien.rect.x,fleet_direction,game_active。这是最直接有效的。绘制调试图形使用pygame.draw.rect(screen, (255,0,0), some_rect, 1)在屏幕上临时绘制精灵的边界框直观查看碰撞矩形是否如你所想。控制帧率在游戏主循环中使用clock.tick(60)来稳定帧率。帧率波动有时会放大逻辑问题。使用断言在代码关键位置加入assert语句例如assert self.fleet_direction in (1, -1)确保变量值在合理范围内。5.2 常见问题速查表问题现象可能原因排查步骤与解决方案游戏窗口无响应或无法关闭主循环while True内没有正确处理pygame.QUIT事件或存在死循环。检查_check_events()函数是否被正确调用并确保sys.exit()能被执行。子弹发射后消失太快或太慢bullet_speed_factor设置不合理或子弹更新逻辑有误。检查bullet.py中update()方法是否正确使rect.y递减向上飞。调整settings.py中的速度值。重新开始游戏后画面有残留精灵组没有在游戏重置时清空或屏幕没有用背景色重绘。在开始新游戏的函数中确认调用了self.aliens.empty()和self.bullets.empty()。确保_update_screen()中每次都用self.bg_color填充整个屏幕。外星人舰队不移动或移动方向错误fleet_direction初始化错误或在_change_fleet_direction中没有正确取反。检查fleet_direction的初始值应为1或-1。在_change_fleet_direction中打印其值确认逻辑正确。碰撞检测后子弹和外星人有时不消失pygame.sprite.groupcollide()的参数dokilla,dokillb没有都设为True。确认调用为groupcollide(bullets, aliens, True, True)。游戏结束后键盘还能控制飞船游戏状态game_active为False后飞船的update()方法仍被调用。在主循环中将self.ship.update()放在if self.stats.game_active:条件判断内部。5.3 版本控制与代码回滚在进行此类系统性修复时强烈建议使用Git等版本控制工具。在每次进行一个明确的修改如“修复舰队抖动”前后进行一次提交。这样当你的修改引入了新的、更严重的Bug时可以轻松地回退到上一个可工作的状态而不是在混乱的代码中挣扎。如果你还没有使用Git至少手动备份一份修复前的原始代码。这是专业开发者的基本习惯能为你节省大量时间。完成这一系列的修复和优化后你的外星人入侵项目将脱胎换骨。它不再是一个脆弱的课堂练习而是一个代码结构更清晰、逻辑更严谨、体验更流畅的完整小游戏项目。这个过程带给你的不仅仅是几行代码的修改更是对程序健壮性、状态管理和调试思维的实战训练。当你再次运行游戏看到舰队整齐划一地移动、子弹精准地消灭目标、游戏流畅地重启时那种成就感远非第一次运行通功能时可比。

相关新闻

StartupOS依赖注入:Dagger框架在Java项目中的简单应用教程

StartupOS依赖注入:Dagger框架在Java项目中的简单应用教程

StartupOS依赖注入:Dagger框架在Java项目中的简单应用教程 【免费下载链接】startup-os Working examples of Googles Open Source stack and deployment to the cloud. 项目地址: https://gitcode.com/gh_mirrors/st/startup-os StartupOS是Google开源技术栈…

2026/10/12 22:22:01 阅读更多 →
Audiveris终极指南:如何用开源OMR工具快速识别乐谱图像

Audiveris终极指南:如何用开源OMR工具快速识别乐谱图像

Audiveris终极指南:如何用开源OMR工具快速识别乐谱图像 【免费下载链接】audiveris Latest generation of Audiveris OMR engine 项目地址: https://gitcode.com/gh_mirrors/au/audiveris Audiveris是一款强大的开源光学音乐识别(OMR)…

2026/10/13 10:49:14 阅读更多 →
如何在3分钟内快速绕过Steam DRM实现游戏独立运行?

如何在3分钟内快速绕过Steam DRM实现游戏独立运行?

如何在3分钟内快速绕过Steam DRM实现游戏独立运行? 【免费下载链接】Steam-auto-crack Steam Game Automatic Cracker 项目地址: https://gitcode.com/gh_mirrors/st/Steam-auto-crack 你是否曾经遇到过这样的困扰:明明已经购买了正版Steam游戏&a…

2026/10/11 9:32:01 阅读更多 →

最新新闻

搞懂MyBatis与Spring Boot整合:两大核心类自动装配原理与排错

搞懂MyBatis与Spring Boot整合:两大核心类自动装配原理与排错

搞懂 MyBatis 和 Spring Boot 的整合原理,其实只要抓住两个类:MybatisAutoConfiguration和AutoConfiguredMapperScannerRegistrar。我们常用 Spring Boot 的人都知道,加一个mybatis-spring-boot-starter就能自动装配 SqlSessionFactory、Mapp…

2026/10/15 19:17:12 阅读更多 →
Vue项目中Tinymce自定义本地视频上传完整指南

Vue项目中Tinymce自定义本地视频上传完整指南

说到富文本编辑器,Vue项目里在地选择Tinymce的人真不少,我也是被它的扩展性吸引的。但前阵子做某知识库后台,客户要求用户能直接从本地选择视频传到编辑器里,并且要在文章里正常播放。原以为Tinymce自带的媒体插件能搞定&#xff…

2026/10/15 19:17:12 阅读更多 →
Attention-transfer:轻量化模型注意力迁移实战指南

Attention-transfer:轻量化模型注意力迁移实战指南

1. 项目概述:为什么“Attention-transfer”成了轻量化网络学习里绕不开的关键词最近在几个高校实验室和工业界模型压缩团队的交流中,反复听到一个词——“Attention-transfer”。它不像知识蒸馏(Knowledge Distillation)那样被写进…

2026/10/15 19:17:12 阅读更多 →
MySQL 基础 + AI SQL 优化

MySQL 基础 + AI SQL 优化

楠风测开 测试工程师复习日记 Day15 用一套订单、支付和库存样例,把查询、关联、金额核对与事务验证串起来。 前言:SQL跑通之后,还差一次结果验收 朋友们好,我是楠风。 上一阶段聊完Linux监控,我们开始补上测试工程…

2026/10/15 19:17:12 阅读更多 →
回文链表高效判断:快慢指针与反转链表实现O(1)空间解法

回文链表高效判断:快慢指针与反转链表实现O(1)空间解法

1. 题目与核心思路拆解1.1 回文链表到底在考什么回文链表这道题,在主流刷题平台的 Hot 100 榜单里长期占据前排位置。我第一次刷的时候,觉得很简单,链表的节点值放进数组,左右双指针一比对,不就完事了吗?后…

2026/10/15 19:17:12 阅读更多 →
冒险岛WZ格式解析与自定义加密实战指南

冒险岛WZ格式解析与自定义加密实战指南

简介:这是一款面向《冒险岛》游戏开发者、MOD制作者及资深玩家的WZ资源编辑与加密工具集,专为破解、定制和重打包游戏核心资源(如图像、音效、脚本、技能配置)提供完整支持。资源包共34个文件,含17个DLL动态库&#xf…

2026/10/15 19:16:09 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →