cocos2d 3.0滑动菜单网格

时间:2014-06-25 13:23:53

标签: ios iphone cocos2d-iphone

我正在将所有游戏迁移到cocos2d 3.0。我稍微修改了SlidingMenuGrid.m。

SlidingMenuGrid.h:

//
//  SlidingMenuGrid
//
//  Created by Brandon Reynolds on 1/9/11.

#import "cocos2d.h"

@interface SlidingMenuGrid : CCLayer
{
    tCCMenuState state; // State of our menu grid. (Eg. waiting, tracking touch, cancelled, etc)
    CCMenuItem *selectedItem; // Menu item that was selected/active.

    CGPoint padding; // Padding in between menu items.
    CGPoint menuOrigin; // Origin position of the entire menu grid.
    CGPoint touchOrigin; // Where the touch action began.
    CGPoint touchStop; // Where the touch action stopped.

    int iPageCount; // Number of pages in this grid.
    int iCurrentPage; // Current page of menu items being viewed.

    bool bMoving; // Is the grid currently moving?
    bool bSwipeOnlyOnMenu; // Causes swiping functionality to only work when siping on top of the menu items instead of entire screen.
    bool bVerticalPaging; // Disabled by default. Allows for pages to be scrolled vertically instead of horizontal.

    float fMoveDelta; // Distance from origin of touch and current frame.
    float fMoveDeadZone; // Amount they need to slide the grid in order to move to a new page.
    float fAnimSpeed; // 0.0-1.0 value determining how slow/fast to animate the paging.



    CGPoint pageIndicatorPosition;

}


//use this 5:
-(int) getTotalPage;
-(int) getCurrentPage;
-(void) moveToPage: (int) page animated: (BOOL) animated;
+(id) packWithArray: (NSMutableArray*) items posY: (int) posY indicatorPosY: (int) indiPosY;
+(id) levelWithArray: (NSMutableArray*) items cols: (int) cols rows: (int) rows leftEdge: (int) leftEdge upperEdge: (int) upperEdge lowerEdge: (int) lowerEdge indicatorPosY: (int) indiPosY;




+(id) menuWithArray:(NSMutableArray*)items cols:(int)cols rows:(int)rows position:(CGPoint)pos padding:(CGPoint)pad pageIndicatorPosition:(CGPoint)pip;

-(id) initWithArray:(NSMutableArray*)items cols:(int)cols rows:(int)rows position:(CGPoint)pos padding:(CGPoint)pad verticalPaging:(bool)vertical pageIndicatorPosition:(CGPoint)pip;

-(void) buildGrid:(int)cols rows:(int)rows;
-(void) buildGridVertical:(int)cols rows:(int)rows;
-(CCMenuItem*) GetItemWithinTouch:(UITouch*)touch;
- (CGPoint) GetPositionOfCurrentPageWithOffset:(float)offset;
- (CGPoint) GetPositionOfCurrentPage;

- (bool) IsSwipingOnMenuOnlyEnabled;
- (void) SetSwipingOnMenuOnly:(bool)bValue;

- (float) GetSwipeDeadZone;
- (void) SetSwipeDeadZone:(float)fValue;

- (bool) IsVerticallyPaged;
- (void) SetVerticalPaging:(bool)bValue;

@property (nonatomic, readwrite) CGPoint padding;
@property (nonatomic, readwrite) CGPoint menuOrigin;
@property (nonatomic, readwrite) CGPoint touchOrigin;
@property (nonatomic, readwrite) CGPoint touchStop;
@property (nonatomic, readwrite) int iPageCount;
@property (nonatomic, readwrite) int iCurrentPage;
@property (nonatomic, readwrite) bool bMoving;
@property (nonatomic, readwrite) bool bSwipeOnlyOnMenu;
@property (nonatomic, readwrite) bool bVerticalPaging;
@property (nonatomic, readwrite) float fMoveDelta;
@property (nonatomic, readwrite) float fMoveDeadZone;
@property (nonatomic, readwrite) float fAnimSpeed;

