图片

抽奖功能模块源码
产品出发点
1、通过动态抽奖数据和排行激发用户抽奖消费;
2、通过技能和宝石等以及转盘的燃爆值,中奖率翻倍等等吸引用户;
3、根本上是为了激发用户活跃性以及刺激消费

技术难点
1、抽奖转盘分为两种转盘,业务逻辑分一个parentVC 管理两个 子 VC;
2、抽奖奖品服务端返回,显示在每一个扇形区域的中间,金额同似;
3、点击抽奖,拿到奖品id, 找出是在转盘中的哪个区域,让转盘指针停止在那一区域;
4、抽奖动态弹幕;
5、燃烧值 和 倒计时的控制;

业务操作说明
1、两个转盘,某个转盘点击开始抽奖 互不影响; 黄金转盘具有宝箱和技能;
2、每抽取一次,扣除相应的金额,如有中奖,则弹出中奖奖品;抽奖分为单次,十连抽,三十连抽等;
3、抽奖后产生记录;在记录中可看到每次抽奖消费情况;
4、转盘有燃烧值,当满时候,触发倒计时3分钟,倒计时内 中奖率将翻倍;
5、燃烧值每3秒刷新一次,当中途离开再次打开,则拿到最新倒计时显示;
6、弹幕从最新100条记录 每隔2秒随机生成一条记录;

模块设计
1、整个框架布局在一个 MainVC中控制转盘类型,请求余额,通知等刷新金额; 管理childVC ;
2、childVC 中 处理抽奖业务逻辑;UI 布局,抽奖请求, 燃烧值处理,弹幕处理;
3、其他功能性子View 单独自定义视图; 转盘视图,燃烧值进度视图,倒计时进度视图, 弹窗类视图;弹幕视图;
4、弹窗类视图 以一个ParentView公共视图容器 ,其中子视图由枚举参数值控制自定义;有玩法视图,记录视图,保险视图,技能视图,排行榜视图;

弹幕处理
NSTimer 每2秒中往弹幕父视图中添加一条弹幕view;
CADisplayLink 调动 setNeedsDisplay 方法 触发 系统drawRect 方法;
drawRect 方法中 ,把弹幕父视图所有的弹幕都每次移动x值,再 移除屏幕中的弹幕 x值 小于0 的弹幕(判断 每条弹幕view 有自己的位置);

倒计时处理
在自定义视图中 ,drawRect 方法中 贝塞尔曲线 绘制 两个曲线园;clockwise 逆方向; 每次通过设置剩余时间 调用setNeedLayout 会触发drawRect ; 倒计时启动timer,每0.05秒 重复一次,改变剩余时间;剩余时间 小于 或 为0 时候,则倒计时走完,停止timer;

转盘处理
一个点围绕 某个起点 旋转 n 度 后 的转标 通过这个公式计算 : #define pointRotatedAroundAnchorPoint(point,anchorPoint,angle) CGPointMake((point.x-anchorPoint.x)cos(angle) - (point.y-anchorPoint.y)sin(angle) + anchorPoint.x, (point.x-anchorPoint.x)sin(angle) + (point.y-anchorPoint.y)cos(angle)+anchorPoint.y)

拿到奖品后,根据扇形个数 计算每个扇形的角度,正起点方向 为原点 旋转角度以便设置每个奖品的中心位置point ; 和transform;

转盘指针停在的位置: 指针不动,实际是转动底盘; 需将底盘视图 旋转到固定角度即可;顺时针是 360度 - 固定角度; 每次转动前,需将上一次转动角度归位;

1
2
3
4
5
6
7
8
9
10
11
CABasicAnimation *layer = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];

// 顺时针(所有这里需要用360-对应的角度) 逆时针不需要
layer.toValue = @((M_PI*2 - (_perSection*index +_perSection*0.5)) + M_PI*2*4); //先转4圈
layer.duration = 4;
layer.removedOnCompletion = NO;
layer.fillMode = kCAFillModeForwards;
layer.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
layer.delegate = self;

[self.gameBgView.layer addAnimation:layer forKey:nil];

1
2
3
4
5
6
7
8
9
-(void)backToStartPosition{
//归位
CABasicAnimation *layer = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
layer.toValue = @(0);
layer.duration = 0.001;
layer.removedOnCompletion = NO;
layer.fillMode = kCAFillModeForwards;
[self.gameBgView.layer addAnimation:layer forKey:nil];
}

弹出视图
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
#import <UIKit/UIKit.h>
#import "PrizeRecord.h"

typedef void(^GYActionDateDoneBlock)(id selectedDate);

typedef enum : NSInteger {
Prize_Ranking, //抽奖
Prize_Gift, //奖品
Prize_SkillDesc, //描述
Prize_PlayDesc, //描述
Prize_Record, //中奖记录
Prize_RecordDetail //中奖详情
} PrizeStyle;

@interface GYPrizeContairView : UIView

- (instancetype)initSheetStyle:(PrizeStyle)prizeStyle actionBlock:(GYActionDateDoneBlock)actionDateDoneBlock;

-(void)showInView;

//中奖奖品;
-(void)fetch_Prize_Gift:(NSArray *)datas;

//默认选中查询的转盘
-(void)fetch_Record_DefaultChooseSelect:(DrawPrizeType)drawType;
-(void)fetch_Record_Detail:(PrizeRecord *)record;

//排行榜
-(void)fetch_Ranking_DrawType:(DrawPrizeType)drawType;

@end

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if(_sheetCellStyle == Prize_Ranking){
[self createRankingView]; //排行榜;
titleLabel.text = @"排行榜";
}else if(_sheetCellStyle == Prize_Gift){
[self createPrizeGiftView]; //奖品
titleLabel.text = @"恭喜您获得以下奖品";
}else if(_sheetCellStyle == Prize_SkillDesc){
[self createSkillDescView]; //技能描述
titleLabel.text = @"技能";
}else if(_sheetCellStyle == Prize_PlayDesc){
[self createPlayPrizeDescView]; //技能描述
titleLabel.text = @"玩法说明";
}else if(_sheetCellStyle == Prize_Record){
[self createPlayPrizeRecordView]; //技能记录描述
titleLabel.text = @"抽奖记录";
}else if(_sheetCellStyle == Prize_RecordDetail){
[self createPlayPrizeDetailRecordView]; //奖品记录详情
titleLabel.text = @"抽奖详情";
}

如图:
图片2
图片
图片
图片
图片

抽奖功能模块源码

评论