Explorar o código

添加了purchaseBanner文件夹

MoYuWang hai 9 meses
pai
achega
144bfc7087

+ 1 - 1
Classes/IAP/Test/IAPTestCard.cpp

@@ -70,7 +70,7 @@ void IAPTestCard::onNotifyDevelopment(const redutils::ReboltNotifyData& data) {
     if (data.notify == "") {
         
     } else if (data.notify == "点击") {
-        
+        accepted();
     }
 }
 

+ 98 - 0
Classes/IAP/purchaseBanner/PBConfigData.cpp

@@ -0,0 +1,98 @@
+//
+//  PBConfigData.cpp
+//  merge6
+//
+//  Created by Black Homles on 2024/9/24.
+//
+
+#include "PBConfigData.hpp"
+#include "rapidcsv.h"
+
+PBConfigData* PBConfigData::_gPBConfigData = nullptr;
+
+PBConfigData::PBConfigData() {
+}
+
+PBConfigData::~PBConfigData() {
+}
+
+PBConfigData* PBConfigData::getInstance() {
+    if (_gPBConfigData == nullptr || !_gPBConfigData) {
+        _gPBConfigData = new (std::nothrow) PBConfigData();
+    }
+    return _gPBConfigData;
+}
+
+void PBConfigData::initData() {
+    string fileName = "purchaseBannerConfig.csv";
+    _bannerInfoList.clear();
+    if (!FileUtils::getInstance()->isFileExist(fileName)) {
+        return;
+    }
+    std::string fullfiledata = FileUtils::getInstance()->getStringFromFile(fileName);
+    std::stringstream sstream(fullfiledata);
+    rapidcsv::Document tempDoc(sstream);
+    int rowcount = (int)tempDoc.GetRowCount();
+    for (int irow = 0; irow < rowcount; irow++) {
+        bannerInfo tmpinfo;
+        tmpinfo.bannerName = tempDoc.GetCell<string>("名称",irow);
+        tmpinfo.bannerDes = tempDoc.GetCell<string>("描述",irow);
+        tmpinfo.bannerType = tempDoc.GetCell<string>("类型",irow);
+        tmpinfo.bannerFile = tempDoc.GetCell<string>("文件名称",irow);
+        tmpinfo.bannerTitle = tempDoc.GetCell<string>("标题",irow);
+        tmpinfo.bannerPlist = tempDoc.GetCell<string>("图集名称",irow);
+        tmpinfo.bannerBGSp = tempDoc.GetCell<string>("背景图片",irow);
+        tmpinfo.bannerPID = tempDoc.GetCell<string>("商品ID",irow);
+        tmpinfo.bannerCutCount = tempDoc.GetCell<string>("折扣数字",irow);
+        tmpinfo.bannerPrice = tempDoc.GetCell<string>("价格数字",irow);
+        tmpinfo.bannerBtnStr = tempDoc.GetCell<string>("按钮文字",irow);
+        tmpinfo.bannerTime = tempDoc.GetCell<int>("有效时间秒",irow);
+        tmpinfo.item1ID = tempDoc.GetCell<string>("物品1ID",irow);
+        tmpinfo.item1Type = tempDoc.GetCell<string>("物品1类型",irow);
+        tmpinfo.item1Count = tempDoc.GetCell<int>("物品1数量",irow);
+        tmpinfo.item1PNG = tempDoc.GetCell<string>("物品1图片",irow);
+        tmpinfo.item2ID = tempDoc.GetCell<string>("物品2ID",irow);
+        tmpinfo.item2Type = tempDoc.GetCell<string>("物品2类型",irow);
+        tmpinfo.item2Count = tempDoc.GetCell<int>("物品2数量",irow);
+        tmpinfo.item2PNG = tempDoc.GetCell<string>("物品2图片",irow);
+        tmpinfo.item3ID = tempDoc.GetCell<string>("物品3ID",irow);
+        tmpinfo.item3Type = tempDoc.GetCell<string>("物品3类型",irow);
+        tmpinfo.item3Count = tempDoc.GetCell<int>("物品3数量",irow);
+        tmpinfo.item3PNG = tempDoc.GetCell<string>("物品3图片",irow);
+        tmpinfo.item3Des = tempDoc.GetCell<string>("物品3描述",irow);
+        _bannerInfoList.push_back(tmpinfo);
+    }
+    //view config
+    string fileName2 = "bannerViewConfig.csv";
+    _bResList.clear();
+    if (!FileUtils::getInstance()->isFileExist(fileName2)) {
+        return;
+    }
+    std::string fullfiledata2 = FileUtils::getInstance()->getStringFromFile(fileName2);
+    std::stringstream sstream2(fullfiledata2);
+    rapidcsv::Document tempDoc2(sstream2);
+    int rowcount2 = (int)tempDoc2.GetRowCount();
+    for (int lopp = 1; lopp < rowcount2; lopp++) {
+        string tmpstr = tempDoc2.GetCell<string>("资源名称",lopp);
+        _bResList.push_back(tmpstr);
+    }
+    _thisDotcfg.sepWidth = tempDoc2.GetCell<int>("圆点宽度",0);
+    _thisDotcfg.yStart = tempDoc2.GetCell<int>("圆点高度",0);
+    _thisDotcfg.highSp = tempDoc2.GetCell<string>("圆点亮图",0);
+    _thisDotcfg.normalSp = tempDoc2.GetCell<string>("圆点暗图",0);
+}
+
+PBConfigData::bannerInfo PBConfigData::getBannerInfo(string bName) {
+    bannerInfo tmpinfo;
+    for (int lopp = 0; lopp < _bannerInfoList.size(); lopp++) {
+        if (_bannerInfoList[lopp].bannerName == bName) {
+            tmpinfo = _bannerInfoList[lopp];
+            break;
+        }
+    }
+    return tmpinfo;
+}
+
+PBConfigData::sPBDotCfg PBConfigData::getViewDot() {
+    return _thisDotcfg;
+}

+ 67 - 0
Classes/IAP/purchaseBanner/PBConfigData.hpp

@@ -0,0 +1,67 @@
+//
+//  PBConfigData.hpp
+//  merge6
+//
+//  Created by Black Homles on 2024/9/24.
+//
+
+#ifndef PBConfigData_hpp
+#define PBConfigData_hpp
+
+#include "cocos2d.h"
+
+class PBConfigData {
+public:
+    struct bannerInfo {
+        string bannerName = ""; //P-名称
+        string bannerDes = ""; //P-描述
+        string bannerType = ""; //P-类型
+        string bannerFile = ""; //P-文件名称
+        string bannerTitle = ""; //P-标题
+        string bannerPlist = ""; //P-图集名称
+        string bannerBGSp = ""; //P-背景图片
+        string bannerPID = ""; //P-商品ID
+        string bannerCutCount = ""; //P-折扣数字
+        string bannerPrice = ""; //P-价格数字
+        string bannerBtnStr = ""; //P-按钮文字
+        int bannerTime = 0; //P-有效时间秒
+        string item1ID = ""; //P-物品1ID
+        string item1Type = ""; //P-物品1类型
+        int item1Count = 0; //P-物品1数量
+        string item1PNG = ""; //P-物品1图片
+        string item2ID = ""; //P-物品2ID
+        string item2Type = ""; //P-物品2类型
+        int item2Count = 0; //P-物品2数量
+        string item2PNG = ""; //P-物品2图片
+        string item3ID = ""; //P-物品3ID
+        string item3Type = ""; //P-物品3类型
+        int item3Count = 0; //P-物品3数量
+        string item3PNG = ""; //P-物品3图片
+        string item3Des = ""; //P-物品3描述
+    };
+    struct sPBDotCfg {
+        int sepWidth = 0;
+        int yStart = 0;
+        string highSp = "";
+        string normalSp = "";
+    };
+
+    PBConfigData();
+    ~PBConfigData();
+    static PBConfigData* getInstance();
+    
+    ///初始化数据配置
+    void initData();
+    
+    bannerInfo getBannerInfo(string bName);
+    sPBDotCfg getViewDot();
+    
+private:
+    static PBConfigData* _gPBConfigData;
+    
+    vector<bannerInfo> _bannerInfoList = {};
+    vector<string> _bResList = {};
+    sPBDotCfg _thisDotcfg;
+};
+
+#endif /* PBConfigData_hpp */

