Unity 3D\2D手机游戏开发:从学习到产品(第3版)
上QQ阅读APP看书,第一时间看更新

2.4 创建主角

这个游戏的主角是一艘太空飞船,我们将使用一个飞船模型作为主角的游戏体,并赋予它一个脚本,控制它的运动。脚本是实现游戏逻辑的核心,它本身并不能独立运行,必须作为某个游戏体的组件才能运行。

2.4.1 创建脚本

步骤 01 在Project窗口中找到Player.fbx,将其拖动到Hierarchy窗口中创建飞船模型的游戏体,然后在Inspector窗口中将其旋转-180°,如图2-16所示。

图2-16 创建飞船游戏体

步骤 02 在Project窗口中选择Assets并单击鼠标右键,选择【Create】→【Folder】创建一个文件夹,将其命名为Scripts,我们可以将所有创建的脚本都放入到这个文件夹中。

步骤 03 选择Scripts文件夹并单击鼠标右键,选择【Create】→【C# Script】创建一个C#脚本,将其命名为Player。

步骤 04 双击Player.cs脚本将其打开,会发现Unity已经自动创建了一些基本代码:

        using UnityEngine;
        using System.Collections;
        public class Player : MonoBehaviour
        {
            // Use this for initialization
            void Start()
            {
            }
            // Update is called once per frame
            void Update()
            {
            }
        }

Player是类的名字,这个名字必须与脚本的文件名一致,它默认继承自MonoBehaviour,只有继承自MonoBehaviour的类才能作为Unity脚本组件使用。

步骤 05 选择主角的飞船模型游戏体,然后在菜单栏中选择【Component】→【Scripts】→【Player】,将脚本指定给主角游戏体作为组件。

步骤 06 默认新创建的脚本都会出现在菜单栏【Component】→【Scripts】下面,为了便于管理脚本,也可以自定义脚本在菜单栏中的位置。在Player类前面添加AddComponentMenu属性:

        [AddComponentMenu("MyGame/Player")]
        public class Player : MonoBehaviour

步骤 07 在菜单栏中选择【Component】,会发现Player脚本出现在自定义的MyGame子菜单中,如图2-17所示。

图2-17 自定义脚本在菜单中的位置

2.4.2 控制飞船移动

我们将使用键盘上的上、下、左、右键来控制飞船的行动。

步骤 01 在Player类中添加一个控制飞行速度的属性:

        public float m_speed = 1;

步骤 02 在Player类中,默认有一个Update函数,这个函数在程序运行时,每帧都会被调用,我们将在这个函数中添加键盘操作的代码:

        void Update () {

              // 纵向移动距离
              float movev=0;

              // 水平移动距离
              float moveh=0;
              // 按上键
              if ( Input.GetKey( KeyCode.UpArrow ) )
              {
                  movev -= m_speed * Time.deltaTime;
              }
              // 按下键
              if ( Input.GetKey( KeyCode.DownArrow ) )
              {
                  movev += m_speed * Time.deltaTime;
              }
                // 按左键
                if ( Input.GetKey( KeyCode.LeftArrow ) )
                {
                    moveh += m_speed * Time.deltaTime;
                }
                // 按右键
                if ( Input.GetKey( KeyCode.RightArrow ) )
                {
                    moveh -= m_speed * Time.deltaTime;
                }
                // 移动
                this.transform.Translate( new Vector3( moveh, 0, movev ) );
              }

Input是一个包装了输入功能的类,它包括几乎所有的键盘、鼠标或触控操作函数。

Time.deltaTime表示每帧的经过时间,那些需要每帧做增减变动的数值都建议乘上Time.deltaTime。在本示例中,速度与Time.deltaTime相乘,表示每帧移动N米距离。

this.transform调用的是游戏体的Transform组件,Transform组件提供的主要功能都是和移动、旋转、缩放游戏体有关的。我们调用了Translate函数移动游戏体,其中有一个Vector3类型的参数,用来表示x、y、z三个方向上的移动距离。

步骤 03 在Update函数中如果每帧都去调用this.transform组件,就会造成一定的效率问题,我们可以在对象初始化时只调用一次并将其保存起来。Start函数会在对象被实例化时自动调用一次,类似构造函数,可以在这里进行一些初始化的工作,如下所示:

        m_transform = this.transform;
        void Start () {
            m_transform = this.transform;
        }

提示

MonoBehaviour的派生类不能使用构造函数初始化。

步骤 04 在Update函数中修改控制移动的代码,将this.transform替换为this.m_transform,这样程序就不用每帧都去查找Transform组件,提高了程序的运行效率,如下所示:

        this.m_transform.Translate( new Vector3( moveh, 0, movev ) );

步骤 05 运行游戏,应当可以控制飞船移动了,但我们可能会觉得飞船的移动速度不够快。退出游戏运行模式,选择主角飞船游戏体,在Inspector窗口中找到Player脚本组件,将Speed的值加大至6,如图2-18所示。

