iOS開發-iOS粒子發射器開發-iOS粒子動畫下雨下雪天氣動畫開發-CAEmitterLayer粒子發射器-CAEmitterCell粒子開發實踐

本期內容:

  • CAEmitterLayer 粒子發射器(層)
  • CAEmitterCell 粒子
  • 下雨效果
  • 下雪效果
  • 煙火效果
  • 需要注意的屬性疊加
  • 總結以及demo下載

CAEmitterLayer 粒子發射器(層)

簡介:CAEmitterLayer是發射、動畫和渲染粒子系統的層。 是CALayer的一個常用子類,CALayer的子類有很多,如果能很好的使用它們會得到一些意想不到的效果。CAEmitterLayer就是其中之一,CAEmitterLayer是用於實現基於Core Animation的粒子發生器系統。由CAEmitterCell實例定義的粒子被繪製在層的背景顏色和邊框之上。

具體屬性清單:
	// 常用屬性:
     NSArray<CAEmitterCell *> *emitterCells; // 用來裝粒子的數組
     
     CGPoint emitterPosition; 	// 決定了粒子發射形狀的中心點
     CGFloat emitterZPosition;
     CGSize emitterSize; 			// 發射源的尺寸大小
     
     NSString *emitterShape; 		// 發射源的形狀
     NSString *emitterMode; 		// 發射模式
     NSString *renderMode; 		// 渲染模式
     
   // 不常用屬性:
     float birthRate; 			// 粒子產生係數,默認1.0 (可以在Cell裏面賦值)
     float lifetime; 			// 粒子的生命週期係數, 默認1.0 (可以在Cell裏面賦值)
     BOOL preservesDepth;		// 定義該層是否將其子層壓平到其平面。
     CGFloat emitterDepth;		// 確定發射器形狀的深度
     float velocity; 			// 粒子速度係數, 默認1.0 (可以在Cell裏面賦值)
     float scale; 				// 粒子的縮放比例係數, 默認1.0 (可以在Cell裏面賦值)
     float spin; 				// 粒子的自旋轉速度係數, 默認1.0 (可以在Cell裏面賦值)
     unsigned int seed; 		// 隨機數發生器

CAEmitterLayer的使用方式如下:

    // 1.創建CAEmitterLayer
    emitterLayer = [CAEmitterLayer layer];
    
    // 2.設置CAEmitterLayer的屬性(最主要的是前四個)
    // 發射源的形狀 是枚舉類型
    emitterLayer.emitterShape = kCAEmitterLayerLine;
    //    kCAEmitterLayerCircle
    //    粒子從一個以(發射位置)爲中心的圓中發射出來。
    //    kCAEmitterLayerCuboid
    //    粒子從一個相反角的長方體(3D矩形)發射。
    //    kCAEmitterLayerLine
    //    粒子從(發射位置)沿直線發射。
    //    kCAEmitterLayerPoint
    //    粒子從一個點(發射位置)發射出來。
    //    kCAEmitterLayerRectangle
    //    粒子從一個有相對角的矩形發射。
    //    kCAEmitterLayerSphere
    //    粒子從一個以(發射位置)爲中心的球體中發射出來。
    
    // 發射模式 枚舉類型
    emitterLayer.emitterMode = kCAEmitterLayerSurface;
    //    kCAEmitterLayerOutline
    //    粒子從粒子發射器的輪廓發射出來。
    //    kCAEmitterLayerPoints
    //    粒子從粒子發射器上的點發射出來。
    //    kCAEmitterLayerSurface
    //    粒子從粒子發射器的表面發射出來。
    //    kCAEmitterLayerVolume
    //    粒子從粒子發射器中的a位置發射。
    
    // 發射源的size 決定了發射源的大小,如果做了傾斜或者便宜屏幕寬度是不夠的,那時候就需要自定義
    emitterLayer.emitterSize = self.view.frame.size;
    // 發射源的位置
    emitterLayer.emitterPosition = CGPointMake(self.view.bounds.size.width * 0.5, -10);
    // 渲染模式 枚舉類型 (⭐️這個渲染模式表達效果會很不好,不常用,kCAEmitterLayerAdditive,可以讓重疊的部分高亮)
    emitterLayer.renderMode = kCAEmitterLayerAdditive;
    //  kCAEmitterLayerOldestFirst;
    //  kCAEmitterLayerOldestLast;
    //  kCAEmitterLayerBackToFront;
    //  kCAEmitterLayerAdditive;
    
    // 3.添加到目標視圖的layer上
    [self.view.layer addSublayer:emitterLayer];

CAEmitterCell 粒子

