碰撞检測


源码:https://github.com/Esdeath/collsion


我相信搞iOS得人。多多少少都知道 弹球这个小游戏。

撞击不同的点,就能改变其运动的轨迹。对于非常多人来说,假设不知道思路可能认为小球在屏幕中撞来撞去,碰到墙壁就改变运动方向似乎非常难实现。

事实上这个仅仅须要一点点iOS画图基础和动画基础,还要一点点物理知识就OK了。

iOS动画中的物理知识应用之愤慨的小鸟-碰撞检測-LMLPHP

1.速度和位移都是矢量

在2D坐标系中,速度和位移都能分解成在x轴和y轴上的分量

iOS动画中的物理知识应用之愤慨的小鸟-碰撞检測-LMLPHP

所以能够依据速度在Vx 和 Vy来描写叙述物体的运动情况。

界面每次刷新单位时间。利用物体速度分量Vx与Vy的值来计算下次物体出现的位置:

  • 下次X轴坐标=Vx + 当前X轴坐标
  • 下次Y轴坐标=Vy + 当前Y轴坐标

2.碰撞的速度模型

iOS动画中的物理知识应用之愤慨的小鸟-碰撞检測-LMLPHP

假设物体撞到屏幕的底边,这时候物体在X轴上的方向不变。y轴方向上速度取反,同理撞到屏幕顶边也是。

物理模型:

  • Vx = Vx
  • Vy = - Vy

同理,假设物体撞到左边或者右边:

  • Vx = - Vx
  • Vy = Vy

3.代码实现

1.新建一个MRView加入到根View上。

iOS动画中的物理知识应用之愤慨的小鸟-碰撞检測-LMLPHP

2.加入CADisplayLink

CADisplayLink是一个能让我们以和屏幕刷新率同样的频率将内容画到屏幕上的定时器。

我们在应用中创建一个新的 CADisplayLink 对象,把它加入到一个runloop中,并给它提供一个 target 和selector 在屏幕刷新的时候调用。

CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(setNeedsDisplay)];
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

3.设置成员属性

//小鸟图片
@property (nonatomic,strong) UIImage *imageBird;
//小鸟的位置
@property (nonatomic,assign) CGFloat birdX;
@property (nonatomic,assign) CGFloat birdY;
//小鸟的速度
@property (nonatomic,assign) CGFloat birdSpeedX;
@property (nonatomic,assign) CGFloat birdSpeedY;

4.初始化

这里要注意,要设置从xib,storyboard,还有代码中初始化都必须引用到。

CADisplayLink中调用setNeedsDisplay用来不停的重绘。

//从xib或者storyboard初始化调用
- (void)awakeFromNib
{
[self setUpBird];
}
//从代码初始化调用这个
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self setUpBird];
} return self;
} -(void)setUpBird
{
self.backgroundColor = [UIColor blackColor]; CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(setNeedsDisplay)];
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; self.imageBird = [UIImage imageNamed:@"QQ20150714-1"];
//设置初始位置
self.birdX = 1;
self.birdY = 1;
//设置初始速度
self.birdSpeedX = 5;
self.birdSpeedY = 5;
}

5.画图

主要是推断好。小鸟碰撞四周的时候速度反向

- (void)drawRect:(CGRect)rect
{
[self.imageBird drawInRect:CGRectMake(self.birdX , self.birdY, IMAGEWIDTH, IMAGEHEIGHT)]; if (self.birdX < 0 || (self.birdX > SCREENWIDTH - IMAGEWIDTH) )
{
self.birdSpeedX = -self.birdSpeedX;
} if (self.birdY < 0 || (self.birdY > SCREENHEIGHT - IMAGEHEIGHT) )
{
self.birdSpeedY = -self.birdSpeedY;
} self.birdX += self.birdSpeedX;
self.birdY += self.birdSpeedY;
}

6.完整的代码

这里MRView是self.view的子控件。

全然覆盖self.view

#import "MRView.h"

#define SCREENHEIGHT   [UIScreen mainScreen].bounds.size.height
#define SCREENWIDTH [UIScreen mainScreen].bounds.size.width #define IMAGEWIDTH 50
#define IMAGEHEIGHT 50 @interface MRView() @property (nonatomic,strong) UIImage *imageBird;
//小鸟的位置
@property (nonatomic,assign) CGFloat birdX;
@property (nonatomic,assign) CGFloat birdY;
//小鸟的速度
@property (nonatomic,assign) CGFloat birdSpeedX;
@property (nonatomic,assign) CGFloat birdSpeedY; @end @implementation MRView
- (void)awakeFromNib
{
[self setUpBird];
} - (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self setUpBird];
} return self;
} -(void)setUpBird
{
self.backgroundColor = [UIColor blackColor]; CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(setNeedsDisplay)];
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; self.imageBird = [UIImage imageNamed:@"QQ20150714-1"];
//设置初始位置
self.birdX = 1;
self.birdY = 1;
//设置初始速度
self.birdSpeedX = 5;
self.birdSpeedY = 5;
} - (void)drawRect:(CGRect)rect
{
[self.imageBird drawInRect:CGRectMake(self.birdX , self.birdY, IMAGEWIDTH, IMAGEHEIGHT)]; if (self.birdX < 0 || (self.birdX > SCREENWIDTH - IMAGEWIDTH) )
{
self.birdSpeedX = -self.birdSpeedX;
} if (self.birdY < 0 || (self.birdY > SCREENHEIGHT - IMAGEHEIGHT) )
{
self.birdSpeedY = -self.birdSpeedY;
} self.birdX += self.birdSpeedX;
self.birdY += self.birdSpeedY;
} @end

7.结果展示

iOS动画中的物理知识应用之愤慨的小鸟-碰撞检測-LMLPHP

iOS动画中的物理知识应用之愤慨的小鸟-碰撞检測-LMLPHP

iOS动画中的物理知识应用之愤慨的小鸟-碰撞检測-LMLPHP

iOS动画中的物理知识应用之愤慨的小鸟-碰撞检測-LMLPHP

iOS动画中的物理知识应用之愤慨的小鸟-碰撞检測-LMLPHP

05-11 20:46