ios中实现staggeringBeauty的效果(三)

ios中实现staggeringBeauty的效果(三)

我们直接进入主题吧。
先由main.js来入手。https://github.com/georgealways/staggeringbeauty/blob/master/src/main.js
这里我只展开需要的部分,其他部分先忽略,一开始声明了很多的变量,其中重要的有pathBody会调用

function buildBody() {

  for (i = 0; i < numPoints; i++) {

    var x = view.size.width / 2;
    var y = view.size.height - (i-1)*segmentLength;

    var particle = physics.makeParticle(2.5, x, y, 0);
    var support = physics.makeParticle(1, x, y - segmentLength, 0);
    var support2 = physics.makeParticle(1, x, y + segmentLength, 0);

    if (i > 0) {
      var prevSupport = supports[i-1];
      var prevParticle = particles[i-1];
      physics.makeSpring(particle, prevSupport, 0.6, 0.48, 0);
      physics.makeSpring(prevParticle, support2, 0.3, 0.7, 0);
      springs.push(physics.makeSpring(particle, prevParticle, 0.2, 0.1, segmentLength));
    }

    if (i < 2) {
      particle.makeFixed();
    }

    support.makeFixed();
    support2.makeFixed();

    var point = new Point();
    pathBody.add(point);
    // pathBodyStroke.add(point);
    // pathShadow.add(point);

    particles.push(particle);
    supports.push(support);
    supports2.push(support2);

  }

}

来建立body,这里想要说的是supports与supports2的用来不断去设限制条件(力和距离的控制点在oc中要重点实现)。

function setPositions() {

  var e = mouseDown ? params.mouseTargetEasing : params.mouseTargetEasingUp;

  mousePos.x += (targetMousePos.x - mousePos.x) * e;
  mousePos.y += (targetMousePos.y - mousePos.y) * e;

  particles[1].position.x = mousePos.x;
  particles[1].position.y = mousePos.y;

  var targetStress = 0;

  for (var i = 1; i < numPoints; i++) {

    var support = supports[i];
    var curParticle = particles[i];

    curParticle.position.x = clamp(curParticle.position.x, padding, view.size.width-padding);

    var prevParticle = particles[i-1];
    var angle = Math.atan2(curParticle.position.y - prevParticle.position.y, curParticle.position.x - prevParticle.position.x);

    var force = curParticle.force.length();
    if (force > maxForce) {
      curParticle.force.scale(force / maxForce);

      force = maxForce;
    }

    if (i > 1) targetStress += force;

    support.position.x = curParticle.position.x + Math.cos(angle + i*bend)*segmentLength;
    support.position.y = curParticle.position.y + Math.sin(angle + i*bend)*segmentLength;

    pathBody.segments[i].angle = angle;

    var support2 = supports2[i];
    support2.position.x = curParticle.position.x + Math.cos(Math.PI + angle)*segmentLength;
    support2.position.y = curParticle.position.y + Math.sin(Math.PI + angle)*segmentLength;

  }

  stress += (targetStress-stress)*0.03;

}


function updateAppearance() {

  if (stress > 80) {

    hue += stress > 300 ? Math.pow(stress/5, 2) : stress;

    pathBody.strokeColor = 'hsl('+Math.round(hue)%360+', 100%, 50%)';
    pathMouth.strokeColor = 'hsl('+Math.round(hue)%360+', 100%, 90%)';
    pathTongue.strokeColor = 'hsl('+Math.round(hue)%360+', 100%, 50%)';
    pathMouth.strokeWidth = thickness/1.5 + (Math.random()-Math.random())*20;
    pathTongue.strokeWidth = pathMouth.strokeWidth*0.65;
    // pathShadow.strokeColor = '#000';
    peaking = true;
    clearTimeout(wrong);
    document.getElementById('shake').style.display = 'none';

  } else {


    pathBody.strokeColor = params.fillColor;
    // pathBodyStroke.strokeColor = params.strokeColor;
    // pathShadow.strokeColor = null;
    peaking = false;

  }


  if (peaking) {
    // document.body.className = Math.random() < 0.8 ? 'bg-a' : 'bg-b';
      document.body.className = frameCount % 3 != 0 ? 'bg-a' : 'bg-b';

    if (!prevPeaking) {
      physics.drag = 0.2;
      pathMouth.opacity = 1;
      pathTongue.opacity = 1;
      // unSmooth();
      eyeJiggler.rest = 17;
    }
    if (firstPlay && audio) {
      // audio.play({ loops: 1000 });
      // console.log('set volume');
      audio.setVolume(50);
      audio2.setVolume(70);
      firstPlay = false;
    }
  } else if (!peaking && prevPeaking) {
    document.body.className = '';
    physics.drag = restDrag;
    pathMouth.opacity = 0;
    pathTongue.opacity = 0;
    eyeJiggler.rest = 6;
    if (audio) {
      // audio.pause();
      audio.setVolume(0);
      audio2.setVolume(0);
      firstPlay = true;
    }
  }

  prevPeaking = peaking;

}

