4

我想做的是制作一个像泰拉瑞亚这样的标题,只是它的来回摇摆而不是图形方面知道怎么做吗?

所以我想学习如何制作像泰拉瑞亚中显示的标题那样来回摇摆的图像?

对于那些不知道泰拉瑞亚是什么的人来说是这样的。

http://www.youtube.com/watch?v=3K8PMG42l3M

4

2 回答 2

4

徽标似乎在不相等的时间间隔内旋转并改变其大小。

首先,您需要熟悉此方法

SpriteBatch.Draw 方法(Texture2D、Vector2、Nullable、Color、Single、Vector2、Single、SpriteEffects、Single)

参数是:

Texture2D texture,                   // texture of your logo
Vector2 position,                    // where to draw
Nullable<Rectangle> sourceRectangle, // null
Color color,                         // Color.White
float rotation,                      // you will be changing this
Vector2 origin,                      // and this
float scale,                         // also this
SpriteEffects effects,               // SpriteEffects.None
float layerDepth                     // 0

使用这些变量:

float rotation = 0,
    rotationSpeed = 0.002f, // this is how much rotation will change each frame
    maximumAngle = 0.1f,
    minimumAngle = -0.1f,
    rotationDirection = 1,
    scale = 1f, // 1 means 100%, 0.95f = 95%
    scaleChange = 0.005f, // this may seem not much, but it's enough
    maxScale = 1.1f,
    minScale = 0.9f,
    scaleDirection = 1;

只需DrawLogo();输入您的主要Draw()方法。

void DrawLogo()
{
    // these two very similar pieces of code will control scale and rotation

    if (rotationDirection > 0)
    {
        if (rotation < maximumAngle)
            rotation += rotationSpeed;
        else
            rotationDirection = -rotationDirection;
    }
    else
        if (rotation > minimumAngle)
            rotation -= rotationSpeed;
        else
            rotationDirection = -rotationDirection;

    if (scaleDirection > 0)
    {
        if (scale < maxScale)
            scale += scaleChange;
        else
            scaleDirection = -scaleDirection;
    }
    else
        if (scale > minScale)
            scale -= scaleChange;
        else
            scaleDirection = -scaleDirection;


    Texture2d t2d = logoTexture;

    spriteBatch.Draw(t2d,
        centerScreen,            // change this to `new Vector2(123, 456)`
        null,                    // null means draw entire texture
        Color.White,             // no tinting
        rotation,                // the rotation we calculate above
        new Vector2(t2d.Width / 2, t2d.Height / 2),
          // this sets rotation point to the center of the texture

        scale,                   // the scale we calculate above
        SpriteEffects.None,      // you can mirror your texture with this
        0);                      // I usually leave it zero :p
}

这是经过测试并且工作得很好:)

于 2012-12-21T08:28:09.837 回答
3

您的意思是当您在菜单中选择内容时,我们可以在大约 1:16(可能也在其他时间)看到的效果?

概念

据我所知,您可以通过简单的旋转和缩放来做到这一点。因此,如果您不想制作动画 gif(您认为它是),您可以在您的 XNA 代码中完成。使用带有 alpha 通道的 png 或 gif(以便非文本是透明的)。

然后,当您在屏幕上绘制它时,spriteBatch.draw()您可以选择支持缩放旋转的重载之一。

然后你必须设置:

  • 您想要的轮换(随着时间的推移,这将是一个轮换)
  • 原点(到图像的中心)
  • 规模(将随着时间的推移而扩大)

据我记得 XNA将时钟发送到update()方法,我们将不得不在那里更新图像的旋转和缩放。我们需要时钟,因为我们不能只是设置rotaton = 10°,XNA 会为我们处理一切。我们必须自己计算每个时间步的当前旋转。例如,如果一个完整的旋转将持续 10 秒,而 5 秒过去了,那么你知道你有一个半旋转。所以我们会告诉 XNA: Set our rotation to 180° now,在下一个时间步,我们可能会告诉: Set our rotation to 190° now

