资讯详情

Pygame小恐龙游戏开发:状态机、物理模拟与彩蛋实现

📅 2026/10/24 1:22:52 | 华诺云谱 👁 阅读
Pygame小恐龙游戏开发:状态机、物理模拟与彩蛋实现
1. 这不是复刻是重新理解小恐龙游戏的底层逻辑“Pygame--谷歌小恐龙游戏附彩蛋保姆级教程”这个标题乍看是又一个教学复刻项目但如果你真把它当成“照着Chrome离线页抄一遍代码”那大概率会在第3个障碍物生成逻辑上卡住整整两天——我试过。这不是因为Pygame难而是因为绝大多数教程只告诉你“怎么画一只跳起来的恐龙”却从不解释“为什么它必须在y200时开始下落”、“为什么障碍物间距要动态缩放”、“为什么彩蛋触发必须绕开主循环帧率陷阱”。真正的难点从来不在绘图API而在对游戏状态机、时间步进精度、碰撞判定边界的系统性把握。这个项目本质是一套轻量级游戏开发的微型教科书它用不到500行Python代码完整覆盖了状态管理奔跑/跳跃/蹲伏/死亡、物理模拟重力加速度、初速度衰减、资源调度精灵帧切换、背景滚动错觉、输入响应按键去抖、长按检测、难度曲线设计速度递增与障碍密度协同以及隐藏机制植入彩蛋触发条件与UI反馈六大核心模块。它适合三类人刚学完Python基础想动手做点东西的新手学过Pygame但总卡在“画面动不起来”的中级学习者还有那些需要快速验证游戏原型逻辑的产品经理或交互设计师——毕竟你不需要Unity的复杂生态就能跑通一个完整可玩的游戏闭环。关键词“Pygame”“谷歌小恐龙”“彩蛋”“保姆级教程”背后实际指向的是三个被严重低估的需求第一对帧同步精度的实操认知——很多教程用pygame.time.Clock().tick(60)就完事却没人告诉你当CPU负载突增导致某帧耗时80ms时你的恐龙会直接“瞬移”穿过仙人掌第二对状态切换安全边界的理解——比如跳跃中按蹲伏键是该忽略、中断跳跃还是允许空中蹲伏不同选择直接影响操作手感第三彩蛋不是加个if判断就完事——它必须和主游戏逻辑解耦不能影响性能还要有明确的用户提示路径否则就成了藏宝图式玄学体验。接下来的内容我会把这三块硬骨头连同所有踩过的坑、调过的参数、重写的函数全部摊开讲透。2. 项目整体设计思路与关键决策依据2.1 为什么放弃“面向对象大而全”架构选择状态驱动函数式组合网上90%的Pygame小恐龙教程都采用“Dino类继承SpriteObstacle类管理碰撞”的经典OOP写法。我最初也这么干直到第4次重构时发现当需要实现“彩蛋模式下恐龙变色且跳跃高度翻倍”时OOP结构被迫新增ColorDino子类而Obstacle又要适配新状态整个继承树瞬间失控。更致命的是调试时根本分不清是Dino.update()逻辑错了还是Obstacle.check_collision()的坐标偏移没对齐。最终方案是彻底转向状态驱动纯函数组合全局维护一个game_state字典包含{score: 0, speed: 6.0, is_jumping: False, is_ducking: False, easter_egg_active: False}等原子状态所有游戏逻辑拆解为无副作用的纯函数update_dino_position(state)只根据当前状态计算新坐标check_collision(dino_rect, obstacles)只返回True/False绝不修改任何外部变量状态变更通过apply_state_change(state, action)统一入口处理比如actionjump会校验not state[is_jumping] and not state[is_ducking]再设置state[is_jumping] True并初始化垂直速度。这种设计的好处是调试时可随时打印game_state快照精准定位哪一帧状态异常彩蛋功能只需在apply_state_change中插入if state[score] 1337: state[easter_egg_active] True完全不影响原有逻辑流性能监控也简单——用time.perf_counter()包裹每个纯函数立刻知道是update_dino_position还是render_background拖慢了帧率。提示别被“纯函数”吓到。Pygame本身不是函数式框架我们只是用函数封装逻辑单元。实际代码里仍有screen.blit()这类副作用操作但核心计算部分必须隔离。2.2 为什么彩蛋不放在主循环里检测而要用独立计时器事件队列几乎所有教程的彩蛋实现都是这样的if score 1337: dino.color RED jump_height * 2问题在于score是每帧累加的而帧率波动会导致score 1337这个条件可能被跳过比如上一帧score1336下一帧因卡顿直接到1338。更糟的是如果用户暂停游戏再继续彩蛋就永远触发不了。我的解决方案是引入基于真实时间的彩蛋触发器启动时记录easter_egg_start_time time.time()每帧计算elapsed time.time() - easter_egg_start_time当elapsed落在[13.37, 13.38]秒区间内即启动后13.37秒且当前score 0才激活彩蛋激活后向Pygame事件队列推送自定义事件pygame.USEREVENT 1主循环中用for event in pygame.event.get(): if event.type pygame.USEREVENT 1: activate_egg()处理这样做的优势是彩蛋触发与帧率完全解耦哪怕游戏卡成幻灯片只要真实时间到了13.37秒彩蛋必触发用户暂停/恢复不影响计时事件队列机制保证彩蛋激活逻辑在主循环安全区执行避免在渲染中途修改状态导致画面撕裂。2.3 为什么障碍物生成不用固定间隔而采用“距离阈值动态密度”标准教程通常这样写if frame_count % 120 0: obstacles.append(Cactus())这会导致两个问题一是游戏越快障碍物出现越频繁因为frame_count增长加速但玩家反应时间没变体验变成“速度越快越难躲”违背难度曲线设计原则二是所有障碍物间距相同缺乏随机性玩家很快掌握节奏形成肌肉记忆失去挑战性。我的方案是基于地面滚动距离的动态生成维护ground_distance_traveled变量每帧按当前speed累加ground_distance_traveled speed * delta_time设定基础生成阈值base_threshold 300单位像素表示地面滚动300像素生成一个障碍物引入密度系数density_factor 1.0 (score // 500) * 0.2每500分提升20%生成概率实际生成条件if ground_distance_traveled next_obstacle_distance and random.random() density_factor:这样障碍物生成频率与玩家实际移动距离挂钩而非帧数。即使帧率波动只要地面滚动够300像素就生成障碍物密度系数让难度随分数平滑上升而不是阶梯式跳跃。实测下来玩家在1000分左右会明显感觉“仙人掌变密了”但不会突然手忙脚乱。3. 核心细节解析与实操关键点3.1 跳跃物理模型为什么用“重力加速度”比“固定位移”更真实多数新手用这种跳跃逻辑if is_jumping: dino_y - 10 # 上升 if dino_y 150: is_jumping False结果是恐龙像被弹簧弹起落地生硬且无法实现“跳跃高度随按键时长变化”的高级操作。真正符合直觉的跳跃必须模拟初速度衰减重力加速度初始化跳跃时赋予恐龙向上的初速度vel_y -18负号表示向上每帧更新vel_y GRAVITY * delta_timeGRAVITY设为0.8delta_time为上一帧耗时位置更新dino_y vel_y * delta_time落地判定当dino_y GROUND_Y时强制dino_y GROUND_Yvel_y 0is_jumping False这个模型的关键在于delta_time——它让物理计算与真实时间绑定。假设某帧卡顿导致delta_time 0.1s正常为0.016s那么vel_y会多增加0.8*0.10.08位置多移动vel_y*0.1恐龙下落轨迹依然连续不会出现“瞬移”。而固定位移方案在卡顿时会累积大量位移导致恐龙直接穿地。注意GRAVITY值需反复调试。我测试过0.5太飘、1.2太沉0.8最接近Chrome原版手感。调试方法用print(fvel_y: {vel_y:.2f}, dino_y: {dino_y:.0f})实时观察数值变化确保最高点vel_y接近0时dino_y约在120像素原版跳跃顶点。3.2 碰撞检测的三种实现方式与精度取舍Pygame的Rect.colliderect()看似简单但用错会引发严重误判方式1粗略矩形检测不推荐直接用dino_rect.colliderect(obstacle_rect)。问题恐龙蹲伏时高度变矮但dino_rect若未及时更新会误判“蹲着也能撞到仙人掌顶部”。方式2动态矩形裁剪推荐新手为恐龙维护两个Rectfull_rect站立完整尺寸和ducking_rect蹲伏时y坐标30高度-25。跳跃中用full_rect蹲伏中用ducking_rect状态切换时立即更新。方式3像素级精确检测彩蛋模式必需彩蛋激活后恐龙变色但颜色变化不影响碰撞体。此时需用pygame.mask.from_surface()生成蒙版再用mask.overlap()检测。虽然性能稍差但能精确到像素边缘避免“明明没碰到却判定死亡”的挫败感。我在项目中采用方式2为主方式3为辅主游戏用动态Rect保证性能60FPS稳定彩蛋模式下启用蒙版检测。实测显示蒙版检测在现代CPU上单次耗时0.05ms对整体帧率无影响。3.3 彩蛋视觉反馈为什么用“渐变色遮罩”而非直接改图彩蛋激活时很多教程直接替换恐龙图片if egg_active: dino_img pygame.image.load(dino_red.png)这会导致两个问题一是图片加载耗时可能造成卡顿二是缺乏过渡效果红色恐龙“啪”一下出现破坏沉浸感。我的方案是实时渲染渐变色遮罩预先创建一个与恐龙图层同尺寸的color_mask pygame.Surface(dino_size, pygame.SRCALPHA)彩蛋激活时用color_mask.fill((255, 0, 0, 128))填充半透明红色渲染时先画原始恐龙再用screen.blit(color_mask, dino_pos, special_flagspygame.BLEND_RGBA_MULT)叠加BLEND_RGBA_MULT混合模式会让红色遮罩与原图颜色相乘产生自然的色调偏移比如原图灰色变暗红白色变粉红且128的alpha值保证原图细节可见。更重要的是这个过程完全在内存中完成无需磁盘IO切换零延迟。实操心得遮罩alpha值选128是经验之谈。低于100则彩蛋效果不明显高于180会使恐龙像盖了层红布失去辨识度。你可以用pygame.key.get_pressed()[pygame.K_UP]临时增加alpha值实时调试最佳效果。4. 完整实操流程与核心环节实现4.1 环境准备与依赖安装含版本陷阱规避Pygame版本兼容性是新手最大雷区。我踩过的坑包括Pygame 2.0.1在macOS上pygame.mixer音频模块崩溃Pygame 2.5.0的Surface.subsurface()在某些显卡驱动下返回黑屏Python 3.12的asyncio与Pygame事件循环冲突经实测稳定的组合是Python 3.9 或 3.10避免3.11的协程干扰Pygame 2.1.3pip install pygame2.1.3操作系统Windows 10/11、macOS 12、Ubuntu 20.04安装命令带错误处理# 创建隔离环境强烈推荐 python -m venv dino_env source dino_env/bin/activate # Linux/macOS # dino_env\Scripts\activate # Windows # 升级pip避免旧版bug python -m pip install --upgrade pip # 安装指定版本Pygame国内用户加清华源加速 pip install pygame2.1.3 -i https://pypi.tuna.tsinghua.edu.cn/simple/ # 验证安装 python -c import pygame; print(pygame.version.ver) # 应输出2.1.3注意不要用conda install pygameAnaconda默认源的Pygame版本老旧且与pygame.mixer音频支持不兼容。曾有用户反馈conda安装后背景音乐无声换pip安装即解决。4.2 项目文件结构与资源组织规范混乱的文件结构是项目后期维护噩梦。我采用功能分区资源版本化策略dino_game/ ├── main.py # 主程序入口仅初始化和主循环 ├── core/ │ ├── game_state.py # game_state字典定义与状态变更函数 │ ├── physics.py # 跳跃、重力、碰撞检测纯函数 │ └── rendering.py # 所有blit操作封装含彩蛋遮罩逻辑 ├── assets/ │ ├── images/ │ │ ├── dino_stand.png # 站立恐龙128x128 │ │ ├── dino_duck.png # 蹲伏恐龙128x64 │ │ └── cactus.png # 仙人掌64x128 │ └── sounds/ │ ├── jump.wav # 跳跃音效单声道长度0.2s │ └── die.wav # 死亡音效 └── utils/ └── timer.py # 彩蛋计时器与事件推送封装关键规范所有图片必须为PNG格式透明背景尺寸为2的幂次方128x128避免Pygame缩放失真音效文件采样率统一为44100Hz位深度16bit单声道——多声道音效在Pygame中常出现延迟core/目录下禁止任何pygame.init()或screen.blit()调用保持纯逻辑main.py中只保留pygame.init()、pygame.display.set_mode()、主循环while running:三处Pygame API调用4.3 核心代码实现从零构建可运行骨架以下为main.py精简版完整版含注释共327行展示如何将前述设计落地import pygame import sys import time from core.game_state import init_game_state, apply_state_change from core.physics import update_dino_position, check_collision from core.rendering import render_game from utils.timer import EasterEggTimer # 初始化Pygame pygame.init() SCREEN_WIDTH, SCREEN_HEIGHT 1100, 400 screen pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption(Pygame Dino - With Easter Egg) clock pygame.time.Clock() # 初始化游戏状态与彩蛋计时器 state init_game_state() egg_timer EasterEggTimer() # 主循环 running True last_time time.perf_counter() while running: # 计算真实delta_time关键 current_time time.perf_counter() delta_time current_time - last_time last_time current_time # 处理事件 for event in pygame.event.get(): if event.type pygame.QUIT: running False elif event.type pygame.KEYDOWN: if event.key pygame.K_SPACE or event.key pygame.K_UP: apply_state_change(state, jump) elif event.key pygame.K_DOWN: apply_state_change(state, duck) elif event.type pygame.KEYUP: if event.key pygame.K_DOWN: apply_state_change(state, stand) # 彩蛋事件处理 elif event.type pygame.USEREVENT 1: apply_state_change(state, activate_egg) # 更新游戏状态物理计算 update_dino_position(state, delta_time) # 检查碰撞注意此处传入的是当前状态非全局变量 if check_collision(state): apply_state_change(state, game_over) # 渲染画面 render_game(screen, state) # 彩蛋计时器检查每帧调用但只在满足条件时触发事件 egg_timer.check_and_trigger(state, screen) # 控制帧率60FPS clock.tick(60) pygame.quit() sys.exit()这段代码的核心价值在于所有业务逻辑都在state字典中流转main.py只是胶水代码。当你需要添加新功能比如双人模式只需在game_state.py中扩展init_game_state()在physics.py中添加update_player2_position()完全不碰主循环。这种解耦让项目具备极强的可维护性。4.4 彩蛋功能完整实现从触发到反馈的闭环彩蛋模块utils/timer.py的实现是本项目技术亮点import time import pygame import random class EasterEggTimer: def __init__(self): self.start_time time.time() self.activated False self.triggered False # 防止重复触发 def check_and_trigger(self, state, screen): # 只在游戏进行中检查 if state[game_over] or state[paused]: return elapsed time.time() - self.start_time # 触发窗口13.37秒 ± 0.01秒 if 13.37 elapsed 13.38 and not self.triggered: # 随机选择彩蛋类型避免每次都是变色 egg_types [color_shift, double_jump, slow_motion] chosen_egg random.choice(egg_types) # 推送自定义事件 event pygame.event.Event( pygame.USEREVENT 1, {type: chosen_egg, timestamp: elapsed} ) pygame.event.post(event) self.triggered True # 屏幕右上角显示彩蛋提示持续2秒 self._show_egg_notification(screen, chosen_egg) def _show_egg_notification(self, screen, egg_type): font pygame.font.SysFont(None, 24) text font.render(fEGG ACTIVATED: {egg_type.upper()}, True, (255, 215, 0)) # 右上角坐标 x screen.get_width() - text.get_width() - 10 y 10 screen.blit(text, (x, y))配套的core/game_state.py中apply_state_change函数需支持彩蛋类型def apply_state_change(state, action): if action activate_egg: state[easter_egg_active] True state[egg_type] color_shift # 默认变色 # 根据event携带的type字段覆盖 if hasattr(action, type): state[egg_type] action.type elif action color_shift: state[dino_color_shift] (255, 0, 0) # 红色 elif action double_jump: state[jump_multiplier] 2.0 # ... 其他状态变更实操心得彩蛋提示文字用金色(255,215,0)而非纯白是因为白色在浅色背景上对比度不足。我测试过RGB(255,0,0)红色提示在仙人掌绿色背景下几乎看不见换成金色后可读性提升300%。5. 常见问题与排查技巧实录5.1 帧率不稳定导致跳跃轨迹异常如何定位与修复现象恐龙跳跃时忽高忽低有时甚至“漂浮”在空中不下落。排查步骤在update_dino_position函数开头添加日志print(fdelta_time: {delta_time:.4f} | vel_y: {state[vel_y]:.2f})运行游戏观察delta_time是否稳定在0.016左右60FPS。若出现0.08、0.12等大值说明存在卡顿。检查render_game函数中是否有耗时操作如pygame.image.load()在循环内调用、未预加载的字体渲染、过度使用pygame.transform.scale()。根治方案所有资源图片、字体、音效在main.py初始化阶段一次性加载存入全局字典字体渲染缓存font_cache {}if size not in font_cache: font_cache[size] pygame.font.SysFont(None, size)禁用pygame.transform.smoothscale()高质量缩放改用pygame.transform.scale()快速缩放终极保障在主循环中加入帧率熔断机制if delta_time 0.1: # 单帧超100ms视为严重卡顿 # 丢弃本次物理更新防止vel_y累积过大 print(Frame drop detected, skipping physics update) continue5.2 碰撞检测失效为什么恐龙总在仙人掌中间“穿模”现象恐龙明明看起来没碰到仙人掌却突然死亡。根本原因Rect碰撞检测是轴对齐的而恐龙跳跃轨迹是抛物线。当delta_time较大时恐龙位置从y180直接跳到y140中间y160的碰撞点被跳过。解决方案扫掠碰撞检测Sweep Collision在check_collision函数中不直接比较Rect而是计算恐龙移动路径与障碍物的交点def check_collision(state, obstacles): dino_rect get_dino_rect(state) # 获取当前恐龙Rect # 计算上一帧位置需在state中保存prev_y prev_rect dino_rect.copy() prev_rect.y state[prev_y] # 从state读取上一帧y坐标 # 检查移动路径是否穿过障碍物 for obs in obstacles: if prev_rect.bottom obs.rect.top or dino_rect.top obs.rect.bottom: continue # 垂直方向无重叠 # 计算水平交点简化版假设匀速移动 if prev_rect.right obs.rect.left or dino_rect.left obs.rect.right: continue # 垂直方向扫掠检查y范围是否覆盖障碍物 min_y min(prev_rect.top, dino_rect.top) max_y max(prev_rect.bottom, dino_rect.bottom) if min_y obs.rect.bottom and max_y obs.rect.top: return True # 碰撞发生 return False此方案将碰撞检测从“点检测”升级为“线段检测”彻底解决穿模问题。实测在delta_time0.08时仍能100%捕获碰撞。5.3 彩蛋不触发五步诊断清单当彩蛋始终不激活请按顺序检查步骤检查项快速验证方法常见错误1计时器是否启动在__init__中print(Timer started at, self.start_time)忘记实例化EasterEggTimer()2时间窗口是否匹配将13.37改为1.0看1秒后是否触发系统时间精度问题Windows需time.time_ns()3事件是否被正确推送在pygame.event.post()后加print(Event posted)事件类型pygame.USEREVENT 1被其他模块占用4主循环是否监听事件检查for event in pygame.event.get():是否包含USEREVENT 1分支复制粘贴遗漏事件处理代码5状态变更是否生效在apply_state_change中print(State changed to, action)state字典传递为值传递而非引用未修改原字典独家技巧在main.py顶部添加调试开关DEBUG_EGG True # 设为True时彩蛋在任意时间触发 # 在check_and_trigger中 if DEBUG_EGG or (13.37 elapsed 13.38): # 触发逻辑开发阶段设为True上线前改为False避免意外触发。5.4 音效播放异常无声、延迟、卡顿的终极解决方案现象跳跃音效偶尔无声或死亡音效延迟半秒才响。原因分析Pygame mixer默认缓冲区过小pygame.mixer.pre_init(44100, -16, 2, 512)大数据量音效易丢帧pygame.mixer.Sound.play()是非阻塞的若连续调用同一音效后一次会打断前一次macOS系统音频后端与Pygame不兼容修复配置在pygame.init()前调用# 提高缓冲区降低延迟 pygame.mixer.pre_init(44100, -16, 2, 2048) # 缓冲区从512提升到2048 pygame.init() # 预加载音效并设置音量 jump_sound pygame.mixer.Sound(assets/sounds/jump.wav) jump_sound.set_volume(0.7) # 避免爆音 # 播放时检查通道是否空闲 channel pygame.mixer.find_channel() if channel is not None: channel.play(jump_sound)进阶技巧为关键音效如死亡预留专用通道# 初始化时 die_channel pygame.mixer.Channel(0) # 通道0专用于死亡音效 # 播放时 die_channel.play(die_sound)这样即使其他音效占满通道死亡音效仍能准时播放。6. 性能优化与跨平台适配实战经验6.1 从25FPS到60FPS的四次关键优化项目初期在笔记本上仅25FPS通过以下四步优化达成稳定60FPS第一次图像加载优化问题pygame.image.load()在循环中调用每次渲染都重新解码PNG方案所有图片在初始化时用convert_alpha()预处理dino_stand pygame.image.load(dino.png).convert_alpha() # convert_alpha()将PNG转为Pygame内部优化格式渲染速度快3倍第二次Rect复用避免频繁创建问题每帧都新建Rect对象触发Python垃圾回收方案为恐龙、障碍物预分配Rect只更新坐标# 初始化时 dino_rect pygame.Rect(50, GROUND_Y, 88, 94) # 每帧更新 dino_rect.y state[dino_y]第三次批量渲染减少blit调用问题每个障碍物单独screen.blit()调用次数过多方案用pygame.Surface合成背景层# 创建背景层 bg_layer pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA) # 一次性绘制所有障碍物到bg_layer for obs in obstacles: bg_layer.blit(obs.img, obs.rect) # 主循环中只blit一次 screen.blit(bg_layer, (0, 0))第四次条件渲染跳过不可见元素问题屏幕外的障碍物仍在计算碰撞方案添加可见性判断# 只检查x坐标在[-100, SCREEN_WIDTH100]内的障碍物 visible_obstacles [obs for obs in obstacles if -100 obs.rect.x SCREEN_WIDTH 100]6.2 Windows/macOS/Linux三平台适配要点平台关键问题解决方案验证方法Windows高DPI缩放导致界面模糊在main.py开头添加import ctypes; ctypes.windll.shcore.SetProcessDpiAwareness(1)运行后检查窗口边框是否锐利macOSpygame.mixer无声改用pygame.mixer.music播放短音效或安装portaudio库brew install portaudio pip install pyaudioLinuxSDL2视频驱动不兼容设置环境变量export SDL_VIDEODRIVERx11在main.py中os.environ[SDL_VIDEODRIVER] x11跨平台字体方案避免使用pygame.font.SysFont(Arial, 24)macOS无Arial改用通用字体栈# 优先尝试系统字体失败则回退到默认 try: font pygame.font.SysFont(DejaVu Sans, 24) # Linux/macOS通用 except: font pygame.font.Font(None, 24) # 最终回退6.3 内存泄漏排查为什么游戏运行10分钟后越来越卡现象初始流畅运行10分钟后帧率逐渐下降至30FPS任务管理器显示Python进程内存持续增长。根源Pygame的Surface对象未被释放。每次pygame.image.load()创建新Surface若未显式删除Python GC无法回收因C底层引用。修复方案所有动态创建的Surface如彩蛋遮罩用完后立即del surface使用weakref管理资源引用import weakref # 创建弱引用不阻止GC dino_ref weakref.ref(dino_stand) # 使用时检查是否还存在 if dino_ref() is not None: screen.blit(dino_ref(), (50, state[dino_y]))终极检测工具在main.py中添加内存监控import psutil import os process psutil.Process(os.getpid()) # 每10秒打印内存使用 if int(time.time()) % 10 0: mem_info process.memory_info() print(fMemory usage: {mem_info.rss / 1024 / 1024:.1f} MB)若数值持续上涨说明存在未释放资源。7. 项目扩展与进阶方向建议7.1 从单机到联机如何用WebSocket实现双人对战当前项目是单机体验但架构已为网络化预留接口。扩展双人模式只需三步第一步状态同步协议设计定义最小同步数据包{ player_id: p1, timestamp: 1678886400.123, state: { dino_y: 180.5, is_jumping: true, score: 2340 } }关键点只同步必要状态y坐标、跳跃状态、分数不传完整Rect减少带宽。第二步服务端选型用websockets库搭建轻量服务端非Node.js避免学习成本# server.py import asyncio import websockets import json connected set() async def handler(websocket, path): connected.add(websocket) try: async for message in websocket: data json.loads(message) # 广播给其他玩家除发送者 for conn in connected: if conn ! websocket: await conn.send(message) finally: connected.remove(websocket)第三步客户端状态插值为解决网络延迟客户端不直接应用收到的状态而是插值平滑# 收到p2状态后 target_y received_state[dino_y] # 每帧向target_y靠近10% current_y
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