簡介:CAEmitterCell類表示CAEmitterLayer對象發出的一個粒子源。 CAEmitterCell定義發射粒子的方向和性質。CAEmitterLayer發射器可以有一系列子粒子,這些子粒子可以讓粒子自己發射粒子,也就是CAEmitterCell也可以發射CAEmitterCell

/**
  具體屬性清單:
  // 常用屬性清單(以空行來劃分使用點):
     NSString *name; 			// 粒子名字, 默認爲nil

     float birthRate; 			// 粒子的產生率,默認0
     float lifetime; 			// 粒子的生命週期,以秒爲單位。默認0
     float lifetimeRange; 		// 粒子的生命週期的範圍,以秒爲單位。默認0
     
     CGFloat emissionLatitude;// 指定緯度,緯度角代表了在x-z軸平面座標系中與x軸之間的夾角,默認0:
     CGFloat emissionLongitude; // 指定經度,經度角代表了在x-y軸平面座標系中與x軸之間的夾角,默認0:
     CGFloat emissionRange; 	//發射角度範圍,默認0,以錐形分佈開的發射角度。角度用弧度制。粒子均勻分佈在這個錐形範圍內;
     
     CGFloat velocity; 			// 速度和速度範圍,兩者默認0
     CGFloat velocityRange;
     CGFloat xAcceleration; 	// x,y,z方向上的加速度分量,三者默認都是0
     CGFloat yAcceleration;
     CGFloat zAcceleration;
     
     CGFloat scale; 			// 縮放比例, 默認是1
     CGFloat scaleRange; 		// 縮放比例範圍,默認是0
     CGFloat scaleSpeed; 		// 在生命週期內的縮放速度,默認是0
     
     CGFloat spin; 				// 粒子的平均旋轉速度,默認是0
     CGFloat spinRange; 		// 自旋轉角度範圍,弧度制,默認是0
     
     CGColorRef color; 			// 粒子的顏色,默認白色
     float redRange; 			// 粒子顏色red,green,blue,alpha能改變的範圍,默認0
     float greenRange;
     float blueRange;
     float alphaRange;
     float redSpeed; 			// 粒子顏色red,green,blue,alpha在生命週期內的改變速度,默認都是0
     float greenSpeed;
     float blueSpeed;
     float alphaSpeed;
     
     id contents; 				// 粒子的內容,爲CGImageRef的對象

     NSArray<CAEmitterCell *> *emitterCells; // 粒子裏面的粒子
     
  // 非常不常用屬性:
     BOOL enabled;
     NSDictionary *style;
     CGRect contentsRect;
     CGFloat contentsScale;
     NSString *minificationFilter;
     NSString *magnificationFilter;
     float minificationFilterBias;
     
     */

CAEmitterCell的使用方式如下:

 // 1. 配置cell
    CAEmitterCell * showCell = [CAEmitterCell emitterCell];
    
 // 2. 設置屬性
    showCell.contents = (id)[[UIImage imageNamed:@"xxx"] CGImage];  // 粒子的內容 是CGImageRef類型的
    
    // 粒子的產生率
    showCell.birthRate = 25.f;
    // 粒子的生命週期,以秒爲單位。
    showCell.lifetime = 100.f;
    // 粒子的生命週期的範圍,以秒爲單位。默認0
    showCell.lifetimeRange = 25.f;
    // 速度,制約粒子生命週期
    // 官方解釋爲:指定時間如何從父時間空間映射到接收者的時間空間。「必需的」
    // 值越大粒子消失的越快
    showCell.speed = 2.f;
    
    // 速度
    showCell.velocity = 20.f;
    // 速度範圍
    showCell.velocityRange = 80.f;
    // 三軸加速度(一般使用Y值)
    showCell.yAcceleration = 90.f;
    //    showCell.xAcceleration = 20.f;
    //    showCell.zAcceleration = 10.f;
    
    // 縮放比列
    showCell.scale = 0.3;
    // 縮放範圍
    showCell.scaleRange = 0.5;
    // 在粒子的生命週期內尺度變化的速度。可以做成動畫。
    showCell.scaleSpeed = 0.02;
    
    // 設置經緯度(方向)(⭐️⭐️需要在 kCAEmitterLayerPoint 的情況下搭配使用)
    //    showCell.emissionLongitude = M_PI; // 上(-M_PI_2) 下(M_PI_2) 左(M_PI) 右(M_PI_4) 通常使用這個
    //    // showCell.emissionLatitude = -M_PI_2; // 前(-M_PI_2) 後(M_PI_2) 左(M_PI) 右(M_PI_4)
    //    // 設置角度,控制發射範圍(受到經緯度的影響)
    //    showCell.emissionRange = M_PI / 6; // 圍繞X軸向左90度
    
    // 設置自轉速度
    showCell.spin = 0.f;
    // 設置自轉方向
    showCell.spinRange = M_PI;
    
    // 設置顏色(⭐️⭐️直接影響到圖片的原有顏色)
    //    snowCell.color = [[UIColor colorWithRed:0.5 green:0.f blue:0.5 alpha:1.f] CGColor];
    // 粒子在三個色相中以及可見度的變化程度
    showCell.redRange = 10.f;
    showCell.greenRange = 20.f;
    showCell.blueRange = 30.f;
    
    showCell.redSpeed = 1.f;
    showCell.greenSpeed = 1.f;
    showCell.blueSpeed = 1.f;
    
    showCell.alphaRange = 0.8;
    showCell.alphaSpeed = -0.1f;
    
 // 3.粒子添加到CAEmitterLayer上
    emitterLayer.emitterCells = @[showCell];