function updatePaths() {

  for (var i = 0, j, l; i < numPoints; i++) {

    var curParticle = particles[i];
    var prevParticle = particles[i-1];
    var angle = pathBody.segments[i].angle + Math.PI/2;

    pathBody.segments[i].point.x = curParticle.position.x;
    pathBody.segments[i].point.y = curParticle.position.y;

    // pathBodyStroke.segments[i].point.x = curParticle.position.x;
    // pathBodyStroke.segments[i].point.y = curParticle.position.y;

    j = i-mouthPadding+1;
    l = pathMouth.segments.length;

    if (j >= 0 && j < l) {

      pathMouth.segments[j].point.x = curParticle.position.x;// + (Math.random() - Math.random())*10;
      pathMouth.segments[j].point.y = curParticle.position.y;// + (Math.random() - Math.random())*10;
      pathMouth.segments[j].point.x += Math.cos(angle)*thickness/6;
      pathMouth.segments[j].point.y += Math.sin(angle)*thickness/10;

      if (pathTongue.segments[j]) {
        pathTongue.segments[j].point.x = pathMouth.segments[j].point.x;
        pathTongue.segments[j].point.y = pathMouth.segments[j].point.y;
        pathTongue.segments[j].point.x -= Math.cos(angle)*(pathMouth.strokeWidth/15);
        pathTongue.segments[j].point.y -= Math.sin(angle)*(pathMouth.strokeWidth/5);
      }

    }

    // pathShadow.segments[i].point.x = curParticle.position.x+50;
    // pathShadow.segments[i].point.y = curParticle.position.y-10;


  }

  if (smooth) {
    for (var i = 0, l = paths.length; i < l; i++) {
      paths[i].smooth();
    }
  }

}

而这里的setPositions() ,updateAppearance(),updatePaths()由它的名字就可以得知它门各自的作用分别是设置点的位置,更新显示,更新paths。这就是我们在oc要重构的东西。

如果只是要实现的话你可以自己,在你工程文件中加入https://github.com/chrismiles/DynamicXray
工程中的Spring Rope文件
这里写图片描述
然后直接在里面修改,当然这是最直接方法,如果你想一步步的展开,明天的博客,我会按照我当时摸索的一步步来。
这里使用了,外国的这位大神已经为我门做了particle和path了。
我们在layer中实现这些运动。
这里我们先简单说一下CALayer这里就引用大神的话来解释吧,http://www.cnblogs.com/kenshincui/p/3972100.html
去这里看看,试一试我大家就会有所了解,这里姑且把它当作一个需要渲染的图层吧,(后面我还在这图层上加了UIView为了加物理碰撞。。。好象有点前后矛盾在CALayer中加UIView好像并不符合一般的规则)

/*
    Physics Configuration
 */
static CGFloat const CMSpringyRopeDamping = 1.0f;
static CGFloat const CMSpringyRopeFrequency = 4.0f;
static CGFloat const CMSpringyRopeParticleDensity = 1.0f;
static CGFloat const CMSpringyRopeParticleResistance = 1.0f;

/*
    Visual Configuration
 */
static CGFloat const CMSpringyRopeLength =300.0f;
static NSUInteger const CMSpringyRopeSubdivisons = 8;
static CGFloat const CMSpringyRopeHandleRadius = 5.0f;




static CGFloat const stressNumber=1300;

/*
    Utility Functions
 */
static CGFloat CGPointDistance(CGPoint userPosition, CGPoint prevPosition)
{
    CGFloat dx = prevPosition.x - userPosition.x;
    CGFloat dy = prevPosition.y - userPosition.y;
    return sqrtf(dx*dx + dy*dy);
}


/*
    CMSpringyRopeLayer
 */
@interface CMSpringyRopeLayer ()

@property (assign, nonatomic) float rope_length;
@property (assign, nonatomic) NSUInteger subdivisions;

@property (assign, nonatomic) BOOL isDragging;
@property (assign, nonatomic) CGSize lastSize;

@property (assign, nonatomic) float gravityScale;
@property (strong, nonatomic) CMMotionManager *motionManager;

