iOS中粒子發(fā)射(封裝下雨,下雪声登,噴火等特效)

在iOS中實(shí)現(xiàn)粒子特效,有對(duì)應(yīng)的的屬性CAEmitterLayer,它是Layer的子類(lèi)突勇,用它來(lái)實(shí)現(xiàn)粒子特效不會(huì)怎么占用資源,從而去影響UI的流程性坷虑。
粒子CAEmitterLayer發(fā)射器的基本屬性

//是否允許在規(guī)定的范圍內(nèi)
@property BOOL masksToBounds;

//發(fā)射器的形狀
//kCAEmitterLayerPoint 點(diǎn)的形狀甲馋,粒子從一個(gè)點(diǎn)發(fā)出
//kCAEmitterLayerLine 線的形狀,粒子從一條線發(fā)出
//kCAEmitterLayerRectangle 矩形形狀迄损,粒子從一個(gè)矩形中發(fā)出
//kCAEmitterLayerCuboid 立方體形狀定躏,會(huì)影響z平面的效果
//kCAEmitterLayerCircle 圓形,粒子會(huì)在圓形范圍發(fā)射
//kCAEmitterLayerSphere 球形
@property(copy) NSString *emitterShape;

//發(fā)射器的發(fā)射模式
//kCAEmitterLayerPoints 從發(fā)射器中發(fā)出
//kCAEmitterLayerOutline 從發(fā)射器邊緣發(fā)出
//kCAEmitterLayerSurface 從發(fā)射器表面發(fā)出
//kCAEmitterLayerVolumen 從發(fā)射器中點(diǎn)發(fā)出
@property(copy) NSString *emitterMode;

// 發(fā)射器的尺寸大小
@property CGSize emitterSize;

//發(fā)射器在xy平面的中心位置
@property CGPoint emitterPosition;

//發(fā)射器在Z平面的位置
@property CGFloat emitterZPosition;

粒子的屬性芹敌,也就是特效痊远,需要用到CAEmitterCell這個(gè)類(lèi)

//類(lèi)方法創(chuàng)建發(fā)射單元
+ (instancetype)emitterCell;

//粒子的創(chuàng)建速率
@property float birthRate;

//粒子的生存時(shí)間
@property float lifetime;

//粒子的生存時(shí)間容差
@property float lifetimeRange;

//粒子在Z軸方向的發(fā)射角度
@property CGFloat emissionLatitude;

//粒子在xy平面的發(fā)射角度
@property CGFloat emissionLongitude;

//粒子發(fā)射角度的容差
@property CGFloat emissionRange;

//粒子的速度
@property CGFloat velocity;

//粒子速度的容差
@property CGFloat velocityRange;

//x,y氏捞,z三個(gè)方向的加速度
@property CGFloat xAcceleration;
@property CGFloat yAcceleration;
@property CGFloat zAcceleration;

//縮放大小碧聪,縮放容差和縮放速度
@property CGFloat scale;
@property CGFloat scaleRange;
@property CGFloat scaleSpeed;

//旋轉(zhuǎn)度與旋轉(zhuǎn)容差
@property CGFloat spin;
@property CGFloat spinRange;

//
@property CGColorRef color;

//粒子在rgb三個(gè)色相上的容差和透明度的容差
@property float redRange;
@property float greenRange;
@property float blueRange;
@property float alphaRange;

//粒子在RGB三個(gè)色相上的變化速度和透明度的變化速度
@property float redSpeed;
@property float greenSpeed;
@property float blueSpeed;
@property float alphaSpeed;

//渲染粒子,可以設(shè)置為一個(gè)CGImage的對(duì)象
@property(strong) id contents;

//渲染的范圍
@property CGRect contentsRect;

好液茎,接下來(lái)我們看一下他的基本用法逞姿。

    //創(chuàng)建出layer
    CAEmitterLayer *emitterLayer = [CAEmitterLayer layer];//遍歷構(gòu)造器創(chuàng)建
    //給定尺寸
    emitterLayer.frame = CGRectMake(100, 100, 100, 100);
    //顯示邊框
    emitterLayer.borderWidth = 1.f;
    //發(fā)射點(diǎn)
    emitterLayer.emitterPosition = CGPointMake(0, 0);
    
