游戲中的时间倒回系统

游戲中的时间倒回系统

The Player 玩家

          首先, 在场景中创建一个立方体,作为我们的角色。再创建一个名为Player.cs的C#脚本,加一个如下的Update()函数:

void Update()
{
    transform.Translate (Vector3.forward * 3.0f * Time.deltaTime * Input.GetAxis ("Vertical"));
    transform.Rotate (Vector3.up * 200.0f * Time.deltaTime * Input.GetAxis ("Horizontal"));
}
这个脚本通过健盘上的上下健产生简单的移动,把这个脚本绑定到立方体上。当你点击Play运行,你就能够移动。

倾斜相机,当我们移动时,以便可以从上面观察立方体。最后,创建一个Floor的面,两个物体使不用同的材质便於觀察;

时间控制TimeController

现在创建一个新的C#脚本,命名为TimeController.cs,创建一个空的GameObject,绑定脚本。脚本处理实时记录和随时倒回游戏。

为了让它运行,我们会记录玩家的所有移动。当我们按下倒回按钮时,可以修正玩家的坐标。脚本如下:
using UnityEngine;
using System.Collections;
  
public class TimeController: MonoBehaviour
{
    public GameObject player;
    public ArrayList playerPositions;
    public bool isReversing = false;
  
    void Start()
    {
        playerPositions = new ArrayList();
    }
  
    void Update()
    {
        if(Input.GetKey(KeyCode.Space))
        {
            isReversing = true;
        }
        else
        {
            isReversing = false;
        }
    }
      
    void FixedUpdate()
    {
        if(!isReversing)
        {
            playerPositions.Add (player.transform.position);
        }
        else
        {
            player.transform.position = (Vector3) playerPositions[playerPositions.Count - 1];
            playerPositions.RemoveAt(playerPositions.Count - 1);
        }
    }
}
在启动的时候,新加的代码自动在场景中到TimeController对象,在整个运行过程中检查它是在倒回还是在移动。只有当不在倒回状态下,我们才可以控制移动物体。
此外,還需要另一个数据来存储旋转值,在最开始的时候初始化它,在处理位置数据的地方保存和应用数据。最後代碼如下:
using UnityEngine;
using System.Collections;
  
public class TimeController: MonoBehaviour
{
    public GameObject player;
    public ArrayList playerPositions;
    public ArrayList playerRotations;
    public bool isReversing = false;
      
    void Start()
    {
        playerPositions = new ArrayList();
        playerRotations = new ArrayList();
    }
      
    void Update()
    {
        if(Input.GetKey(KeyCode.Space))
        {
            isReversing = true;
        }
        else
        {
            isReversing = false;
        }
    }
      
    void FixedUpdate()
    {
        if(!isReversing)
        {
            playerPositions.Add (player.transform.position);
            playerRotations.Add (player.transform.localEulerAngles);
        }
        else
        {
            player.transform.position = (Vector3) playerPositions[playerPositions.Count - 1];
            playerPositions.RemoveAt(playerPositions.Count - 1);
      
            player.transform.localEulerAngles = (Vector3) playerRotations[playerRotations.Count - 1];
            playerRotations.RemoveAt(playerRotations.Count - 1);
        }
    }
}

记录少量的数据,使用插入值
       现在,我们每秒要记录50次,Player的位置和旋转数据。这个数据量太大了,一些移动设备上处理能力相对较低,复杂游戏使用这种数据量会变得特别的引人注意。
使用一个自定义类来保存Player数据

现在我们是使用的两个数据来存player的位置和旋转。这样做的话,我们需要记得 记录和取数据 同时有两个地方,这会产生潜在的问题。
我们可以怎么做呢,创建一个单独的类来存存这些数据。
public class Keyframe
{
    public Vector3 position;
    public Vector3 rotation;

    public Keyframe(Vector3 position,Vector3 rotation)
    {
        this.position = position;
        this.rotation = rotation;
    }
}
經過改良,代碼如下:

using UnityEngine;
using System.Collections;
public class Keyframe
{
    public Vector3 position;
    public Vector3 rotation;

    public Keyframe(Vector3 position,Vector3 rotation)
    {
        this.position = position;
        this.rotation = rotation;
    }
}
public class TimeController : MonoBehaviour
{
    //public ArrayList playerPosition;
    //public ArrayList playerRotation;
    public Transform player;
    public ArrayList keyframes;
    public int keyFrame = 5;  //表示FixedUpdate函數每被調用5次,就記錄數據;
    private int frameCounter = 0;

    public bool isReversing = false;


    private Camera camera;
    
    private int reverseCounter = 0;

    private Vector3 currentPosition;
    private Vector3 previousPosition;
    private Vector3 currentRotation;
    private Vector3 previousRotation;

    private bool firstRun = true;
    void Start()
    {
        //playerPosition = new ArrayList();
        //playerRotation = new ArrayList();
        keyframes = new ArrayList();
        camera = Camera.main;
    }

    void Update()
    {
        if (Input.GetKey(KeyCode.Space))
        {
            isReversing = true;
        }
        else
        {
            isReversing = false;
            firstRun = true;
        }
    }
    void FixedUpdate()
    {
        if(!isReversing) //時間倒回未啓用則記錄數據
        {
            if(frameCounter<keyFrame)
            {
                frameCounter += 1;
            }
            else
            {
                frameCounter = 0;
                //playerPosition.Add(player.transform.position);
                //playerRotation.Add(player.transform.localEulerAngles);
                keyframes.Add(new Keyframe(player.position,player.localEulerAngles));
            }
            
        }
        else  //時間倒囘開始
        {
            if(reverseCounter>0)
            {
                reverseCounter -= 1;
            }
            else
            {
                //player.transform.position = (Vector3)playerPosition[playerPosition.Count - 1];
                //playerPosition.RemoveAt(playerPosition.Count - 1);

                //player.transform.localEulerAngles = (Vector3)playerRotation[playerRotation.Count - 1];
                //playerRotation.RemoveAt(playerRotation.Count - 1);
                RestorePositions();
                reverseCounter = keyFrame;
            }
            if(firstRun)
            {
                firstRun = false;
                RestorePositions();
            }
            float interPolation = (float)reverseCounter / (float)keyFrame;
            player.position = Vector3.Lerp(previousPosition, currentPosition, interPolation);
            player.localEulerAngles = Vector3.Lerp(previousRotation,currentRotation,interPolation);
        }
        if(keyframes.Count>128) //只記錄游戲結束前128個數據
        {
            keyframes.RemoveAt(0);
        }
    }

    void RestorePositions()
    {
        int lastIndex = keyframes.Count - 1;
        int secondToLastIndex = keyframes.Count - 2;
        if(secondToLastIndex>=0)
        {
            currentPosition = (keyframes[lastIndex] as Keyframe).position;
            previousPosition = (keyframes[secondToLastIndex] as Keyframe).position;

            currentRotation = (keyframes[lastIndex] as Keyframe).rotation;
            previousRotation = (keyframes[secondToLastIndex] as Keyframe).rotation;
            keyframes.RemoveAt(lastIndex);
        }
    }
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值