水果忍者刀划痕效果,github地址:https://github.com/hiepnd/CCBlade
该例子主要用一下两个文件:
CCBlade.m//划痕效果的顶点存储,opengl的渲染 TouchTrailLayer.m //继承CCLayer,接收touch的begin、end点,传递给CCBlade,进行动画显示
CCBlade.h
#import <Foundation/Foundation.h> #import "cocos2d.h" #define USE_STL_LIST 0 inline float fangle(CGPoint vect); inline float lagrange1(CGPoint p1, CGPoint p2, float x); inline void CGPointSet(CGPoint *v, float x, float y); inline void f1(CGPoint p1, CGPoint p2, float d, CGPoint *o1, CGPoint *o2); @interface CCBlade : CCNode { //轨迹所有点array NSMutableArray *path; unsigned int pointLimit; int count; //opengl中存储vertices & coordinate数组 CGPoint *vertices; CGPoint *coordinates; BOOL reset; CCTexture2D *_texture; float width; BOOL _finish; BOOL _willPop; } @property (readonly)unsigned int pointLimit; @property(retain) CCTexture2D *texture; @property(nonatomic) float width; @property (nonatomic, assign) BOOL autoDim; + (id) bladeWithMaximumPoint:(int) limit; - (id) initWithMaximumPoint:(int) limit; - (void) push:(CGPoint) v; - (void) pop:(int) n; - (void) clear; - (void) reset; - (void) dim:(BOOL) dim; - (void) finish; @end
CCBlade.m
#import "CCBlade.h" //计算旋转角度 inline float fangle(CGPoint vect){ //相同,不旋转 if (vect.x == 0.0 && vect.y == 0.0) { return 0; } //y不同,旋转90度 if (vect.x == 0.0) { return vect.y > 0 ? M_PI/2 : -M_PI/2; } //x逆向 if (vect.y == 0.0 && vect.x < 0) { return -M_PI; } //出去上面的特殊情况,剩下的atan计算角度 float angle = atan(vect.y / vect.x); return vect.x < 0 ? angle + M_PI : angle; } //p1,p2 原点 //o1,o2 目标点 //d 宽度 inline void f1(CGPoint p1, CGPoint p2, float d, CGPoint *o1, CGPoint *o2){ float l = ccpDistance(p1, p2); //计算转角角度 float angle = fangle(ccpSub(p2, p1)); //将p1点的width两端进行旋转 //这里只取p1,是因为下一次p2会迭代为p1进行计算 *o1 = ccpRotateByAngle(ccp(p1.x + l,p1.y + d), p1, angle); *o2 = ccpRotateByAngle(ccp(p1.x + l,p1.y - d), p1, angle); } inline float lagrange1(CGPoint p1, CGPoint p2, float x){ return (x-p1.x)/(p2.x - p1.x)*p2.y + (x-p2.x)/(p1.x - p2.x)*p1.y ; } inline void CGPointSet(CGPoint *v, float x, float y){ v->x = x; v->y = y; } @implementation CCBlade @synthesize texture = _texture; @synthesize pointLimit; @synthesize width; @synthesize autoDim; + (id) bladeWithMaximumPoint:(int) limit{ return [[[self alloc] initWithMaximumPoint:limit] autorelease]; } - (id) initWithMaximumPoint:(int) limit{ self = [super init]; pointLimit = limit; self.width = 5; vertices = (CGPoint *)calloc(2*limit+5, sizeof(vertices[0])); coordinates = (CGPoint *)calloc(2*limit+5, sizeof(coordinates[0])); CGPointSet(coordinates+0, 0.00, 0.5); reset = NO; path = [[NSMutableArray alloc] init]; return self; } - (void) dealloc{ [_texture release]; free(vertices); free(coordinates); [path release]; [super dealloc]; } //move (populater) vertices - (void) populateVertices{ vertices[0] = [[path objectAtIndex:0] CGPointValue]; //get the header point ,then iterate it CGPoint pre = vertices[0]; unsigned int i = 0; /** glTexCoordPointer(2, GL_FLOAT, 0, coordinates); glVertexPointer(2, GL_FLOAT, 0, vertices); */ //get second point ,then iterate it CGPoint it = [[path objectAtIndex:1] CGPointValue]; float dd = width / [path count]; //as "pre"&"it" cost 2 item ,so "while" is "n-2" // printf("%s:%d sizeof CGPoing:%ld\n",__FUNCTION__,__LINE__,sizeof(CGPoint)); while (i < [path count] - 2){ //change the width (height) of the blade //"width - i * dd",dd不变 i 越大,越宽 f1(pre, it, width - i * dd , vertices+2*i+1, vertices+2*i+2); // f1(pre, it, 7, vertices+2*i+1, vertices+2*i+2); //all coordinates are same value , never change value CGPointSet(coordinates+2*i+1, .5, 1.0); CGPointSet(coordinates+2*i+2, .5, 0.0); i++; pre = it; it = [[path objectAtIndex:i+1] CGPointValue]; } CGPointSet(coordinates+1, 0.25, 1.0); CGPointSet(coordinates+2, 0.25, 0.0); vertices[2*[path count]-3] = it; CGPointSet(coordinates+2*[path count]-3, 0.75, 0.5); } //移动点坐标,未用 - (void) shift{ int index = 2 * pointLimit - 1; for (int i = index; i > 3; i -= 2) { vertices[i] = vertices[i-2]; vertices[i-1] = vertices[i-3]; } } - (void) setWidth:(float)width_{ width = width_ * CC_CONTENT_SCALE_FACTOR(); } #define DISTANCE_TO_INTERPOLATE 10 //允许的线条最大长度 //insert a point at the header of the path - (void) push:(CGPoint) v{ _willPop = NO; if (reset) { return; } //retina screen if (CC_CONTENT_SCALE_FACTOR() != 1.0f) { v = ccpMult(v, CC_CONTENT_SCALE_FACTOR()); } if ([path count] == 0) { [path insertObject:[NSValue valueWithCGPoint:v] atIndex:0]; return; } CGPoint first = [[path objectAtIndex:0] CGPointValue]; if (ccpDistance(v, first) < DISTANCE_TO_INTERPOLATE) { //如果小于最大长度,则insert at the header [path insertObject:[NSValue valueWithCGPoint:v] atIndex:0]; if ([path count] > pointLimit) { [path removeLastObject]; } }else{ //移除最后的vertices int num = ccpDistance(v, first) / DISTANCE_TO_INTERPOLATE; CGPoint iv = ccpMult(ccpSub(v, first), (float)1./(num + 1)); for (int i = 1; i <= num + 1; i++) { [path insertObject:[NSValue valueWithCGPoint:ccpAdd(first, ccpMult(iv, i))] atIndex:0]; } while ([path count] > pointLimit) { [path removeLastObject]; } } [self populateVertices]; } //移除最后点 - (void) pop:(int) n{ while ([path count] > 0 && n > 0) { [path removeLastObject]; n--; } if ([path count] > 2) { [self populateVertices]; } } - (void) clear{ [path removeAllObjects]; reset = NO; if (_finish) [self removeFromParentAndCleanup:YES]; } - (void) reset{ reset = TRUE; } - (void) dim:(BOOL) dim{ reset = dim; } - (void) draw{ if ((reset && [path count] > 0) || (self.autoDim && _willPop)) { [self pop:1]; if ([path count] < 3) { [self clear]; } } if ([path count] < 3) { return; } _willPop = YES; glDisableClientState(GL_COLOR_ARRAY); NSAssert(_texture, @"NO TEXTURE SET"); /** f1(pre, it, width - i * dd , vertices+2*i+1, vertices+2*i+2); // f1(pre, it, 7, vertices+2*i+1, vertices+2*i+2); //all coordinates are same value , never change value CGPointSet(coordinates+2*i+1, .5, 1.0); CGPointSet(coordinates+2*i+2, .5, 0.0); */ glBindTexture(GL_TEXTURE_2D, _texture.name); // glVertexPointer(2, GL_FLOAT, 0, vertices); glTexCoordPointer(2, GL_FLOAT, 0, coordinates); glVertexPointer(2, GL_FLOAT, 0, vertices); // glTexCoordPointer(2, GL_FLOAT, 0, vertices); // glVertexPointer(2, GL_FLOAT, 0, coordinates); glDrawArrays(GL_TRIANGLE_STRIP, 0, 2*[path count]-2); //不是blade,是fans // glDrawArrays(GL_TRIANGLE_FAN, 0, 2*[path count]-2); glEnableClientState(GL_COLOR_ARRAY); } - (void) finish { _finish = YES; }