因为繁琐于写精灵的曲线运动,所以找相关解决的办法,最后找到了贝塞尔曲线。不过,只有cocos2d只支持3阶的贝塞尔动作怎么办,而且网上的算法也只有写3阶的。 于是,自己写了一个高阶的贝塞尔曲线,封装成CCActionInterval,调用的时候只要[sprite runAction:bezier]; 岂不爽哉! 第一步是找理论支持: 用到了下面这个公式: 阶贝塞尔曲线可如下推断。给定点P0、P1、…、Pn,其贝塞尔曲线即 。高阶曲线为建构高阶曲线,便需要相应更多的中介点。对于三次曲线,可由线性贝塞尔曲线描述的中介点Q0、Q1、Q2,和由二次曲线描述的点R0、R1所建构:
更详细的资料可以查看*——被赛尔曲线 然后是写算法: typedef struct controlPos{ float posX; float posY; }controlPos; //阶乘 static inline int factorial(int n){ int result = 1; while (n) { result *=n; n--; } return result; } //杨辉三角 static inline int pascalTriangleRatio(int n,int i){ int result = 0; result = factorial(n)/(factorial(i)*factorial(n-i)); return result; } //在t点贝塞尔多项式的和 static inline controlPos bezieerat(controlPos *p,int n,float t){ float px =0; float py = 0; int i=0; while (i<=n) { px += pascalTriangleRatio(n, i)*p.posX*powf(t, i)*powf(1-t, n-i); py += pascalTriangleRatio(n, i)*p.posY*powf(t, i)*powf(1-t, n-i); i++; } controlPos m; m.posX = px; m.posY = py; return m; } 第三步的时候考虑到贝塞尔曲线在确定控制点的时候实在不太友好,于是写个这么个东西: 为了直观的定义曲线,所以写了个类名为TestBeszer的CCLayer,在这个层可以编辑曲线, 在项目里加载这个层,则可以直观的在地图上编辑出曲线,挺方便的是不是。 // TestBeszer *testBezer = [[TestBeszer alloc] init]; // [self addChild:testBezer]; 我既可以画出爱心: 也可以画出卫生巾: 点击打印后就会打印出所有的坐标点了。 第四步封装: 我认为封装成CCActionInterval子类实在是太高明了,这让使用非常方便,测试过与原装的cocos2d动作都兼容。 封装的时候花了一些时间来弄明白cocos2d的动作编写机制。 类名是HCBezier, 调用方式如下,与原装动作可以组合使用。 controlPos array[3]={ {708,800}, {590,346}, {126,446} }; id bezier = [HCBezier actionWithPoints:array pointNumber:3 Duration:4.f]; // [sprite runAction:bezier]; [sprite runAction:[CCRepeatForever actionWithAction:[CCSequence actions:bezier,[CCDelayTime actionWithDuration:3.f],[CCMoveBy actionWithDuration:1.f position:ccp(-200, 40)],[bezier reverse], nil]]]; 最后,在HCBizer中有个不满意的地方 -(id) initWithPoints:(controlPos *)array pointNumber:(int)number Duration:(ccTime)t{ if (self = [super initWithDuration:t]) { number_ = number; arrayOfControlPoints = [[NSMutableArray alloc] init]; for (int i = 0; i<number_; i++) { CGPoint p = ccp(array.posX, array.posY); [arrayOfControlPoints addObject:[NSValue valueWithCGPoint:p]]; } } return self; } 我传入的是一个数组指针,我却没办法使用全局变量的方式取用这个数组,只能用nsarray转换,让人十分不爽,希望有人帮我解决这个问题。 //这里是让精灵移动,将t从0到1调用一遍是一个周期,这个周期会走完整个曲线,这个周期所经历的时间就是动作执行的时间。 -(void) update: (ccTime) t { controlPos _controlPos[number_]; for (int i = 0; i<number_; i++) { _controlPos.posX = [[arrayOfControlPoints objectAtIndex:i] CGPointValue].x; _controlPos.posY = [[arrayOfControlPoints objectAtIndex:i] CGPointValue].y; } controlPos pos = bezieerat(_controlPos, number_-1, t); CGPoint p = ccp(pos.posX, pos.posY); [target_ setPosition:p]; } 高阶贝塞尔曲线.zip(7.26 KB, 下载次数: 62) 补充内容 (2012-9-11 16:57): 更新了附件在三楼 |
-
-
HAH3]R%9QIT~85~B)_X52GI.jpg(40.46 KB, 下载次数: 0)
-
-
QQ20120906-1.png(31.7 KB, 下载次数: 0)
来自:http://bbs.tairan.com/thread-3536-1-1.html