看着代碼很煩人是吧?把我們上面的 emitterLayer 和 showCell 結合在一起,就是一個完整的粒子發射過程了,給大家看看效果:
在這裏插入圖片描述
其實實現的效果非常簡單,但一定要自己去嘗試上面👆代碼中,那些註釋了的東西。

下雨效果

接下來繼續,下雨效果,大家來想想下雨效果是什麼樣子呢?粒子應該從什麼位置發射?應該怎麼配置?
思考結束,我們繼續:

    // 創建粒子發射器圖層
    CAEmitterLayer * rainEmitterLayer = [CAEmitterLayer layer];
    // 設置屬性
    // 發射源的形狀 是枚舉類型  ⭐️因爲是下雨 所以要作爲 直線發射
    rainEmitterLayer.emitterShape = kCAEmitterLayerLine;
    // 發射模式 從表面發射
    rainEmitterLayer.emitterMode = kCAEmitterLayerSurface;
    // 發射源的size 據定了發射源的大小 設定發射器大小爲整個屏幕的大小
    rainEmitterLayer.emitterSize = self.view.frame.size;
    // 發射源的位置 ⭐️因爲是下雨 所以要從屏幕上方往下發射(如果想讓粒子佔據整個屏幕的寬度,設定位置寬度爲視圖的一半)
    rainEmitterLayer.emitterPosition = CGPointMake(self.view.frame.size.width*0.5, -20);
    // 渲染模式,暫不使用 ⭐️很不常用
    
    // 添加到目標視圖的layer上
    [self.view.layer addSublayer:rainEmitterLayer];
    
    // 配置粒子Cell
    CAEmitterCell * rainCell = [CAEmitterCell emitterCell];
    // 設置粒子圖片
    rainCell.contents = (id)[[UIImage imageNamed:@"rain"]CGImage];
    
    // 可以以分組的形式來記憶粒子的設定如下:
    // 組1 ⭐️三個參數缺一不可
    // 設置粒子產生率 每秒 60個 ⭐️粒子產生率可以通過 EmitterLayer 來控制
    rainCell.birthRate = 60.f;
    // 設置粒子生命週期 生命週期 40秒
    rainCell.lifetime = 40.f;
    // 設置粒子持續時間,持續時間制約粒子生命週期
    rainCell.speed = 5.f;
    
    // 組2
    // 設置粒子速度
    rainCell.velocity = 20.f;
    // 設置粒子速度範圍
    rainCell.velocityRange = 100.f;
    // 設置粒子下落加速度 Y軸
    rainCell.yAcceleration = 2000.f;
    
    // 組3 雨圖片需要縮放統一大小 不能使用範圍
    // 設置縮放比例
    rainCell.scale = 0.05f;
//    // 設置縮放範圍
//    rainCell.scaleRange = 0.8f;
//    // 設置粒子存在期間縮放變化的速度
//    rainCell.scaleSpeed = 0.5f;
    
//    // 組4 雨點不需要旋轉
//    // 設置粒子旋轉速度
//    rainCell.spin = 0.5f;
//    // 設置粒子旋轉範圍
//    rainCell.spinRange = M_PI_2;
    
    // 設置粒子顏色 會附和圖片修改圖片顏色
    rainCell.color = [[UIColor whiteColor]CGColor];
    
    // 添加到粒子發射器
    rainEmitterLayer.emitterCells = @[rainCell];

運行效果如下:
在這裏插入圖片描述
我們可以稍加改進,比如綿綿細雨,試想一下,怎麼才能做到往一個方向傾斜的呢?我們正常的加速度是:yAcceleration,用來設置粒子下落加速度(Y軸),如果想要傾斜,我們就加上xAcceleration,也就是X軸加速度。運行效果如下:
在這裏插入圖片描述
這時候新的問題來了,我們會發現,下雨覆蓋不滿屏幕了這是爲什麼呢?之前說了 EmitterLayer 設置屬性有:

