用原生HTML5 Canvas与JavaScript复刻经典游戏:超级马里奥的Web实现
1. 从像素到网页一个经典游戏的现代重生十年前如果有人告诉我那个在红白机上蹦蹦跳跳、吃蘑菇变大、踩乌龟救公主的意大利水管工能完整地跑在我的浏览器里我大概会觉得他在开玩笑。毕竟那是一个Flash还在称王称霸网页游戏大多还是简单棋牌的时代。但今天这已经成了现实。一个名为“在线版的超级马里奥 Super Mario HTML5”的项目正是这种技术变迁最生动的注脚。它不仅仅是一个怀旧玩具更是一个绝佳的技术实践场向我们展示了现代Web技术——特别是HTML5、CSS3和JavaScript——所能达到的惊人高度。这个项目本质上是一个用纯前端技术HTML5 Canvas、JavaScript完整复刻了初代《超级马里奥兄弟》核心玩法的网页应用。你不需要安装任何插件不需要下载几十兆的模拟器更不用折腾复杂的配置。只需一个现代浏览器点开链接那个熟悉的1-1关卡就会立刻呈现在你面前。方向键控制移动空格键跳跃顶砖块、吃蘑菇、踩敌人、钻水管……所有经典操作一应俱全。这背后是Web标准历经多年发展后在图形渲染、音频处理、实时交互等方面取得的巨大突破。HTML5的canvas元素提供了堪比原生应用的绘图能力Web Audio API让8位芯片音乐得以精准重现而JavaScript引擎的性能飞跃则保证了游戏逻辑每秒60帧的流畅运行。那么谁需要了解甚至动手实现这样一个项目呢首先当然是前端开发者。如果你想深入理解Canvas动画、游戏循环、碰撞检测、物理模拟、资源加载与管理这些前端领域的硬核知识还有什么比亲手实现一个经典游戏更好的“练级副本”呢其次是游戏开发爱好者。对于想入门游戏开发但又畏惧C或Unity/Unreal引擎复杂性的朋友从Web游戏入手门槛更低反馈更即时成就感来得更快。最后即便是普通的技术爱好者或马里奥粉丝探究一下这个“网页里的红白机”是如何工作的也是一件充满乐趣的事情。接下来我将带你深入这个项目的内部拆解其技术架构还原其实现细节并分享在复刻过程中必然会遇到的“坑”与应对之策。2. 技术栈选型为什么是纯前端“三件套”当我们决定在浏览器里复刻一个经典游戏时面临的首要问题就是技术选型。市面上有诸多成熟的选择Unity可以通过WebGL导出为WebAssembly性能强大Phaser、Pixi.js这类专业的HTML5游戏引擎功能齐全社区活跃。但这个“在线版超级马里奥”项目却选择了一条看似更“原始”的道路纯原生HTML5 Canvas 原生JavaScript或ES6 CSS。这个选择背后有着非常实际和深刻的考量。2.1 追求极致的轻量与可控Unity或大型游戏引擎固然强大但它们会带来巨大的运行时开销。一个简单的“Hello World”项目打包后可能就有好几兆其中包含了整个引擎的核心代码。对于《超级马里奥》这种像素风格、逻辑相对清晰的2D平台跳跃游戏来说引入这样一个庞然大物无异于“杀鸡用牛刀”不仅加载慢而且会丧失对代码每一行的掌控感。而原生“三件套”的方案最终产出的可能只是一个几百KB的HTML文件加上一些图片、音频资源真正做到即开即玩。更重要的是从零开始构建意味着你对游戏中的每一个碰撞箱、每一帧动画、每一条物理规则都了如指掌这对于学习和理解游戏开发的基础原理至关重要。2.2 深入理解游戏引擎的核心机制使用现成引擎你是在学习引擎的API和编辑器而使用原生技术你是在亲手打造一个微型的游戏引擎。这个过程会让你被迫去思考并实现那些引擎帮你封装好的底层机制游戏循环Game Loop如何组织requestAnimationFrame来驱动游戏的每一帧更新Update和绘制Draw状态管理游戏中的开始、进行中、暂停、死亡、过关等状态如何清晰地定义和切换实体-组件系统ECS的雏形虽然不一定实现完整的ECS但你会自然地将马里奥、敌人、砖块、金币等抽象为“游戏对象GameObject”并为它们赋予位置、速度、精灵图Sprite等属性以及更新、渲染、碰撞检测等方法。这是一种最直观的面向对象实践。资源管理器如何预加载所有图片和音效确保游戏开始时不出现资源缺失的尴尬通过亲手实现这些你对“游戏是如何跑起来的”会有刻骨铭心的理解这种理解是单纯调用引擎API无法获得的。2.3 规避依赖与兼容性陷阱“在线版”的核心诉求是随处可玩。依赖特定引擎或插件就意味著兼容性风险。虽然WebAssembly已经非常普及但在一些旧设备或特殊环境的浏览器上仍可能存在问题。而纯HTML5方案几乎拥有最广泛的兼容性。只要浏览器支持Canvas和基本的JavaScript游戏就能运行。这确保了项目最大的可访问性真正实现了“打开浏览器就是游戏机”的愿景。注意这里说的“原生JavaScript”并非排斥任何工具。在实际开发中我们完全可以使用ES6的模块化语法或者引入一些轻量级的工具库例如用Howler.js简化音频播放用一个小型的向量数学库。关键在于不引入一个决定整体架构的重型框架保持核心游戏逻辑的透明和可控。3. 核心架构拆解一个微型游戏引擎的诞生理解了“为什么”之后我们来看看“是什么”。一个完整的“在线版超级马里奥”项目其代码结构可以看作一个微型的、定制化的游戏引擎。它通常包含以下几个核心模块我们可以用一个简单的类图思想来理解它们之间的关系虽然不画出来但可以描述清楚。3.1 发动机游戏循环与主控制器这是整个游戏的心脏。它不负责具体的画图或逻辑而是负责调度。在main.js或Game.js中你会看到一个类似下面的核心结构class Game { constructor() { this.canvas document.getElementById(game-canvas); this.ctx this.canvas.getContext(2d); this.lastTime 0; this.accumulatedTime 0; this.timeStep 1000 / 60; // 目标每秒60帧每帧约16.67ms this.state LOADING; // 状态LOADING, MENU, PLAYING, PAUSED, GAME_OVER, LEVEL_COMPLETE this.currentLevel null; this.player null; // ... 其他游戏对象集合 } load() { // 异步加载所有图片、音效 // 加载完成后将状态切换为 MENU } startLevel(levelId) { this.state PLAYING; // 根据levelId创建关卡数据平台、敌人、砖块等 this.currentLevel new Level(levelId); this.player new Player(spawnX, spawnY); } update(deltaTime) { if (this.state ! PLAYING) return; // 1. 更新玩家状态位置、速度、动画帧 this.player.update(deltaTime, this.currentLevel); // 2. 更新所有敌人 this.currentLevel.enemies.forEach(enemy enemy.update(deltaTime)); // 3. 检测碰撞玩家 vs 敌人 玩家 vs 砖块/金币/道具 this.checkCollisions(); // 4. 更新镜头让画面跟随马里奥滚动 this.updateCamera(); } draw() { // 1. 清空画布 this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); // 2. 根据镜头偏移绘制背景天空、云、山等静态元素 this.drawBackground(); // 3. 绘制关卡地形砖块、水管、地面 this.currentLevel.draw(this.ctx); // 4. 绘制所有敌人 // 5. 绘制玩家 this.player.draw(this.ctx); // 6. 绘制UI分数、金币数、剩余生命 this.drawHUD(); } run(currentTime) { // 计算上一帧到这一帧的时间差deltaTime let deltaTime currentTime - this.lastTime; this.lastTime currentTime; // 使用固定时间步长进行更新避免帧率波动导致物理模拟不稳定 this.accumulatedTime deltaTime; while (this.accumulatedTime this.timeStep) { this.update(this.timeStep); // 用固定的timeStep更新逻辑 this.accumulatedTime - this.timeStep; } this.draw(); // 每一帧都绘制 requestAnimationFrame((time) this.run(time)); // 循环继续 } }这个Game类掌控一切初始化、资源加载、状态切换、驱动更新和绘制循环。它采用的**固定时间步长Fixed Timestep**更新模式是游戏开发中的经典模式能确保无论玩家电脑性能如何马里奥的跳跃高度和移动速度在逻辑上是恒定的避免了快慢设备上游戏体验不一致的问题。3.2 舞台与演员关卡与实体系统关卡Level类是舞台。它通常由一个二维数组或更复杂的数据结构定义每个数字或字符代表一种地图元素0空气1砖块2方块P水管E敌人出生点等。Level类的职责是根据这个数据在内存中生成所有对应的“实体”Entity对象并提供一些查询方法例如“获取某坐标下方是什么类型的地面”。实体Entity是所有会动、会交互的事物的基类。Player马里奥、Goomba板栗仔、Koopa诺库龟、Block砖块、Coin金币都继承自它。一个典型的实体基类可能包含class Entity { constructor(x, y, width, height) { this.position { x, y }; // 世界坐标 this.velocity { x: 0, y: 0 }; // 速度向量 this.size { width, height }; // 碰撞箱大小 this.sprite null; // 当前显示的精灵图 this.isAlive true; } update(deltaTime, level) { // 应用重力 this.velocity.y GRAVITY * deltaTime; // 根据速度更新位置 this.position.x this.velocity.x * deltaTime; this.position.y this.velocity.y * deltaTime; // 调用具体的更新逻辑由子类实现 this.onUpdate(deltaTime, level); // 处理与关卡边界的碰撞防止掉出世界 this.handleWorldBounds(level); } draw(ctx) { if (!this.sprite) return; // 将精灵图绘制到Canvas上注意坐标可能要根据相机偏移调整 ctx.drawImage(this.sprite.image, this.sprite.x, this.sprite.y, ...); } // 与另一个实体的碰撞检测AABB即轴对齐包围盒 collidesWith(other) { return this.position.x other.position.x other.size.width this.position.x this.size.width other.position.x this.position.y other.position.y other.size.height this.position.y this.size.height other.position.y; } }通过这样的继承体系我们可以用多态的方式统一管理所有游戏对象。Game.update()中遍历更新所有实体时调用的是各自重写的onUpdate方法板栗仔会左右移动马里奥会响应键盘输入。3.3 物理与交互碰撞检测的实战细节碰撞检测是平台跳跃游戏的灵魂也是新手最容易栽跟头的地方。简单的AABB检测只能告诉你“撞上了”但我们需要知道“撞上了哪一边”从而做出正确的反应站在地面上、顶到砖头、碰到敌人侧面。3.3.1 分层与顺序检测一个高效的策略是分层检测。首先检测马里奥与地面的碰撞决定是否站立然后检测与可碰撞物体砖块、方块的碰撞最后检测与敌人的碰撞。顺序很重要因为一次移动可能会触发多次碰撞需要按合理的优先级解决。3.3.2 解决“隧道效应”如果马里奥速度过快在一帧内就从砖块的一侧“穿越”到了另一侧AABB检测就会失效这叫隧道效应。解决方法之一是使用连续碰撞检测CCD或者更简单实用的“先移动一个轴检测并解决碰撞再移动另一个轴”。例如先计算马里奥本帧的预期新位置newX, newY。然后水平移动检测尝试移动到(newX, oldY)检测水平方向碰撞。如果碰撞则将x坐标调整到碰撞箱的边界并将水平速度velocity.x设为0碰到墙。垂直移动检测基于上一步调整后的x坐标再尝试移动到(adjustedX, newY)检测垂直方向碰撞。如果从上方碰撞脚碰到地面则将y坐标调整到地面顶部并将velocity.y设为0同时将马里奥状态设为“在地面上”如果从下方碰撞头碰到砖块则调整y坐标并将velocity.y设为正值被弹开同时触发“顶砖块”事件。3.3.3 碰撞响应检测到碰撞后响应逻辑因对象而异马里奥 vs 地面/砖块如上所述调整位置重置速度。马里奥 vs 方块除了调整位置还要触发方块“被顶”的动画上下抖动并生成一个金币或蘑菇实体。马里奥 vs 板栗仔判断碰撞位置。如果马里奥的脚部碰撞箱的下方一定区域碰到了板栗仔的顶部则判定为“踩”板栗仔被消灭马里奥获得一个向上的反弹速度否则判定为侧面碰撞马里奥受伤变小或死亡。蘑菇 vs 马里奥接触后蘑菇消失触发马里奥“变大”的状态切换并播放音效。这些精细的碰撞逻辑是游戏手感是否“原汁原味”的关键。差之毫厘谬以千里。4. 资源与呈现让像素跳动起来游戏逻辑是骨骼而图像和声音是血肉。如何高效地管理和呈现这些资源是项目中的另一个重点。4.1 精灵图Sprite Sheet与动画系统你不会为马里奥的每一个动作走、跑、跳、蹲都准备一张单独的图片。那样会产生大量HTTP请求效率低下。标准的做法是使用精灵图——将一个人物的所有动画帧按顺序排列在一张大图上。Sprite类负责处理精灵图。它记录着在大图中的起始坐标(sx, sy)、单帧的宽高以及动画的帧序列和播放速度。class Sprite { constructor(image, frameWidth, frameHeight) { this.image image; // 加载好的Image对象 this.frameWidth frameWidth; this.frameHeight frameHeight; this.currentFrame 0; this.frameCount 0; // 总帧数 this.animationSpeed 0.1; // 每帧停留的“时间”单位 this.elapsedTime 0; this.animations {}; // 存储不同动画的帧序列如{ idle: [0], run: [1,2,3,2], jump: [4] } this.currentAnimation idle; } update(deltaTime) { const frames this.animations[this.currentAnimation]; if (!frames || frames.length 1) return; // 单帧动画不更新 this.elapsedTime deltaTime; if (this.elapsedTime this.animationSpeed) { this.currentFrame (this.currentFrame 1) % frames.length; this.elapsedTime 0; } } draw(ctx, x, y) { const frameIndex this.animations[this.currentAnimation][this.currentFrame]; const sx (frameIndex % this.horizontalFrames) * this.frameWidth; const sy Math.floor(frameIndex / this.horizontalFrames) * this.frameHeight; ctx.drawImage( this.image, sx, sy, this.frameWidth, this.frameHeight, // 源图像区域 x, y, this.frameWidth, this.frameHeight // 在画布上绘制的区域 ); } }马里奥的Player类内部会持有一个Sprite实例并根据自身状态是否移动、是否在空中、是否变大来切换sprite.currentAnimation。在Player.draw()方法中直接调用sprite.draw()即可。这种分离让动画逻辑变得非常清晰。4.2 音效管理Web Audio API的轻量级应用游戏音效需要低延迟、精准触发。虽然可以用HTML5的audio标签但在快速连续播放如连续顶砖块时可能出现卡顿或延迟。Web Audio API是更专业的选择。不过其API相对复杂。在实践中一个常见的折中方案是使用Howler.js这样的轻量级库它封装了Web Audio API和HTML5 Audio提供了简单统一的接口并能自动处理多声道播放避免音效重叠被截断的问题。import { Howl } from howler; const soundAssets { jump: new Howl({ src: [sounds/jump.wav] }), coin: new Howl({ src: [sounds/coin.wav] }), stomp: new Howl({ src: [sounds/stomp.wav] }), powerup: new Howl({ src: [sounds/powerup.wav] }), }; // 在碰撞检测到吃金币时 soundAssets.coin.play();4.3 关卡数据的存储与生成关卡数据地图布局如果硬编码在JavaScript数组里会使得代码臃肿且难以维护。更好的做法是将其存储在独立的JSON文件或通过特定格式的文本文件定义。例如可以用一个字符矩阵来表示[ “........................................”, “........................................”, “...................1....................”, “..............???....1...................”, “.....E....................E.........”, “” ]其中.代表空1代表砖块?代表方块代表地面E代表敌人出生点。Level类的构造函数读取这个字符串数组遍历每一个字符在对应的世界坐标生成相应的实体对象。这种方式使得设计和修改关卡变得非常直观甚至可以开发一个简单的可视化关卡编辑器。5. 性能优化与调试让游戏丝般顺滑当所有功能都实现后你可能会发现游戏在滚动复杂场景时出现卡顿。这时性能优化就派上用场了。5.1 视口裁剪与脏矩形渲染最直接的优化是不要绘制屏幕外的东西。Canvas的drawImage是昂贵的操作。在每一帧draw调用中遍历所有实体前先计算当前相机视口Viewport的范围camera.x, camera.y, camera.width, camera.height。只绘制那些位置与视口有交集的实体。这被称为“视口裁剪”Viewport Culling。更进一步可以采用“脏矩形”渲染。即只重绘上一帧中发生变化的那部分区域。但对于《超级马里奥》这种卷轴游戏几乎整个屏幕每帧都在变实现脏矩形收益不大视口裁剪已经足够了。5.2 使用离屏Canvas进行静态背景合成关卡中的背景远处的山、云、城堡通常是静态的或者滚动速度很慢视差滚动。我们可以将这些静态背景预先绘制到一个离屏的Canvas上然后在每一帧主绘制中只需要将这个离屏Canvas的图像drawImage到主Canvas上而不是重新绘制每一个背景元素。这相当于把背景“缓存”了起来。// 在关卡加载时 this.backgroundCanvas document.createElement(canvas); this.bgCtx this.backgroundCanvas.getContext(2d); // 将静态背景元素绘制到 this.backgroundCanvas 上 // 在每一帧绘制时 ctx.drawImage(this.backgroundCanvas, camera.x * parallaxFactor, 0, ...);5.3 避免在游戏循环中触发垃圾回收垃圾回收GC的暂停是导致游戏卡顿的元凶之一。要避免在update或draw循环中频繁创建新对象。例如复用对象池对于频繁创建销毁的对象如子弹、特效粒子可以使用对象池。预先创建一定数量的对象放在池中需要时取出并激活用完后重置并放回池中避免不断new和垃圾回收。避免在循环中创建函数或数组例如entities.forEach(e e.update())会产生一个新的箭头函数。如果实体数量多、帧率高这也是开销。可以使用传统的for循环。将常量、配置项提升到循环外部如重力常数GRAVITY、帧时间timeStep等不要在循环内反复查找或计算。5.4 利用Chrome DevTools进行性能剖析现代浏览器的开发者工具是强大的调试利器。Performance面板录制一段游戏过程可以看到详细的火焰图。找到耗时最长的函数调用通常是drawImage或复杂的碰撞检测函数对其进行优化。Memory面板定期进行堆快照对比检查是否有内存泄漏例如不断创建实体却从未被销毁。FPS计数器实时监控帧率确保稳定在60FPS。实操心得性能优化是一个“测量-优化-再测量”的过程。不要过早优化。先让游戏逻辑正确运行然后利用性能工具找到真正的瓶颈。很多时候最大的性能提升往往来自于一两个关键点的修改比如实现了视口裁剪或者修复了一个导致全屏重绘的Bug。6. 从复刻到创新项目的延伸思考完成一个基本可玩的复刻版已经是一个了不起的成就。但技术的乐趣在于无止境的探索。在此基础上你可以尝试许多有趣的扩展让这个项目从“复刻”走向“创造”。6.1 实现关卡编辑器这是最具实用价值的扩展。开发一个基于Web的所见即所得关卡编辑器。左侧是素材面板各种砖块、敌人、水管图标中间是网格画布右侧是属性面板。编辑器可以将设计好的关卡导出为前面提到的JSON或文本格式直接被你的游戏引擎加载。这不仅能让你轻松创造新关卡也使得项目从一个“玩具”升级为一个“平台”。6.2 添加多人游戏模式利用WebSocket和Node.js或其他后端技术可以实现简单的多人同屏游戏。例如合作模式两个玩家分别控制马里奥和路易吉共同闯关。需要同步两个玩家的位置、状态以及关卡中可交互元素如已被顶过的砖块的状态。对战模式在一个特定的竞技场地图中互相发射火球或争夺金币。 实现多人游戏会引入全新的技术挑战网络延迟的补偿插值、预测、游戏状态的权威性服务器仲裁、防止作弊等这是一个更深的水池。6.3 引入物理引擎如Matter.js目前我们的物理是简化的匀速运动重力碰撞反应。可以集成一个轻量的2D物理引擎如Matter.js来获得更真实、更丰富的物理效果。比如让砖块被顶后不仅上下抖动还能被顶飞让敌人被打败后有一个抛物线式的抛飞效果。但要注意物理引擎的引入会增加复杂性和性能开销需要权衡。6.4 适配移动端触摸控制让游戏在手机和平板上也能玩。这不仅仅是把画布缩放适应屏幕那么简单。你需要设计虚拟摇杆和按钮在Canvas上覆盖透明的UI层监听touchstart,touchmove,touchend事件将触摸位置转换为方向输入和动作输入跳跃、加速跑。处理多点触控防止虚拟按钮之间的干扰。性能考量移动设备性能参差不齐可能需要进一步简化绘制或降低渲染分辨率以保证流畅度。6.5 添加游戏进度保存与成就系统利用浏览器的localStorageAPI可以轻松实现本地存档。保存的数据可以包括已解锁的关卡、收集的金币总数、最快通关时间等。甚至可以设计一套成就系统“第一次踩死敌人”、“无伤通过1-1”、“收集所有隐藏金币”增加游戏的可重复玩性。走到这一步你已经远远超出了一个“复刻者”的角色。你拥有了一个功能完备的2D游戏开发框架理解了从底层渲染到上层逻辑从单机到联网从桌面到移动的完整知识链。这个“在线版超级马里奥”项目就像一颗种子已经长成了一棵枝繁叶茂的技术之树。无论你未来是专注于前端可视化还是转向游戏开发这段从零开始构建一个完整交互系统的经历都将是你简历上最扎实、也最有趣的一笔。

相关新闻

多源信息融合实战:从数据孤岛到智能决策的核心架构与算法

多源信息融合实战:从数据孤岛到智能决策的核心架构与算法

1. 项目概述:从“信息孤岛”到“决策大脑”的进化干了这么多年数据分析和系统架构,我越来越深刻地体会到,我们缺的从来不是数据,而是“把数据用对地方”的能力。你手头可能有来自传感器的实时流、来自业务数据库的历史记录、来自第…

2026/8/26 11:34:27 阅读更多 →
PLC在游泳池自控系统中的应用与实战拆解

PLC在游泳池自控系统中的应用与实战拆解

1. 从需求到方案:游泳池自控为什么绕不开PLC搞了好几年工业自动化,说实话,接到游泳池这个项目的时候,我最初是有点“大材小用”的感觉的。一套游泳池控制系统,无非就是循环过滤、加热、消毒、补水这几件事,…

2026/8/26 11:34:27 阅读更多 →
多源信息融合实战:从卡尔曼滤波到深度学习,构建智能决策系统

多源信息融合实战:从卡尔曼滤波到深度学习,构建智能决策系统

1. 项目概述:从“信息孤岛”到“决策大脑”的跃迁如果你在数据、物联网、自动驾驶或者任何一个需要做判断的领域待过,你肯定听过“多源信息融合”这个词。听起来挺高大上,但说白了,就是让不同地方、不同格式、不同时间来的信息&am…

2026/8/26 11:34:27 阅读更多 →

最新新闻

STM32开发环境搭建:从Keil/IAR迁移到CLion+开源工具链全攻略

STM32开发环境搭建:从Keil/IAR迁移到CLion+开源工具链全攻略

1. 从零开始的CLion STM32开发环境搭建:为什么我放弃了Keil和IAR如果你和我一样,厌倦了Keil那略显陈旧的界面和IAR昂贵的授权,想在Linux或macOS上优雅地开发STM32,或者单纯想用一个更现代的IDE来提升嵌入式开发的体验,…

2026/8/26 11:59:01 阅读更多 →
CLion配置STM32开发环境:从工具链到调试实战指南

CLion配置STM32开发环境:从工具链到调试实战指南

1. 项目概述:为什么选择CLion开发STM32? 作为一名在嵌入式领域摸爬滚打了十多年的老鸟,我经历过各种开发环境的变迁。从早期的Keil MDK、IAR EWARM,到后来在Linux上用VSCodeGCCOpenOCD,再到如今在CLion上搭建一套丝滑的…

2026/8/26 11:59:01 阅读更多 →
从模糊需求到可行方案:系统设计 Mock Interview 实战指南

从模糊需求到可行方案:系统设计 Mock Interview 实战指南

第一次参加 System Design Mock Interview 时,我很快就陷入了一个尴尬的循环:面试官问“设计一个 url 短链服务”,我脑子里浮现的是各种各样现成的架构图,却连“这个系统大概要支撑多大的访问量”都没有主动追问。那次模拟结束之后…

2026/8/26 11:59:01 阅读更多 →
曲面镜成像全解:凹面镜与凸面镜的公式、作图及应用

曲面镜成像全解:凹面镜与凸面镜的公式、作图及应用

1. 从一面镜子说起:为什么凹面镜和凸面镜值得单独讲 说到镜子,大多数人脑子里浮现的都是浴室里那面平面镜,照出来的人既不胖也不瘦,平平无奇。但如果你把镜面稍微弯一下,事情就完全不一样了——它会放大、缩小、倒立&a…

2026/8/26 11:59:01 阅读更多 →
PHP斗地主源码全解析:从游戏逻辑到移动端自适应与后端部署

PHP斗地主源码全解析:从游戏逻辑到移动端自适应与后端部署

简介:在Web游戏开发中,PHP凭借轻量、灵活和低门槛的特点,常被用于实现休闲棋牌类游戏的后端逻辑。理解一段完整的源码结构,是快速上手游戏开发的有效路径。本文以一套典型的斗地主H5游戏源码为例,从服务端牌局引擎出发…

2026/8/26 11:59:01 阅读更多 →
RP2350安全启动实战:从TrustZone到OTP密钥管理

RP2350安全启动实战:从TrustZone到OTP密钥管理

1. 为什么一颗MCU要专门聊安全:先说清楚威胁模型1.1 大多数嵌入式开发者的安全认知误区在做物联网产品、设备固件或者消费电子的时候,很多嵌入式工程师对"安全"的理解其实停留在非常表面的层次。最常见的想法是:我把固件编译好&…

2026/8/26 11:58:00 阅读更多 →

日新闻

Python random 模块常用函数详解:从入门到实战

Python random 模块常用函数详解:从入门到实战

目录 1. 引言2. 准备工作3. 基础随机函数4. 序列相关函数5. 随机种子与复现6. 实战案例7. 注意事项8. 常见问题与排查9. 总结 1. 引言 摘要: 本文系统介绍 Python 标准库 random 模块中最常用的随机数生成函数。内容涵盖基础随机函数(random()、unifor…

2026/8/26 0:00:40 阅读更多 →
《Microsoft Sql server 2008 Internals》读书笔记--第三章Databases and Database Files(2)

《Microsoft Sql server 2008 Internals》读书笔记--第三章Databases and Database Files(2)

《Microsoft Sql server 2008 Internals》索引目录: 《Microsoft Sql server 2008 Internals》读书笔记--目录索引 在上篇文章中,主要介绍了创建数据库的基本语法和FileGroup的初步知识。需要注意的是: 关于FileGroup 如果你的系统是用Raid设备直接存…

2026/8/26 1:18:18 阅读更多 →
政务AI智能体怎么建?三种模式、三步路径与四个误区

政务AI智能体怎么建?三种模式、三步路径与四个误区

政务AI智能体已经从概念试点阶段,转入了政务服务的常态化落地应用;在实际使用过程中,它能自主理解办事需求、辅助完成填报申报、开展材料预审,并联动多个系统协同作业,真正嵌入到政务办理的全流程当中。但在落地推进过…

2026/8/26 1:18:18 阅读更多 →

周新闻

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/25 3:38:12 阅读更多 →
SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/25 3:38:18 阅读更多 →
Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/25 3:38:23 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/26 3:50:20 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/25 10:31:12 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/26 1:24:05 阅读更多 →