使用Unity制作ZigZag游戏两步教程 VR资源

admins 2017-12-12 17:29:00
单手操作却独具挑战性的ZigZag游戏是否也让你玩上瘾了呢?今天来教大家使用Unity制作一款ZigZag游戏,附详细步骤及源码。

如果还不知道ZigZag怎么玩,请看:
 
 

准备工作

首先新建Unity 3D工程,任意命名并保存。将相机的Clear Flags设为Solid Color,如下:
 

然后需要一个脚本让相机可以跟着小球移动。新建C#脚本命名为CameraFollow,将其绑定到Main Camera上,并添加以下代码:
using UnityEngine;
using System.Collections;
 
public class CameraFollow : MonoBehaviour
{
        public bool shouldRotate = false;
 
        // 跟随目标
        public Transform target;
        // 目标距XZ平面的距离
        public float distance = 10.0f;
        // 相机在目标上方的高度
        public float height = 5.0f;
        public float heightDamping = 2.0f;
        public float rotationDamping = 3.0f;
        float wantedRotationAngle;
        float wantedHeight;
        float currentRotationAngle;
        float currentHeight;
        Quaternion currentRotation;
 
        void LateUpdate ()
        {
                if (target){
                        // 计算当前旋转角度
                        wantedRotationAngle = target.eulerAngles.y;
                        wantedHeight = target.position.y + height;
                        currentRotationAngle = transform.eulerAngles.y;
                        currentHeight = transform.position.y;
                        currentRotationAngle = Mathf.LerpAngle (currentRotationAngle, wantedRotationAngle, rotationDamping * Time.deltaTime);
                        // 计算当前高度
                        currentHeight = Mathf.Lerp (currentHeight, wantedHeight, heightDamping * Time.deltaTime);
                        // 将角度转换为欧拉角
                        currentRotation = Quaternion.Euler (0, currentRotationAngle, 0);
                        // 设置相机至XZ平面的距离设置
                        transform.position = target.position;
                        transform.position -= currentRotation * Vector3.forward * distance;
                        // 设置相机高度
                        transform.position = new Vector3 (transform.position.x, currentHeight, transform.position.z);
                        // 保持朝向目标
                        if (shouldRotate)
                                transform.LookAt (target);
                }
 
        }
}

到此前期的准备工作完毕,下面来看实现步骤。

第一步

整个游戏都只包含一些基本几何体,所以不需要额外的资源。按照如下步骤在场景中添加平台:

新建Cube,将Position和Rotation均设为(0, 0, 0),Scale设为(5, 1, 5)。
为Cube添加Rigidbody组件并勾选Is Kinematic: 

新建Materials文件夹,在文件夹下新建材质Material命名为MatPlatform,将其赋予Cube。将MatPlatform材质的着色器设置为Legacy Shaders-> Bumped Specular,并按照自己的喜好设置Main Color及Shininess等属性。
 

至此小球所在的平台就设置完毕了,如下: 


下面按照与平台相同的步骤来创建小球:

新建Sphere,将Position、Rotation及Scale分别设为(0, 1, 0),(0, 45, 0)和(0.5, 0.5, 0.5)。
为Sphere添加Rigidbody组件,展开Constraints,勾选Freeze Rotation后的所有项(X、Y、Z)以避免小球因为摩擦力而发生旋转。

 

在Materials文件夹下新建材质Material命名为MatSphere,将其赋予Sphere。将MatSphere材质的着色器设置为Legacy Shaders-> Bumped Specular,并按照自己的喜好设置Main Color及Shininess等属性。
 

小球创建完成后,下面就让相机可以跟随小球移动。前面已经将CameraFollow脚本绑定到Main Camera上了,接下来勾选CameraFollow脚本的ShouldRotate属性,并将小球(Sphere)拖拽至CameraFollow脚本的Target字段,设置好其它的属性值:
 

运行场景会发现,此时相机会跟随小球移动。
 

第二步

游戏需要的所有物体都创建完毕,接下来就是添加脚本逻辑了。新建C#脚本命名为Ball,这个脚本将用于控制小球的行为。Ball脚本的完整代码如下:
using UnityEngine;
using System.Collections;
 
public class Ball : MonoBehaviour
{   
        public GameObject _platfrom;
        GameObject _lastPlatform;
 
        enum BALL_STATE
        {
                LEFT,
                RIGHT
        }
 
        Rigidbody _rb;
        BALL_STATE _ballState = BALL_STATE.RIGHT;
        bool _isStarted = false;
        float _speed = 3;
 
        void Start ()
        {
                _rb = GetComponent<Rigidbody>();
                // 在上一块平台相同位置生成新的平台
                _lastPlatform = Instantiate (_platfrom) as GameObject;
                // Now create 50 platfroms initially
                for (int index = 0; index < 50; index++) {
                        // 随机向左或向右生成50快平台
                        SpawnPlatform ();
                }
        }
 
