4

问候 Stackoverflow,

我目前正在尝试在我正在开发的 cocos2d-x 游戏中实现滚动菜单。问题是这些项目正在向我想要的相反方向滚动。例如,如果我将手指从屏幕底部拖动​​到顶部,精灵将弹回其原始位置。

如果我将手指从顶部拖到底部,精灵将跟随我的手指(直到它到达边界)。

这是我的代码:

    /////////////////////
    //SCROLL VIEW + LAYER
    CCLayer *layer = CCLayer::create();
    layer->setContentSize( CCSizeMake( winSize.width, winSize.height ) );
    layer->addChild( menu );

    scrollView = CCScrollView::create();
    scrollView->retain();
    scrollView->setContentSize( CCSizeMake ( layer->getContentSize().width,  layer->getContentSize().height ) );
    scrollView->setDirection( CCScrollViewDirectionVertical );
    scrollView->setPosition( ccp( 0,0 ) );
    scrollView->setContainer( layer );

    this->addChild(scrollView);

    scrollView->setContentOffset( CCPointZero );

非常感谢任何建议或帮助。如果您有任何其他方法可以使用另一种方法创建滚动菜单,我很想听听。

谢谢!

最好的问候安德烈亚斯

4

4 回答 4

8

参考:cocos2dx/extensions/GUI/CCScrollView/CCScrollView.cpp

具体CCScrollView::minContainerOffsetCCScrollView::maxContainerOffset

CCScrollViewOpenGL 坐标(相对于窗口坐标)中工作 - 值相对于(左、下),正 Y 轴向上。另外,请记住滚动视图的定位和容器被锚定(CCNode::setAnchorPoint)到(左,下)。

当您向下滚动(向上移动/拉动内容以查看剪切/剪辑下方的内容)时,您会看到屏幕底部边缘下方的内容,但在您松开触摸/拖动时它会弹回,因为maxContainerOffset返回(0, 0)并且您'刚刚尝试移动到积极的内容偏移量。

CCScrollView 与容器的坐标

该图显示了滚动视图容器在创建/初始化时的状态。这是设置和定位子元素容器时要“考虑”的状态或坐标。灰色矩形(左,下)显示滚动容器的有效区域。想象容器的锚点在其中移动。

要查看容器开始滚动到顶部(在窗口坐标中工作时您所期望的),请相应地设置内容偏移量(在设置后立即)。这将给出预期的结果/行为。

scrollView->setContentOffset(ccp(0.f, (scrollViewHeight-scrollContainerHeight)), false);

