iOSアニメの実戦釣り小ゲームの実例コード


前言
最近は釣りゲームを書いていますが、自分は普段ゲームをしたことがありません。このようなゲームはcocos 2 dなどで実現すると思っていましたが、実はアニメは素晴らしい効果を実現することができます。まず効果図を見てください。

コンダクタンス
まず、私達は思考図を見てみます。このゲームは主に4つの大きな塊に分けられています。その中で魚の実現が一番複雑です。

コンダクタンス
プロジェクト構造

準備工作
まず必要な図を用意します。この魚は写真のセットです。画像のサイズが固定されていて、フレームごとに位置が変化しています。だから上下に動く魚のように見えます。


枚の写真
フックモジュール
アニメーションを振る
フックの振り幅は[M_]です。PI/4.0、-M_PI/4.0(垂直下は0度、時計回りは正)、ここではタイマを利用して角度の変更を行い、タイマー用のCADisplayLinkは画面のリフレッシュ率と一致するタイマーです。カードがないと、毎秒の更新回数は60回、本Demoの多くのタイムマシンはすべてCADisplayLinkです。以下はフックの主なコードです。(ポイント:1、アンカーポイントを設定してから、frameをリセットします。2、角度を変えて、3、回転)。ここでblockを定義して、アングルを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);
}
魚のモジュール
魚のモジュールはUImageViewから継承されているクラスです。
魚のモジュールは3種類の初期化方式を提供しています。釣りができる魚、釣れない魚(使わなくてもいいです)、釣れた魚の3種類があります。
魚の移動方法は二つあります。エニュメレート・定義を使って、左から右へ、右から左へ。
魚の種類は6種類ありますが、列挙で定義されています。

typedef NS_ENUM(NSInteger, FishModelImageViewType){
FishModelImageViewTypeXHY = 0, //   
FishModelImageViewTypeSBY = 1, //   
FishModelImageViewTypeHSY = 2, //   
FishModelImageViewTypeBWY = 3, //   
FishModelImageViewTypeSHY = 4, //   
FishModelImageViewTypeSY = 5, //  
};
釣った魚の代理店を提供します。

FishModelImageViewDelegate
//    -    -    
   - (void)catchTheFishWithType:(FishModelImageViewType)type
andDirection:(FishModelImageViewDirection)dir
andWinCount:(int)count;
1、ダイナミックな魚
ダイナミック魚のロード方法

//   UIImageView
UIImageView *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%   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  , 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に追加すればいいです。vieDidDisplaarで資源を解放してください。

- (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];
}
フックアニメーション:魚の池をクリックしてジェスチャーを追加しました。クリックして釣り針の動きを実行して、釣り針の動きを一時停止します。動画が終わったら、高速魚のモジュールが引っかかることができます。そして釣り針の底の中心座標を過去に伝えます。釣り糸はCAShape Layerで描いて、strook Endアニメーションを実行します。

//    
- (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の時に魚釣り不可のお知らせを送ります。魚モジュールが釣れなくなりました。そして、インターネット動画を実行します。

//      
- (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