笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。
Avatar换装系统又称为纸娃娃系统,在游戏开发中是使用非常广泛的技术,特别是在MMOARPG或者是MMORPG等网络游戏中,玩家创建的3D角色都具有Avatar换装功能,在游戏开发中经常需要对角色更换装备,比如角色在战斗过程中获取到新的盔甲要穿戴在身上或者新的武器要更换等等。要实现该技术所使用的引擎都必须具有支持Avatar换装系统的骨骼挂节点,比如市面上的Unity引擎,UE4引擎等都提供了这种挂接骨骼方法,获取到骨骼挂节点后,可以直接将武器挂接到需要绑定的骨骼上。实现的效果如下图:
场景中的三个角色采用了Avatar换装技术,它们采用的是同一套骨架,将需要更换的各个Mesh模型都挂接到对应的骨架上,从而形成了Avatar换装系统。而本书介绍的Cocos2d-x引擎也不例外,该引擎也提供了支持Avatar技术的功能,实现该功能的类是AttachNode。下面介绍实现挂接结点的步骤,不论是挂接Mesh还是在角色身上挂接武器都需要根据骨骼挂接,这就要用到AttachNode类实现的功能,实现的函数如下所示:
AttachNode* AttachNode::create(Bone3D* attachBone) { auto attachnode = new (std::nothrow) AttachNode(); attachnode->_attachBone = attachBone; attachnode->autorelease(); return attachnode; }
首先是创建需要挂接的骨骼,骨骼动画是需要矩阵支撑的,骨骼动画它在世界坐标系中的变换都需要转换到世界变换矩阵,这些实现过程也需要引擎提供,下面把接口的函数给读者展示如下:
Mat4 AttachNode::getWorldToNodeTransform() const { static Mat4 mat; mat.setIdentity(); auto parent = getParent(); if (parent) { mat=parent->getWorldToNodeTransform() * _attachBone->getWorldMat() * Node::getNodeToParentTransform(); } else { mat=_attachBone->getWorldMat() * Node::getNodeToParentTransform(); } return mat; }
getWorldToNodeTransform函数的实现原理是把模型挂接到骨骼上,该骨骼是需要挂接模型的父结点,父结点运动会带动所绑的模型运动,从而保证挂接到骨骼结点的武器能够与骨骼动画一致。这个实现过程是与矩阵相关的,通过案例把实现的代码片段给读者展示如下:
//Girl.c3b里保存了女角色所执行动画的所有零件(姑且这么叫吧)包括衣服,鞋子等等 std::string fileName = "Sprite3DTest/Girl.c3b"; auto sprite = Sprite3D::create(fileName); sprite->setScale(4); sprite->setRotation3D(Vec3(0,0,0)); addChild(sprite); sprite->setPosition( Vec2( p.x, p.y-60) ); auto animation = Animation3D::create(fileName); if (animation) { auto animate = Animate3D::create(animation); sprite->runAction(RepeatForever::create(animate)); } _sprite = sprite; _curSkin[SkinType::UPPER_BODY] = "Girl_UpperBody01"; _curSkin[SkinType::PANTS] = "Girl_LowerBody01"; _curSkin[SkinType::SHOES] = "Girl_Shoes01"; _curSkin[SkinType::HAIR] = "Girl_Hair01"; _curSkin[SkinType::FACE] = "Girl_Face01"; _curSkin[SkinType::HAND] = "Girl_Hand01"; _curSkin[SkinType::GLASSES] = "";
上面的代码片段是针对一个模型进行换装操作,首先实现的是对换装的部位进行初始化操作。下面开始遍历获取到骨骼动画挂接的数量,对于挂接的模型,如果是多个通过显示和隐藏将其显示出来。下面的代码片段函数是ApplySkin,函数内容片段如下所示:
//函数getMeshCount获取动画所有零件数目 for (ssize_t i = 0; i < _sprite->getMeshCount(); i++) { auto mesh = _sprite->getMeshByIndex(static_cast<int>(i)); bool isVisible = false; for (auto& it : _curSkin) { if (mesh->getName() == it.second) { isVisible = true; break; } } //通过索引来获取零件并设置可见性 _sprite->getMeshByIndex(static_cast<int>(i))->setVisible(isVisible); }
下面给大家展示应用案例代码如下所示:
std::string str = _curSkin[SkinType::HAIR]; if (str == "Girl_Hair01") _curSkin[SkinType::HAIR] = "Girl_Hair02"; else _curSkin[SkinType::HAIR] = "Girl_Hair01";
同时要调用ApplySkin函数就可以完成换装的要求,实现效果如下图:
场景中的角色裤子、头发、鞋子都发生了改变,完成换装。关于换装,笔者在CSDN学院出版一个免费的视频讲座《游戏Avatar换装系统》,供开发者参考。