@end

SlidingMenuGrid.m

#import "SlidingMenuGrid.h"

#import "Constants.h"

@implementation SlidingMenuGrid

@synthesize padding;
@synthesize menuOrigin;
@synthesize touchOrigin;
@synthesize touchStop;
@synthesize bMoving;
@synthesize bSwipeOnlyOnMenu;
@synthesize fMoveDelta;
@synthesize fMoveDeadZone;
@synthesize iPageCount;
@synthesize iCurrentPage;
@synthesize bVerticalPaging;
@synthesize fAnimSpeed;


-(int) getTotalPage {
    return iPageCount;
}
-(int) getCurrentPage {
    return iCurrentPage;
}

+(id) packWithArray: (NSMutableArray*) items posY: (int) posY indicatorPosY: (int) indiPosY {


    CGSize size = [CCDirector sharedDirector].winSize;
    BOOL vertical = NO;
    //pos, padding, pageindicatorpos
    CGPoint pos = ccp(size.width / 2, posY);
    CGPoint posIndicator = ccp(size.width / 2, indiPosY);
    //padding no matter

    return [SlidingMenuGrid menuWithArray:items cols:1 rows:1 position:pos padding:ccp(0, 0) verticalPaging:vertical pageIndicatorPosition:posIndicator];

}
+(id) levelWithArray: (NSMutableArray*) items cols: (int) cols rows: (int) rows leftEdge: (int) leftEdge upperEdge: (int) upperEdge lowerEdge: (int) lowerEdge indicatorPosY: (int) indiPosY {

    CGSize screen = [CCDirector sharedDirector].winSize;
    BOOL vertical = NO;

    CGSize itemSize = [[items objectAtIndex:0] boundingBox].size;
    //pos, padding, pageindipos
    CGPoint posIndicator = ccp(screen.width / 2, indiPosY);

    int posx = leftEdge + itemSize.width / 2;
    int posy = screen.height - (upperEdge + itemSize.height / 2);
    int padx = (screen.width - itemSize.width - 2 * leftEdge) / (cols - 1);
    int pady = (screen.height - upperEdge - lowerEdge - itemSize.height) / (rows - 1);

    return [SlidingMenuGrid menuWithArray:items cols:cols rows:rows position:ccp(posx, posy) padding:ccp(padx, pady) verticalPaging:vertical pageIndicatorPosition:posIndicator];
}



+(id) menuWithArray:(NSMutableArray*)items cols:(int)cols rows:(int)rows position:(CGPoint)pos padding:(CGPoint)pad pageIndicatorPosition:(CGPoint)pip
{
    return [[[self alloc] initWithArray:items cols:cols rows:rows position:pos padding:pad verticalPaging:false pageIndicatorPosition:pip] autorelease];
}

+(id) menuWithArray:(NSMutableArray*)items cols:(int)cols rows:(int)rows position:(CGPoint)pos padding:(CGPoint)pad verticalPaging:(bool)vertical pageIndicatorPosition: (CGPoint) pip
{
    return [[[self alloc] initWithArray:items cols:cols rows:rows position:pos padding:pad verticalPaging:vertical pageIndicatorPosition:pip] autorelease];
}

-(id) initWithArray:(NSMutableArray*)items cols:(int)cols rows:(int)rows position:(CGPoint)pos padding:(CGPoint)pad verticalPaging:(bool)vertical pageIndicatorPosition:(CGPoint)pip
{
    if ((self = [super init]))
    {
        self.isTouchEnabled = YES;

        int z = 1;
        for (id item in items)
        {
            [self addChild:item z:z tag:z];
            ++z;
        }

        padding = pad;
        iCurrentPage = 0;
        bMoving = false;
        bSwipeOnlyOnMenu = false;
        menuOrigin = pos;
        fMoveDeadZone = 10;
        bVerticalPaging = vertical;
        fAnimSpeed = 0.6f;
        (bVerticalPaging) ? [self buildGridVertical:cols rows:rows] : [self buildGrid:cols rows:rows];
        self.position = menuOrigin;


        pageIndicatorPosition = pip;
    }

    return self;
}

