【OpenHarmony/HarmonyOs 】平抛运动 2D 与 3D 视图Canvas 动画、轨迹点与视角滑块实践本文基于我的 OpenHarmony/HarmonyOS 项目「物理视界 PhysicsVision」整理。项目中的「平抛运动」模型不仅有 2D 抛物线轨迹还提供了 3D 视图、视角滑块、轨迹点记录、速度箭头和播放控制。这一篇对应“全新视觉与交互体验”和“端侧 AI/端侧计算能力”的方向重点讲如何用 ArkTS Canvas 做动态物理模拟。⚽一、为什么平抛运动适合做成动态模型平抛运动是高中物理中的经典模型。它有两个方向水平方向匀速直线运动竖直方向自由落体运动。课本上通常给公式xv0ty1/2gt²但学生真正难理解的是为什么水平速度不变竖直速度却越来越大轨迹为什么是抛物线所以项目把它做成 Canvas 动画让用户看到小球从平台飞出、轨迹逐渐形成、速度箭头实时变化。二、核心状态设计平抛页面中定义了这些状态Statev0: number 10StateisPlaying: boolean falseStatetime: number 0StateposX: number 0StateposY: number 0Stateis3D: boolean falseStatecamAngle: number 0.6这些状态分别表示初速度是否播放当前时间水平位移竖直下落位移当前是否为 3D 视图3D 摄像机角度。通过这些状态页面可以同时管理物理计算、动画播放和视角切换。三、轨迹点结构项目定义了一个简单接口interfaceProjPoint{x:numbery:number}并用数组保存轨迹private points: ProjPoint[][]每一帧计算出当前位置后把点加入轨迹数组。这样 Canvas 就能绘制历史路径而不只是显示当前小球位置。四、动画播放16ms 定时刷新启动动画的方法如下startAnimation(): void {if(this.timerId ! -1)returnthis.time 0this.posX 0this.posY 0this.points []this.isPlaying truethis.timerId setInterval(() {this.time 0.03this.posX this.v0 *this.timethis.posY 0.5*this.gravity *this.time *this.time let p: ProjPoint { x:this.posX, y:this.posY }this.points.push(p)if(this.canvasReady)this.redraw() },16) }这里的核心就是公式this.posX this.v0 *this.timethis.posY 0.5*this.gravity *this.time *this.time每 16ms 刷新一次接近 60fps 的动画体验。五、生命周期清理避免定时器泄漏页面退出时清理定时器aboutToDisappear(): void {if(this.timerId ! -1) { clearInterval(this.timerId)this.timerId -1} }这是动画页面必须注意的细节。如果不清理用户离开页面后定时器还在跑会浪费资源也可能导致状态异常。六、2D 绘制平台、网格、轨迹、小球2D 绘制方法中先画背景、平台和地面ctx.clearRect(0,0, w, h) ctx.fillStyle this.canvasBg() ctx.fillRect(0,0, w, h) ctx.fillStyle#DFE6E9ctx.strokeStyle this.wireColor() ctx.lineWidth3ctx.beginPath() ctx.rect(0, offsetY -10, offsetX 10, h - offsetY 10) ctx.fill() ctx.stroke()再绘制轨迹if(this.points.length 1) { ctx.strokeStyle #4D96FF ctx.lineWidth 2ctx.setLineDash([4, 4])ctx.beginPath()for(leti 0; i this.points.length; i) {letpx this.points[i].x*scaleF offsetXletpy this.points[i].y*scaleF offsetYif(i0) ctx.moveTo(px,py)elsectx.lineTo(px,py)} ctx.stroke()ctx.setLineDash([])}虚线轨迹让运动路径更清晰。七、速度箭头拆分水平和竖直方向播放时显示水平和竖直速度箭头if(this.isPlaying) { ctx.strokeStyle #1A73E8 ctx.beginPath()ctx.moveTo(ballX 18,ballY)ctx.lineTo(ballX 45,ballY)ctx.stroke()letvyLen Math.min(this.posY*2,50)if(vyLen 5) { ctx.strokeStyle #FF6D00 ctx.beginPath()ctx.moveTo(ballX,ballY 18)ctx.lineTo(ballX,ballY 18 vyLen)ctx.stroke()} }蓝色表示水平速度橙色表示竖直方向变化。学生可以直观看到水平速度保持竖直速度越来越明显。八、3D 视图用投影函数模拟空间感项目中并没有引入 Three.js而是用 Canvas 自己做简单 3D 投影proj(x3d:number,y3d:number,z3d:number):number[] {letc Math.cos(this.camAngle)lets Math.sin(this.camAngle)letrx x3d * c - z3d * sletrz x3d * s z3d * c 400letf 480letsc f / rzreturn[this.cw/2 rx * sc,this.ch*0.55- y3d * sc, sc] }这段代码做了三个步骤根据视角旋转坐标加上景深距离通过透视比例映射到屏幕。虽然是简化 3D但对教学展示已经很有效。九、视角滑块让用户主动观察3D 模式下显示视角滑块Slider({value:this.camAngle*100,min: 0,max: 628,step: 5 }).layoutWeight(1).trackColor($r(app.color.slider_track)) .selectedColor(#4D96FF).onChange((v:number) { this.camAngle v/100if(this.canvasReady) this.redraw()})用户拖动滑块后3D 场景实时变化。这让模型从“看动画”变成“操作实验”。十、总结平抛运动页面是项目中很典型的“端侧物理模拟”案例。它没有请求网络也没有调用外部 AI而是用本地公式、Canvas 绘制和状态更新完成了动态演示。这篇文章对应的主题是全新视觉与交互体验 端侧计算能力。对 CSDN 读者来说它能展示 OpenHarmony/HarmonyOS 不只适合做表单和列表也能做有动画、有交互、有物理逻辑的学习应用。