明天ios中实现staggeringBeauty的效果(四)
好吧。。。过了两天再回来。。
今天讲的是用户的交互,先在 CMSpringyRopeLayer.h中加上外调的函数,之后会在CMSpringyRopeView中调用
- (void)touchBeganAtLocation:(CGPoint)location;
- (void)touchMovedAtLocation:(CGPoint)location;
- (void)touchEndedAtLocation:(CGPoint)location;
- (void)touchCancelledAtLocation:(CGPoint)location;
然后跳的CMSpringyRopeLayer.m来实现上面这三个函数
#pragma mark - Handle touches
- (void)touchBeganAtLocation:(CGPoint)location
{
//if (CGPointDistance(location, self.handleParticle.center) <= 40.0f) {
[self moveHandleToLocation:location];
self.isDragging = YES;
//}
}
- (void)touchMovedAtLocation:(CGPoint)location
{
if (self.isDragging) {
[self moveHandleToLocation:location];
}
}
- (void)touchEndedAtLocation:(CGPoint)location
{
if (self.isDragging) {
[self moveHandleToLocation:location];
//self.isDragging = NO;
}
}
- (void)touchCancelledAtLocation:(__unused CGPoint)location
{
if (self.isDragging) {
//self.isDragging = NO;
}
}
#pragma mark - Move Handle
- (void)moveHandleToLocation:(CGPoint)location
{
CGFloat angle=atan2(location.y,location.x-CGRectGetMidX(self.bounds));
location.x=CGRectGetMidX(self.bounds)+cos(angle)*_rope_length*1.5;
location.y=CGRectGetHeight(self.bounds)-sin(angle)*_rope_length/5;
self.addGravite=cos(angle)*0.5;
self.handleParticle.center = location;
self.handleSpringBehavior.anchorPoint = location;
[self.animator updateItemUsingCurrentState:self.handleParticle];
}
其中的handleParticle这里使用的第2个Particle点,上一篇的- (void)generateParticles 函数中的一句:
self.handleParticle = [particles objectAtIndex:1];
可以得,当然这个是个人调试定出来的,可以通过调试根据个人喜好来决定。。。其实应该把数值用 static CGFloat const ****去先定义好,然后以后改就直接在上面去修改,方便去看去参考,所以之前就说代码没有重构好,先不放上来。好吧先姑且看着吧。
上面的- (void)touchBeganAtLocation:(CGPoint)location;
- (void)touchMovedAtLocation:(CGPoint)location;
- (void)touchEndedAtLocation:(CGPoint)location;
- (void)touchCancelledAtLocation:(CGPoint)location;
函数与苹果自带的那几个东西,是不是很像对,你猜的没错就是在那几个东西里分别去调用。给自己一个赞吧。
#pragma mark - Handle touches
- (void)touchesBegan:(NSSet *)touches withEvent:(__unused UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint position = [touch locationInView:self];
[self.springyRopeLayer touchBeganAtLocation:position];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(__unused UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint position = [touch locationInView:self];
[self.springyRopeLayer touchMovedAtLocation:position];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(__unused UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint position = [touch locationInView:self];
[self.springyRopeLayer touchEndedAtLocation:position];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(__unused UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint position = [touch locationInView:self];
[self.springyRopeLayer touchCancelledAtLocation:position];
}
当然了,你得先在#import “CMSpringyRopeLayer.h”,这个就再提一下。。虽然大家都应该知道。
现在来讲一下update的实现吧,当用户做了操作之后当然要update一下,要做一个反馈,一般update都是每隔一段时间然后重新去加载。
这里有一点特别,如果你看的仔细的话,在init中有那么两句
__weak CMSpringyRopeLayer *weakSelf = self;
_gravityBehavior.action = ^{
__strong CMSpringyRopeLayer *strongSelf = weakSelf;
[strongSelf drawFrame];
};
把_gravityBehavior(重力)与drawFrame(重绘)联系在了一起,为什么这样做,我想应该是为了方便,先来看一下重绘吧。
#pragma mark - Draw Frame
- (void)drawFrame
{
//if (self.motionManager.isDeviceMotionActive) {
//CMAcceleration gravity = self.motionManager.deviceMotion.gravity;
//由stress的值来决定重力的大小
CGVector gravityVector = CGVectorMake((float)self.addGravite, (float)-0.5);
if (self.stress>stressNumber) {
gravityVector = CGVectorMake((float)self.addGravite, (float)-2.5);
}else{
gravityVector = CGVectorMake((float)self.addGravite, (float)-0.5);
}
gravityVector = [self vector:gravityVector rotatedToInterfaceOrientation:[[UIApplication sharedApplication] statusBarOrientation]];
self.gravityBehavior.gravityDirection = gravityVector;
// }
[self setNeedsDisplay]; // draw layer
/* FPS */
if (self.fpsLabel) {
double curr_time = CACurrentMediaTime();
if (curr_time - self.fps_prev_time >= 0.2) {
double delta = (curr_time - self.fps_prev_time) / self.fps_count;
self.fpsLabel.text = [NSString stringWithFormat:@"%0.0f fps", 1.0/delta];
self.fps_prev_time = curr_time;
self.fps_count = 1;
}
else {
self.fps_count++;
}
}
//set the supports points
CGFloat targetStress=0;
double bend=-0.15;
NSUInteger particlesMaxIndex = [self.particles count];
//调整 support1,support2
for (NSUInteger i=1; i<particlesMaxIndex; i++) {
// CMSpringyRopeParticle *particle=self.particles[i];
// if (particle.center.x<CGRectGetMinX(self.bounds)) {
// particle.center=CGPointMake(CGRectGetMinX(self.bounds)+50, particle.center.y) ;
// }else if(particle.center.x>CGRectGetMaxX(self.bounds)){
// particle.center=CGPointMake(CGRectGetMaxX(self.bounds)-50, particle.center.y) ;
// }
//
CMSpringyRopeParticle *support2=self.supports2[i];
CMSpringyRopeParticle *curPartice=self.particles[i];
CMSpringyRopeParticle *prePartice=self.particles[i-1];
double angle=atan2(curPartice.center.y-prePartice.center.y, curPartice.center.x-prePartice.center.x);
CGFloat support2x=curPartice.center.x-cos(angle+i*bend)*CMSpringyRopeLength/9 ;
CGFloat support2y=curPartice.center.y-sin(angle+i*bend)*CMSpringyRopeLength /9;
support2.center=CGPointMake(support2x, support2y);
CMSpringyRopeParticle *support1=self.supports1[i];
CGFloat support1x=curPartice.center.x-cos(angle+3.14)*CMSpringyRopeLength/9 ;
CGFloat support1y=curPartice.center.y-sin(angle+3.14)*CMSpringyRopeLength /9;
support1.center=CGPointMake(support1x, support1y);
CGFloat length=(curPartice.center.x-prePartice.center.x)*(curPartice.center.x-prePartice.center.x)/200;
if (i>1) {
targetStress+=length;
}
}
self.stress+=(targetStress-self.stress*0.1)*0.1;
}
#pragma mark - CALayer methods
- (void)drawInContext:(CGContextRef)ctx
{
if (!CGSizeEqualToSize(self.bounds.size, self.lastSize)) {
self.gravityScale = 1.0f * CGRectGetHeight(self.frame) / 320.0f;
self.lastSize = self.bounds.size;
}
CGMutablePathRef path = CGPathCreateMutable();
CGPoint anchorPoint = self.anchorSpringBehavior.anchorPoint;
CGPathMoveToPoint(path, NULL, anchorPoint.x, anchorPoint.y);
for (NSUInteger i=0; i<[self.particles count]; i++) {
CMSpringyRopeParticle *p = [self.particles objectAtIndex:i];
CGPathAddLineToPoint(path, NULL, p.center.x, p.center.y);
}
UIGraphicsPushContext(ctx);
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithCGPath:path];
bezierPath = smoothedPath(bezierPath, 8);
bezierPath.lineWidth=110;
bezierPath.lineCapStyle=kCGLineCapRound;
bezierPath.lineJoinStyle = kCGLineJoinRound;
if (self.smoothed) {
bezierPath.lineWidth=110;
bezierPath.lineJoinStyle = kCGLineJoinRound;
bezierPath.lineCapStyle=kCGLineCapRound;
//[bezierPath fill];
}
if (self.stress>stressNumber) {
NSLog(@"rilegoule");
[[UIColor colorWithRed:1 green:0 blue:0.1 alpha:0.9]setStroke];
}
[bezierPath stroke];
UIGraphicsPopContext();
CGPathRelease(path);
// Draw handle
CGPoint handlePoint = self.handleParticle.center;
CGContextAddEllipseInRect(ctx, CGRectMake(handlePoint.x-CMSpringyRopeHandleRadius, handlePoint.y-CMSpringyRopeHandleRadius, CMSpringyRopeHandleRadius*2, CMSpringyRopeHandleRadius*2));
CGContextStrokePath(ctx);
[self addEyes:ctx];
}
一般的在代码中已经写了注释,这里提一下上面的
[self setNeedsDisplay]; // draw layer
是调用- (void)drawInContext:(CGContextRef)ctx的标志千万不要忘了
而[self addEyes:ctx];是加那对色咪咪的眼睛,
#pragma mark - add eyes
-(void)addEyesBig:(CGContextRef)ctx{
CGFloat eyeToeyelength=40;
UIView *view1=self.particles[[self.particles count]-1];
UIView *view2=self.particles[[self.particles count]-2];
CGFloat angle=atan2(view2.center.y-view1.center.y, view2.center.x-view1.center.x)+90;
CGPoint eyeLeft=CGPointMake(view2.center.x+cos(angle)*eyeToeyelength/2+5, view2.center.y+sin(angle)*eyeToeyelength/6-20);
CGPoint eyeRight=CGPointMake(view2.center.x-cos(angle)*eyeToeyelength/2+5, view2.center.y-sin(angle)*eyeToeyelength/6-20);
// CGContextAddRect(ctx, CGRectMake(eyeLeft.x, eyeLeft.y+5, 20, 2));
CGContextAddEllipseInRect(ctx, CGRectMake(eyeLeft.x, eyeLeft.y, 15, 15));
CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
// CGContextRotateCTM(ctx,angle*M_PI/90);
//CGContextAddRect(ctx, CGRectMake(eyeRight.x, eyeRight.y+5, 20, 2));
CGContextAddEllipseInRect(ctx, CGRectMake(eyeRight.x, eyeRight.y, 15, 15));
CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
CGContextRotateCTM(ctx,angle*M_PI/180);
CGContextFillPath(ctx);
}
-(void)addEyesSmall:(CGContextRef)ctx{
CGFloat eyeToeyelength=40;
UIView *view1=self.particles[[self.particles count]-1];
UIView *view2=self.particles[[self.particles count]-2];
CGFloat angle=atan2(view2.center.y-view1.center.y, view2.center.x-view1.center.x)+90;
CGPoint eyeLeft=CGPointMake(view2.center.x+cos(angle)*eyeToeyelength/2+5, view2.center.y+sin(angle)*eyeToeyelength/6-20);
CGPoint eyeRight=CGPointMake(view2.center.x-cos(angle)*eyeToeyelength/2+5, view2.center.y-sin(angle)*eyeToeyelength/6-20);
CGContextAddRect(ctx, CGRectMake(eyeLeft.x, eyeLeft.y+5, 15, 2));
//CGContextAddEllipseInRect(ctx, CGRectMake(eyeLeft.x, eyeLeft.y, 10, 10));
CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
// CGContextRotateCTM(ctx,angle*M_PI/90);
CGContextAddRect(ctx, CGRectMake(eyeRight.x, eyeRight.y+5, 15, 2));
//CGContextAddEllipseInRect(ctx, CGRectMake(eyeRight.x, eyeRight.y, 10, 10));
CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
CGContextRotateCTM(ctx,angle*M_PI/180);
CGContextFillPath(ctx);
}
-(void)addEyesshape:(CGContextRef)ctx{
CGFloat eyeToeyelength=40;
UIView *view1=self.particles[[self.particles count]-1];
UIView *view2=self.particles[[self.particles count]-2];
CGFloat angle=atan2(view2.center.y-view1.center.y, view2.center.x-view1.center.x)+90;
CGPoint eyeLeft=CGPointMake(view2.center.x+cos(angle)*eyeToeyelength/2+5, view2.center.y+sin(angle)*eyeToeyelength/6-20);
CGPoint eyeRight=CGPointMake(view2.center.x-cos(angle)*eyeToeyelength/2+5, view2.center.y-sin(angle)*eyeToeyelength/6-20);
CGContextAddRect(ctx, CGRectMake(eyeLeft.x, eyeLeft.y+5, 15, 2));
CGContextAddRect(ctx, CGRectMake(eyeLeft.x+7.5, eyeLeft.y-2.5, 2, 15));
//CGContextAddEllipseInRect(ctx, CGRectMake(eyeLeft.x, eyeLeft.y, 10, 10));
CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
// CGContextRotateCTM(ctx,angle*M_PI/90);
CGContextAddRect(ctx, CGRectMake(eyeRight.x, eyeRight.y+5, 15, 2));
CGContextAddRect(ctx, CGRectMake(eyeRight.x+7.5, eyeRight.y-2.5, 2, 15));
//CGContextAddEllipseInRect(ctx, CGRectMake(eyeRight.x, eyeRight.y, 10, 10));
CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
CGContextRotateCTM(ctx,angle*M_PI/180);
CGContextFillPath(ctx);
}
-(void)addEyes:(CGContextRef)ctx{
if (self.stress>stressNumber) {
[self addEyesshape:ctx];
}else{
self.eyesNumber+=1;
int i=self.eyesNumber;
if (i==509||i==510|| i==524||i==525||i==538||i==539||i==548||i==549) {
[self addEyesSmall:ctx];
}else if((i>510&&i<524)||(i>538&&i<548)){
}
else{
[self addEyesBig:ctx];
}
if (self.eyesNumber>1000) {
self.eyesNumber=0;
}
}
}
所以就是这样, staggeringBeauty那个魔性的晃动就是这样模仿出来了,然后在下一篇会完全按照,traer.js去做,不使用苹果自带的物理模型,当然。。。不一定会做。。也许就简单的把代码重构后打包上来分享了。。。因为最近在做另一款游戏也比较忙。。。见谅。。