zoukankan      html  css  js  c++  java
  • UIDynamic(物理仿真)

    简介

    1. 什么是UIDynamic
      • UIDynamic是从iOS 7开始引入的一种新技术,隶属于UIKit框架
      • 可以认为是一种物理引擎,能模拟和仿真现实生活中的物理现象
      • 如: 重力、弹性碰撞等现象
    2. 物理引擎的价值
      • 广泛用于游戏开发,经典成功案例是“愤怒的小鸟”
      • 让开发人员可以在远离物理学公式的情况下,实现炫酷的物理仿真效果
      • 提高了游戏开发效率,产生更多优秀好玩的物理仿真游戏
    3. 知名的2D物理引擎
      • Box2d
      • Chipmunk

    三大概念

    1. 三大概念

      1. 物理仿真元素(Dynamic Item)
        • 谁要进行物理仿真?
      2. 物理仿真行为(Dynamic Behavior) 
        • 执行怎样的物理仿真效果?怎样的动画效果
      3. 物理仿真器(Dynamic Animator) 
        • 让物理仿真元素执行具体的物理仿真行为
    2. 物理仿真元素

      1. 注意
        1. 不是任何对象都能做物理仿真元素
        2. 不是任何对象都能进行物理仿真
          1. 哪些对象才能做物理仿真元素
        3. 任何遵守了UIDynamicItem协议的对象
        4. UIView默认已经遵守了UIDynamicItem协议,因此任何UI控件都能做物理仿真
        5. UICollectionViewLayoutAttributes类默认也遵守UIDynamicItem协议
    3. 物理仿真行为

      1. UIDynamic提供了以下几种物理仿真行为
         UIGravityBehavior:重力行为
         UICollisionBehavior:碰撞行为
         UISnapBehavior:捕捉行为
         UIPushBehavior:推动行为
         UIAttachmentBehavior:附着行为
         UIDynamicItemBehavior:动力元素行为
        
      2. 物理仿真行为须知
        1. 上述所有物理仿真行为都继承自UIDynamicBehavior
        2. 所有的UIDynamicBehavior都可以独立进行
        3. 组合使用多种行为时,可以实现一些比较复杂的效果
    4. 物理仿真器

      1. 物理仿真器须知

        • 它可以让物理仿真元素执行物理仿真行为
        • 它是UIDynamicAnimator类型的对象
      2. UIDynamicAnimator的初始化

        • - (instancetype)initWithReferenceView:(UIView )view;
        • view参数:是一个参照视图,表示物理仿真的范围
      3. UIDynamicAnimator的常见方法

             - (void)addBehavior:(UIDynamicBehavior *)behavior;
             添加1个物理仿真行为
        
             - (void)removeBehavior:(UIDynamicBehavior *)behavior;
             移除1个物理仿真行为
        
             - (void)removeAllBehaviors;
             移除之前添加过的所有物理仿真行为
        
      4. UIDynamicAnimator的常见属性

             @property (nonatomic, readonly) UIView* referenceView;
             参照视图
        
             @property (nonatomic, readonly, copy) NSArray* behaviors;
             添加到物理仿真器中的所有物理仿真行为
        
             @property (nonatomic, readonly, getter = isRunning) BOOL running;
             是否正在进行物理仿真
        
             @property (nonatomic, assign) id <UIDynamicAnimatorDelegate> delegate;
             代理对象(能监听物理仿真器的仿真过程,比如开始和结束)
      5. 使用步骤

        1. 创建一个物理仿真器(顺便设置仿真范围)

        2. 创建相应的物理仿真行为(顺便添加物理仿真元素)

        3. 将物理仿真行为添加到物理仿真器中 -> 开始仿真

         

        Demo

        1. 环境准备
          1. 创建项目
          2. 设置不使用autolayout(这里仅仅是为了简单,物理仿真支持autolayout,在愤怒的小鸟中演示)
          3. 设置屏幕的尺寸为5.5 因为Xcode7 默认使用是iPhone6 s Plus
          4. 拖入一个View,颜色设置蓝色,大小设置为100,100
          5. 连线到控制器中,属性为blueView
        2. 让蓝色View执行仿真重力仿真行为,代码如下:

              - (void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
              {
                  //  创建一个物理仿真器,并指定参照系为控制器的View
                      UIDynamicAnimator *dynamicAnimator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
                  //  创建重力仿真行为并指定仿真元素为蓝色的view
                      UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.blueView]];
                  //  把仿真行为添加到仿真器中
                      [dynamicAnimator addBehavior:gravity];
              }
          

          点击控制器的View,没有任何反应,这是因为还要没有执行动画物理仿真器就销毁,所以我们需要对物理仿真器有一个强引用 懒加载物理仿真器

          1. 定义物理仿真器属性

                 @property (nonatomic, strong) UIDynamicAnimator *dynamicAnimator;
            
          2. 懒加载物理仿真器器

                 - (UIDynamicAnimator *)dynamicAnimator
                 {
                     if (_dynamicAnimator == nil) {
                         //  创建一个物理仿真器,并指定参照系为控制器的View
                         _dynamicAnimator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
                     }
                     return _dynamicAnimator;
                 }
            
            1. 修改touchesBegan方法

               - (void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
              {
              //  创建重力仿真行为并指定仿真元素为蓝色的view
                UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.blueView]];
              //  把仿真行为添加到仿真器中
                [self.dynamicAnimator addBehavior:gravity];
              }
              
            2. 运行,点击控制器View,蓝色View向下运动,然后从下面出去了
        3. 如果想让blueView到底部停止还需要添加一个碰撞行为

                  - (void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
                   {
                   //  创建重力仿真行为并指定仿真元素为blueView
                       UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.blueView]];
          
                   //  创建一个碰撞的仿真行为并指定仿真元素为blueView
                       UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.blueView]];
                   //  设置仿真边界为碰撞边界
                       collision.translatesReferenceBoundsIntoBoundary = YES;
                   //  添加碰撞行为到仿真器中
                       [self.dynamicAnimator addBehavior:collision];
          
                   //  把仿真行为添加到仿真器中
                       [self.dynamicAnimator addBehavior:gravity];
                   }
          
        4. 在storyboard上添加一个添加一个红色View,在蓝色的View下方,运行程序蓝色的View会从红色的View上方飘过,这是因为此时红色的View并没有添加到仿真器中,如果你希望蓝色的View撞到红色的View那么就需要把红色的View添加到碰撞的仿真行为中 1.红色View的拖线到控制器中,属性名称为redView 2.把红色View添加到碰撞仿真行为中

               UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.blueView,self.redView]];
          
          1. 运行程序,点击屏幕,红色的View被推下去了;把红色的View放到蓝色View能砸到其角上的一个位置,测试,会有惊喜发现哦!
        5. 添加碰撞边界

          1. 添加直线边界

                 - (void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
                 {
                 //  创建重力仿真行为并指定仿真元素为blueView
                     UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.blueView]];
            
                 //  创建一个碰撞的仿真行为并指定仿真元素为blueView
                     UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.blueView]];
                 //  设置仿真边界为碰撞边界
                     collision.translatesReferenceBoundsIntoBoundary = YES;
            
                 //  添加直线碰撞边界
                     [collision addBoundaryWithIdentifier:@"line" fromPoint:CGPointMake(0, self.view.frame.size.height * 0.5) toPoint:CGPointMake(self.view.frame.size.width, self.view.frame.size.height)];
            
                 //  添加碰撞行为到仿真器中
                     [self.dynamicAnimator addBehavior:collision];
            
                 //  把仿真行为添加到仿真器中
                     [self.dynamicAnimator addBehavior:gravity];
                 }
            
          2. 添加一个贝塞尔曲线碰撞边界,把添加直线碰撞边界的代码修改如下代码

                 //  添加贝塞尔曲线碰撞边界
                 UIBezierPath *bezierPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.width)];
                 [collision addBoundaryWithIdentifier:@"bezier" forPath:bezierPath];
            
        6. 重力行为的常见属性

           ////  设置重力的角度,默认为M_PI_2(向下),0为右,M_PI向左
           //    gravity.angle = 0;
           ////  设置重力的大小,默认是1
           //    gravity.magnitude = 2;
          
           //  设置重力向量,(0,0) -> (1,1) 之间的连线,大小为:根号2
               gravity.gravityDirection = CGVectorMake(1, 1);
          
        7. 捕获行为

            //  相同类型仿真行为只能添加到仿真器一次,所以在添加仿真行为之前,移除之前添加仿真行为
               [self.dynamicAnimator removeAllBehaviors];
          
           //  获取描述用户点击的对象
               UITouch *touch = [touches anyObject];
           //  获取用户点击的位置
               CGPoint loc =  [touch locationInView:self.view];
           //  创建一个捕获行为
               UISnapBehavior *snap = [[UISnapBehavior alloc] initWithItem:self.blueView snapToPoint:loc];
          
           //  设置减震效果,取值范围为 0.0 to 1.0. 0表示最小减震效果,也就是振幅最大
               snap.damping = 0;
          
           //  把捕获行为添加到仿真器中
               [self.dynamicAnimator addBehavior:snap];
        8. Demo2  愤怒的小鸟

            1. 视图
  • 相关阅读:
    poj 1088 滑雪
    位运算与bitset
    hdu 4607 Park Visit
    树的直径
    codeforces 495D Sonya and Matrix
    German Collegiate Programming Contest 2015(第三场)
    BAPC 2014 Preliminary(第一场)
    Benelux Algorithm Programming Contest 2014 Final(第二场)
    E. Reachability from the Capital(tarjan+dfs)
    poj2104 K-th Number(划分树)
  • 原文地址:https://www.cnblogs.com/YRFios/p/4963221.html
Copyright © 2011-2022 走看看