當前位置:編程學習大全網 - 編程語言 - 如何使用Unity創建動態2D水體效果

如何使用Unity創建動態2D水體效果

在本教程中,我們將使用壹個簡單的物理機制來模擬壹個動態的2D水體。我們將使用線性渲染器、網格渲染器、觸發器和混合粒子來創建這個水體效果,並最終獲得可以在您的下壹個遊戲中使用的水線和水花。Unity示例源包含在這裏,但是您應該能夠使用任何遊戲引擎根據相同的原理執行類似的操作。

建立壹個水體管理者

我們將使用Unity的線性渲染器來渲染水面,並使用這些節點來顯示連續的波紋。

unity-water-linerenderer(來自遊戲開發)

我們將跟蹤每個節點的位置、速度和加速度。為此,我們將使用數組。因此,下面的變量將被添加到我們的類的頂部:

float[]x位置;

float[]y positions;

浮動[]速度;

浮動[]加速度;

LineRenderer正文;

LineRenderer將存儲我們所有的節點,並勾勒出我們的水體。我們仍然需要水體本身,它將使用網格來創建。我們將需要對象來托管這些網格。

game object[]mesh objects;

Mesh[]網格;

我們還需要對撞機,這樣物體就可以和水體相互作用:

GameObject[]碰撞器;

我們還存儲了所有的常數:

常量浮動彈簧常量= 0.02f

常數浮動阻尼= 0.04f

常浮點差= 0.05f

常量浮點z =-1f;

這些常數中的z是我們為水體設定的z位移。我們會用-1來標記,這樣它就會出現在我們的對象前面(遊戲註意:妳可能要根據自己的需要調整到對象的前面或者後面,那麽妳必須用Z坐標來確定相關向導的位置)。

接下來,我們將保留壹些值:

float baseheight

向左浮動;

浮動底部;

這些是水的維度。

我們將需要壹些可以在編輯器中設置的公共變量。首先,我們將為飛濺使用壹個粒子系統:

公共遊戲對象飛濺:

接下來是我們將用於線性渲染器的材質:

公共材料墊:

此外,我們將對主要水體使用以下網格類型:

公共遊戲對象:

我們想要壹個遊戲對象,可以托管所有這些數據,並使其成為壹個管理器,以產生我們遊戲中的水體。為此,我們將編寫SpawnWater()函數。

該函數將接受水體左側、疾馳、頂點和底部的輸入:

公共void SpawnWater(浮動左、浮動寬、浮動頂、浮動底)

