• cocos2d-x 托付模式的巧妙运用——附源代码(一)


    先来说一下托付模式是什么。以下的内容摘要自维基百科:

    托付模式是软件设计模式中的一项基本技巧。在托付模式中,有两个对象參与处理同一个请求。接受请求的对象将请求托付给还有一个对象来处理。托付模式是一项基本技巧。更多的模式,如状态模式、策略模式、訪问者模式本质上是在更特殊的场合採用了托付模式。托付模式使得我们能够用聚合来替代继承。

    简单的Java样例

    在此例中。类模拟打印机Printer拥有针式打印机RealPrinter的实例,Printer拥有的方法print()将处理转交给RealPrinter的print()方法。

     class RealPrinter { // the "delegate"
         void print() { 
           System.out.print("something"); 
         }
     }
     
     class Printer { // the "delegator"
         RealPrinter p = new RealPrinter(); // create the delegate 
         void print() { 
           p.print(); // delegation
         } 
     }
     
     public class Main {
         // to the outside world it looks like Printer actually prints.
         public static void main(String[] args) {
             Printer printer = new Printer();
             printer.print();
         }
     }
    复杂的Java样例

    通过使用接口,托付能够做到类型安全而且更加灵活。在这个样例中。类C能够托付类A或者类B。类C拥有方法使自己能够在类A或者类B间选择。由于类A或者类B必须实现接口I规定的方法。所以在这里托付是类型安全的。这个样例显示出托付的缺点就是须要很多其它的代码。

    interface I {
         void f();
         void g();
     }
     
     class A implements I {
         public void f() { System.out.println("A: doing f()"); }
         public void g() { System.out.println("A: doing g()"); }
     }
     
     class B implements I {
         public void f() { System.out.println("B: doing f()"); }
         public void g() { System.out.println("B: doing g()"); }
     }
     
     class C implements I {
         // delegation
         I i = new A();
     
         public void f() { i.f(); }
         public void g() { i.g(); }
     
         // normal attributes
         public void toA() { i = new A(); }
         public void toB() { i = new B(); }
     }
     
     
     public class Main {
         public static void main(String[] args) {
             C c = new C();
             c.f();     // output: A: doing f()
             c.g();     // output: A: doing g()
             c.toB();
             c.f();     // output: B: doing f()
             c.g();     // output: B: doing g()
         }
     }

    介绍了托付模式。根本上讲就是我是一个对象,我须要做的事我托付还有一个对象来做,这样就降低了我这个对象所要做的事情,我仅仅需把须要的东西都托付给还有一个对象,它能自行处理我的需求。这样一来我这个对象所须要实现的代码就降低了。并且托付的对象能够反复利用,不光我这个对象。凡是有这个需求的都能够托付这个对象来处理相同的事,降低了开发中的反复代码。

    对于cocos2d-x中的托付设计模式,在这里我不讲GUI方面的托付模式。比如Menu的响应事件。Button的响应事件,我主要将一下在游戏控制中。推断游戏開始、执行、结束时用到的托付模式。这样把这三个逻辑都交给一个托付类来实现。思路较清晰,并且能够反复利用,降低开发周期。

    游戏中的主要逻辑都集中在GameLayer层中,在GameScene场景中加入所须要的Layer层,然后在各个Layer层中实现对应的逻辑。

    对于大多数的开发中,我都是在一个GameLayer层中完毕游戏中的全部逻辑推断。后来感觉这样的方法使GameLayer层的代码太臃肿,太不清晰,自己看着都想重构一下代码。

    接下来以一个小demo来介绍下cocos2d-x中的托付模式的巧妙运用,使游戏开发更清晰,更快捷。

    先来看一下托付类。游戏中的開始、执行、结束的逻辑推断都在这个托付类中实现。

    以下是托付类的实现代码,StatusLayer.h的详细代码

    #include "cocos2d.h"
    #include "GameLayer.h"
    
    USING_NS_CC;
    
    const int SPRITE_TITLE_TAG = 1000;
    /**
     * StatusDelegate 是托付类的父类。在GameLayer中实现三个虚函数
     * 具体代码例如以下
     * class StatusDelegate {
     *	public:
     *		virtual void onGameStart() = 0;
     *		virtual void onGamePlaying() = 0;
     *		virtual void onGameEnd() = 0;
     *	};
     */
    class StatusLayer : public Layer ,public StatusDelegate{
    public:
    	StatusLayer(void);
    	~StatusLayer(void);
    
    	virtual bool init();
    	CREATE_FUNC(StatusLayer);
    
    	//实现父类StatusDelegate的三个虚函数
    	void onGameStart();//游戏開始逻辑推断函数
    	void onGamePlaying();//游戏执行逻辑推断函数
    	void onGameEnd();//游戏结束逻辑推断函数
    
    private:
    
    	void moveFinished(Ref* pSender);//title精灵移动结束后回调此函数
    	void showRestartMenu(Ref* pSender);//显示又一次開始button
    	void showOverSprite();//显示GameOver精灵函数
    	void menuRestartCallback(cocos2d::Ref* pSender);//点击開始button后回调此函数
    	void menuShareCallback(cocos2d::Ref* pSender);//分享button回调button
    
    private:
    	Size visibleSize;
    	Point origin;
    	Sprite* gameOverSprite;
    };
    
    代码中不做太多解释。在该凝视的地方都有具体凝视。

    以下来看托付类StatusLayer的详细实现。

    Statuslayer.cpp

    /*
     * StatusLayer.cpp
     *
     *  Created on: 2014年7月29日
     *      Author: tubuntu
     */
    #include "StatusLayer.h"
    #include "GameScene.h"
    
    USING_NS_CC;
    
    StatusLayer::StatusLayer() {
    }
    
    StatusLayer::~StatusLayer() {
    }
    
    bool StatusLayer::init() {
    	if(!Layer::init()) {
    		return false;
    	}
    	//获取屏幕大小和原点坐标
    	visibleSize = Director::getInstance()->getVisibleSize();
    	origin = Director::getInstance()->getVisibleOrigin();
    	//加入游戏中的背景
    	Sprite* background = Sprite::createWithSpriteFrameName("flappyrec_welcome_bg.png");
    	background->setPosition(Point::ZERO);
    	background->setAnchorPoint(Point::ZERO);
    	this->addChild(background);
    
    	//加入游戏中的标题
    	Sprite* title = Sprite::createWithSpriteFrameName("flappyrec_welcome_title.png");
    	title->setPosition(Vec2(0-title->getContentSize().width,visibleSize.height*4/5));
    	title->setTag(SPRITE_TITLE_TAG);//设置tag值
    	this->addChild(title);
    
    	auto move = MoveTo::create(1.0f,Vec2(visibleSize.width/2-50,title->getPositionY()));
    	//移动结束后回调此函数
    	auto moveDone = CallFuncN::create(CC_CALLBACK_1(StatusLayer::moveFinished,this));
    	//先加速后减速的动画特效
    	EaseExponentialOut* sineIn = EaseExponentialOut::create(move);
    	//序列动画
    	auto sequence = Sequence::createWithTwoActions(sineIn,moveDone);
    	title->runAction(sequence);
    
    	return true;
    }
    
    /**
     * title移动结束后调用此函数
     */
    void StatusLayer::moveFinished(Ref* pSender) {
    	//TODO
    }
    
    /**
     * 托付类的方法。此方法会在GameLayer中被调用,用于游戏的開始
     */
    void StatusLayer::onGameStart(){
    	this->getChildByTag(SPRITE_TITLE_TAG)->runAction(FadeOut::create(0.4f));
    }
    
    /**
     * 托付类的方法,此方法会在GameLayer中被调用,用于游戏的执行中的逻辑实现
     */
    void StatusLayer::onGamePlaying(){
    	//TODO
    }
    
    /**
     * 托付类的方法,此方法会在GameLayer中被调用,用于游戏的结束逻辑的实现
     */
    void StatusLayer::onGameEnd(){
    	this->showOverSprite();
    
    }
    /**
     * gameOverSprite精灵的加入,并加入从下到上出现的动作。
     * 动作结束后调用显示button的函数
     */
    void StatusLayer::showOverSprite() {
    
    	gameOverSprite = Sprite::createWithSpriteFrameName("flappyrec_welcome_rec.png");
    	gameOverSprite->setPosition(Vec2(visibleSize.width / 2,0-gameOverSprite->getContentSize().height));
    	gameOverSprite->setScale(0.5f);
    	this->addChild(gameOverSprite);
    
    	auto move = MoveTo::create(0.8f ,Vec2(visibleSize.width/2,visibleSize.height/2 + 60));
    	auto moveDone = CallFuncN::create(CC_CALLBACK_1(StatusLayer::showRestartMenu,this));
    	EaseExponentialOut* sineIn = EaseExponentialOut::create(move);
    	Sequence* sequence = Sequence::createWithTwoActions(sineIn,moveDone);
    
    	gameOverSprite->runAction(sequence);
    }
    /**
     * button显示的回调函数。显示開始和分享button
     * 并为button设置回调函数
     */
    void StatusLayer::showRestartMenu(Ref* pSender) {
    
    	Node* tmpNode = Node::create();//两个button的父节点
    
    	Sprite* restartBtn = Sprite::createWithSpriteFrameName("play.png");
    	Sprite* restartBtnActive = Sprite::createWithSpriteFrameName("play.png");
    	restartBtn->setScale(0.6f);//缩放
    	restartBtnActive->setScale(0.6f);//缩放
    	restartBtnActive->setPositionY(-4);//先下移动四个单位
    
    	auto menuRestartItem = MenuItemSprite::create(restartBtn,restartBtnActive,NULL,
    			CC_CALLBACK_1(StatusLayer::menuRestartCallback,this));//设置button回调函数
    	auto menuRestart = Menu::create(menuRestartItem,NULL);
    	menuRestart->setPosition(Vec2(this->visibleSize.width/2 - 35,
    			this->visibleSize.height/2 - gameOverSprite->getContentSize().height/3 + 60.0f));
    	tmpNode->addChild(menuRestart);//将button加入到父节点中
    
    	Sprite* shareBtn = Sprite::createWithSpriteFrameName("share.png");
    	Sprite* shareBtnActive = Sprite::createWithSpriteFrameName("share.png");
    	shareBtn->setScale(0.6f);
    	shareBtnActive->setScale(0.6f);
    	shareBtnActive->setPositionY(-4);
    
    	auto menuShareItem = MenuItemSprite::create(shareBtn,shareBtnActive,NULL,
    			CC_CALLBACK_1(StatusLayer::menuShareCallback,this));//分享button的会点函数
    	auto menuShare = Menu::create(menuShareItem,NULL);
    	menuShare->setPosition(Point(this->visibleSize.width/2 + 65,
    			this->visibleSize.height/2 - gameOverSprite->getContentSize().height/3 + 60.0f));
    	tmpNode->addChild(menuShare);
    
    	this->addChild(tmpNode);//加入父节点
    	auto fadeIn = FadeIn::create(0.1f);//0.1s后显示出现
    	tmpNode->runAction(fadeIn);//父节点执行动作
    }
    
    /**
     * 又一次開始button的回调函数,再次開始游戏
     */
    void StatusLayer::menuRestartCallback(cocos2d::Ref* pSender){
        auto scene = GameScene::create();
        TransitionScene *transition = TransitionFade::create(1, scene);
        Director::getInstance()->replaceScene(transition);
    }
    /**
     * 分享button的回调函数
     */
    void StatusLayer::menuShareCallback(cocos2d::Ref* pSender){
    	//TODO
    }
    
    上面的函数都做了具体的凝视,后面会给出具体的源代码。

    托付类中的实现主要是实现了父类StatusDelegate类中的三个虚函数onGameStart(),onGamePlaying(),onGameEnd()。这三个函数不必在GameLayer中实现,能够在GameLayer中调用托付类中的这三个函数。来实现对应的逻辑推断,也起到了GameLayer层和StatusLayer层通信的目的。

    好了,这篇介绍了详细的托付类的实现,下一篇介绍这个托付类的详细使用。





  • 相关阅读:
    Android:实现手势滑动的事件处理方法
    Android开发——跟随手指的小球实现
    android 关于setWidth()和setHeight()没反应的问题
    Android 设置 横屏 竖屏
    Android给TextView设置透明背景、圆角边框
    android 为TextView添加边框
    C++实现RTMP协议发送H.264编码及AAC编码的音视频
    视频编码器
    HTTP Live Streaming直播(iOS直播)技术分析与实现
    nginx上搭建HLS流媒体服务器
  • 原文地址:https://www.cnblogs.com/zsychanpin/p/7249829.html
Copyright © 2020-2023  润新知