// Physics
@property (strong, nonatomic) UIDynamicAnimator *animator;
@property (strong, nonatomic) UIGravityBehavior *gravityBehavior;
@property (strong, nonatomic) UICollisionBehavior *collisionBehavior;
@property (strong, nonatomic) NSArray *particles;

@property (assign,nonatomic) CGFloat addGravite;

//support
@property (strong,nonatomic)NSArray *supports1;
@property (strong,nonatomic)NSArray *supports2;


@property (strong, nonatomic) UIAttachmentBehavior *anchorSpringBehavior;
@property (strong, nonatomic) CMSpringyRopeParticle *handleParticle;
@property (strong, nonatomic) UIAttachmentBehavior *handleSpringBehavior;
@property (strong, nonatomic) UIDynamicItemBehavior *particleBehavior;
/*
    Physics Configuration
 */
static CGFloat const CMSpringyRopeDamping = 1.0f;
static CGFloat const CMSpringyRopeFrequency = 4.0f;
static CGFloat const CMSpringyRopeParticleDensity = 1.0f;
static CGFloat const CMSpringyRopeParticleResistance = 1.0f;

/*
    Visual Configuration
 */
static CGFloat const CMSpringyRopeLength =300.0f;
static NSUInteger const CMSpringyRopeSubdivisons = 8;
static CGFloat const CMSpringyRopeHandleRadius = 5.0f;




static CGFloat const stressNumber=1300;

/*
    Utility Functions
 */
static CGFloat CGPointDistance(CGPoint userPosition, CGPoint prevPosition)
{
    CGFloat dx = prevPosition.x - userPosition.x;
    CGFloat dy = prevPosition.y - userPosition.y;
    return sqrtf(dx*dx + dy*dy);
}


/*
    CMSpringyRopeLayer
 */
@interface CMSpringyRopeLayer ()

@property (assign, nonatomic) float rope_length;
@property (assign, nonatomic) NSUInteger subdivisions;

@property (assign, nonatomic) BOOL isDragging;
@property (assign, nonatomic) CGSize lastSize;

@property (assign, nonatomic) float gravityScale;
@property (strong, nonatomic) CMMotionManager *motionManager;

// Physics
@property (strong, nonatomic) UIDynamicAnimator *animator;
@property (strong, nonatomic) UIGravityBehavior *gravityBehavior;
@property (strong, nonatomic) UICollisionBehavior *collisionBehavior;
@property (strong, nonatomic) NSArray *particles;

@property (assign,nonatomic) CGFloat addGravite;

//support
@property (strong,nonatomic)NSArray *supports1;
@property (strong,nonatomic)NSArray *supports2;


@property (strong, nonatomic) UIAttachmentBehavior *anchorSpringBehavior;
@property (strong, nonatomic) CMSpringyRopeParticle *handleParticle;
@property (strong, nonatomic) UIAttachmentBehavior *handleSpringBehavior;
@property (strong, nonatomic) UIDynamicItemBehavior *particleBehavior;
@property (strong, nonatomic) DynamicXray *dynamicXray;

// FPS
@property (assign, nonatomic) double fps_prev_time;
@property (assign, nonatomic) NSUInteger fps_count;
@property (assign,nonatomic) int eyesNumber;



@property(assign,nonatomic) CGFloat stress;

@end


@implementation CMSpringyRopeLayer

@property (strong, nonatomic) DynamicXray *dynamicXray;

// FPS
@property (assign, nonatomic) double fps_prev_time;
@property (assign, nonatomic) NSUInteger fps_count;
@property (assign,nonatomic) int eyesNumber;



@property(assign,nonatomic) CGFloat stress;

@end


@implementation CMSpringyRopeLayer

先定义了一大部分的属性,变量的大家就看着英文去了解吧。。我就不逐个去翻译了。其中的DynamicXray *dynamicXray 是这个应用的一个功能,用Xray去观察运动,这个用来去慢慢调整那个魔性的晃动效果简直不能太赞了。(感谢神让我找到他。。)
先补充一句上面的代码是我已经做了修改的了,所以和Github上的有的不一样,在最后好会把我的做成游戏的代码附上,因为把它提交了之后,就赶着做第二款游戏,都没有整理一下代码。。。乱的够可以的,所以我整理之后会在最后的一篇中把代码附上。

好吧继续分析代码,轮到init了

