订婚app要么game'肯定不会陌生:CCScrollView并且CCTableView。

假如我不知道是什么CCScrollView,再看看testcpp要么testlua样品棒。

先说说CCScrollView:.cpp和.h文件在\cocos2d-x-2.2.3\extensions\GUI\文件夹下,所以要使用CCScrollView首先要引入头文件#include "cocos-ext.h",以及空间名USING_NS_CC_EXT; 假设头文件报错,那么请检查project的配置。这里就不多说了无非是引用,link的输入和c/c++里面的附加包括文件夹。(ps:假设是个简单的project个人建议你又一次建个新project)。

#include "cocos-ext.h"
USING_NS_CC_EXT;
void HelloWorld::initScroll(){
  CCSize size = CCDirector::sharedDirector()->getWinSize();
  CCScrollView* scroll = CCScrollView::create(size); //scroll->setViewSize(size);
  scroll->setDirection(kCCScrollViewDirectionVertical);  //设置滚动方向
  CCSprite* p1 = CCSprite::create("HelloWorld.png");
  p1->ignoreAnchorPointForPosition(true);
  CCSprite* p2 = CCSprite::create("HelloWorld.png");
  p2->setPosition(ccp(0,size.height));
  p2->ignoreAnchorPointForPosition(true);
  CCLayer* conLayer = CCLayer::create();
  conLayer->addChild(p1);
  conLayer->addChild(p2);
  scroll->setContainer(conLayer);
  scroll->setContentSize(CCSizeMake(size.width,320*2));
  this->addChild(scroll);
}

执行以上代码。我们就能够使用Scrollview了,总结起来就是

1、create scrollview

2、create Container层

3、将内容add到containner层

4、container层add到scrollview,scrollview增加指定layer或者scene

这里有几个点须要注意:

1、setContentSize不是scrollview大小,而是可滑动面的大小,viewSize是滑动面大小。

2、setContentSize不能放在setContainer前面,假设放在前面。那么这个滑动后回自己主动回到第一页。

3、container层中的内容position须要手动设定

4、假设不create container层,那么CCScrollView会给你创建个一个,可是直接在scrollview下add多个node仅仅会保留一个,原因在后面分析。

好了。最easy的部分写完了,以下分析一下CCScrollView的源代码和一些让人蛋疼的东西。

CCScrollView::CCScrollView()
: m_fZoomScale(0.0f)
, m_fMinZoomScale(0.0f)
, m_fMaxZoomScale(0.0f)
, m_pDelegate(NULL) //view管理器
, m_eDirection(kCCScrollViewDirectionBoth) //滚动类型
, m_bDragging(false)
, m_pContainer(NULL) //container层
, m_bTouchMoved(false)
, m_bBounceable(false) //弹性开关
, m_bClippingToBounds(false) //弹性开关
, m_fTouchLength(0.0f)
, m_pTouches(NULL)
, m_fMinScale(0.0f)
, m_fMaxScale(0.0f)
{ }
CCScrollView* CCScrollView::create(CCSize size, CCNode* container/* = NULL*/)
{
CCScrollView* pRet = new CCScrollView();
if (pRet && pRet->initWithViewSize(size, container))
{
pRet->autorelease();
}
else
{
CC_SAFE_DELETE(pRet);
}
return pRet;
}
bool CCScrollView::initWithViewSize(CCSize size, CCNode *container/* = NULL*/)
{
if (CCLayer::init())//scrollview继承CCLayer
{
m_pContainer = container; if (!this->m_pContainer)
{
m_pContainer = CCLayer::create();//create container层
this->m_pContainer->ignoreAnchorPointForPosition(false);
this->m_pContainer->setAnchorPoint(ccp(0.0f, 0.0f));
} this->setViewSize(size);//设置视图尺寸,假设使用CCScrollView::create() 引擎会设置 size 为 CCSizeMake(200, 200) setTouchEnabled(true); //scrollview 自然是要有触摸的
m_pTouches = new CCArray();//触点 array
m_pDelegate = NULL;
m_bBounceable = true; //默认弹性开启
m_bClippingToBounds = true;
//m_pContainer->setContentSize(CCSizeZero);
m_eDirection = kCCScrollViewDirectionBoth; //默认both滚动模式
m_pContainer->setPosition(ccp(0.0f, 0.0f));
m_fTouchLength = 0.0f; this->addChild(m_pContainer);
m_fMinScale = m_fMaxScale = 1.0f; //默认放缩1.0
m_mapScriptHandler.clear(); //清理回调列表
return true;
}
return false;
}

