前言
最近写了一款钓鱼小游戏,自己平时也没做过游戏,本来以为这种游戏要用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】
新闻热点
疑难解答