有些游戏需要通过一定的物理运动并且达到相应的结果。可以准备两套相应的物体,一套绑定上相应的物理组件,一套单纯的物体。
物理组件那套不让相机渲染,默默在后面工作,通过物理引擎驱动运动,在FixedUpdate中记录相应的位置和角度,生成轨迹数据,在生成轨迹数据列表。
单纯物体那套,通过事先生成好的数据做规定的插值运动,既可以达到很好的物理效果。角度问题可以通过加上一个父物体解决,子物体进行做偏移纠最总的角度不对。如果不想显得那么突兀,子物体的纠正可以在轨迹运动的时间内做插值纠正。
一、记录物理运动的帧数据
void FixedUpdate()
{
if (!isStartinng)
return;
if (Time.unscaledTime - preGenerateTime >= generateFrameTime)
{
RecordFrame();//隔一段时间记录数据
preGenerateTime = Time.unscaledTime;
}
}
private void RecordFrame(bool isStart = false)
{
FrameData data = new FrameData();
bool isColliderWall = false;
for (int i = 0; i < Count; i++)
{
data.poss[i] = Cubes[i].transform.localPosition;
data.rots[i] = Cubes[i].transform.rotation;
if (!isStart)
{
if (i == 0)
{
data.isStop = Cubes[i].IsStop();
}
else
{
data.isStop = data.isStop && Cubes[i].IsStop();
}
if (Cubes[i].IsCollideWall())
isColliderWall = true;
}
}
data.time = Time.unscaledTime - recodeStartTime;
curRecordData.frames.Add(data);
if (data.isStop || isColliderWall)
{
bool is_correct = true;
for (int i = 0; i < colorGameCubes.Count; i++)
{
curRecordData.tops[i] = Cubes[i].GetUpIndex();//物理结果的索引
if (!Cubes[i].CheckUpCorrect())
{
is_correct = false;
}
}
if (is_correct)
{
aniDatas.Add(curRecordData);
genCount--;
isStartinng = false;
GenerateData();//继续生成
}
else
{
isStartinng = false;
GenerateData();//继续生成
}
}
}二、使用物理运动数据
//角度纠正
public void SetTargetIndexAndColor(int targetIndex, string color)
{
ResetToOrigin();
var colorData = GetDataByColor(color);//不旋转时结果的角度
var tartgetData = GetDataByIndex(targetIndex);//物理运动结果的角度
Quaternion q = Quaternion.FromToRotation(colorData.dir, tartgetData.dir);//将结果颜色那一面旋转到物理运动结果的那一面
obj.localEulerAngles = q.eulerAngles;
}
//运动
void FixedUpdate()
{
if (AniData == null)
return;
tmp_time = Mathf.Clamp01( ( curPlayTime - preData.time) / (curData.time - preData.time));//计算两记录帧之间的时间进度
SetFrame(tmp_time);
if (curPlayTime >= curData.time)
{
if (curData.isStop)
{
AniData = null;
if (aniEndCallback != null)
{
aniEndCallback();
}
}
else
{
curFrame++;
preData = AniData.frames[curFrame - 1];
curData = AniData.frames[curFrame];
}
}
curPlayTime += Time.fixedDeltaTime;
}
void SetFrame(float t)
{
for (int i = 0; i < cubeCount; i++)
{
CubeList[i].transform.localPosition = Vector3.Lerp( preData.poss[i],curData.poss[i],t );
CubeList[i].transform.rotation = Quaternion.Lerp(preData.rots[i], curData.rots[i], t);
}
}三、记录一些方法
//刚体判断是否停止
public bool IsStop()
{
if (Time.unscaledTime - start_time < 1)
{
return false;
}
bool isStop = rgBody.velocity.magnitude < (0.001f * 0.001f);
return isStop;
}