我们补习一下滚动模式,CCScrollView中定义了一个枚举类型来表示滚动模式

typedef enum {
kCCScrollViewDirectionNone = -1, //不滚动
    kCCScrollViewDirectionHorizontal = 0, //横向滚动
    kCCScrollViewDirectionVertical, //竖向滚动
    kCCScrollViewDirectionBoth //双向滚动
} CCScrollViewDirection;

初始化就先讲到这,在看看属性设置上一些东西

void CCScrollView::setContainer(CCNode * pContainer)
{
    // Make sure that 'm_pContainer' has a non-NULL value since there are
    // lots of logic that use 'm_pContainer'.
    if (NULL == pContainer)
        return;
    this->removeAllChildrenWithCleanup(true); //这个就是多次使用setContainer却仅仅能显示一个sprite的原因
    this->m_pContainer = pContainer //假设setContentSize在setContainer之前,实际上设置的size给引擎自带的container,而不是目标container
    this->m_pContainer->ignoreAnchorPointForPosition(false);
    this->m_pContainer->setAnchorPoint(ccp(0.0f, 0.0f));
    this->addChild(this->m_pContainer);
    this->setViewSize(this->m_tViewSize);
}
void CCScrollView::setViewSize(CCSize size)
{
    m_tViewSize = size;
    CCLayer::setContentSize(size); //这里不是container的size。而是scrollview的size
}
void CCScrollView::setContentSize(const CCSize & size)
{
    if (this->getContainer() != NULL)
    {
        this->getContainer()->setContentSize(size); //这里才是设置container的size
this->updateInset(); //设置弹性状态下虚拟边界值。
    }
}
/**尽管setcontainer仅仅能用一次。可是addchild却能够满足我们的愿望。

 * make sure all children go to the container
 */
void CCScrollView::addChild(CCNode * child, int zOrder, int tag)
{
    child->ignoreAnchorPointForPosition(false);
    child->setAnchorPoint(ccp(0.0f, 0.0f));
    if (m_pContainer != child) {
        m_pContainer->addChild(child, zOrder, tag);
    } else {
        CCLayer::addChild(child, zOrder, tag);
    }
}

属性设置完了,显示是没问题了。只是scrollview究竟是怎样滚动的?

首先:

    virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
    virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);
    virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);

代码太多,这里就不全贴出来了。有兴趣能够自己去看源代码。让我们把主要代码摘出来