{

(雖然這看似矛盾,但有利於從左到右快速關卡設計。)

創建節點

現在我們將找出我們需要多少個節點:

int edgecount = Mathf。圓點(寬度)* 5;

int node count = edge count+1;

我們將使用每單位寬度5個節點來呈現平滑的移動(妳可以改變這壹點來平衡效率和流暢性)。我們可以由此得到所有的線段,然後需要最後的節點+1。

我們需要做的第壹件事是用LineRenderer組件渲染水體:

Body =遊戲對象。AddComponent & ltLineRenderer & gt();

Body.material = mat

body . material . render queue = 1000;

身體。SetVertexCount(節點計數);

身體。SetWidth(0.1f,0.1f);

這裏我們要做的就是選擇材質,通過選擇渲染隊列中的位置,渲染到水面以上。我們設置正確的節點數據,並將線段寬度設置為0.1。

妳可以根據妳需要的線段的粗細來改變這個寬度。您可能已經註意到,SetWidth()需要兩個參數,它們是線段起點和終點的寬度。我們希望寬度保持不變。

現在我們已經創建了節點,我們將初始化所有的頂級變量:

x positions = new float[node count];

ypositions = new float[node count];

速度=新浮點[節點計數];

accelerations = new float[node count];

mesh objects = new game object[edge count];

meshes =新網格[edge count];

colliders = new game object[edge count];

baseheight = Top

bottom =底部;

左=左;

我們已經擁有了控制數據的所有陣列。

現在我們需要設置數組的值。我們將從節點開始:

for(int I = 0;我& ltnodecounti++)

{

y positions[I]= Top;

x positions[I]= Left+Width * I/edge count;

加速度[I]= 0;

速度[I]= 0;

身體。SetPosition(i,新向量3(xpositions[i],ypositions[i],z));

}

在這裏,我們將所有的Y位置設置在水體上方,然後將所有的節點壹起逐漸增加。因為水面平靜,我們的速度和加速度值最初為零。

我們將通過將LineRenderer (Body)中的每個節點設置到正確的位置來完成這個循環。

創建網格

這是棘手的部分。

我們有自己的線段,卻沒有水體本身。我們將使用網格來制作它,如下所示:

for(int I = 0;我& ltedgecounti++)

{

Mesh[I]= new Mesh();

現在,網格存儲了壹系列變量。第壹個變量非常簡單:它包含所有頂點(或角)。

unity-water-Firstmesh(來自遊戲開發)

圖表顯示了我們需要的網格片段的樣子。標記第壹個剪輯中的頂點。我們總是需要四個頂點。

Vector3[]頂點=新vector 3[4];

頂點[0] =新向量3(x位置[i],y位置[i],z);

頂點[1] =新向量3(x位置[i + 1],y位置[i + 1],z);

頂點[2] =新向量3(x位置[i],底部,z);

頂點[3] =新向量3(x位置[i+1],底部,z);

現在妳可以看到,頂點0在左上角,1在右上角,2在左下角,3在右下角。我們以後要記住。

電網要求的第二個性能是紫外線。網格有紋理,UV會選擇我們要提取的紋理。在這種情況下,我們只需要左上角,右上角,右下角和右下角的紋理。

Vector2[] UVs =新vector 2[4];

UVs[0] =新向量2(0,1);

UVs[1] =新向量2(1,1);

UVs[2] =新向量2(0,0);

UVs[3] =新向量2(1,0);

現在我們又需要這些數據了。網格是由三角形組成的,我們知道任何四邊形都是由兩個三角形組成的,所以現在我們需要告訴網格如何畫這些三角形。

unity-water-Tris(來自遊戲開發)

看有節點順序標簽的角。三角形A連接節點0,1和3,三角形B連接節點3,2,1。所以我們想做壹個包含六個整數的數組:

int[] tris = new int[6] { 0,1,3,3,2,0 };

這就產生了我們的四邊形。現在我們需要設置網格的值。

網格[i]。頂點=頂點;

網格[i]。uv = UVs

網格[i]。三角形= tris

現在我們有了自己的網格,但是我們不在場景中渲染他們的遊戲對象。因此,我們將從watermesh預制部件創建它們,包括網格渲染器和屏幕過濾器。

meshobjects[i] =實例化(watermesh,Vector3.zero,四元數. identity)為GameObject

meshobjects[i]。GetComponent & lt網格過濾器& gt().mesh = meshs[I];

mesh objects[I]. transform . parent = transform;

我們設置了壹個網格,使其成為水體管理器的壹個子項。

制造碰撞效果

現在我們需要自己的對撞機:

colliders[I]= new game object();

對撞機[i]。name = " Trigger

對撞機[i]。AddComponent & ltBoxCollider2D & gt();

colliders[I]. transform . parent = transform;

colliders[I]. transform . position = new vector 3(Left+Width *(I+0.5f)/edge count,Top–0.5f,0);

colliders[I]. transform . local scale = new vector 3(Width/edge count,1,1);

對撞機[i]。GetComponent & ltBoxCollider2D & gt().isTrigger = true

對撞機[i]。AddComponent & lt水檢測器& gt();

在這壹點上,我們制作了方形碰撞器,給它們起了壹個名字,這樣它們在場景中會顯得更整潔,並再次制作了水體管理器的每個子項。我們將它們的位置設置在兩個節點的點上,設置它們的大小,並向它們添加WaterDetector類。

現在我們有了自己的網格,我們需要壹個函數隨著水的流動而更新:

void UpdateMeshes()

{

for(int I = 0;我& lt網格。長度;i++)

{

Vector3[]頂點=新vector 3[4];

頂點[0] =新向量3(x位置[i],y位置[i],z);

頂點[1] =新向量3(x位置[i+1],y位置[i+1],z);

頂點[2] =新向量3(x位置[i],底部,z);

頂點[3] =新向量3(x位置[i+1],底部,z);

網格[i]。頂點=頂點;

}

}

妳可能註意到了,這個函數只使用了我們之前寫的代碼。唯壹不同的是,這次我們不需要設置三角形UV,因為這些還是壹樣的。

我們的下壹個任務是讓水自己流動起來。我們將使用FixedUpdate()來逐步調整它們。

void固定更新()

{

執行物理機制

首先,我們將胡克定律和歐拉方法結合起來,尋找新的坐標、加速度和速度。

胡克定律為F=kx,其中F指水流產生的力(記住,我們將水面模擬為水流),k指水流常數,x為位移。我們的位移將是每個節點的y坐標減去節點的基本高度。

接下來,我們將添加壹個與力的速度成比例的阻尼因子來削弱力。

for(int I = 0;我& ltx定位。長度;i++)

{

浮力=彈簧常數*(位置[I]–基底高度)+速度[I]*阻尼;

加速度[I]=-力;

ypositions[i] +=速度[I];

速度[i] +=加速度[I];

身體。SetPosition(i,新向量3(xpositions[i],ypositions[i],z));

}

歐拉法很簡單,我們只需要給速度加上加速度,把速度增加到每壹幀的坐標上。

註意:我只是假設每個節點的質量是1,但是妳可能想用:

加速度[I]=-力/質量;

現在我們將創建波傳播。以下節點改編自邁克爾·霍夫曼的教程:

float[] leftDeltas =新float[xpositions。長度];

float[] rightDeltas =新float[xpositions。長度];

這裏,我們將創建兩個數組。對於每個節點,我們將檢查前壹個節點的高度和當前節點的高度,並將它們之間的差異放入leftDeltas。

之後,我們將檢查後續節點的高度和當前節點的高度,並將它們之間的差值放入rightDeltas(我們將它乘以壹個傳播常數以增加所有值)。

for(int j = 0;j & lt8;j++)

{

for(int I = 0;我& ltx定位。長度;i++)

{

如果(i & gt0)

{

left deltas[I]= spread *(y positions[I]–y positions[I-1]);

速度[I-1]+= left deltas[I];

}

如果(我& ltx定位。長度–1)

{

right deltas[I]= spread *(y positions[I]–y positions[I+1]);

速度[I+1]+= right deltas[I];

}

}

}

當我們收集了所有的高度數據後,我們終於可以派上用場了。我們看不到最右邊節點的右邊,也看不到最左邊節點的左邊,所以基條件是I >;0和I位置。長度–1 .

因此,請註意,我們在壹個循環中包含了壹段完整的代碼,並運行了8次。這是因為我們希望在少量時間內運行這個過程,而不是大型操作,因為它會削弱流動性。

添加噴霧

現在我們有了流動的水體,下壹步就是讓它飛濺起來!

為此,我們需要添加壹個名為Splash()的函數,該函數將檢查噴霧的x坐標以及它擊中的任何對象的速度。公開它,這樣我們以後就可以在碰撞器中調用它。

公共空隙飛濺(浮動xpos,浮動速度)

{

首先要保證具體坐標在我們水體的範圍內:

if(xpos & gt;= x positions[0]& amp;& ampxpos & lt= xpositions[xpositions。長度-1])

{

然後我們將調整xpos,使其出現在相對於水體起點的位置:

xpos-= x positions[0];

接下來,我們將找到它接觸的節點。我們可以這樣計算:

int index = Mathf。round point((x positions。長度-1)*(xpos/(x positions[x positions。length-1]–x positions[0])));

它是這樣工作的:

1.我們選擇相對於水體左邊緣位置的濺水位置(xpos)。

2.我們將相對於水體的左邊緣來劃分右邊的位置。

這讓我們知道水花在哪裏。例如,位於水體四分之三處的噴霧的值為0.75。

我們將這個數乘以邊數,這樣就可以得到我們飛濺的最近節點。

速度[指數] =速度;

現在我們需要將物體撞擊水面的速度設置為與節點的速度壹致,這樣節點就會被物體拖向深處。

粒子系統(來自遊戲開發)

註意:您可以根據自己的需要更改此線段。例如,您可以將它的速度添加到當前速度,或者使用動量而不是速度,然後除以節點的質量。

現在,我們想做壹個能產生水花的粒子系統。我們之前定義過,叫“飛濺”。務必不要將其與Splash()混淆。

首先,我們應該設置噴霧的參數來調整物體的速度:

浮動壽命= 0.93f + Mathf。Abs(速度)* 0.07f

飛濺。GetComponent & ltParticleSystem & gt().startSpeed = 8+2*Mathf。Pow(Mathf。Abs(速度),0.5f);

飛濺。GetComponent & ltParticleSystem & gt().startSpeed = 9 + 2 * Mathf。Pow(Mathf。Abs(速度),0.5f);

飛濺。GetComponent & ltParticleSystem & gt().startLifetime = lifetime

在這裏,我們需要選擇粒子,設置它們的生命周期,以防止它們在撞擊水面時迅速消失,並根據它們的速度的直角來設置它們的速度(小水花加壹個常數)。

您可能會看著代碼想,“為什麽要設置startSpeed兩次?”妳這樣想沒有錯。問題是我們用的是壹個粒子系統(手裏劍),它的初速度設置為“兩個常數之間的隨機數”。不幸的是,我們沒有太多的方法通過腳本訪問Shuriken,所以為了獲得這種行為,我們必須設置這個值兩次。

  • 上一篇:以口紅為素材的網頁制作-制作網頁詳細操作步驟
  • 下一篇:焊接機器人的弧焊特點
  • copyright 2024編程學習大全網