原型继承适用于定义可复用的行为模板,而非管理运行时精灵对象族;应将行为逻辑挂载于prototype,状态数据存于实例自身,用结构化数组、id查表与位掩码实现高性能异构精灵架构。

原型继承在Canvas游戏引擎中不适用于管理运行时精灵对象族,它真正适合的是定义可复用的模板逻辑,而非构建实体关系或状态树。要实现高度解耦的异构精灵对象族,关键不是靠Object.setPrototypeOf或new Sprite()链式继承,而是把“行为模板”和“数据实例”彻底分开。
用原型封装不可变行为逻辑
所有共享方法(如坐标更新、帧动画步进、基础碰撞判定)应统一挂载在构造函数的prototype上,避免每个实例重复创建函数:
- 定义
SpriteBase.prototype.update = function(dt) { this.x += this.vx * dt; },而不是在构造函数里写this.update = function() {...} - 用
Object.create(null)创建精简原型链,跳过Object.prototype,减少属性查找开销 - 所有可变状态——
this.x、this.frameIndex、this.visible——必须放在实例自身,绝不能塞进原型
用扁平数组+ID查表替代实例化树
成百上千个精灵不该靠new Player()、new Particle()分散创建。高性能做法是:
用户要生成可打印的中文字帖/练习纸、导出多页 A4 PDF 报告,或把 SVG 设计稿零误差还原到 Canvas 时使用。本技能是「Canvas 内容工厂闭环」的总控,编排:网格渲染引擎(13 种教育网格+拼音标注) → 多页 PDF 导出(A4 合成) → SVG 精准复刻(坐标误差<0.001px)。触发词:生成字帖、练习纸、导出 PDF、SVG 转 Canvas、印刷级还原、A4 报告、米字格田字格。
- 用
Float32Array存储位置、缩放、旋转等数值,内存连续,利于CPU缓存命中 - 每个精灵只是一个整数ID,通过ID查表获取当前状态,而非持有完整对象引用
- 可见性、激活态、是否正在播放动画等布尔标记,打包进一个整数的位掩码(bitmask),支持批量位运算与快速筛选
父子关系用显式引用,不用原型链
需要层级关系的场景(如炮塔随战车旋转、UI子元素跟随父容器缩放),正确方式是:
- 每个精灵实例上存
parent: number | null和children: number[],ID指向同一数组中的其他项 - 更新时按拓扑顺序遍历(如DFS),用父级世界变换 × 局部偏移计算子级最终位置
- 绝对避免让子精灵的
__proto__指向父类原型——这会破坏数据局部性,拖慢V8内联缓存
渲染与交互完全脱离原型体系
原型对绘制优化毫无帮助。真正起效的是结构化合批与GPU友好设计:
- 把同图集、同着色器、同混合模式的精灵归入同一
SpriteBatch,单次WebGL调用绘制数百个 - 用GPU实例化(
gl.drawElementsInstanced),顶点着色器内通过instanceID查表取位置/颜色/UV - 交互检测走空间划分(网格桶、四叉树),不是靠原型链向上冒泡或遍历继承链
不复杂但容易忽略:原型只管“怎么算”,不管“谁是谁”。把模板逻辑压进prototype,把运行时数据交给结构化数组,把关系管理交给ID引用——这才是Canvas下真正可扩展、可预测、可调试的异构精灵架构。










