设为首页 加入收藏

TOP

物理模拟(基于定时器的动画 11.2)(一)
2017-10-11 13:57:33 】 浏览:2580
Tags:物理 模拟 基于 定时器 动画 11.2

物理模拟

即使使用了基于定时器的动画来复制第10章中关键帧的行为,但还是会有一些本质上的区别:在关键帧的实现中,我们提前计算了所有帧,但是在新的解决方案中,我们实际上实在按需要在计算。意义在于我们可以根据用户输入实时修改动画的逻辑,或者和别的实时动画系统例如物理引擎进行整合。

Chipmunk

我们来基于物理学创建一个真实的重力模拟效果来取代当前基于缓冲的弹性动画,但即使模拟2D的物理效果就已近极其复杂了,所以就不要尝试去实现它了,直接用开源的物理引擎库好了。

我们将要使用的物理引擎叫做Chipmunk。另外的2D物理引擎也同样可以(例如Box2D),但是Chipmunk使用纯C写的,而不是C++,好处在于更容易和Objective-C项目整合。Chipmunk有很多版本,包括一个和Objective-C绑定的“indie”版本。C语言的版本是免费的,所以我们就用它好了。在本书写作的时候6.1.4是最新的版本;你可以从http://chipmunk-physics.net下载它。

Chipmunk完整的物理引擎相当巨大复杂,但是我们只会使用如下几个类:

  • cpSpace - 这是所有的物理结构体的容器。它有一个大小和一个可选的重力矢量
  • cpBody - 它是一个固态无弹力的刚体。它有一个坐标,以及其他物理属性,例如质量,运动和摩擦系数等等。
  • cpShape - 它是一个抽象的几何形状,用来检测碰撞。可以给结构体添加一个多边形,而且cpShape有各种子类来代表不同形状的类型。

在例子中,我们来对一个木箱建模,然后在重力的影响下下落。我们来创建一个Crate类,包含屏幕上的可视效果(一个UIImageView)和一个物理模型(一个cpBody和一个cpPolyShape,一个cpShape的多边形子类来代表矩形木箱)。

用C版本的Chipmunk会带来一些挑战,因为它现在并不支持Objective-C的引用计数模型,所以我们需要准确的创建和释放对象。为了简化,我们把cpShapecpBody的生命周期和Crate类进行绑定,然后在木箱的-init方法中创建,在-dealloc中释放。木箱物理属性的配置很复杂,所以阅读了Chipmunk文档会很有意义。

视图控制器用来管理cpSpace,还有和之前一样的计时器逻辑。在每一步中,我们更新cpSpace(用来进行物理计算和所有结构体的重新摆放)然后迭代对象,然后再更新我们的木箱视图的位置来匹配木箱的模型(在这里,实际上只有一个结构体,但是之后我们将要添加更多)。

Chipmunk使用了一个和UIKit颠倒的坐标系(Y轴向上为正方向)。为了使得物理模型和视图之间的同步更简单,我们需要通过使用geometryFlipped属性翻转容器视图的集合坐标(第3章中有提到),于是模型和视图都共享一个相同的坐标系。

具体的代码见清单11.3。注意到我们并没有在任何地方释放cpSpace对象。在这个例子中,内存空间将会在整个app的生命周期中一直存在,所以这没有问题。但是在现实世界的场景中,我们需要像创建木箱结构体和形状一样去管理我们的空间,封装在标准的Cocoa对象中,然后来管理Chipmunk对象的生命周期。图11.1展示了掉落的木箱。

清单11.3 使用物理学来对掉落的木箱建模

  1 #import "ViewController.h" 
  2 #import 
  3 #import "chipmunk.h"
  4 
  5 @interface Crate : UIImageView
  6 
  7 @property (nonatomic, assign) cpBody *body;
  8 @property (nonatomic, assign) cpShape *shape;
  9 
 10 @end
 11 
 12 @implementation Crate
 13 
 14 #define MASS 100
 15 
 16 - (id)initWithFrame:(CGRect)frame
 17 {
 18     if ((self = [super initWithFrame:frame])) {
 19         //set image
 20         self.image = [UIImage imageNamed:@"Crate.png"];
 21         self.contentMode = UIViewContentModeScaleAspectFill;
 22         //create the body
 23         self.body = cpBodyNew(MASS, cpMomentForBox(MASS, frame.size.width, frame.size.height));
 24         //create the shape
 25         cpVect corners[] = {
 26             cpv(0, 0),
 27             cpv(0, frame.size.height),
 28             cpv(frame.size.width, frame.size.height),
 29             cpv(frame.size.width, 0),
 30         };
 31         self.shape = cpPolyShapeNew(self.body, 4, corners, cpv(-frame.size.width/2, -frame.size.height/2));
 32         //set shape friction & elasticity
 33         cpShapeSetFriction(self.shape, 0.5);
 34         cpShapeSetElasticity(self.shape, 0.8);
 35         //link the crate to the shape
 36         //so we can refer to crate from callback later on
 37         self.shape->data = (__bridge void *)self;
 38         //set the body position to match view
 39         cpBodySetPos(self.body, cpv(frame.origin.x + frame.size.width/2, 300 - frame.origin.y - frame.size.height/2));
 40     }
 41     return self;
 42 }
 43 
 44 - (void)dealloc
 45 {
 46     //release shape and body
 47     cpShapeFree(_shape);
 48     cpBodyFree(_body);
 49 }
 50 
 51 @end
 52 
 53 @interface ViewController ()
 54 
 55 @property (nonatomic, weak) IBOutlet UIView *containerView;
 56 @property (nonatomic, assign) cpSpace *space;
 57 @property (nonatomic, strong) CADisplayLink *timer;
 58 @property (nonatomic, assign) CFTimeInterval lastStep;
 59 
 60 @end
 61 
 62 @implementation ViewController
 63 
 64 #define GRAV
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇动画速度(缓冲 10.1) 下一篇安装及使用cocos2d-x

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目