之前左右游戏的时候有需要实现模拟物体漂浮的功能的,所以写了一个简单的物体漂浮的算法,使用正弦函数和余弦函数去控制物体的偏移量,这样就能实现物体绕着原点漂浮的感觉。
首先我们需要设置一个最大偏移量offset和振动频率frequency。
public Vector3 offset;
public float frequency;
然后我们还需要记录物体的原始坐标即原点originPosition,用于计算当前时间量的tick值(可以理解成函数坐标轴的x值),物体的振幅(根据我们设定的frequency计算)和用于控制物体漂浮动画的animate值。
private Vector3 originPosition;
private float tick;
private float amplitude;
private bool animate;
在Awake方法中对各个属性进行赋值,然后在FixedUpdate方法中进行计算:
void Awake()
{
// 如果没有设置频率或者设置的频率为0则自动记录成1
if (Mathf.Approximately(frequency, 0))
frequency = 1f;
originPosition = transform.localPosition;
tick = Random.Range(0f, 2f * Mathf.PI);
// 计算振幅
amplitude = 2 * Mathf.PI / frequency;
animate = false;
}
void FixedUpdate()
{
if (animate)
{
// 计算下一个时间量
tick = tick + Time.fixedDeltaTime * amplitude;
// 计算下一个偏移量
var amp = new Vector3(Mathf.Cos(tick) * offset.x, Mathf.Sin(tick) * offset.y, 0);
// 更新坐标
transform.localPosition = originPosition + amp;
}
}
由于需求是针对UI的,所以Z轴上不需要做位移,这里可以根据需求进行修改。我们还可以设置一个是否自动播放的变量,并在Awake方法中将其赋值给animate:
public bool playAwake;
void Awake()
{
animate = playAwake;
}
最后写两个简单的播放和停止的方法:
public void Play()
{
transform.localPosition = originPosition;
animate = true;
}
public void Stop()
{
transform.localPosition = originPosition;
animate = false;
}
这里直接在停止时将物体移动到原点,如果需要更顺畅的动画的话,我们可以在停止时在停止的位置点和原点之间做一个插值动画来让物体慢慢飘回原点。
将脚本挂载到物体上后进行编辑:
设置不同的合适的偏移量和频率还可以达到远近景的效果。
运行效果:
完整代码:
FloatingObj.cs:
using UnityEngine;
public class FloatingObj : MonoBehaviour
{
public Vector3 offset;
public float frequency;
public bool playAwake;
private Vector3 originPosition;
private float tick;
private float amplitude;
private bool animate;
void Awake()
{
// 如果没有设置频率或者设置的频率为0则自动记录成1
if (Mathf.Approximately(frequency, 0))
frequency = 1f;
originPosition = transform.localPosition;
tick = Random.Range(0f, 2f * Mathf.PI);
// 计算振幅
amplitude = 2 * Mathf.PI / frequency;
animate = playAwake;
}
public void Play()
{
transform.localPosition = originPosition;
animate = true;
}
public void Stop()
{
transform.localPosition = originPosition;
animate = false;
}
void FixedUpdate()
{
if (animate)
{
// 计算下一个时间量
tick = tick + Time.fixedDeltaTime * amplitude;
// 计算下一个偏移量
var amp = new Vector3(Mathf.Cos(tick) * offset.x, Mathf.Sin(tick) * offset.y, 0);
// 更新坐标
transform.localPosition = originPosition + amp;
}
}
}
By: 蒋志杰