Unity3D-VR《静夜诗》5-李白吟诗

1.设计场景中的可视内容1.1添加李白人物对象1.2添加显示诗词的文本对象

2. 李白行走路径动画2.1动画控制器libaiMain2.2 动画编辑器编辑动画剪辑libaiMain

3. 李白抬头等动画3.1 动画控制器3.2 动画事件脚本函数SetTrigger

4. 李白行走时同步吟诗4.1 设置动画事件4.2 动画事件脚本函数PlayPoem

5. 初始状态设定6. 背景音效7. 总结

窗户打开动画播放结束后,应该是出现李白吟诗了,如何实现呢?

在工程视图中选中NDVRresources\ Res\ Animations\ WinOpen动画剪辑文件,在监视视图中可以看到该动画剪辑的时长是1S。根据项目实现要求,大约在窗户打开1S后李白开始吟诗。 这样我们可以在播放窗户打开动画后延时2S再播放李白吟诗的动画。 按照习惯,先来完成场景中的可视内容的设计。

1.设计场景中的可视内容

1.1添加李白人物对象

将素材资源目录中已经提供的李白角色的预设对象拖放到场景中,调整到合适的位置及朝向。设置参考如下:

1.2添加显示诗词的文本对象

场景中合适的位置新建诗词文本背景Image对象ImagePoemBg,设置属性如下:

组件Image中的图片Five在资源目录NDVRresources\UIRcs中已经提供给大家了。

在对象ImagePoemBg下新建文本子对象TextPoem属性设置如下:

2. 李白行走路径动画

2.1动画控制器libaiMain

在LiBai\Animations目录下有许多李白的动画剪辑,如抬头、低头、左转等,还有2个动画控制器文件,其中动画控制器文件libaiMain是播放李白的行走的位移动画的,控制器设定如下:

默认状态是libaiMain,对应播放libaiMain动画剪辑,我们将动画控制器libaiMain拖放到LiBai对象上,自动为LiBai对象添加了动画控制器组件,并设置动画控制器Controller属性值为libaiMain。

可以试着运行场景,看看libaiMain动画状态播放的libaiMain动画剪辑 提示

不要搞混了概念,资源中提供的动画控制器文件、设定的动画状态名、状态对应的动画剪辑命名都是libaiMain)。

运行时在控制台出现了以下错误提示:

‘LiBai’ AnimationEvent ‘SetTrigger’ has no receiver! Are you missing a component?

你可以忽略这些错误继续运行,可以看到李白在屋里行走的过程,每走到一个地方,就会出现类似的错误,最后出现以下错误:

‘LiBai’ AnimationEvent ‘ShowQuestionp’ has no receiver! Are you missing a component?

错误的提示意思是动画播放到某一帧时动画事件没有对应受理的函数。

2.2 动画编辑器编辑动画剪辑libaiMain

动画控制器默认播放的就是libaiMain动画剪辑,libaiMain动画剪辑是一个路径动画,播放的是李白吟诗时在室内行走的路径。在场景中选中LiBai对象,通过Window | Animation 打开动画剪辑编辑器编辑LiBai对象上的动画剪辑libaiMain。操作界面如下:

说明

在时间标尺上拖动红线(动画帧)可以看到整个动画播放时李白行走的路径位移。标尺下方白色柱状亮条表示该帧设定有一个动画事件,前面6个动画事件调用的函数是’SetTrigger’,最后一个动画事件调用的函数是’ShowQuestionp’。李白在行走到某个位置时还应该有一些转身、抬头、低头等动作,通过设置动画事件调用函数来播放这些小动画是我们常用的实现方法。问题是目前我们还没有设计好这样的脚本函数,这就导致了运行时的这些错误。

为了修正这些错误,要为动画控制器所在的对象LiBai添加新的脚本animationCtl.cs,脚本中添加 Public void SetTrigger(),代码参考如下:

public class animationCtl : MonoBehaviour {

public void SetTrigger()

{

}

}

函数SetTrigger的实现可以在后面继续完善的。

可以将libaiMain动画剪辑中的最后一个调用的函数’ShowQuestionp’的动画事件去掉,因为根据实现功能要求是不需要实现(其实是在李白吟诗结束后界面上显示一个问题让玩家作答吧,同学们有兴趣可以想想如何实现这样的功能?)

测试: 运行场景,错误没有了。

3. 李白抬头等动画

3.1 动画控制器

