850 lines
33 KiB
JavaScript
850 lines
33 KiB
JavaScript
/**
|
|
* AlignmentUtils - 精灵对齐工具类
|
|
* 文件: client/js/01_SubGame/codes/game/utils/AlignmentUtils.js
|
|
*
|
|
* 🎯 设计目的:
|
|
* 提供统一的精灵对齐计算方法,简化UI布局代码
|
|
*
|
|
* 🔑 核心原则:
|
|
* 1. 精灵锚点永远在左上角,无法更改
|
|
* 2. 所有对齐计算都基于锚点位置
|
|
* 3. 支持常见的9种对齐方式(左上/中上/右上/左中/中中/右中/左下/中下/右下)
|
|
* 4. 支持偏移量微调
|
|
*
|
|
* 📐 坐标系统:
|
|
* - X轴:从左到右递增
|
|
* - Y轴:从上到下递增
|
|
* - 精灵锚点:左上角 (0, 0)
|
|
*
|
|
* @author JinXian Team
|
|
* @version 1.0.0
|
|
* @since 2025-12-30
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
var AlignmentUtils = {
|
|
VERSION: '1.0.0',
|
|
|
|
/**
|
|
* 对齐常量
|
|
*/
|
|
ALIGN: {
|
|
// 水平对齐
|
|
LEFT: 'left', // 左对齐
|
|
CENTER: 'center', // 水平居中
|
|
RIGHT: 'right', // 右对齐
|
|
|
|
// 垂直对齐
|
|
TOP: 'top', // 顶部对齐
|
|
MIDDLE: 'middle', // 垂直居中
|
|
BOTTOM: 'bottom' // 底部对齐
|
|
},
|
|
|
|
/**
|
|
* 将精灵对齐到目标矩形区域
|
|
*
|
|
* 🔑 核心:精灵的锚点永远在左上角,此方法计算锚点应放置的位置
|
|
*
|
|
* @param {Object} target - 目标矩形区域
|
|
* @param {number} target.x - 目标区域左上角X坐标
|
|
* @param {number} target.y - 目标区域左上角Y坐标
|
|
* @param {number} target.width - 目标区域宽度
|
|
* @param {number} target.height - 目标区域高度
|
|
*
|
|
* @param {Object} sprite - 精灵信息(精灵锚点固定在左上角)
|
|
* @param {number} sprite.width - 精灵宽度
|
|
* @param {number} sprite.height - 精灵高度
|
|
*
|
|
* @param {string} horizontalAlign - 水平对齐方式: 'left'|'center'|'right'
|
|
* @param {string} verticalAlign - 垂直对齐方式: 'top'|'middle'|'bottom'
|
|
*
|
|
* @param {Object} [offset] - 偏移量(可选)
|
|
* @param {number} [offset.x=0] - X轴偏移
|
|
* @param {number} [offset.y=0] - Y轴偏移
|
|
*
|
|
* @returns {Object} 精灵锚点位置(左上角) {x, y}
|
|
*
|
|
* @example
|
|
* // 将文本标签对齐到矩形框左下角
|
|
* var labelPos = AlignmentUtils.alignTo(
|
|
* { x: 10, y: 10, width: 60, height: 60 }, // 矩形框区域
|
|
* { width: 40, height: 20 }, // 标签大小
|
|
* 'left', // 左对齐
|
|
* 'bottom', // 底部对齐
|
|
* { x: 0, y: 5 } // 向下偏移5px
|
|
* );
|
|
* // 返回: { x: 10, y: 75 } (矩形底部 + 偏移,注意精灵锚点在左上角)
|
|
*
|
|
* @example
|
|
* // 将图标对齐到矩形框右下角
|
|
* var iconPos = AlignmentUtils.alignTo(
|
|
* { x: 10, y: 10, width: 60, height: 60 }, // 矩形框区域
|
|
* { width: 30, height: 30 }, // 图标大小
|
|
* 'right', // 右对齐
|
|
* 'bottom', // 底部对齐
|
|
* { x: -5, y: 5 } // 向左偏移5px,向下偏移5px
|
|
* );
|
|
* // 返回: { x: 35, y: 75 } (矩形右边界 - 图标宽度 - 5px,精灵锚点在左上角)
|
|
*/
|
|
alignTo: function(target, sprite, horizontalAlign, verticalAlign, offset) {
|
|
offset = offset || {};
|
|
var offsetX = offset.x || 0;
|
|
var offsetY = offset.y || 0;
|
|
|
|
var x, y;
|
|
|
|
// 计算水平位置
|
|
switch (horizontalAlign) {
|
|
case this.ALIGN.LEFT:
|
|
// 左对齐:精灵左边缘与目标左边缘对齐
|
|
x = target.x;
|
|
break;
|
|
case this.ALIGN.CENTER:
|
|
// 水平居中:精灵中心与目标中心对齐
|
|
// 🔑 精灵的锚点永远在左上角,所以需要减去精灵宽度的一半
|
|
x = target.x + (target.width - sprite.width) / 2;
|
|
break;
|
|
case this.ALIGN.RIGHT:
|
|
// 右对齐:精灵右边缘与目标右边缘对齐
|
|
// 🔑 精灵的锚点永远在左上角,所以需要减去精灵宽度
|
|
x = target.x + target.width - sprite.width;
|
|
break;
|
|
default:
|
|
console.warn('[AlignmentUtils] 未知的水平对齐方式:', horizontalAlign);
|
|
x = target.x;
|
|
}
|
|
|
|
// 计算垂直位置
|
|
switch (verticalAlign) {
|
|
case this.ALIGN.TOP:
|
|
// 顶部对齐:精灵顶边与目标顶边对齐
|
|
y = target.y;
|
|
break;
|
|
case this.ALIGN.MIDDLE:
|
|
// 垂直居中:精灵中心与目标中心对齐
|
|
// 🔑 精灵的锚点永远在左上角,所以需要减去精灵高度的一半
|
|
y = target.y + (target.height - sprite.height) / 2;
|
|
break;
|
|
case this.ALIGN.BOTTOM:
|
|
// 底部对齐:精灵底边与目标底边对齐
|
|
// 🔑 精灵的锚点永远在左上角,所以需要加上目标高度
|
|
y = target.y + target.height;
|
|
break;
|
|
default:
|
|
console.warn('[AlignmentUtils] 未知的垂直对齐方式:', verticalAlign);
|
|
y = target.y;
|
|
}
|
|
|
|
// 应用偏移
|
|
return {
|
|
x: x + offsetX,
|
|
y: y + offsetY
|
|
};
|
|
},
|
|
|
|
/**
|
|
* 将精灵对齐到目标矩形的左下角(快捷方法)
|
|
*
|
|
* 🔑 注意:精灵的锚点永远在左上角
|
|
*
|
|
* @param {Object} target - 目标矩形区域
|
|
* @param {number} target.x - 目标区域左上角X坐标
|
|
* @param {number} target.y - 目标区域左上角Y坐标
|
|
* @param {number} target.width - 目标区域宽度
|
|
* @param {number} target.height - 目标区域高度
|
|
*
|
|
* @param {Object} sprite - 精灵大小(锚点固定在左上角)
|
|
* @param {number} sprite.width - 精灵宽度
|
|
* @param {number} sprite.height - 精灵高度
|
|
*
|
|
* @param {Object} [offset] - 偏移量
|
|
* @param {number} [offset.x=0] - X偏移
|
|
* @param {number} [offset.y=0] - Y偏移
|
|
*
|
|
* @returns {Object} 精灵锚点位置(左上角) {x, y}
|
|
*
|
|
* @example
|
|
* // 将文本标签对齐到容器左下角
|
|
* var pos = AlignmentUtils.alignBottomLeft(
|
|
* { x: 10, y: 10, width: 60, height: 60 }, // 容器区域
|
|
* { width: 40, height: 20 }, // 标签大小
|
|
* { x: 0, y: 5 } // 向下偏移5px
|
|
* );
|
|
*/
|
|
alignBottomLeft: function(target, sprite, offset) {
|
|
return this.alignTo(target, sprite, this.ALIGN.LEFT, this.ALIGN.BOTTOM, offset);
|
|
},
|
|
|
|
/**
|
|
* 将精灵对齐到目标矩形的右下角(快捷方法)
|
|
*
|
|
* 🔑 注意:精灵的锚点永远在左上角,右对齐时会自动减去精灵宽度
|
|
*
|
|
* @param {Object} target - 目标矩形区域
|
|
* @param {Object} sprite - 精灵大小(锚点固定在左上角)
|
|
* @param {Object} [offset] - 偏移量
|
|
* @returns {Object} 精灵锚点位置(左上角) {x, y}
|
|
*
|
|
* @example
|
|
* // 将图标对齐到容器右下角
|
|
* var pos = AlignmentUtils.alignBottomRight(
|
|
* { x: 10, y: 10, width: 60, height: 60 }, // 容器区域
|
|
* { width: 30, height: 30 }, // 图标大小
|
|
* { x: -5, y: 5 } // 向左偏移5px,向下偏移5px
|
|
* );
|
|
*/
|
|
alignBottomRight: function(target, sprite, offset) {
|
|
return this.alignTo(target, sprite, this.ALIGN.RIGHT, this.ALIGN.BOTTOM, offset);
|
|
},
|
|
|
|
/**
|
|
* 将精灵对齐到目标矩形的顶部居中(快捷方法)
|
|
*
|
|
* 🔑 注意:精灵的锚点永远在左上角,居中时会自动减去精灵宽度的一半
|
|
*
|
|
* @param {Object} target - 目标矩形区域
|
|
* @param {Object} sprite - 精灵大小(锚点固定在左上角)
|
|
* @param {Object} [offset] - 偏移量
|
|
* @returns {Object} 精灵锚点位置(左上角) {x, y}
|
|
*/
|
|
alignTopCenter: function(target, sprite, offset) {
|
|
return this.alignTo(target, sprite, this.ALIGN.CENTER, this.ALIGN.TOP, offset);
|
|
},
|
|
|
|
/**
|
|
* 将精灵对齐到目标矩形的底部居中(快捷方法)
|
|
*
|
|
* 🔑 注意:精灵的锚点永远在左上角,居中时会自动减去精灵宽度的一半
|
|
*
|
|
* @param {Object} target - 目标矩形区域
|
|
* @param {Object} sprite - 精灵大小(锚点固定在左上角)
|
|
* @param {Object} [offset] - 偏移量
|
|
* @returns {Object} 精灵锚点位置(左上角) {x, y}
|
|
*/
|
|
alignBottomCenter: function(target, sprite, offset) {
|
|
return this.alignTo(target, sprite, this.ALIGN.CENTER, this.ALIGN.BOTTOM, offset);
|
|
},
|
|
|
|
/**
|
|
* 将精灵对齐到目标矩形的中心(快捷方法)
|
|
*
|
|
* 🔑 注意:精灵的锚点永远在左上角,居中时会自动减去精灵宽度和高度的一半
|
|
*
|
|
* @param {Object} target - 目标矩形区域
|
|
* @param {Object} sprite - 精灵大小(锚点固定在左上角)
|
|
* @param {Object} [offset] - 偏移量
|
|
* @returns {Object} 精灵锚点位置(左上角) {x, y}
|
|
*/
|
|
alignCenter: function(target, sprite, offset) {
|
|
return this.alignTo(target, sprite, this.ALIGN.CENTER, this.ALIGN.MIDDLE, offset);
|
|
},
|
|
|
|
// ============================================================================
|
|
// 角落对齐方法 - 精灵的角与目标的角重合
|
|
// ============================================================================
|
|
|
|
/**
|
|
* 将精灵的左上角对齐到目标的左上角
|
|
*
|
|
* 🔑 注意:精灵的锚点永远在左上角
|
|
* 💡 角落对齐:精灵的角与目标的角重合(不是边缘对齐)
|
|
*
|
|
* @param {Object} target - 目标矩形区域
|
|
* @param {Object} sprite - 精灵大小(锚点固定在左上角)
|
|
* @param {Object} [offset] - 偏移量
|
|
* @returns {Object} 精灵锚点位置(左上角) {x, y}
|
|
*
|
|
* @example
|
|
* // 将子元素的左上角与容器的左上角重合
|
|
* var pos = AlignmentUtils.alignCornerTopLeft(
|
|
* { x: 10, y: 10, width: 100, height: 100 },
|
|
* { width: 30, height: 30 }
|
|
* );
|
|
* // 返回: { x: 10, y: 10 }
|
|
*/
|
|
alignCornerTopLeft: function(target, sprite, offset) {
|
|
offset = offset || {};
|
|
return {
|
|
x: target.x + (offset.x || 0),
|
|
y: target.y + (offset.y || 0)
|
|
};
|
|
},
|
|
|
|
/**
|
|
* 将精灵的右上角对齐到目标的右上角
|
|
*
|
|
* 🔑 注意:精灵的锚点永远在左上角,需要减去精灵宽度
|
|
* 💡 角落对齐:精灵的角与目标的角重合
|
|
*
|
|
* @param {Object} target - 目标矩形区域
|
|
* @param {Object} sprite - 精灵大小(锚点固定在左上角)
|
|
* @param {Object} [offset] - 偏移量
|
|
* @returns {Object} 精灵锚点位置(左上角) {x, y}
|
|
*
|
|
* @example
|
|
* var pos = AlignmentUtils.alignCornerTopRight(
|
|
* { x: 10, y: 10, width: 100, height: 100 },
|
|
* { width: 30, height: 30 }
|
|
* );
|
|
* // 返回: { x: 80, y: 10 } (10 + 100 - 30)
|
|
*/
|
|
alignCornerTopRight: function(target, sprite, offset) {
|
|
offset = offset || {};
|
|
return {
|
|
x: target.x + target.width - sprite.width + (offset.x || 0),
|
|
y: target.y + (offset.y || 0)
|
|
};
|
|
},
|
|
|
|
/**
|
|
* 将精灵的左下角对齐到目标的左下角
|
|
*
|
|
* 🔑 注意:精灵的锚点永远在左上角,需要减去精灵高度
|
|
* 💡 角落对齐:精灵的角与目标的角重合
|
|
*
|
|
* @param {Object} target - 目标矩形区域
|
|
* @param {Object} sprite - 精灵大小(锚点固定在左上角)
|
|
* @param {Object} [offset] - 偏移量
|
|
* @returns {Object} 精灵锚点位置(左上角) {x, y}
|
|
*
|
|
* @example
|
|
* var pos = AlignmentUtils.alignCornerBottomLeft(
|
|
* { x: 10, y: 10, width: 100, height: 100 },
|
|
* { width: 30, height: 30 }
|
|
* );
|
|
* // 返回: { x: 10, y: 80 } (10 + 100 - 30)
|
|
*/
|
|
alignCornerBottomLeft: function(target, sprite, offset) {
|
|
offset = offset || {};
|
|
return {
|
|
x: target.x + (offset.x || 0),
|
|
y: target.y + target.height - sprite.height + (offset.y || 0)
|
|
};
|
|
},
|
|
|
|
/**
|
|
* 将精灵的右下角对齐到目标的右下角
|
|
*
|
|
* 🔑 注意:精灵的锚点永远在左上角,需要减去精灵宽度和高度
|
|
* 💡 角落对齐:精灵的角与目标的角重合
|
|
*
|
|
* @param {Object} target - 目标矩形区域
|
|
* @param {Object} sprite - 精灵大小(锚点固定在左上角)
|
|
* @param {Object} [offset] - 偏移量
|
|
* @returns {Object} 精灵锚点位置(左上角) {x, y}
|
|
*
|
|
* @example
|
|
* var pos = AlignmentUtils.alignCornerBottomRight(
|
|
* { x: 10, y: 10, width: 100, height: 100 },
|
|
* { width: 30, height: 30 }
|
|
* );
|
|
* // 返回: { x: 80, y: 80 }
|
|
*/
|
|
alignCornerBottomRight: function(target, sprite, offset) {
|
|
offset = offset || {};
|
|
return {
|
|
x: target.x + target.width - sprite.width + (offset.x || 0),
|
|
y: target.y + target.height - sprite.height + (offset.y || 0)
|
|
};
|
|
},
|
|
|
|
/**
|
|
* 计算多个精灵水平居中的起始X坐标
|
|
*
|
|
* @param {number} containerWidth - 容器宽度
|
|
* @param {number} totalItemsWidth - 所有项目的总宽度(包括间距)
|
|
* @returns {number} 起始X坐标
|
|
*
|
|
* @example
|
|
* // 3张牌,每张42px,间距5px,容器宽度600px
|
|
* var startX = AlignmentUtils.centerMultipleItems(600, 42 * 3 + 5 * 2);
|
|
* // 返回: 258 ((600 - 136) / 2)
|
|
*/
|
|
centerMultipleItems: function(containerWidth, totalItemsWidth) {
|
|
return (containerWidth - totalItemsWidth) / 2;
|
|
},
|
|
|
|
/**
|
|
* 计算矩形区域的中心点
|
|
*
|
|
* @param {Object} rect - 矩形区域
|
|
* @param {number} rect.x - 左上角X
|
|
* @param {number} rect.y - 左上角Y
|
|
* @param {number} rect.width - 宽度
|
|
* @param {number} rect.height - 高度
|
|
* @returns {Object} 中心点 {x, y}
|
|
*/
|
|
getCenter: function(rect) {
|
|
return {
|
|
x: rect.x + rect.width / 2,
|
|
y: rect.y + rect.height / 2
|
|
};
|
|
},
|
|
|
|
// ============================================================================
|
|
// 精灵ID版本 - 自动获取精灵尺寸
|
|
// ============================================================================
|
|
|
|
/**
|
|
* 将精灵对齐到目标精灵(使用精灵ID,自动获取尺寸)
|
|
*
|
|
* 🔑 核心:精灵的锚点永远在左上角,此方法计算锚点应放置的位置
|
|
* 💡 优点:无需手动获取精灵尺寸,代码更简洁
|
|
*
|
|
* @param {number} targetSpriteId - 目标精灵ID(会自动获取位置和大小)
|
|
* @param {number} spriteId - 要对齐的精灵ID(会自动获取大小)
|
|
* @param {string} horizontalAlign - 水平对齐方式: 'left'|'center'|'right'
|
|
* @param {string} verticalAlign - 垂直对齐方式: 'top'|'middle'|'bottom'
|
|
* @param {Object} [offset] - 偏移量(可选)
|
|
* @param {number} [offset.x=0] - X轴偏移
|
|
* @param {number} [offset.y=0] - Y轴偏移
|
|
*
|
|
* @returns {Object|null} 精灵锚点位置(左上角) {x, y},失败返回null
|
|
*
|
|
* @example
|
|
* // 将座位标签(精灵5678)对齐到头像(精灵1234)左下角
|
|
* var pos = AlignmentUtils.alignSpriteToSprite(
|
|
* 1234, // 目标精灵ID(头像)
|
|
* 5678, // 要对齐的精灵ID(座位标签)
|
|
* 'left', // 左对齐
|
|
* 'bottom', // 底部对齐
|
|
* { x: 0, y: 5 } // 向下偏移5px
|
|
* );
|
|
* if (pos) {
|
|
* SpriteManager.setPosition(5678, pos.x, pos.y);
|
|
* }
|
|
*/
|
|
alignSpriteToSprite: function(targetSpriteId, spriteId, horizontalAlign, verticalAlign, offset) {
|
|
if (typeof SpriteManager === 'undefined') {
|
|
console.error('[AlignmentUtils] SpriteManager 未加载,无法使用 alignSpriteToSprite');
|
|
return null;
|
|
}
|
|
|
|
// 获取目标精灵的位置和大小
|
|
var targetPos = SpriteManager.getPosition(targetSpriteId);
|
|
var targetSize = SpriteManager.getSize(targetSpriteId);
|
|
if (!targetPos || !targetSize) {
|
|
console.error('[AlignmentUtils] 无法获取目标精灵 ' + targetSpriteId + ' 的位置或大小');
|
|
return null;
|
|
}
|
|
|
|
// 获取要对齐的精灵的大小
|
|
var spriteSize = SpriteManager.getSize(spriteId);
|
|
if (!spriteSize) {
|
|
console.error('[AlignmentUtils] 无法获取精灵 ' + spriteId + ' 的大小');
|
|
return null;
|
|
}
|
|
|
|
// 构建目标矩形
|
|
var target = {
|
|
x: targetPos.x,
|
|
y: targetPos.y,
|
|
width: targetSize.width,
|
|
height: targetSize.height
|
|
};
|
|
|
|
// 调用核心对齐方法
|
|
return this.alignTo(target, spriteSize, horizontalAlign, verticalAlign, offset);
|
|
},
|
|
|
|
/**
|
|
* 将精灵对齐到目标精灵的左下角(快捷方法)
|
|
*
|
|
* 🔑 注意:精灵的锚点永远在左上角
|
|
* 💡 自动获取精灵尺寸,无需手动传入
|
|
*
|
|
* @param {number} targetSpriteId - 目标精灵ID
|
|
* @param {number} spriteId - 要对齐的精灵ID
|
|
* @param {Object} [offset] - 偏移量
|
|
* @returns {Object|null} 精灵锚点位置(左上角) {x, y}
|
|
*
|
|
* @example
|
|
* var pos = AlignmentUtils.alignSpriteBottomLeft(1234, 5678, { x: 0, y: 5 });
|
|
* if (pos) SpriteManager.setPosition(5678, pos.x, pos.y);
|
|
*/
|
|
alignSpriteBottomLeft: function(targetSpriteId, spriteId, offset) {
|
|
return this.alignSpriteToSprite(targetSpriteId, spriteId, this.ALIGN.LEFT, this.ALIGN.BOTTOM, offset);
|
|
},
|
|
|
|
/**
|
|
* 将精灵对齐到目标精灵的右下角(快捷方法)
|
|
*
|
|
* 🔑 注意:精灵的锚点永远在左上角,右对齐时会自动减去精灵宽度
|
|
* 💡 自动获取精灵尺寸,无需手动传入
|
|
*
|
|
* @param {number} targetSpriteId - 目标精灵ID
|
|
* @param {number} spriteId - 要对齐的精灵ID
|
|
* @param {Object} [offset] - 偏移量
|
|
* @returns {Object|null} 精灵锚点位置(左上角) {x, y}
|
|
*
|
|
* @example
|
|
* var pos = AlignmentUtils.alignSpriteBottomRight(1234, 5678, { x: -5, y: 5 });
|
|
* if (pos) SpriteManager.setPosition(5678, pos.x, pos.y);
|
|
*/
|
|
alignSpriteBottomRight: function(targetSpriteId, spriteId, offset) {
|
|
return this.alignSpriteToSprite(targetSpriteId, spriteId, this.ALIGN.RIGHT, this.ALIGN.BOTTOM, offset);
|
|
},
|
|
|
|
/**
|
|
* 将精灵对齐到目标精灵的顶部居中(快捷方法)
|
|
*
|
|
* 🔑 注意:精灵的锚点永远在左上角,居中时会自动减去精灵宽度的一半
|
|
* 💡 自动获取精灵尺寸,无需手动传入
|
|
*
|
|
* @param {number} targetSpriteId - 目标精灵ID
|
|
* @param {number} spriteId - 要对齐的精灵ID
|
|
* @param {Object} [offset] - 偏移量
|
|
* @returns {Object|null} 精灵锚点位置(左上角) {x, y}
|
|
*/
|
|
alignSpriteTopCenter: function(targetSpriteId, spriteId, offset) {
|
|
return this.alignSpriteToSprite(targetSpriteId, spriteId, this.ALIGN.CENTER, this.ALIGN.TOP, offset);
|
|
},
|
|
|
|
/**
|
|
* 将精灵对齐到目标精灵的底部居中(快捷方法)
|
|
*
|
|
* 🔑 注意:精灵的锚点永远在左上角,居中时会自动减去精灵宽度的一半
|
|
* 💡 自动获取精灵尺寸,无需手动传入
|
|
*
|
|
* @param {number} targetSpriteId - 目标精灵ID
|
|
* @param {number} spriteId - 要对齐的精灵ID
|
|
* @param {Object} [offset] - 偏移量
|
|
* @returns {Object|null} 精灵锚点位置(左上角) {x, y}
|
|
*/
|
|
alignSpriteBottomCenter: function(targetSpriteId, spriteId, offset) {
|
|
return this.alignSpriteToSprite(targetSpriteId, spriteId, this.ALIGN.CENTER, this.ALIGN.BOTTOM, offset);
|
|
},
|
|
|
|
/**
|
|
* 将精灵对齐到目标精灵的中心(快捷方法)
|
|
*
|
|
* 🔑 注意:精灵的锚点永远在左上角,居中时会自动减去精灵宽度和高度的一半
|
|
* 💡 自动获取精灵尺寸,无需手动传入
|
|
*
|
|
* @param {number} targetSpriteId - 目标精灵ID
|
|
* @param {number} spriteId - 要对齐的精灵ID
|
|
* @param {Object} [offset] - 偏移量
|
|
* @returns {Object|null} 精灵锚点位置(左上角) {x, y}
|
|
*/
|
|
alignSpriteCenter: function(targetSpriteId, spriteId, offset) {
|
|
return this.alignSpriteToSprite(targetSpriteId, spriteId, this.ALIGN.CENTER, this.ALIGN.MIDDLE, offset);
|
|
},
|
|
|
|
// ============================================================================
|
|
// 精灵ID版本 - 角落对齐
|
|
// ============================================================================
|
|
|
|
/**
|
|
* 将精灵的左上角对齐到目标精灵的左上角
|
|
*
|
|
* 🔑 注意:精灵的锚点永远在左上角
|
|
* 💡 角落对齐:精灵的角与目标的角重合
|
|
*
|
|
* @param {number} targetSpriteId - 目标精灵ID
|
|
* @param {number} spriteId - 要对齐的精灵ID
|
|
* @param {Object} [offset] - 偏移量
|
|
* @returns {Object|null} 精灵锚点位置(左上角) {x, y}
|
|
*/
|
|
alignSpriteCornerTopLeft: function(targetSpriteId, spriteId, offset) {
|
|
if (typeof SpriteManager === 'undefined') {
|
|
console.error('[AlignmentUtils] SpriteManager 未加载');
|
|
return null;
|
|
}
|
|
|
|
var targetPos = SpriteManager.getPosition(targetSpriteId);
|
|
var spriteSize = SpriteManager.getSize(spriteId);
|
|
if (!targetPos || !spriteSize) {
|
|
console.error('[AlignmentUtils] 无法获取精灵位置或大小');
|
|
return null;
|
|
}
|
|
|
|
offset = offset || {};
|
|
return {
|
|
x: targetPos.x + (offset.x || 0),
|
|
y: targetPos.y + (offset.y || 0)
|
|
};
|
|
},
|
|
|
|
/**
|
|
* 将精灵的右上角对齐到目标精灵的右上角
|
|
*
|
|
* 🔑 注意:精灵的锚点永远在左上角,需要减去精灵宽度
|
|
* 💡 角落对齐:精灵的角与目标的角重合
|
|
*
|
|
* @param {number} targetSpriteId - 目标精灵ID
|
|
* @param {number} spriteId - 要对齐的精灵ID
|
|
* @param {Object} [offset] - 偏移量
|
|
* @returns {Object|null} 精灵锚点位置(左上角) {x, y}
|
|
*/
|
|
alignSpriteCornerTopRight: function(targetSpriteId, spriteId, offset) {
|
|
if (typeof SpriteManager === 'undefined') {
|
|
console.error('[AlignmentUtils] SpriteManager 未加载');
|
|
return null;
|
|
}
|
|
|
|
var targetPos = SpriteManager.getPosition(targetSpriteId);
|
|
var targetSize = SpriteManager.getSize(targetSpriteId);
|
|
var spriteSize = SpriteManager.getSize(spriteId);
|
|
if (!targetPos || !targetSize || !spriteSize) {
|
|
console.error('[AlignmentUtils] 无法获取精灵位置或大小');
|
|
return null;
|
|
}
|
|
|
|
offset = offset || {};
|
|
return {
|
|
x: targetPos.x + targetSize.width - spriteSize.width + (offset.x || 0),
|
|
y: targetPos.y + (offset.y || 0)
|
|
};
|
|
},
|
|
|
|
/**
|
|
* 将精灵的左下角对齐到目标精灵的左下角
|
|
*
|
|
* 🔑 注意:精灵的锚点永远在左上角,需要减去精灵高度
|
|
* 💡 角落对齐:精灵的角与目标的角重合
|
|
*
|
|
* @param {number} targetSpriteId - 目标精灵ID
|
|
* @param {number} spriteId - 要对齐的精灵ID
|
|
* @param {Object} [offset] - 偏移量
|
|
* @returns {Object|null} 精灵锚点位置(左上角) {x, y}
|
|
*/
|
|
alignSpriteCornerBottomLeft: function(targetSpriteId, spriteId, offset) {
|
|
if (typeof SpriteManager === 'undefined') {
|
|
console.error('[AlignmentUtils] SpriteManager 未加载');
|
|
return null;
|
|
}
|
|
|
|
var targetPos = SpriteManager.getPosition(targetSpriteId);
|
|
var targetSize = SpriteManager.getSize(targetSpriteId);
|
|
var spriteSize = SpriteManager.getSize(spriteId);
|
|
if (!targetPos || !targetSize || !spriteSize) {
|
|
console.error('[AlignmentUtils] 无法获取精灵位置或大小');
|
|
return null;
|
|
}
|
|
|
|
offset = offset || {};
|
|
return {
|
|
x: targetPos.x + (offset.x || 0),
|
|
y: targetPos.y + targetSize.height - spriteSize.height + (offset.y || 0)
|
|
};
|
|
},
|
|
|
|
/**
|
|
* 将精灵的右下角对齐到目标精灵的右下角
|
|
*
|
|
* 🔑 注意:精灵的锚点永远在左上角,需要减去精灵宽度和高度
|
|
* 💡 角落对齐:精灵的角与目标的角重合
|
|
*
|
|
* @param {number} targetSpriteId - 目标精灵ID
|
|
* @param {number} spriteId - 要对齐的精灵ID
|
|
* @param {Object} [offset] - 偏移量
|
|
* @returns {Object|null} 精灵锚点位置(左上角) {x, y}
|
|
*/
|
|
alignSpriteCornerBottomRight: function(targetSpriteId, spriteId, offset) {
|
|
if (typeof SpriteManager === 'undefined') {
|
|
console.error('[AlignmentUtils] SpriteManager 未加载');
|
|
return null;
|
|
}
|
|
|
|
var targetPos = SpriteManager.getPosition(targetSpriteId);
|
|
var targetSize = SpriteManager.getSize(targetSpriteId);
|
|
var spriteSize = SpriteManager.getSize(spriteId);
|
|
if (!targetPos || !targetSize || !spriteSize) {
|
|
console.error('[AlignmentUtils] 无法获取精灵位置或大小');
|
|
return null;
|
|
}
|
|
|
|
offset = offset || {};
|
|
return {
|
|
x: targetPos.x + targetSize.width - spriteSize.width + (offset.x || 0),
|
|
y: targetPos.y + targetSize.height - spriteSize.height + (offset.y || 0)
|
|
};
|
|
},
|
|
|
|
// ============================================================================
|
|
// 批量精灵分布对齐
|
|
// ============================================================================
|
|
|
|
/**
|
|
* 计算多个精灵水平分布的位置
|
|
*
|
|
* 🔑 核心:精灵的锚点永远在左上角
|
|
* 💡 用途:将多个相同大小的精灵水平排列,支持居中/左对齐/右对齐
|
|
*
|
|
* @param {Object} options - 分布选项
|
|
* @param {number} options.anchorX - 锚点X坐标(对齐基准点)
|
|
* @param {number} options.anchorY - 锚点Y坐标(所有精灵的Y坐标)
|
|
* @param {number} options.count - 精灵数量
|
|
* @param {number} options.itemWidth - 每个精灵的宽度
|
|
* @param {number} options.itemHeight - 每个精灵的高度
|
|
* @param {number} [options.spacing=0] - 精灵之间的间距
|
|
* @param {string} [options.anchor='center'] - 对齐方式: 'left'|'center'|'right'
|
|
*
|
|
* @returns {Array<Object>} 每个精灵的位置数组 [{x, y}, ...]
|
|
*
|
|
* @example
|
|
* // 3张牌水平居中排列
|
|
* var positions = AlignmentUtils.distributeHorizontally({
|
|
* anchorX: 640, // 屏幕中心X
|
|
* anchorY: 500, // Y位置
|
|
* count: 3, // 3张牌
|
|
* itemWidth: 62, // 牌宽
|
|
* itemHeight: 86, // 牌高
|
|
* spacing: 0, // 无间距
|
|
* anchor: 'center' // 居中对齐
|
|
* });
|
|
* // 返回: [{x: 547, y: 500}, {x: 609, y: 500}, {x: 671, y: 500}]
|
|
*/
|
|
distributeHorizontally: function(options) {
|
|
var anchorX = options.anchorX || 0;
|
|
var anchorY = options.anchorY || 0;
|
|
var count = options.count || 0;
|
|
var itemWidth = options.itemWidth || 0;
|
|
var itemHeight = options.itemHeight || 0;
|
|
var spacing = options.spacing || 0;
|
|
var anchor = options.anchor || 'center';
|
|
|
|
if (count <= 0) return [];
|
|
|
|
// 计算总宽度
|
|
var totalWidth = count * itemWidth + (count - 1) * spacing;
|
|
|
|
// 计算起始X位置(精灵锚点在左上角)
|
|
var startX;
|
|
switch (anchor) {
|
|
case 'left':
|
|
// 左对齐:第一个精灵的左边缘与锚点对齐
|
|
startX = anchorX;
|
|
break;
|
|
case 'right':
|
|
// 右对齐:最后一个精灵的右边缘与锚点对齐
|
|
startX = anchorX - totalWidth;
|
|
break;
|
|
case 'center':
|
|
default:
|
|
// 居中:精灵组的中心与锚点对齐
|
|
startX = anchorX - totalWidth / 2;
|
|
break;
|
|
}
|
|
|
|
// 生成每个精灵的位置
|
|
var positions = [];
|
|
for (var i = 0; i < count; i++) {
|
|
positions.push({
|
|
x: startX + i * (itemWidth + spacing),
|
|
y: anchorY
|
|
});
|
|
}
|
|
|
|
return positions;
|
|
},
|
|
|
|
/**
|
|
* 计算多个精灵垂直分布的位置
|
|
*
|
|
* 🔑 核心:精灵的锚点永远在左上角
|
|
* 💡 用途:将多个相同大小的精灵垂直排列,支持居中/顶部对齐/底部对齐
|
|
*
|
|
* @param {Object} options - 分布选项
|
|
* @param {number} options.anchorX - 锚点X坐标(所有精灵的X坐标)
|
|
* @param {number} options.anchorY - 锚点Y坐标(对齐基准点)
|
|
* @param {number} options.count - 精灵数量
|
|
* @param {number} options.itemWidth - 每个精灵的宽度
|
|
* @param {number} options.itemHeight - 每个精灵的高度
|
|
* @param {number} [options.spacing=0] - 精灵之间的间距
|
|
* @param {string} [options.anchor='center'] - 对齐方式: 'top'|'center'|'bottom'
|
|
*
|
|
* @returns {Array<Object>} 每个精灵的位置数组 [{x, y}, ...]
|
|
*
|
|
* @example
|
|
* // 3张牌垂直居中排列
|
|
* var positions = AlignmentUtils.distributeVertically({
|
|
* anchorX: 100, // X位置
|
|
* anchorY: 360, // 屏幕中心Y
|
|
* count: 3, // 3张牌
|
|
* itemWidth: 62, // 牌宽
|
|
* itemHeight: 86, // 牌高
|
|
* spacing: 2, // 2px间距
|
|
* anchor: 'center' // 居中对齐
|
|
* });
|
|
*/
|
|
distributeVertically: function(options) {
|
|
var anchorX = options.anchorX || 0;
|
|
var anchorY = options.anchorY || 0;
|
|
var count = options.count || 0;
|
|
var itemWidth = options.itemWidth || 0;
|
|
var itemHeight = options.itemHeight || 0;
|
|
var spacing = options.spacing || 0;
|
|
var anchor = options.anchor || 'center';
|
|
|
|
if (count <= 0) return [];
|
|
|
|
// 计算总高度
|
|
var totalHeight = count * itemHeight + (count - 1) * spacing;
|
|
|
|
// 计算起始Y位置(精灵锚点在左上角)
|
|
var startY;
|
|
switch (anchor) {
|
|
case 'top':
|
|
// 顶部对齐:第一个精灵的顶边与锚点对齐
|
|
startY = anchorY;
|
|
break;
|
|
case 'bottom':
|
|
// 底部对齐:最后一个精灵的底边与锚点对齐
|
|
startY = anchorY - totalHeight;
|
|
break;
|
|
case 'center':
|
|
default:
|
|
// 居中:精灵组的中心与锚点对齐
|
|
startY = anchorY - totalHeight / 2;
|
|
break;
|
|
}
|
|
|
|
// 生成每个精灵的位置
|
|
var positions = [];
|
|
for (var i = 0; i < count; i++) {
|
|
positions.push({
|
|
x: anchorX,
|
|
y: startY + i * (itemHeight + spacing)
|
|
});
|
|
}
|
|
|
|
return positions;
|
|
},
|
|
|
|
/**
|
|
* 计算多个精灵分布的位置(自动选择水平或垂直)
|
|
*
|
|
* @param {Object} options - 分布选项
|
|
* @param {string} [options.direction='horizontal'] - 分布方向: 'horizontal'|'vertical'
|
|
* @param {number} options.anchorX - 锚点X坐标
|
|
* @param {number} options.anchorY - 锚点Y坐标
|
|
* @param {number} options.count - 精灵数量
|
|
* @param {number} options.itemWidth - 每个精灵的宽度
|
|
* @param {number} options.itemHeight - 每个精灵的高度
|
|
* @param {number} [options.spacing=0] - 精灵之间的间距
|
|
* @param {string} [options.anchor='center'] - 对齐方式
|
|
*
|
|
* @returns {Array<Object>} 每个精灵的位置数组 [{x, y}, ...]
|
|
*/
|
|
distribute: function(options) {
|
|
var direction = options.direction || 'horizontal';
|
|
if (direction === 'vertical') {
|
|
return this.distributeVertically(options);
|
|
} else {
|
|
return this.distributeHorizontally(options);
|
|
}
|
|
}
|
|
};
|
|
|
|
// ============================================================================
|
|
// 导出
|
|
// ============================================================================
|
|
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = AlignmentUtils;
|
|
} else if (typeof window !== 'undefined') {
|
|
window.AlignmentUtils = AlignmentUtils;
|
|
}
|