unity 制作小汽车跑起来
Posted X-q-X
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了unity 制作小汽车跑起来相关的知识,希望对你有一定的参考价值。
文章目录
前言
- 以下方法可以说是纯代码实现的,让汽车动起来还有比这个简便的方法,但是以下方式实现是为了更明白unity里面可能出现的一些问题,之后会在写另一个简单的方法.
一、制作简易汽车
- 创建一个cube作为车身名为CarBody,在拿一个cube名为CarHead作为车头,创建四个Cylinder作为车轮名为WheelRF(右前轮),WheelLF(左前轮),WheelLB(左后轮),WheelRB(右后轮),
- 名字和物体要对应,方便管理
- 把车头和轮子挂在CarBody下.
二、车轮向前向后转动
- 创建一个脚本wheelControl挂在四个轮子上
- 在脚本里写上上代码
- 在类下面写一个轮子转动的方法
public void RotWheel(bool isForward)
transform.Rotate(Vector3.up * 360 * Time.deltaTime * (isForward ? -1 : 1));
- 在Update里写
if (Input.GetKey(KeyCode.W))
RotWheel(true);
if (Input.GetKey(KeyCode.S))
RotWheel(false);
为什么是Vector3.up:刚开始创建Cylinder时,Vector3.up指的方向是刚开始时的y轴,然后作为车轮以z轴旋转了90度,但是Cylinder物体的y轴也会随着转动,所以如果车轮要向前转的话,不能看现在的车轮方向轴,所以写Vector3.up
360 * Time.deltaTime :每秒转360度
(isForward ? -1 : 1)正数向前转,负数向后转,按下w,true,向前转,但是因为Cylinder旋转过,所以要注意
-
回到unity运行,轮子可以转动了,但是发现轮子"变异"了
-
这是因为轮子作为CarBody的子物体,子物体会受到父物体的位置变化形状变化影响所以我们要创建一个空物体名为Control,CarBody和四个轮子都挂在Control下,这样就正常了
三.控制车轮向左向右转弯
- 汽车转弯只需要控制前两个轮胎转动就行了,
- 创建一个脚本挂在Control下
- 在CarControl类下面创建两个Transform控制前面两个轮子
public Transform LF;
public Transform RF;
- 接着写轮子转弯的方法
public void FowardWheelLF(Transform Wheel, bool isRight)
Wheel.Rotate(Vector3.up * 30 * Time.deltaTime * (isRight ? 1 : -1),Space.World);
第二个参数Space.World说明Vector3.up是沿着世界坐标的up方向转动车轮
- 在Update里写
if (Input.GetKey(KeyCode.A))
FowardWheelLF(LF, false);
FowardWheelLF(RF, false);
if (Input.GetKey(KeyCode.D))
FowardWheelLF(LF, true);
FowardWheelLF(RF, true);
- 回到unity,将对应的车轮拖到相应的位置
- 这样就成功了,但是,如果车子是上坡的话,再来看看这轮转动是什么样的
- 会发现前后是没问题的,但是向左向右转的时候,是有点问题的.它是按照世界坐标转动的,但是汽车运动是变动的
- 所以我们来创建两个空物体,分别叫LF_obj,RF_obj,
- 然后把空物体拖到对应轮胎的中心地方
- 然后把两个空物体挂在Control下,再把两个前轮分别挂在对应的下面
- 在Control下的脚本里就不是把轮子拖进去了,把轮子对应的空物体拖进去
- 然后把控制轮子转弯的方法里第二个参数Space.World就可以删掉了,
- 最后运行没什么问题
四.车子前后跑起来
- 在CarControl脚本里的update里加上
if (Input.GetKey(KeyCode.W))
transform.Translate(Vector3.forward * 5 * Time.deltaTime);//每秒向前走5m
if (Input.GetKey(KeyCode.S))
transform.Translate(Vector3.forward * -1 * 5 * Time.deltaTime);
- 车子就可以向前向后移动了
五.车子左右转弯
- 在CarControl脚本下update里按下A健里面加上
transform.Rotate(Vector3.up * -1 * Time.deltaTime * 60);
- 按下D健加上
transform.Rotate(Vector3.up * Time.deltaTime * 60);
- 注意的是Control这个空物体必须在CarBody中心,
- 转弯完成,但是发现车子原地不动也可以转弯,
- 所以我们在刚才的代码加个条件,按下A或D时,还要按下W健才能转弯
if (Input.GetKey(KeyCode.W))
transform.Rotate(Vector3.up * -1 * Time.deltaTime * 60);
if (Input.GetKey(KeyCode.W))
transform.Rotate(Vector3.up * Time.deltaTime * 60);
- 这样原地转动时只有车轮转了
六.限制车轮转动角度
- 发现转弯时,车轮可以一直转,现实中,车轮转弯有限制的.
- 我们把WheelLF和WheelRF先拿出来
- 然后设置LF_obj和RF_obj的属性面板里transform里的Rotation里的y设置90
- 设置完成后,再将车轮挂到上面去
- 然后再CarControl脚本里的update里按下A健车轮转弯设个条件
if (RF.localEulerAngles.y >= 60 )
FowardWheelLF(LF, false);
FowardWheelLF(RF, false);
- D健也一样
if (LF.localEulerAngles.y<=120)
FowardWheelLF(LF, true);
FowardWheelLF(RF, true);
七.汽车倒退时转弯
- 我们发现汽车后退时没有写转弯的代码
- 我们在按下A或D时,还要按下W健才能转弯的条件下价格else if
if (Input.GetKey(KeyCode.W))
transform.Rotate(Vector3.up * -1 * Time.deltaTime * 60);
else if (Input.GetKey(KeyCode.S))
transform.Rotate(Vector3.up * 1 * Time.deltaTime * 60);
- 注意正负号
- 还有D健里也是一样
if (Input.GetKey(KeyCode.W))
transform.Rotate(Vector3.up * Time.deltaTime * 60);
else if (Input.GetKey(KeyCode.S))
transform.Rotate(Vector3.up * -1 * Time.deltaTime * 60);
八.车轮自动回正
- 我们发现车子走动转弯后,再次点击W时,车轮还是弯的,没有自己回正,
- 我们判断车子是否已经转动过,在CarControl脚本update里写
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.A))
IsComeback = true;
- 如果转动过,那么接着写
if (IsComeback)
LF.localEulerAngles = new Vector3(0, Mathf.SmoothDamp(LF.localEulerAngles.y, 90, ref num, 0.5f), 0);
RF.localEulerAngles = new Vector3(0, Mathf.SmoothDamp(LF.localEulerAngles.y, 90, ref num, 0.5f), 0);
if (LF.localEulerAngles.y==90)
IsComeback = false;
- 此外,在类下面创建两个值
float num;
bool IsComeback = false;
总结
最后,差不多是一个完美的汽车了,可以自己给材质球上颜色,或者直接在asset story里下载免费的跑车,就很拉风.
Unity3D开发小游戏Unity3D零基础一步一步教你制作跑酷类游戏
推荐阅读
一、前言
最近跑酷游戏比较流行,开发教程也很多,但是大部分都是不太详细。
这篇文章就带着大家一步一步开发出来一个跑酷类的游戏,教程比较基础,适合大部分Unity开发的初学者。
还有就是,此专栏已经开通收费,里面整合的都是小游戏的开发教程,想要学习Unity开发游戏的,都可以订阅一下。
如果学习中出现什么问题,记得联系我,我有空就会回复的。
二、效果图&下载链接
CSDN下载地址:https://download.csdn.net/download/q764424567/87274444
三、教程
在教程开始之前,我们分析一下跑酷类游戏制作思路:
(1)道路和障碍物:我们可以先设置三段道路,然后障碍物随机生成。
(2)道路中间有抵达点:角色到达抵达点判断是否将后面的道路移动到前面接起来。
(3)到达第一段的抵达点,不切换路段(切换到后面不就掉下去了)。
(4)到达第二段的抵达点,将1号路段移动到最前面。
(5)到达第三段的抵达点,将2号路段移动到最前面。
(6)循环往复,无穷尽也。
(7)主角的移动脚本,躲避障碍物,移动位置固定三个点,可以跳,可以铲地。
(8)主角碰到障碍物就挂,游戏结束。
OK,下面就正式开始。
1、新建项目
博主的Unity版本是Unity2018.4.0f1
,推荐大家使用我这个版本:
创建完项目后,设置文件目录(不按照这个来也行,不影响):
2、导入资源
资源已经上传到CSDN,需要的可以下载:
https://download.csdn.net/download/q764424567/87274226
下载后解压:
导入到项目中:
3、处理动画资源
角色的模型:
接着我们就可以新建一个Animator Controller文件来管理动画文件:
命名为character:
接着我们将动画剪辑(idle、run、jump、slide)都拖到Animator视图中:
设置这些动画片段之间的切换触发条件:
(1)新建三个bool值,来控制动画的切换:
(2)右击动画片段,选择“Take Transition”将run、jump、run 、slide、idle进行连接。
提示:连过线之后,点击线,就可以设置Conditions(切换的条件):
每条线的切换条件如下所示:
run→jump,Conditions:jump=true
jump→run,Conditions:jump=false
run→slide,Conditions:slide=true
slide→run,Conditions:slide=false
run→idle,Conditions:idle=true
提示:当run切换到idle的时候就说明已经死亡了,就播放站立的动画了。
设置好之后的样子:
接下来我们就可以在场景中看一下动画效果了:
4、处理路段模型
首先我们找到导入的资源SimpleRoadwork,里面有一个Demo场景,点进去可以看一下各类模型:
在Prefabs文件夹中,可以找到我们需要的各类模型,包括路面、路标、障碍物:
接下来,我们就设计一下路面,将Road_straight_mesh拖入到场景中,然后复制一份,调整旋转:
选中左右两个路段,使用快捷键Ctrl+D可以复制很多份,然后调整位置如下图所示:
接着找到Assets/SimpleRoadwork/Prefabs文件夹,使用文件夹中的路标进行摆放:
接着摆放障碍物,也在Assets/SimpleRoadwork/Prefabs文件夹中:
障碍物需要放到一个组中,方便后期代码控制:
因为障碍物我们要后期自动生成,只需要障碍物的位置坐标即可,现在就可以先隐藏起来:
然后设置到达点(到达点的目的是当角色到达这个位置的时候,自动切换路线):
隐藏它的Mesh Renderer ,将BoxCollider IsTrigger设置成true:
修改它的的名字为MonitorPos0(必须这个名字,代码要控制):
路段就完成了:
将所有的对象拉到Road_1对象下面,路段一就完成了,整个目录如下:
接着制作路段二,然后选中Road_1对象,快捷键Ctrl+D复制一份出来,修改名字Road_2,调整位置:
修改Road_2中的MonitorPos0对象的名字,将名字改为MonitorPos1:
接着制作路段三,然后选中Road_2对象,快捷键Ctrl+D复制一份出来,修改名字Road_3,调整位置:
修改Road_3中的MonitorPos1对象的名字,将名字改为MonitorPos2:
三段路制作完成后如下图所示:
5、主角模型处理
玩家模型:
明显是有点大,我们给它同比例缩小一下:
接着设置一下摄像机的视角:
6、生成障碍物
在Project视图中,右击选择Create→C# Script命名为Control_Scenes:
双击打开脚本,修改代码:
using UnityEngine;
public class Control_Scenes : MonoBehaviour
public GameObject[] m_ObstacleArray;
public Transform[] m_ObstaclePosArray;
void Start()
//因为要生成3段路段,所以生成的障碍物也是不同的,传递不同的下标生成不同的路段障碍物
//游戏开始自动生成3组障碍物
for (int i = 0; i < 3; i++)
Spawn_Obstacle(i);
//生成障碍物
public void Spawn_Obstacle(int index)
//销毁原来的对象
GameObject[] obsPast = GameObject.FindGameObjectsWithTag("Obstacle" + index);
for (int i = 0; i < obsPast.Length; i++)
Destroy(obsPast[i]);
//生成障碍物
foreach (Transform item in m_ObstaclePosArray[index])
GameObject prefab = m_ObstacleArray[Random.Range(0, m_ObstacleArray.Length)];
Vector3 eulerAngle = new Vector3(0, Random.Range(0, 360), 0);
GameObject obj = Instantiate(prefab, item.position, Quaternion.Euler(eulerAngle));
obj.tag = "Obstacle" + index;
提示,因为脚本中设置了对象的tag,所以需要在Inspector视图中设置一下Tag:
将脚本挂在Scripts对象上:
将Prefab文件夹里面的障碍物模型拖入到ObstacleArray对象数组卡槽中(任意障碍物),将隐藏以后的障碍物拖入到ObstaclePosArray对象数组卡槽中:
运行:
7、路段切换
我们接着打开Control_Scenes.cs脚本,修改代码:
using System.Collections.Generic;
using UnityEngine;
public class Control_Scenes : MonoBehaviour
//是否到达第一段路
bool m_ISFirst;
//所有的路段对象
public GameObject[] m_RoadArray;
//障碍物数组对象
public GameObject[] m_ObstacleArray;
//障碍物的位置
public List<Transform> m_ObstaclePosArray = new List<Transform>();
void Start()
m_ISFirst = true;
//游戏开始自动生成3组障碍物
for (int i = 0; i < 3; i++)
Spawn_Obstacle(i);
//根据传递的参数来决定切换那条路段
public void Change_Road(int index)
//到达第一条路段不切换
if (m_ISFirst && index == 0)
m_ISFirst = false;
return;
else
int lastIndex = index - 1;
if (lastIndex < 0)
lastIndex = 2;
//当前到达的路段的上一条路段进行切换,也就是说达到第二条路段,将第一条路段进行切换
m_RoadArray[lastIndex].transform.position = m_RoadArray[lastIndex].transform.position + new Vector3(150, 0, 0);
Spawn_Obstacle(lastIndex);
public void Spawn_Obstacle(int index)
//销毁原来的对象
GameObject[] obsPast = GameObject.FindGameObjectsWithTag("Obstacle" + index);
for (int i = 0; i < obsPast.Length; i++)
Destroy(obsPast[i]);
//生成障碍物
foreach (Transform item in m_ObstaclePosArray[index])
GameObject prefab = m_ObstacleArray[Random.Range(0, m_ObstacleArray.Length)];
Vector3 eulerAngle = new Vector3(0, Random.Range(0, 360), 0);
GameObject obj = Instantiate(prefab, item.position, Quaternion.Euler(eulerAngle));
obj.tag = "Obstacle" + index;
PS:这里解释一下代码,怎么切换的呢
举个例子,角色跑到了第二段,那么第一段要移动到第三段后面隔一个路段长度的距离,接下来画个图:
那么为啥x轴减去150。这是因为我发现这三条路段的距离都差了50,坐标轴是负轴,所以就减去了150。
我们可以测试一下效果:
但是仅仅这样是不够的,我们还需要在角色到达抵达点的时候,切换路线,当然第一段路不用切换,因为再切就没了。。
8、角色移动
提示:因为我们设定的三条道,所以角色只能在三条道里面切换。
那么只需要改变角色的z值就可以了。
如果角色在最左边,那么只能往右移动,同理在最右边,只能往左移动,在中间两边都可以移动。
接着我们就可以看一下z轴的值。
中间:
左边:
右边:
知道这些后,就可以使用脚本来控制玩家移动了,在Project视图中,右击选择Create→C# Script命名为Control_Player:
双击打开脚本,修改代码:
using UnityEngine;
using UnityEngine.SceneManagement;
public class Control_Player : MonoBehaviour
//场景控制对象
Control_Scenes m_ControlScenes;
//前进速度
public float m_ForwardSpeeed = 7.0f;
//动画组件
private Animator m_Anim;
//动画现在状态
private AnimatorStateInfo m_CurrentBaseState;
//动画状态参照
static int m_jumpState = Animator.StringToHash("Base Layer.jump");
static int m_slideState = Animator.StringToHash("Base Layer.slide");
void Start()
//获得主角身上的Animator组件
m_Anim = GetComponent<Animator>();
m_ControlScenes = GameObject.Find("Scripts").GetComponent<Control_Scenes>();
void Update()
//主角向前跑
transform.position += Vector3.right * m_ForwardSpeeed * Time.deltaTime;
//获得现在播放的动画状态
m_CurrentBaseState = m_Anim.GetCurrentAnimatorStateInfo(0);
if (Input.GetKeyDown(KeyCode.W))
m_Anim.SetBool("jump", true);//切换跳状态
else if (Input.GetKeyDown(KeyCode.S))
m_Anim.SetBool("slide", true);//切换下滑状态
else if (Input.GetKeyDown(KeyCode.A))
Change_PlayerZ(true);//移动主角向左移动
else if (Input.GetKeyDown(KeyCode.D))
Change_PlayerZ(false);//移动主角向右移动
if (m_CurrentBaseState.fullPathHash == m_jumpState)
m_Anim.SetBool("jump", false);//改变动画状态
else if (m_CurrentBaseState.fullPathHash == m_slideState)
m_Anim.SetBool("slide", false);//改变动画状态
if (m_IsEnd && Input.GetKeyDown(KeyCode.F1))
//重新开始游戏
SceneManager.LoadScene(0);
public void Change_PlayerZ(bool IsAD)
if (IsAD)//当按下键盘的A 也就是向左移动
//主角在最左边
if (transform.position.z == -5f)
return;
//主角在中间
else if (transform.position.z == -10f)
transform.position = new Vector3(transform.position.x, transform.position.y, -5f);
//主角在最右边
else
transform.position = new Vector3(transform.position.x, transform.position.y, -10f);
else//当按下键盘的D 也就是向右移动
//主角在最右边
if (transform.position.z == -15f)
return;
//主角在中间
else if (transform.position.z == -10f)
transform.position = new Vector3(transform.position.x, transform.position.y, -15f);
//主角在最左边
else
transform.position = new Vector3(transform.position.x, transform.position.y, -10f);
键盘WSAD控制上跳,下滑,左右移动等操作。现在就可以去试试啦。
但是,有一点哈,角色怎么越跑越远离开了我们呢,因为,还没有写摄像机跟随脚本,接下来就写一下摄像机跟随玩家移动的脚本。
9、摄像机跟随
在Project视图中,右击选择Create→C# Script命名为Control_Camera:
双击打开脚本,修改代码:
using UnityEngine;
public class Control_Camera : MonoBehaviour
//间隔距离
public float m_DistanceAway = 5f;
//间隔高度
public float m_DistanceHeight = 10f;
//平滑值
public float smooth = 2f;
//目标点
private Vector3 m_TargetPosition;
//参照点
Transform m_Follow;
void Start()
m_Follow = GameObject.Find("Player").transform;
void LateUpdate()
m_TargetPosition = m_Follow.position + Vector3.up * m_DistanceHeight - m_Follow.forward * m_DistanceAway;
transform.position = Vector3.Lerp(transform.position, m_TargetPosition, Time.deltaTime * smooth);
OK 摄像机跟着Player跑起来了。
10、碰撞检测
我们需要不停的躲避障碍物,一旦碰撞到障碍物就dead了
我们首先修改障碍物的碰撞器属性:
Mesh Collider : Is Trigger=true
我们给Player加上刚体和碰撞体:
注意要勾上Is Trigger。
继续修改Control_Player.cs脚本:
using UnityEngine;
using UnityEngine.SceneManagement;
public class Control_Player : MonoBehaviour
//场景控制对象
Control_Scenes m_ControlScenes;
//前进速度
public float m_ForwardSpeeed = 7.0f;
//动画组件
private Animator m_Anim;
//动画现在状态
private AnimatorStateInfo m_CurrentBaseState;
//动画状态参照
static int m_jumpState = Animator.StringToHash("Base Layer.jump");
static int m_slideState = Animator.StringToHash("Base Layer.slide");
void Start()
//获得主角身上的Animator组件
m_Anim = GetComponent<Animator>();
m_ControlScenes = GameObject.Find("Scripts").GetComponent<Control_Scenes>();
void Update()
//主角向前跑
transform.position += Vector3.right * m_ForwardSpeeed * Time.deltaTime;
//获得现在播放的动画状态
m_CurrentBaseState = m_Anim.GetCurrentAnimatorStateInfo(0);
if (Input.GetKeyDown(KeyCode.W))
m_Anim.SetBool("jump", true);//切换跳状态
else if (Input.GetKeyDown(KeyCode.S)Unity3D开发小游戏Unity3D零基础一步一步教你制作跑酷类游戏