原創: 涵紫。首發于泰然,轉載請著名出處。 引言 Cocos2d-x引擎中有很多Action,這樣可以方便的讓開發者調用相應的Action去完成一些動作,例如:移動,彈跳,淡入淡出等。可在實際的開發過程中,由于游戲的需要,顯然地,引擎自帶的Action是完全不夠用的,很多時候都需要我們自己去寫。今天我就來分享一個讓精靈和粒子繞著圓角矩形運動的實例,細講一下實現過程(僅憑個人想法實現,如有其他更好的方法,歡迎交流分享)。 效果 該實例類似天天愛消除等系列游戲中的按鈕特效:
沒圖片資源,將就看吧。 實現方法 剛開始本來考慮自己定義一條圓角矩形的路徑,即建一個自己的動作模塊,讓精靈和粒子按照自己的定義的動作來運動來著,就像MoveTo/MoveBy、BezierTo/BezierBy等Action一樣。但是后來發現好難啊,因為根本沒有函數可以來定義圓角矩形(至少我不知道),所以一番糾結后,果斷放棄了這種設想。 另辟蹊徑,不是說cocos2d-x引擎提供很多的Action嗎,那我們就來“拼”一個圓角矩形的Action??!要“拼”這個Action,我覺得很有必要了解清楚Cocos2d-x中的各個Action,引擎中常用的Action有:
了解更多可查看官網信息: http://www./reference/native-cpp/V3.0alpha0/db/d61/classcocos2d11_action.html 其中以To結尾的動作和以By結尾的動作的 區別 在于: To是設置Node(引擎中所以物體的基類)到指定坐標位置,而By則是設置Node到相對的坐標位置。例如:一個Sprite的坐標是(100,200),XXTo(1.0f, ccp(100, 100))是在1秒內運動到點(100, 100)處,無論節點之前的坐標在哪,它最終的位置坐標都是點(100,100);XXBy(1.0f, ccp(100, 100))則是表示1秒內向x軸方向運動100個單位,向y軸方向運動100個單位,它是以自身節點為參照位置,運動了(100,100)個單位。 理清Action后回歸到正題,根據圓角矩形的特征,這里我們可以把圓角矩形分成四段:左右兩半弧和上下兩直線,如下圖:
沿直線的運動的2、4段我們可以用MoveTo、MoveBy,而沿著左右兩邊的曲線運動呢?曲線!首先想到的應該是貝塞爾曲線吧,先來了解一下貝塞爾曲線。 貝賽爾曲線的每一個頂點都有兩個控制點,用于控制在該頂點兩側的曲線的弧度。它是應用于二維圖形應用程序的數學曲線。曲線的定義有四個點:起始點、終止點(也稱錨點)以及兩個相互分離的中間點?;瑒觾蓚€中間點,貝塞爾曲線的形狀會發生變化。 在引擎中是這樣子定義一個貝塞爾曲線的配置信息的: typedef struct _ccBezierConfig { //! end position of the bezier Point endPosition; //! Bezier control point 1 Point controlPoint_1; //! Bezier control point 2 Point controlPoint_2; } ccBezierConfig; 描述結構體中三個點分別是:曲線的目的結束點,控制點1和控制點2, Bezier的起始點則是它當前的位置坐標。貝塞爾曲線的兩個控制點的位置將決定曲線的形狀,不清楚的可以在Photoshop等有貝塞爾曲線的軟件中去調。以圓角矩形左邊的曲線為例,我調了一條曲線,如下圖所示:
從圖中可以看到,只要Point1與起始點連成的直線和Point2與結束點連成的直線平行 && 兩個控制點都在以起點和終點為連線的同一個面 && 兩個控制點的連線與起始點終點的連線平行時,就可以確定一條相對標準的曲線,可以近似圓角矩形的圓角部分。左右移動Point1和Point2的位置可調節這條曲線的形狀,如圖:
理清思路以后,上代碼“畫”上圖的貝塞爾曲線: ccBezierConfig bezier; bezier.controlPoint_1 = Point(-controlX, 0); //控制點1 bezier.controlPoint_2 = Point(-controlX, controlY); //控制點2 bezier.endPosition = Point(0, controlY); //目的地(終點) auto bezierBy = BezierBy::create(1.0f, bezier);//創建動作 node->runAction(bezierBy); //讓節點按bezierBy路徑運動
注意,使用BezierBy時,節點始終把自己的運動初始位置看做(0, 0),與它的實際場景位置無關,ccBezierConfig中的點都是相對坐標點,如果使用BezierTo,ccBezierConfig的點就都是絕對坐標點,曲線的起始點也將被認作為實際場景位置坐標,而非(0, 0),因此也將不能達到上圖的效果。
右邊的貝塞爾曲線類似,直線的運動同理用MoveBy,而不用MoveTo。移動的代碼很簡單,如: 這樣圓角矩形的四部分都能用相應的Action來實現了,接下來該完成的就是把它們按順序的串連在一起并重復的執行下去。那就要用到Sequenc(按順序執行一系列的動作) 和RepeatForever(重復執行動作)了。下面就是抽象出來的方法,返回值為一個能繞圓角矩形運動的循環動作: RepeatForever* HelloWorld::MyPathFun(float controlX, float controlY, float w) { ccBezierConfig bezier1; bezier1.controlPoint_1 = Point(-controlX, 0); bezier1.controlPoint_2 = Point(-controlX, controlY); bezier1.endPosition = Point(0, controlY); auto bezierBy1 = BezierBy::create(0.8f, bezier1); auto move1 = MoveBy::create(0.8f, Point(w, 0)); ccBezierConfig bezier2; bezier2.controlPoint_1 = Point(controlX, 0); bezier2.controlPoint_2 = Point(controlX, -controlY); bezier2.endPosition = Point(0, -controlY); auto bezierBy2 = BezierBy::create(0.8f, bezier2); auto move2 = MoveBy::create(0.8f, Point(-w, 0)); auto path = RepeatForever::create(Sequence::create(bezierBy1, move1, bezierBy2, move2, NULL)); return path; } 函數MyPathFun()的參數分別是控制點1的X分量、控制點2的Y分量(圓角矩形的高)、直線移動的x分量,如上圖。因為參數controlX和w都不是確定的值,所以傳參時要特別注意,要根據按鈕的形狀來調節這兩個參數。 接下來只需要讓節點runAction這個動作就可以了,下面利用粒子系統做一條尾巴。關于粒子特效的介紹大家可以參考泰然網的一篇文章,地址: http://www./archives/3460 ParticleSystem* HelloWorld::particleInit() { auto _emitter = new ParticleSystemQuad(); _emitter->initWithTotalParticles(50); addChild(_emitter, 10); _emitter->setTexture(Director::getInstance()->getTextureCache()->addImage("point.png")); _emitter->setAnchorPoint(Point(0, 0)); // duration _emitter->setDuration(ParticleSystem::DURATION_INFINITY); // radius mode _emitter->setEmitterMode(ParticleSystem::Mode::RADIUS); // radius mode: start and end radius in pixels _emitter->setStartRadius(4); _emitter->setStartRadiusVar(1); _emitter->setEndRadius(ParticleSystem::START_RADIUS_EQUAL_TO_END_RADIUS); _emitter->setEndRadiusVar(0); // radius mode: degrees per second _emitter->setRotatePerSecond(100); _emitter->setRotatePerSecondVar(0); // angle _emitter->setAngle(90); _emitter->setAngleVar(0); // emitter position auto size = Director::getInstance()->getWinSize(); _emitter->setPosVar(Point::ZERO); // life of particles _emitter->setLife(0.5); _emitter->setLifeVar(0); // spin of particles _emitter->setStartSpin(0); _emitter->setStartSpinVar(0); _emitter->setEndSpin(0); _emitter->setEndSpinVar(0); // color of particles Color4F startColor(0.0f, 0.8f, 0.9f, 1.0f); _emitter->setStartColor(startColor); Color4F startColorVar(0, 0, 0, 1.0f); _emitter->setStartColorVar(startColorVar); Color4F endColor(1.0f, 1.0f, 1.0f, 0.1f); _emitter->setEndColor(endColor); Color4F endColorVar(0, 0, 0, 0.1f); _emitter->setEndColorVar(endColorVar); Color4F setStartColor(Color4F(Color4B(50, 50, 50, 50))); Color4F setEndColor(Color4F(Color4B(0, 0, 0, 0))); // size, in pixels _emitter->setStartSize(20); _emitter->setStartSizeVar(1); _emitter->setEndSize(0); // emits per second _emitter->setEmissionRate(_emitter->getTotalParticles() / _emitter->getLife()); // additive _emitter->setBlendAdditive(false); return _emitter; }
這里也可以利用粒子特效制作工具來編輯好看的粒子,然后通過plist文件加載粒子。 starSprite->setPosition(Point(btnSprite->getPosition().x + btnSprite->getContentSize().height / 2 - 4, btnSprite->getPosition().y));//設置星星的坐標 _emitter->setPosition(Point(btnSprite->getPosition().x + btnSprite->getContentSize().height / 2 - 4, btnSprite->getPosition().y + 3));//設置尾巴粒子發射器的坐標 float X = btnSprite->getContentSize().height / 2; auto path = MyPathFun(X+10, btnSprite->getContentSize().height, btnSprite->getContentSize().width - X * 2 ); //根據按鈕的形狀調節按鈕的動作路徑 starSprite->runAction(path); _emitter->runAction(path->clone()); 這里把星星和尾巴的起點坐標設為上圖的originPoint點,因為描點的原因,星星starSprite和尾巴_emitter的位置要做一定的微調。
該方法實用于任意圓角矩形,同時適用于矩形,只要把controlX設置為零,W設置為矩形寬就都實現,即:
工程下載地址: https://github.com/renshan/btnTest/tree/master/Test-btn |
|
來自: 勤奮不止 > 《游戲引擎cocos2d》