①發射源的size 據定了發射源的大小 EmitterLayer.emitterSize 目前我們的size是屏幕寬度,即使我們把雨弄傾斜了,發射源的大小和下落位置的大小還是屏幕寬度,這時候我們就需要調整 EmitterLayer 的父 layer 的 View 的大小了,寬度變成 2 倍。

②發射源的位置 EmitterLayer.emitterPosition,之前我們學習到了如果想讓粒子佔據整個屏幕的寬度,設定位置寬度爲視圖的一半,這時候也同樣。

通過以上兩個步驟,傾斜的雨點就會沾滿整個屏幕了


下雪效果

好了,我們繼續來學習下雪效果,之前下雨效果已經完成了,下雪就很簡單啦,直接上代碼:

    // 設置發射器圖層
    CAEmitterLayer * snowEmitterlayer = [CAEmitterLayer layer];
    // 發射源的形狀 是枚舉類型 ,因爲是下雨 所以要作爲 直線發射
    snowEmitterlayer.emitterShape = kCAEmitterLayerLine;
    // 發射模式
    snowEmitterlayer.emitterMode = kCAEmitterLayerSurface;
    // 發射源的size 據定了發射源的大小
    snowEmitterlayer.emitterSize = self.view.frame.size;
    // 發射源的位置 從屏幕上方往下發射
    snowEmitterlayer.emitterPosition = CGPointMake(self.view.frame.size.width*0.5, -10);
    // 渲染模式,暫不使用
    
    [seslf.view.layer addSublayer:snowEmitterlayer];
    
    // 創建粒子
    CAEmitterCell * snowCell = [CAEmitterCell emitterCell];
    // 設置粒子圖片
    snowCell.contents = (id)[[UIImage imageNamed:@"snow@3x"]CGImage];
    
    // 組1
    // 設置粒子產生率
    snowCell.birthRate = 10.f;
    // 設置粒子生命週期
    snowCell.lifetime = 40.f;
    // 設置粒子持續時間,持續時間制約粒子生命週期
    snowCell.speed = 5.f;
    
    // 組2
    // 設置粒子速度
    snowCell.velocity = 20.f;
    // 設置粒子速度範圍
    snowCell.velocityRange = 100.f;
    // 設置粒子下落加速度 Y軸
    snowCell.yAcceleration = 80.f;
    
    // 組3 雪花圖片 需要縮放大小 使用縮放範圍
    // 設置縮放比例
    snowCell.scale = 0.2f;
    // 設置縮放範圍
    //    snowCell.scaleRange = 0.5f;
    //    // 設置粒子存在期間縮放變化的速度
    //    snowCell.scaleSpeed = 0.5f;
    
    // 組4 雨點不需要旋轉
    // 設置粒子旋轉速度
    //    snowCell.spin = 0.5f;
    //    // 設置粒子旋轉範圍
    //    snowCell.spinRange = M_PI_2;
    
    // 設置粒子顏色 會附和圖片修改圖片顏色
//    snowCell.color = [[UIColor redColor]CGColor];
    
    // 添加到粒子發射器
    snowEmitterlayer.emitterCells = @[snowCell];

運行效果如圖:
在這裏插入圖片描述
開出來很單調是吧?我們來使用幾個屬性,讓下雪變得好看吧:

①設置粒子縮放範圍 snowCell.scaleRange

②設置粒子存在期間縮放變化的速度 snowCell.scaleSpeed

③設置粒子旋轉速度 snowCell.spin

④設置粒子旋轉範圍snowCell.spinRange

如果想設置大雪我們就增加Y軸加速度,圖片展示了以上兩個修改,運行效果如圖:
在這裏插入圖片描述


煙火效果

