您好,登錄后才能下訂單哦!
前言
最近寫了一款釣魚小游戲,自己平時(shí)也沒做過(guò)游戲,本來(lái)以為這種游戲要用cocos2d什么的實(shí)現(xiàn),后來(lái)發(fā)現(xiàn)其實(shí)動(dòng)畫就可以實(shí)現(xiàn)很棒的效果,先看看效果圖。
思維導(dǎo)圖
首先我們看下思維導(dǎo)圖,本游戲主要分為4大塊,其中魚的實(shí)現(xiàn)最為復(fù)雜
思維導(dǎo)圖
項(xiàng)目結(jié)構(gòu)
準(zhǔn)備工作
首先將需要的圖準(zhǔn)備好,這個(gè)魚其實(shí)就是一組圖片,圖片大小固定,每一幀位置變化,所以看起來(lái) 是一個(gè)上下游動(dòng)的魚。
單張圖片
魚鉤模塊
擺動(dòng)動(dòng)畫
魚鉤的擺動(dòng)范圍是[M_PI/4.0,-M_PI/4.0] (垂直向下為0度,順時(shí)針為正),這里利用了計(jì)時(shí)器進(jìn)行角度的更改,計(jì)時(shí)器用的CADisplayLink,它是一個(gè)和屏幕刷新率一致的定時(shí)器,如果沒有卡頓,每秒刷新次數(shù)是60次,本Demo很多計(jì)時(shí)器用的都是CADisplayLink。下面是魚鉤的主要代碼(重點(diǎn):1、設(shè)置錨點(diǎn)后重置frame,2、更改角度,3、旋轉(zhuǎn))。 其中定義了一個(gè)block將角度angle回傳到FishingView界面計(jì)算魚鉤落到池塘的位置。
@property (nonatomic, strong) CADisplayLink *linkTimer; @property (nonatomic, assign) BOOL isReduce;//改變方向 @property (nonatomic, assign) CGFloat angle;//擺動(dòng)的角度 - (void)initView{ [self setAnchorPoint:CGPointMake(0.5, 0) forView:self]; UIImageView *gouImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, self.frame.size.height - 35 , 30, 35)]; gouImageView.image = [UIImage imageNamed:@"fish_catcher_tong"]; [self addSubview:gouImageView]; UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake((self.frame.size.width - 3)/2.0, 0, 3, self.frame.size.height - 35)]; lineView.backgroundColor = HEXCOLOR(0x9e664a); [self addSubview:lineView]; // 創(chuàng)建一個(gè)對(duì)象計(jì)時(shí)器 _linkTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(hookMove)]; //啟動(dòng)這個(gè)link [_linkTimer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; } //設(shè)置錨點(diǎn)后重新設(shè)置frame - (void) setAnchorPoint:(CGPoint)anchorpoint forView:(UIView *)view{ CGRect oldFrame = view.frame; view.layer.anchorPoint = anchorpoint; view.frame = oldFrame; } #pragma mark - 魚鉤擺動(dòng) - (void)hookMove{ if (self.isReduce){ _angle-=1.8*cos(1.5*_angle)*0.01;//計(jì)算角度,利用cos模擬上升過(guò)程中減慢,下降加快 if (_angle < -M_PI/180*45){ self.isReduce = NO; } }else { _angle+=1.8*cos(1.5*_angle)*0.01; if (_angle > M_PI/180*45){ self.isReduce = YES; } } if (self.angleBlock){ self.angleBlock(_angle); } // DLog(@"魚鉤角度%f",_angle); //旋轉(zhuǎn)動(dòng)畫 self.transform = CGAffineTransformMakeRotation(_angle); }
魚模塊
魚模塊是繼承自UIImageView的一個(gè)類
魚模塊提供了三種初始化方式,可垂釣的魚、不可垂釣的魚(可以不用)、釣到的魚三種魚。
魚的移動(dòng)方式有兩種,使用枚舉定義,從左到右,從右到左
魚的種類有六種,用枚舉進(jìn)行了定義
typedef NS_ENUM(NSInteger, FishModelImageViewType){ FishModelImageViewTypeXHY = 0, //小黃魚 FishModelImageViewTypeSBY = 1, //石斑魚 FishModelImageViewTypeHSY = 2, //紅杉魚 FishModelImageViewTypeBWY = 3, //斑紋魚 FishModelImageViewTypeSHY = 4, //珊瑚魚 FishModelImageViewTypeSY = 5, //鯊魚 };
提供了一個(gè)釣到魚后的代理
FishModelImageViewDelegate //魚的種類-游動(dòng)方向-贏取金額 方法 - (void)catchTheFishWithType:(FishModelImageViewType)type andDirection:(FishModelImageViewDirection)dir andWinCount:(int)count;
1、動(dòng)態(tài)的魚
加載動(dòng)態(tài)魚的方法
//初始化UIImageView UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 55, 55)]; //如果圖片的名字是有順序的,例如xhy1,xhy2,xhy3...,可以取去掉序號(hào)的名字,然后會(huì)自動(dòng)將所有的圖片都加載進(jìn)來(lái),duration是動(dòng)畫時(shí)長(zhǎng) imageView.image = [UIImage animatedImageNamed:@"xhy" duration:1]; [self.view addSubview:imageView];
初始化不同的魚,不同的魚大小不同,移動(dòng)的速度不同,所以動(dòng)畫時(shí)長(zhǎng)不一樣
//初始化小魚 git動(dòng)畫時(shí)長(zhǎng) - (void)initViewWithType:(FishModelImageViewType)type andDuration:(double)time{ self.fishType = type; switch (type) { case FishModelImageViewTypeXHY://小黃魚 self.duration = 6.0; self.frame = CGRectMake(-100, 0, 35, 40); //魚的大小要定義好 self.image = [UIImage animatedImageNamed:@"xhy" duration:time]; break; case FishModelImageViewTypeSBY://石斑魚 self.duration = 7.0; self.frame = CGRectMake(-100, 0, 50, 50); self.image = [UIImage animatedImageNamed:@"sby" duration:time]; break; case FishModelImageViewTypeHSY://紅杉魚 self.duration = 8.0; self.frame = CGRectMake(-100, 0, 50, 40); self.image = [UIImage animatedImageNamed:@"hsy" duration:time]; break; case FishModelImageViewTypeBWY://斑紋魚 self.duration = 8.5; self.frame = CGRectMake(-100, 0, 65, 53); self.image = [UIImage animatedImageNamed:@"bwy" duration:time]; break; case FishModelImageViewTypeSHY://珊瑚魚 self.duration = 9.0; self.frame = CGRectMake(-100, 0, 55, 55); self.image = [UIImage animatedImageNamed:@"shy" duration:time]; break; case FishModelImageViewTypeSY://鯊魚 self.duration = 11.0; self.frame = CGRectMake(-200, 0, 145, 90); self.image = [UIImage animatedImageNamed:@"sy" duration:time]; break; } }
2、移動(dòng)的魚
提供的圖片都是頭朝左的(見上面的動(dòng)圖),所以從左往右游的話圖片需要進(jìn)行鏡像反轉(zhuǎn)
對(duì)于魚是否可以垂釣是用通知進(jìn)行傳遞信息的,可垂釣、不可垂釣兩種狀態(tài)
可垂釣:魚鉤沉到魚塘?xí)r受到垂釣通知(將魚鉤底部的坐標(biāo)傳過(guò)來(lái)),現(xiàn)在魚可以垂釣,當(dāng)根據(jù)上鉤概率等因素判斷魚上鉤后,對(duì)魚進(jìn)行旋轉(zhuǎn),然后執(zhí)行上鉤動(dòng)畫。動(dòng)畫結(jié)束后執(zhí)行代理。
//初始化可以垂釣的魚 - (instancetype)initCanCatchFishWithType:(FishModelImageViewType)type andDirection:(FishModelImageViewDirection)dir{ if (self = [super init]){ self.direction = dir; [self initViewWithType:type andDuration:1]; if (dir == FishModelImageViewFromLeft){//從左往右,默認(rèn)所有的魚都是從右往左 self.transform = CGAffineTransformMakeScale(-1, 1); //鏡像 } [self initFishView]; } return self; } #pragma mark - 可以垂釣的魚(計(jì)時(shí)器) - (void)initFishView{ //接收可以垂釣的通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationCanCatch:) name:NotificationFishHookStop object:nil]; //接收不可垂釣的通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationCannotCatch) name:NotificationFishHookMove object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(removeTimer) name:NotificationRemoveFishModelTimer object:nil]; //創(chuàng)建計(jì)時(shí)器 _linkTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(fishMove)]; //啟動(dòng)這個(gè)link(加入到線程池) [_linkTimer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; _offsetX = ScreenWidth; _offsetY = 100; _fishWidth = self.frame.size.width; //Y可變高度范圍 _randomRange = (int) (YuTangHeight - self.frame.size.height - OffSetYRange); self.speed = (ScreenWidth + _fishWidth)/self.duration;//游動(dòng)速度 self.changeX = self.speed/60.0;//計(jì)時(shí)器每秒60次 DLog(@"魚游動(dòng)的速度:%f,每次位移:%f", self.speed,self.changeX); }
魚移動(dòng)動(dòng)畫和上鉤動(dòng)畫
- (void)fishMove{ if (self.direction == FishModelImageViewFromLeft){//從左至右 if (_offsetX > ScreenWidth + _fishWidth){ _offsetY = arc4random()%_randomRange + OffSetYRange; _offsetX = - _fishWidth - _offsetY; } _offsetX+=self.changeX; self.frame = [self resetFrameOrigin:CGPointMake(_offsetX, _offsetY)]; if ([self fishCanBeCatchedWithOffsetX:_offsetX + _fishWidth]){ NSLog(@"釣到從左到右的魚了:%ld",(long)self.fishType); CGAffineTransform transform = CGAffineTransformIdentity; transform = CGAffineTransformScale(transform, -1, 1);//鏡像 transform = CGAffineTransformRotate(transform, M_PI_2);//旋轉(zhuǎn)90度 self.transform = transform; self.frame = [self resetFrameOrigin:CGPointMake(ScreenWidth*2, 0)]; [self fishCatchedMoveUpWithOffsetX:_offsetX + _fishWidth]; _offsetX = ScreenWidth + _fishWidth + 1;//重置起點(diǎn) _linkTimer.paused = YES;//計(jì)時(shí)器暫停 } }else {//從右到左 if (_offsetX < -_fishWidth){ _offsetY = arc4random()%_randomRange + OffSetYRange; _offsetX = ScreenWidth + _offsetY; } _offsetX-=self.changeX; self.frame = [self resetFrameOrigin:CGPointMake(_offsetX, _offsetY)]; if ([self fishCanBeCatchedWithOffsetX:_offsetX]){ NSLog(@"釣到從右到左的魚了:%ld",(long)self.fishType); self.transform = CGAffineTransformMakeRotation(M_PI_2); self.frame = [self resetFrameOrigin:CGPointMake(ScreenWidth*2, 0)]; [self fishCatchedMoveUpWithOffsetX:_offsetX]; _offsetX = -_fishWidth-1;//重置起點(diǎn) _linkTimer.paused = YES;//計(jì)時(shí)器暫停 } } }
魚上鉤的概率和贏得的金幣個(gè)數(shù)
//魚是否可以被釣上來(lái)(根據(jù)概率計(jì)算) - (BOOL)fishCanBeCatchedWithOffsetX:(CGFloat)offsetX{ if (!self.isCanCatch) return NO; if (fabs(offsetX - self.hookX) > self.changeX/2.0) return NO; //判斷是否到達(dá)了可以垂釣的點(diǎn) int random = arc4random()%100; //[0,99] DLog(@"random:%d", random); switch (self.fishType) { case FishModelImageViewTypeXHY://小黃魚 80% 金幣2 if (random < 80){ self.moneyCount = 2; return YES; } break; case FishModelImageViewTypeSBY://石斑魚 50% 金幣5 if (random < 50) { self.moneyCount = 5; return YES; } break; case FishModelImageViewTypeHSY://紅杉魚 30% 金幣10 if (random < 30) { self.moneyCount = 10; return YES; } break; case FishModelImageViewTypeBWY://斑紋魚 15% 金幣20 if (random < 15) { self.moneyCount = 20; return YES; } break; case FishModelImageViewTypeSHY://珊瑚魚 5% 金幣50 if (random < 5) { self.moneyCount = 50; return YES; } break; case FishModelImageViewTypeSY://鯊魚 1% 金幣100 if (random < 1) { self.moneyCount = 100; return YES; } break; } self.moneyCount = 0; return NO; }
3.被釣到的魚
初始化被釣到的魚方法
//初始化釣到的小魚 - (instancetype)initCatchedFishWithType:(FishModelImageViewType)type andDirection:(FishModelImageViewDirection)dir{ if (self = [super init]){ self.direction = dir; [self initViewWithType:type andDuration:0.5]; //重制x,y坐標(biāo), 30為魚鉤的寬度,85為魚鉤的長(zhǎng)度 self.x = (30 - self.width)/2.0; self.y = 85 - 6; if (dir == FishModelImageViewFromLeft){//從左往右,默認(rèn)所有的魚都是從右往左 CGAffineTransform transform = CGAffineTransformIdentity; transform = CGAffineTransformScale(transform, -1, 1);//鏡像 transform = CGAffineTransformRotate(transform, M_PI_2);//旋轉(zhuǎn)90度 self.transform = transform; }else { self.transform = CGAffineTransformMakeRotation(M_PI_2); } } return self; }
當(dāng)魚被抓到后,執(zhí)行上鉤動(dòng)畫
//魚被抓到后往上游 - (void)fishCatchedMoveUpWithOffsetX:(CGFloat) offsetX{ //鉤沉到魚塘的高度為45 //位移動(dòng)畫 CABasicAnimation *ani = [CABasicAnimation animationWithKeyPath:@"position"]; ani.duration = 0.7; if (self.fishType == FishModelImageViewTypeSY){//鯊魚由于太長(zhǎng),所以不進(jìn)行上游動(dòng)畫了 ani.fromValue = [NSValue valueWithCGPoint:CGPointMake(offsetX,45 + _fishWidth/2.0)]; ani.toValue = [NSValue valueWithCGPoint:CGPointMake(_hookX, 45 + _fishWidth/2.0)]; }else { ani.fromValue = [NSValue valueWithCGPoint:CGPointMake(offsetX, (_offsetY < 60) ? 45 + _fishWidth/2.0 : _offsetY)];//離鉤子近的話則不進(jìn)行動(dòng)畫 ani.toValue = [NSValue valueWithCGPoint:CGPointMake(_hookX, 45 + _fishWidth/2.0)]; } ani.delegate = self; //設(shè)置這兩句動(dòng)畫結(jié)束會(huì)停止在結(jié)束位置 [ani setValue:kFishCatchedMoveUpValue forKey:kFishCatchedMoveUpKey]; [self.layer addAnimation:ani forKey:kFishCatchedMoveUpKey]; }
魚上游動(dòng)畫結(jié)束后將翻轉(zhuǎn)的魚復(fù)位,然后執(zhí)行代理將釣到的魚通過(guò)代理傳遞出去
#pragma mark - CAAnimationDelegate - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ if (flag){ if ([[anim valueForKey:kFishCatchedMoveUpKey] isEqualToString:kFishCatchedMoveUpValue]){//魚上游 if (self.direction == FishModelImageViewFromLeft){ CGAffineTransform transform = CGAffineTransformIdentity; transform = CGAffineTransformScale(transform, -1, 1);//鏡像 transform = CGAffineTransformRotate(transform, 0);//旋轉(zhuǎn)90度 self.transform = transform; }else { self.transform = CGAffineTransformMakeRotation(0); } if ([self.delegate respondsToSelector:@selector(catchTheFishWithType:andDirection:andWinCount:)]){ [self.delegate catchTheFishWithType:self.fishType andDirection:self.direction andWinCount:self.moneyCount]; } } } }
釣魚View
這是實(shí)現(xiàn)界面了,本來(lái)是寫在VC里的,后來(lái)發(fā)現(xiàn)也能提取出來(lái),所有就提取出來(lái)了,在調(diào)用時(shí)非常簡(jiǎn)單,像正常View一樣初始化后添加到主View上即可,在viewDidDisappear中講資源釋放掉即可。
- (void)viewDidLoad { [super viewDidLoad]; _fishView = [[FishingView alloc] initWithFrame:self.view.bounds]; [self.view addSubview:_fishView]; } - (void)viewDidDisappear:(BOOL)animated{ [super viewWillDisappear:animated]; [_fishView removeFishViewResource]; }
1.初始化魚鉤
初始化魚鉤
講魚鉤擺動(dòng)的角度通過(guò)代理傳到本界面
#pragma mark - 魚鉤 - (void)initHookView{ _fishHookView = [[FishHookView alloc] initWithFrame:CGRectMake((ScreenWidth - 30)/2.0, 5, 30, 85)]; __weak typeof (self) weakSelf = self; _fishHookView.angleBlock = ^(CGFloat angle) { weakSelf.angle = angle; }; [self addSubview:_fishHookView]; UIImageView *yuGanImageView = [[UIImageView alloc] initWithFrame:CGRectMake(ScreenWidth/2.0 - 2, 0, ScreenWidth/2.0, 50)]; yuGanImageView.image = [UIImage imageNamed:@"fish_gan_tong"]; [self addSubview:yuGanImageView]; }
下鉤動(dòng)畫:魚塘增加了點(diǎn)擊手勢(shì),點(diǎn)擊后執(zhí)行釣魚動(dòng)作,暫停魚鉤擺動(dòng)計(jì)時(shí)器,下鉤動(dòng)畫結(jié)束后發(fā)送通知高速魚模塊可以上鉤了,并將魚鉤的底部中心坐標(biāo)傳遞過(guò)去,魚線用CAShapeLayer繪制,并執(zhí)行strokeEnd動(dòng)畫
//釣魚動(dòng)作 - (void)fishBtnAction{ if (self.fishHookState != FishHookStateShake) return; //不是搖擺狀態(tài)不可出桿 [self.fishHookView hookTimerPause];//暫停魚鉤的計(jì)時(shí)器 double degree = _angle*180/M_PI;//度數(shù) double rate = tan(_angle);//比列 DLog(@"degree:%f---rate:%f",degree,rate); //計(jì)算出來(lái)線終點(diǎn)x的位置 , 鉤到水里的深度不變,即y是固定的 _lineOffsetX = ScreenWidth/2.0 - (FishLineHeigth)*rate; //鉤子底部xy值 _hookBottomX = ScreenWidth/2.0 - (FishLineHeigth + FishHookHeight)*rate; _hookBottomY = FishLineHeigth + FishHookHeight; //動(dòng)畫時(shí)間 double aniDuration = [self hookOutOfRiver] ? 0.5 : 1; //繪制路徑 UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(ScreenWidth/2.0 ,5)]; [path addLineToPoint:CGPointMake(_lineOffsetX, FishLineHeigth)]; //圖形設(shè)置 _linePathLayer = [CAShapeLayer layer]; _linePathLayer.frame = self.bounds; _linePathLayer.path = path.CGPath; _linePathLayer.strokeColor = [HEXCOLOR(0x9e664a) CGColor]; _linePathLayer.fillColor = nil; _linePathLayer.lineWidth = 3.0f; _linePathLayer.lineJoin = kCALineJoinBevel; [self.layer addSublayer:_linePathLayer]; //下鉤動(dòng)畫 CAKeyframeAnimation *ani = [CAKeyframeAnimation animationWithKeyPath:@"strokeEnd"]; ani.duration = aniDuration; ani.values = @[@0,@0.8,@1]; ani.keyTimes = @[@0,@0.6,@1]; ani.delegate = self; [ani setValue:kLineDownAnimationValue forKey:kLineDownAnimationKey]; [_linePathLayer addAnimation:ani forKey:kLineDownAnimationKey]; //位移動(dòng)畫 _hookAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; //移動(dòng)路徑 CGFloat tempOffsetX = ScreenWidth/2.0 - (FishLineHeigth*0.8)*rate; NSValue *p1 = [NSValue valueWithCGPoint:CGPointMake(ScreenWidth/2.0 ,5)]; NSValue *p2 = [NSValue valueWithCGPoint:CGPointMake(tempOffsetX, FishLineHeigth*0.8)]; NSValue *p3 = [NSValue valueWithCGPoint:CGPointMake(_lineOffsetX, FishLineHeigth)]; _hookAnimation.duration = aniDuration; _hookAnimation.values = @[p1,p2,p3]; _hookAnimation.keyTimes = @[@0,@0.7,@1];//動(dòng)畫分段時(shí)間 //設(shè)置這兩句動(dòng)畫結(jié)束會(huì)停止在結(jié)束位置 _hookAnimation.removedOnCompletion = NO; _hookAnimation.fillMode=kCAFillModeForwards; [_fishHookView.layer addAnimation:_hookAnimation forKey:@"goukey"]; }
釣魚動(dòng)作:下鉤動(dòng)畫結(jié)束后計(jì)時(shí)器打開,執(zhí)行此方法;倒計(jì)時(shí)為最后一秒時(shí)魚不可上鉤(魚上鉤動(dòng)畫0.7s,要留上鉤動(dòng)畫的時(shí)間);計(jì)時(shí)器為0時(shí)發(fā)送不可垂釣通知告訴魚模塊不可上鉤了,并執(zhí)行上鉤動(dòng)畫。
//鉤子停在底部 - (void)hookStop:(NSTimer *)timer{ _stopDuration-=1; //最后一秒不可上鉤 if (_stopDuration == 1){ //發(fā)送不可垂釣的通知 self.fishHookState = FishHookStateUp; [[NSNotificationCenter defaultCenter] postNotificationName:NotificationFishHookMove object:nil]; } if (_stopDuration <= 0){ //關(guān)閉計(jì)時(shí)器 [timer setFireDate:[NSDate distantFuture]]; UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(_lineOffsetX, FishLineHeigth)]; [path addLineToPoint:CGPointMake(ScreenWidth/2.0 ,5)]; _linePathLayer.path = path.CGPath; //動(dòng)畫時(shí)間 double aniDuration = [self hookOutOfRiver] ? 0.5 : 1; //上鉤 CABasicAnimation *ani = [CABasicAnimation animationWithKeyPath:@"strokeStart"]; ani.duration = aniDuration; ani.fromValue = [NSNumber numberWithFloat:0]; ani.toValue = [NSNumber numberWithFloat:1]; ani.delegate = self; ani.removedOnCompletion = NO; ani.fillMode=kCAFillModeForwards; [ani setValue:kLineUpAnimationValue forKey:kLineUpAnimationKey]; [_linePathLayer addAnimation:ani forKey:kLineUpAnimationKey]; [_fishHookView.layer removeAllAnimations]; NSValue *p1 = [NSValue valueWithCGPoint:CGPointMake(ScreenWidth/2.0 ,5)]; NSValue *p2 = [NSValue valueWithCGPoint:CGPointMake(_lineOffsetX, FishLineHeigth)]; _hookAnimation.duration = aniDuration; _hookAnimation.values = @[p2,p1]; _hookAnimation.keyTimes = @[@0,@1]; [_fishHookView.layer addAnimation:_hookAnimation forKey:@"goukey"]; } }
金幣動(dòng)畫&加分動(dòng)畫
下鉤動(dòng)畫開始,總金幣減少10個(gè)
上鉤動(dòng)畫開始,發(fā)送不可垂釣通知,魚鉤狀態(tài)為上鉤狀態(tài)
如果有捉到魚(根據(jù)魚模塊代理是否執(zhí)行判斷是否捉到),執(zhí)行金幣動(dòng)畫和加分動(dòng)畫
下鉤動(dòng)畫結(jié)束,發(fā)送可以垂釣的通知給魚模塊,并將魚鉤坐標(biāo)傳遞過(guò)去,開啟上鉤的計(jì)時(shí)器
上鉤動(dòng)畫結(jié)束,更改魚鉤狀態(tài),移除一些View,魚鉤繼續(xù)擺動(dòng)
#pragma mark - CAAnimationDelegate 動(dòng)畫代理 //動(dòng)畫開始 - (void)animationDidStart:(CAAnimation *)anim{ //下鉤動(dòng)畫開始 if ([[anim valueForKey:kLineDownAnimationKey] isEqualToString:kLineDownAnimationValue]){ self.fishHookState = FishHookStateDown;//下鉤狀態(tài) //錢數(shù) self.moneyLabel.text = [NSString stringWithFormat:@"%d", _totalMoney-=10]; self.winMoney = 0; }else if ([[anim valueForKey:kLineUpAnimationKey] isEqualToString:kLineUpAnimationValue]){//上鉤動(dòng)畫開始 self.fishHookState = FishHookStateUp;//上鉤狀態(tài) [[NSNotificationCenter defaultCenter] postNotificationName:NotificationFishHookMove object:nil]; } if (self.isCatched){//釣到魚后落金幣 HHShootButton *button = [[HHShootButton alloc] initWithFrame:CGRectMake(_lineOffsetX, 0, 10, 10) andEndPoint:CGPointMake(10, 200)]; button.setting.iconImage = [UIImage imageNamed:@"coin"]; button.setting.animationType = ShootButtonAnimationTypeLine; [self.bgImageView addSubview:button]; [self bringSubviewToFront:button]; [button startAnimation]; HHWinMoneyLabel *winLabel = [[HHWinMoneyLabel alloc] initWithFrame:CGRectMake(_lineOffsetX - 100/2, ScreenFullHeight - FishSeaHeight, 100, 30)]; winLabel.text = [NSString stringWithFormat:@"+%d",_winMoney]; [self addSubview:winLabel]; self.isCatched = !self.isCatched; //金幣總數(shù) self.moneyLabel.text = [NSString stringWithFormat:@"%d", _totalMoney+=self.winMoney]; } } //動(dòng)畫結(jié)束 - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ if (flag){ if ([[anim valueForKey:kLineDownAnimationKey] isEqualToString:kLineDownAnimationValue]){//下鉤動(dòng)畫結(jié)束 self.fishHookState = FishHookStateStop;//垂釣狀態(tài) //鉤的位置 NSDictionary *dic = @{@"offsetX":[NSString stringWithFormat:@"%.2f",_hookBottomX],@"offsetY":[NSString stringWithFormat:@"%.2f",_hookBottomY]}; //發(fā)送可以垂釣的通知,鉤的位置傳過(guò)去 [[NSNotificationCenter defaultCenter] postNotificationName:NotificationFishHookStop object:nil userInfo:dic]; _stopDuration = [self hookOutOfRiver] ? 1 : arc4random()%3 + 3; //默認(rèn)時(shí)間[3,5),拋到岸上1s //開啟上鉤定時(shí)器 [_fishTimer setFireDate:[NSDate distantPast]]; }else if ([[anim valueForKey:kLineUpAnimationKey] isEqualToString:kLineUpAnimationValue]){//上鉤動(dòng)畫結(jié)束 self.fishHookState = FishHookStateShake;//搖擺狀態(tài) [_linePathLayer removeFromSuperlayer]; [_fishHookView hoolTimerGoOn];//魚鉤計(jì)時(shí)器繼續(xù) _catchedHeight = 0; //移除釣上來(lái)的魚 [self removeTheCatchedFishes]; } } }
魚模塊的代理方法
創(chuàng)建一個(gè)被釣到的魚,加在魚鉤上,這樣便可和魚鉤一起執(zhí)行上鉤動(dòng)畫了
#pragma mark - FishModelImageViewDelegate 釣到魚后的代理 - (void)catchTheFishWithType:(FishModelImageViewType)type andDirection:(FishModelImageViewDirection)dir andWinCount:(int)count{ self.isCatched = YES; FishModelImageView *fishImageView = [[FishModelImageView alloc] initCatchedFishWithType:type andDirection:dir]; [self.fishHookView addSubview:fishImageView]; fishImageView.y = fishImageView.y + _catchedHeight; _catchedHeight += 8;//每釣到一個(gè)y坐標(biāo)往下移 //贏得錢數(shù) self.winMoney += count; }
2.初始化魚塘
簡(jiǎn)單的創(chuàng)建魚背景并添加點(diǎn)擊手勢(shì)
3.初始化魚
通過(guò)for循環(huán)可以創(chuàng)建出多個(gè)某種魚
//小黃魚 for (int i = 0; i < 8; i++){ FishModelImageView *model1 = [[FishModelImageView alloc] initCanCatchFishWithType:FishModelImageViewTypeXHY andDirection: (i%2 == 0) ? FishModelImageViewFromRight : FishModelImageViewFromLeft]; model1.delegate = self; [self.bgImageView addSubview:model1]; }
4.資源移除
由于計(jì)時(shí)器不銷毀會(huì)造成循環(huán)引用,導(dǎo)致內(nèi)存泄漏,所以必須手動(dòng)移除他,還有動(dòng)畫如果執(zhí)行了代理,并且設(shè)置了結(jié)束后停留在結(jié)束位置,也會(huì)得不到釋放,所以都要手動(dòng)釋放資源
- (void)removeFishViewResource{ //解決魚鉤上鉤動(dòng)畫循環(huán)引用的問(wèn)題 _linePathLayer = nil; //釣魚計(jì)時(shí)器關(guān)閉 [_fishTimer invalidate]; _fishTimer = nil; //釋放魚鉤的計(jì)時(shí)器 [self.fishHookView hoolTimerInvalidate]; //發(fā)送通知釋放小魚資源 [[NSNotificationCenter defaultCenter] postNotificationName:NotificationRemoveFishModelTimer object:nil]; }
總結(jié)
至此,本游戲已經(jīng)完成了,寫的比較多,也比較亂,有什么不好的地方歡迎批評(píng)指正,希望對(duì)大伙有所幫助吧,本demo地址【https://github.com/Ccalary/FishingGame】
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。