跳轉至內容

使用 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");

現在玩它,你應該看到魚在你觸碰它們時發生變化。

華夏公益教科書