前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >游戲中的时间倒回系统

游戲中的时间倒回系统

作者头像
bering
发布2019-12-03 15:45:05
4620
发布2019-12-03 15:45:05
举报
文章被收录于专栏:游戏开发之旅

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/CJB_King/article/details/73456858

游戲中的时间倒回系统

The Player 玩家

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

代码语言:javascript
复制
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,绑定脚本。脚本处理实时记录和随时倒回游戏。

为了让它运行,我们会记录玩家的所有移动。当我们按下倒回按钮时,可以修正玩家的坐标。脚本如下:

代码语言:javascript
复制
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对象,在整个运行过程中检查它是在倒回还是在移动。只有当不在倒回状态下,我们才可以控制移动物体。

此外,還需要另一个数据来存储旋转值,在最开始的时候初始化它,在处理位置数据的地方保存和应用数据。最後代碼如下:

代码语言:javascript
复制
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的位置和旋转。这样做的话,我们需要记得 记录和取数据 同时有两个地方,这会产生潜在的问题。我们可以怎么做呢,创建一个单独的类来存存这些数据。

代码语言:javascript
复制
public class Keyframe
{
    public Vector3 position;
    public Vector3 rotation;

    public Keyframe(Vector3 position,Vector3 rotation)
    {
        this.position = position;
        this.rotation = rotation;
    }
}

經過改良,代碼如下:

代码语言:javascript
复制
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);
        }
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017/06/19 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 游戲中的时间倒回系统
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档