缩放精灵来制造跳跃的视觉效果

3
我有一些代码可以运行,但我感觉它可以更好,想要一些反馈。
我的目标是在按下按钮时,使精灵在时间上进行缩放并恢复原状,以便在游戏的“俯视”视图中给人一种跳跃的错觉。就像角色从屏幕上跳下来一样。我已经知道如何绘制缩放的图像,我更感兴趣的是时间方面的逻辑。
这个代码可以工作,只是不确定它是否最好。想到也许有一些等式,一个数学朋友告诉我可能是线性方程或者像抛物线或二阶方程之类的东西。但我不太擅长数学。
无论如何。
类属性
private double _jumpingStartedAt;
private double _totalJumpTimeInSeconds = 0.7;
private double _totalJumpFrames = 14;
private double _timeSinceLastScale;
private double _jumpingHalfWayAt;

当按钮第一次被按下时,我会启动“跳跃逻辑”。这将在每次跳跃时运行一次。我的想法是标记“开始”时间,并通过totalJumpTimeInSeconds确定“中途”时间。

_jumpingStartedAt = gameTime.TotalGameTime.TotalSeconds;
_jumpingHalfWayAt = _jumpingStartedAt + MillisecondsBetweenFrame() * (_totalJumpFrames / 2);

然后这个操作会在每个Update()上运行,直到我的“跳跃”完成或者isJumping = false。这里的逻辑是我会在每一帧都放大直到一半的位置,然后再缩小。

_timeSinceLastScale += gameTime.ElapsedGameTime.TotalSeconds;
if (_timeSinceLastScale > MillisecondsBetweenFrame() && gameTime.TotalGameTime.TotalSeconds < _jumpingHalfWayAt)
{
     Scale += 0.2f;
     _timeSinceLastScale = 0;
}
else if (gameTime.TotalGameTime.TotalSeconds > _jumpingHalfWayAt)
{
     Scale -= 0.2f;
     if (Scale < 1.0) Scale = 1; //probably don't need this was worried if it went passed 0
     if (Scale == 1.0) _isJumping = false;
}

private double SecondsBetweenFrame()
{
    return _totalJumpTimeInSeconds / this._totalJumpFrames;
}

现在这个方法可以用,但对我来说似乎有些复杂。

1个回答

3

跳跃时图片的拉伸 - 侧面视图

嗯,你创造的东西相当复杂。

我猜想你的精灵在跳跃时也会上下移动。你可能有某种形式的Vector2 velocity,你可以通过每次更新时的dv = gravityAcceleration * dt来改变它,因此你可以通过dp = velocity * dt来改变Vector2 position。如果是这样,我宁愿使用我的velocity.Y值来计算精灵应该如何拉伸。我认为这更自然。而且你的代码会变得更简单。

这里有一张图片更好地描述了我的意思:

Jump

然而,在跳跃开始时,你可能会遇到另一个问题:当精灵还接近地面时,它将突然获得高速度,这可能导致它穿过地面一段时间。为了防止这种情况发生,你可以通过最小必要值人工向上移动你的精灵以进行跳跃。该问题由下面的图片描述:

Floor crossing

正如你可以看到的那样,第一个被拉伸的球向上移动了一点,但不够。你必须计算拉伸前后的大小差异,然后将你的精灵向上移动该距离。

如果你这样做,你的Update应该缩短为只有几行。我相信你可以自己做出简单的计算。


更简单的方法

……除非你更愿意让你的精灵按照的意愿行事。然后你可以根据你的Y位置修改比例:

if (KeyboardState.IsKeyDown(Keys.Space))
{
    isJumping = true;
    jumpStartPosition = Position;        
}

if (!isJumping) Scale = 1f;
else 
{
    Scale = StretchFactor * (Position.Y - jumpStartPosition.Y);
}

其中: - isJumping 是一个布尔值, - jumpStartPosition 是一个 Vector2 类型, - Position 是你的精灵的一个 Vector2 属性, - StretchFactor 是你的精灵的一个 float 属性,表示它的伸缩程度。