-(void) dealloc
{
    [super dealloc];
}

-(void) buildGrid:(int)cols rows:(int)rows
{
    CGSize winSize = [[CCDirector sharedDirector] winSize];

    int col = 0, row = 0;
    for (CCMenuItem* item in self.children)
    {
        // Calculate the position of our menu item. 
        item.position = CGPointMake(self.position.x + col * padding.x + (iPageCount * winSize.width), self.position.y - row * padding.y);

        // Increment our positions for the next item(s).
        ++col;
        if (col == cols)
        {
            col = 0;
            ++row;

            if( row == rows )
            {
                iPageCount++;
                col = 0;
                row = 0;
            }
        }
    }

    if([self children].count > rows * cols * iPageCount) iPageCount++;

}



-(void) buildGridVertical:(int)cols rows:(int)rows
{
    CGSize winSize = [[CCDirector sharedDirector] winSize];

    int col = 0, row = 0;
    for (CCMenuItem* item in self.children)
    {
        // Calculate the position of our menu item. 
        item.position = CGPointMake(self.position.x + col * padding.x , self.position.y - row * padding.y + (iPageCount * winSize.height));

        // Increment our positions for the next item(s).
        ++col;
        if (col == cols)
        {
            col = 0;
            ++row;

            if( row == rows )
            {
                iPageCount++;
                col = 0;
                row = 0;
            }
        }
    }


    if([self children].count > rows * cols * iPageCount) iPageCount++;



}

-(void) addChild:(CCMenuItem*)child z:(int)z tag:(int)aTag
{
    return [super addChild:child z:z tag:aTag];
}

-(CCMenuItem*) GetItemWithinTouch:(UITouch*)touch
{
    // Get the location of touch.
    CGPoint touchLocation = [[CCDirector sharedDirector] convertToGL: [touch locationInView: [touch view]]];

    // Parse our menu items and see if our touch exists within one.
    for (CCMenuItem* item in [self children])
    {
        //only deal with the item
        if ([item isKindOfClass:[CCMenuItem class]]) {
            CGPoint local = [item convertToNodeSpace:touchLocation];

            CGRect r = [item rect];
            r.origin = CGPointZero;

            // If the touch was within this item. Return the item.
            if (CGRectContainsPoint(r, local))
            {
                return item;
            }
        }
    }

    // Didn't touch an item.
    return nil;
}

-(void) registerWithTouchDispatcher
{
    [[CCDirector sharedDirector].touchDispatcher addTargetedDelegate:self priority:kCCMenuHandlerPriority swallowsTouches:NO];
}

-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
    // Convert and store the location the touch began at.
    touchOrigin = [[CCDirector sharedDirector] convertToGL:[touch locationInView:[touch view]]];

    // If we weren't in "waiting" state bail out.
    if (state != kCCMenuStateWaiting)
    {
        return NO;
    }

    // Activate the menu item if we are touching one.
    selectedItem = [self GetItemWithinTouch:touch];
    [selectedItem selected];

    // Only track touch if we are either in our menu system or dont care if they are outside of the menu grid.
    if (!bSwipeOnlyOnMenu || (bSwipeOnlyOnMenu && selectedItem) )
    {
        state = kCCMenuStateTrackingTouch;
        return YES;
    }

    return NO;
}