基本概念是:

  1. 计算我们在当前时间步中做了多少旋转/缩放部分
  2. 告诉 XNA 在这个时间步调整这个旋转/比例
    • 一遍又一遍地重复这两个步骤

执行

我认为最好的做法是使用 sin() 或 cos() 函数进行缩放和旋转。他们的优点:

  • 它们也有正值和负值(所以我们可以很容易地双向旋转)
  • 它们很平滑,这意味着您的旋转和缩放在旋转/缩放结束时看起来不会太突然

我希望我的数学在这里是正确的。我会解释一切,所以如果有问题,其他人可以纠正我。或者您也可以找出是否有问题。我们将在这里使用 sin(),因为它从 0 开始,这在我们的例子中意味着什么都不应该发生。这就是我们想要的:我们想要从什么都没有发生的情况开始。

现在,sin() 的循环时间为 2*PI。当然,我们不希望缩放到持续 2*PI,而是希望达到 1000 毫秒。我们不能改变Math.Sin()C# 中的定义,但是我们可以改变我们抛出的值。因此,当我们的意思是 1000 毫秒时,我们会给出Math.Sin()2PI,当我们的意思是 500 毫秒时,我们会给出 PI。

我们将定义这些成员变量:

// define some variables for rotation and scale speed, in milliseconds 
int fullRotationTime = 1000; // max rotation will be reached after 1 second
float maxRotationAngle = MathHelper.ToRadians(10); // we will rotate by 10 degree up and down
int rotationTimePassed = 0;
float currentRotationAngle = 0;

int fullScaleTime = 1000; // max scale will be reached after 1 second
float maxScaleSize = 1.2f; // we will scale to 20% larger max
int scaleTimePassed = 0;
float currentScaleFactor = 1.0;

在该Update()方法中,我们计算我们已经完成了多少旋转。

protected virtual void Update(GameTime gameTime)
{
    int milliseconds = gameTime.ElapsedGameTime.TotalMilliseconds;

    // these are the milliseconds in the current rotation
    rotationTimePassed += milliseconds;
    scaleTimePassed += milliseconds;

    if (rotationTimePassed >= fullRotationTime)
        rotationTimePassed %= fullRotationTime;
    if (scaleTimePassed >= fullScaleTime)
        scaleTimePassed %= fullScaleTime;


    float rotationTimeAdjustedToTwoPi = ((float)rotationTimePassed)/fullRotationTime * 2* Math.PI);
    currentRotationAngle = maxRotationAngle * Math.Sin(rotationTimeAdjustedToTwoPi);

    // we do not want the scaling to be negative, thus we add 1 to the whole and
    // divide by 2. Then the maximum will be 1 and the minimum 0
    float scaleTimeAdjustedToTwoPi = ((float)scaleTimePassed)/fullScaleTime * 2* Math.PI);
    currentScaleFactor = maxScaleSize * (Math.Sin(scaleTimeAdjustedToTwoPi) + 1)/2;
}

然后,在该Draw()方法中,我们可以取之前计算的值并显示我们旋转和缩放的图像。

protected virtual void Draw()
{
    spriteBatch.Begin();
    spriteBatch.Draw(texture,
        new Vector2(50, 50),
        null,
        Color.White,
        currentRotationAngle,
        new Vector2(texture.width/2, texture.height/2),
        currentScaleFactor,
        SpriteEffects.None,
        0
    );
    spriteBatch.End();
}

它没有经过测试,因此甚至可能存在语法错误,但我至少基本思想应该是正确的,我认为重要的是您了解如何在概念上完成它。

可变时间步长

很容易将user1306322提到的可变时间步长集成到上面的代码中。我们有这些 if 条件,我们检查当前时间片是否结束,如下所示if (rotationTimePassed >= fullRotationTime)

现在我们想让时间片变长,这里只需根据随机数调整一个新的时间片。像这样:

var rand = new Random();

if (rotationTimePassed >= fullRotationTime)
{
    rotationTimePassed %= fullRotationTime;

    // next rotation might take between 0.5 and 2.5 seconds
    fullRotationTime = rand.next(500, 2500);
}
于 2012-12-21T08:25:12.120 回答