欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

iOS简单的操作杆旋转实现示例详解,

来源: 开发者 投稿于  被查看 21324 次 评论:43

iOS简单的操作杆旋转实现示例详解,


目录
  • 一、效果实现
  • 二、操作杆实现
  • 三、发射子弹及碰撞检测
    • 1、发射子弹
    • 2、检测碰撞
  • 四、添加病毒及消灭动画
    • 1、随机创建病毒
    • 2、消灭动画
  • 五、思考与总结

    一、效果实现

    简单实现了一个消灭病毒的小效果,画面略显粗糙,多多见谅

    控制球复位

    二、操作杆实现

    实现拖动小球,获取当前小球的旋转方向,将旋转的方向传递出去,旋转“坦克”进行攻击“病毒”。

    #import "DirectionOptionView.h"
    @interface DirectionOptionView()
    //方向指示器滚珠
    @property(nonatomic,strong) UIView * ball;
    @end
    @implementation DirectionOptionView
    - (instancetype)initWithFrame:(CGRect)frame changeDirectionBlock:(ChangeDirectionBlock)changeDirectionBlock
    {
        if (self = [super initWithFrame:frame]) {
            self.changeDirectionBlock = changeDirectionBlock;
            [self makeView];
            [self addPan];
        }
        return self;
    }
    //添加拖拽手势
    - (void)addPan{
        UIPanGestureRecognizer * pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action: @selector(panAction:)];
        [self addGestureRecognizer:pan];
    }
    - (void)panAction:(UIPanGestureRecognizer *)pan
    {
        switch (pan.state) {
            case UIGestureRecognizerStateBegan:
            {
                CGPoint point = [pan locationInView:**self**];
                self.ball.alpha = 1;
                [self moveWithPoint:point];
            }
                break;
            case UIGestureRecognizerStateChanged:
            {
                CGPoint point = [pan locationInView:self];
                [self moveWithPoint:point];
            }
                break;
            case UIGestureRecognizerStateEnded:
            {
                CGPoint point = [pan locationInView:self];
                [self resetBallPositionWithEndPoint:point];
            }
                break;
            default:
                break;
        }
    }
    //小球复位
    - (void)resetBallPositionWithEndPoint:(CGPoint)point
    {
        self.changeDirectionBlock(0);
        [UIView animateWithDuration:0.2 animations:^{
            self.ball.center = CGPointMake((self.frame.size.width / 2.0), (self.frame.size.height / 2.0));
            self.ball.alpha = 0.4;
        }];
    }
    //根据控制球位置获取当前旋转角度
    - (void)moveWithPoint:(CGPoint)point
    {
        CGFloat distanceCircle = (self.ball.frame.size.width / 2.0);
        CGFloat x = point.x;
        CGFloat y = point.y;
        CGFloat dx = x - self.frame.size.width / 2.0;
        CGFloat dy = y - self.frame.size.height / 2.0;
        CGFloat rotation = atan2(dx,dy);
        CGFloat r = self.frame.size.width / 2.0;
        CGFloat rx = (r - distanceCircle) * sin(rotation) + r;
        CGFloat ry = (r - distanceCircle) * cos(rotation) + r;
        //防止控制球越界
        if ((sqrt((dx * dx) + (dy * dy))) > (r - distanceCircle)) {
            x = rx;
            y = ry;
        }
        //用block形式向外界暴露当前控制球相对于屏幕上方的角度
        self.changeDirectionBlock(-rotation + M_PI);
        self.ball.center = CGPointMake(x, y);
    }
    - (void)makeView{
        //进行倒角
        self.layer.masksToBounds = YES;
        self.layer.cornerRadius = self.frame.size.width / 2.0;
        self.backgroundColor = [[UIColor groupTableViewBackgroundColor] colorWithAlphaComponent:0.7];
        //添加控制球
        [self addSubview:self.ball];
    }
    //控制球
    - (UIView *)ball
    {
        if (!_ball) {
            CGSize size = CGSizeMake(45, 45);
            _ball = [[UIView alloc] initWithFrame:CGRectMake((self.frame.size.width - size.width) / 2.0, (self.frame.size.height - size.height) / 2.0, size.width, size.height)];
            _ball.alpha = 0.4;
            _ball.layer.masksToBounds = YES;
            _ball.layer.cornerRadius = _ball.frame.size.width / 2.0;
            _ball.backgroundColor = [UIColor lightGrayColor];
        }
        return _ball;
    }
    @end
    

    三、发射子弹及碰撞检测

    1、发射子弹

    //根据当前角度,预判子弹动画的结束位置
    - (NSArray *)prepareBulletPath
    {
        CGPoint center = self.center;
        CGFloat maxLength = sqrt(([UIScreen mainScreen].bounds.size.width * [UIScreen mainScreen].bounds.size.width) + ([UIScreen mainScreen].bounds.size.height * [UIScreen mainScreen].bounds.size.height));
        CGFloat endY = sin(self.angle - M_PI / 2.0) * maxLength + center.y;
        CGFloat endX = cos(self.angle - M_PI / 2.0) * maxLength + center.x;
        CGPoint endPoint = CGPointMake(endX, endY);
        return @[@(center),@(endPoint)];
    }
    - (void)fir
    {
        CGFloat bulletWidth = 10;
        BulletView * lastBulletView = self.bulletArr.count > 0 ? self.bulletArr.lastObject : nil;
        if (!lastBulletView) {
            BulletView * view = [[BulletView alloc] initWithFrame:CGRectMake((self.frame.size.width - bulletWidth) / 2.0, 0,bulletWidth,bulletWidth)];
            view.points = [self prepareBulletPath];
            [self.superview insertSubview:view belowSubview:self];
            [self.bulletArr addObject:view];
            view.center = [view.points[0] CGPointValue];
            [UIView animateWithDuration:1 animations:^{
                view.center = [view.points[1] CGPointValue];
            } completion:^(BOOL finished) {
                [view removeFromSuperview];
                [self.bulletArr removeObject:view];
            }];
        }
    }
    

    fir 本身是一个定时器事件,在里面添加一些创建子弹的逻辑,位置移动还是用了最简单的 UIViewanimateWithDuration 方法,但是注意这里面通过 frame 进行碰撞检测是获取不到,所以,添加了 CADisplayLink 屏幕刷新事件来检测子弹视图的 layer.presentationLayer.frame来进行与病毒的 frame 进行检测屏幕位置是否包含。

    2、检测碰撞

    bool CGRectIntersectsRect(CGRect rect1, CGRect rect2) 检测碰撞的方法

    //添加屏幕刷新事件监听
    - (void)addScreenRefreshAction
    {
        self.displayLink = [CADisplayLink displayLinkWithTarget:self selector: @selector(update)];
        [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
    }
    - (void)update
    {
        [self.bulletArr enumerateObjectsUsingBlock:^(BulletView * bulletView, NSUInteger idx, BOOL * _Nonnull stop) {
            [self.virusArr enumerateObjectsUsingBlock:^(VirusView * virusView, NSUInteger idx, BOOL * _Nonnull stop) {
                //检测碰撞
                if (CGRectIntersectsRect(bulletView.layer.presentationLayer.frame, virusView.frame)) {
                    [bulletView removeFromSuperview];
                    [self.bulletArr removeObject:bulletView];
                    [virusView attacked];
                    if ([virusView isDie]) {
                        [virusView removeFromSuperview];
                        [self.virusArr removeObject:virusView];
                    }
                }
            }];
        }];
        if (!self.virusArr.count) {
            [self createVirusView];
        }
    }
    

    四、添加病毒及消灭动画

    1、随机创建病毒

    - (void)createVirusView
    {
        int width = arc4random() % 30 + 50;
        int x = arc4random() % ([[NSNumber numberWithFloat:[UIScreen mainScreen].bounds.size.width] integerValue] - width);
        int y = arc4random() % ([[NSNumber numberWithFloat:[UIScreen mainScreen].bounds.size.height / 2.0] integerValue]);
        VirusView * virusView = [[VirusView alloc] initWithFrame:CGRectMake(x, y, width, width)];
        [self.superview addSubview:virusView];
        [self.virusArr addObject:virusView];
    }
    

    2、消灭动画

    添加了一点粒子效果,显示病毒消散动画

    - (void)fireExplode
    {
        CAEmitterLayer * emitter = [CAEmitterLayer layer];
        emitter.frame = self.frame;
        [self.superview.layer addSublayer:emitter];
        emitter.renderMode = kCAEmitterLayerAdditive;
        emitter.emitterPosition = CGPointMake(emitter.frame.size.width*0.5,    emitter.frame.size.height*0.5);
        CAEmitterCell *cell = [[CAEmitterCell alloc] init];
        cell.contents = ( __bridge id)[UIImage imageNamed:@"v4"].CGImage;
        cell.birthRate = 1;//出生率
        cell.lifetime = 0.7;//生命周期
        cell.emissionLongitude = - M_PI_2;
        cell.emissionRange = M_PI_2;
        cell.alphaSpeed = -0.2;
        cell.velocity = 10;//速度
        cell.scale = 0.15;//缩放倍数
        emitter.emitterCells = @[cell];
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [emitter removeFromSuperlayer];
        });
    }
    

    五、思考与总结

    添加 UIViewanimateWithDuration 方法后,这里用的是屏幕刷新检测,来获取当前控件的 layer.presentationLayer.frame 来检测碰撞,其他逻辑都相对简单。

    以上就是iOS 简单的操作杆旋转实现示例详解的详细内容,更多关于iOS 操作杆旋转的资料请关注3672js教程其它相关文章!

    您可能感兴趣的文章:
    • iOS 断点上传文件的实现方法
    • iOS开发中以application/json上传文件实例详解
    • IOS开发教程之put上传文件的服务器的配置及实例分享
    • iOS内存管理Tagged Pointer使用原理详解
    • iOS 底层alloc init new 源码流程示例分析
    • iOS通过UIDocumentInteractionController实现应用间传文件

    用户评论