news 2026/4/16 18:20:10

前端物理引擎实战:Matter.js + Canvas,300行代码复刻“羊了个羊”掉落版

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
前端物理引擎实战:Matter.js + Canvas,300行代码复刻“羊了个羊”掉落版

摘要:当“羊了个羊”的消除玩法遇上物理引擎的重力掉落,会碰撞出怎样的火花?本文将带你手把手使用 Matter.js 2D 物理引擎配合 HTML5 Canvas,仅用 300 行代码实现一个自带物理碰撞、重力掉落、堆叠效果的消除小游戏。告别枯燥的网格布局,让卡牌“动”起来!


一、 创意缘起:为什么是物理版?

传统的“羊了个羊”类三消游戏,卡牌通常是静态层叠的,点击上层卡牌后,下层卡牌露出。虽然经典,但缺乏动态交互的爽快感。

如果我们给每一张卡牌加上实体(Body)重力,让它们像积木一样堆叠在一起,会有什么效果?

  1. 动态布局:卡牌不再死板地排列,而是自然散落或堆成金字塔。
  2. 交互反馈:抽取底层卡牌时,上层卡牌会因为重力失去支撑而发生物理崩塌,视觉冲击力极强。
  3. 技术挑战:如何高性能地渲染几十上百个物理实体?如何处理点击拾取?

今天我们就用Matter.js来挑战这个创意。

二、 技术选型与架构

2.1 核心库选择

  • 物理引擎:Matter.js
    • 理由:最流行的 Web 2D 物理引擎,稳定、文档齐全,自带轻量级渲染器(Render),非常适合快速原型开发和轻量级游戏。
  • 渲染层:HTML5 Canvas
    • 理由:Matter.js 自带的 Render 基于 Canvas,足以应对数百个刚体的渲染,且修改绘制逻辑(如贴图、文字)非常方便。

2.2 核心逻辑架构

我们使用典型的游戏循环架构,物理模拟与渲染同步进行。

Click Tile

Hit

Match

Full

Update Loop

Engine Update

Render Trace

Custom Draw (Emoji/Texture)

Game Init

Matter.js Engine Setup

Create World Bounds

Generate Tiles (Bodies)

Game Loop (Runner)

User Interaction

Raycast / Query

Remove from World

Add to UI Slot

Check Match-3

Eliminate & Effect

Game Over

三、 核心代码实现

3.1 初始化物理世界

首先,我们需要创建一个物理世界,并设定重力。为了让掉落感更沉重、更爽快,我们将 Y 轴生力调大一点。

constEngine=Matter.Engine,Render=Matter.Render,Runner=Matter.Runner,Bodies=Matter.Bodies,Composite=Matter.Composite;constengine=Engine.create();// 调整重力,默认是 1,调到 1.2 让掉落更迅速engine.gravity.y=1.2;constrender=Render.create({element:document.body,engine:engine,options:{width:window.innerWidth,height:window.innerHeight,wireframes:false,// 关闭线框模式,使用颜色填充background:'#cce8cf'}});Render.run(render);construnner=Runner.create();Runner.run(runner,engine);

3.2 生成卡牌实体

卡牌本质上就是矩形刚体(Rectangle Body)。这里有一个技巧:为了让它看起来像圆角卡牌,我们使用chamfer属性。

同时,我们给每个 Body 绑定一个自定义属性gameType,用于后续判断是否消除。

