核心动画-1. 播放器图片旋转 2. 实现汽车轨迹移动

199 阅读4分钟

贝塞尔曲线

截屏2022-09-24 23.37.37.png

1. 播放器图片旋转

IMG_6656.GIF

代码:

#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
#define DEGREES_TO_RADIANS(d) (d * M_PI / 180)
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    //设置背景颜色
    self.view.backgroundColor = [UIColor colorWithRed:0.972 green:0.134 blue:0.173 alpha:1.000];
    self.view.tintColor = [UIColor whiteColor];
    
    // Setup AVPlayer
    //1.视频地址
    NSString *moviePath = [[NSBundle mainBundle] pathForResource:@"cyborg" ofType:@"m4v"];
    //2.创建player对象
    self.player = [AVPlayer playerWithURL:[NSURL fileURLWithPath:moviePath]];
    //3.播放
    [self.player play];
    
    //4.创建和配置AvPlayerlayer
    AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
    playerLayer.bounds = CGRectMake(0, 0, 300, 170);
    playerLayer.position = CGPointMake(210, 200);
    playerLayer.borderColor = [UIColor whiteColor].CGColor;
    playerLayer.borderWidth = 3.0;
    playerLayer.shadowOffset = CGSizeMake(0, 3);
    playerLayer.shadowOpacity = 0.80;
    
    //5.添加透视投影
    self.view.layer.sublayerTransform = CATransform3DMakePerspective(1000);
    [self.view.layer addSublayer:playerLayer];
    
    // Set up slider used to rotate video around Y-axis
    UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(60, 300, 300, 23)];
    slider.minimumValue = -1.0;
    slider.maximumValue = 1.0;
    slider.continuous = NO;
    slider.value = 0.0;
    [slider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventTouchDragInside];
    [self.view addSubview:slider];
    
    // Spin button to spin the video around the X-axis
    UIButton *spinButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    spinButton.frame = CGRectMake(0, 0, 50, 31);
    spinButton.center = CGPointMake(210, 350);
    [spinButton setTitle:@"Spin" forState:UIControlStateNormal];
    [spinButton addTarget:self action:@selector(spinIt) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:spinButton];
}

// Animate spinning video around X-axis
- (void)spinIt {
    CALayer *layer = [self.view.layer sublayers][0];
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"];
    animation.duration = 1.25f;
    animation.toValue = @(DEGREES_TO_RADIANS(360));
    [layer addAnimation:animation forKey:@"spinAnimation"];
}

// Rotate the layer around the Y-axis as slider value is changed
-(void)sliderValueChanged:(UISlider *)sender{
    CALayer *layer = [self.view.layer sublayers][0];
    layer.transform = CATransform3DMakeRotation([sender value], 0, 1, 0);
}

static CATransform3D CATransform3DMakePerspective(CGFloat z) {
    CATransform3D t = CATransform3DIdentity;
    t.m34 = - 1.0 / z;
    return t;
}

- (void)dealloc {
    [self.player pause];
}

2. 实现汽车轨迹移动

可以借鉴实现下啦刷新控件

IMG_6658.GIF

- (void)test{
    
    //1.定义贝塞尔曲线
    UIBezierPath *path = [UIBezierPath bezierPath];
    //起始点
    [path moveToPoint:CGPointMake(20, 200)];
    
    //终点和控制点
    [path addCurveToPoint:CGPointMake(300, 200) controlPoint1:CGPointMake(100, 100) controlPoint2:CGPointMake(200, 300)];
    
    //2.为了显示贝塞尔曲线->shapeLayer(显示路径)
    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = path.CGPath;
    shapeLayer.fillColor = nil;
    shapeLayer.strokeColor = [UIColor redColor].CGColor;
    [self.view.layer addSublayer:shapeLayer];
    
    
    //添加图层
    CALayer *carLayer = [CALayer layer];
    carLayer.frame = CGRectMake(15, 200-18,36,36);
    //寄宿图
    carLayer.contents = (id)[UIImage imageNamed:@"car.png"].CGImage;
    carLayer.anchorPoint = CGPointMake(0.5, 0.8);
    [self.view.layer addSublayer:carLayer];

    
    //关键帧动画
    CAKeyframeAnimation *anim = [CAKeyframeAnimation animation];
    //路径! keypath
    anim.keyPath = @"position";
    //path
    anim.path = path.CGPath;
    anim.duration = 4.0;
    anim.rotationMode = kCAAnimationRotateAuto;
    
    [carLayer addAnimation:anim forKey:nil];

}

小猪摇晃

IMG_6660.GIF

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    CAKeyframeAnimation *anim = [CAKeyframeAnimation animation];
    anim.keyPath = @"transform.rotation";
    anim.values = @[@angleToRadians(-3),
                     @angleToRadians(5),
                     @angleToRadians(-3),
                     ];
    
    anim.autoreverses = YES;
    anim.speed = 2;
    anim.duration = 1;
    anim.repeatCount = MAXFLOAT;
    [_pigView.layer addAnimation:anim forKey:nil];
}

重力 UIGravityBehavior

IMG_6662.GIF

/*
 **使用2D物理引擎分两个步骤:**
 1.添加行为(绑定view)
 2.把行为添加在容器中(绑定view的父view)
 */
@interface ViewController ()

@property(nonatomic,strong)UIDynamicAnimator * animator;
@property(nonatomic,strong)UIDynamicAnimator * animator2;
@property(nonatomic,strong)UIAttachmentBehavior * attachmentBehavior;

