欢迎光临散文网 会员登陆 & 注册

来吧,用Unity当一个套马的汉子

2019-05-24 17:23 作者:皮皮关做游戏  | 我要投稿

作者:繁华如梦


前言

《疯狂动物园》(不是《疯狂动物城》)是一款将“和动物互动”与跑酷元素结合起来的游戏。虽然游戏本身多年前便已推出,但由于机缘巧合最近才接触到。

作为一个(自认为)涉猎广泛的游戏开发人员,怎么不来搞一下试试呢?

地图复用

之前做过跑酷游戏的教程,地图是使用方块自动生成的。而就这款游戏而言,不需要这么复杂的地图生成。这里我们先做一个简单的地图,复用一下就行。

新建3个Plane物体,修改物体的缩放值,使其能够作为跑道使用。参数为(3,1,10)。然后将3个Plane平铺组合成一个较长的跑道。如下图:

搭建简易地图场景

接下来新建一个GameMode脚本,通过玩家的位置来控制地图移动。原理如下:

代码实现如下:

public class GameMode : MonoBehaviour {

...

    public Transform player;//玩家的位置

    public Transform floorOne;

    public Transform floorTwo;     

    public Transform floorThree;//3个地板

    int maxVaule = 70;//触发点的位置

    int floorIndex = 1;//当前应该移动第几块地板

    public void CheckBackMove()    // 检测地板是否移动

    {

        float zValue = player.position.z;//获取玩家的位置的Z值用于计算

        if (zValue> maxVaule)

        {

            maxVaule += 100;//触发点位置移动

            if (floorIndex == 1)

            {

                floorOne.transform.position = new Vector3(0, 0, maxVaule + 130);//通过触发点位置计算新的地板坐标位置

                floorIndex = 2;

            }

            else if (floorIndex == 2)

            {

                floorTwo.transform.position = new Vector3(0, 0, maxVaule + 130);

                floorIndex = 3;

            }

            else

            {

                floorThree.transform.position = new Vector3(0, 0, maxVaule + 130);

                floorIndex = 1;

            }

        }

    }

}

 

玩家控制

由于是套牛游戏,玩家总是在牛身上,于是移动相关的代码大部分都是在动物身上,于是玩家身上只需要控制套索的旋转,以及切换动物时的跳跃移动就行了。

套索旋转

套索自身旋转较为简单,只需要使用Rotate函数就可以达成目标。但是在游戏中,套索要跟随玩家的手来进行移动并旋转,这样才有玩家控制套索旋转的感觉。实现这个方法有2种方式:

1. 将套索物体绑定在玩家手臂的骨骼节点下面,使其作为子物体跟随玩家移动并旋转。

2. 通过根骨骼节点的位置,每一帧计算套索的位置,并让套索自转。

此处选择了第二种方式,代码如下:

public class Player : MonoBehaviour {

...

    public GameObject lassoObj;         //套索物体

    public float lassoSpeed;            //套索旋转速度

    public Transform lassRootPoint;     //套索的骨骼节点

    public void LassRotate()    // 套索旋转

    {

        lassoObj.transform.position = offestPoint + lassRootPoint.position;

        lassoObj.transform.Rotate(Vector3.up, lassoSpeed * Time.deltaTime);

    }

}

 

效果如下:

跳跃移动

游戏中玩家需要自己控制从动物上弹起,并在空中切换骑乘动物。其空中的移动就是一边向前移动,一边受重力缓慢下降了。代码如下:

public class Player : MonoBehaviour {

...

    public void JumpMove()

    {

        transform.position += transform.forward * moveSpeed * Time.deltaTime;

        transform.position += Vector3.down * 9.8f*0.4f * Time.deltaTime;//乘以0.4f 是让重力减少,增加在空中的时间

    }

}

 

动物控制

动物有2种移动方式。一种是未骑乘下的直线奔跑。2是骑乘状态下有玩家控制的移动。于是动物的移动代码如下:

public class AnimalColler : MonoBehaviour {

...

    public float moveSpeed;//动物移动速度

    public void Move()

    {

        transform.position += transform.forward * moveSpeed * Time.deltaTime*-1;//素材原因,移动方向为Z轴的反方向

    }

    public void RideMove()

    {

        if (Input.GetKey(KeyCode.A))//骑乘状态下移动主要修改移动方向来进行实现的

        {

            transform.Rotate(new Vector3(0, -30, 0) * Time.deltaTime);

        }

        else if (Input.GetKey(KeyCode.D))

        {

            transform.Rotate(new Vector3(0, 30, 0) * Time.deltaTime);

        }

        else

        {

            transform.rotation = startQuat;//停止按键旋转复位

        }

    }

}

 

动物在套索范围内,还有一个改变自身颜色的功能。此处我们是通过更换当前动物的材质来实现的对应功能。代码如下:

public class AnimalColler : MonoBehaviour {

...

    public Material startMater;   //一开始动物的材质

    public SkinnedMeshRenderer rendererTest; //动物自己的渲染组件

    public Material yellowMater;      //编辑器赋值

    public void SwitchColor()

    {

        rendererTest.material = GameMode.Instance.yellowMater;

    }

    public void RestColor()

    {

        rendererTest.material = startMater;

    }

}

 

动物生成

由于地图是复用的,于是我们只需要通过玩家的位置,在玩家前方的一定范围内生成出新的动物即可。代码如下:

public class GameMode : MonoBehaviour {

...

    public GameObject[] animlObjs;      //所用的能够生成的怪物数组

