解锁你的游戏大门,适合小白入门看的,通过简单的实例大概了解unity的一些基本操作。
常用快捷键
CtrlC/V/X/Z对应复制/粘贴/剪切/回退很多小白都惟手熟尔了,
W物体对象的位置/平移/移动 ,E物体对象旋转,R物体对象缩放,
Q/Alt中键用于场景的移动,右键/Alt左键用于场景的旋转,滚轮/Alt右键用于场景的缩放,
F显示被选目标,CtrlD物体对象克隆相当于复制粘贴,F2重命名,
W/A/S/D右键场景漫游,
其中部分三维软件通用。
C#基础
c#也是一门面向对象的语言,在语法上跟java、cpp等有异曲同工之处,有一定编程基础的小白,对于学一门新的编程语言是不难上手的。在语法上与java的部分区别,比如c#跟c/cpp一样用的是命名空间namespace,java用的是包package;c#继承接口用冒号":",java用extends与implements;c#中有virtual和override修饰虚方法和重写方法,java中没有;java中有static{}、synchroized{}代码块的概念,c#中没有;c#中用is来判断一个实例是否是某一个类的,java中用instanceof 等等。刚入门unity游戏开发,这部分是很重要的,如果这部分也是小白,可以先学程序设计基础篇 ,了解什么是面向对象编程的思想基础。
面板
安装完unity后,登录进unityhub,点击create一个project,点击创建的工程文件。打开unity后,首先映入的是熟悉的天空盒背景了。作为入门级小白,先熟悉一下几个菜单栏与面板窗口。
Scene窗口用于场景物体的搭建,也是我们开发游戏看到的界面。
Game窗口是游戏界面,是我们想达到的效果。
Hierarchy窗口创建或拖入各种游戏对象。
Inspector窗口显示游戏对象的一些属性与脚本信息等。
Project窗口资源脚本文件处理。
Console窗口用于脚本程序调试。
在unity中做游戏就像在拍戏,scene是舞台,game是相机拍到的画面,inspector可以看到每个演员的剧本与扮演的角色,project是后台有着未上场的演员和没有使用的剧本,console是表演过程中的信息反馈。
场景搭建
首先,进行简单的建模与贴图。
在Hierarchy面板中选一处空的地方右键,找到3D Object,选plane平面作为球台。
然后设置模型的大小,左键单击该物体对象即选中它,在Inspector面板中可以看到很多属性,其中基础属性就是game object与transform。transform属性控制物体对象的平移、旋转、缩放,默认值分别是(0,0,0)(0,0,0)(1,1,1)。想让小球作为舞台的主角,可以设置plane大一点,调整缩放值,可以通过快捷键,在Scene面板拉坐标轴,也可以在Inspector中自行输入参数,注意plane是平面,调整X轴跟Z轴,不用设置Y轴。
输入参数设计面的大小,如与后面创建的对象大小不协调,也可以再次点击设置。建模后然后给平面贴图。在Project面板中asset文件create一个folder代表新建文件夹,重名Material,该文件用于存放材质。点击该文件右键create一个Material,点击新建的Material,Inspector面板中找到Albedo,点击框的默认白色块,可以看到有调色块了,点击色块上的大圈小圈选取颜色,也可以拉滑动条调色,选中后,材质上色。
拖曳这个材质到Scene面板中的面,这样模型就有颜色了。
然后这个作为地面,搭建球台不难发现还需要一些墙,可以用几个长方体搭建,在Hierarchy面板中找到3D Object,选cube,就有一个方块出现在场景上。可能会有小白想问,这是个正方体阿。是的,建模还需要你进行一定的变形,点击它,在transform面板中调整位置与缩放。如果不太会设计的,这里放一下教材给的参数参考图,适当调整即可。
摆放好位置后,可以在Material文件附上图片,用于贴图,置放在文件后,将图片直接拉到Scene面板中。
物体的运动
球台搭建后,我们可以开始创建游戏对象了。create一个sphere球体当作小球,调整一下需要摆放的位置。接下来,我们可以先写个脚本尝试让物体动起来。如果只是简单的前进后退,可以调用transform成员方法控制物体移动。但我们是想通过输入控制小球移动的方向,可以添加一些物理特性,给它一些力让他加速,然后后续的小球撞击障碍物是需要实现碰撞的,而在unity中,实现碰撞的条件是,碰撞的两个物体都有碰撞器且至少一个物体有刚体,因此可以给小球添加刚体。选中小球,在菜单栏找到rigidbody,让小球有刚体特性。
控制小球的移动代码如下,刚想了解unity的可以先学会调用,代码也不多。
using UnityEngine;
using Chapter01;
namespace Chapter01
{
public class SphereMove : MonoBehaviour
{
public float speed;//玩家移动速度
//需要用到对象的Rigidbody刚体组件实现移动功能
private Rigidbody playerRigidbody;
void Start()
{
speed = 10f;//为速度变量进行赋值
//获取到该对象Inspector面板中的Rigidbody组件
playerRigidbody = this.GetComponent<Rigidbody>();
}
//物理规定的每一帧间隔调用一次,不会因为不同电脑的性能造成相同时间位移不同,
//可以在ProjectSettings-Time中设置
void FixedUpdate()
{
//获取用户输入,可以在菜单栏的Edit-ProjectSettings-InputManager中查看设置修改
//Input调用输入事件,GetAxis获取方向轴变化,(”Horizontal“)为轴的名称
float moveHorizontal = Input.GetAxis("Horizontal"); //获取水平输入即A/D/left键/right键输入值
float moveVertical = Input.GetAxis("Vertical"); //获取垂直输入即W/S/up键/down键输入值
//定义Player移动的方向向量并赋值
Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);
//调用对象身上Rigidbody组件中的AddForce方法,向按键方向施加一个力使得对象移动
playerRigidbody.AddForce(movement * speed);
}
}
}
把脚本挂载在Hierarchy面板中的sphere,即从project文件拖拽脚本文件到你所在需要的游戏对象。
在上图中,我们可以看到,视角是随着小球滚动而改变的,这也需要我们对相机进行脚本代码的编写,使得相机的视角即我们看到的game窗口跟随小球运动。
using UnityEngine;
using Chapter01;
namespace Chapter01
{
public class CameraFollow : MonoBehaviour
{
public GameObject player;//摄像机需要跟随的对象
private Vector3 offset;//摄像机与对象的位移差值
void Start()
{
//通过GameObject类中的FindGameObjectWithTag()
//方法可以找到场景中带Player标签的第一个对象
player = GameObject.FindGameObjectWithTag("Player");
//计算摄像机与Player玩家初始位置的位移插值
//通过获得其transform组件的position属性值空间中的位置(x,y,z)进行求差
offset = this.transform.position - player.transform.position;
}
//LateUpdate将会在Update()方法之后自动调用
void LateUpdate()
{
//获取Player最新的位置坐标加上初始坐标差后跟新相机transform组件的position位置
this.transform.position = player.transform.position + offset;
}
}
}
把该脚本拖拽在相机,然后把小球的tag改为player,这里的tag可以理解为标签,跟js中的getElementById取元素类似,获取它进行操控。但是在unity中,这个tag中的player是可以有很多个的,代码中获取的是带有这个标签的第一个对象,如果不在这获取,也可以直接点击长按小球拖对象到变量框。
有了大致的了解后,我们就可以继续做我们的方块障碍物了。在这里,不妨想到,一个小球滚动碰撞的游戏,一两个方块明显是没有什么游戏体验的,可以克隆多个障碍物,让小球滚起来撞一个得一分,撞完胜利等等。那入门小白怎么设置这么多障碍物呢,每个物体都有一个脚本,一个一个拖岂不是很繁琐。因此,我们需要学习到预设体。预设体使得游戏对象及资源能够重复利用。在assets文件下新建folder,重名prefab。在Hierarchy面板create一个cube,再把cube拖到prefab文件下。接下来,新建一个空对象重名cubes,把cube对象放在cubes下继承,注意,此时cube的transform坐标系是局部坐标系,因此最好确认cubes的位置再进行调整,然后进行cube的克隆。
可以看到cube的图标是不一样的,这是因为用了预设体,因此,我们接下来对cube进行贴图的时候,只需把你用的材质选中往下拖到prefab文件夹的cube中,场景的cube就全贴上了。简单来说,你想设计的一些脚本信息挂载在预设体上,几个物体对象会跟着一起更新。接着,游戏是想通过小球碰撞方块让方块消失,达到“消灭障碍物”的效果,在这里,我们可以为player小球做代码编写,当然对方块写也行,实现碰撞检测效果即可。
using UnityEngine;
using Chapter01;
namespace Chapter01
{
public class SphereCollision : MonoBehaviour
{
//当挂有刚体组件和碰撞体组件进入到另一个对象的碰撞组件触发区域就会调用该方法
//Collider other 为被进入的触发区域的碰撞对象
private void OnCollisionEnter(Collision collision)
{
//进行判断碰撞触发对象的标签Tag是否为设置的Cube
if (collision.gameObject.CompareTag("Cube"))
{
//调用父类中的销毁函数销毁触碰到的对象物体
Destroy(collision.gameObject);
//调用UIManager中的设置UI文本方法
UIManager._instance.SetText();
}
}
}
}
当然,为了让游戏更生动一点,我们可以对障碍物进行简单的设计,使得游戏画面不会那么呆。我们可以先让方块旋转一定角度摆放,再让它在原地旋转,这是不是就不一样了。
写脚本代码让其旋转。
using UnityEngine;
using Chapter01;
namespace Chapter01
{
public class CubeRotate : MonoBehaviour
{
//定义所需要变量,private为私有参数类型外界不可访问;public公开参数,可以在其Inspector面板进行调节
private Vector3 rotationAxis; //定义三维向量类型的变量:rotationAxis
public float speed;//定义PickUp旋转的速度:speed
//Start()方法会在游戏开始后第一次调用时自动运行该方法
void Start()
{
rotationAxis = new Vector3(0, 1, 0); //设置rotationAxis的向量坐标为(0,1,0)即y轴
speed = 0.5f;//设置旋转的速度为0.5,由于是float类型需要添加f
}
// Update is called once per frame
//游戏在运行时的每一帧都会调用Update()方法
void Update()
{
//this代表该脚本所挂载的对象,调用该对象默认的transform组件并使用其组件内置的Rotate方法
//传入每帧绕某向量轴旋转度数的参数以及设置该向量是以世界坐标系作为参考对象的。
this.transform.Rotate(rotationAxis * speed, Space.World);
}
}
}
做到这里,可以实现大概的游戏运行了。
简单的UI界面
游戏胜利后, 有弹窗显示,有利于给予玩家肯定。对于该游戏,有个计数器也能帮助我们更好清楚游戏的状况,这就要用到ui控件了,该游戏先对其中的文本控件进行了解。创建ui控件与创建前面的物体对象略有不同。先create一个canvas画布对象,再在canvas右键create一个text。这里版本不同可能会有点差异,textmeshpro不一样,这是高级文本设置,有些显示乱码,要自导入字体,当然你熟练了也可以用这个设计得花里胡哨点。
把菜单栏的2D模式打开,然后放缩, 看到的界面应该是这样,有个大框,有个小框,其中大框就是canvas画布,小框就是刚刚创建text文本。
同样,在哪里调整属性,相信大家也会了。值得注意的是,这个canvas画布其实就是对应game窗口的界面,即放文本在哪个角落,也就在game窗口的哪个角落。文本框是可以放缩跟拖动的,这个跟其它软件类似,然后选中文本框,需要调整的文本属性也是那几个,排版内容字体等等,这个默认字体是不够大的,所以先把字体调大点,放到合适的位置,内容可以选择不输入也行,接下来的代码编写会进行改写显示。
一个text用于计数器,一个text用于显示游戏胜利,所以是两个对象,记得重名方便我们操作。然后编写脚本计数,判定胜利条件。那这个脚本给谁,当然是给player小球了,小球撞到一个,计数器就少一个,我们让代码与ui控件关联起来即可。
using UnityEngine;
using UnityEngine.UI;//需要导入UI包
using Chapter01;
namespace Chapter01
{
public class UIManager : MonoBehaviour
{
//单例模式,保证实例的唯一性。
public static UIManager _instance;
public Text countText;
public Text infoText;
public int cubeCount = 8;//场景中Cube的个数
private void Awake()
{
_instance = this;
}
void Start()
{
//初始化设置Text文本框
countText.text = "Count:" + cubeCount.ToString();
infoText.text = "";
}
//当玩家触碰到Cube对象时可以被调用
public void SetText()
{
//显示当前游戏场景中Cube数量
cubeCount--;
countText.text = "Count: " + cubeCount.ToString();
//判断当前场景中Cube数量是否为0
if (cubeCount == 0)
{
infoText.text = "You Win!";//显示获胜文本内容
}
}
}
}
要把文本对象拖进对象框
最后,优化一些细节,看看哪个位置没有摆好,哪里设计得不够合理,控制台有没有报错,不合适的再调整一下,没有什么复杂的操作。到了这里,这个简单的小游戏就完成啦,我们来体验一下吧。
实验心得
这几天,你看着许多素未谋面的软件,都不带装的。