+ 153 - 0
Classes/IAP/purchaseBanner/PurchaseBannerCell.cpp

@@ -0,0 +1,153 @@
+//
+//  PurchaseBannerCell.cpp
+//  merge6
+//
+//  Created by Black Homles on 2024/9/23.
+//
+
+#include "PurchaseBannerCell.hpp"
+
+PurchaseBannerCell* PurchaseBannerCell::create(string bName) {
+    PurchaseBannerCell* ret = new (std::nothrow) PurchaseBannerCell();
+    if (ret && ret->init()) {
+        ret->autorelease();
+    } else {
+        CC_SAFE_DELETE(ret);
+    }
+    if (bName.empty()) {
+        CC_SAFE_DELETE(ret);
+    } else {
+        ret->_bannerName = bName;
+        ret->initBanner();
+    }
+    return ret;
+}
+
+void PurchaseBannerCell::setBtnClickCallBack(std::function<void(int,string)> tmpCallBack) {
+    _reboltCallBack = tmpCallBack;
+}
+
+void PurchaseBannerCell::setBannerNO(int bno) {
+    _bannerNO = bno;
+}
+
+int PurchaseBannerCell::getBannerNO() {
+    return _bannerNO;
+}
+
+void PurchaseBannerCell::onNotifyDevelopment(redream::ReboltRedManager* reboltRedManager, redream::NotifyDevelopmentWaiter* waiter,
+                                 std::string notify, std::string param, bool reboltIsWait, Node* outNode) {
+    if (notify == "点击") {
+        if (_reboltCallBack != nullptr) {
+            if (_bannerInfo.bannerType == "计时" && _leftTime <= 0) {
+                _reboltCallBack(_bannerNO,"noTime");
+            } else {
+                _reboltCallBack(_bannerNO,_bannerName);
+            }
+        }
+    } else if (notify == "绑定倒计时") {
+        if (outNode != nullptr) {
+            this->scheduleBannerTime(outNode);
+        }
+    }
+}
+
+void PurchaseBannerCell::initBanner() {
+    _bannerInfo = PBConfigData::getInstance()->getBannerInfo(_bannerName);
+    if (_bannerInfo.bannerName.empty()) {
+        return;
+    }
+    _lyCellBanner = RedreamLoader::ReboltLayer(_bannerInfo.bannerFile);
+    this->addChild(_lyCellBanner);
+    _lyCellBanner->_reboltCallBack = std::bind(&PurchaseBannerCell::onNotifyDevelopment,this,
+                                            std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,
+                                            std::placeholders::_4,std::placeholders::_5,std::placeholders::_6);
+    _lyCellBanner->getReboltManager()->setCoderDataVar("P-标题",_bannerInfo.bannerTitle);
+    _lyCellBanner->getReboltManager()->setCoderDataVar("P-图集名称",_bannerInfo.bannerPlist);
+    _lyCellBanner->getReboltManager()->setCoderDataVar("P-背景图片",_bannerInfo.bannerBGSp);
+    _lyCellBanner->getReboltManager()->setCoderDataVar("P-折扣数字",_bannerInfo.bannerCutCount);
+    _lyCellBanner->getReboltManager()->setCoderDataVar("P-价格数字",_bannerInfo.bannerPrice);
+    _lyCellBanner->getReboltManager()->setCoderDataVar("P-按钮文字",_bannerInfo.bannerBtnStr);
+    {
+        _lyCellBanner->getReboltManager()->setCoderDataVar("P-有效时间秒",to_string(_bannerInfo.bannerTime));
+        _lyCellBanner->getReboltManager()->setCoderDataVar("P-物品1类型",_bannerInfo.item1Type);
+        _lyCellBanner->getReboltManager()->setCoderDataVar("P-物品1数量",to_string(_bannerInfo.item1Count));
+        _lyCellBanner->getReboltManager()->setCoderDataVar("P-物品1图片",_bannerInfo.item1PNG);
+        _lyCellBanner->getReboltManager()->setCoderDataVar("P-物品2类型",_bannerInfo.item2Type);
+        _lyCellBanner->getReboltManager()->setCoderDataVar("P-物品2数量","x" + to_string(_bannerInfo.item2Count));
+        _lyCellBanner->getReboltManager()->setCoderDataVar("P-物品2图片",_bannerInfo.item2PNG);
+    }
+    {
+        _lyCellBanner->getReboltManager()->setCoderDataVar("P-物品3类型",_bannerInfo.item3Type);
+        _lyCellBanner->getReboltManager()->setCoderDataVar("P-物品3数量",to_string(_bannerInfo.item3Count));
+        _lyCellBanner->getReboltManager()->setCoderDataVar("P-物品3图片",_bannerInfo.item3PNG);
+        _lyCellBanner->getReboltManager()->setCoderDataVar("P-物品3描述",_bannerInfo.item3Des);
+    }
+    {
+        //not enough
+    }
+    _lyCellBanner->getReboltManager()->runBehaviacWhitFunName("初始化");
+}
+
+void PurchaseBannerCell::scheduleBannerTime(Node* tmpNode) {
+    Label* tmplabel = dynamic_cast<Label*>(tmpNode);
+    if (tmplabel == nullptr) {
+        return;
+    }
+    if (_leftTime <= 0) {
+        if (_bannerInfo.bannerTime > 0) {
+            _leftTime = _bannerInfo.bannerTime;
+        } else {
+            _leftTime = 60;
+        }
+    }
+    string schedulName = "PurchaseBannerCell::scheduleBannerTime";
+    auto thisNode = this;
+    tmplabel->unschedule(schedulName);
+    tmplabel->schedule([=](float dt){
+        thisNode->_leftTime--;
+        if (thisNode->_leftTime > 0) {
+            string timestr = thisNode->convertSecondIntToHMSString(thisNode->_leftTime);
+            tmplabel->setString(timestr);
+        } else {
+            if (thisNode->_lyCellBanner != nullptr) {
+                thisNode->_lyCellBanner->getReboltManager()->runBehaviacWhitFunName("按钮失效");
+            }
+            tmplabel->unschedule(schedulName);
+        }
+    },1,schedulName);
+}
+
+void PurchaseBannerCell::setCellStatus() {
+    if (_lyCellBanner != nullptr) {
+        _lyCellBanner->getReboltManager()->runBehaviacWhitFunName("更新完成状态");
+    }
+}
+
+string PurchaseBannerCell::convertSecondIntToHMSString(int iTime) {
+    int lasttime = iTime;
+    int hours = lasttime / 3600;
+    lasttime = lasttime - (3600 * hours);
+    int mins = lasttime / 60;
+    lasttime = lasttime - (60 * mins);
+    if (lasttime <= 0 && hours <= 0 && mins <= 0) {
+        return "00:00:00";
+    }
+    int seconds = lasttime;
+    string timestrH = "";
+    if (hours < 10) {
+        timestrH = "0";
+    }
+    string timestrM = "";
+    if (mins < 10) {
+        timestrM = "0";
+    }
+    string timestrS = "";
+    if (seconds < 10) {
+        timestrS = "0";
+    }
+    string timestr = timestrH + to_string(hours) + ":"
+                    + timestrM + to_string(mins) + ":"
+                    + timestrS + to_string(seconds);
+    return timestr;
+}

+ 51 - 0
Classes/IAP/purchaseBanner/PurchaseBannerCell.hpp