LiBai对象的动画控制器播放的是李白行走的路径,通过观看项目运行视频或运行程序,可以看到李白行走到某一位置时不但会吟诗还会做一个动作(比如抬头、低头、转身等)。

在场景中选中LiBai对象下的子对象libai_libai_rig,在监视视图中可以看到子对象下也有一个动画控制器组件,动画控制器Animator的Controller属性默认为空,将工程视图中NDVRresources\SceneRcs\JiaoHu\LiBai\Animations目录下的另一动画控制器文件LiBai设置为该属性值。该动画控制器就是控制李白行走到某个位置时要做的转身、抬头等小动作。打开动画控制器文件LiBai,显示其动画状态设置如下: 说明

可以看到控制器有5个状态(待机、左转90度、低头、走路、抬头),分别对应着李白角色的5个动画剪辑,默认状态时LiBai_DaiJi(待机),左边还设定了4个Trigger型的4个参数,分别是zuozhuan(左转)、zoulu(走路)、taitou(抬头)、ditou(低头),这4个参数控制着动画状态间的5个过渡,比如当前如果是LiBai_DaiJi状态,触发了zuozhuan参数后,控制器就会将动画过渡到LiBai_ZuoZhuan90du状态,播放该状态对应的动画剪辑。

3.2 动画事件脚本函数SetTrigger

通过反复观看视频或发布后的软件,可以推测李白行走的libaiMain动画剪辑中的前面6个动画事件调用的函数SetTrigger分别是依次触发zuozhuan、ditou、zoulu、taitou、zuozhuan、ditou这6个动画参数的。所以函数SetTrigger是带有字符串参数的,要调用libai_libai_rig对象上的动画控制器,根据传递的触发参数过渡到对应动画状态,从而播放该状态的动画剪辑,实现李白行走到某个位置时低头、抬头等一些列动作。

打开animationCtl.cs脚本,根据需要进行修改,修改后的参考代码如下:

public class animationCtl : MonoBehaviour {

public Animator anim_child;

public void SetTrigger(string name) //

{

anim_child.SetTrigger(name);

}

}

在场景中选中LiBai对象,将libai_libai_rig对象拖放到animationCtl脚本的参数anim_child中,赋值好了脚本的参数后,再设置好LiBai对象上libaiMain动画剪辑中的6个动画事件调用函数SetTrigger的参数,分别依次是zuozhuan、ditou、zoulu、taitou、zuozhuan、ditou。 可以试着运行了。

测试: 李白行走时配有转身、低头、抬头动作。 提示:

在动画编辑器中可以拖动动画事件的高亮柱条,调整动画事件触发的事件。 李白初始位置可以设置为动画第一帧时的位置值。

4. 李白行走时同步吟诗

4.1 设置动画事件

通过观看项目运行视频或发布后的运行程序,结合李白行走动画剪辑libaiMain在时间轴上的转身、抬头等动画事件的设定时间,可以初步拟定在libaiMain动画播放后,2秒、6秒、13秒、18秒处显示诗词第一、二、三、四句文本及播放对应的音频剪辑,23秒处诗词文本消失。

在libaiMain动画的时间轴的对应点设置动画事件,调用脚本函数PlayPoem(int i)。 接下来我们实现该播放对应位置诗词的脚本函数。

4.2 动画事件脚本函数PlayPoem

在animationCtl.cs脚本类中要新增一个函数PlayPoem,根据参数的序号,显示对应的诗词文本和播放诗词音频

为此要在脚本类中增加一些变量的声明:

要引用显示诗词文本的对象ImagePoemBg,以便通过调用对象的SetActive函数来设置诗词对象是否活动的(即可见),吟诗结束后设置诗词对象不活动(不可见)。根据动画事件函数的触发调用来更改ImagePoemBg对象的文本子对象TextPoem的显示内容要引用播放诗词音频的播放器要保存诗词音频剪辑的数组保存诗词文本的字符串数组。

打开animationCtl.cs脚本,新增一些变量的定义代码,变量的初始化代码,以及动画事件要调用的函数PlayPoem(int i)实现,完整的脚本参考代码的如下:

public class animationCtl : MonoBehaviour {

public Animator anim_child;

public GameObject go_Poem;

//诗词文本,\r\n表示换行

[TextArea]

public string[] poems=

{"窗\r\n前\r\n明\r\n月\r\n光",

"疑\r\n是\r\n地\r\n上\r\n霜",

"举\r\n头\r\n望\r\n明\r\n月",

"低\r\n头\r\n思\r\n故\r\n乡" };

public AudioClip[] aduioPoems;//诗词音频

//私有变量

private AudioSource audioPlayer;//音频播放器

private Text textPoem;

private void Start()

{ //初始化一些变量

audioPlayer = GetComponent();

textPoem = go_Poem.GetComponentInChildren();

go_Poem.SetActive(false);//初始不可见的

}

//设置动画参数,过渡到相应动画状态

public void SetTrigger(string name) //

{

anim_child.SetTrigger(name);

}

//显示对应序号的诗词文本、播放对应的诗词音频

public void PlayPoem(int i) {

go_Poem.SetActive(true);//设置诗词文字可见

if (i <=3 && i>=0) {

textPoem.text = poems[i]; //显示诗词文字

audioPlayer.clip = aduioPoems[i];//赋值诗词声音

audioPlayer.Play(); //播放诗词声音

}

if(i==4)

{

go_Poem.SetActive(false );//设置诗词文字可见

}

}

}

体会[TextArea]在变量声明中的使用,其效果可以看一下脚本在监视视图中变量展示形式的不同。数组定义初始赋值以及换行符请参考C#的语法。

脚本完成后在监视视图脚本组件中设置脚本的参数如下:

最后还要为LiBai对象添加AudioSource组件,如果没有的话在Start函数调用GetComponent()时会报错的。

思考:

变量能声明私有的尽量不要声明公有,脚本中anim_child变量声明改为私有private后,如何给它初始化?

测试:

运行后播放libaiMain动画,在播放过程中通过设置的动画事件调用脚本函数,实现诗词文本音频及转身抬头等动画的同步播放,最后诗词文本对象自动消失。

说明

项目演示中李白吟诗动画是在窗户打开后2秒播放的,初始不播放李白吟诗动画,只要设置LiBai对象的动画控制器组件Animator的enable属性为false即可,要播放时则设置为true。

5. 初始状态设定

要设定游戏的初始状态值,建议在全局游戏控制脚本GameManager的Start函数中设置。需要在全局游戏控制脚本中定义一些变量,以便引用游戏中的对象。

完成后的脚本GameManager.cs,参考代码如下:

public class GameManager : MonoBehaviour {

public Animator animator_Window;//窗口动画控制器

public Collider collider_Window;//可交互的窗口对象碰撞器

public Animator animator_Libai;//李白动画控制器

// Use this for initialization

void Start () {

animator_Window.enabled = false; //设置窗口动画控制器不使能(不起作用)

collider_Window.enabled = false; //设置窗口对象不可交互

animator_Libai.enabled = false; //设置李白动画控制器不使能(不起作用)

}

//凝视开始按钮触发交互后执行的方法

public void StartPlay(){

animator_Window.enabled = true; //设置窗口动画控制器使能(起作用)

collider_Window.enabled = true; //设置窗口对象可交互

}

//凝视窗户触发交互后执行的方法

public void OpenWindow(){

collider_Window.enabled = false; //关闭窗户对象可交互功能

animator_Window.SetTrigger("Open"); //播放窗户打开动画

StartCoroutine ("delayPlay"); //调用协程 延时2秒播放李白吟诗动画

}

//延时2秒后,播放李白行走动画、诗词声音、文字

IEnumerator delayPlay(){

yield return new WaitForSeconds (2); //延时n秒

animator_Libai.enabled = true; //播放李白行走动画

}

}

注意协同函数delayPlay()的设计及调用方法,协同函数返回类型是IEnumerator,通过StartCoroutine()函数调用,具体使用方法可以参考Unity Script API文档。

在GameManager脚本的监视视图中对Public变量进行赋值,把场景中的LiBai对象赋值给animator_Libai(因为LiBai对象有Animator组件)。

想一想

显示诗词文本的对象是在哪初始设定的?

6. 背景音效

演示的项目在运行时是有背景音效的,建议在场景中的GameManager对象添加AudioSource组件,并设置属性如下(设置循环播放):

7. 总结

建议用一个全局的脚本来控制一些游戏的逻辑实现,如全局变量的定义,公开一些函数在其他脚本中被调用,设置初始状态的值等。 对于多数呈现的视觉效果,如动画,可以用程序实现,也可以用动画编辑实现。 有时间轴延续进行的呈现(如李白吟诗),尽量用动画编辑器实现,配合动画事件的设定可以实现比较复杂的动画效果 对于不确定的需要交互延续的(窗户闪烁及窗户打开)只能用编程实现。

好文链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。