前言
最近寫了一款釣魚小游戲,自己平時也沒做過游戲,本來以為這種游戲要用cocos2d什么的實現,后來發現其實動畫就可以實現很棒的效果,先看看效果圖。
思維導圖
首先我們看下思維導圖,本游戲主要分為4大塊,其中魚的實現最為復雜
思維導圖
項目結構
準備工作
首先將需要的圖準備好,這個魚其實就是一組圖片,圖片大小固定,每一幀位置變化,所以看起來 是一個上下游動的魚。
單張圖片
魚鉤模塊
擺動動畫
魚鉤的擺動范圍是[M_PI/4.0,-M_PI/4.0] (垂直向下為0度,順時針為正),這里利用了計時器進行角度的更改,計時器用的CADisplayLink,它是一個和屏幕刷新率一致的定時器,如果沒有卡頓,每秒刷新次數是60次,本Demo很多計時器用的都是CADisplayLink。下面是魚鉤的主要代碼(重點:1、設置錨點后重置frame,2、更改角度,3、旋轉)。 其中定義了一個block將角度angle回傳到FishingView界面計算魚鉤落到池塘的位置。
@property (nonatomic, strong) CADisplayLink *linkTimer;@property (nonatomic, assign) BOOL isReduce;//改變方向@property (nonatomic, assign) CGFloat angle;//擺動的角度- (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];// 創建一個對象計時器_linkTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(hookMove)];//啟動這個link[_linkTimer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];}//設置錨點后重新設置frame- (void) setAnchorPoint:(CGPoint)anchorpoint forView:(UIView *)view{CGRect oldFrame = view.frame;view.layer.anchorPoint = anchorpoint;view.frame = oldFrame;}#pragma mark - 魚鉤擺動- (void)hookMove{if (self.isReduce){_angle-=1.8*cos(1.5*_angle)*0.01;//計算角度,利用cos模擬上升過程中減慢,下降加快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);//旋轉動畫self.transform = CGAffineTransformMakeRotation(_angle);}
魚模塊
魚模塊是繼承自UIImageView的一個類
魚模塊提供了三種初始化方式,可垂釣的魚、不可垂釣的魚(可以不用)、釣到的魚三種魚。
魚的移動方式有兩種,使用枚舉定義,從左到右,從右到左
魚的種類有六種,用枚舉進行了定義
typedef NS_ENUM(NSInteger, FishModelImageViewType){FishModelImageViewTypeXHY = 0, //小黃魚FishModelImageViewTypeSBY = 1, //石斑魚FishModelImageViewTypeHSY = 2, //紅杉魚FishModelImageViewTypeBWY = 3, //斑紋魚FishModelImageViewTypeSHY = 4, //珊瑚魚FishModelImageViewTypeSY = 5, //鯊魚};
提供了一個釣到魚后的代理
FishModelImageViewDelegate//魚的種類-游動方向-贏取金額方法 - (void)catchTheFishWithType:(FishModelImageViewType)typeandDirection:(FishModelImageViewDirection)dirandWinCount:(int)count;
1、動態的魚
加載動態魚的方法
//初始化UIImageViewUIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 55, 55)];//如果圖片的名字是有順序的,例如xhy1,xhy2,xhy3...,可以取去掉序號的名字,然后會自動將所有的圖片都加載進來,duration是動畫時長imageView.image = [UIImage animatedImageNamed:@"xhy" duration:1];[self.view addSubview:imageView];
初始化不同的魚,不同的魚大小不同,移動的速度不同,所以動畫時長不一樣
//初始化小魚 git動畫時長- (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、移動的魚
提供的圖片都是頭朝左的(見上面的動圖),所以從左往右游的話圖片需要進行鏡像反轉
對于魚是否可以垂釣是用通知進行傳遞信息的,可垂釣、不可垂釣兩種狀態
可垂釣:魚鉤沉到魚塘時受到垂釣通知(將魚鉤底部的坐標傳過來),現在魚可以垂釣,當根據上鉤概率等因素判斷魚上鉤后,對魚進行旋轉,然后執行上鉤動畫。動畫結束后執行代理。
//初始化可以垂釣的魚- (instancetype)initCanCatchFishWithType:(FishModelImageViewType)type andDirection:(FishModelImageViewDirection)dir{if (self = [super init]){self.direction = dir;[self initViewWithType:type andDuration:1];if (dir == FishModelImageViewFromLeft){//從左往右,默認所有的魚都是從右往左self.transform = CGAffineTransformMakeScale(-1, 1); //鏡像}[self initFishView];}return self;}#pragma mark - 可以垂釣的魚(計時器)- (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];//創建計時器_linkTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(fishMove)];//啟動這個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;//游動速度self.changeX = self.speed/60.0;//計時器每秒60次DLog(@"魚游動的速度:%f,每次位移:%f", self.speed,self.changeX);}
魚移動動畫和上鉤動畫
- (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);//旋轉90度self.transform = transform;self.frame = [self resetFrameOrigin:CGPointMake(ScreenWidth*2, 0)];[self fishCatchedMoveUpWithOffsetX:_offsetX + _fishWidth];_offsetX = ScreenWidth + _fishWidth + 1;//重置起點_linkTimer.paused = YES;//計時器暫停}}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;//重置起點_linkTimer.paused = YES;//計時器暫停}}}
魚上鉤的概率和贏得的金幣個數
//魚是否可以被釣上來(根據概率計算)- (BOOL)fishCanBeCatchedWithOffsetX:(CGFloat)offsetX{if (!self.isCanCatch) return NO;if (fabs(offsetX - self.hookX) > self.changeX/2.0) return NO; //判斷是否到達了可以垂釣的點int random = arc4random()%100; //[0,99]DLog(@"random:%d", random);switch (self.fishType) {case FishModelImageViewTypeXHY://小黃魚 80% 金幣2if (random < 80){self.moneyCount = 2;return YES;}break;case FishModelImageViewTypeSBY://石斑魚 50% 金幣5if (random < 50) {self.moneyCount = 5;return YES;}break;case FishModelImageViewTypeHSY://紅杉魚 30% 金幣10if (random < 30) {self.moneyCount = 10;return YES;}break;case FishModelImageViewTypeBWY://斑紋魚 15% 金幣20if (random < 15) {self.moneyCount = 20;return YES;}break;case FishModelImageViewTypeSHY://珊瑚魚 5% 金幣50if (random < 5) {self.moneyCount = 50;return YES;}break;case FishModelImageViewTypeSY://鯊魚 1% 金幣100if (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坐標, 30為魚鉤的寬度,85為魚鉤的長度self.x = (30 - self.width)/2.0;self.y = 85 - 6;if (dir == FishModelImageViewFromLeft){//從左往右,默認所有的魚都是從右往左CGAffineTransform transform = CGAffineTransformIdentity;transform = CGAffineTransformScale(transform, -1, 1);//鏡像transform = CGAffineTransformRotate(transform, M_PI_2);//旋轉90度self.transform = transform;}else {self.transform = CGAffineTransformMakeRotation(M_PI_2);}}return self;}
當魚被抓到后,執行上鉤動畫
//魚被抓到后往上游- (void)fishCatchedMoveUpWithOffsetX:(CGFloat) offsetX{//鉤沉到魚塘的高度為45//位移動畫CABasicAnimation *ani = [CABasicAnimation animationWithKeyPath:@"position"];ani.duration = 0.7;if (self.fishType == FishModelImageViewTypeSY){//鯊魚由于太長,所以不進行上游動畫了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)];//離鉤子近的話則不進行動畫ani.toValue = [NSValue valueWithCGPoint:CGPointMake(_hookX, 45 + _fishWidth/2.0)];}ani.delegate = self;//設置這兩句動畫結束會停止在結束位置[ani setValue:kFishCatchedMoveUpValue forKey:kFishCatchedMoveUpKey];[self.layer addAnimation:ani forKey:kFishCatchedMoveUpKey];}
魚上游動畫結束后將翻轉的魚復位,然后執行代理將釣到的魚通過代理傳遞出去
#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);//旋轉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
這是實現界面了,本來是寫在VC里的,后來發現也能提取出來,所有就提取出來了,在調用時非常簡單,像正常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.初始化魚鉤
初始化魚鉤
講魚鉤擺動的角度通過代理傳到本界面
#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];}
下鉤動畫:魚塘增加了點擊手勢,點擊后執行釣魚動作,暫停魚鉤擺動計時器,下鉤動畫結束后發送通知高速魚模塊可以上鉤了,并將魚鉤的底部中心坐標傳遞過去,魚線用CAShapeLayer繪制,并執行strokeEnd動畫
//釣魚動作- (void)fishBtnAction{if (self.fishHookState != FishHookStateShake) return; //不是搖擺狀態不可出桿[self.fishHookView hookTimerPause];//暫停魚鉤的計時器double degree = _angle*180/M_PI;//度數double rate = tan(_angle);//比列DLog(@"degree:%f---rate:%f",degree,rate);//計算出來線終點x的位置 , 鉤到水里的深度不變,即y是固定的_lineOffsetX = ScreenWidth/2.0 - (FishLineHeigth)*rate;//鉤子底部xy值_hookBottomX = ScreenWidth/2.0 - (FishLineHeigth + FishHookHeight)*rate;_hookBottomY = FishLineHeigth + FishHookHeight;//動畫時間double aniDuration = [self hookOutOfRiver] ? 0.5 : 1;//繪制路徑UIBezierPath *path = [UIBezierPath bezierPath];[path moveToPoint:CGPointMake(ScreenWidth/2.0 ,5)];[path addLineToPoint:CGPointMake(_lineOffsetX, FishLineHeigth)];//圖形設置_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];//下鉤動畫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];//位移動畫_hookAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];//移動路徑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];//動畫分段時間//設置這兩句動畫結束會停止在結束位置_hookAnimation.removedOnCompletion = NO;_hookAnimation.fillMode=kCAFillModeForwards;[_fishHookView.layer addAnimation:_hookAnimation forKey:@"goukey"];}
釣魚動作:下鉤動畫結束后計時器打開,執行此方法;倒計時為最后一秒時魚不可上鉤(魚上鉤動畫0.7s,要留上鉤動畫的時間);計時器為0時發送不可垂釣通知告訴魚模塊不可上鉤了,并執行上鉤動畫。
//鉤子停在底部- (void)hookStop:(NSTimer *)timer{_stopDuration-=1;//最后一秒不可上鉤if (_stopDuration == 1){//發送不可垂釣的通知self.fishHookState = FishHookStateUp;[[NSNotificationCenter defaultCenter] postNotificationName:NotificationFishHookMove object:nil];}if (_stopDuration <= 0){//關閉計時器[timer setFireDate:[NSDate distantFuture]];UIBezierPath *path = [UIBezierPath bezierPath];[path moveToPoint:CGPointMake(_lineOffsetX, FishLineHeigth)];[path addLineToPoint:CGPointMake(ScreenWidth/2.0 ,5)];_linePathLayer.path = path.CGPath;//動畫時間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"];}}
金幣動畫&加分動畫
下鉤動畫開始,總金幣減少10個
上鉤動畫開始,發送不可垂釣通知,魚鉤狀態為上鉤狀態
如果有捉到魚(根據魚模塊代理是否執行判斷是否捉到),執行金幣動畫和加分動畫
下鉤動畫結束,發送可以垂釣的通知給魚模塊,并將魚鉤坐標傳遞過去,開啟上鉤的計時器
上鉤動畫結束,更改魚鉤狀態,移除一些View,魚鉤繼續擺動
#pragma mark - CAAnimationDelegate 動畫代理//動畫開始- (void)animationDidStart:(CAAnimation *)anim{//下鉤動畫開始if ([[anim valueForKey:kLineDownAnimationKey] isEqualToString:kLineDownAnimationValue]){self.fishHookState = FishHookStateDown;//下鉤狀態//錢數self.moneyLabel.text = [NSString stringWithFormat:@"%d", _totalMoney-=10];self.winMoney = 0;}else if ([[anim valueForKey:kLineUpAnimationKey] isEqualToString:kLineUpAnimationValue]){//上鉤動畫開始self.fishHookState = FishHookStateUp;//上鉤狀態[[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;//金幣總數self.moneyLabel.text = [NSString stringWithFormat:@"%d", _totalMoney+=self.winMoney];}}//動畫結束- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{if (flag){if ([[anim valueForKey:kLineDownAnimationKey] isEqualToString:kLineDownAnimationValue]){//下鉤動畫結束self.fishHookState = FishHookStateStop;//垂釣狀態//鉤的位置NSDictionary *dic = @{@"offsetX":[NSString stringWithFormat:@"%.2f",_hookBottomX],@"offsetY":[NSString stringWithFormat:@"%.2f",_hookBottomY]};//發送可以垂釣的通知,鉤的位置傳過去[[NSNotificationCenter defaultCenter] postNotificationName:NotificationFishHookStop object:nil userInfo:dic];_stopDuration = [self hookOutOfRiver] ? 1 : arc4random()%3 + 3; //默認時間[3,5),拋到岸上1s//開啟上鉤定時器[_fishTimer setFireDate:[NSDate distantPast]];}else if ([[anim valueForKey:kLineUpAnimationKey] isEqualToString:kLineUpAnimationValue]){//上鉤動畫結束self.fishHookState = FishHookStateShake;//搖擺狀態[_linePathLayer removeFromSuperlayer];[_fishHookView hoolTimerGoOn];//魚鉤計時器繼續_catchedHeight = 0;//移除釣上來的魚[self removeTheCatchedFishes];}}}
魚模塊的代理方法
創建一個被釣到的魚,加在魚鉤上,這樣便可和魚鉤一起執行上鉤動畫了
#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;//每釣到一個y坐標往下移//贏得錢數self.winMoney += count;}
2.初始化魚塘
簡單的創建魚背景并添加點擊手勢
3.初始化魚
通過for循環可以創建出多個某種魚
//小黃魚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.資源移除
由于計時器不銷毀會造成循環引用,導致內存泄漏,所以必須手動移除他,還有動畫如果執行了代理,并且設置了結束后停留在結束位置,也會得不到釋放,所以都要手動釋放資源
- (void)removeFishViewResource{//解決魚鉤上鉤動畫循環引用的問題_linePathLayer = nil;//釣魚計時器關閉[_fishTimer invalidate];_fishTimer = nil;//釋放魚鉤的計時器[self.fishHookView hoolTimerInvalidate];//發送通知釋放小魚資源[[NSNotificationCenter defaultCenter] postNotificationName:NotificationRemoveFishModelTimer object:nil];}
總結
至此,本游戲已經完成了,寫的比較多,也比較亂,有什么不好的地方歡迎批評指正,希望對大伙有所幫助吧,本demo地址【https://github.com/Ccalary/FishingGame】
|
新聞熱點
疑難解答