//    emitterLayer.masksToBounds = YES;
    
    //發(fā)射模式
    emitterLayer.emitterMode = kCAEmitterLayerSurface;
    //發(fā)射形狀
    emitterLayer.emitterShape = kCAEmitterLayerLine;
    
    [self.view.layer addSublayer:emitterLayer];
    
    CAEmitterCell *cell = [CAEmitterCell emitterCell];
    //粒子產(chǎn)生率
    cell.birthRate = 1.f;
    //粒子生命周期
    cell.lifetime = 120.f;
    //速度值
    cell.velocity = 10;
    //速度值的微調(diào)值
    cell.velocityRange = 3.f;
    //y軸加速度
    cell.yAcceleration = 2.f;
    //發(fā)射角度
    cell.emissionRange = 0.5 *M_1_PI;
    //設(shè)置粒子顏色
//    cell.color = [UIColor blueColor].CGColor;
    
    cell.contents = (__bridge id _Nullable)([UIImage imageNamed:@"234"].CGImage);
    //讓CAEmitterCell與CAEmitterLayer產(chǎn)生關(guān)系
    emitterLayer.emitterCells = @[cell];

然后運(yùn)行后得到的效果如下:

caotu.gif

CAEmitterLayer基本的使用也就這樣辞嗡,但為了避免繁瑣的設(shè)置,我們將CAEmitterLayer封裝成一個(gè)較為通用的父類(lèi)供子類(lèi)使用滞造。

首先創(chuàng)建一個(gè)繼承UIView的視圖CAEmitterLayerView续室,由于此view默認(rèn)創(chuàng)建的隱式layer不是CAEmitterLayer,所以我們需要在CAEmitterLayerView.m中重寫(xiě)layerClass方法断部,返回CAEmitterLayer猎贴。由于CAEmitterLayer含有非常多的屬性要設(shè)置,如果都寫(xiě)在CAEmitterLayerView.h中的話(huà)蝴光,會(huì)顯得非常的繁瑣她渴,所以在這里我們寫(xiě)set和get方法,通過(guò)這個(gè)方法蔑祟,當(dāng)我們需要使用哪個(gè)屬性的時(shí)候趁耗,再在子類(lèi)中進(jìn)行調(diào)用即可。CAEmitterLayerView的代碼如下:
CAEmitterLayerView.h

@interface CAEmitterLayerView : UIView
//模仿setter疆虚,getter方法
- (void)setEmitterLayer:(CAEmitterLayer *)layer;
- (CAEmitterLayer *)emitterLayer;

//顯示出當(dāng)前view
- (void)show;
//隱藏
- (void)hide;
@end

CAEmitterLayerView.m

@interface CAEmitterLayerView() {
    CAEmitterLayer *_emitterLayer;
}

@end

@implementation CAEmitterLayerView
+(Class)layerClass {
    return [CAEmitterLayer class];
}

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        _emitterLayer = (CAEmitterLayer *)self.layer;
    }
    return self;
}

- (void)setEmitterLayer:(CAEmitterLayer *)layer {
    _emitterLayer = layer;
}

- (CAEmitterLayer *)emitterLayer {
    return _emitterLayer;
}

- (void)show {

}

- (void)hide {

}

好了苛败,通過(guò)這種方法,我們?cè)陧?xiàng)目中倘若要設(shè)計(jì)下雨或者下雪等效果時(shí)候径簿,只需要繼承該CAEmitterLayerView罢屈,然后在子類(lèi)中實(shí)現(xiàn)對(duì)應(yīng)的效果即可。

1.下雪效果
首先創(chuàng)建一個(gè)CAEmitterLayerView的子類(lèi)視圖SnowView篇亭,在.m中的代碼如下

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self setup];
    }
    return self;
}

- (void)setup {
 //初始化一些參數(shù)
    self.emitterLayer.masksToBounds = YES;
    self.emitterLayer.emitterShape = kCAEmitterLayerLine;
    self.emitterLayer.emitterMode = kCAEmitterLayerSurface;
    self.emitterLayer.emitterSize = self.frame.size;
    self.emitterLayer.emitterPosition = CGPointMake(self.bounds.size.width / 2.f, -20);
}

