激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - IOS - iOS 動畫實戰之釣魚小游戲實例代碼

iOS 動畫實戰之釣魚小游戲實例代碼

2021-04-21 19:37程序員大咖 IOS

最近小編做了一個釣魚小游戲,平時沒有做過,所以上手有點急躁,不過,最終還是實現了,下面小編給大家分享iOS 動畫實戰之釣魚小游戲的實現思路,感興趣的朋友一起看看吧

前言

最近寫了一款釣魚小游戲,自己平時也沒做過游戲,本來以為這種游戲要用cocos2d什么的實現,后來發現其實動畫就可以實現很棒的效果,先看看效果圖。

iOS 動畫實戰之釣魚小游戲實例代碼

思維導圖

首先我們看下思維導圖,本游戲主要分為4大塊,其中魚的實現最為復雜

iOS 動畫實戰之釣魚小游戲實例代碼

思維導圖

項目結構

iOS 動畫實戰之釣魚小游戲實例代碼

準備工作

首先將需要的圖準備好,這個魚其實就是一組圖片,圖片大小固定,每一幀位置變化,所以看起來 是一個上下游動的魚。

iOS 動畫實戰之釣魚小游戲實例代碼

iOS 動畫實戰之釣魚小游戲實例代碼

單張圖片

魚鉤模塊

擺動動畫

魚鉤的擺動范圍是[m_pi/4.0,-m_pi/4.0] (垂直向下為0度,順時針為正),這里利用了計時器進行角度的更改,計時器用的cadisplaylink,它是一個和屏幕刷新率一致的定時器,如果沒有卡頓,每秒刷新次數是60次,本demo很多計時器用的都是cadisplaylink。下面是魚鉤的主要代碼(重點:1、設置錨點后重置frame,2、更改角度,3、旋轉)。 其中定義了一個block將角度angle回傳到fishingview界面計算魚鉤落到池塘的位置。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@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的一個類

魚模塊提供了三種初始化方式,可垂釣的魚、不可垂釣的魚(可以不用)、釣到的魚三種魚。

魚的移動方式有兩種,使用枚舉定義,從左到右,從右到左

魚的種類有六種,用枚舉進行了定義

?
1
2
3
4
5
6
7
8
typedef ns_enum(nsinteger, fishmodelimageviewtype){
fishmodelimageviewtypexhy = 0, //小黃魚
fishmodelimageviewtypesby = 1, //石斑魚
fishmodelimageviewtypehsy = 2, //紅杉魚
fishmodelimageviewtypebwy = 3, //斑紋魚
fishmodelimageviewtypeshy = 4, //珊瑚魚
fishmodelimageviewtypesy = 5, //鯊魚
};

提供了一個釣到魚后的代理

?
1
2
3
4
5
fishmodelimageviewdelegate
//魚的種類-游動方向-贏取金額
方法 - (void)catchthefishwithtype:(fishmodelimageviewtype)type
anddirection:(fishmodelimageviewdirection)dir
andwincount:(int)count;

1、動態的魚

加載動態魚的方法

?
1
2
3
4
5
//初始化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];

初始化不同的魚,不同的魚大小不同,移動的速度不同,所以動畫時長不一樣

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//初始化小魚 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、移動的魚

提供的圖片都是頭朝左的(見上面的動圖),所以從左往右游的話圖片需要進行鏡像反轉

對于魚是否可以垂釣是用通知進行傳遞信息的,可垂釣、不可垂釣兩種狀態

可垂釣:魚鉤沉到魚塘時受到垂釣通知(將魚鉤底部的坐標傳過來),現在魚可以垂釣,當根據上鉤概率等因素判斷魚上鉤后,對魚進行旋轉,然后執行上鉤動畫。動畫結束后執行代理。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//初始化可以垂釣的魚
- (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);
}

魚移動動畫和上鉤動畫

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
- (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;//計時器暫停
}
}
}

魚上鉤的概率和贏得的金幣個數

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//魚是否可以被釣上來(根據概率計算)
- (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.被釣到的魚

初始化被釣到的魚方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//初始化釣到的小魚
- (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;
}

當魚被抓到后,執行上鉤動畫

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//魚被抓到后往上游
- (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];
}

魚上游動畫結束后將翻轉的魚復位,然后執行代理將釣到的魚通過代理傳遞出去

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#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中講資源釋放掉即可。

?
1
2
3
4
5
6
7
8
9
- (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.初始化魚鉤

初始化魚鉤

講魚鉤擺動的角度通過代理傳到本界面

?
1
2
3
4
5
6
7
8
9
10
11
12
#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動畫

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//釣魚動作
- (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時發送不可垂釣通知告訴魚模塊不可上鉤了,并執行上鉤動畫。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//鉤子停在底部
- (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,魚鉤繼續擺動

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#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];
}
}
}

魚模塊的代理方法

創建一個被釣到的魚,加在魚鉤上,這樣便可和魚鉤一起執行上鉤動畫了

?
1
2
3
4
5
6
7
8
9
10
#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循環可以創建出多個某種魚

?
1
2
3
4
5
6
//小黃魚
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.資源移除

