视频教程:https://www.bilibili.com/video/BV12s411g7gU?p=128
目录
Time
Prefab
Animation
Time
Time.time:自应用程序启动以来,每帧的开始时间(只读)
Time.deltaTime:每帧间隔,或说完成一帧的时间(等于当前帧的Time.time-下一帧的Time.time)
public float speed=100;
void Update()
{
transform.Rotate(0,speed*Time.deltaTime,0);
// 旋转/移动速度*每帧间隔,以保证旋转/移动速度不受渲染影响
}
Time.timeScale:时间的缩放,可用于慢动作效果或加快应用程序速度
ps:当设置为1.0时,时间流逝的速度与实时时间一样快;当设置为0.5时,时间比实时慢2倍
Time.unscaledTime:不收缩放影响的每帧间隔
//渲染时执行,不受TimeScale影响
void Update()
{
// transform.Rotate(0, speed * Time.deltaTime, 0);
}
// 固定0.02s执行一次,与渲染无关,受TimeScale影响
void FixedUpdate()
{
// this.transform.Rotate(0, speed * Time.fixedDeltaTime, 0);
}
void OnGUI()
{
if (GUILayout.Button("暂停游戏"))
{
Time.timeScale = 0;
}
if (GUILayout.Button("继续游戏"))
{
Time.timeScale = 1;
}
}
尽管Update的执行不受timeScale的影响,但是在运行后,Update中编写的Transform.Rotate方法仍会受到timeScale的影响,这是因为Time.deltaTime受到了timeScale的影响,若修改代码不乘Time.deltaTime,则按下“暂停游戏”可使物体停止旋转
transform.Rotate(0, speed, 0);
使场景中的某些物体不受“暂停”的影响
public float speed = 100;
void Update()
{
transform.Rotate(0, speed * Time.unscaledTime, 0);
}
void OnGUI()
{
if (GUILayout.Button("暂停游戏"))
{
Time.timeScale = 0;
}
if (GUILayout.Button("继续游戏"))
{
Time.timeScale = 1;
}
}
Time.frameCount:自游戏开始以来的总帧数(只读)
Time.realtimeSinceStartup:游戏开始以来的实际时间(只读)
可以使用如下代码了解Time.timeScale,Time.unscaledTime及Time.realtimeSinceStartup的区别。运行后点击“暂停游戏”按钮,可以发现除了变量a,其余变量的值仍在累积
public float a;
public float b;
public float c;
void Update()
{
a=Time.time;
b=Time.unscaledTime;
c=Time.realtimeSinceStartup;
}
void OnGUI()
{
if (GUILayout.Button("暂停游戏"))
{
Time.timeScale = 0;
}
if (GUILayout.Button("继续游戏"))
{
Time.timeScale = 1;
}
}
每1秒变化一次的时钟
难点:因为Update的执行受渲染的影响,使每帧的时间间隔不同(但一般仍在0.02左右)
方法1:
private float nextTime = 1;
void Update()
{
if (Time.time >= nextTime)
{
second--;
textTimer.text = string.Format($"{second / 60:d2}:{second % 60:d2}");
nextTime = Time.time + 1;
}
}
方法2:
private float totalTime = 1;
void Update()
{
totalTime+=Time.deltaTime;
if (totalTime>1)
{
second--;
textTimer.text = string.Format($"{second / 60:d2}:{second % 60:d2}");
totalTime-=1;
}
}
方法3:
void Start()
{
textTimer = GetComponent<TMP_Text>();
InvokeRepeating("Timer", 1, 1);
}
void Timer()
{
if (second <= 0)
{
CancelInvoke("Timer");
}
second--;
textTimer.text = string.Format($"{second / 60:d2}:{second % 60:d2}");
}
MonoBehaviour.InvokeRepeating(string methodName, float time, float repeatRate):在time 秒后调用methodName方法,然后每repeatRate秒调用一次
methodName | 调用的方法名 |
time | n秒后开始调用 |
repeatRate | 每n秒重复一次。 |
MonoBehaviour.CancelInvoke:取消该MonoBehaviour上的所有Invoke调用,或取消该行为上所有名为methodName的Invoke调用
Prefab
一种资源类型,可以多次在场景进行实例。且对预制件的修改,可以同步到所有实例,从而提高开发效率,当若单独修改实例的属性值,则该值不再随预制件变化
将处于Hierarchy面板的游戏对象拖入Project面板
Open:在场景中打开预制件
Select:通过预制件实例选择对应预制件
Revert All:放弃对实例属性值的修改,并还原预制件属性值
Apply All:将某一实例的修改应用至预制件和其他所有实例
Animation
Animation.CrossFade:在一定时间内淡入名称为name的动画并使其他动画淡出
Animation.Play:播放不带有任何混合的动画
Animation.PlayQueued:在前一个动画播放完成之后直接播放下一个动画(按指定的序列一个接一个地播放动画)
制作开门动画
在场景中使用一个Cube(Base)作为门的模型,用一个空物体(Door)作为门的旋转轴并使其作为前者的父级
调整空物体(Door)的位置,使其Z轴与门的旋转轴重合
选择游戏对象Door,并进入Window-->Animation-->Animation创建名为Door的动画后,点击左上角的红点进入录制模式;点击Add Property选择Transform下的Rotation属性(点击右侧的+号)
添加相应属性后,默认的动画长度为0:00到1:00,可拖动末尾的关键帧至适当的位置改变动画长度,或对其按下右键选以删除末尾的关键帧(对关键帧上右键选择Delete Key)后,在合适位置双击添加新的关键帧(亦或是在合适的时间线上右键选择Add Key)
返回Inspector面板即可发现相应的属性的显示框成红色,在选择时间线末尾帧的情况下,将Rotation的Y值设置为90(绕Y轴选择90度)
ps:如生成了Animator则卸载该组件并挂载Animation组件后,按上图进行设置
编写脚本Door并将其挂载至游戏对象Door上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Door : MonoBehaviour
{
public bool isOpen = false;
public string animName;
private Animation anim;
private void Start()
{
anim = GetComponent<Animation>();
}
private void OnMouseDown()
{
if (isOpen)
{
if (anim.isPlaying == false)
{
anim[animName].time = anim[animName].length;
}
anim[animName].speed = -1;
}
else
{
anim[animName].speed = 1;
}
anim.Play(animName);
isOpen = !isOpen;
}
}
ps:对于新版不使用Animator控制动画需进行如下设置,否则会弹出警告
The AnimationClip ‘Door‘ used by the Animation component ‘Door‘ must be marked as Legacy
在Inspector面板右上方的菜单中选择Debug模式后,勾选Legacy