- (void)show {
   //配置
    CAEmitterCell *snowFlake = [CAEmitterCell emitterCell];
    snowFlake.birthRate = 1.f;
    snowFlake.speed = 10.f;
    snowFlake.velocity = 2.f;
    snowFlake.velocityRange = 10.f;
    snowFlake.yAcceleration = 10.f;
    snowFlake.emissionRange = 0.5 * M_PI;
    snowFlake.spinRange = 0.25 * M_PI;
    snowFlake.contents = (__bridge id _Nullable)([UIImage imageNamed:@"234"].CGImage);
    snowFlake.color = [UIColor redColor].CGColor;
    snowFlake.lifetime = 180.f;
    snowFlake.scale = 0.5;
    snowFlake.scaleRange = 0.3;
    
    //添加動(dòng)畫(huà)
    self.emitterLayer.emitterCells = @[snowFlake];
}

下雪模型已搭建好缠捌,然后在我們的控制器中導(dǎo)入SnowView

    SnowView *sView = [[SnowView alloc] initWithFrame:CGRectMake(100, 400, 100, 100)];
    [self.view addSubview:sView];
    [sView show];

效果如下:

snow.gif

2.下雨效果
創(chuàng)建一個(gè)CAEmitterLayerView的子類(lèi)視圖RainView,在.m中的代碼如下

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self setup];
    }
    return self;
}

- (void)setup {
    self.emitterLayer.masksToBounds = YES;
    self.emitterLayer.emitterShape = kCAEmitterLayerLine;
    self.emitterLayer.emitterMode = kCAEmitterLayerSurface;
    self.emitterLayer.emitterSize = self.frame.size;
    self.emitterLayer.emitterPosition
    = CGPointMake(self.bounds.size.width / 2.f, -20);
}

- (void)show {
    CAEmitterCell *rainFlake = [CAEmitterCell emitterCell];
    rainFlake.birthRate = 25.f;
    rainFlake.speed = 10.f;
    rainFlake.velocity = 10.f;
    rainFlake.velocityRange = 10.f;
    rainFlake.yAcceleration = 1000.f;
    rainFlake.contents = (__bridge id _Nullable)([UIImage imageNamed:@"234"].CGImage);
    rainFlake.color = [UIColor blackColor].CGColor;
    rainFlake.lifetime = 7.f;
    rainFlake.scaleRange = 0.f;
    rainFlake.scale = 0.2f;
    //添加動(dòng)畫(huà)
    self.emitterLayer.emitterCells = @[rainFlake];
}

效果如下(圖片可以切長(zhǎng)點(diǎn)译蒂,我在這里沒(méi)改圖片曼月,看著效果并沒(méi)那么好):

rain.gif

3.火焰
創(chuàng)建一個(gè)CAEmitterLayerView的子類(lèi)視圖fireView,在這里設(shè)置了兩個(gè)CAEmitterCell(特效)柔昼,在.m中的代碼如下

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self setup];
    }
    return self;
}

- (void)setup {
    self.emitterLayer.masksToBounds = YES;
    self.emitterLayer.renderMode = kCAEmitterLayerAdditive;
    self.emitterLayer.emitterSize = CGSizeMake(self.bounds.size.width - 100, 20);
    self.emitterLayer.emitterPosition
    = CGPointMake(self.bounds.size.width / 2.f, self.bounds.size.height - 20);
}

- (void)show {
    //火焰
  CAEmitterCell * fire = [CAEmitterCell emitterCell];
    fire.birthRate=800;
    fire.lifetime=2.0;
    fire.lifetimeRange=1.5;
    fire.color=[[UIColor colorWithRed:0.8 green:0.4 blue:0.2 alpha:0.1]CGColor];
    fire.contents=(id)[[UIImage imageNamed:@"fire"]CGImage];
    
    fire.velocity=160;
    fire.velocityRange=80;
    fire.emissionLongitude=M_PI+M_PI_2;
    fire.emissionRange=M_PI_2;
    
    
    
    fire.scaleSpeed=0.3;
    fire.spin=0.2;
    
    //煙霧
    CAEmitterCell * smoke = [CAEmitterCell emitterCell];
    smoke.birthRate=400;
    smoke.lifetime=3.0;
    smoke.lifetimeRange=1.5;
    smoke.color=[[UIColor colorWithRed:1 green:1 blue:1 alpha:0.05]CGColor];
    smoke.contents=(id)[[UIImage imageNamed:@"smoke"]CGImage];
    
    smoke.velocity=250;
    smoke.velocityRange=100;
    smoke.emissionLongitude=M_PI+M_PI_2;
    smoke.emissionRange=M_PI_2;
    
    self.emitterLayer.emitterCells = [NSArray arrayWithObjects:smoke,fire, nil];
}

