iOS 簡單的操作桿旋轉(zhuǎn)實現(xiàn)示例詳解
一、效果實現(xiàn)
簡單實現(xiàn)了一個消滅病毒的小效果,畫面略顯粗糙,多多見諒

控制球復(fù)位

二、操作桿實現(xiàn)
實現(xiàn)拖動小球,獲取當(dāng)前小球的旋轉(zhuǎn)方向,將旋轉(zhuǎn)的方向傳遞出去,旋轉(zhuǎn)“坦克”進行攻擊“病毒”。
#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;
}
}
//小球復(fù)位
- (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;
}];
}
//根據(jù)控制球位置獲取當(dāng)前旋轉(zhuǎn)角度
- (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形式向外界暴露當(dāng)前控制球相對于屏幕上方的角度
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
三、發(fā)射子彈及碰撞檢測
1、發(fā)射子彈
//根據(jù)當(dāng)前角度,預(yù)判子彈動畫的結(jié)束位置
- (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 本身是一個定時器事件,在里面添加一些創(chuàng)建子彈的邏輯,位置移動還是用了最簡單的 UIView 的 animateWithDuration 方法,但是注意這里面通過 frame 進行碰撞檢測是獲取不到,所以,添加了 CADisplayLink 屏幕刷新事件來檢測子彈視圖的 layer.presentationLayer.frame來進行與病毒的 frame 進行檢測屏幕位置是否包含。
2、檢測碰撞
bool CGRectIntersectsRect(CGRect rect1, CGRect rect2) 檢測碰撞的方法
//添加屏幕刷新事件監(jiān)聽
- (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、隨機創(chuàng)建病毒
- (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;//縮放倍數(shù)
emitter.emitterCells = @[cell];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[emitter removeFromSuperlayer];
});
}
五、思考與總結(jié)
添加 UIView 的 animateWithDuration 方法后,這里用的是屏幕刷新檢測,來獲取當(dāng)前控件的 layer.presentationLayer.frame 來檢測碰撞,其他邏輯都相對簡單。
以上就是iOS 簡單的操作桿旋轉(zhuǎn)實現(xiàn)示例詳解的詳細內(nèi)容,更多關(guān)于iOS 操作桿旋轉(zhuǎn)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
iOS 開發(fā)中 NavigationController經(jīng)常出現(xiàn)的問題原因分析
這篇文章主要介紹了iOS 開發(fā)中 NavigationController經(jīng)常出現(xiàn)的問題原因分析的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-09-09
在iOS開發(fā)的Quartz2D使用中實現(xiàn)圖片剪切和截屏功能
這篇文章主要介紹了在iOS開發(fā)的Quartz2D使用中實現(xiàn)圖片剪切和截屏功能的方法,代碼基于傳統(tǒng)的Objective-C,需要的朋友可以參考下2015-12-12

