如何灵活创建矩形、三角形等多类型形状对象以适配z-buffer程序
实现方案
核心采用统一接口+多态的设计思路,抽离所有形状的公共属性和方法到基类,不同形状独立实现自己的点检测逻辑,既保留矩形直接创建的便利性,也支持扩展三角形等任意形状,原有z-buffer渲染逻辑不需要做任何修改。
具体实现步骤
1. 抽离公共形状基类
把所有形状都有的颜色、z轴深度两个公共属性放到基类,同时定义所有形状必须实现的点是否在形状内的接口:
class Shape { /** @member {Object} RGB颜色值 */ color; /** @member {Number} z轴深度值 */ z; constructor(props) { this.color = props.color; this.z = props.z ?? 0; } /** * 点是否在当前形状内的接口,所有子类必须实现 * @param {Number} px 点x坐标 * @param {Number} py 点y坐标 * @return {Boolean} */ isPointInside(px, py) { throw new Error('子类必须实现isPointInside方法'); } }
2. 改造原有的Box类继承基类
原有Box的创建逻辑完全不变,只需要继承基类,把原来的pointInBox方法改名为统一接口名即可:
class Box extends Shape { /** @member {Object} 左上角坐标x,y */ position; /** @member {Object} 尺寸width, height */ size; constructor(props) { // 把z值传给父类 super({ color: props.color, z: props.position.z }); this.position = { x: props.position.x, y: props.position.y }; this.size = props.size; } isPointInside(px, py) { return this.position.x < px && this.position.x + this.size.width > px && this.position.y < py && this.position.y + this.size.height > py; } }
3. 新增Triangle三角形类
按照同样的规范实现三角形类,点检测用叉积法判断:
class Triangle extends Shape { /** @member {Array} 三个顶点的x,y坐标数组 */ points; constructor(props) { super({ color: props.color, z: props.z }); this.points = props.points; } // 叉积法判断点是否在三角形内 isPointInside(px, py) { const [p1, p2, p3] = this.points; const cross = (v1x, v1y, v2x, v2y) => v1x * v2y - v1y * v2x; const d1 = cross(px - p1.x, py - p1.y, p2.x - p1.x, p2.y - p1.y); const d2 = cross(px - p2.x, py - p2.y, p3.x - p2.x, p3.y - p2.y); const d3 = cross(px - p3.x, py - p3.y, p1.x - p3.x, p1.y - p3.y); const hasNeg = (d1 < 0) || (d2 < 0) || (d3 < 0); const hasPos = (d1 > 0) || (d2 > 0) || (d3 > 0); return !(hasNeg && hasPos); } }
使用示例
原来的Box创建方式完全不变,同时可以自由插入三角形实例,统一放在shapes数组里供z-buffer使用:
const shapes = [ // 原有Box创建逻辑完全不变 new Box({ position: { x: 50, y: 50, z: 10 }, size: { width: 150, height: 50 }, color: { r: 255, g: 0, b:0 } }), new Box({ position: { x: 80, y: 30, z: 5 }, size: { width: 10, height: 150 }, color: { r: 0, g: 255, b:0 } }), new Box({ position: { x: 70, y: 70, z: 8 }, size: { width: 50, height: 40 }, color: { r: 0, g: 0, b: 255 } }), // 新增三角形实例 new Triangle({ z: 15, points: [ {x: 200, y: 50}, {x: 250, y: 150}, {x: 150, y: 150} ], color: {r: 255, g: 255, b: 0} }) ]; console.log({ shapes });
配套CSS代码保持不变即可:
.as-console-wrapper { min-height: 100%!important; top: 0; }
方案优势
- 完全兼容原有逻辑:原有Box的创建代码不需要任何修改,保留直接创建矩形的便利性
- 扩展性极强:后续需要新增圆形、多边形等其他形状,只需要继承Shape类实现
isPointInside方法即可 - 无需修改z-buffer核心逻辑:渲染时统一遍历shapes数组,按z值排序后调用
isPointInside判断像素归属,不需要关心具体形状类型 - 无额外性能开销:每个形状的点检测都是对应最优实现,没有拼接三角形的额外计算成本
内容的提问来源于stack exchange,提问作者KillerSheltie
相关产品推荐
相关产品推荐