@@ -0,0 +1,51 @@
+//
+//  PurchaseBannerCell.hpp
+//  merge6
+//
+//  Created by Black Homles on 2024/9/23.
+//
+
+#ifndef PurchaseBannerCell_hpp
+#define PurchaseBannerCell_hpp
+
+#include "cocos2d.h"
+#include "extensions/cocos-ext.h"
+#include "RedreamLoader.h"
+#include "PBConfigData.hpp"
+
+class PurchaseBannerCell :
+public Node,
+public redream::NotifyDevelopmentDelegate {
+public:
+    struct sPageCfg {
+        int row;
+        int col;
+        int startId;
+        int cnt;
+    };
+    
+    static PurchaseBannerCell* create(string bName);
+    
+    void setBtnClickCallBack(std::function<void(int,string)> tmpCallBack);
+    void setCellStatus();
+    void setBannerNO(int bno);
+    int getBannerNO();
+    
+    virtual void onNotifyDevelopment(redream::ReboltRedManager* reboltRedManager, redream::NotifyDevelopmentWaiter* waiter,
+                                     std::string notify, std::string param, bool reboltIsWait, Node* outNode) override;
+    
+protected:
+    CC_SYNTHESIZE(int, _idx, Idx);
+    RedreamLoader* _lyCellBanner = nullptr;
+    string _bannerName = "";
+    std::function<void(int,string)> _reboltCallBack = nullptr;
+    PBConfigData::bannerInfo _bannerInfo;
+    int _leftTime = 0;
+    int _bannerNO = -1;
+    
+    void initBanner();
+    void scheduleBannerTime(Node* tmpNode);
+    string convertSecondIntToHMSString(int iTime);
+};
+
+#endif /* PurchaseBannerCell_hpp */

+ 141 - 0
Classes/IAP/purchaseBanner/PurchaseBannerCtrl.cpp

@@ -0,0 +1,141 @@
+//
+//  PurchaseBannerCtrl.cpp
+//  merge6
+//
+//  Created by Black Homles on 2024/9/24.
+//
+
+#include "PurchaseBannerCtrl.hpp"
+#include "PBConfigData.hpp"
+
+PurchaseBannerCtrl* PurchaseBannerCtrl::tempPBCtrlInst = nullptr;
+
+PurchaseBannerCtrl::PurchaseBannerCtrl() {
+}
+
+PurchaseBannerCtrl::~PurchaseBannerCtrl() {
+}
+
+PurchaseBannerCtrl* PurchaseBannerCtrl::getInstance() {
+    if (tempPBCtrlInst == nullptr || !tempPBCtrlInst) {
+        tempPBCtrlInst = new (std::nothrow) PurchaseBannerCtrl();
+    }
+    return tempPBCtrlInst;
+}
+
+void PurchaseBannerCtrl::init(PurchaseBannerDelegate* pDelegate) {
+    _pBannerDelegate = pDelegate;
+    PBConfigData::getInstance()->initData();
+    SpriteFrameCache::getInstance()->addSpriteFramesWithFile("内购版位_UI.plist");
+}
+
+void PurchaseBannerCtrl::showBanner(Node* outerNode,vector<string> bNameList,float autoTime) {
+    if (outerNode == nullptr || bNameList.size() <= 0) {
+        return;
+    }
+    _parentNode = outerNode;
+    //640,340
+    Size tmpsize = Size(640,340);
+    auto vDotCfg = PBConfigData::getInstance()->getViewDot();
+    _gDotCfg.sepWidth = vDotCfg.sepWidth;
+    _gDotCfg.yStart = vDotCfg.yStart;
+    _gDotCfg.highSp = vDotCfg.highSp;
+    _gDotCfg.normalSp = vDotCfg.normalSp;
+    _pviewNode = PurchaseBannerView::create(tmpsize,_gDotCfg,true);
+    _pviewNode->setDelegate(this);
+    _parentNode->addChild(_pviewNode);
+    _pviewNode->setAnchorPoint(Vec2(.5,.5));
+    _pviewNode->setIgnoreAnchorPointForPosition(false);
+    _pviewCellNameMap.clear();
+    for (int lopp = 0; lopp < bNameList.size(); lopp++) {
+        string tmpbName = bNameList[lopp];
+        auto tmppbcell = PurchaseBannerCell::create(tmpbName);
+        _pviewNode->addBanner(tmppbcell);
+        tmppbcell->setBtnClickCallBack(std::bind(&PurchaseBannerCtrl::pageViewBtnClick,this,std::placeholders::_1,std::placeholders::_2));
+        tmppbcell->setBannerNO(lopp);
+        _pviewCellNameMap[lopp] = tmppbcell;
+    }
+    this->startShowNextPage(autoTime);
+}
+
+void PurchaseBannerCtrl::pageViewBtnClick(int bNO,string bName) {
+    if (bName == "noTime") {
+        this->showTimeOutTip();
+        return;
+    }
+    auto bannerinfo = PBConfigData::getInstance()->getBannerInfo(bName);
+    if (_pBannerDelegate == nullptr) {
+        return;
+    }
+    auto thisobj = this;
+    if (bannerinfo.bannerType == "礼包") {
+        _pBannerDelegate->onPurchaseClick(bannerinfo.bannerPID,[=](bool isok){
+            thisobj->purchaseOverCallBack(bNO,bName,isok);
+        });
+    } else if (bannerinfo.bannerType == "计时") {
+        _pBannerDelegate->onPurchaseClick(bannerinfo.bannerPID,[=](bool isok){
+            thisobj->purchaseOverCallBack(bNO,bName,isok);
+        });
+    } else if (bannerinfo.bannerType == "活动") {
+        _pBannerDelegate->onActBtnClick(bannerinfo.bannerName);
+    }
+}
+
+void PurchaseBannerCtrl::purchaseOverCallBack(int bNO,string bName,bool isok) {
+    if (isok) {
+        if (_pviewCellNameMap.find(bNO) != _pviewCellNameMap.end()) {
+            _pviewCellNameMap[bNO]->setCellStatus();
+        }
+    }
+}
+
+void PurchaseBannerCtrl::showTimeOutTip() {
+    auto tmpTipLayer = RedreamLoader::Layer("内购版位_浮层_提示文本.redream");
+    auto pNode = Director::getInstance()->getRunningScene();
+    pNode->addChild(tmpTipLayer);
+    float dtt = tmpTipLayer->playAnim("优惠已过期");
+    tmpTipLayer->scheduleOnce([=](float dt){
+        tmpTipLayer->removeFromParent();
+    },dtt,"PurchaseBannerCtrl::showTimeOutTip");
+}
+
+void PurchaseBannerCtrl::startShowNextPage(float dtt) {
+    if (dtt <= 0 || _pviewNode == nullptr) {
+        return;
+    }
+    if (_pviewNode->getPageCount() <= 1) {
+        return;
+    }
+    auto thisNode = this;
+    _moveNextTime = 0;
+    string schname = "PurchaseBannerCtrl::startShowNextPage";
+    _pviewNode->unschedule(schname);
+    _pviewNode->schedule([=](float dt){
+        if (thisNode->_moveNextTime >= dtt) {
+            int curridx = thisNode->_pviewNode->getCurrentPageIdx();
+            int pagecount = thisNode->_pviewNode->getPageCount();
+            if (curridx >= pagecount - 1) {
+                thisNode->_pviewNode->moveToFirstPage();
+            } else {
+                thisNode->_pviewNode->moveToNextPage();
+            }
+            thisNode->_moveNextTime = 0;
+        } else {
+            thisNode->_moveNextTime++;
+        }
+    },1,schname);
+}
+
+PurchaseBannerCell* PurchaseBannerCtrl::pageCellAtIndex(PurchaseBannerView* pageView, int index) {
+    return nullptr;
+}
+
+void PurchaseBannerCtrl::pageCellTouched(Touch* touch, PurchaseBannerCell* page) {
+}
+
+void PurchaseBannerCtrl::onPageChanged(int currentPageIndex, bool manualSet) {
+}
+
+void PurchaseBannerCtrl::onPageTouchBegan(Touch* touch) {
+    _moveNextTime = 0;
+}

+ 65 - 0
Classes/IAP/purchaseBanner/PurchaseBannerCtrl.hpp