在上文的學習中,我們看到了CAEmitterCell的特性,即:CAEmitterCell也可以發射CAEmitterCell,現在就來給大傢俱體展示一下:

    // 配置layer
    CAEmitterLayer * fireworksLayer = [CAEmitterLayer layer];
    [self.view.layer addSublayer:fireworksLayer];
    
    // 發射源大小 
    fireworksLayer.emitterSize = CGSizeMake(self.view.layer.bounds.size.width * 0.1, 0.f);
    // 發射位置 在底部向上發射
    fireworksLayer.emitterPosition = CGPointMake(self.view.layer.bounds.size.width * 0.5, self.view.layer.bounds.size.height);
    // 以直線發射
    fireworksLayer.emitterShape = kCAEmitterLayerLine;
    // 在指定位置的表面發射
    fireworksLayer.emitterMode = kCAEmitterLayerSurface;
    // 渲染效果,疊加高亮
    fireworksLayer.renderMode = kCAEmitterLayerAdditive;
    
    // 發射粒子效果
    CAEmitterCell * shootCell = [CAEmitterCell emitterCell];
    shootCell.name = @"shootCell";
    // 粒子產生率 1秒一個
    shootCell.birthRate = 2.f;
    // 粒子存在時間 1.02 上一個銷燬了下一個再發出來
    shootCell.lifetime = 1.02f;
    
    // 粒子速度和速度範圍 默認是發射模式方向的加速度⭐️
    shootCell.velocity = 600.f;
    shootCell.velocityRange = 100.f;
    // Y方向的加速度 模擬重力影響 發射會感受收到向下的阻礙
    shootCell.yAcceleration = 150.f;
    
    // 發射角度範圍 看着更像是到處在放煙火🎆
    shootCell.emissionRange = M_PI * 0.25;
    
    shootCell.scale = 0.05;
    shootCell.color = [[UIColor redColor] CGColor];
    shootCell.greenRange = 1.f;
    shootCell.redRange = 1.f;
    shootCell.blueRange = 1.f;
    shootCell.contents = (id)[[UIImage imageNamed:@"shoot_white"] CGImage];
    // 煙火在發射的過程中自轉
    shootCell.spinRange = M_PI;  // 自轉360度
 
    // 爆炸粒子效果
    CAEmitterCell * explodeCell = [CAEmitterCell emitterCell];
    explodeCell.name = @"explodeCell";
    explodeCell.birthRate = 1.f;
    explodeCell.lifetime = 0.5f;
    explodeCell.velocity = 0.f;
    explodeCell.scale = 2.5;
    explodeCell.redSpeed = -1.5;  //爆炸的時候變化顏色
    explodeCell.blueRange = 1.5; //爆炸的時候變化顏色
    explodeCell.greenRange = 1.f; //爆炸的時候變化顏色
    
    // 火花粒子效果
    CAEmitterCell * sparkCell = [CAEmitterCell emitterCell];
    sparkCell.name = @"sparkCell";
    sparkCell.birthRate = 400.f;
    sparkCell.lifetime = 1.5f;
    sparkCell.velocity = 125.f;
    sparkCell.yAcceleration = 75.f;  // 模擬重力影響
    sparkCell.emissionRange = M_PI * 2;  // 360度
    sparkCell.scale = 1.2f;
    sparkCell.contents = (id)[[UIImage imageNamed:@"star_white_stroke"] CGImage];
    sparkCell.redSpeed = 0.4;
    sparkCell.greenSpeed = -0.1;
    sparkCell.blueSpeed = -0.1;
    sparkCell.alphaSpeed = -0.25;
    sparkCell.spin = M_PI * 2;
    
    // 添加動畫 每個粒子效果 都可以添加後續動畫
    fireworksLayer.emitterCells = @[shootCell];
    // ⭐️粒子添加粒子,再添加粒子,就自動完成了煙火效果
    shootCell.emitterCells = @[explodeCell];
    explodeCell.emitterCells = @[sparkCell];

運行效果如下:
在這裏插入圖片描述


需要注意的屬性疊加

看到上面有【發射源形狀】【發射模式】兩個枚舉類型,在這裏要和大家說一聲,這兩個枚舉類型在使用的時候不好區分而且效果太模糊,給大家看一下運行圖,一共有四種發射模式和六種發射源形狀,大家可以看一下:
在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述


總結

想要做好各種粒子發射動畫,最關鍵的幾個點如下:

layer需要注意的:
// 發射源的形狀 是枚舉類型
emitterLayer.emitterShape = kCAEmitterLayerLine;
// 發射模式 枚舉類型
emitterLayer.emitterMode = kCAEmitterLayerSurface;

cell需要注意的:
// 設置經緯度(方向)(⭐️⭐️需要在 kCAEmitterLayerPoint 的情況下搭配使用)
showCell.emissionLongitude 上(-M_PI_2) 下(M_PI_2) 左(M_PI) 右(M_PI_4) 通常使用這個
showCell.emissionLatitude 前(-M_PI_2) 後(M_PI_2) 左(M_PI) 右(M_PI_4)
// 設置角度,控制發射範圍(受到經緯度的影響)
showCell.emissionRange // 圍繞X軸向左【指定度數覆蓋範圍】發射

鏈接: https://pan.baidu.com/s/1RpD7pOki6Y3eaBREyOfeBA 提取碼: 9ehx

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章