void CCScrollView::setContentOffset(CCPoint offset, bool animated/* = false*/) //此方法在ccTouchMoved中调用,功能是将container移动到指定位置
{
    if (animated)
    { //animate scrolling
        this->setContentOffsetInDuration(offset, BOUNCE_DURATION);//将container移动到指定位置,BOUNCE_DURATION=0.15f。移动时间
    } 
    else
    { //set the container position directly
        if (!m_bBounceable) //未开启边界弹性
        {
            const CCPoint minOffset = this->minContainerOffset();
            const CCPoint maxOffset = this->maxContainerOffset();
            
            offset.x = MAX(minOffset.x, MIN(maxOffset.x, offset.x));
            offset.y = MAX(minOffset.y, MIN(maxOffset.y, offset.y));
        }         m_pContainer->setPosition(offset);         if (m_pDelegate != NULL)
        {
            m_pDelegate->scrollViewDidScroll(this);   //回调虚函数,由子类override。lua中能够注冊该函数的回调
        }
    }
}
void CCScrollView::setContentOffsetInDuration(CCPoint offset, float dt) //好了,动画来了。
{
    CCFiniteTimeAction *scroll, *expire;
    scroll = CCMoveTo::create(dt, offset);
    expire = CCCallFuncN::create(this, callfuncN_selector(CCScrollView::stoppedAnimatedScroll));
    m_pContainer->runAction(CCSequence::create(scroll, expire, NULL));
    this->schedule(schedule_selector(CCScrollView::performedAnimatedScroll));
}
void CCScrollView::deaccelerateScrolling(float dt) //该方法是在ccTouchEnded中的主要内容 ,当滑动停止的时候,container还会移动一段距离。
    if (m_bDragging) //拖拽的话该方法不会多次循环调用
    {
        this->unschedule(schedule_selector(CCScrollView::deaccelerateScrolling));
        return;
    }
    float newX, newY;
    CCPoint maxInset, minInset;
    
    m_pContainer->setPosition(ccpAdd(m_pContainer->getPosition(), m_tScrollDistance));
    
    if (m_bBounceable) //弹性设置边界,该值>设置containerSize值。
    {
        maxInset = m_fMaxInset;
        minInset = m_fMinInset;
    }
    else
    {
        maxInset = this->maxContainerOffset();
        minInset = this->minContainerOffset();
    }
    
    //check to see if offset lies within the inset bounds
    newX     = MIN(m_pContainer->getPosition().x, maxInset.x);
    newX     = MAX(newX, minInset.x);
    newY     = MIN(m_pContainer->getPosition().y, maxInset.y);
    newY     = MAX(newY, minInset.y);
    
    newX = m_pContainer->getPosition().x;
    newY = m_pContainer->getPosition().y;
    
    m_tScrollDistance     = ccpSub(m_tScrollDistance, ccp(newX - m_pContainer->getPosition().x, newY - m_pContainer->getPosition().y));
    m_tScrollDistance     = ccpMult(m_tScrollDistance, SCROLL_DEACCEL_RATE);
    this->setContentOffset(ccp(newX,newY));
    //滑动灵敏度推断,边界推断,结束定时任务。在每次移动结束都会调用
    if ((fabsf(m_tScrollDistance.x) <= SCROLL_DEACCEL_DIST &&
         fabsf(m_tScrollDistance.y) <= SCROLL_DEACCEL_DIST) ||
        newY > maxInset.y || newY < minInset.y ||
        newX > maxInset.x || newX < minInset.x ||
        newX == maxInset.x || newX == minInset.x ||
        newY == maxInset.y || newY == minInset.y)
    {
        this->unschedule(schedule_selector(CCScrollView::deaccelerateScrolling));
        this->relocateContainer(true); //又一次设置locate。边界弹性
    }
}
void CCScrollView::relocateContainer(bool animated)  //没什么好说的,推断边界。如超出的话就移动回来
{
    CCPoint oldPoint, min, max;
    float newX, newY;
    
    min = this->minContainerOffset();
    max = this->maxContainerOffset();
    
    oldPoint = m_pContainer->getPosition();     newX     = oldPoint.x;
    newY     = oldPoint.y;
    if (m_eDirection == kCCScrollViewDirectionBoth || m_eDirection == kCCScrollViewDirectionHorizontal)
    {
        newX     = MAX(newX, min.x);
        newX     = MIN(newX, max.x);
    }     if (m_eDirection == kCCScrollViewDirectionBoth || m_eDirection == kCCScrollViewDirectionVertical)
    {
        newY     = MIN(newY, max.y);
        newY     = MAX(newY, min.y);
    }     if (newY != oldPoint.y || newX != oldPoint.x)
    {
       this->setContentOffset(ccp(newX, newY), animated);
    }
}

好了。到这里基本上大体就算一站了,还有些细节以及放缩就不在细说。

那么我们搞了这么久到底是要干什么?非常easy。我们希望滑动能够自己主动匹配图片的大小。

怎么做那?

方法一:改动源代码:

1、加入一个成员变量。记录初始滑动位置。

2、加入成员变量:图片匹配size

3、改动relocateContainer,max。min取近期符合要求的坐标。setContentOffset or setContentOffsetInDuration就可以

原理就是:

  1. touch開始的时候记录初始位置。在touch结束的时候, 获取结束时刻的时间和位置. 通过滑动距离等推断是否已经翻页,然后设置终于目标坐标。

    • 方法二:自己定义控件,继承CCScrollView。在ccTouchEnded末尾调用自己定义函数,实现以上功能。

    • 假设是lua开发,我推荐第一中方法,高速,改动相对少些。不用新增pkg文件。假设是c++的话,还是继承的好。
    • 试着改动下源代码,不仅有利于学习,并且有快感!!!

版权声明:本文博客原创文章,博客,未经同意,不得转载。

