使用VisualStudio3D初学者工具包开发应用程序(第2部分,共3部分)

A 几天前 我们讨论了如何使用VisualStudio3D初学者工具包创建一个简单的掷骰子应用程序。  现在我们将通过添加一些动画,使应用程序更进一步。  如果你需要跟上, 这里有一个链接 上一篇博文。

null

让它滚吧,宝贝,滚吧

为了使图形应用程序中的任何对象移动,步骤始终相同:

  1. 设置一些状态(例如布尔标志)以指示动画应该正在运行。如果需要,这也是保存动画的开始位置和时间的好时机。
  2. 在Update方法(在渲染前的每一帧上调用)中,计算对象的位置/旋转/缩放(在3D语言中, 变换 )使用动画开始和当前帧时间之间的时间。还必须确保在动画结束时正确更新状态以停止动画。
  3. 在“渲染方法”(Render method)中,确保将变换正确应用于每个对象。

在本例中,我们将添加一个名为RollDie()的新方法,该方法将设置状态并节省启动时间。我们将使用此方法来计算每个模具滚动结果,但现在让我们只执行一个动画,将模具从1旋转到6。

要创建这个动画,我们需要一组变量来跟踪立方体的变换以及动画时间。我们将创建一个布尔值来表示动画正在运行,一个浮点值来存储动画时间,三个向量来存储立方体的初始、最终和当前旋转。这些向量应为XMFLOAT3类型,以存储偏航、俯仰和滚转旋转(参见下图)。

图片[1]-使用VisualStudio3D初学者工具包开发应用程序(第2部分,共3部分)-yiteyi-C++库

因此,让我们创建这些字段和RollDie()方法。在Game.h中添加以下代码:

ref class Game sealed : public GameBase{    // (snip) other class declarations...        Platform::String^ OnHitObject(int x, int y);    void RollDie();  
private:    std::vector<VSD3DStarter::Mesh*> m_meshModels;    bool m_isAnimationRunning;    float m_animationTime;    DirectX::XMFLOAT3 m_initialRotation;    DirectX::XMFLOAT3 m_currentRotation;    DirectX::XMFLOAT3 m_targetRotation;};

现在,让我们从RollDie()实现开始创建动画。将以下代码添加到Game.cpp:

void Game::RollDie(){    m_initialRotation = m_currentRotation;    m_targetRotation = XMFLOAT3(0.0f, XM_PI, 0.0f); // always rotate to 6    m_animationTime = 0.0f;    m_isAnimationRunning = true;}

RollDie()将通过将mu isAnimationRunning变量设置为true来启动动画。我们需要在Update()方法中添加一些代码来在每一帧旋转立方体。代码如下所示:

void Game::Update(float timeTotalfloat timeDelta){    if (m_isAnimationRunning)    {        m_animationTime += timeDelta;        static const float animationDuration = 0.5f;        float animationProgress = std::min<float>(m_animationTime / animationDuration, 1.0f);        XMVECTOR initial = XMLoadFloat3(&m_initialRotation);        XMVECTOR target = XMLoadFloat3(&m_targetRotation);        XMVECTOR current = initial + animationProgress * (target - initial);        XMStoreFloat3(&m_currentRotation, current);        if (animationProgress >= 1.0f)            m_isAnimationRunning = false;    }}

分解此代码:

  1. 仅当设置了mu isAnimationRunning标志时,才应执行动画。
  2. 首先计算动画开始后的时间(从0到0.5秒)和动画进度(从0到1),即已完成动画的百分比。请注意,进度限制为1.0。
  3. 将初始和目标旋转矢量加载到XMVECTORs中,通过使用 CPU内部函数 .
  4. 使用线性公式执行计算:

当前=初始+进度*(目标-初始)

  1. 将最终计算值存储回m泳currentRotation。
  2. 检查动画是否完成,必要时停止。

动画中的下一步是使用渲染方法中计算的旋转来旋转立方体。为此,请更改Render()方法中的以下代码行:

void Game::Render(){    GameBase::Render();    // (snip) clear...    XMMATRIX transform = XMMatrixRotationRollPitchYawFromVector(XMLoadFloat3(&m_currentRotation));    for (UINT i = 0; i < m_meshModels.size(); i++)    {        m_meshModels[i]->Render(m_graphics, transform);    }    // (snip) MSAA...}

我们调用的方法获取包含横摇、俯仰和偏航的XMVECTOR,并返回与组合变换相对应的旋转矩阵。如果愿意,还可以使用xmmatrixrotationrollpoitchyaw方法,该方法分别获取横摇、俯仰和偏航分量。您甚至可以使用方法来计算每个组件,然后自己将它们相乘–要获得生成变换矩阵的方法的完整列表,请选中此项 MSDN文档页 .

我们现在需要做的就是调用RollDie()方法。让我们在用户点击屏幕时调用它。在DirectXPage::OnTapped方法中将此代码添加到DirectXPage.xaml.cpp文件中:

void DirectXPage::OnTapped(Platform::ObjectsenderTappedRoutedEventArgse){    m_renderer->RollDie();}

如果你现在运行应用程序并点击/点击任何地方,骰子将从1掷到6!

应用程序逻辑:随机数生成器

如果你知道会得到哪个数字,掷骰子就没什么意思了。我们必须使用C运行时库函数添加一个随机数生成器 兰德() ,所以骰子每掷一次都会显示一个不同的数字。

要使用rand(),第一步是使用一些种子值初始化它。如果我们不使用任何值初始化它或使用固定值初始化它,那么每次运行应用程序时生成的数字序列都是相同的,这不是我们希望发生的。在本教程中,我们将使用当前的CPU时间为随机数生成器播种。将以下代码添加到游戏::Initialize()代码:

void Game::Initialize(){    Mesh::LoadFromFile(m_graphics, L"die.cmo", L"", L"", m_meshModels);    srand ((unsigned int) time(NULL));}

您还需要在Game.cpp的开头包含,才能访问time()函数:

#include "pch.h"#include "Game.h"#include <DirectXMath.h>#include <DirectXColors.h>#include <algorithm>#include <time.h>

初始化之后,我们可以使用RollDie()方法中的rand()函数来计算滚动。我们还需要为每个辊正确设置目标模具旋转。为此,替换设置mu targetRotation的行,以便RollDie()方法 看起来像这样:

void Game::RollDie(){    m_initialRotation = m_currentRotation;    int currentRoll = rand() % 6 + 1;    switch (currentRoll)    {        case 1:            m_targetRotation = XMFLOAT3(0.0f, 0.0f, 0.0f);            break;        case 2:            m_targetRotation = XMFLOAT3(0.0f, XM_PIDIV2, 0.0f);            break;        case 3:            m_targetRotation = XMFLOAT3(XM_PIDIV2, 0.0f, 0.0f);            break;        case 4:            m_targetRotation = XMFLOAT3(-1.0f * XM_PIDIV2, 0.0f, 0.0f);            break;        case 5:            m_targetRotation = XMFLOAT3(0.0f, -1.0f * XM_PIDIV2, 0.0f);            break;        case 6:            m_targetRotation = XMFLOAT3(0.0f, XM_PI, 0.0f);            break;    }    m_animationTime = 0.0f;    m_isAnimationRunning = true;}

现在,如果你运行应用程序,我们有我们的动画死亡!你可以在屏幕上的任何地方轻敲来滚动模具。您还可以检查它在捕捉视图上的外观。

让它跳起来!

这个小程序已经很有用了,但是现在我们可以让它变得更有趣。本节将演示如何添加一些天赋,使模具跳跃时,滚动,并添加一些额外的随机旋转看起来更像一个真正的模具。

要添加“跳跃”,我们将向动画中添加另一个变量–垂直(Y)坐标。我们将在骰子滚动时(在Update()方法中)使该值随时间而改变,并将Render()方法更改为将转换应用于立方体。第一步是将转换变量添加到Game.h:

ref class Game sealed : public GameBase{    // (snip) other class declarations...private:    std::vector<VSD3DStarter::Mesh*> m_meshModels;    bool m_isAnimationRunning;    float m_animationTime;    DirectX::XMFLOAT3 m_initialRotation;    DirectX::XMFLOAT3 m_currentRotation;    DirectX::XMFLOAT3 m_targetRotation;    float m_currentTranslationY;};

然后,在Update()方法上使值随时间而改变:

void Game::Update(float timeTotalfloat timeDelta){    if (m_isAnimationRunning)    {        // (snip)        XMVECTOR current = initial + animationProgress * (target - initial);        XMStoreFloat3(&m_currentRotation, current);        const float maxHeight = 2.0f;        m_currentTranslationY = 4.0f * maxHeight * animationProgress * (1 - animationProgress);        if (animationProgress >= 1.0f)            m_isAnimationRunning = false;    }}

对于那些记得高中数学课的人来说,这个函数是一个抛物线方程,极点在0和1,顶点在(0.5,maxHeight)。这将使我们的立方体上下与现实的效果。 您可以在下面的位置看到此函数的图形 新型网络搜索引擎 .

最后一步是在渲染阶段使用计算出的平移来更改立方体的变换。为此,请向Render方法添加以下代码:

void Game::Render(){    // (snip) clear...    m_d3dContext->ClearDepthStencilView( /* (snip) */ );    XMMATRIX transform = XMMatrixRotationRollPitchYawFromVector(XMLoadFloat3(&m_currentRotation));    transform *= XMMatrixTranslation(0.0f, m_currentTranslationY, 0.0f);        for (UINT i = 0; i < m_meshModels.size(); i++)    {        m_meshModels[i]->Render(m_graphics, transform);    }    // (snip) MSAA...}

现在运行应用程序,点击屏幕将产生一个很好的动画与跳跃模具。最后一步,使它看起来更好是添加一些随机旋转每轴每当模具是滚动。为此,我们只需要更改RollDie()方法,以向目标旋转添加一些随机旋转:

void Game::RollDie(){    // (snip) initialization, roll and switch(currentRoll)    XMVECTOR target = XMLoadFloat3(&m_targetRotation);    XMVECTOR current = XMLoadFloat3(&m_currentRotation);    // account for current rotation    target += XMVectorFloor(current / XM_2PI) * XM_2PI;    // add -1, 0 or 1 extra spins    XMVECTOR randomVector = XMLoadFloat3(&XMFLOAT3(rand() % 3 - 1.0f, rand() % 3 - 1.0f, rand() % 3 - 1.0f));    target += randomVector * XM_2PI;    XMStoreFloat3(&m_targetRotation, target);    m_animationTime = 0.0f;    m_isAnimationRunning = true;}

此代码对目标旋转执行两个更改:

  1. 将迄今为止的完整旋转总数添加到目标旋转,使每个旋转相对于上一个旋转,而不是相对于模具的初始状态。
  2. 向目标相对旋转添加-1、0或1个额外的完整旋转。为了做到这一点,我们创建了一个向量,其中三个随机值选择在-1,0和1之间,我们将其乘以2*PI(以弧度为单位的完整旋转)。

还要注意的是,我们再次使用XMVECTORs来加快计算速度,并且能够只编写一个公式,而不是分别为x、y和z分量编写一个公式。

这就完成了我们的应用程序功能。它绝对是经典随机数生成器的一个更有用、更有趣的版本。您可以在上下载此版本 码丛 (下面的互动程序上有直接下载链接)。

图片[2]-使用VisualStudio3D初学者工具包开发应用程序(第2部分,共3部分)-yiteyi-C++库

我们只有几个步骤来完成,以使这个应用程序运行在WindowsRT和WindowsPhone以及!  我们将在第三篇也是最后一篇博文中介绍这些步骤。 敬请期待!

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享