- (id)init
{
    self = [super init];
    if (self) {
    //适应屏幕大小
    self.contentsScale = [UIScreen mainScreen].scale;

    _lastSize = self.bounds.size;

    _rope_length = CMSpringyRopeLength;
    _subdivisions = CMSpringyRopeSubdivisons;

    _motionManager = [[CMMotionManager alloc] init];
        _motionManager.deviceMotionUpdateInterval = 0.02; // 50 Hz

    //add UIDynamicAnimator
    _animator = [[UIDynamicAnimator alloc] init];
    //add UIGravityBehavior
    _gravityBehavior = [[UIGravityBehavior alloc] initWithItems:nil];
    _gravityBehavior.gravityDirection = CGVectorMake(0.0, -0.5f);

    __weak CMSpringyRopeLayer *weakSelf = self;
    _gravityBehavior.action = ^{
        __strong CMSpringyRopeLayer *strongSelf = weakSelf;
        [strongSelf drawFrame];
    };
    [_animator addBehavior:_gravityBehavior];

    _particleBehavior = [[UIDynamicItemBehavior alloc] initWithItems:nil];
    _particleBehavior.density = CMSpringyRopeParticleDensity;
    _particleBehavior.resistance = CMSpringyRopeParticleResistance;

    [_animator addBehavior:_particleBehavior];

        self.dynamicXray = [[DynamicXray alloc] init];
        [self.animator addBehavior:self.dynamicXray];
    }
    return self;
}

主要是加物理系统,这里用到了苹果自带的物理系统而没有使用traer.js,用了traer.js的重构的那个后面我会在提到。但这里也会跟据traer.js的原理来使用苹果自带的物理系统 UIDynamicAnimator
可以借鉴http://my.oschina.net/u/1378445/blog/335014

然后就是实现main.js中的particle了

#pragma mark - Set Up Physics

- (void)generateParticles
{
    NSMutableArray *particles = [NSMutableArray array];
    NSMutableArray *supports1=[NSMutableArray array];
    NSMutableArray *supports2=[NSMutableArray array];

    CGPoint anchorPoint = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetHeight(self.bounds));

    NSUInteger subdivisions = self.subdivisions;

    float sub_len = self.rope_length / subdivisions;
    for (NSUInteger i=1; i<=subdivisions; i++) {
    UIView *p = [[UIView alloc] initWithFrame:CGRectMake(anchorPoint.x, anchorPoint.y - i*sub_len, 10, 10)];
    [particles addObject:p];

        CMSpringyRopeParticle *support1=[[CMSpringyRopeParticle alloc]initWithCenterPosition:CGPointMake(anchorPoint.x, anchorPoint.y - (i-1)*sub_len)];
        [supports1 addObject:support1];

        CMSpringyRopeParticle *support2=[[CMSpringyRopeParticle alloc]initWithCenterPosition:CGPointMake(anchorPoint.x, anchorPoint.y - (i+1)*sub_len)];
        [supports2 addObject:support2];

    [self.particleBehavior addItem:p];
    [self.gravityBehavior addItem:p];



        [self.particleBehavior addItem:support1];
        [self.particleBehavior addItem:support2];

    }

    self.handleParticle = [particles objectAtIndex:1];
    NSUInteger particlesMaxIndex = [particles count] - 1;

    //add SpringBehavior
    for (NSUInteger i=0; i<particlesMaxIndex; i++)  {
    if (i == 0) {
        self.anchorSpringBehavior = [self addSpringBehaviorWithItem:particles[i] attachedToAnchor:anchorPoint];
    }

    UIAttachmentBehavior *springBehavior = [self addSpringBehaviorWithItem:particles[i] attachedToItem:particles[i+1]];

        UIAttachmentBehavior *support1SpringBehavior=[self addSuppotr1SpringBehaviorWithItem:supports1[i+1] attachedToItem:particles[i]];

        UIAttachmentBehavior *support2SpringBehavior=[self addSuppotr2SpringBehaviorWithItem: supports2[i]attachedToItem:particles[i+1]];

    if (i == 1) {
        self.handleSpringBehavior = springBehavior;
    }
    }

//    UIView * leftconner=[[UIView alloc] initWithFrame:CGRectMake(CGRectGetMinX(self.bounds), CGRectGetMinY(self.bounds), 20, 20)];
//    
//     UIView * rightconner=[[UIView alloc] initWithFrame:CGRectMake(CGRectGetMaxX(self.bounds)-10, CGRectGetMinY(self.bounds), 10, CGRectGetMaxY(self.bounds))];

    self.particles = particles;
    self.supports1=supports1;
    self.supports2=supports2;