生命游戏(两),有一种东西叫CCScrollView的更多相关文章

  1. [LeetCode] Game of Life 生命游戏

    According to the Wikipedia's article: "The Game of Life, also known simply as Life, is a cellul ...

  2. javascript小游戏--生命游戏

    昨天参加Code Retreat的活动,"Code Retreat是一个一天的集中练习的活动,专注于软件开发和设计的基础". 要了解更多信息可前往 CodeRetreat官网 通过 ...

  3. 生命游戏&一维细胞自动机 笔记

    de 生命游戏是一种简单的聚合模型,展示了事物是如何聚合的,是自动机(CA)模型的一种.由剑桥大学约翰康威发明,其规则为: 1. 每个细胞拥有八个邻居,细胞状态只有存活(黑)和死亡(白)两种: 2.处 ...

  4. Python,OpenGL生命游戏

    初学Python和OpenGL,练手的第一个小程序life.py,这个小程序在日后会不断调整,增加类.优化判断及操作 执行效果: 按正规生命游戏的规则: 1.周围生命等于3时产生生命 2.周围生命等于 ...

  5. Python实现生命游戏

    1. 生命游戏是什么 生命游戏是英国数学家约翰·何顿·康威在1970年发明的细胞自动机.它包括一个二维矩形世界,这个世界中的每个方格居住着一个活着的或死了的细胞.一个细胞在下一个时刻生死取决于相邻八个 ...

  6. Leetcode 289.生命游戏

    生命游戏 根据百度百科,生命游戏,简称为生命,是英国数学家约翰·何顿·康威在1970年发明的细胞自动机. 给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞.每个细胞具有一个初始状 ...

  7. [LeetCode] 289. Game of Life 生命游戏

    According to the Wikipedia's article: "The Game of Life, also known simply as Life, is a cellul ...

  8. Python 速通爆肝、列表推导式、生成器、装饰器、生命游戏

    列表推导式.赋值.切片(替换.插入).字符串处理与判断.enumerate().格式化字符串.读写文件.global 关键字.字符串startswith().类与对象.生成器.装饰器.Self.*ar ...

  9. Conway生命游戏

    版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖.如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/9986679.html 作者:窗户 Q ...

随机推荐

  1. A Game of Thrones(9) - Tyrion

    Somewhere in the great stone maze(迷宫:迷惑) of Winterfell, a wolf howled. The sound hung over the castl ...

  2. Java LinkedBlockingQueue和ArrayBlockingQueue分析

    LinkedBlockingQueue是一个链表实现的堵塞队列,在链表一头增加元素,假设队列满.就会堵塞.还有一头取出元素.假设队列为空.就会堵塞. LinkedBlockingQueue内部使用Re ...

  3. nginx 301跳转到带www域名方法rewrite(转)

    首先一.得在你的域名管理里面定义 test.com和www.test.com指向你的主机ip地址,我们可以使用nslookup命令测试:直接输入 nslookup test.com和nslookup ...

  4. Date和String类型的相互转换

    String转Date: SimpleDateFormat bartDateFormat = new SimpleDateFormat("MM-dd-yyyy"); String ...

  5. HTML5 CSS3专题 纯CSS打造相冊效果

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/30993277 今天偶然发现电脑里面还有这种一个样例.感觉效果还不错,不记得啥时候 ...

  6. Swift 的类、结构体、枚举等的构造过程Initialization(下)

    类的继承和构造过程 类里面的全部存储型属性--包含全部继承自父类的属性--都必须在构造过程中设置初始值. Swift 提供了两种类型的类构造器来确保全部类实例中存储型属性都能获得初始值,它们各自是指定 ...

  7. linux--档案权限与目录配置

    下面是最近学习档案权限与目录配置的一些知识点总结***博客园-邦邦酱好*** Linux最优秀的地方之一,就在于他的多人多任务环境.而为了让各个使用者具有较保密的档案数据,因此档案的权限管理就变的很重 ...

  8. http协议之cookie标准RFC6265介绍

      [Docs] [txt|pdf] [draft-ietf-httpst...] [Diff1] [Diff2] [Errata] PROPOSED STANDARD Errata Exist In ...

  9. Java数据结构系列之——栈(2):栈的链式存储结构及其操作

    package Stack; import LinkList.SinglyLinkList; public class LinkListStack { private SinglyLinkList&l ...

  10. Javascript语言精粹之Array常用方法分析

    Javascript语言精粹之Array常用方法分析 1.Array常用方法分析 1.1 Array.prototype.sort() Javascript的默认比较函数假定被排序元素都是字符串,所以 ...