【转载】iOS中的物理引擎
目前知名的2D物理引擎有 Box2d,和Chipmunk,这些是跨平台的。但苹果本身也封装了一个物理引擎, UIDynamic是从iOS 7开始引入的一种新技术,隶属于UIKit框架。这可以让开发人员可以在远离物理学公式的情况下,实现炫酷的物理仿真效果。在游戏开发中会经常用到。本文主要是玩一些较浅的功能,就不说那些游戏中框架中的高级用法了。毕竟我也入门这个没多久啊只会些简单点的,可以用在普通应用界面中偶尔炫酷一下足矣。
如果你不是在董铂然博客园看到本文,请点击查看原文
主要的步骤就三步
1.创建一个物理仿真器。设置仿真范围
2.创建相应的物理仿真行为,添加物理仿真元素
3.将物理仿真行为添加到仿真器中开始仿真。
懒加载方法创建 物理仿真器
1
2
3
4
5
6
7
8
|
- (UIDynamicAnimator *)animator { if (!_animator) { // 创建一个物理仿真器 _animator = [[UIDynamicAnimator alloc] initWithReferenceView: self .view]; } return _animator; } |
模拟重力行为 UIGravityBehavior
重力行为有一个属性是重力加速度,设置越大速度增长越快。默认是1
1 | gravity.magnitude = 100; |
添加元素,告诉仿真器哪些元素可以重力行为
1 | [gravity addItem: self .sxView]; |
简单演示:
1
2
3
4
5
6
7
8
|
// 创建重力行为 UIGravityBehavior *gravity = [[UIGravityBehavior alloc] init]; // magnitude越大,速度增长越快 gravity.magnitude = 100; [gravity addItem: self .sxView]; // 添加到仿真器中开始仿真 [ self .animator addBehavior:gravity]; |
可以看到只是从图中掉下,(注意这不是匀速动画,他是模拟物体以重力加速度落下的)
模拟碰撞行为 UICollisionBehavior
碰撞行为需要先添加元素,告诉物理仿真器哪些元素允许碰撞。如
[collision addItem: self .sxView]; |
其次是设置碰撞的边界,有个参数默认是以屏幕为边界。
collision.translatesReferenceBoundsIntoBoundary = YES ; |
把碰撞行为和重力行为结合演示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
// 1.创建重力行为 UIGravityBehavior *gravity = [[UIGravityBehavior alloc] init]; // magnitude越大,速度增长越快 gravity.magnitude = 2; [gravity addItem: self .sxView]; // 2.创建碰撞行为 UICollisionBehavior *collision = [[UICollisionBehavior alloc] init]; [collision addItem: self .sxView]; [collision addItem: self .bigBlock]; [collision addItem: self .smallBlock]; // 设置碰撞的边界 collision.translatesReferenceBoundsIntoBoundary = YES ; // 3.开始仿真 [ self .animator addBehavior:gravity]; [ self .animator addBehavior:collision]; |
(图中之所以那两个控件会往上飘,是因为他们虽然都添加了碰撞行为,但是没有添加重力行为)
如果觉得屏幕作为边界不好,可以自己设置一条边可以是普通的边
1
2
3
|
[collision addBoundaryWithIdentifier:@ "line2" fromPoint: CGPointMake( self .view.frame.size.width, 0) toPoint: CGPointMake( self .view.frame.size.width, 400)]; |
也可以是个贝塞尔路径。(注意这里的路径是不会显示的,想要能看见得在view中画一个和你设置的边界一样的图形)
1
2
3
|
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(0,150, self .view.frame.size.width, self .view.frame.size.width)]; [collision addBoundaryWithIdentifier:@ "circle" forPath:path]; |
效果如图
模拟捕捉行为 UISnapBehavior
捕捉行为需要在创建时就给与一个点。
1 | UISnapBehavior *snap = [[UISnapBehavior alloc] initWithItem: self .sxView snapToPoint:point]; |
捕捉行为有一个防震系数属性,设置的越大,振幅就越小
1 | snap.damping = 1; |
因为默认只能移动一次,如果想多次移动,就在模拟仿真前清空之前的仿真器
1 | [ self .animator removeAllBehaviors]; |
结合演示,鼠标点哪,移动到哪
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
- ( 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: self .sxView snapToPoint:point]; // 防震系数,damping越大,振幅越小 snap.damping = 1; // 4.清空之前的并再次开始 [ self .animator removeAllBehaviors]; [ self .animator addBehavior:snap]; } |
还有一些在此就不一一演示了 头文件都很简单能看懂的。
比如重力还可以设置重力方向,碰撞还能监听整个碰撞过程,附着动画类似于iOS8的iMessage短信聊天界面(上下拖动)等等,有兴趣的可以自行研究,偶尔在应用中做个“撒红包”“砸金蛋” 等动画啥的可以用这些方法。
欢迎关注。