一、效果实现
简单实现了一个消灭病毒的小效果,画面略显粗糙,多多见谅
控制球复位
二、操作杆实现
实现拖动小球,获取当前小球的旋转方向,将旋转的方向传递出去,旋转“坦克”进行攻击“病毒”。
#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 本身是一个定时器事件,在里面添加一些创建子弹的逻辑,位置移动还是用了最简单的 uiview 的 animatewithduration 方法,但是注意这里面通过 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]; }); }
五、思考与总结
添加 uiview 的 animatewithduration 方法后,这里用的是屏幕刷新检测,来获取当前控件的 layer.presentationlayer.frame 来检测碰撞,其他逻辑都相对简单。
以上就是ios 简单的操作杆旋转实现示例详解的详细内容,更多关于ios 操作杆旋转的资料请关注代码网其它相关文章!
发表评论