跳转至内容

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

现在玩它,你应该看到鱼在你触碰它们时发生变化。

华夏公益教科书