此外,你还需要有跳跃结束条件——例如当精灵的 Position.Y 小于 jumpStartPosition.Y。但总体来说,这种解决方案(以及你的方案)都有一个缺点——如果你想从一个高度开始跳跃,并在另一个高度结束,那么就会出现问题:

enter image description here

因此,我更倾向于推荐我的第一个解决方案。在那里,你可以通过碰撞检测来停止跳跃。


跳跃时拉伸图像——俯视图

糟糕,由于最初没有指定它是像早期的GTA那样的俯视游戏,我误解了问题,因此答案不太适合。所以现在重新回答。

如果你想要更加真实,你应该使用一些基本的透视原理。当我们从上面看着角色跳跃时,它向我们靠近,所以它的图像会变大。为什么呢?看下面的图片:

Jump

透视需要两个东西:透视中心和屏幕。透视中心是所有“光线”交汇的点。 “光线”是从世界上的任何点到我们眼睛的中心的线。现在,屏幕是创建3D世界图像的平面。真实世界的点被沿着光线投射到屏幕上。当然,你的游戏是伪3D的,但在这种情况下,这不应该有影响。

z 增加时,精灵接近 透视中心。如果你想象一下从 透视中心精灵边缘 的光线,那么随着它与透视中心的距离变小,光线的角度也会改变。而角度的变化使得点在屏幕上的图像移动。这就是图像变大或变小的原因。

现在我们可以想一下:好的,现在如何用数字来表示呢?看下面的图片:

Perspective

我故意使用-C来翻译整个世界,以使透视中心的z坐标为0。这样可以简化计算。我们要找到的是屏幕上点的x'坐标。让Z* = |z - C|。如果我们看一下这张图片,就会发现我们可以通过相当简单的比例来找到我们需要的东西:
使用相同的方法,您可以计算y'。如果您的角色始终位于屏幕中心,则您所需的所有内容将为x'/x = y'/y = S,即您的比例。这是因为在这种情况下,x实际上是精灵的半宽,而y是半高。但是,如果您的角色能够自由移动屏幕,则可能希望对其进行缩放和平移,以使其更加自然:
白色正方形是地面上的精灵,灰色正方形是跳跃的精灵。在这种情况下,您将需要知道精灵边界的l(左)、r(右)、t(顶部)和b(底部)坐标(顶部-底部表示Y轴,而不是Z轴)。然后使用相同的比例,您可以获得l'r't'b' - 精灵在屏幕上的图像边界。从这些数据中,您应该能够计算出比例和平移。
注意: L是我们计算的参数,您必须自己选择。假设屏幕具有恒定的宽度Ws和高度HsL严格对应于FOV(视野)。您也可以使用比例来获取它。所以L = (cos(FOV/2) * Ws)/2。我建议FOV = 60度。如果您使FOV太大,您可能会面临鱼眼问题

1
你知道这是一个非常好的答案,深入浅出,我给了它一票。虽然我意识到在我的问题中没有明确说明游戏是“俯视”视图,所以我进行缩放是为了营造从上往下看角色跳跃的错觉。就像它从屏幕上脱颖而出一样。通过阅读你的解答,似乎它是为侧向滚动设计的。尽管我喜欢你的重力部分和你对侧向跳跃的解决方案。想知道是否可以使用Z索引来代替Y。如果Z和缩放使其以相同的方式工作,但从上往下看。 - Mastro
好的,那改变了一切 :) 你知道吗,我甚至想过写一个更复杂的跳跃拉伸模型,但后来我想:“一步一步来”。所以我没做。现在,如果它是一个自上而下的游戏,那么精灵的比例确实应该取决于它离地面的“高度”。如果在我沉默了四天之后(抱歉,我很忙),你还没有找到答案,我会在一两分钟内写下来。 - Sushi271
1
这是一个很棒的答案!非常感谢你所付出的努力!我几乎没有注意到你添加了第二部分。你应该为每个部分命名,以便其他人可以找到它们。比如“从侧面视图跳跃”和“从俯视图跳跃”。真是太棒了! - Mastro
嗯,我非常喜欢制作游戏,所以写这个答案纯粹是一种乐趣 :) 谢谢你的建议。我会为每个部分添加标题的。 - Sushi271

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接