// Touch has ended. Process sliding of menu or press of menu item.
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{   
    // User has been sliding the menu.
    if( bMoving )
    {
        bMoving = false;

        // Do we have multiple pages?
        if( iPageCount > 1 && (fMoveDeadZone < abs(fMoveDelta)))
        {
            // Are we going forward or backward?
            bool bForward = (fMoveDelta < 0) ? true : false;

            // Do we have a page available?
            if(bForward && (iPageCount>iCurrentPage+1))
            {
                // Increment currently active page.
                iCurrentPage++;
            }
            else if(!bForward && (iCurrentPage > 0))
            {
                // Decrement currently active page.
                iCurrentPage--;
            }
        }

        // Start sliding towards the current page.
        [self moveToCurrentPage];           

    }
    // User wasn't sliding menu and simply tapped the screen. Activate the menu item.
    else 
    {
        [selectedItem unselected];
        [selectedItem activate];
    }

    // Back to waiting state.
    state = kCCMenuStateWaiting;
}

-(void) moveToPage: (int) page animated:(BOOL)animated {
    float interval = 0;
    if (animated) {
        interval = 0.3f * abs(iCurrentPage - page);
    }

    iCurrentPage = page;

    // Perform the action
    CGPoint position = [self GetPositionOfCurrentPage];
    CCMoveTo* action = [CCMoveTo actionWithDuration:interval position:position];
    [self runAction:action];

}

// Run the action necessary to slide the menu grid to the current page.
- (void) moveToCurrentPage
{
    CGSize winSize = [[CCDirector sharedDirector] winSize];

    // Perform the action
    CGPoint position = [self GetPositionOfCurrentPage];
    CCMoveTo* action = [CCMoveTo actionWithDuration:fAnimSpeed * 0.3f position:position];
    [self runAction:action];

}

-(void) ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event
{
    [selectedItem unselected];

    state = kCCMenuStateWaiting;
}

