建设官方网站的费用账务处理,石家庄seo推广优化,快递网站策划怎么做ppt,保定网站电话前言
笔者前些天参加完了一场72小时的GameJam游戏开发比赛。这次比赛的主题是“探索”#xff0c;笔者做了一个名为《探索者号》的探索宇宙的游戏#xff08;游戏名一开始叫做《星际拾荒者》#xff0c;但这不重要#xff09;。
在开发过程中#xff0c;笔者遇到了一些问…前言
笔者前些天参加完了一场72小时的GameJam游戏开发比赛。这次比赛的主题是“探索”笔者做了一个名为《探索者号》的探索宇宙的游戏游戏名一开始叫做《星际拾荒者》但这不重要。
在开发过程中笔者遇到了一些问题特此做下记录和分享希望对大家和今后的我有所帮助。
笔者本次的参赛作品在实现路径预测可视化时使用了RK4方法效果还不错
【72小时极限游戏开发挑战赛】探索者号
《探索者号》核心玩法 玩家可以控制飞船加速和转向并可以射击障碍物来保证自身不被撞毁探索7颗星球。玩家的每个操作还有随着时间流逝都会消耗燃料。燃料耗尽后玩家将无法操控飞船但5秒后会消耗生命值来补充一定燃料。玩家每接近一个星球并使用引力弹弓离开时会将燃料加满。生命值耗尽游戏失败。 简而言之就是借助引力弹弓来补充燃料和加速以到达更远距离探索更多星球的目的。
重力场中路径预测可视化
为什么有这种需求
该游戏的难点在于玩家无法凭空推算出或感觉出在飞船靠近行星时应该如何调整自身方向才能保证不撞到星球上并且完成有效的“引力弹弓”动作。 所以笔者希望在游戏中添加一条路径预测的引导线有了这根线将大大降低新人玩家的上手难度。
核心思路
笔者的方法是在飞船对象上附加一个LineRenderer组件利用它来绘制飞船在未来时间点的预测路径。
具体实现方式首先利用当前的飞船速度和所受的引力影响计算出飞船在“下一瞬间”的预期位置并将这个位置设置为LineRenderer的第一个节点。接着基于这个预测位置再计算出飞船在“下下一瞬间”的位置将其设置为LineRenderer的第二个节点。通过重复这一过程我们能够逐步构建出一系列时间点上的飞船位置节点。 通过将这些节点相连形成了一条连续的引导线这条引导线基于飞船的初始速度向量、飞船与行星之间的引力互动、以及它们的相对位置关系。这样在单个渲染帧内我们就能够预测并展示飞船在接下来一段时间内的运动轨迹。
这种可视化的路径预测不仅增强了游戏的互动性和玩家的体验还提供了一个直观的方式来理解和预测物体在复杂重力场中的动态行为。通过这种方法玩家可以更好地规划飞船的航线避免撞到星球优化飞行轨迹。
常规方法
高中物理略。
计算过程 对于每个时间点 i 预测位置 S i S i − 1 U i t 1 2 a i t 2 更新加速度 a i gravityStrength r i 2 更新速度 V i U i − 1 a i t 假设 G × M 为行星的重力强度 g r a v i t y S t r e n g t h \text{对于每个时间点 } i \\ \text{ 预测位置 } S_i S_{i-1} U_it \frac{1}{2}a_it^2 \\ \text{ 更新加速度 } a_i \frac{\text{gravityStrength}}{r_i^2} \\ \text{ 更新速度 } V_i U_{i-1} a_it \\ \\ 假设G×M为行星的重力强度gravityStrength 对于每个时间点 i 预测位置 SiSi−1Uit21ait2 更新加速度 airi2gravityStrength 更新速度 ViUi−1ait假设G×M为行星的重力强度gravityStrength
核心代码 // 目标行星Transformpublic Transform targetPlanet;// 行星重力强度public float gravityStrength;// 路径点数public int pathResolution 50;// 预测路径总时长public float pathPredictTime 5f;private LineRenderer lineRenderer;void Start(){lineRenderer gameObject.AddComponentLineRenderer();lineRenderer.positionCount pathResolution;}void Update(){// 其他运动逻辑// 调用UpdatePath进行路径预测UpdatePath(currentPos, currentVelocity, currentAcceleration);}// 更新路径预测private void UpdatePath(Vector2 currentPos, Vector2 currentVelocity, Vector2 currentAcceleration){// 每一步的时间间隔float t pathPredictTime / pathResolution;for (int i 0; i pathResolution; i){// 使用基本运动方程预测位置Vector2 predictedPos currentPos currentVelocity * t 0.5f * currentAcceleration * t * t;// 将计算的位置设置为轨迹的一部分lineRenderer.SetPosition(i, predictedPos);// 基于新的预测位置计算下一点的重力加速度Vector2 gravityDirection (Vector2)targetPlanet.position - predictedPos;currentAcceleration gravityDirection.normalized * gravityStrength / gravityDirection.sqrMagnitude;// 更新当前位置和速度currentPos predictedPos;currentVelocity currentAcceleration * t;}}RK4方法
Runge-Kutta第四阶RK4算法是一种用于求解常微分方程初值问题的数值方法。给定一个常微分方程 d y d t f ( t , y ) \frac{\mathrm{d} y}{\mathrm{d} t} f(t,y) dtdyf(t,y), 及其初始条件 y ( t 0 ) y 0 y(t_0)y_0 y(t0)y0, RK4方法通过以下步骤来估计在处的值其中 h h h是步长 k 1 f ( t , y ) , k 2 f ( t h 2 , y h 2 k 1 ) , k 3 f ( t h 2 , y h 2 k 2 ) , k 4 f ( t h , y h k 3 ) , y ( t h ) y h 6 ( k 1 2 k 2 2 k 3 k 4 ) . \begin{align*} k_1 f(t, y), \\ k_2 f\left(t \frac{h}{2}, y \frac{h}{2}k_1\right), \\ k_3 f\left(t \frac{h}{2}, y \frac{h}{2}k_2\right), \\ k_4 f(t h, y hk_3), \\ \\ y(t h) y \frac{h}{6}(k_1 2k_2 2k_3 k_4). \end{align*} k1k2k3k4y(th)f(t,y),f(t2h,y2hk1),f(t2h,y2hk2),f(th,yhk3),y6h(k12k22k3k4).
这个过程提供了一种高精度的方式来逼近常微分方程的解通过将整个步长 h h h分为更小的部分并计算在这些部分上的斜率然后将这些斜率的加权平均值用于最终的估计。
应用到游戏中 △ t T n k 1 v v k 1 a a ( p ) k 2 v v k 1 a ⋅ Δ t 2 k 2 a a ( p k 1 v ⋅ Δ t 2 ) k 3 v v k 2 a ⋅ Δ t 2 k 3 a a ( p k 2 v ⋅ Δ t 2 ) k 4 v v k 3 a ⋅ Δ t k 4 a a ( p k 3 v ⋅ Δ t ) v new v ( k 1 a 2 k 2 a 2 k 3 a k 4 a ) ⋅ Δ t 6 p new p ( k 1 v 2 k 2 v 2 k 3 v k 4 v ) ⋅ Δ t 6 a ( p ) g ⋅ r 2 ∥ d ∥ 2 其中 初始位置 p 和速度 v 需要根据游戏中实际情况确定 △ t 每一步的时间间隔 T 总预测时间 n 分辨率对应 L i n e R e n d e r e r 的节点数 k 1... k 4 四组斜率 d 物体到行星中心的向量 g 模拟行星重力强度相当于 G M r 行星半径 ∥ d ∥ 2 d 的平方模长 a 加速度 \begin{align*} \triangle t \frac{T}{n} \\ k1_v v \\ k1_a a(p) \\ k2_v v k1_a \cdot \frac{\Delta t}{2} \\ k2_a a\left(p k1_v \cdot \frac{\Delta t}{2}\right) \\ k3_v v k2_a \cdot \frac{\Delta t}{2} \\ k3_a a\left(p k2_v \cdot \frac{\Delta t}{2}\right) \\ k4_v v k3_a \cdot \Delta t \\ k4_a a(p k3_v \cdot \Delta t) \\ \\ v_{\text{new}} v \frac{(k1_a 2k2_a 2k3_a k4_a) \cdot \Delta t}{6} \\ p_{\text{new}} p \frac{(k1_v 2k2_v 2k3_v k4_v) \cdot \Delta t}{6} \\ \\ a(p) \frac{g \cdot r^2}{\|d\|^2} \\ 其中 \\ 初始位置p和速度v需要根据游戏中实际情况确定 \\ \triangle t每一步的时间间隔 \\ T 总预测时间 \\ n 分辨率对应LineRenderer的节点数 \\ k1...k4 四组斜率 \\ d 物体到行星中心的向量 \\ g 模拟行星重力强度相当于GM \\ r 行星半径 \\ \|d\|^2 d的平方模长 \\ a 加速度 \end{align*} △tk1vk1ak2vk2ak3vk3ak4vk4avnewpnewa(p)其中△tTnk1...k4dgr∥d∥2anTva(p)vk1a⋅2Δta(pk1v⋅2Δt)vk2a⋅2Δta(pk2v⋅2Δt)vk3a⋅Δta(pk3v⋅Δt)v6(k1a2k2a2k3ak4a)⋅Δtp6(k1v2k2v2k3vk4v)⋅Δt∥d∥2g⋅r2初始位置p和速度v需要根据游戏中实际情况确定每一步的时间间隔总预测时间分辨率对应LineRenderer的节点数四组斜率物体到行星中心的向量模拟行星重力强度相当于GM行星半径d的平方模长加速度
核心代码
using UnityEngine;public class PathPrediction : MonoBehaviour
{// 玩家的初始位置和速度public Vector2 initialPosition;public Vector2 initialVelocity;// 表示重力场源的行星public Transform planetTransform;// 行星的重力强度public float planetGravity;// 行星的半径public float planetRadius;// 路径分辨率即路径上的点数public int pathResolution 100;// 预测路径的总时长public float pathPredictTime 5f;private LineRenderer lineRenderer;private void Start(){lineRenderer GetComponentLineRenderer();lineRenderer.positionCount pathResolution;UpdatePathWithRK4();}// 使用RK4算法更新路径private void UpdatePathWithRK4(){Vector2 currentPos initialPosition;Vector2 currentVelocity initialVelocity;float deltaTime pathPredictTime / pathResolution;for (int i 0; i pathResolution; i){// RK4方法的四个步骤Vector2 k1_vel currentVelocity;Vector2 k1_acc CalculateAcceleration(currentPos);Vector2 k2_vel currentVelocity k1_acc * (deltaTime / 2f);Vector2 k2_acc CalculateAcceleration(currentPos k1_vel * (deltaTime / 2f));Vector2 k3_vel currentVelocity k2_acc * (deltaTime / 2f);Vector2 k3_acc CalculateAcceleration(currentPos k2_vel * (deltaTime / 2f));Vector2 k4_vel currentVelocity k3_acc * deltaTime;Vector2 k4_acc CalculateAcceleration(currentPos k3_vel * deltaTime);// 使用四个斜率的加权平均值来更新速度和位置currentVelocity (k1_acc 2f * (k2_acc k3_acc) k4_acc) * (deltaTime / 6f);currentPos (k1_vel 2f * (k2_vel k3_vel) k4_vel) * (deltaTime / 6f);// 更新LineRenderer以显示路径lineRenderer.SetPosition(i, new Vector3(currentPos.x, currentPos.y, 0));}}// 计算给定位置处的加速度考虑重力场的影响private Vector2 CalculateAcceleration(Vector2 position){Vector2 gravityDirection (Vector2)planetTransform.position - position;// 使用万有引力公式计算加速度return gravityDirection.normalized * (planetGravity * Mathf.Pow(planetRadius, 2) / gravityDirection.sqrMagnitude);}
}总结
简单方法
优点 简单直观适用于线性系统或短时间内预测。计算速度快。 缺点 对于非线性系统或需要长时间预测的情况简单的逼近方法可能不够精确尤其是在引力场强烈变化的区域。 RK4方法
优点 精度高适用于复杂的动态系统特别是需要准确模拟物理行为的系统。稳定性强在处理较平滑的动力学问题拥有较高的稳定性。 缺点 与简单方法相比RK4需要在每个时间步长中计算四次斜率这增加了每个时间步的计算负担。实现更复杂不易理解需要更多的编码工作和调试。 本游戏由于场景简单多在路径预测上多花些资源也不算过分于是使用了RK4方法效果如文章开头的视频中所示
实际使用中我们可以根据不同的场景选择更加合适的方法。
大佬们如果有优化思路或者更多实现方式也请多多指点
吉祥话
最后祝大家新年快乐长命百岁