对推力从当前速度矢量到目标矢量的平滑变化进行编程
TL;dr:“我不确定如何计算一个矢量与另一个矢量之间的推力平滑过渡。”
我正在编写一个简单的游戏,敌人在开放空间(没有墙壁)中追逐玩家。我正在计算敌人的x& y 速度独立,如果它们朝玩家的方向移动,则加速它们;如果它们走错方向,则快速减慢它们(例如 EnemyVelocity.x > 0 & player.x < heavenly.x,然后 EnemyVelocity.x > 0 x - 2.)
虽然尝试躲避敌人的游戏玩法相当有趣,但我希望让敌人使用适当的物理行为。我目前正在做的是让敌人根据他们和玩家之间的角度设置他们的推力(想想宇宙飞船),并让他们的推力加速到最大速度(计算 EnemyVelocity 三角形的 c 边)。一旦发生这种情况,我不确定让推力自行调整的最佳方法。如果我没有保留最大速度,敌人会很好地加速,但很容易超过玩家,然后需要很长时间才能获得足够的动量返回玩家的方向。
我想要发生的是让敌人在接近玩家的路上不断调整他们的速度,瞄准他们所在的任何地方(我不希望他们预测你会在哪里)。然后,当他们想念球员时,我想要同样的推力和压力。加速度公式来重新调整它们的速度并将它们发送回玩家。
我认为这将涉及两个向量:一个是敌人当前正在行进的向量,另一个是敌人想要行进的向量(将把他们直接带到玩家那里的向量)。我不知道如何计算一个矢量与另一个矢量之间的推力的平滑过渡。
任何提示、公式或问题将不胜感激!谢谢堆栈溢出。
TL;dr: "I am not sure how to calculate a smooth transition of thrust between one vector and another."
I am programming a simple game where an enemy chases after the player in an open space (no walls). I was calculating the enemy's x & y velocities independently, accelerating them if they were taking them in the direction of the player and quickly slowing them if they were going the wrong way (e.g. EnemyVelocity.x > 0 & player.x < enemy.x, then EnemyVelocity.x - 2.)
While the gameplay is decently fun trying to dodge the enemy, it is my desire to have the enemy behave using proper physics. What I am currently doing is have the enemy set their thrust (think a spaceship) based on the angle between them and the player, and have their thrust accelerate up to a max speed (calculating side c of the EnemyVelocity triangle). Once that happens, I'm not sure the best way to have the thrust adjust itself. If I leave no max speed, the enemy accelerates nicely but will easily overshoot the player, and then take a long time to get enough momentum heading back in the player's direction.
What I'd like to happen is have the enemy constantly adjust their velocity on the way to the player, targeting wherever they are at (I don't want them to predict where you will be). Then, when they miss the player, I'd like for the same thrust & acceleration formulas to readjust their velocity and send them back at the player.
I'm thinking this will involve two vectors: one where the enemy is currently traveling, and one where the enemy wants to travel (the vector that will take them straight to the player). I am not sure how to calculate a smooth transition of thrust between one vector and another.
Any tips, formulas or questions will be much appreciated! Thank you Stack Overflow.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
这一切都回到牛顿方程:
在这种情况下,
F
是力(推力),a
是加速度,m
是质量船的。s
是当前位置,s_o
是原始位置,v
是速度,t
是当前位置时间。当然,这是沿着一条直线,所以如果你想转换为二维或三维,你必须做一些数学运算。
F
、s
、v
和a
都是向量,这意味着它们的方向同样重要。从技术上讲,t
也是一个向量,但由于时间通常只向一个方向移动,因此我们不必担心这一点。现在,为了将您的速度调整到玩家的方向,您需要一个固定的总力 (
F
) 来更改您当前朝向玩家的速度。在物理学中,事情不会立即发生,但你的目标应该是最小化变化发生的时间(“t”)。这将为您提供一个由您的当前位置 (
(s_o_x,s_o_y)
或(s_o_x,s_o_y,s_o_z)
) 和对手的当前位置或您的目标位置 ((s_x,s_y)
或(s_x,s_y,s_z)
),用于您的目标速度(忽略加速度)。我们可以用这个代替我们的其他方程:
然后我们求解加速度(这与力有关,这就是我们要计算的)。
将其代入力方程:
现在求解
t
:时间应该收敛,因此时间将相等!这为我们提供了每个坐标(平面和球体)的方程组。请注意,有多个可能的值,但有些涉及虚数,因此您必须消除这些解决方案:
求解
(F_x,F_y)
或(F_x,F_y,F_z)< /code> 坐标,你就得到了你需要的力量。
如果您有任何疑问或发现我的数学错误,请告诉我。
It all comes back to Newton's equations:
In this case
F
is the force (thrust),a
is the acceleration, andm
is the mass of the ship.s
is the current location,s_o
is the original location,v
is the velocity, andt
is the current time.Of course this is along a straight line, so if you want to convert to two or three dimensions you'll have to do some math.
F
,s
,v
, anda
are all vectors, meaning that their direction is equally important. Technicallyt
is also a vector, but since time generally only goes one direction, we don't have to worry about that.Now to adjust your velocity to the direction of the player, you've got a fixed total force (
F
) in order to change your current velocity toward the player. In physics things don't happen instantaneously, but your goal should be to minimize the time in which the change happens ('t').This gives you an equation in terms of your current location (
(s_o_x,s_o_y)
or(s_o_x,s_o_y,s_o_z)
) and your opponent's current location or your target location ((s_x,s_y)
or(s_x,s_y,s_z)
), for your target velocity (ignores acceleration).We can substitute this for our other equation:
We then solve for the acceleration (this is related to the force, which is what we are trying to calculate).
Plug this into the force equation:
Now solve for
t
:The times should converge, so the times will be equal! This gives us a system of equations for each coordinate (plane and sphere). Note that there are multiple possible values, but some involve imaginary numbers so you'll have to eliminate those solutions:
Solve for the
(F_x,F_y)
or(F_x,F_y,F_z)
coordinates and you've got the force you need.Let me know if you have any questions or if you find mistakes in my math.
您可以通过确保速度(而不是推力)的平滑变化来获得您想要的效果。这样,如果敌人超过玩家,它可以立即反转其加速度,从而减慢其速度并最终反转其行进方向。
您可以通过在每次迭代期间更改速度来实现此目的,更改的幅度取决于敌人到玩家的距离:
通过独立计算
x
和y
值,您可以省去处理矢量、角度和联立方程的麻烦。同样,通过认识到加速度(推力)只是速度的变化,而速度的变化又是位置的变化,您可以仅使用简单的代数而不是微积分来创建离散时间模拟。
玩得开心!
You may get the effect you want by ensuring a smooth change in velocity, rather than thrust. That way, if the enemy overshoots the player, it can immediately reverse its acceleration, which will slow it down and eventually reverse its direction of travel.
You can accomplish this by changing the velocity during each iteration, by a small amount that's based on the distance from the enemy to the player:
By calculating the
x
andy
values independently, you can save yourself the headache of dealing with vectors, angles, and simultaneous equiations.Similarly, by recognizing that acceleration (thrust) is simply a change in velocity, which in turn is a change in position, you can create a discrete-time simulation using only simple algebra instead of calculus.
Have fun!
你需要用正确的物理术语来思考。您有一个速度,并且想要添加一个加速度。这就是它的全部内容 - 加速度是速度的逐渐变化,它将把敌人拉向玩家,允许其超调,减速(或转向),然后返回玩家。
加速度的测量方式为 d(速度)/时间。您希望在任何时间点向玩家加速,因此每个间隔(秒、百分之一秒或您选择的任何时间)都需要将敌人和玩家之间的向量乘以某个常数,添加到您的速度中。
常数 c 将取决于您想要向玩家加速的速度,以及您更新速度的频率。
如果您想“限制”敌人的最大速度,使其不会无限期地继续增加速度,您也可以这样做。
编辑:为了进一步澄清,添加速度只是意味着添加分量向量。其中
V 是速度,A 是加速度。大小的测量方式为
sqrt(Vx^2 + Vy^2)
,即直角三角形的斜边。所以如果你想让敌人的最大速度为m,You need to think in proper physics terms. You have a velocity, and you want to add an acceleration. That's all there is to it - the acceleration is a gradual change in velocity that will draw the enemy towards to player, allow it to overshoot, slow down (or turn) and then head back towards the player.
Acceleration is measured as d(velocity)/time. You want to accelerate towards the player at any point in time, so every interval (second, hundredth of a second or whatever you choose) you need to add the vector between enemy and player, multiplied by some constant, to your velocity.
Constant c will depend on how fast you want to accelerate towards the player, and how often you are updating your velocity.
If you want to 'cap' the maximum speed of the enemy so that it doesn't continue to increase the magnitude of its velocity indefinitely, you can also do so.
EDIT: to clarify further, adding a Velocity simply means adding the component vectors. So
where V is velocity and A is acceleration. Magnitude is measured as
sqrt(Vx^2 + Vy^2)
, ie the hypotenuse of a right triangle. So if you want maximum speed of the enemy to be m,不久前我写了一个简单的小行星游戏,其中有一艘“盟友”飞船,它会追捕小行星并为你射击。基本上它发现了最近的小行星,然后开始平稳地转向它并追赶它。遗憾的是我不再有代码了,但如果没记错的话,我想我每转都会稍微转动一下船,然后如果小行星很远我就会加速,但如果它很近我会尝试匹配小行星的速度。实际上这很酷,并且至少涉及代数。
最好的方法是采用 2 个弧度值并在它们之间进行 lerp,处理环绕。 (必要时可以添加或减去 2pi)。然后将其转换为单位向量。随后将其乘以您希望船舶加速的速度,就可以了!
I wrote a simple asteroids game a while back that had an "ally" ship which would hunt down asteroids and shoot at them for you. Basically it found the closest asteroid then started smoothly turning towards it and going after it. Sadly i don't have the code anymore but if memory serves, i think i tured the ship a little each turn, then if the asteroid was far away i accelerated but if it was close i tried to match the asteroid's speed. It was pretty cool actually, and a minimum of algebra involved.
The best way to do it would be to take 2 radian values and lerp between them, handling wrapping. (perhaps by adding or subtracting 2pi where necessary). Then convert it to a unit vector. Subsequently multiply that by the speed you want the ship to accelerate, and there you go!
一种简单的方法(不是正确的物理方法)是计算敌人的“所需速度”,然后调整敌人当前的速度,注意其顶部的任何限制或最小速度。
例如,在我编写的一个小 2d 游戏中(http://wordwarvi.sourceforge.net)有“热寻导弹。”如果导弹停在半空中掉头,看起来就很奇怪。所以我所做的如下:我计算朝向玩家的“所需速度”。这只是通过“相似三角形”来完成的。我在 X 和 Y 中找到到玩家的距离,以较大者为准,我将“所需(x 或 y)速度设置为最大可能值,然后缩放另一个速度以适应“相似三角形”。 ,这只是“所需速度”,而不是当前速度,我采用当前速度并将其缓慢(每帧一点点)调整到“所需”速度(尽管所需速度也会按帧重新计算)。在 vx 和 vy 上设置最小值以防止它们在半空中停止
,但它工作正常(没有人抱怨它们太简单、太难或太不切实际。)
编辑:在重新阅读问题时,我的答案可能不是你想要的。
One simple way (not proper physics) is to calculate your enemy's "desired velocity" and then adjust enemy's currently velocity towards that, minding whatever limits on top, or minimum speed it has.
For instance, in a little 2d game I wrote (http://wordwarvi.sourceforge.net) there are "heat seeking missiles." It looks pretty weird if the missiles stop in midair to turn around. So what I did was as follows: I calculate a "desired velocity" which is towards the player. This is just done by "similar triangles". I find the distance to the player in X, and in Y, and whichver is greater, I make the "desired (x or y) velocity be the maximum possible, and then scale the other one to fit the "similar triangle." Note, that's just the "desired velocity," not the current velocity. I take the current velocity and adjust it slowly (by a little bit per frame) towards the "desired" velocity (though the desired velocity is recalculated per frame as well,) mindimg minimums on vx and vy to keep them from stopping mid-air.
Dumb algorithm, but it works ok (nobody's complained that they are too easy, too hard, or too unrealistic.)
Edit: on re-reading the question, my answer is probably not what you're after.
我已经专业地解决过这样的问题,我建议您从简单的版本开始并逐步完善。在尝试下一步之前,请确保每一步都获得预期的行为。
现在,如果您想要一个不能立即转弯但必须弯曲的导引头,事情就会变得棘手......
I've solved problems like this professionally, and I advise you to start with simple versions and work up. Make sure you get expected behavior at each step before you try the next.
Now if you want a seeker that can't turn on a dime, but must curve around, things get tricky...
只需一些提示即可轻松正确地完成此操作。 1)使用向量是最简单、最通用的,而不是把所有内容都写两三次。 2)如果你控制力(实际上是加速度,因为 A=F/质量),然后动态地改变速度和位置,事情看起来就会正确。
真实运动的基本循环看起来像这样(其中 CAP 是向量,dt 是你的时间步长):
实际上,这就是动态进化的情况。
然后你需要决定如何确定你的加速度,即编写
get_acceleration
。这里有很多选择取决于多种因素,而现实生活中的追逐者会采用多种策略。例如,如果相对于您的质量有很大的推力(即高加速度),您可能只想径直冲向目标;但如果你的质量相对于你的推力很大,你可能想要进行拦截航向。如果您想在接近目标时减速,则可以在|X-X_target|
变小时(即它们接近)和/或它们的速度接近时反转加速。此外,阻尼可以帮助物体不振荡,为此,请在加速度中添加一个术语,例如-c*(V-V_target)
。我建议你尝试一下这些,直到你得到与你想要的物理外观和感觉相匹配的东西。There are just a few pointers to get this right and easy. 1) it's easiest and most general to work with vectors rather that writing everything two or three times. 2) things will look right if you control the force (which is effectively the acceleration since A=F/mass) and then dynamically evolve the velocity and position.
Your basic loop for realistic motion looks like (where the CAPs are vectors and dt is your timestep):
And really, this is about it for you're dynamic evolution.
Then you need to decide how to determine your acceleration, i.e. write
get_acceleration
. There are a number of options here that depend on multiple factors, and real-life chasers employ multiple strategies. For example, if you have a lot of thrust relative to your mass (i.e. high acceleration) you probably just want to head straight at the target; but if you have a lot of mass relative to your thrust you probably want to make an interception course. If you want to slow down as you approach the target, you could reverse the acceleration when|X-X_target|
becomes small (i.e. they get close) and/or their velocities are close. Also, damping can help things not oscillate, and for this, add a term to the acceleration something like-c*(V-V_target)
. I suggest you play around with these until you get something that matches the physical look and feel that you're aiming for.