-(void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{


    // Calculate the current touch point during the move.
    touchStop = [[CCDirector sharedDirector] convertToGL:[touch locationInView:[touch view]]];

    // Distance between the origin of the touch and current touch point.
    fMoveDelta = (bVerticalPaging) ? (touchStop.y - touchOrigin.y) : (touchStop.x - touchOrigin.x);

    // Set our position.
    [self setPosition:[self GetPositionOfCurrentPageWithOffset:fMoveDelta]];
    bMoving = true;

    if (selectedItem) {
        [selectedItem unselected];
        selectedItem = nil;
    }

}

- (CGPoint) GetPositionOfCurrentPage
{
    CGSize winSize = [[CCDirector sharedDirector] winSize];

    return (bVerticalPaging) ?
    CGPointMake(menuOrigin.x,menuOrigin.y-(iCurrentPage*winSize.height))
    : CGPointMake((menuOrigin.x-(iCurrentPage*winSize.width)),menuOrigin.y);
}

- (CGPoint) GetPositionOfCurrentPageWithOffset:(float)offset
{
    CGSize winSize = [[CCDirector sharedDirector] winSize];

    return (bVerticalPaging) ?
    CGPointMake(menuOrigin.x,menuOrigin.y-(iCurrentPage*winSize.height)+offset)
    : CGPointMake((menuOrigin.x-(iCurrentPage*winSize.width)+offset),menuOrigin.y);
}



// Returns whether or not we should only allow swiping on the actual grid.
- (bool) IsSwipingOnMenuOnlyEnabled
{
    return bSwipeOnlyOnMenu;
}

// Sets the ability to swipe only on the menu or utilize entire screen for swiping.
- (void) SetSwipingOnMenuOnly:(bool)bValue
{
    bSwipeOnlyOnMenu = bValue;
}

// Returns the swiping dead zone. 
- (float) GetSwipeDeadZone
{
    return fMoveDeadZone;
}

- (void) SetSwipeDeadZone:(float)fValue
{
    fMoveDeadZone = fValue;
}

// Returns wheather or not vertical paging is enabled.
- (bool) IsVerticallyPaged
{
    return bVerticalPaging;
}

// Sets the vertical paging flag.
- (void) SetVerticalPaging:(bool)bValue
{
    bVerticalPaging = bValue;
    [self buildGridVertical];
}










- (void) visit
{
    [super visit];//< Will draw after glPopScene.

    BOOL showPagesIndicator = YES;


    ccColor4B pagesIndicatorNormalColor_ = ccc4(180, 180, 180, 255);
    ccColor4B pagesIndicatorSelectedColor_ = ccc4(255, 255, 255, 255);
    if (showPagesIndicator)
    {
        int totalScreens = iPageCount;

        // Prepare Points Array
        CGFloat n = (CGFloat)totalScreens; //< Total points count in CGFloat.
        CGFloat pY = pageIndicatorPosition.y; //< Points y-coord in parent coord sys.
        CGFloat d = ph_pad(16.0f, 16.0f * 2); //< Distance between points.
        CGPoint points[totalScreens];
        for (int i=0; i < totalScreens; ++i)
        {
            CGFloat pX = pageIndicatorPosition.x + d * ( (CGFloat)i - 0.5f*(n-1.0f) );
            points[i] = ccp (pX, pY);
        }

        // Set GL Values
#if COCOS2D_VERSION >= 0x00020000
//        ccGLEnable(CC_GL_BLEND);
        ccPointSize( ph_pad(5.0 * CC_CONTENT_SCALE_FACTOR(), 5.0 * CC_CONTENT_SCALE_FACTOR() * 2) );
#define DRAW_4B_FUNC ccDrawColor4B

#else
        glEnable(GL_POINT_SMOOTH);
        GLboolean blendWasEnabled = glIsEnabled( GL_BLEND );
        glEnable(GL_BLEND);

        // save the old blending functions
        int blend_src = 0;
        int blend_dst = 0;
        glGetIntegerv( GL_BLEND_SRC, &blend_src );
        glGetIntegerv( GL_BLEND_DST, &blend_dst );
        glPointSize( ph_pad(5.0 * CC_CONTENT_SCALE_FACTOR(), 5.0 * CC_CONTENT_SCALE_FACTOR() * 2) );

#define DRAW_4B_FUNC glColor4ub

#endif
        ccGLBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

        // Draw Gray Points
        DRAW_4B_FUNC(pagesIndicatorNormalColor_.r,
                     pagesIndicatorNormalColor_.g,
                     pagesIndicatorNormalColor_.b,
                     pagesIndicatorNormalColor_.a);

        ccDrawPoints( points, totalScreens );

        // Draw White Point for Selected Page
        DRAW_4B_FUNC(pagesIndicatorSelectedColor_.r,
                     pagesIndicatorSelectedColor_.g,
                     pagesIndicatorSelectedColor_.b,
                     pagesIndicatorSelectedColor_.a);
        ccDrawPoint(points[iCurrentPage]);

        // Restore GL Values
#if COCOS2D_VERSION >= 0x00020000
        ccPointSize(1.0f);
#else
        glPointSize(1.0f);
        glDisable(GL_POINT_SMOOTH);
        if (! blendWasEnabled)
            glDisable(GL_BLEND);

        // always restore the blending functions too
        ccGLBlendFunc( blend_src, blend_dst);
//        glBlendFunc( blend_src, blend_dst );
#endif
    }
}




@end

源代码来自Brandon Reynolds,我对其进行了一些修改以更好地适应我的游戏。我使用这5种方法轻松构建包(单行,多列)和级别(多行,多列)的菜单

-(int) getTotalPage;
-(int) getCurrentPage;
-(void) moveToPage: (int) page animated: (BOOL) animated;
+(id) packWithArray: (NSMutableArray*) items posY: (int) posY indicatorPosY: (int) indiPosY;
+(id) levelWithArray: (NSMutableArray*) items cols: (int) cols rows: (int) rows leftEdge: (int) leftEdge upperEdge: (int) upperEdge lowerEdge: (int) lowerEdge indicatorPosY: (int) indiPosY;

但是对于cocos2d 3.0(例如ccGLBlendFunc等),open gl代码不再起作用了。如何为cocos2d 3.x更新此类?或类似菜单网格的任何新实现?

1 个答案:

答案 0 :(得分:0)

现在最好使用CCScrollView。

它支持分页,您只需将其预创建为内容节点,即可轻松创建关卡网格。