目录
一、非物理类移动
二、物理类移动
(以下内容涉及示例图内容受GIF帧率影响,不代表真实观感)
一、非物理类移动
①Transform变换相关
- transform.Translate()是非物理移动使用的比较频繁的一种方式,无论是2d还是3d适用范围都比较广,我们根据官方给出的函数结合Input类函数实现前后左右:
public void?Translate?(Vector3?translation,?Space?relativeTo= Space.Self);
/// <summary>
/// 变换移动-V3.?
/// </summary>
void transMove1() {
if (Input.GetKey(KeyCode.W))
{
transform.Translate(Vector3.forward * speed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.S))
{
transform.Translate(Vector3.back * speed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.A))
{
transform.Translate(Vector3.left * speed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.D))
{
transform.Translate(Vector3.right * speed * Time.deltaTime);
}
}
图1-1 GetKey与Translate
缺点:?
整体移动观感较为僵硬,设置Key键代码重复率高,输入受帧率影响
优点:
8向移动较为平滑,I/O反馈及时手感还不错(个人觉得算优点)
- 同样为transform.Translate()方法,不过是将Input.GetKey()改为GetAxis(),官方给出的示例:
public static float?GetAxis?(string?axisName);
如果将轴映射到鼠标,该值会有所不同,并且不会在 -1...1 的范围内。此时,该值为当前鼠标增量乘以轴灵敏度。通常,正值表示鼠标向右/向下移动,负值表示鼠标向左/向上移动。该值与帧率无关;使用该值时,您无需担心帧率变化问题。
/// <summary>
/// 变换移动-V3+Translate
/// </summary>
void transMove2() {
float h = Input.GetAxis("Horizontal") * speed * Time.deltaTime;
float v = Input.GetAxis("Vertical") * speed * Time.deltaTime;
Vector3 thisVec = new Vector3(h, 0, v);
transform.Translate(thisVec);
}
图1-2 ?GetAxis与Translate
缺点:?
无
优点:
有一定的惯性感,同样8向平滑,因为输入方法不受帧率影响手感更好
- transform.position与transform.localPosition的加减
/// <summary>
/// 变换移动-V3+position加减法
/// </summary>
void transMove3(){
if (Input.GetKey(KeyCode.W)) {
transform.localPosition = new Vector3(transform.localPosition.x, transform.localPosition.y, transform.localPosition.z + speed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.D))
{
transform.localPosition = new Vector3(transform.localPosition.x + speed * Time.deltaTime, transform.localPosition.y, transform.localPosition.z);
}
if (Input.GetKey(KeyCode.S))
{
transform.localPosition = new Vector3(transform.localPosition.x, transform.localPosition.y, transform.localPosition.z - speed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.A))
{
transform.localPosition = new Vector3(transform.localPosition.x - speed * Time.deltaTime, transform.localPosition.y, transform.localPosition.z);
}
}
?图1-3 position与localPosition
缺点:?
同第一种较为僵硬,代码量较大
优点:
8向移动较为平滑,相比第一种要更顺畅一些
②Vector向量相关
- SmoothDamp()平滑阻尼的方式,所涉及的参数较多,但效果很好。随时间推移将一个向量逐渐改变为所需目标。向量通过某个类似于弹簧-阻尼的函数(它从不超过目标)进行平滑。 最常见的用法是用于平滑跟随摄像机。其中官方给出的示例:
public static?Vector3?SmoothDamp?(Vector3?current,?Vector3?target, ref?Vector3?currentVelocity, float?smoothTime, float?maxSpeed= Mathf.Infinity, float?deltaTime= Time.deltaTime);
其中参数从左到右分别是:当前位置,目标位置,当前速度,到达目的的时间近似值,最大速度,函数调用时间
/// <summary>
/// v3移动-平滑阻尼
/// </summary>
void v3Move1() {
//vt我设置的是private Vector3 vt = Vector3.zero;
//smoothTime为5
//mousePosition = Input.mousePosition;
transform.position = Vector3.SmoothDamp(transform.position, target, ref vt, smoothTime);
}
?图2-1 SmoothDamp下的摄像机
缺点:?
参数较多,且涉及当前速度参数设置时候较为麻烦
优点:
代码量极少,效果很好,很适合制作摄像机运镜或跟随摄像机的平滑过渡,也可以联系鼠标输入做moba类游戏
- Lerp()线性插值,同样涉及参数较多,且想要好的使用效果需要计算。在两个点之间进行线性插值。使用插值?
t ?在点?a ?和?b ?之间进行插值。参数?t ?限制在范围 [0, 1] 内。这最常用于查找占两个终端之间距离特定百分比的点(例如,以便在这些点之间逐步移动对象),官方给出的示例:
public static?Vector3?Lerp?(Vector3?a,?Vector3?b, float?t);
其中参数从左到右分别是:起始位置,目标位置,当前插值(0~1)。若不理解插值的含义,可以简单参考若插值为0则返回的是V3 a,1则是V3 b,0.5则是V3 (a+b)/2
public Transform startMarker;
public Transform endMarker;
private float startTime;
private float journeyLength; //两点距离
void Start()
{
startTime = Time.time;
journeyLength = Vector3.Distance(startMarker.position, endMarker.position);
}
/// <summary>
/// v3移动-线性插值Lerp
/// </summary>
void v3Move2() {
float distCovered = (Time.time - startTime) * speed; //两点间移动所需要的时间
float fractionOfJourney = distCovered / journeyLength; //帧率与时间换算的百分比值
transform.position = Vector3.Lerp(startMarker.position, endMarker.position, fractionOfJourney);
}
?图2-2 Lerp()线性插值
缺点:?
同样参数较多,且需要计算,用帧率和时间换算的插值较难理解
优点:
比较灵活,可以通过其他条件控制实现一些建议AI或特殊武器的效果
- SLerp()球形插值,涉及参数较多,且想要好的使用效果需要计算。在两个向量之间进行球形插值。在?
a ?和?b ?之间按大小?t ?进行插值。 球形插值与线性插值(也称为“lerp”)的区别在于, 向量被视为方向而不是空间中的点。返回的向量的方向通过角度进行插值, 其?magnitude?在?from ?和?to ?的大小之间进行插值。官方给出的示例:
public static?Vector3?Slerp?(Vector3?a,?Vector3?b, float?t);其参数设置与线性插值一样
/// <summary>
/// v3移动-球型插值SLerp
/// </summary>
void v3Move3() {
Vector3 center = (startMarker.position + endMarker.position) * 0.5F; //圆弧中心点 (a+b)/2
center -= new Vector3(0, 1, 0); //将圆弧中心下移,使弧垂直
//相对于中心点在圆弧上插值
Vector3 riseRelCenter = startMarker.position - center;
Vector3 setRelCenter = endMarker.position - center;
float fracComplete = (Time.time - startTime) / journeyLength; //所需时间除以所经时间得t[0,1]
transform.position = Vector3.Slerp(riseRelCenter, setRelCenter, fracComplete);
transform.position += center;
}
图2-3 SLerp()球形插值
缺点:?
同样参数较多,且需要计算,同时无法修改移动速度,因其插值和两点挂钩
优点:
可以制作一些星球起落或导弹轨迹的效果
二、物理类移动
①刚体力相关
public void?AddForce?(Vector3?force,?ForceMode?mode= ForceMode.Force);
/// <summary>
/// 刚体移动-AddForce()
/// </summary>
void rbMove1() {
float h = Input.GetAxis("Horizontal") * speed; //充当force力
float v = Input.GetAxis("Vertical") * speed;
rb.AddForce(new Vector3(h, 0, v));
}
图3-1 AddForce()移动
缺点:?
若想要好的效果,还需要外加对速度和力的控制条件,且与重量、角速挂钩
优点:
手感观感上都更加真实,参数细节调的好的话体验会非常不错
②刚体速度相关
- rigidbody.Velocity,为刚体添加方向的速度。刚体的速度矢量。它表示刚体位置的变化率。官方给出的示例:
rb.velocity = new Vector3(0, 10, 0);?
isMoving = true;
/// <summary>
/// 刚体移动-Velocity
/// </summary>
void rbMove3()
{
//在大多数情况下,不应该直接修改速度,因为这可能导致行为失真 - 改用 AddForce 请勿在每个物理步骤中设置对象的速度,这将导致不真实的物理模拟。
//需要更改速度的一个典型用法是第一人称射击游戏中的跳跃动作设计,因为此时需要立即更改速度。rb.velocity = new Vector3(0, 10, 0);
Vector3 maxVelocity = new Vector3(30,0,0);
if (Input.GetKeyDown(KeyCode.W)) {
rb.velocity += new Vector3(10, 0, 0); //速度会不断增加,根据需要设置顶峰或停滞
//若等于最大值
if (rb.velocity.Equals(maxVelocity)) {
rb.velocity = new Vector3(0,0,0);
rb.Sleep();
}
}
}?
?图3-2 Velocity模拟赛车加速
缺点:?
同上,需要外加控制
优点:
手感观感上都更加真实,速度变化更舒适可以做赛车竞速类游戏
②刚体方法相关
/// <summary>
/// 刚体移动-MovePosition()
/// </summary>
void rbMove2()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
rb.MovePosition(transform.position + new Vector3(h, 0, v) * speed * Time.deltaTime);
}
?图3-3 MoveToPosition()移动
缺点:?
无(我认为最好用的一个)
优点:
既涉及到质量速度等因素,又可以有很高的帧率,且代码量极少,不断反复还可以明显感受到动态变化的过程
好了如果觉得对你有帮助的话不如给个点赞加关注,如果有问题也欢迎评论或私聊我解决哦。
|