functioncreateTile(x,y,typeIndex){consttile=Bodies.rectangle(x,y,50,50,{chamfer:{radius:8},// 圆角效果render:{fillStyle:'#f5f5f5',// 卡牌底色strokeStyle:'#8d6e63',// 描边lineWidth:2}});tile.gameType=typeIndex;// 绑定类型数据returntile;}// 金字塔式生成for(letr=0;r<5;r++){for(letc=0;c<=r;c++){// 计算坐标,错位堆叠constx=window.innerWidth/2+(c-r/2)*55;consty=150+r*55;consttile=createTile(x,y,Math.floor(Math.random()*6));Composite.add(engine.world,tile);}}

3.3 自定义渲染(绘制 Emoji)

Matter.js 默认只能渲染颜色或图片贴图。如果想直接显示 Emoji(🥕, 🐑),我们需要 Hook 它的渲染循环,在afterRender事件中直接操作 Canvas Context。

Matter.Events.on(render,'afterRender',function(){constctx=render.context;ctx.font='30px Arial';ctx.textAlign='center';ctx.textBaseline='middle';constbodies=Composite.allBodies(engine.world);bodies.forEach(body=>{// 排除墙壁和地面,只渲染有 gameType 的卡牌if(body.gameType!==undefined){const{x,y}=body.position;// 获取刚体中心实时坐标// 随刚体移动绘制 Emojictx.fillStyle='#000';ctx.fillText(TYPES[body.gameType],x,y+2);}});});

🔥 重点解析:这是 Canvas 游戏开发常用的技巧。物理引擎只负责计算 Position 和 Angle,渲染层完全可以由我们接管。这样既享受了物理计算,又拥有了 Canvas 的绘图灵活性。

3.4 交互与射线检测

Matter.js 提供了Matter.Query.point类似于 Unity 的 Raycast,用于检测鼠标位置下的刚体。

// 监听鼠标按下Matter.Events.on(mouse,"mousedown",(event)=>{// 获取所有卡牌constallTiles=Composite.allBodies(engine.world).filter(b=>b.gameType!==undefined);// 射线检测constclickedBodies=Matter.Query.point(allTiles,event.mouse.position);if(clickedBodies.length>0){// 获取最上层的一个consttarget=clickedBodies[0];pickTile(target);}});

3.5 消除逻辑

当卡牌被点击后,我们需要做两件事:

  1. 从物理世界移除Composite.remove(world, body)。只要移除了,上面的卡牌就会因为失去支撑而自然掉落——这就是物理版的精髓!
  2. 加入 UI 槽位:将数据转移到逻辑数组slots中,并检查三消。
functionpickTile(body){// 1. 物理移除Composite.remove(engine.world,body);// 2. 逻辑加入槽位addToSlot(body.gameType);}functioncheckEliminate(){// 简单的数组匹配逻辑letcount=1;for(leti=1;i<slots.length;i++){if(slots[i]===slots[i-1]){count++;if(count===3){// 触发消除,移除 i, i-1, i-2slots.splice(i-2,3);renderUI();// 更新 UIreturn;}}else{count=1;}}}

四、 性能与体验优化

4.1 刚体休眠(Sleeping)

如果场景中有几百个方块,一直计算碰撞极其消耗 CPU。Matter.js 默认开启enableSleeping。当物体静止一段时间后,引擎会停止该物体的物理计算,直到它被撞击。
在初始化时确保开启(默认通常开启):

// engine.enableSleeping = true;

但在消除游戏中,我们需要频繁唤醒,所以通常不需要手动干预,Matter.js 处理得很好。

4.2 手机端适配

Matter.js 的MouseConstraint在移动端可能需要处理touchstart事件兼容。本例中我们直接使用了 Matter.Mouse 模块,它内部已经处理了 DOM 事件的归一化,但在真机调试时,注意 Canvas 的touch-action: none防止页面滚动。

五、 总结

不到 300 行代码,我们就实现了一个具备以下特性的游戏原型:

  • 真实物理反馈:卡牌掉落、碰撞、堆叠。
  • 自定义渲染:Canvas 绘制 Emoji。
  • 完整游戏闭环:点击 -> 拾取 -> 消除 -> 胜负判定。

Matter.js是一个非常强大的 2D 物理引擎,它不仅能做游戏,还能做物理特效网页(如掉落的彩带、重力感应的 Logo)。希望这篇教程能给你带来灵感,去创造更有趣的交互体验!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 16:29:43

用Z-Image-Turbo做了个AI绘画项目,全过程公开

用Z-Image-Turbo做了个AI绘画项目&#xff0c;全过程公开 在本地跑通一个真正能用的文生图模型&#xff0c;到底有多难&#xff1f; 我试过手动下载30GB权重、被CUDA版本折磨到重装系统、为中文提示词失效反复调试CLIP分词器……直到遇见这个预置全部权重的Z-Image-Turbo镜像—…

作者头像 李华
网站建设 2026/4/16 12:56:48

YOLOv13模型导出TensorRT引擎,提速三倍不是梦

YOLOv13模型导出TensorRT引擎&#xff0c;提速三倍不是梦 在边缘AI部署实践中&#xff0c;一个常被低估却影响深远的瓶颈悄然浮现&#xff1a;模型推理速度卡在“够用”和“真快”之间。你是否经历过这样的场景——YOLOv13在PyTorch下跑出2.98ms延迟&#xff0c;已属优秀&…

作者头像 李华
网站建设 2026/4/16 14:27:09

实时对话能实现吗?Live Avatar流式生成测试

实时对话能实现吗&#xff1f;Live Avatar流式生成测试 数字人技术正从“能动”迈向“能聊”&#xff0c;而真正的实时对话体验&#xff0c;需要突破模型规模、显存瓶颈与推理延迟三重关卡。Live Avatar——由阿里联合多所高校开源的14B参数级数字人模型&#xff0c;宣称支持“…

作者头像 李华
网站建设 2026/4/16 12:33:06

GPT-OSS-20B金融场景应用:智能投研系统搭建

GPT-OSS-20B金融场景应用&#xff1a;智能投研系统搭建 你是不是也遇到过这些情况&#xff1a; 每天要翻几十份PDF研报&#xff0c;却找不到关键数据点&#xff1b;上市公司财报一出&#xff0c;团队要花两三天才能整理出核心指标对比&#xff1b;行业新闻刷屏&#xff0c;但…

作者头像 李华
网站建设 2026/4/16 12:41:45

SSH隧道访问技巧,远程调试FSMN-VAD服务

SSH隧道访问技巧&#xff0c;远程调试FSMN-VAD服务 在实际语音处理项目中&#xff0c;我们经常需要在服务器上部署离线VAD&#xff08;Voice Activity Detection&#xff09;服务进行本地调试或团队协作。但受限于云平台的安全策略&#xff0c;Web服务默认无法直接对外暴露端口…

作者头像 李华
网站建设 2026/4/16 12:41:29

GPEN镜像快速上手:测试图+自定义图都能修

GPEN镜像快速上手&#xff1a;测试图自定义图都能修 你是不是也遇到过这些情况&#xff1a;老照片泛黄模糊、手机拍的人像有噪点、证件照不够清晰、社交平台上传的自拍照细节丢失&#xff1f;别急着找修图师&#xff0c;也别在PS里折腾半天——现在有一套开箱即用的人像修复方…

作者头像 李华