@@ -0,0 +1,65 @@
+//
+//  PurchaseBannerCtrl.hpp
+//  merge6
+//
+//  Created by Black Homles on 2024/9/24.
+//
+
+#ifndef PurchaseBannerCtrl_hpp
+#define PurchaseBannerCtrl_hpp
+
+#include "cocos2d.h"
+#include "extensions/cocos-ext.h"
+#include "PurchaseBannerDelegate.h"
+#include "PurchaseBannerView.hpp"
+
+class PurchaseBannerCtrl :
+public PurchaseBannerViewDelegate {
+public:
+    PurchaseBannerCtrl();
+    ~PurchaseBannerCtrl();
+    static PurchaseBannerCtrl* getInstance();
+    
+    ///初始化组件
+    ///tmpNode,代理类实现
+    void init(PurchaseBannerDelegate* pDelegate);
+    
+    ///加载pageview节点,添加banner
+    ///outerNode,外部传入的父节点
+    ///bNameList,要添加的banner名称
+    ///autoTime,如果要自动切换下一页,需要设置时间
+    void showBanner(Node* outerNode,vector<string> bNameList,float autoTime = 0);
+    
+    ///pageview元素被点击,如果是活动,通过代理发送到外部
+    ///bName,banner名称,是谁发的消息
+    void pageViewBtnClick(int bNO,string bName);
+    
+    ///内购回调函数,如果是礼包,通过代理下发
+    ///succ,内购结果成功或失败
+    void purchaseReturn(bool succ);
+    
+    void purchaseOverCallBack(int bNO,string bName,bool isok);
+    
+    virtual PurchaseBannerCell* pageCellAtIndex(PurchaseBannerView* pageView, int index) override;
+    virtual void pageCellTouched(Touch* touch, PurchaseBannerCell* page) override;
+    virtual void onPageChanged(int currentPageIndex, bool manualSet) override;
+    virtual void onPageTouchBegan(Touch* touch) override;
+    
+private:
+    static PurchaseBannerCtrl* tempPBCtrlInst;
+    
+    PurchaseBannerDelegate* _pBannerDelegate = nullptr;
+    Node* _parentNode = nullptr;
+    vector<string> _bNameList = {};
+    vector<string> _bResList = {};
+    PurchaseBannerView* _pviewNode = nullptr;
+    PurchaseBannerView::sDotCfg _gDotCfg;
+    std::map<int,PurchaseBannerCell*> _pviewCellNameMap = {};
+    
+    float _moveNextTime = 0;
+    
+    void showTimeOutTip();
+    void startShowNextPage(float dtt);
+};
+
+#endif /* PurchaseBannerCtrl_hpp */

+ 110 - 0
Classes/IAP/purchaseBanner/PurchaseBannerDelegate.h

@@ -0,0 +1,110 @@
+//
+//  PurchaseBannerDelegate.h
+//  merge6
+//
+//  Created by Black Homles on 2024/9/24.
+//
+
+#ifndef PurchaseBannerDelegate_h
+#define PurchaseBannerDelegate_h
+
+#include "cocos2d.h"
+
+class PurchaseBannerDelegate {
+public:
+    virtual void onActBtnClick(string bName) = 0;
+    virtual void onPurchaseClick(string ppid,std::function<void(bool)> overCallBack) = 0;
+};
+
+#endif /* PurchaseBannerDelegate_h */
+
+
+void PurchaseBannerDelegateImpl::onActBtnClick(string name) {
+    if (name == "tilepass") {
+        // 显示tilepass的购买页面
+        auto tpSys = ActivityManager::getInstance()->getTilePassSystem();
+        tpSys->showActivatePopup();
+    }
+}
+
+
+void PurchaseBannerDelegateImpl::onPurchaseClick(string ppid,std::function<void(bool)> overCallBack) {
+    GoodsInfo gi;
+    if (ppid == "tilefavor") {
+        gi.id = ppid;
+        gi.idxGT2 = 0;
+        AreaInGooods aig;
+        {
+            ItemInGoods iig;
+            iig.name = "coin";
+            iig.count = "1000";
+            aig.push_back(iig);
+        }
+        {
+            ItemInGoods iig;
+            iig.name = "back1";
+            iig.count = "1";
+            aig.push_back(iig);
+        }
+        {
+            ItemInGoods iig;
+            iig.name = "life";
+            iig.count = "5";
+            aig.push_back(iig);
+        }
+        gi.areas.push_back(aig);
+    } else if (ppid == "tilepack") {
+        gi.id = ppid;
+        gi.idxGT2 = 0;
+        AreaInGooods aig;
+        {
+            ItemInGoods iig;
+            iig.name = "coin";
+            iig.count = "4000";
+            aig.push_back(iig);
+        }
+        {
+            ItemInGoods iig;
+            iig.name = "back1";
+            iig.count = "3";
+            aig.push_back(iig);
+        }
+        gi.areas.push_back(aig);
+    }
+    IAPProcess::getInstance()->buy(gi, 104, true, [=](){
+        if (overCallBack) {
+            overCallBack(true);
+        }
+    }, [=](){
+        if (overCallBack) {
+            overCallBack(false);
+        }
+    });
+}
+
+void MetaGameDelegateImpl::showIAPCardWhenFailed(cocos2d::Node* nd, int coinsNeeded, int livedNeeded) {
+    vector<string> banners;
+    int coinsNow = UserDataManager::getInstance()->getCoinNum();
+    int gap = coinsNeeded - coinsNow;
+    if (gap > 0) {
+        if (gap <= 1000 && !UserDataManager::getInstance()->everPurchased()) {
+            banners.push_back("tilefavor");
+        } else if (gap <= 4000) {
+            banners.push_back("tilepack");
+        }
+    }
+    if (livedNeeded > UserDataManager::getInstance()->getLifeLeft()) {
+        if (!UserDataManager::getInstance()->everPurchased()) {
+            if (std::find(banners.begin(), banners.end(), "tilefavor") == banners.end()) {
+                banners.push_back("tilefavor");
+            }
+        }
+        auto tp = ActivityManager::getInstance()->getTilePassSystem();
+        if (tp && tp->isActive() && !tp->passActivated()) {
+            banners.push_back("tilepass");
+        }
+    }
+    if (banners.size() > 0) {
+        PurchaseBannerCtrl::getInstance()->showBanner(nd, banners);
+    }
+}

+ 359 - 0
Classes/IAP/purchaseBanner/PurchaseBannerView.cpp

