使用 XNA 建立簡單的 3D 遊戲/新增 NPC
外觀
建立其他魚最簡單的方法是複製模型檔案並修改其本地紋理。在我的例子中,我在“Content”/“Models”資料夾中建立了一個名為“OtherFish”的新資料夾,並修改了紋理,使所有紋理都變成橙色而不是藍色。確保新的紋理檔案與之前的紋理檔案同名,並且“內容處理器”設定為“SkinnedModelProcessor”,它將正常工作。
接下來,在你的其他類變數旁邊建立一個新的使用者製作的“ModelRenderer”型別陣列,名為 OtherFishes。
ModelRenderer[] OtherFishes = new ModelRenderer[16];
並在你的 LoadContent() 方法中,與其他語句一起放置以下“for”語句,對它們進行初始化。
//Initialises the NPC fish
currentModel = Content.Load<Model>("Models\\OtherFish\\FishModel");
for (int i = 0; i < OtherFishes.Length; i++)
{
OtherFishes[i] = new ModelRenderer(currentModel);
OtherFishes[i].Translation = new Vector3(0f);//Move it to the centre
}
與我們建立的原始魚一樣,我們需要呼叫每個魚的繪製和更新方法。將以下語句與“FishMen”更新方法呼叫一起放置;
for (int i = 0; i < OtherFishes.Length; i++)
{
OtherFishes[i].Update(gameTime);
}
以及它呼叫繪製時。
for (int i = 0; i < OtherFishes.Length; i++)
{
OtherFishes[i].ModelDraw(GraphicsDevice, cameraPosition, cameraTarget, farPlaneDistance);
}
這涵蓋了顯示魚的常規方面。
建立一個名為“ResetNPCFish”的新方法,如下所示;
//Resets NPC fishes
void ResetNPCFish(int input)
{
Random random = new Random();//Allows for the creation of random numbers
Vector2 Boundarys = new Vector2(14f);//Defines the boundarys of where the fish start
//Rotates the fish so they rotate towards the screen
OtherFishes[input].Rotation.Y = (float)((Math.PI / 180.0) * 180);//Put simply, this will rotate it by 180 degrees
OtherFishes[input].Rotation.Z = (float)((Math.PI / 180.0) * 180);
//Moves the fish into a random position defined by the 'Boundarys' variable
OtherFishes[input].Translation.X = random.Next((int)Boundarys.X * -1, (int)Boundarys.X);
OtherFishes[input].Translation.Y = random.Next((int)Boundarys.Y * -1, (int)Boundarys.Y);
//Moves the fish beyond the viewing horizon
OtherFishes[input].Translation.Z = random.Next((int)farPlaneDistance + 100);
OtherFishes[input].PlayAnimation("Frown");
}
並在你的初始化例程中呼叫它,如下所示。
//Initialises the NPC fish
currentModel = Content.Load<Model>("Models\\OtherFish\\FishModel");
for (int i = 0; i < OtherFishes.Length; i++)
{
OtherFishes[i] = new ModelRenderer(currentModel);
OtherFishes[i].Translation = new Vector3(0f);//Move it to the centre
OtherFishes[i].PlayAnimation("Swim");//Play the default swimming animation
ResetNPCFish(i);
}
如果你運行遊戲,你應該看到 16 條初始化的魚遊過可控魚,除此之外沒有別的。

為了確保魚無限地遊動,請將以下更改新增到“OtherFishes”的更新程式碼中,它將檢查魚在螢幕上的位置,並在需要時重新啟動它。
for (int i = 0; i < OtherFishes.Length; i++)
{
float speed = 0.02f;
OtherFishes[i].Translation.Z -= speed * (float)gameTime.ElapsedGameTime.TotalMilliseconds;
if (OtherFishes[i].Translation.Z < -10f)
ResetNPCFish(i);
OtherFishes[i].Update(gameTime);
}
現在執行它,它將無限地執行。
接下來,我們將新增程式碼,預設情況下讓魚顯示皺眉,當它被玩家撞到時,將魚的皺眉顛倒過來。在“ResetNPCFish”方法的底部新增以下行。
OtherFishes[input].PlayAnimation("Frown");
為了檢查玩家和敵人之間的碰撞,建立以下兩個新方法。
bool CheckCollision(Vector3 PlayerPosition, Vector3 NPCPosition)
{
double DifferenceNeeded = 4;//Feel free to adjust, affects how close the NPC has to be before the expression changes
double X = Difference(PlayerPosition.X, NPCPosition.X);
X *= X;
double Y = Difference(PlayerPosition.Y, NPCPosition.Y);
Y *= Y;
double Z = Difference(PlayerPosition.Z, NPCPosition.Z);
Z *= Z;
if (Math.Sqrt(X + Y + Z) < DifferenceNeeded)
return true;
return false;
}
float Difference(float int1, float int2)
{
if (int1 > int2)
return int1 - int2;
else
return int2 - int1;
}
並將以下內容與其他更新程式碼一起新增。
if(CheckCollision(FishMen.Translation, OtherFishes[i].Translation))
OtherFishes[i].PlayAnimation("Smile");
現在玩它,你應該看到魚在你觸碰它們時發生變化。