效果如下:

fire.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末哑芹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子捕透,更是在濱河造成了極大的恐慌聪姿,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,946評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件激率,死亡現(xiàn)場(chǎng)離奇詭異咳燕,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)乒躺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)招盲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人嘉冒,你說(shuō)我怎么就攤上這事曹货∨胤保” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,716評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵顶籽,是天一觀的道長(zhǎng)玩般。 經(jīng)常有香客問(wèn)我,道長(zhǎng)礼饱,這世上最難降的妖魔是什么坏为? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,222評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮镊绪,結(jié)果婚禮上匀伏,老公的妹妹穿的比我還像新娘。我一直安慰自己蝴韭,他們只是感情好够颠,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,223評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著榄鉴,像睡著了一般履磨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上庆尘,一...
    開(kāi)封第一講書(shū)人閱讀 52,807評(píng)論 1 314
  • 那天剃诅,我揣著相機(jī)與錄音,去河邊找鬼驶忌。 笑死综苔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的位岔。 我是一名探鬼主播,決...
    沈念sama閱讀 41,235評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼堡牡,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼抒抬!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起晤柄,我...
    開(kāi)封第一講書(shū)人閱讀 40,189評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤擦剑,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后芥颈,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體惠勒,經(jīng)...
    沈念sama閱讀 46,712評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,775評(píng)論 3 343
  • 正文 我和宋清朗相戀三年爬坑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了纠屋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,926評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡盾计,死狀恐怖售担,靈堂內(nèi)的尸體忽然破棺而出赁遗,到底是詐尸還是另有隱情,我是刑警寧澤族铆,帶...
    沈念sama閱讀 36,580評(píng)論 5 351
  • 正文 年R本政府宣布岩四,位于F島的核電站,受9級(jí)特大地震影響哥攘,放射性物質(zhì)發(fā)生泄漏剖煌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,259評(píng)論 3 336
  • 文/蒙蒙 一逝淹、第九天 我趴在偏房一處隱蔽的房頂上張望耕姊。 院中可真熱鬧,春花似錦创橄、人聲如沸箩做。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,750評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)邦邦。三九已至,卻和暖如春醉蚁,著一層夾襖步出監(jiān)牢的瞬間燃辖,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,867評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工网棍, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留黔龟,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,368評(píng)論 3 379
  • 正文 我出身青樓滥玷,卻偏偏與公主長(zhǎng)得像氏身,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子惑畴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,930評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • >復(fù)雜的組織都是專(zhuān)門(mén)化的 >Catharine R. Stimpson 到目前為止蛋欣,我們已經(jīng)探討過(guò)`CALayer...
    夜空下最亮的亮點(diǎn)閱讀 1,030評(píng)論 0 2
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,341評(píng)論 25 707
  • 最近 除了瑜伽的練習(xí),其他基本處于放松的狀態(tài)如贷。我在觀察著陷虎,思考著。是不是我的世界里僅留給正能量這個(gè)價(jià)值觀-這個(gè)社會(huì)...
    東方沐雪_09ed閱讀 233評(píng)論 0 0
  • 前言 通過(guò)安裝ag和ack.vim杠袱,給vim提供全局搜索代碼的功能 安裝以及配置 安裝Ag 裝好之后尚猿,可以直接在s...
    壞壞的大貓貓閱讀 3,043評(píng)論 0 1
  • 驕陽(yáng)在頭頂笑 麥穗在田里笑 我在風(fēng)中笑 只有遠(yuǎn)處的烏鴉哀叫 風(fēng)中的笑刺痛他的哀叫 他不知道 我只剩微笑
    馬流云閱讀 328評(píng)論 0 2