3D遊戲編程與設計作業08

汽車尾氣模擬

情景簡介

衆所周知,汽車在將燃料轉化爲動力時會排放廢氣。我們可以使用粒子系統來給一輛車增加一個排氣口以作爲車輛的裝飾,從而使其更接近現實。

粒子的時間線

  • 汽車尾氣將以很快的速度從排氣管道中冒出來
  • 汽車尾氣與大氣一接觸,速度會迅速減慢
  • 汽車尾氣與大氣接觸後,會擴散開來,變得越來越微弱
  • 由於汽車尾氣是熱的,當它通過周圍較冷的空氣時,它也會略微上升

對於一粒廢氣煙而言:

  • 必須從不大於管道寬度的地方開始
  • 在其短暫的使用壽命內,尺寸會大大增加
  • 在其短暫的使用壽命內,尺寸會大大增加
  • 與空氣混合時,通常會開始部分透明,然後逐漸完全透明
  • 在動力學方面,粒子會很快發射出來,但隨後會很快變慢,還會稍稍向上提升。

粒子製作

  • 圓柱形排氣管

    • Shape模塊中,選擇Cone,並將它的Angle屬性設置爲0,在這種情況下圓錐體cone實際上是一個圓柱形管道
    • 管道的半徑Radius取決於車輛的大小,通常可以利用場景視圖中提供的Gizmo網格線框來匹配兩者的大小
      半徑實際上決定了有關所選特性的許多設置,例如粒子的大小(particle size)和發射速率(emission rate)
    • 在本例中,我們假設車輛遵循Unity的的標準尺寸慣例,即以1米爲1個世界單位(one world unit),因此將半徑設置爲0.05左右(也就是5cm左右)
  • Smoke材料(Material)

    • 在資源商店(Asset Store)中下載並導入資源Standard Assets
    • 將其中的`ParticleSystems拖到Assets目錄下
    • 將ParticleSystems/Prefabs下的Smoke拖入場景視圖中(或者打開其預製進行查看),可以看到其Render模塊中的Material已經設置爲了ParticleSmokeBlack
  • 粒子系統屬性配置

    • Start Lifetime2.5
      一般對於汽車尾氣來說,默認的5秒生存週期過長,因此可以打開粒子系統模塊(該模塊名稱與GameObject同名,本例中爲Smoke)對Start Lifetime進行設置。在本模塊中還將進行以下配置
    • Simulation SpaceWolrd
      通過使用世界模擬空間,即使車輛移動,煙霧也可以繼續縈繞在它產生的地方。
    • Gravity Modifier-0.01(也可以是其他絕對值較小的負數)
      負重力效應使煙霧顆粒上升,從而模擬它們相對於周圍大氣是熱氣體的情景
    • Start Rotation:將其設置爲Random Between Two Constants(在右側的下拉菜單欄中選擇),然後將這兩個常數值設置爲0360
      如此設置將可以使煙霧粒子在發射時隨機旋轉,形成隨機的、不成形的煙霧軌跡的效果,從而更逼真

接下來配置煙霧向外翻滾和消散的效果:

  • 粒子Color over Lifetime模塊

    • 單擊漸變條最右端的上標定(用於設置alpha值),將透明度alpha值設置爲0,由此場景中的煙霧粒子將具有逐漸消失爲0的效果(實際上預製中已配置好了)
      ColorOverLifetime
      事實上,根據發動機的清潔程度,我們往往希望在汽車啓動時降低漸變的alpha值。此外,濃重的黑煙往往表明燃燒不乾淨,效率低下
  • 粒子Size Over Lifetime模塊

    • 打開模塊,選擇曲線並滑動左端的曲線控制柄,使粒子以其完整大小(full size)的一小部分開始,從而使粒子具有逸出時增大的效果
      SizeOverLifetime.PNG
    • Size的選擇取決於排氣管的尺寸(稍大於排氣管尺寸的Size可以使效果更逼真)
    • 可以在場景視圖中進行模擬並調試,以獲得煙霧外觀的良好視覺效果。如果煙霧的擴散程度不足以產生所需的效果,則此時可以增大Particle System模塊中的Start Size

最後,配置當煙散開時減慢速度的效果:

  • 粒子Force Over Lifetim模塊
    • SpaceLocal
    • Z:一個負值,如:-0.75(系統沿對象局部空間的正Z方向發射粒子的情況下,否則則設置正值)

藉助腳本模擬不同場景效果

  • 汽車啓動
  • 汽車運行
  • 汽車停下
  • 汽車故障

思路:如果腳本中有一個表示發動機轉速或車輛速度的變量,則只需將該值乘以一個常數,然後將結果賦給particlesystem的emissionrate屬性。

爲此,我設計了一個簡單的小遊戲以表示各個不同的場景

  • 道路road

    • 下載並導入資源KajamansRoads,自行選用其Free/Prefabs目錄下的一個道路
    • 合理佈置於場景中
  • 汽車Car

    • 下載並導入資源Retro Cartoon Car Cicada

    • 合理佈置於場景中

    • 掛載JoyStick.cs代碼實現虛擬軸控制汽車移動

      //JoyStick.cs
      using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;
      
      public class JoyStick : MonoBehaviour
      {
          private float speedX = 150F;
          private float speedZ = 15F;
      
          // Update is called once per frame
          void Update()
          {
              float translationZ = Input.GetAxis("Vertical") * speedZ;
              float translationX = Input.GetAxis("Horizontal") * speedX;
              translationZ *= Time.deltaTime;
              translationX *= Time.deltaTime;
              transform.Translate(0, 0, translationZ);
              transform.Rotate(0, translationX, 0);
          }
      }
      
    • 設置主相機跟隨,將CameraFollow.cs代碼掛載在Main Camera對象下,並將Car遊戲對象拖動賦值給腳本中的follow

      //CameraFollow.cs
      using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;
      
      public class CameraFollow : MonoBehaviour
      {
          public GameObject follow;            //跟隨的物體
          public float smothing = 5f;          //相機跟隨的速度
          Vector3 offset;                      //相機與物體相對偏移位置
      
          void Start()
          {
              offset = transform.position - follow.transform.position;
          }
      
          void FixedUpdate()
          {
              if (follow != null)
              {
                  Vector3 target = follow.transform.position + offset;
                  //攝像機自身位置到目標位置平滑過渡
                  transform.position = Vector3.Lerp(transform.position, target, smothing * Time.deltaTime);
              }
          }
      }
      
    • 掛載SmokeEmission.cs腳本,實現煙霧粒子發射隨不同場景變化效果

      //SmokeEmission.cs
      //設置煙霧粒子生成地的座標隨汽車座標移動變換
      GameObject smoke = null;
      if (Mathf.Abs(Input.GetAxis("Vertical")) > 0.1 || Mathf.Abs(Input.GetAxis("Horizontal")) > 0.1)
      {
          smoke = Instantiate(Resources.Load<GameObject>("Prefabs/Smoke"), new Vector3(this.gameObject.transform.position.x - 0.635f,
              this.transform.position.y + 0.17f, this.transform.position.z - 1.6f), Quaternion.identity);
          float tranlationZ = Input.GetAxis("Vertical") * speedZ;
          smoke.GetComponent<ParticleSystem>().emissionRate = engineCoeffient * tranlationZ;
      }
      
      ...
      
      //汽車發生故障(與障礙物發生碰撞)後煙霧粒子效果變化以及故障恢復
      float engineCoeffient = 2.5f;
      bool break_down = false;
      int recover_time = 500;
      if (Vector3.Distance(this.gameObject.transform.position, barrier_pos) < 1.5f)
      {
          //car is break down
          break_down = true;
          engineCoeffient = 10;
      }
      if (break_down)
      {
          if (recover_time == 0)
          {
              break_down = false;
              recover_time = 500;
              engineCoeffient = 2.5f;
          }
          else
          {
              recover_time--;
          }
      }
      
  • 障礙物Barrier

    • 下載並導入資源IndustrialEnvironment,自行選用TrafficBarriers/Prefabs目錄下的一個障礙物作爲預製,置於目錄Assets/Resources/Prefabs下
    • 汽車每向前移動100個單位就生成一個障礙物
      //SmokeEmission.cs
      float old_pos_z;
      void Start()
      {
          old_pos_z = this.gameObject.transform.position.z;
      }
      
      void Update() {
      	...
      
      	shift += (this.gameObject.transform.position.z - old_pos_z);
      	        old_pos_z = this.gameObject.transform.position.z;
      	
      	if (shift >= 100)
      	{
      	    barrier_pos = new Vector3(this.gameObject.transform.position.x-1,
      	        this.gameObject.transform.position.y, this.gameObject.transform.position.z + 30);
      	    barrier = Instantiate(Resources.Load<GameObject>("Prefabs/Barrier"), barrier_pos, Quaternion.identity);
      	    shift = 0;
      	}
      	
      	...
      }
      

完整代碼參考——>代碼傳送門

參考資料

潘老師的課程網站
Unity官方汽車模擬教程

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