    void Start () {

...

        animlObjs = Resources.LoadAll<GameObject>("Prefabs"); //所有动物预制体存放在Resources文件夹下的Prefabs文件夹中

    }

    public void CreatAnimal()

    {

        int arrayIndex = Random.Range(0, animlObjs.Length);//从数组随机选取一只动物进行生成

        GameObject tempObj = Instantiate(animlObjs[arrayIndex], Vector3.zero,Quaternion.identity);

        tempObj.transform.position = RandomPoint();

        tempObj.transform.Rotate(new Vector3(0, 180, 0));//素材问题,生成后需要先旋转180度才能够正常使用

    }

 

    public Vector3 RandomPoint()

    {

        float xVaule = Random.Range(-14, 14);//随机X轴  游戏固定

        //通过玩家的位置来确定动物的生成的范围,并进行生成

        float zVaule = Random.Range((player.transform.position.z + 100),(player.transform.position.z + 150));

        Vector3 tempPoint = new Vector3(xVaule, 0, zVaule);

        return tempPoint;

    }

}

 

套索范围圈

游戏中套索的范围光圈,我们这简陋的使用一个2D物体来进行替代。使其做为玩家的子物体,跟随玩家移动。然后代码中控制其位置,使其紧贴地面。并通过上面的碰撞器来确定范围内的动物,然后使其改变颜色,并进行后续的操作。代码如下:

public class CirceColler : MonoBehaviour {

    public float startY;        //开始的Y值

    void Start () {

        startY = transform.position.y;

    }

    void Update () {

        transform.position = new Vector3(transform.position.x, startY, transform.position.z);   //固定Y值

    }

    private void OnTriggerEnter(Collider other)

    {

        AnimalColler animal = other.GetComponent<AnimalColler>();

        if (animal!=null)

        {

            GameMode.Instance.animal = animal;  //确定当前被选中的动物

            GameMode.Instance.isCanRide = true; //现在能够骑乘

            animal.SwitchColor();//切换动物颜色

        }

    }

}

 

效果如下:

骑乘

通过之前的步骤,我们已经能够确定玩家是否能够满足骑乘条件了。现在就是来实现骑乘的效果了。

首先,我们需要在动物预制体上新建一个空物体,并命名为ridePoint(方便代码进行读取),并调整至合适位置。用于玩家骑乘。如下图:

设置好的骑乘点

然后在玩家代码中实现骑乘逻辑。代码如下:

public class Player : MonoBehaviour {

...

    void Update () {

        if (Input.GetKeyDown(KeyCode.Space) && !isMove)//按下了空格键并且没有在空中进行移动

        {

            transform.SetParent(null);//离开骑乘的动物

            Time.timeScale = timeScale;//设置时间缩放,制作时间变慢的效果

            isMove = true;//开始在空中进行移动

            circleObj.SetActive(true);//打开套索光圈物体

        }

        else if(Input.GetKeyDown(KeyCode.Space))//在空中按下了空格键

        {

            if (GameMode.Instance.animal!=null)//现在光圈中有动物可以被骑乘

            {

                transform.SetParent(GameMode.Instance.animal.ridePoint);//玩家的父物体设置为骑乘动物的骑乘点

                GameMode.Instance.animal.RestColor();//颜色重置

                GameMode.Instance.animal.ChangSpeed(moveSpeed);//改变速度

                GameMode.Instance.animal.SetRideState(true);//设置骑乘状态

                StartCoroutine(MoveToTarget());//开启协程移动到骑乘点

                isMove = false;//关闭空中移动

                circleObj.SetActive(false);//关闭光圈物体显示

                animalRide = GameMode.Instance.animal;//当前骑乘的动物赋值

                GameMode.Instance.animal = null;//

            }

        }

    }

    IEnumerator MoveToTarget()

    {

        for (int i=0;i<20;i++)//20帧移动到骑乘点

        {

            transform.localPosition = Vector3.Lerp(transform.localPosition, Vector3.zero, 0.2f);

            yield return null;

        }

        transform.localPosition = Vector3.zero;

        Time.timeScale = 1;//时间缩放回滚  结束时间变慢效果

    }

}

 

效果如下:

距离显示

由于我们是直线移动,只需要每一帧计算与开始移动位置的距离,就可以得到我们现在移动的距离。代码如下:

public class GameMode : MonoBehaviour {

...

    public Text fractionText;           //用于显示分数的文本

    private Vector3 startPoint;         //玩家一开始的起始点 用于计算距离

    void Start () {

...

        startPoint = player.position;

    }

    public void UpdataDistance()

    {

        moveDistance = Vector3.Distance(new Vector3(startPoint.x, player.position.y, startPoint.z), player.position);

        fractionText.text = "当前的奔跑的距离: " + ((int)moveDistance).ToString();

    }

}

 

结语

这样一个简单的套牛跑酷游戏就算完成了。虽然有点简陋,不过追求完美的童鞋可以在这个基础上进行美化操作,并继续填充游戏的内容。(PS:动画功能已经实现,未在文章中进行讲解,欢迎参考工程食用!)

相关链接

工程链接:https://pan.baidu.com/s/1yo6KwcnT-f5r4rICcFALCQ?errno=0&errmsg=Auth%20Login%20Sucess&&bduss=&ssnerror=0&traceid=

惯例时间

有线下学习游戏开发打算的童鞋,欢迎访问levelpp.com/

线上课程的传送门如下:https://study.163.com/course/introduction/1006462005.htm

另有专业开发交(gao)流(ji)群等待大家强势插入:869551769

来吧,用Unity当一个套马的汉子的评论 (共 条)

分享到微博请遵守国家法律