当前位置 : 145z游戏站 | 热血传奇 | 技术教程 | 

Cocos2d-x精灵织画还原热血传奇登录城门开启效果完整实现

热度:
热血传奇登录界面那道城门是从ChrSel.wzl/ChrSel.wzx里抽出来的序列帧(背景索引22,开门帧索引24~32,共9帧,原图约495×361),原理就是Cocos2d-x的SpriteFrameCache加载图集plist+Animation::createWithSpriteFrames组帧+Animate驱动Sprite播放,锚点锁左下角贴回原坐标,点击或延时触发一次不循环开门动作。下面按3.xAPI写可直接抄进HelloWorldScene的完整链路。

一、素材准备与透明处理
1.用WzlWzxExtractor/传奇资源浏览器从ChrSel.wzx抽出24~32帧PNG;
2.传奇里RGB(000)代表透明,抽图后最右一列常留黑线,PS删掉最右1px再存,避免播动画时竖黑边;
3.第一帧门几乎闭合,可裁掉做8帧,TexturePacker打图集door.plist+door.png,帧名door_00.png~door_07.png;
4.资源扔Resources目录,Android放assets,Win32放调试目录根。

二、场景初始化与背景铺设
boolHelloWorld::init()
{
if(!Scene::init())returnfalse;

autovisibleSize=Director::getInstance()->getVisibleSize();
autoorigin=Director::getInstance()->getVisibleOrigin();

//登录背景
autobg=Sprite::create("background.png");
bg->setPosition(Vec2(visibleSize.width/2+origin.x
visibleSize.height/2+origin.y));
this->addChild(bg0);

//预加载门图集
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("door.plist");

returntrue;
}


三、核心开门方法(锚点+坐标还原)
传奇门帧原点在图片左下角,必须setAnchorPoint(Vec2(00)),位置按原界面贴(示例153143,按自己背景尺寸换算):
voidHelloWorld::playOpenDoor()
{
staticSprite*door=nullptr;
if(door==nullptr)
{
door=Sprite::create();
door->setAnchorPoint(Vec2(00));//左下角锚点,对齐传奇原图基点
door->setPosition(Vec2(153143));//门在背景上的绝对位置
this->addChild(door1);
}

Animation*animation=AnimationCache::getInstance()->getAnimation("openDoor");
if(animation==nullptr)
{
constintframeCount=8;//24~31共8帧可用
Vector<SpriteFrame*>frames;
auto*cache=SpriteFrameCache::getInstance();
for(inti=0;i<frameCount;++i)
{
std::stringkey=StringUtils::format("door_%02d.png"i);
SpriteFrame*f=cache->getSpriteFrameByName(key);
if(f)frames.pushBack(f);
}
animation=Animation::createWithSpriteFrames(frames1.5f/frames.size());
animation->setRestoreOriginalFrame(false);//播完停最后一帧(门保持开)
animation->setLoops(1);
AnimationCache::getInstance()->addAnimation(animation"openDoor");
}

door->stopAllActions();
door->runAction(Animate::create(animation));
}

delayPerUnit用1.5f/帧数≈0.1875s/帧,总时长1.5s,贴近官服厚重推门节奏;setRestoreOriginalFrame(false)让门开完不回弹。

四、触发方式(鼠标点击/延时自动)
点击触发:
automouseListener=EventListenerMouse::create();
mouseListener->onMouseDown=[&](EventMouse*e){this->playOpenDoor();};
_eventDispatcher->addEventListenerWithSceneGraphPriority(mouseListenerthis);

进场景自动开:
this->runAction(Sequence::create(DelayTime::create(0.6f)
CallFunc::create([&](){playOpenDoor();})nullptr));


五、2.x旧版写法对照(CC前缀)
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("door.plist");
CCArray*arr=CCArray::create();
for(inti=0;i<8;i++){
constchar*n=CCString::createWithFormat("door_%02d.png"i)->getCString();
arr->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(n));
}
CCAnimation*anim=CCAnimation::createWithSpriteFrames(arr1.5f/8);
anim->setRestoreOriginalFrame(false);
doorSprite->runAction(CCAnimate::create(anim));

3.x把CCArray换Vector<SpriteFrame*>,sharedXXX换getInstance,其余一致。

六、常见歪点排查
•门播出来位置偏:锚点没设(00),传奇帧基点左下,默认(0.50.5)必错位;

-黑竖线:抽图没删RGB(000)最右列,plist里trim没开;
•只闪一帧:frames为空,plist帧名和代码format不一致;

•门播完弹回闭合:setRestoreOriginalFrame没设false;

-想循环演示:setLoops(-1)或RepeatForever::create(Animate::create(anim));
•想关门反向:把frames反转再建Animation,或Sequence::create(openAnimopenAnim->reverse()nullptr);

-大图内存吃紧:TexturePacker压8bit、裁冗余像素、首帧去重,495×361原图能砍掉近三成。

七、扩成游戏内城门/机关门
把door坐标改成地图物体世界坐标,绑定碰撞盒;角色走到触发距离→playOpenDoor();门动画播完设物理body失效让角色穿过;关门用reverse动画+重置碰撞。序列帧机制不变,只换触发源和坐标空间。

整套就是SpriteFrameCache解plist→取帧组Animation→Animate绑Sprite→锚点左下还原传奇基点→单次非循环播放,黑线透明和首帧去重是抽ChrSel资源时必做的两步。
[顶部]