        // 在平台结束处生成新的平台
        void SpawnPlatform ()
        {
                // 随机数0和1用于决定平台生成方向
                int randonNumber = Random.Range (0, 2);
                // 如果随机数为0
                if (randonNumber == 0) {
                        // 在平台结束处左边生成新的平台
                        _lastPlatform = Instantiate (_platfrom, new Vector3 (_lastPlatform.transform.position.x + 1,
                                _lastPlatform.transform.position.y,
                                _lastPlatform.transform.position.z),
                                Quaternion.identity) as GameObject;
                } else {
                        // 在平台结束处右边生成新的平台
                        _lastPlatform = Instantiate (_platfrom, new Vector3 (_lastPlatform.transform.position.x,
                                _lastPlatform.transform.position.y,
                                _lastPlatform.transform.position.z + 1),
                                Quaternion.identity) as GameObject;
                }
        }
 
        void Update ()
        {
                OnTap ();
        }
 
        void OnTap ()
        {
                // 检测是否有点击
                if (Input.GetMouseButtonDown (0)) {
                        // 检测游戏是否开始
                        if (!_isStarted) {
                                // 游戏开始标志
                                _isStarted = true;
                                // 首次点击时为小球增加一些速度
                                _rb.velocity = new Vector3 (_speed, 0, 0);
                                // 返回
                                return;
                        }
 
                        // 点击切换小球前进方向
                        switch (_ballState) {
                        // 如果当前方向为左
                        case BALL_STATE.LEFT:
                                // 切换为右
                                _ballState = BALL_STATE.RIGHT;
                                // 让小球向右移动
                                _rb.velocity = new Vector3 (_speed, 0, 0);
                                break;
                        case BALL_STATE.RIGHT:
                                // 切换为左
                                _ballState = BALL_STATE.LEFT;
                                // 让小球向左移动
                                _rb.velocity = new Vector3 (0, 0, _speed);
                                break;
                        }
                }
        }
 
        void OnCollisionExit (Collision other)
        {
                // 这里只有平台与小球碰撞,所以退出平台后直接生成新平台
                SpawnPlatform ();
                // 新建游戏对象保存当前平台
                GameObject platform = other.gameObject;
                // 关掉isKinematic属性让平台下落
                platform.GetComponent<Rigidbody> ().isKinematic = false;
                // 下落1秒后销毁平台
                InvokeDestroyPlatfrom (platform);
        }
 
        void InvokeDestroyPlatfrom (GameObject platform)
        {
                // 调用协程销毁平台
                StartCoroutine (DestroyPlatform (platform));
        }
 
        IEnumerator DestroyPlatform (GameObject platform)
        {
                // 等待1秒
                yield return new WaitForSeconds (1.0f);
                // 销毁平台
                Destroy (platform);
        }
}
其中BALL_STATE枚举用来定义小球的移动方向。OnTap函数检测玩家输入,并控制小球移动方向的转换,在玩家点击屏幕时开始游戏或切换小球前进方向。在Update函数中调用OnTap,每帧都要检测玩家输入。

添加了移动的代码后,小球就可以移动了,但还不够流畅。为了让小球可以流畅向前滚动,需要将小球和平台的摩擦力去掉。在Materials文件夹下新建Physical Material重命名为Frictionless,并将所有的摩擦力和弹力等属性值设为0:
 

然后将Frictionless分别赋给平台(Cube)Box Collider和小球(Sphere)Sphere Collider上的Material字段:
 

这样小球就可以流畅地向前移动了,下面来创建平台Prefab以便运行时动态生成平台。新建文件夹Resources,这是由Unity控制的特殊文件夹,所以文件夹名字不要写错。
•        新建Cube重命名为Platform,分别设置Position、Rotation、Scale为(3, 0, 2)、(0, 0, 0)和(1, 1, 1)。
•        将Materials文件夹下的Frictionless赋给Box Collider的Material,MatPlatform赋给Mesh Renderer的Material。
 

最后将Platform从层级视图拖拽至项目视图的Resources文件夹下保存为Prefab,删除层级视图的Platform。

SpawnPlatform函数用于生成平台,在游戏开始时及小球走过一个平台后调用。游戏开始时一次性生成50块平台,此后每次小球经过一块平台则重新生成一个。小球已经经过的平台会在等待一秒后坠落,这是通过调用StartCoroutine来实现的。

将Ball脚本绑定到小球(Sphere)上,然后将Resources下的Platform拖拽至Ball脚本的Platform字段: 
 


到此整个游戏就完成了,一共就两个脚本,两个步骤。最后运行效果如下:
 

这还只是最简单的版本,大家还可以继续打磨,比如增加一些道具和游戏计分的逻辑等等。
99VR视界二维码
热门推荐
Hot Recommended
在线客服