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

作者:繁华如梦
前言
《疯狂动物园》(不是《疯狂动物城》)是一款将“和动物互动”与跑酷元素结合起来的游戏。虽然游戏本身多年前便已推出,但由于机缘巧合最近才接触到。
作为一个(自认为)涉猎广泛的游戏开发人员,怎么不来搞一下试试呢?
地图复用
之前做过跑酷游戏的教程,地图是使用方块自动生成的。而就这款游戏而言,不需要这么复杂的地图生成。这里我们先做一个简单的地图,复用一下就行。
新建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=
惯例时间
有线下学习游戏开发打算的童鞋,欢迎访问http://levelpp.com/。
线上课程的传送门如下:https://study.163.com/course/introduction/1006462005.htm
另有专业开发交(gao)流(ji)群等待大家强势插入:869551769