//    NSMutableArray * collisonView=[NSMutableArray arrayWithArray:particles];
//    [collisonView addObject:leftconner];
//    [collisonView addObject:rightconner];

    UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:particles];
    collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
    collisionBehavior.collisionMode=UICollisionBehaviorModeEverything;
    [collisionBehavior addBoundaryWithIdentifier:@"line1" fromPoint:CGPointMake(CGRectGetMinX(self.bounds)+10, CGRectGetMinY(self.bounds)) toPoint:CGPointMake(CGRectGetMinX(self.bounds)+10,CGRectGetMaxY(self.bounds)+400)];

        [collisionBehavior addBoundaryWithIdentifier:@"line2" fromPoint:CGPointMake(CGRectGetMaxX(self.bounds)-10, CGRectGetMinY(self.bounds)) toPoint:CGPointMake(CGRectGetMaxX(self.bounds)-10,CGRectGetMaxY(self.bounds)+400)];

//    UICollisionBehavior *collisionBehavior2 = [[UICollisionBehavior alloc] initWithItems:@[leftconner,rightconner]];
//    collisionBehavior2.translatesReferenceBoundsIntoBoundary = YES;
//    collisionBehavior2.collisionMode=UICollisionBehaviorModeEverything;
//    


    [self.animator addBehavior:collisionBehavior];
    //[self.animator addBehavior:collisionBehavior2];

}

按照traer.js在particle间加了Spring弹簧引力。

其中各个particle,support1,support2间力的作用由下面的函数来实现


- (UIAttachmentBehavior *)addSpringBehaviorWithItem:(id<UIDynamicItem>)item attachedToAnchor:(CGPoint)anchorPoint
{
    UIAttachmentBehavior *springBehavior = [[UIAttachmentBehavior alloc] initWithItem:item attachedToAnchor:anchorPoint];
    [self configureSpringBehavior:springBehavior];
    [self.animator addBehavior:springBehavior];
    return springBehavior;
}

- (UIAttachmentBehavior *)addSpringBehaviorWithItem:(id<UIDynamicItem>)itemA attachedToItem:(id<UIDynamicItem>)itemB
{
    UIAttachmentBehavior *springBehavior = [[UIAttachmentBehavior alloc] initWithItem:itemA attachedToItem:itemB];
    [self configureSpringBehavior:springBehavior];
    [self.animator addBehavior:springBehavior];
    return springBehavior;
}

- (UIAttachmentBehavior *)addSuppotr1SpringBehaviorWithItem:(id<UIDynamicItem>)itemA attachedToItem:(id<UIDynamicItem>)itemB
{
    UIAttachmentBehavior *springBehavior = [[UIAttachmentBehavior alloc] initWithItem:itemA attachedToItem:itemB];
    [self configureSupport1SpringBehavior:springBehavior];
    [self.animator addBehavior:springBehavior];
    return springBehavior;
}

- (UIAttachmentBehavior *)addSuppotr2SpringBehaviorWithItem:(id<UIDynamicItem>)itemA attachedToItem:(id<UIDynamicItem>)itemB
{
    UIAttachmentBehavior *springBehavior = [[UIAttachmentBehavior alloc] initWithItem:itemA attachedToItem:itemB];
    [self configureSupport2SpringBehavior:springBehavior];
    [self.animator addBehavior:springBehavior];
    return springBehavior;
}


- (void)configureSpringBehavior:(UIAttachmentBehavior *)springBehavior
{
    float sub_len = self.rope_length / self.subdivisions;
    springBehavior.length = sub_len;
    springBehavior.frequency = CMSpringyRopeFrequency;
    springBehavior.damping = CMSpringyRopeDamping;
}

- (void)configureSupport1SpringBehavior:(UIAttachmentBehavior *)springBehavior
{
   // float sub_len = self.rope_length / self.subdivisions;
    springBehavior.length = 0.0;
    springBehavior.frequency = CMSpringyRopeFrequency*7;
    springBehavior.damping = CMSpringyRopeDamping*2;
}

- (void)configureSupport2SpringBehavior:(UIAttachmentBehavior *)springBehavior
{
    //float sub_len = self.rope_length / self.subdivisions;
    springBehavior.length = 0.0;
    springBehavior.frequency = CMSpringyRopeFrequency*3;
    springBehavior.damping = CMSpringyRopeDamping*5;
}

这是按照traer.js然后作细调的来实现的。

然后有update,与玩家的交互什么的明天在分析,今天代码量有点多一天不能吃成胖子嘛,明天ios中实现staggeringBeauty的效果(四)继续,尽量不跳票。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值