@@ -0,0 +1,359 @@
+//
+//  PurchaseBannerView.cpp
+//  merge6
+//
+//  Created by Black Homles on 2024/9/23.
+//
+
+#include "PurchaseBannerView.hpp"
+
+PurchaseBannerView* PurchaseBannerView::create(Size& viewSize, sDotCfg& dotCfg, bool cachePages,bool isHor) {
+    PurchaseBannerView* ret = new PurchaseBannerView();
+    ret->init(viewSize, dotCfg, cachePages, isHor);
+    ret->autorelease();
+    return ret;
+}
+
+void PurchaseBannerView::setDelegate(PurchaseBannerViewDelegate* delegate) {
+    _pageViewDelegate = delegate;
+}
+
+void PurchaseBannerView::init(Size& viewSize, sDotCfg& dotCfg, bool cachePages, bool isHor) {
+    Layer::init();
+    _dotCfg = dotCfg;
+    _viewSize = viewSize;
+    _cachePages = cachePages;
+    _isHori = isHor;
+    _currentPageIndex = 0;
+    _pageCount = 0;
+    this->setContentSize(_viewSize);
+    //get scrollview
+    _scrollView = cocos2d::extension::ScrollView::create();
+    _scrollView->setViewSize(_viewSize);
+    if (isHor) {
+        _scrollView->setDirection(cocos2d::extension::ScrollView::Direction::HORIZONTAL);
+    } else {
+        _scrollView->setDirection(cocos2d::extension::ScrollView::Direction::VERTICAL);
+    }
+    _scrollView->setBounceable(false);
+    _scrollView->setDelegate(this);
+    this->addChild(_scrollView);
+    auto listener = EventListenerTouchOneByOne::create();
+    listener->setSwallowTouches(true);
+    listener->onTouchBegan = CC_CALLBACK_2(PurchaseBannerView::onTouchBegan,this);
+    listener->onTouchMoved = CC_CALLBACK_2(PurchaseBannerView::onTouchMoved,this);
+    listener->onTouchEnded = CC_CALLBACK_2(PurchaseBannerView::onTouchEnded,this);
+    listener->onTouchCancelled = CC_CALLBACK_2(PurchaseBannerView::onTouchCancelled,this);
+    Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener,this);
+}
+
+void PurchaseBannerView::_initDotInd() {
+    if (!_initedDot) {
+        _initedDot = true;
+        if (_dotCfg.sepWidth != 0) {
+            int sepWidth = _dotCfg.sepWidth;
+            int yStart = _dotCfg.yStart;
+            auto tmpSp = Sprite::createWithSpriteFrameName(_dotCfg.normalSp);
+            int contentWidth = tmpSp->getContentSize().width;
+            int xStart = (_viewSize.width - _pageCount * contentWidth - (_pageCount - 1) * sepWidth) / 2;
+            for (int i = 0; i < _pageCount; i++) {
+                tmpSp = Sprite::createWithSpriteFrameName(_dotCfg.normalSp);
+                tmpSp->setPosition(Vec2(xStart + i * (contentWidth + sepWidth), yStart));
+                this->addChild(tmpSp, 1);
+                _dotSpArr.push_back(tmpSp);
+            }
+            _updateIndSp();
+        }
+    }
+}
+
+void PurchaseBannerView::_initDotAdded() {
+    if (_dotSpArr.size() < _pageCount && _dotCfg.sepWidth != 0) {
+        int sepWidth = _dotCfg.sepWidth;
+        int yStart = _dotCfg.yStart;
+        auto tmpSp = Sprite::createWithSpriteFrameName(_dotCfg.normalSp);
+        int contentWidth = tmpSp->getContentSize().width;
+        int xStart = (_viewSize.width - _pageCount * contentWidth - (_pageCount - 1) * sepWidth) / 2;
+        for (int i = (int)_dotSpArr.size(); i < _pageCount; i++) {
+            tmpSp = Sprite::createWithSpriteFrameName(_dotCfg.normalSp);
+            tmpSp->setPosition(Vec2(xStart + i * (contentWidth + sepWidth), yStart));
+            this->addChild(tmpSp, 1);
+            _dotSpArr.push_back(tmpSp);
+        }
+        for (int i = 0; i < _dotSpArr.size(); i++) {
+            tmpSp = _dotSpArr[i];
+            tmpSp->setPosition(Vec2(xStart + i * (contentWidth + sepWidth), yStart));
+        }
+        _updateIndSp();
+    }
+}
+
+void PurchaseBannerView::_updateIndSp() {
+    if (_dotSpArr.size() > 0) {
+        for (int i = 0; i < _pageCount; i++) {
+            string spname = i == _currentPageIndex ? _dotCfg.highSp : _dotCfg.normalSp;
+            _dotSpArr[i]->setSpriteFrame(spname);
+        }
+    }
+}
+
+void PurchaseBannerView::_resizeView() {
+    if (_scrollView == nullptr) {
+        return;
+    }
+    if (_isHori) {
+        _scrollView->setContentSize(Size(_viewSize.width * _pageCount, _viewSize.height));
+        _scrollView->setContentOffset(Vec2(-_currentPageIndex * _viewSize.width, 0));
+    } else {
+        _scrollView->setContentSize(Size(_viewSize.width, _viewSize.height * _pageCount));
+        _scrollView->getContainer()->setPositionY(-_viewSize.height * (_pageCount - 1));
+        _scrollView->setContentOffset(Vec2(0, -(_pageCount - 1 - _currentPageIndex) * _viewSize.height));
+    }
+}
+
+void PurchaseBannerView::onEnter() {
+    Layer::onEnter();
+    _touchedCount = 0;
+    _scrollView->setTouchEnabled(true);
+    _scrollView->setSwallowTouches(false);
+}
+
+void PurchaseBannerView::onExit() {
+    Layer::onExit();
+    //log("PageView ~ onExit");
+}
+
+void PurchaseBannerView::addBanner(PurchaseBannerCell* tmpNode) {
+    if (tmpNode == nullptr) {
+        return;
+    }
+    _pageCount++;
+    _currentPageIndex = 0;
+    this->_resizeView();
+    int addInIdx = _pageCount - 1;
+    if (_isHori) {
+        tmpNode->setPositionX(_viewSize.width * addInIdx);
+    } else {
+        tmpNode->setPositionY(_viewSize.height * (_pageCount - addInIdx - 1));
+    }
+    tmpNode->setAnchorPoint(Vec2(0,0));
+    _scrollView->getContainer()->addChild(tmpNode,0,addInIdx);
+    tmpNode->setIdx(addInIdx);
+    this->_initDotAdded();
+}
+
+void PurchaseBannerView::reloadData(int pageCount, int defaultIndex) {
+    _scrollView->getContainer()->removeAllChildren();
+    _currentPageIndex = defaultIndex;
+    _pageCount = pageCount;
+    this->_resizeView();
+    this->_generatePage();
+    if (_pageViewDelegate != nullptr) {
+        _pageViewDelegate->onPageChanged(_currentPageIndex, defaultIndex > 0);
+    }
+    this->_initDotInd();
+}
+
+void PurchaseBannerView::setCurrentPageIndex(int index) {
+    if (index != _currentPageIndex && index >= 0 && index < _pageCount) {
+        _currentPageIndex = index;
+        this->_generatePage();
+        this->_removeExpirePage();
+        _scrollView->setContentOffset(Vec2(-_currentPageIndex * _viewSize.width, 0));
+        this->_notifyPageChanged(true);
+    }
+}
+
+PurchaseBannerCell* PurchaseBannerView::getCurrentPage() {
+    return dynamic_cast<PurchaseBannerCell*>(_scrollView->getContainer()->getChildByTag(_currentPageIndex));
+}
+
+int PurchaseBannerView::getCurrentPageIdx() {
+    return _currentPageIndex;
+}
+
+void PurchaseBannerView::moveToPrePage() {
+    if (_currentPageIndex > 0) {
+        --_currentPageIndex;
+        this->_beginNewMoveToAnimation(0);
+    }
+}
+
+void PurchaseBannerView::moveToNextPage() {
+    if (_currentPageIndex < _pageCount - 1) {
+        ++_currentPageIndex;
+        this->_beginNewMoveToAnimation(0);
+    }
+}
+
+void PurchaseBannerView::moveReferToPageIndex(int delta) {
+    if (delta > 0 && _currentPageIndex + delta < _pageCount - 1) {
+        _currentPageIndex += delta;
+        this->_beginNewMoveToAnimation(0);
+    } else if (delta < 0 && delta + _currentPageIndex >= 0) {
+        _currentPageIndex += delta;
+        this->_beginNewMoveToAnimation(0);
+    }
+}
+
+void PurchaseBannerView::moveToFirstPage() {
+    _currentPageIndex = 0;
+    this->_beginNewMoveToAnimation(0);
+}
+
+int PurchaseBannerView::getPageCount() {
+    return _pageCount;
+}
+
+void PurchaseBannerView::_generatePage() {
+    if (_pageViewDelegate == nullptr || _cachePages) {
+        return;
+    }
+    for (int i = _currentPageIndex - 1; i <= _currentPageIndex + 1; i++) {
+        if (i >= 0 && i < _pageCount) {
+            PurchaseBannerCell* page = dynamic_cast<PurchaseBannerCell*>(_scrollView->getContainer()->getChildByTag(i));
+            if (page == nullptr) {
+                page = _pageViewDelegate->pageCellAtIndex(this, i);
+                if (_isHori) {
+                    page->setPositionX(_viewSize.width * i);
+                } else {
+                    page->setPositionY(_viewSize.height * (_pageCount - i - 1));
+                }
+                _scrollView->getContainer()->addChild(page,0,i);
+                page->setIdx(i);
+            }
+        }
+    }
+}
+
+void PurchaseBannerView::_removeExpirePage() {
+    if (_cachePages) {
+        return;
+    }
+    int firstLeftPageIndex = _currentPageIndex - 2;
+    int lastRightPageIndex = _currentPageIndex + 2;
+    for (int i = 0; i <= firstLeftPageIndex; i++) {
+        PurchaseBannerCell* page =  dynamic_cast<PurchaseBannerCell*>(_scrollView->getContainer()->getChildByTag(i));
+        if (page != nullptr) {
+            _scrollView->getContainer()->removeChild(page);
+        }
+    }
+    for (int i = lastRightPageIndex; i < _pageCount; i++) {
+        PurchaseBannerCell* page =  dynamic_cast<PurchaseBannerCell*>(_scrollView->getContainer()->getChildByTag(i));
+        if (page != nullptr ) {
+            _scrollView->getContainer()->removeChild(page);
+        }
+    }
+}
+
+void PurchaseBannerView::_beginNewMoveToAnimation(float dt) {
+    _scrollView->unscheduleAllCallbacks();
+    _scrollView->getContainer()->stopAllActions();
+    if (_isHori) {
+        _scrollView->setContentOffset(Vec2(-_currentPageIndex * _viewSize.width,0),true);
+    } else {
+        _scrollView->setContentOffset(Vec2(0,-(_pageCount - _currentPageIndex - 1) * _viewSize.height),true);
+    }
+    this->_generatePage();
+    this->_removeExpirePage();
+    auto thisnode = this;
+    this->scheduleOnce([=](float dt){
+        thisnode->_notifyPageChanged(false);
+    },0.18,"notifyPageChanged");
+}
+
+void PurchaseBannerView::_notifyPageChanged(bool manualSet) {
+    if (_pageViewDelegate != nullptr) {
+        _pageViewDelegate->onPageChanged(_currentPageIndex, manualSet);
+    }
+    this->_updateIndSp();
+    this->_autoSetBounceable();
+}
+
+void PurchaseBannerView::_autoSetBounceable() {
+    if (_currentPageIndex == 0 || _currentPageIndex == _pageCount - 1) {
+        _scrollView->setBounceable(true);
+    } else {
+        _scrollView->setBounceable(false);
+    }
+}
+
+bool PurchaseBannerView::onTouchBegan(Touch* touch, Event* unused_event) {
+    if (this->isTouchedInNode(this,touch)) {
+        //log("PageView : onTouchBegan!");
+        if (this->isTouchedInNode(_scrollView,touch,true,_scrollView->getViewSize())) {
+            _touchedCount++;
+            if (_touchedCount == 1) {
+                _touchBeganPoint = touch->getLocation();
+                this->_autoSetBounceable();
+                if (_pageViewDelegate != nullptr) {
+                    _pageViewDelegate->onPageTouchBegan(touch);
+                }
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+void PurchaseBannerView::onTouchEnded(Touch* touch, Event* unused_event) {
+    //log("PageView - onTouchEnded");
+    Vec2 newPoint = touch->getLocation();
+    if (_scrollViewMoved) {
+        bool autoScroll = false;
+        if (_isHori) {
+            if (newPoint.x > _touchBeganPoint.x && _currentPageIndex > 0) {
+                //<-
+                _currentPageIndex--;
+                autoScroll = true;
+            } else if (newPoint.x < _touchBeganPoint.x && _currentPageIndex < _pageCount - 1) {
+                //->
+                _currentPageIndex++;
+                autoScroll = true;
+            }
+        } else {
+            if (newPoint.y < _touchBeganPoint.y && _currentPageIndex > 0) {
+                //-/|\;
+                _currentPageIndex--;
+                autoScroll = true;
+            } else if (newPoint.y > _touchBeganPoint.y && _currentPageIndex < _pageCount - 1) {
+                //-\|/
+                _currentPageIndex++;
+                autoScroll = true;
+            }
+        }
+        if (autoScroll) {
+            _scrollView->setBounceable(false);
+            this->scheduleOnce(CC_SCHEDULE_SELECTOR(PurchaseBannerView::_beginNewMoveToAnimation),0);
+        }
+        _scrollViewMoved = false;
+    } else if (_touchedCount == 1) {
+        if (this->isTouchedInNode(_scrollView,touch,true,_scrollView->getViewSize())) {
+            PurchaseBannerCell* page = dynamic_cast<PurchaseBannerCell*>(_scrollView->getContainer()->getChildByTag(_currentPageIndex));
+            if (_pageViewDelegate != nullptr) {
+                _pageViewDelegate->pageCellTouched(touch, page);
+            }
+        }
+    }
+    _touchedCount = 0;
+}
+
+void PurchaseBannerView::scrollViewDidScroll(cocos2d::extension::ScrollView* view) {
+    _scrollViewMoved = _scrollView->isTouchMoved();
+}
+
+bool PurchaseBannerView::isTouchedInNode(Node* node, Touch* touch, bool isAnotherSize, Vec2 anotherSize) {
+    Size contentSize = Size::ZERO;
+    if (isAnotherSize) {
+        contentSize = Size(anotherSize.x,anotherSize.y);
+    } else {
+        contentSize = node->getContentSize();
+    }
+    Vec2 pos = node->convertTouchToNodeSpace(touch);
+    if (pos.x >= 0 && pos.x <= contentSize.width) {
+        if (pos.y >= 0 && pos.y <= contentSize.height) {
+            return true;
+        }
+    }
+    return false;
+}

+ 118 - 0
Classes/IAP/purchaseBanner/PurchaseBannerView.hpp

@@ -0,0 +1,118 @@
+//
+//  PurchaseBannerView.hpp
+//  MyGameCpp
+//
+//  Created by zhang yuntao on 2017/10/10.
+//
+//
+#ifndef PurchaseBannerView_hpp
+#define PurchaseBannerView_hpp
+
+#include "cocos2d.h"
+#include "extensions/cocos-ext.h"
+#include "PurchaseBannerCell.hpp"
+
+/*
+ PageView类:
+     主要用途:    为了模仿iPhone的主屏幕page滑动页控件,使用场景:一些帮助页面使用。有的格子关卡页面等等。
+     使用说明:
+         1. 使用 PageView* create(cocos2d::Size& viewSize, sDotCfg & dotCfg, bool cachePages)来创建.
+             一般在ccb里设置好node的大小,然后得到大小传过来。cachePages:需不需要来缓存各个page,出于性能考虑,不缓存的话,通常只有三个页面存在
+             于内存中。来回迭代创建而已。
+             代码创建出来后一般设置 原点和锚点都为0, 再放在上面ccb设置的node上面。
+             然后设置delegate为自己类,且实现代理方法。
+             //下方小圆圈这个功能是可选择的,如果不需要,上面dotCfg随便创建一个对象传进去就成。
+             _initDotInd()
+             //初始完毕后,使用下面函数刷新数据.
+             reloadData(int pageCount, int defaultIndex = 0);
+
+         2. sDotCfg为iPhone主屏下方小圆圈配置。定义如下:
+             struct sDotCfg {
+                 int sepWidth = 0;            //每个小圆圈之间的间距
+                 int yStart = 0;                //默认是在viewSize的底部.也可以设置偏移.
+                 string highSp = "";            //当前页高亮与普通对应的图片.
+                 string normalSp = "";
+             };
+
+         3. 实现三个代理方法:
+             //创建cell页面。
+             virtual PageViewCell* pageCellAtIndex(PageView * pageView, int index) = 0;
+             //点击到pagecell时的通知。
+             virtual void pageCellTouched (Touch * touch, PageViewCell * page) = 0;
+             //当前页面发生改变时通知。manualSet来区分是不是调用setCurrentPageIndex()手动使当前页面刷新。
+             virtual void onPageChanged(int currentPageIndex, bool manualSet) = 0;
+
+         4. 自定义的 pageCell 必须承继于 PageViewCell,只是承继而已,别的不需要做什么。
+ */
+
+class PurchaseBannerView;
+class PurchaseBannerViewDelegate {
+public:
+    virtual PurchaseBannerCell* pageCellAtIndex(PurchaseBannerView* pageView, int index) = 0;
+    virtual void pageCellTouched(Touch* touch, PurchaseBannerCell* page) = 0;
+    virtual void onPageChanged(int currentPageIndex, bool manualSet) = 0;
+    virtual void onPageTouchBegan(Touch* touch) = 0;
+};
+
+class PurchaseBannerView : public Layer, public cocos2d::extension::ScrollViewDelegate {
+public:
+    struct sDotCfg {
+        int sepWidth = 0;
+        int yStart = 0;
+        string highSp = "";
+        string normalSp = "";
+    };
+    
+    static PurchaseBannerView* create(Size& viewSize, sDotCfg& dotCfg, bool cachePages,bool isHor = true);
+    void init(Size& viewSize, sDotCfg& dotCfg, bool cachePages, bool isHor);
+    
+    virtual void onEnter() override;
+    virtual void onExit() override;
+    
+    void setDelegate(PurchaseBannerViewDelegate* delegate);
+    
+    void addBanner(PurchaseBannerCell* tmpNode);
+    void reloadData(int pageCount, int defaultIndex = 0);
+    void setCurrentPageIndex(int index);
+    PurchaseBannerCell* getCurrentPage();
+    int getCurrentPageIdx();
+    void moveToPrePage();
+    void moveToNextPage();
+    void moveReferToPageIndex(int delta);
+    void moveToFirstPage();
+    int getPageCount();
+    
+    virtual void scrollViewDidScroll(cocos2d::extension::ScrollView* view) override;
+    
+    virtual bool onTouchBegan(Touch* touch, Event* unused_event) override;
+    virtual void onTouchEnded(Touch* touch, Event* unused_event) override;
+    
+private:
+    PurchaseBannerViewDelegate* _pageViewDelegate = nullptr;
+    int _currentPageIndex = 0;
+    int _pageCount = 0;
+    cocos2d::extension::ScrollView* _scrollView = nullptr;
+    Size _viewSize = Size::ZERO;
+    Vec2 _touchBeganPoint = Vec2::ZERO;
+    int _touchedCount = 0;
+    sDotCfg _dotCfg;
+    bool _cachePages = false;
+    bool _scrollViewMoved = false;
+    bool _isHori = true;
+    //dot
+    bool _initedDot = false;
+    vector<Sprite*> _dotSpArr = {};
+    
+    void _resizeView();
+    void _generatePage();
+    void _initDotInd();
+    void _initDotAdded();
+    void _updateIndSp();
+    void _removeExpirePage();
+    void _beginNewMoveToAnimation(float dt);
+    void _notifyPageChanged(bool manualSet);
+    void _autoSetBounceable();
+    
+    bool isTouchedInNode(Node* node, Touch* touch, bool isAnotherSize = false, Vec2 anotherSize = Vec2::ZERO);
+};
+#endif /* CPageView_hpp */

+ 162 - 0
Classes/IAP/purchaseBanner/RedreamLoader.cpp

@@ -0,0 +1,162 @@
+#include "RedreamLoader.h"
+
+RedreamLoader::RedreamLoader() {
+}
+
+RedreamLoader::~RedreamLoader() {
+    _mapChilden.clear();
+    if (_loaderReboltRedManager != nullptr) {
+        _loaderReboltRedManager->release();
+        _loaderReboltRedManager = nullptr;
+    }
+}
+
+RedreamLoader* RedreamLoader::Layer(string file) {
+    auto lib = redream::NodeLoaderLibrary::newDefaultNodeLoaderLibrary();
+    lib->registerNodeLoader("RedreamLoader",RedreamLoaderLoader::loader());
+    redream::REDReader* reader = new redream::REDReader(lib);
+    RedreamLoader* node = (RedreamLoader*)reader->readNodeGraphFromFile(file.c_str());
+    reader->autorelease();
+    return node;
+}
+
+RedreamLoader* RedreamLoader::LayerWithLib(string file,redream::NodeLoaderLibrary* lib) {
+    lib->registerNodeLoader("RedreamLoader",RedreamLoaderLoader::loader());
+    redream::REDReader* reader = new redream::REDReader(lib);
+    RedreamLoader* node = (RedreamLoader*)reader->readNodeGraphFromFile(file.c_str());
+    reader->autorelease();
+    return node;
+}
+
+RedreamLoader* RedreamLoader::ReboltLayer(string file) {
+    auto reboltlib = redream::NodeLoaderLibrary::newDefaultNodeLoaderLibrary();
+    reboltlib->registerNodeLoader("RedreamLoader",RedreamLoaderLoader::loader());
+    redream::REDReader* reboltReader = new redream::REDReader(reboltlib);
+    RedreamLoader* tmpNode = nullptr;
+    try {
+        tmpNode = (RedreamLoader*)reboltReader->readNodeGraphFromFile(file.c_str());
+        redream::ReboltRedManager* reboltM = reboltReader->getReboltRedManager();
+        reboltM->retain();
+        reboltM->setNotifyDevelopmentDelegate(tmpNode);
+        auto reboltmangs = reboltReader->getReboltRedManagerMapPtr();
+        for (auto it = reboltmangs->begin(); it != reboltmangs->end(); it++) {
+            auto rrm = it->second;
+            rrm->setNotifyDevelopmentDelegate(tmpNode);
+        }
+        tmpNode->_loaderReboltRedManager = reboltM;
+        reboltReader->release();
+    } catch (string str) {
+        CCLOG("loader error : %s", str.c_str());
+        assert(false);
+    }
+    return tmpNode;
+}
+
+RedreamLoader* RedreamLoader::ReboltLayerWithLib(string file,redream::NodeLoaderLibrary* reboltlib) {
+    reboltlib->registerNodeLoader("RedreamLoader",RedreamLoaderLoader::loader());
+    redream::REDReader* reboltReader = new redream::REDReader(reboltlib);
+    RedreamLoader* tmpNode = nullptr;
+    try {
+        tmpNode = (RedreamLoader*)reboltReader->readNodeGraphFromFile(file.c_str());
+        redream::ReboltRedManager* reboltM = reboltReader->getReboltRedManager();
+        reboltM->retain();
+        reboltM->setNotifyDevelopmentDelegate(tmpNode);
+        auto reboltmangs = reboltReader->getReboltRedManagerMapPtr();
+        for (auto it = reboltmangs->begin(); it != reboltmangs->end(); it++) {
+            auto rrm = it->second;
+            rrm->setNotifyDevelopmentDelegate(tmpNode);
+        }
+        tmpNode->_loaderReboltRedManager = reboltM;
+        reboltReader->release();
+    } catch (string str) {
+        CCLOG("loader error : %s", str.c_str());
+        assert(false);
+    }
+    return tmpNode;
+}
+
+SEL_MenuHandler RedreamLoader::onResolveREDCCMenuItemSelector(Ref* pTarget,const char* pSelectorName) {
+    return nullptr;
+}
+
+cocos2d::extension::Control::Handler RedreamLoader::onResolveREDCCControlSelector(cocos2d::Ref* pTarget,const char* pSelectorName) {
+    //RED_SELECTORRESOLVER_CCCONTROL_GLUE(this, "OnClickCCBButton", RedreamLoader::OnClickCCBButton);
+    return nullptr;
+}
+
+cocos2d::SEL_CallFuncN RedreamLoader::onResolveREDCCCallFuncSelector(cocos2d::Ref* pTarget,const char* pSelectorName) {
+    //RED_SELECTORRESOLVER_CALLFUNC_GLUE(this,"onCCBTimeLineCallBacks",RedreamLoader::onCCBTimeLineCallBacks);
+    return nullptr;
+}
+
+bool RedreamLoader::onAssignREDMemberVariable(cocos2d::Ref* pTarget,const char* pMemberVariableName,cocos2d::Node* node) {
+    if (pTarget == this && node != this && strcmp(pMemberVariableName,"") != 0) {
+        _mapChilden.insert(pair<string,Node*>(string(pMemberVariableName),node));
+        return true;
+    }
+    return false;
+}
+
+void RedreamLoader::onNodeLoaded(cocos2d::Node* node,redream::NodeLoader* nodeLoader) {
+    //loaded after
+}
+
+void RedreamLoader::completedAnimationSequenceNamed(const char* name,int seqId,int tag) {
+}
+
+Node* RedreamLoader::getByName(std::string name) {
+    return _mapChilden[name];
+}
+
+Sprite* RedreamLoader::getSprite(std::string name) {
+    return (Sprite*)_mapChilden[name];
+}
+
+Label* RedreamLoader::getLabel(std::string name) {
+    return (Label*)_mapChilden[name];
+}
+
+ParticleSystemQuad* RedreamLoader::getParticle(std::string name) {
+    return (ParticleSystemQuad*)_mapChilden[name];
+}
+
+redream::REDNodeButton* RedreamLoader::getREDNodeButton(std::string name) {
+    return dynamic_cast<redream::REDNodeButton*>(_mapChilden[name]);
+}
+
+RedreamLoader* RedreamLoader::getSubLoader(std::string name) {
+    return (RedreamLoader*)_mapChilden[name];
+}
+
+void RedreamLoader::stopAnimAll() {
+    this->stopAllActions();
+}
+
+float RedreamLoader::playAnim(std::string anim) {
+    Ref* obj = this->getUserObject();
+    redream::REDAnimationManager* ret = dynamic_cast<redream::REDAnimationManager*>(obj);
+    if (ret != nullptr) {
+        ret->runAnimationsForSequenceNamed(anim.c_str());
+        return ret->getSequenceDuration(anim.c_str());
+    }
+    return 0;
+}
+
+float RedreamLoader::getAnimTime(std::string anim) {
+    Ref* obj = this->getUserObject();
+    redream::REDAnimationManager* ret = dynamic_cast<redream::REDAnimationManager*>(obj);
+    if (ret != nullptr) {
+        return ret->getSequenceDuration(anim.c_str());
+    }
+    return 0;
+}
+
+redream::ReboltRedManager* RedreamLoader::getReboltManager() {
+    return _loaderReboltRedManager;
+}
+
+void RedreamLoader::onNotifyDevelopment(redream::ReboltRedManager* reboltRedManager,redream::NotifyDevelopmentWaiter* waiter,std::string notify,std::string param,bool reboltIsWait,Node* outNode) {
+    if (_reboltCallBack != nullptr) {
+        _reboltCallBack(reboltRedManager,waiter,notify,param,reboltIsWait,outNode);
+    }
+}

+ 58 - 0
Classes/IAP/purchaseBanner/RedreamLoader.h

@@ -0,0 +1,58 @@
+#ifndef __RedreamLoader__
+#define __RedreamLoader__
+
+#include "cocos2d.h"
+#include "extensions/cocos-ext.h"
+#include "Redream.h"
+#include "REDReader.h"
+
+class RedreamLoader : public Layer
+,public redream::REDSelectorResolver
+,public redream::REDMemberVariableAssigner
+,public redream::NodeLoaderListener
+,public redream::REDAnimationManagerDelegate
+,public redream::NotifyDevelopmentDelegate {
+public:
+    static RedreamLoader* Layer(string file);
+    static RedreamLoader* LayerWithLib(string file,redream::NodeLoaderLibrary* lib);
+    static RedreamLoader* ReboltLayer(string file);
+    static RedreamLoader* ReboltLayerWithLib(string file,redream::NodeLoaderLibrary* lib);
+    RED_STATIC_NEW_AUTORELEASE_OBJECT_WITH_INIT_METHOD(RedreamLoader,create);
+    RedreamLoader();
+    ~RedreamLoader();
+    
+    virtual cocos2d::SEL_MenuHandler onResolveREDCCMenuItemSelector(cocos2d::Ref* pTarget,const char* pSelectorName) override;
+    virtual cocos2d::extension::Control::Handler onResolveREDCCControlSelector(cocos2d::Ref* pTarget,const char* pSelectorName) override;
+    virtual cocos2d::SEL_CallFuncN onResolveREDCCCallFuncSelector(cocos2d::Ref* pTarget,const char* pSelectorName) override;
+    virtual bool onAssignREDMemberVariable(cocos2d::Ref* pTarget,const char* pMemberVariableName,cocos2d::Node* node) override;
+    virtual void onNodeLoaded(cocos2d::Node* node,redream::NodeLoader* nodeLoader) override;
+    void completedAnimationSequenceNamed(const char *name, int seqId, int tag) override;
+    //rebolt
+    virtual void onNotifyDevelopment(redream::ReboltRedManager* reboltRedManager,redream::NotifyDevelopmentWaiter* waiter,std::string notify,std::string param,bool reboltIsWait,Node* outNode) override;
+    
+    float playAnim(std::string anim);
+    float getAnimTime(std::string anim);
+    void stopAnimAll();
+    redream::ReboltRedManager* getReboltManager();
+    //get sub node
+    Node* getByName(std::string name);
+    Sprite* getSprite(std::string name);
+    Label* getLabel(std::string name);
+    ParticleSystemQuad* getParticle(std::string name);
+    redream::REDNodeButton* getREDNodeButton(std::string name);
+    RedreamLoader* getSubLoader(std::string name);
+    //rebolt
+    std::function<void(redream::ReboltRedManager*,redream::NotifyDevelopmentWaiter*,std::string,std::string,bool,Node*)> _reboltCallBack = nullptr;
+private:
+    std::map<string,Node*> _mapChilden;
+    redream::ReboltRedManager* _loaderReboltRedManager = nullptr;
+};
+
+class RedreamLoaderLoader : public redream::LayerLoader {
+public:
+    RED_STATIC_NEW_AUTORELEASE_OBJECT_METHOD(RedreamLoaderLoader,loader);
+protected:
+    RED_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(RedreamLoader);
+};
+
+#endif /* RedreamLoader */

+ 6 - 0
proj.ios_mac/demo.xcodeproj/project.pbxproj

@@ -59,6 +59,8 @@
 		C18082332CCB71D3009DE140 /* IAPTestCardViewDelegate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C18082312CCB71D3009DE140 /* IAPTestCardViewDelegate.cpp */; };
 		C18082342CCB71D3009DE140 /* IAPTestCardViewDelegate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C18082312CCB71D3009DE140 /* IAPTestCardViewDelegate.cpp */; };
 		C180823B2CCB82BD009DE140 /* IAPRunTimeData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C18082382CCB82BD009DE140 /* IAPRunTimeData.cpp */; };
+		C19B68922CD1D30B00536ED4 /* purchaseBanner in Resources */ = {isa = PBXBuildFile; fileRef = C19B688A2CD1D30B00536ED4 /* purchaseBanner */; };
+		C19B68932CD1D30B00536ED4 /* purchaseBanner in Resources */ = {isa = PBXBuildFile; fileRef = C19B688A2CD1D30B00536ED4 /* purchaseBanner */; };
 		D44C620C132DFF330009C878 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D44C620B132DFF330009C878 /* OpenAL.framework */; };
 		D44C620E132DFF430009C878 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D44C620D132DFF430009C878 /* AVFoundation.framework */; };
 		D44C6210132DFF4E0009C878 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D44C620F132DFF4E0009C878 /* AudioToolbox.framework */; };
