http://www.reibang.com/p/197c2257f597
粒子動(dòng)畫
CAEmitterLayer常用屬性
CAEmitterLayer并不是雜亂無章地發(fā)射粒子的钾菊,它發(fā)射粒子時(shí)的位置,發(fā)射的面積和面積對(duì)應(yīng)的幾何圖形都是可以配置的冰沙,可以是一個(gè)點(diǎn)耘分,或者一個(gè)方形歼培、圓形等等
emitterShape:發(fā)射形狀
是粒子從什么形狀發(fā)射出來毅往,它并不是表示粒子自己的形狀
- kCAEmitterLayerPoint :點(diǎn)
- kCAEmitterLayerLine:線
- kCAEmitterLayerRectangle :矩形
- kCAEmitterLayerCircle:圓形
- kCAEmitterLayerCuboid :正方體
- kCAEmitterLayerSphere : 球
后兩個(gè)是3D效果粒子,避而不談漾稀。
emitterPosition:發(fā)射位置
在粒子圖層上粒子的發(fā)射點(diǎn)(支持隱式動(dòng)畫),決定了粒子發(fā)射形狀的中心點(diǎn)建瘫。
emitterSize:發(fā)射尺寸
決定了粒子發(fā)射形狀的大小崭捍。
我們用kCAEmitterLayerLine來說明一下。當(dāng)你的CAEmitterLayer的emitterSize為CGSize(10暖混, 10)時(shí)缕贡,你的所選擇的emitterPosition為CGPoint(10,10)。那么形狀為“Line”的CAEmitterLayer就會(huì)在如下圖紫色的直線上產(chǎn)生粒子拣播,對(duì)于“Line”來說,emitterSize的高度是被忽略的收擦。
我們可以這樣理解贮配,emitterPosition是所選emitterShape的中心點(diǎn),例如對(duì)于矩形是對(duì)角線交點(diǎn)塞赂,對(duì)于圓形是圓心泪勒,對(duì)于直線是中點(diǎn)。而emitterSize則決定了矩形的大小宴猾,圓形的大小圆存,直線的長(zhǎng)度。這樣說應(yīng)該就夠通俗易懂了仇哆。
emitterCell會(huì)以中心點(diǎn)抽象為一個(gè)點(diǎn)沦辙,在上述區(qū)域內(nèi)出現(xiàn)。
另外讹剔,我們可以將emitterCell的速度相關(guān)的屬性全部設(shè)置為0油讯,你也可以直接注釋掉他們,采用默認(rèn)值延欠,這樣我們將會(huì)得到一些不會(huì)移動(dòng)的粒子陌兑,因?yàn)樗鼈儧]有速度,這樣我們能看清楚CAEmitterLayer的形狀是什么
kCAEmitterLayerPoint:
kCAEmitterLayerLine:
kCAEmitterLayerRectangle:
kCAEmitterLayerCircle
注意:
emitterShape與emitterSize配合使用
如果是kCAEmitterLayerPoint由捎,emitterSize沒有意義兔综。如果是kCAEmitterLayerLine,emitterSize的高度沒有意義狞玛。如果是其余兩種软驰,emitterSize寬高均有意義,如果此時(shí)不設(shè)置emitterSize为居,與kCAEmitterLayerPoint模式效果一樣碌宴。
emitterMode:發(fā)射模式
emitterMode的作用是進(jìn)一步?jīng)Q定發(fā)射的區(qū)域是在發(fā)射形狀的哪一部份,當(dāng)我們看到它的枚舉時(shí)蒙畴,也就能大概了解了贰镣。
- kCAEmitterLayerPoints : 點(diǎn)發(fā)射
- kCAEmitterLayerOutline : 線發(fā)射
- kCAEmitterLayerSurface:面發(fā)射
- kCAEmitterLayerVolume:容積發(fā)射呜象,3D圖形的體內(nèi)
當(dāng)我們選擇Points的時(shí)候,粒子會(huì)從發(fā)射形狀的“頂點(diǎn)”發(fā)射出來碑隆,這里頂點(diǎn)只是一個(gè)簡(jiǎn)單的描述恭陡,有些圖形不能用頂點(diǎn)來描述的,例如對(duì)于圓形來說,“頂點(diǎn)”就是圓心上煤。Outline是指從形狀的邊界上發(fā)射休玩,surface則是從形狀的表面上發(fā)射,Voloume是相對(duì)于3D形狀的“球體內(nèi)”或“立方體內(nèi)”發(fā)射劫狠,關(guān)于3D形狀的問題拴疤,以后再說。
注意:
發(fā)射方式和emitterShape和emitterSize是配合使用的独泞。當(dāng)emitterShape和emitterSize共同描繪出點(diǎn)的時(shí)候呐矾,發(fā)射方式使用點(diǎn)發(fā)射,選線發(fā)射和面發(fā)射無意義懦砂,依然是點(diǎn)發(fā)射的效果蜒犯。當(dāng)emitterShape和emitterSize共同描繪出矩形時(shí),發(fā)射方式選面發(fā)射荞膘,如果選點(diǎn)發(fā)射會(huì)從點(diǎn)發(fā)射罚随,選線發(fā)射同理。
emitterShape與emitterSize與emitterMode共同配合使用羽资。同選點(diǎn)淘菩、線、或者面即可(其實(shí)功能有重疊部分削罩,或可不用全部設(shè)置)
renderModel:渲染模式瞄勾,默認(rèn)值是kCAEmitterLayerUnordered
- kCAEmitterLayerUnordered:無序隨機(jī)的
- kCAEmitterLayerOldestFirst:最新的在上層出現(xiàn)
- kCAEmitterLayerOldestLast:最新的在下層出現(xiàn)
- kCAEmitterLayerBackToFront :由下層向上層涌動(dòng)
- kCAEmitterLayerAdditive :疊加顯示
渲染模式就是當(dāng)新的Cell出現(xiàn)的時(shí)候,該圖層是在上一個(gè)Cell的上面還是下面弥激。Additive為疊加模式进陡,疊加的位置顏色會(huì)變重。
CAEmitterCell常用屬性
CAEmitterLayer決定了粒子系統(tǒng)的發(fā)射位置微服,致于怎么讓粒子本身酷炫起來趾疚,就需要CAEmitterCell的幫助。
(1)lifetime
粒子在系統(tǒng)上單純的存在時(shí)間以蕴,單位是秒糙麦,時(shí)間到了粒子即會(huì)消失。
(2)lifetimeRange
以lifetime為基準(zhǔn)的時(shí)間跨度丛肮,單位是秒赡磅。即粒子存在的時(shí)間為lifetime為中心點(diǎn),以lifetimeRange為跨度的隨機(jī)數(shù)宝与,它可以配合lifetime來讓粒子生命周期均勻變化焚廊,以便可以讓粒子的出現(xiàn)和消失顯得更加離散冶匹。
例如當(dāng)lifetime=5,lifetimeRange=4時(shí),實(shí)際的粒子存在時(shí)間為3-7秒咆瘟。
(3)birthRate
粒子產(chǎn)生數(shù)量的決定參數(shù),它表示CAEmitterLayer上每秒產(chǎn)生的粒子數(shù)量嚼隘,birthRate是一個(gè)浮點(diǎn)數(shù),即為0.1時(shí)表示每十秒產(chǎn)生一個(gè)粒子袒餐。
(4)contents
contents為cell的內(nèi)容飞蛹,類型為id,通常使用圖片灸眼。用顏色創(chuàng)建圖片的方法如下卧檐。
-(UIImage*)imageWithColor:(UIColor*)color andSize:(CGSize)size
{
UIGraphicsBeginImageContext(size);
CGContextRef context=UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, color.CGColor);
CGRect rect=CGRectMake(0, 0, size.width, size.height);
UIBezierPath*bezierPath=[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:size.width/2.0];
CGContextAddPath(context, bezierPath.CGPath);
CGContextFillPath(context);
CGContextSetFillColorWithColor(context, color.CGColor);
UIImage*theImage=UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return theImage;
}
同樣contents也可以直接使用切圖,代碼如下:
emitterCell.contents = (__bridge id _Nullable)[[UIImage imageNamed:@"imageName"] CGImage];
使用bridge橋接NS類與CF類幢炸。
注意:contents不能為空泄隔,不能使用圖片名不存在的圖片。且圖片大小決定cell的初始大小宛徊。
(5)color
color作為cell的背景色,與contents配合使用逻澳。
如果contents的顏色以[UIColor colorWithRed:1 green:1 blue:1 alpha:1]來創(chuàng)建闸天,并且我們cell的color傳入[UIColor colorWithRed:0.5 green:1 blue:1 alpha:1],那么最終顏色為[UIColor colorWithRed:0.5 green:1 blue:1 alpha:1]斜做。
同樣如果使用藍(lán)色的contents圖片苞氮,黃色的color,最終會(huì)得到綠色圖片瓤逼。
color和contents共同作用得出最終顏色笼吟。所以當(dāng)使用contents圖片控制cell時(shí),color使用白色霸旗;當(dāng)使用color控制cell時(shí)贷帮,contents使用純白色圖片(whiteColor,不可使用clearColor)诱告。
(6)redRange撵枢,greenRange,blueRange
用于隨機(jī)生成顏色精居,該屬性為粒子生成時(shí)的顏色的容差范圍锄禽,值為0~1。
例如redRange為0.1靴姿,那么當(dāng)你的粒子的color對(duì)應(yīng)的rgb為(10沃但,255,255)佛吓。那么在其它值取默認(rèn)值的前提下宵晚,這個(gè)粒子在CAEmitterLayer上發(fā)射出來的時(shí)候垂攘,它的rgb中的red component會(huì)均勻分布在 10正負(fù)0.1*255之間,即[0坝疼,35]搜贤,顏色值不能為負(fù)。
(7)redSpeed钝凶,greenSpeed仪芒,blueSpeed
用于顏色逐步變化,屬性為粒子顏色的變化速度耕陷,它的取值范圍也是0~1掂名。表示每秒鐘的顏色變化率,乘以粒子生命周期即為變化范圍哟沫。
例如你的粒子的顏色是rgb(0饺蔑,255,255)嗜诀,并且你的粒子的redRange也為0 猾警,這表示你的粒子被發(fā)射出來的時(shí)候,它的顏色值中的紅色值總是為0 隆敢。你的粒子的生命周期lifetime為10发皿,即粒子可以存在10秒,10秒后會(huì)從layer上移除拂蝎。那么當(dāng)你的redSpeed取值為0.1時(shí)穴墅,你將會(huì)看到你的粒子的紅色值每秒增加0.1*255,這個(gè)過程是連續(xù)不斷變化温自,外觀上看就是你的粒子越來越接近白色玄货。當(dāng)粒子到達(dá)生命結(jié)束的時(shí)候也就是10秒的時(shí)候,你的粒子的顏色也恰好變成了rgb(255,255,255)悼泌。
(8)alphaRange和alphaSpeed
同(6)松捉、(7),控制透明度的初始范圍和變化速率券躁,可以通過此屬性控制粒子的漸隱漸現(xiàn)惩坑。
(9) emissionLongitude
emissionLongtitude決定了粒子飛行方向跟水平坐標(biāo)軸(x軸)之間的夾角,默認(rèn)是0也拜,即沿著x軸向右飛行以舒。順時(shí)針方向是正向,例如emissionLongtitude為0 慢哈,則粒子順著x軸飛行蔓钟,如果你想讓你的粒子發(fā)射出來后,沿著y軸向下飛行卵贱,那么emissionLongtitude就應(yīng)該設(shè)置為PI/2滥沫。即90度侣集,正如我所說的那樣,順時(shí)針方向是正方向兰绣。如果你想讓你的粒子沿著y軸向上飛行世分,你可以將emissionLongtitude設(shè)置為 3*PI/2也可設(shè)置為 -PI/2。下圖就簡(jiǎn)單展示了emissionLongtitude的幾個(gè)典型取值缀辩,圖中綠色箭頭所指的方向就是當(dāng)emissionLongtitude為箭頭對(duì)應(yīng)角度時(shí)的粒子飛行方向:
(10)emissionRange
emissionRange則決定了粒子的發(fā)散范圍臭埋,同樣是一個(gè)弧度值(radians),表示粒子在沿著emissionLongtitude方向所形成的頂角為2倍emissionRange的圓錐范圍內(nèi)發(fā)散臀玄。我們看例圖:我們把emisstionLongtitude設(shè)置為-PI/2瓢阴,讓粒子向上飛行,并且讓emissionRange為PI/4健无。那么按照上面的說法荣恐,我們應(yīng)該能得到一個(gè)向上的,并且頂角為2 * PI/4的圓錐累贤,結(jié)果應(yīng)該如下圖:
(11) emissionLatitude
粒子Z軸上的發(fā)射角度叠穆,用于三維立體效果,可以不做設(shè)置臼膏。與emissionLongitude原理相同痹束,默認(rèn)為0,在平面上向下讶请,為PI時(shí)向上。為PI/2是垂直屏幕向外屎媳,3*PI/2時(shí)垂直屏幕向里夺溢,在屏幕上表現(xiàn)為粒子不動(dòng)。
emissionLatitude的值為與平面的夾角烛谊,當(dāng)存在值時(shí)风响,我們所看到的粒子運(yùn)動(dòng)距離實(shí)際上為該邊長(zhǎng)在平面上的垂直投影(直角邊),小于velocity與lifeTime的乘積(斜邊)丹禀。
emissionRange的值可能也作用于emissionLatitude状勤,這樣所得出的粒子出沒區(qū)域不再是單純扇形(擁有更大的角度,更短的半徑)双泪,更具有離散性持搜。
(12)velocity
粒子的運(yùn)動(dòng)速度,配合lifeTime得出粒子活動(dòng)區(qū)域焙矛。默認(rèn)為0葫盼,即粒子不運(yùn)動(dòng)。
velocity可以為負(fù)值村斟,即沿反方向移動(dòng)贫导。
(13)velocityRange
粒子運(yùn)動(dòng)速度范圍抛猫。例如當(dāng)velocity為100,velocityRange為200時(shí)孩灯,最終速度范圍為0~200闺金。
(14)xAcceleration yAcceleration zAcceleration
這3個(gè)屬性分別定義了3個(gè)坐標(biāo)軸上的加速度,它們代表了不同坐標(biāo)軸方向上的每秒的速度增量峰档,與物理學(xué)上保持一致败匹。即當(dāng)加速度為正數(shù)時(shí)加速,為負(fù)數(shù)時(shí)減速面哥,當(dāng)速度減為負(fù)數(shù)時(shí)反向加速移動(dòng)哎壳。
(15)spin,spinRange
粒子的自轉(zhuǎn)尚卫。粒子的自轉(zhuǎn)是以弧度制來計(jì)算的归榕,表示每秒鐘粒子自轉(zhuǎn)的弧度數(shù),2PI為每秒自轉(zhuǎn)一周。例如你的粒子的生命周期就是10秒吱涉,那么你想讓你的粒子在10秒內(nèi)剛好自轉(zhuǎn)1周刹泄,那么spin為2PI/10。另外怎爵,當(dāng)spin為正數(shù)的時(shí)候特石,粒子是順時(shí)針旋轉(zhuǎn)的,為負(fù)數(shù)的話就是逆時(shí)針選轉(zhuǎn)了鳖链。 spinRange就不多說了姆蘸,跟其它range的意義和作用是一樣的,讓自轉(zhuǎn)速度離散芙委。
(16)scale逞敷,scaleRange,scaleSpeed
粒子的縮放灌侣。scale與scaleRange的值為0~1推捐,可以更改粒子初始的大小。scaleSpeed表示粒子的變化速率侧啼,與以上其他屬性含義相同牛柒。
(17)subCell
可以指定一個(gè)subcell作為cell的cells列表成員,完成粒子在完成動(dòng)畫消失時(shí)開始下一個(gè)動(dòng)畫痊乾。
一個(gè)簡(jiǎn)單的下雨動(dòng)畫代碼
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self addSubview:self.backgroundImageView];
self.backgroundColor = [UIColor clearColor];
self.layer.masksToBounds = YES;
dispatch_async(dispatch_get_main_queue(), ^{
[self.layer addSublayer:self.emitter];
});
}
return self;
}
- (UIImageView *)backgroundImageView
{
if (!_backgroundImageView) {
_backgroundImageView = [[UIImageView alloc] initWithFrame:self.bounds];
_backgroundImageView.image = [UIImage imageNamed:@"bg_rain"];
}
return _backgroundImageView;
}
- (CAEmitterLayer *)emitter
{
if (!_emitter) {
_emitter = ({
CAEmitterLayer *emitter = [CAEmitterLayer layer];
emitter.backgroundColor = [UIColor clearColor].CGColor;
emitter.emitterPosition = CGPointMake(self.bounds.size.width, -40);
emitter.emitterSize = CGSizeMake(self.bounds.size.width * 1.5, 80);
emitter.emitterMode = kCAEmitterLayerSurface;
emitter.emitterShape = kCAEmitterLayerRectangle;
CAEmitterCell *midEmitterCell = [self midEmitterCell];
CAEmitterCell *smallEmitterCell = [self smallEmitterCell];
CAEmitterCell *largeEmitterCell = [self largeEmitterCell];
//add the cell to the emitter layer
emitter.emitterCells = @[ midEmitterCell, smallEmitterCell, largeEmitterCell ];
emitter;
});
}
return _emitter;
}
- (CAEmitterCell *)largeEmitterCell
{
CAEmitterCell *emitterCell = [CAEmitterCell emitterCell];
emitterCell.contents = (id)[[UIImage imageNamed:@"rain_large"] CGImage];
emitterCell.name = @"rain_large";
UIColor *color = [UIColor colorWithWhite:1.0 alpha:1.0];
emitterCell.color = color.CGColor;
emitterCell.birthRate = LargeRainrate;
emitterCell.lifetime = lifeTime(2.1);
emitterCell.lifetimeRange = 0;
emitterCell.velocity = 150;
emitterCell.velocityRange = 50;
emitterCell.emissionLongitude = 2;
emitterCell.emissionRange = 0;
emitterCell.xAcceleration = -1;
emitterCell.yAcceleration = 20;
emitterCell.alphaRange = 0.8;
emitterCell.alphaSpeed = 0.1;
emitterCell.scale = 0.6;
emitterCell.scaleRange = 0.2;
emitterCell.scaleSpeed = 0.0;
CAEmitterCell *subCell = [self waterCirleCell];
emitterCell.emitterCells = @[ subCell ];
return emitterCell;
}
- (CAEmitterCell *)midEmitterCell
{
CAEmitterCell *emitterCell = [CAEmitterCell emitterCell];
emitterCell.contents = (id)[[UIImage imageNamed:@"rain_mid"] CGImage];
emitterCell.name = @"rain_mid";
UIColor *color = [UIColor colorWithWhite:1.0 alpha:1.0];
emitterCell.color = color.CGColor;
emitterCell.birthRate = MidRainrate;
emitterCell.lifetime = lifeTime(2.0);
emitterCell.lifetimeRange = 0;
emitterCell.velocity = 150;
emitterCell.velocityRange = 50;
emitterCell.emissionLongitude = 2;
emitterCell.emissionRange = 0;
emitterCell.xAcceleration = -1;
emitterCell.yAcceleration = 25;
emitterCell.alphaRange = 0.8;
emitterCell.alphaSpeed = -0.1;
emitterCell.scale = 0.6;
emitterCell.scaleRange = 0.2;
emitterCell.scaleSpeed = 0.0;
return emitterCell;
}
- (CAEmitterCell *)smallEmitterCell
{
CAEmitterCell *emitterCell = [CAEmitterCell emitterCell];
emitterCell.contents = (id)[[UIImage imageNamed:@"rain_small"] CGImage];
emitterCell.name = @"rain_small";
UIColor *color = [UIColor colorWithWhite:1.0 alpha:1.0];
emitterCell.color = color.CGColor;
emitterCell.birthRate = SmallRainrate;
emitterCell.lifetime = lifeTime(2.0);
emitterCell.lifetimeRange = 0;
emitterCell.velocity = 200;
emitterCell.velocityRange = 50;
emitterCell.emissionLongitude = 2;
emitterCell.emissionRange = 0;
emitterCell.xAcceleration = -1;
emitterCell.yAcceleration = 30;
emitterCell.alphaRange = 0.6;
emitterCell.alphaSpeed = -0.2;
emitterCell.scale = 0.6;
emitterCell.scaleRange = 0.2;
emitterCell.scaleSpeed = 0.0;
return emitterCell;
}
- (CAEmitterCell *)waterCirleCell
{
//create new emitter cell
CAEmitterCell *emitterCell = [CAEmitterCell emitterCell];
emitterCell.beginTime = lifeTime(2.05);
//粒子圖片
emitterCell.contents = (__bridge id _Nullable)[[UIImage imageNamed:@"circle_small"] CGImage];
//粒子源名稱
emitterCell.name = @"circle_small";
//get the particles start color
UIColor *color = [UIColor whiteColor];
emitterCell.color = color.CGColor;
//copy all the settings to the emitter cell
//產(chǎn)生速率
emitterCell.birthRate = 1;
//生命周期
emitterCell.lifetime = 2.4;
//透明度
emitterCell.alphaRange = 0.8;
//透明度變化速度
emitterCell.alphaSpeed = -0.3;
//縮放
emitterCell.scale = 0.4;
emitterCell.scaleRange = 0.3;
emitterCell.scaleSpeed = 0.4;
return emitterCell;
}