由于計時器不銷毀會造成循環引用,導致內存泄漏,所以必須手動移除他,還有動畫如果執行了代理,并且設置了結束后停留在結束位置,也會得不到釋放,所以都要手動釋放資源

?
1
2
3
4
5
6
7
8
9
10
11
- (void)removefishviewresource{
//解決魚鉤上鉤動畫循環引用的問題
_linepathlayer = nil;
//釣魚計時器關閉
[_fishtimer invalidate];
_fishtimer = nil;
//釋放魚鉤的計時器
[self.fishhookview hooltimerinvalidate];
//發送通知釋放小魚資源
[[nsnotificationcenter defaultcenter] postnotificationname:notificationremovefishmodeltimer object:nil];
}

總結

至此,本游戲已經完成了,寫的比較多,也比較亂,有什么不好的地方歡迎批評指正,希望對大伙有所幫助吧,本demo地址【https://github.com/ccalary/fishinggame

原文鏈接:http://www.sohu.com/a/223595556_505825

延伸 · 閱讀

精彩推薦
  • IOSiOS實現控制屏幕常亮不變暗的方法示例

    iOS實現控制屏幕常亮不變暗的方法示例

    最近在工作中遇到了要將iOS屏幕保持常亮的需求,所以下面這篇文章主要給大家介紹了關于利用iOS如何實現控制屏幕常亮不變暗的方法,文中給出了詳細的...

    隨風13332021-04-02
  • IOSiOS開發之視圖切換

    iOS開發之視圖切換

    在iOS開發中視圖的切換是很頻繁的,獨立的視圖應用在實際開發過程中并不常見,除非你的應用足夠簡單。在iOS開發中常用的視圖切換有三種,今天我們將...

    執著丶執念5282021-01-16
  • IOS詳解iOS中多個網絡請求的同步問題總結

    詳解iOS中多個網絡請求的同步問題總結

    這篇文章主要介紹了詳解iOS中多個網絡請求的同步問題總結,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧...

    liang199111312021-03-15
  • IOSiOS自定義UICollectionViewFlowLayout實現圖片瀏覽效果

    iOS自定義UICollectionViewFlowLayout實現圖片瀏覽效果

    這篇文章主要介紹了iOS自定義UICollectionViewFlowLayout實現圖片瀏覽效果的相關資料,需要的朋友可以參考下...

    jiangamh8882021-01-11
  • IOSiOS開發技巧之狀態欄字體顏色的設置方法

    iOS開發技巧之狀態欄字體顏色的設置方法

    有時候我們需要根據不同的背景修改狀態欄字體的顏色,下面這篇文章主要給大家介紹了關于iOS開發技巧之狀態欄字體顏色的設置方法,文中通過示例代碼...

    夢想家-mxj8922021-05-10
  • IOSiOS中滑動控制屏幕亮度和系統音量(附加AVAudioPlayer基本用法和Masonry簡單使用)

    iOS中滑動控制屏幕亮度和系統音量(附加AVAudioPlayer基本用法和

    這篇文章主要介紹了iOS中滑動控制屏幕亮度和系統音量(附加AVAudioPlayer基本用法和Masonry簡單使用)的相關資料,需要的朋友可以參考下...

    CodingFire13652021-02-26
  • IOSiOS中UILabel實現長按復制功能實例代碼

    iOS中UILabel實現長按復制功能實例代碼

    在iOS開發過程中,有時候會用到UILabel展示的內容,那么就設計到點擊UILabel復制它上面展示的內容的功能,也就是Label長按復制功能,下面這篇文章主要給大...

    devilx12792021-04-02
  • IOSiOS中MD5加密算法的介紹和使用

    iOS中MD5加密算法的介紹和使用

    MD5加密是最常用的加密方法之一,是從一段字符串中通過相應特征生成一段32位的數字字母混合碼。對輸入信息生成唯一的128位散列值(32個字符)。這篇文...

    LYSNote5432021-02-04
主站蜘蛛池模板: 久久成人免费观看 | 激情网站在线观看 | 九一成人| 97超级碰碰人国产在线观看 | 国产精品视频导航 | 亚洲精品com | 国产亚洲高清视频 | 视频一区国产 | 成人做爰高潮片免费视频美国 | 天堂在线中文资源 | 人人舔人人射 | 国产一区视频在线观看免费 | 久久久久久麻豆 | 欧洲成人免费 | 欧美在线观看视频一区 | 艹男人的日日夜夜 | 国产美女一区二区在线观看 | 久草在线资源福利站 | av在线一区二区三区 | 国产亚洲精品久久 | 国产精品毛片va一区二区三区 | 精品偷拍久久 | 日本不卡一二三区 | 精品国产1区2区3区 免费国产 | 国产毛片网站 | 精品久久久久久久久久中文字幕 | 久久网站热最新地址4 | 情侣啪啪网站 | 毛片免费视频观看 | 日本xxxx视频 | av电影在线免费 | 青青国产在线视频 | 亚洲操比视频 | 婷婷精品国产一区二区三区日韩 | 禁漫天堂久久久久久久久久 | 欧美视频一区二区 | 国产精品视频免费看 | 久久精品欧美一区二区三区不卡 | 国产亚洲精品久久久久久久久久 | 综合99| 久久久成人一区二区免费影院 |