图2-18 脚本组件

Speed的值与Player脚本内的m_speed的值是对应的,这样只需要在场景中修改Speed的值就可以改变飞船的移动速度,而不用每次都去修改原始的代码。

提示

只有public类型的属性才能在编辑器窗口实例化。

再次运行游戏,飞船的移动速度明显提高了。

2.4.3 创建子弹

这是一个射击游戏,飞船还需要发射子弹,我们先创建它的游戏体和脚本。

步骤 01 在Project窗口中找到rocket.fbx模型文件,将其拖动到Hierarchy窗口中创建子弹的游戏体,如图2-19所示。

图2-19 创建子弹游戏体

步骤 02 创建Rocket.cs脚本,将其指定给子弹游戏体。

步骤 03 在Rocket类中添加三个属性,分别控制子弹的飞行速度、生存时间和威力,如下所示:

        [AddComponentMenu("MyGame/Rocket")]
        public class Rocket : MonoBehaviour {

            public float m_speed=10;    // 子弹飞行速度
            public float m_liveTime=1;  // 生存时间
            public float m_power=1.0f;  // 威力
            protected Transform m_trasform;

            // Use this for initialization
            void Start () {
              m_trasform = this.transform;
              Destroy(this.gameObject, m_liveTime);  // 一定时间后自我销毁
            }

在Start函数中,我们调用了Destroy函数,在一定时间后销毁自身。

步骤 04 在Rocket的Update函数中添加如下代码:

        void Update () {
              // 向前移动
              m_trasform.Translate( new Vector3( 0, 0, -m_speed * Time.deltaTime ) );
            }
        }

运行游戏,子弹将飞速地前进,一定时间后会自动消失。

2.4.4 创建子弹Prefab

前面我们已经创建了子弹的游戏体,游戏中的子弹是玩家操作发射的,并可以发射很多子弹。对于需要重复使用的游戏体,需要将其制作成Prefab。

在本书第1章介绍过,Prefab在Unity中可以理解为可重用的游戏体。当我们创建了一个游戏体,为其设置了脚本、参数等,可以将其保存为Prefab,然后在任何时间、场景,甚至在其他Unity游戏中重复使用。下面我们把子弹游戏体制作成一个Prefab。

步骤 01 在Project窗口中的Assets目录内创建一个名为prefabs的文件夹用于保存prefab,然后单击鼠标右键,选择【Create】→【Prefabs】创建一个空的Prefab,将其命名为Rocket,如图2-20所示。

图2-20 创建空的Prefab

步骤 02 在Hierarchy窗口中选择前面创建的子弹游戏体,将其拖动到刚刚创建的prefab上面,Prefab的制作就完成了,如图2-21所示。

图2-21 制作子弹的Prefab

步骤 03 场景中的原始子弹游戏体已经不再需要了,可以按Delete键将其删除。

现在,我们已经完成了Prefab的创建。注意,步骤1并不是必须的,如果没有提前创建一个空的Prefab,步骤(2)直接拖动到Project窗口空白处,同样可以创建Prefab。

2.4.5 发射子弹

接下来,我们将使用Instantiate函数动态地创建子弹游戏体。

步骤 01 首先,我们要将飞船和子弹的Prefab关联起来。打开Player.cs脚本,添加一个Transform属性,它将指向子弹的Prefab,如下所示:

        public Transform m_rocket;

步骤 02 回到Unity编辑器,选择Player游戏体,在Inspector窗口中找到Player脚本组件,会发现新增加了一个Rocket选项,选择子弹的Prefab,将其拖动到Rocket选项上,如图2-22所示。

图2-22 关联Prefab

步骤 03 打开Player.cs脚本,在Update函数的最下面添加如下代码发射子弹:

        void Update () {
          // ...
          // 按空格键或鼠标左键发射子弹
          if ( Input.GetKey( KeyCode.Space ) || Input.GetMouseButton(0) )
          {
              Instantiate( m_rocket, m_transform.position, m_transform.rotation );
              }
          }

提示

Unity的游戏体只能使用Instantiate函数实例化,不能使用new。

步骤 04 运行游戏,按空格键或鼠标左键可以发射子弹,但现在的发射速度太快,我们再略修改一下代码,先添加一个控制发射频率的属性:

        float m_rocketTimer = 0;

步骤 05 在Update函数中修改代码,每隔0.1秒发射一次子弹,如下所示:

              void Update () {
                // ...
                m_rocketTimer -= Time.deltaTime;
                if (m_rocketTimer <= 0 )
                {
                    m_rocketTimer = 0.1f;

                    // 按空格键或鼠标左键发射子弹
                      if ( Input.GetKey( KeyCode.Space ) || Input.GetMouseButton(0) )
                      {
                          Instantiate( m_rocket, m_transform.position, m_transform.rotation );
                      }
                  }