(转自收音机的百度空间:http://hi.baidu.com/amigoradio/item/c7e3928c6d9bb2ccb071547b)
之前项目中使用CCScrollLayer的方法实现的了滚动效果。具体可以参考 这个帖子
当时CCScrollLayer只支持横向的滚动,但自己修改一下源码就可以支持纵向的滚动了,比较简单
这次项目中美术画的滚动效果不是全屏滚动,而是屏幕中间有一块300x300的区域,所有的道具需要在这里面横向滚动。
这个区域外面是一块半透明效果的图,所以没法使用CCScrollLayer来做,因为这个类不能裁剪区域,把多余的区域裁剪掉。
这种效果如果用ios的原生UIScrollView来做,是非常简单的,设置scrollView的frame可视的区域,然后设置contentSize内容区域
但看来效果不好,因为cocos2d里面引入UIScrollView很麻烦,而且UIScrollView里面要放入很多CCSpirte组装好的效果,
这样做非常麻烦,做起来代码也长也繁琐。所以找了一下资料就放弃这种方案了。
还是把精力集中在改造CCScrollLayer上,在cocos2d的社区找到一个CCScrollView的帖子,实现了UIScrollView的效果。
但我能力有限没能看明白怎样使用,也没明白他的原理。还找到一个帖子说CCScrollView限制很多,不建议使用。
但从CCScrollView我发现了opengl的glClipPlane,opengl的区域裁剪函数。
我的想法:做一个scrollLayer,scrollLayer中设置类似frame的显示区域,将frame之外的区域都裁剪掉,然后将要scroll的道具
加入到另一个layer中,再将这个装满道具的layer放入到scrollLayer中,scrollLayer中通过触摸事件来控制里面装道具的layer的
左右移动。这样可以达到UIScrollView的方法。具体看下面代码,从ccScrollLayer修改来的
1)首先加入下面方法,实现layer的裁剪,里面的几个数组我们之后在说
-(void) beforeDraw {
GLfloat planeTop[] = {0.0f, -1.0f, 0.0f, area.origin.y+area.size.height};
GLfloat planeBottom[] = {0.0f, 1.0f, 0.0f, -area.origin.y};
GLfloat planeLeft[] = {1.0f, 0.0f, 0.0f, -area.origin.x};
GLfloat planeRight[] = {-1.0f, 0.0f, 0.0f, area.origin.x+area.size.width};
glClipPlanef(GL_CLIP_PLANE0, planeTop);
glClipPlanef(GL_CLIP_PLANE1, planeBottom);
glClipPlanef(GL_CLIP_PLANE2, planeLeft);
glClipPlanef(GL_CLIP_PLANE3, planeRight);
glEnable(GL_CLIP_PLANE0);
glEnable(GL_CLIP_PLANE1);
glEnable(GL_CLIP_PLANE2);
glEnable(GL_CLIP_PLANE3);
}
-(void) afterDraw {
glDisable(GL_CLIP_PLANE0);
glDisable(GL_CLIP_PLANE1);
glDisable(GL_CLIP_PLANE2);
glDisable(GL_CLIP_PLANE3);
}
2)修改visit方法,原ccScrollLayer中的visit内容包含分页的效果,但我不需要所以去掉了,这里主要是加入了
beforeDraw和afterDraw的调用
- (void) visit{
[self beforeDraw];
[super visit];
[self afterDraw];
}
3)修改initWithLayer和nodeWithLayer的方法,主要是修改了方法名和参数传入一个layer,因为layer中有很多东西,不方便传NSarray
-(id) initWithViews:(CCNode *) view widthOffset: (int) widthOffset total:(int) total frame:(CGRect) rect{
if ( (self = [super init]) )
{
self.isTouchEnabled = YES;
scrollWidth_ = widthOffset;//一个元素的宽度,也就是每次滚动的大小,为了达到好的效果自己慢慢调吧
totalScreens_ = total; //在layer中计算好长度,也就是要滚动多少次达到最后一个元素
currentScreen_ = 1; //当前为第一个元素,也就是左边第一个
area = rect; //定义了显示区域的左下角和高宽
self.minimumTouchLengthToSlide = 30.0f;
self.minimumTouchLengthToChangePage = 100.0f;
self.showPagesIndicator = YES;
view.tag = SCROLLVIEWTAG;
[selfaddChild:view];
}
return self;
}
4)修改moveToPage方法,把self改为上面添加的layer
CCNode *node = [selfgetChildByTag:SCROLLVIEWTAG];
id changePage = [CCMoveToactionWithDuration:0.3 position:ccp(-((page-1)*scrollWidth_),0)];
[node runAction:changePage];
5)修改ccTouchMoved方法,把self改为上面添加的layer
if (state_ == kCCScrollLayerStateSliding){
CCNode *node = [selfgetChildByTag:SCROLLVIEWTAG];
node.position = ccp((-(currentScreen_-1)*scrollWidth_)+(touchPoint.x-startSwipe_),0);
}
ccscrollLayer中的方法不变,下面的调用的方法
CCLayer *layer = [DeskItemLayernode]; //创建一个放置好很多桌椅的layer
CGRect rect = CGRectMake(60, 0, 360, 320); //设置可以显示的区域
CCScrollView *scroll = [CCScrollViewnodeWithViews:layer widthOffset:90 total:layer.layerLong frame:rect];
scroll.minimumTouchLengthToSlide = 20.0;
scroll.minimumTouchLengthToChangePage = 50.0;
[selfaddChild:scroll]; //增加这个scrollLayer
关于opengl的glClipPlanef方法,其实我也不明白这个函数,百度和google之后还是不明白。
还是建议大家去看opengl的书,做做例子来搞懂。下面说下我自己的理解
GL_CLIP_PLANE0 从0-5 是6个面,可以代表上下左右前后,还可以自己添加自己定义的面
GLfloat plane[] = {a,b,c,d}; 这个参数方程,我是一点都没看明白。。。。。。。
但我拿实际的代码调试出来了,abc是一个系数,分别代表xyz的方向,值有正负之分。d为具体的数值
比如
GLfloat plane[] = {1.0,0.0,0.0,-100.0}; 就是裁剪掉屏幕左边100个像素宽度的一个矩形区域
GLfloat plane[] = {1.0,1.0,0.0,-100.0};就是裁剪掉屏幕左边的100个像素的一个三角形,左下角
GLfloat plane[] = {2.0,1.0,0.0,-100.0};就是裁剪掉屏幕左边50个像素宽度的一个矩形区域
glClipPlanef的信息可以参考这里 http://blog.csdn.net/sxzly/article/details/2295642
(转自收音机的百度空间:http://hi.baidu.com/amigoradio/item/c7e3928c6d9bb2ccb071547b)