Cocos2d-x的UI树|(1)
游戏由各种UI元素构成,每个UI元素的核心属性为位置和样式。本节课将从Cocos2d-x源码角度,详细介绍如何确定一个UI元素的位置。
课程笔记 – UI元素
锚点相关函数
在Cocos2d-x中,Node类提供了一系列与锚点相关的函数,以下是部分关键函数的源码及解释:
// 获取锚点在本地坐标系中的非归一化位置
const Vec2& Node::getAnchorPointInPoints() const
{
return _anchorPointInPoints;
}
// 获取锚点在本地坐标系中的归一化位置
const Vec2& Node::getAnchorPoint() const
{
return _anchorPoint;
}
// 设置锚点在本地坐标系中的归一化位置
void Node::setAnchorPoint(const Vec2& point)
{
#if CC_USE_PHYSICS
if (_physicsBody != nullptr && !point.equals(Vec2::ANCHOR_MIDDLE))
{
CCLOG("Node warning: This node has a physics body, the anchor must be in the middle, you can't change this to other value.");
return;
}
#endif
if (!point.equals(_anchorPoint))
{
_anchorPoint = point;
_anchorPointInPoints = Vec2(_contentSize.width * _anchorPoint.x, _contentSize.height * _anchorPoint.y);
_transformUpdated = _transformDirty = _inverseDirty = true;
}
}
锚点(AnchorPoint)的概念可以理解为将精灵抽象成一个点,这个点位于精灵上。例如,调用setAnchorPoint(0.5, 0.5),意味着将精灵的中心位置作为锚点。当调用setPosition方法设置精灵位置时,实际上是以该锚点所在位置为基准进行放置。若调用setAnchorPoint(0, 0),则将精灵的左下角作为锚点,setPosition设置的就是左下角的位置,精灵也会相应显示。
Node类概述
UI元素通常指sprite、label、layer、scene等常见元素,它们都继承自Node类。Node类的主要作用是提供一系列通用函数,用于对UI元素进行各种操作,包括但不限于:
- 设置UI元素的位置
- 根据坐标系对UI元素进行坐标计算
- 确定UI元素的深度值
- 设置UI元素的缩放因子
- 获取UI元素的尺寸
- 设置UI元素的可见性、运行状态、事件监听器、动作、调度器、颜色、Camera等
- 绘制UI元素
- 对子UI元素进行操作
- 处理与父UI元素的关系
- 获取UI元素的
scene、碰撞矩阵绘制元素 - 查询OpenGL ES状态
- 操作用户数据
位置的确定
UI元素的位置由以下三个因素共同确定:
- 确定UI元素的锚点:锚点的作用是在设置UI位置时,将其放置在父UI元素坐标系的某个点上。
- 确定UI元素的父UI元素:明确当前UI元素所属的父元素。
- 确定锚点在父UI元素中的位置:即把UI元素的锚点放置在父UI元素的具体位置。
当这三个因素确定后,从开发者的角度来看,UI元素的位置基本就确定了。如果父UI、祖父UI(如果存在)等在layer上的位置已经确定,那么UI元素的最终位置也就确定了。
Node类的位置相关函数
setAnchorPoint:用于设置Node的锚点在本地坐标系中的位置,传入的参数为归一化坐标。getAnchorPoint与setAnchorPoint相对应,用于获取锚点的归一化位置。getAnchorPointInPoints:获取Node的锚点在本地坐标系中的非归一化位置。setPosition:设置Node的锚点在其父UI元素本地坐标系中的位置,传入参数为位置坐标。getPosition与setPosition相对应。setNormalizedPosition:设置Node的锚点在其父UI元素本地坐标系中的归一化位置,传入参数为归一化坐标。getNormalizedPosition与setNormalizedPosition相对应。setPosition3D:除了设置位置的x和y值,还会设置_positionZ和_globalZOrder。_globalZOrder用于排序和为事件分发器提供位置信息。getPosition3D与setPosition3D相对应。ignoreAnchorPointForPosition:这是一个内部函数,仅适用于scene和layer。其作用是在设置scene和layer的位置时,将锚点按照(0, 0)进行设置。其他类使用该函数会报错。
坐标系
Cocos2d-x拥有一个世界坐标系,该坐标系等同于OpenGL ES坐标系。但开发者在实际开发中接触最多的是本地坐标系,每个父UI元素都有自己独立的本地坐标系,子UI元素在设置坐标时,都是相对于其父UI元素的坐标系进行的。
Node类的坐标系转换函数
getNodeToParentTransform:获取一个Mat4矩阵,用于将Node本地坐标系中的坐标转换为父UI元素坐标系中的坐标。例如,若Node的锚点为(0.5, 0.5),position设置为(100, 100),contentsize为(50, 50),那么在Node本地坐标系中(0, 0)的点,在其父UI元素坐标系中的坐标为(100 - 50 * 0.5, 100 - 50 * 0.5) = (75, 75)。setNodeToParentTransform与getNodeToParentTransform相对应。getNodeToParentAffineTransform与getNodeToParentTransform类似,区别在于前者返回的是仿射变换,在有限维情况下,每个仿射变换由一个矩阵A和一个向量b组成。getParentToNodeTransform:获取一个Mat4矩阵,用于将父UI元素坐标系中的坐标转换为Node本地坐标系中的坐标。getParentToNodeAffineTransform返回的是仿射变换。getNodeToWorldTransform:获取一个Mat4矩阵,用于将Node本地坐标系中的坐标转换为世界坐标系中的坐标。getNodeToWorldAffineTransform返回的是仿射变换。getWorldToNodeTransform:获取一个Mat4矩阵,用于将世界坐标系中的坐标转换为Node本地坐标系中的坐标。getWorldToNodeAffineTransform返回的是仿射变换。convertToNodeSpace:借助getWorldToNodeTransform得到的Mat4矩阵,将世界坐标转换为Node本地坐标系中的本地坐标。反之,convertToWorldSpace则借助getNodeToWorldTransform得到的Mat4矩阵,将Node本地坐标系中的本地坐标转换为世界坐标。convertToNodeSpaceAR:将世界坐标转换为以Node锚点为原点的坐标系中的坐标。反之,convertToWorldSpaceAR将以Node锚点为原点的坐标系中的某一点坐标转换为世界坐标。