@property(nonatomic,strong)UIImageView * redView;
@property(nonatomic,strong)UIImageView * greenView;
@property(nonatomic,strong)UIImageView * yellowView;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    //UI实现
    self.view.backgroundColor = [UIColor whiteColor];
   
    //红色View
    _redView =[[UIImageView alloc]initWithFrame:CGRectMake(100, 200, 50, 50)];
    _redView.image = [UIImage imageNamed:@"ball.png"];
    _redView.userInteractionEnabled = YES;
    _redView.backgroundColor =[UIColor redColor];
    _redView.layer.masksToBounds = YES;
    _redView.layer.cornerRadius = 25;
    [self.view addSubview:_redView];
    
    //绿色View
    _greenView =[[UIImageView alloc]initWithFrame:CGRectMake(100, 400, 50, 50)];
    _greenView.backgroundColor =[UIColor greenColor];
    _greenView.image = [UIImage imageNamed:@"ball2.png"];
    _greenView.userInteractionEnabled = YES;
    _greenView.layer.masksToBounds = YES;
    _greenView.layer.cornerRadius = 25;
    [self.view addSubview:_greenView];
    
    //黄色View
    _yellowView =[[UIImageView alloc]initWithFrame:CGRectMake(200, 500, 50, 50)];
    _yellowView.backgroundColor =[UIColor yellowColor];
    _yellowView.image = [UIImage imageNamed:@"ball3.png"];
    _yellowView.userInteractionEnabled = YES;
    _yellowView.layer.masksToBounds = YES;
    _yellowView.layer.cornerRadius = 25;
    [self.view addSubview:_yellowView];
    
    //物理引擎
     [self animator];
    _animator2 = [[UIDynamicAnimator alloc]initWithReferenceView:self.view];
    
    
    //创建自由落体行为-重力
    UIGravityBehavior *gravity = [[UIGravityBehavior alloc]initWithItems:@[_redView,_yellowView,_greenView]];
    //重力行为有一个属性是重力加速度,设置越大速度增长越快。默认是1
    gravity.magnitude = 2;
    //添加到容器
    [_animator addBehavior:gravity];
    
    //碰撞行为
     UICollisionBehavior *collision =[[UICollisionBehavior alloc]initWithItems:@[_redView,_yellowView,_greenView]];
    //设置边缘(父View的bounds)
    collision.translatesReferenceBoundsIntoBoundary = YES;
    
    
    //可以利用贝塞尔曲线限制边界
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:
                          CGRectMake(0,150, self.view.frame.size.width, self.view.frame.size.width)];
    CAShapeLayer * shapeLayer =[CAShapeLayer layer];
    shapeLayer.path =path.CGPath;
    //画笔颜色
    shapeLayer.strokeColor =[UIColor redColor].CGColor;
    shapeLayer.lineWidth = 5;
    //填充颜色
    shapeLayer.fillColor = nil;
    [self.view.layer addSublayer:shapeLayer];
    [collision addBoundaryWithIdentifier:@"circle" forPath:path];
    [_animator addBehavior:collision];
    
    
    //模拟捕捉行为
    //捕捉行为需要在创建时就给与一个点
    //捕捉行为有一个防震系数属性,设置的越大,振幅就越小
    CGPoint point = CGPointMake(10, 400);
    UISnapBehavior *snap = [[UISnapBehavior alloc] initWithItem:_greenView snapToPoint:point];
    snap.damping = 1;
    [_animator addBehavior:snap];
    
    
    //其他行为的拓展
    UIDynamicItemBehavior *itemBehavior =[[UIDynamicItemBehavior alloc]initWithItems:@[_redView]];
    /*
     elasticity 弹性系数
     friction   摩擦系数
     density    密度
     resistance 抵抗性
     angularResistance 角度阻力
     charge     冲击
     anchored   锚定
     allowsRotation 允许旋转
     */
    itemBehavior.elasticity =.6;//弹性系数
    [_animator addBehavior:itemBehavior];
    
    //添加手势
    UIPanGestureRecognizer *pan =[[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panAuction:)];
    [_redView addGestureRecognizer:pan];
   
}


-(void)panAuction:(UIPanGestureRecognizer *)ges{
    
    if (ges.state == UIGestureRecognizerStateBegan) {
        
        UIOffset offset = UIOffsetMake(-10, -10);
        /*
         offsetFromCenter:偏离中心幅度
         attachedToAnchor:附加到锚点 手势点击的位置
         */
        //UIAttachmentBehavior 附着行为
        _attachmentBehavior =[[UIAttachmentBehavior alloc]initWithItem:_redView offsetFromCenter:offset attachedToAnchor:[ges locationInView:self.view]];
        
        [_animator addBehavior:_attachmentBehavior];
        
    }else if (ges.state == UIGestureRecognizerStateChanged){
        //设置锚点
        [_attachmentBehavior setAnchorPoint:[ges locationInView:self.view]];
        
    }else if (ges.state ==UIGestureRecognizerStateEnded || ges.state == UIGestureRecognizerStateFailed || ges.state == UIGestureRecognizerStateCancelled){
        
        [_animator removeBehavior:_attachmentBehavior];
    }
}



- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 1.获得手指对应的触摸对象
    UITouch *touch = [touches anyObject];
    
    // 2.获得触摸点
    CGPoint point = [touch locationInView:self.view];
    
    // 3.创建捕捉行为
    UISnapBehavior *snap = [[UISnapBehavior alloc] initWithItem:_yellowView snapToPoint:point];
    
    // 防震系数,damping越大,振幅越小
    snap.damping = 1;
    
    // 4.清空之前的并再次开始
    [_animator2 removeAllBehaviors];
    [_animator2 addBehavior:snap];
    
}

//懒加载
- (UIDynamicAnimator *)animator
{
    if (!_animator) {
        // 创建一个物理仿真器
        //容器(里面放一些行为)
        /*
         ReferenceView:关联的view
         */
        _animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
    }
    return _animator;
}