下面编辑的代码中有一个更完整的示例。

  1. 允许在窗口坐标中滚动(正 Y 轴向下)的“修复”可能是调整扩展,这将需要您重建 cocos2dx 库并影响所有项目(甚至您可以尝试的其他示例代码)。

    /*
    // (StackOverflow Post Edit: This hack is not required.)
    CCPoint CCScrollView::maxContainerOffset()
    {
        // Default CCPointZero;
        return ccp(0.0f, m_pContainer->getContentSize().height*m_pContainer->getScaleY() - m_tViewSize.height);
    }
    CCPoint CCScrollView::minContainerOffset()
    {
        // Default Y = m_tViewSize.height - m_pContainer->getContentSize().height*m_pContainer->getScaleY();
        return ccp(m_tViewSize.width - m_pContainer->getContentSize().width*m_pContainer->getScaleX(), 
               0.f);
    }
    */
    
  2. 一个不那么侵入性的 技巧是将ScrollView实例缩放到-1,并将容器节点的节点也缩放到-1。您还必须考虑逆比例重新定位子节点。两个级别的缩放结果是内容(子节点)被直接查看(而不是翻转)。将ScrollView缩放到 -1 的结果是滚动发生在您预期的方向上。请注意,尽管此“修复”也会在 X 轴上翻转滚动,因此适用于您希望垂直滚动 ( ) 的情况。CCScrollViewDirectionVertical

    CCSize winSize = CCDirector::sharedDirector()->getWinSize();
    CCLayer* scrollContainer = CCLayer::create(); // Container for the scroll view
    scrollContainer->setAnchorPoint(CCPointZero); // CCScrollView does this too when it's set as the container.
    
    // Content for the container
    CCSprite *tallContentA = CCSprite::create("TallContentA.png");
    tallContentA ->setPosition(ccp(winSize.width*0.5f, winSize.height*0.9f));
    CCSprite *tallContentB = CCSprite::create("TallContentB.png");
    tallContentB ->setPosition(ccp(winSize.width*0.5f, winSize.height*0.1f));
    scrollContainer->addChild(tallContentA, 2);
    scrollContainer->addChild(tallContentB, 2);
    
    float scrollContainerHeight = tallContentA->getContentSize().height + tallContentB->getContentSize().height;
    scrollContainer->setPosition(CCPointZero);
    scrollContainer->setContentSize(CCSizeMake(winSize.width, scrollContainerHeight*1.05f));
    
    // Set up scroll view
    CCScrollView* scrollView = CCScrollView::create(winSize, scrollContainer);
    scrollView->setPosition(CCPointZero);
    scrollView->setDirection(CCScrollViewDirectionVertical);
    // ScrollView initializes at the (left, bottom). The container also gets positioned relative to that and goes Y-up.
    // Pre-set it to the value CCScrollView::minContainerOffset will return when it's scrolled to the top
    // (note, this is a negative number, indicating the touch moving downwards, i.e. it's pre-scrolled such that the top of the content is visible when we begin)
    scrollView->setContentOffset(ccp(0.f, (winSize.height-scrollContainerHeight*1.05f)), false);
    /*
    // (StackOverflow Post Edit: This hack is not required.)
    // Hack: CCScrollView's maxContainerOffset is (0, 0) and minContainerOffset is (difference between view and content size which is negative)
    // It's designed to be (left, bottom) based and positive scrolling means showing stuff above the top of the screen.
    // Since we're using it in terms of Window coordinates ((left, top) based), we scale the scroll view
    // and it's container's children by -1 and position the children differently
    // (eg. Y position winSize.height*0.1f was changed to winSize.height*0.9f)
    // We can't just set the scroll view's Y scale to -1 because CCNode::getScale asserts that X and Y scale must be the same.
    scrollView->setScale(-1.f);
    tallContentA->setScale(-1.f);
    tallContentB->setScale(-1.f);
    */
    
    addChild(scrollView);
    

还要注意上面提到的两个修复是互斥的不要同时应用。

现在也在 cocos2d-x 论坛上回答。

于 2013-04-24T14:04:17.403 回答
3

@Zennichimaro,

@PAT 的回答是正确的,本质上是一个简化版本

考虑到这一点,请注意 3 件事很重要:

  1. CCScrollView::setViewSize()- 您显然错过了这个,它必须是您的可视空间的宽度和高度(蓝色框,如果您想要全屏,我认为它是您的整个 windowSize)

  2. CCScrollView::setContentSize()- 这个和setContentOffset不一样,看来你把这个误认为是setContentOffset了,反正这个应该设置成整个容器的大小(红框,你的可能是ccp(windowSize.width,2496.0f)

  3. CCScrollView::setContentOffset()- 如果您想定位它以便最初可见最顶部,则最小值和最大值由答案中的灰色小矩形框指定(灰色框,您的可能是ccp(0.0f, windowSize.height-2496.0f)

于 2013-12-10T03:15:48.173 回答
3

更简短的答案是:

scrollView->setContentOffset(scrollView->minContainerOffset());

由于锚点在左下角,所以初始偏移量不是零,而是一个负数。

于 2014-03-15T17:13:25.703 回答
0

如果有人想在 mmo 游戏聊天表中制作滚动视图(将消息添加到底部并自动滚动到底部),那么也许有人会发现这很有用:

我的 ChatTableView.h 的部分代码

//tableView dataSource is vector of strings
class ChatTableView :public Layer, public TableViewDataSource, public TableViewDelegate
{
public:
    vector<string> n_msglist;
    TableView* pTableView;
    void addMsg(string text);
private:

};

//part of the code of my ChatTableView.cpp
void Init(){
    pTableView = TableView::create(this, VisibleRect::getVisibleRect().size, NULL);
    pTableView->setDirection(ScrollView::Direction::VERTICAL);
    pTableView->setVerticalFillOrder(TableView::VerticalFillOrder::TOP_DOWN);
    pTableView->setDelegate(this);
    pTableView->setBounceable(false);

} 
void ChatTableView::addMsg(string text){

    n_msglist.push_back(text); //adds string to vector
    pTableView->reloadData(); //reloads data with newly updated vector and scroll back to top
    pTableView->setContentOffset(pTableView->maxContainerOffset()); //scrolls to bottom
}
于 2014-08-03T17:39:29.123 回答