@@ -205,6 +207,7 @@
 		C18082322CCB71D3009DE140 /* IAPTestCardViewDelegate.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = IAPTestCardViewDelegate.hpp; sourceTree = "<group>"; };
 		C18082382CCB82BD009DE140 /* IAPRunTimeData.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = IAPRunTimeData.cpp; sourceTree = "<group>"; };
 		C18082392CCB82BD009DE140 /* IAPRunTimeData.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = IAPRunTimeData.hpp; sourceTree = "<group>"; };
+		C19B688A2CD1D30B00536ED4 /* purchaseBanner */ = {isa = PBXFileReference; lastKnownFileType = folder; path = purchaseBanner; sourceTree = "<group>"; };
 		D44C620B132DFF330009C878 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = System/Library/Frameworks/OpenAL.framework; sourceTree = SDKROOT; };
 		D44C620D132DFF430009C878 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
 		D44C620F132DFF4E0009C878 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
@@ -375,6 +378,7 @@
 				2F15C5E62CB8F65A0057855D /* IAPDelegate.hpp */,
 				2F15C5EA2CB8F65A0057855D /* IAPCtlShop.hpp */,
 				2F15C5DE2CB8F65A0057855D /* IAPCtlShop.cpp */,
+				C19B688A2CD1D30B00536ED4 /* purchaseBanner */,
 				C1CA495B2CD08C37002745E2 /* Test */,
 				2F15C5DF2CB8F65A0057855D /* Shop */,
 				2F15C5E72CB8F65A0057855D /* User */,
@@ -688,6 +692,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				18BC68102106EAB400288C27 /* Images.xcassets in Resources */,
+				C19B68922CD1D30B00536ED4 /* purchaseBanner in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -697,6 +702,7 @@
 			files = (
 				23F924B52ADCE4A500563AFD /* Icon.icns in Resources */,
 				23F924B42ADCE49D00563AFD /* Images.xcassets in Resources */,
+				C19B68932CD1D30B00536ED4 /* purchaseBanner in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};