模拟物理开奖

有些游戏需要通过一定的物理运动并且达到相应的结果。可以准备两套相应的物体,一套绑定上相应的物理组件,一套单纯的物体。

物理组件那套不让相机渲染,默默在后面工作,通过物理引擎驱动运动,在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;
}



首页 我的博客
粤ICP备17103704号