有些游戏需要通过一定的物理运动并且达到相应的结果。可以准备两套相应的物体,一套绑定上相应的物理组件,一套单纯的物体。
物理组件那套不让相机渲染,默默在后面工作,通过物理引擎驱动运动,在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; }