iOS动画中的物理知识应用之愤怒的小鸟-碰撞检测

碰撞检测


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


我相信搞iOS得人,多多少少都知道 弹球这个小游戏。撞击不同的点,就能改变其运动的轨迹。对于很多人来说,如果不知道思路可能觉得小球在屏幕中撞来撞去,碰到墙壁就改变运动方向似乎很难实现。
其实这个只需要一点点iOS绘图基础和动画基础,还要一点点物理知识就OK了。
这里写图片描述

1.速度和位移都是矢量

在2D坐标系中,速度和位移都能分解成在x轴和y轴上的分量
这里写图片描述
所以可以根据速度在Vx 和 Vy来描述物体的运动情况。界面每次刷新单位时间,利用物体速度分量Vx与Vy的值来计算下次物体出现的位置:

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

2.碰撞的速度模型

这里写图片描述
假设物体撞到屏幕的底边,这时候物体在X轴上的方向不变,y轴方向上速度取反,同理撞到屏幕顶边也是。
物理模型:

  • Vx = Vx
  • Vy = - Vy

同理,如果物体撞到左边或者右边:

  • Vx = - Vx
  • Vy = Vy

3.代码实现

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

这里写图片描述

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.结果展示

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值