第一次接触unity项目,学习了unity官方教程roll-a-ball。接下来是我的整个学习过程
项目学习的过程分为了这样几个步骤:
1.项目简介。
2.环境和小球
3.相机视角和游戏区域
4.收集功能,滚动和创建游戏
第一个部分是介绍了整个游戏的玩法,如题所说的,滚动小球,然后触碰消掉方块,所有方块都被消除完毕后,游戏结束。
第二部分介绍了unity的界面和每个部分的简单功能,并且教我们创建一个unity工程和如何控制小球滚动。第三部分教我们控制相机视角 和创建游戏区域。第四部分教我们创建方块和文字显示区域,并且编写脚本控制它们,最后完成一个可以玩的游戏。
首先打开unity,选择创建一个新工程,起名叫Roll-a-ball
这是我们一开始打开的部分。
scene窗口用来显示我们所创建的所有游戏对象,现在只有一个小摄像机和小太阳。摄像机就相当于我们玩家的视角。太阳是模拟真的太阳发出光线,可以对物体施加光影的效果。game窗口是用来预览游戏画面的界面,当我们点击位于窗口上方的播放按钮是,我们就可以和玩家一样在这个窗口里面玩游戏了,再次点击播放按钮则退回了编辑界面。hierarchy(层级)窗口是放置我们建立的所有的游戏场景,包括地图,人物,模块等等。project窗口是用来存放我们写的脚本,场景的属性(颜色等等物理属性)。在最右边最大的窗口是显示我们当前选择的东西的详细信息。比如你选择了一个.cs文件,那么这个窗口会显示这个cs文件的源代码,如果你选择了一个物体,那么这个窗口就会显示这个物体的各种属性。这个窗口也是我们操作比较多的地方。
首先我们创建一个平面,在hierarchy窗口中点击create->3d->plan,这时在since窗口出现了一个白色的平面,就是我们刚刚创建的平面。将平面命名为Ground。
可以看到ground是位于一个scence下的,这时右键点击UNtitled,选择save scence as,给这个场景起名叫_Scecne,点击保存。注意我们保存的场景都在Assets文件夹下。
点击Ground,右边的inspector窗口就出现了一系列ground的属性。目前我们只需要知道transform窗口中的属性,position是指ground的位置,x和z是水平位移,y是垂直位移,这和数学课本中常用的坐标写法略有不同。rotation是指ground的旋转属性,可以通过改变它的值来改变其相对平面的角度。scale是指ground的大小,也就是长宽高。
接下来我们需要给这个ground添加颜色,在project窗口中创建Material(素材)文件夹,用来存放我们的素材文件。在这个文件夹下,我们新建一个素材,右键文件夹,选择create,material,创建一个素材,选择颜色可以随便选择。然后鼠标点击按住这个素材,直接将它拖到我们在hierarchy中创建的ground上,这时,ground就被染成了这个颜色。
接下来我们创建墙壁,墙壁也是一个物体,需要显示在场景中,我们在hierarchy中点击create,选择3D,cube(方块)创建一个长方形方块,属性和ground差不多,不过这里我们需要将它的长宽高设置一下,位置也要设置一下。
将其位置设置在左边,长度设为10,宽度为0.5,高度为1,如图所示:
这时,第一面墙壁就设置完成了。我们还需要另外三堵墙。将这一块墙壁复制粘贴,修改scale属性和position属性,使其符合我们的要求。
接下来,我们需要创建一个球,这个物体也是在hierarchy窗口中创建的。点击create,3d,sphere,这样就创建了一个球体。不过需要将其position的y设置为0.5,使其可以贴合游戏区域。
好了,现在游戏的场景创建的差不多了,接下来就是编写脚本来对小球进行控制。
首先,点击小球,点击在inspector窗口中最下方的Add Component按钮,选择new script,c#,创建一个叫做PlayController的脚本文件。这个脚本文件可以帮助我们控制小球的运动等功能。这个文件创建后会在project窗口中显示。为了方便管理,我们创建一个新的文件夹script来放置所有的脚本文件。接下来,双击打开这个文件,一般情况下,unity是用自带的编译器monodevelop打开它,这个编译器在安装unity时自动安装。如果电脑上安装了visual studio的话,也可以用它来打开。
接下来,我们看到在PlayerController中,编译器自动为我们创建了两个函数,start()和updat()。Start函数是创建对象时调用的函数,有点像自动调用的Java中的构造函数。Update是对象更新时被调用的函数。这里我们使用的是FixedUpdate(),因为Update 和 FixedUpdate都是对象更新时被调用的函数,在每一帧都会调用的,但是区别在于两者的帧长度是不一样的。Update 与当前平台的帧数相关,根据渲染的帧数来调用的。FixedUpdate采用的真实时间间隔作为帧长,处理物理逻辑一般在FixedUpdate中处理。
这时,我们要思考需要这个脚本文件来干什么,首先便是控制小球能够由键盘wasd或上下左右光标控制移动。那么首先便是给小球绑定一个rigidbody(刚体)对象。刚体能让你的游戏对象被物理引擎所控制,它能通过受到推力和扭力来实现真实的物理表现效果。所有游戏对象必须包含刚体组件来实现重力、通过脚本施加力、或者与其他对象进行交互,这一切都通过NVIDIA的PhysX物理引擎来实现。接下来就是获得我们在键盘上输入的命令。Input类可以使得我们获取到控制器(键盘,手柄或触摸屏)操作的属性。获取到这些属性后,我们通过Vector3来存储这些属性,最后调用rigidbody.AddForce()函数来更新小球的状态,代码如下:
public class PlayerController : MonoBehaviour {
public float speed;
public Rigidbody rb;
void Start () {
rb = GetComponent();
}
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal");//水平方向移动的数据
float moveVertical = Input.GetAxis("Vertical");//垂直方向移动的数据
Vector3 movement = new Vector3(moveHorizontal,0.0f,moveVertical);
rb.AddForce(movement * speed);
}
}
我们现在已经写好了PlayController脚本。接下来回到unity中,刚刚在脚本中定义了一个rigidbody,我们还需要在player中也定义一个这个属性。点击add Component 选择Physics,rigidbody。这样就为小球创建了一个rigidbody属性。然后,将player拖到script中的rigidbody上。
完成后,我们点击场景上方的play按钮,这时,我们就可以通过wasd或光标键来控制小球的移动了。
在成功移动小球后我们发现了一个问题,那就是我们的视野,也就是camera的角度和位置不是很好,所以我们需要写一个脚本来控制camera和player的位置。创建脚本的步骤和上面一样。我们需要这个脚本来保持camera和player的相对位置,并且要让camera跟随player移动。首先,使用GameObject(统一场景中所有实体的基类。)来获取到player,用vector3来设置camera的坐标。在start中使用transform属性来获取player和camera的位置,然后用camera的位置减去player的位置来获取两者的相对位置。当player移动的时候,通过在update方法中加上这个相对值来动态调整camera的位置。
public class CameraController : MonoBehaviour {
public GameObject player;
private Vector3 offset;
void Start()
{
offset = transform.position - player.transform.position;
}
void LateUpdate()
{
transform.position = player.transform.position + offset;
}
}
结果如下(我把ground设置的太小了。。):
在完成了小球移动的功能后,我们开始制作被小球所碰撞的方块了。方块的创建和小球的创建时一样的,所以这里不再赘述。
将方块改名为Pick Up,为了美观显示,将其大小设为长宽高0.5,rotation也都设为0.5。接下来我们需要让方块变为黄色并且让他旋转起来。前者需要新建一个Material属性,后者需要使用脚本文件来控制。
为Pick Up建立一个脚本,在这个脚本中,我们不需要初始化任何对象,所以可以删除start方法,只留下update方法。
public class Rotator : MonoBehaviour {
// Update is called once per frame
void Update () {
transform.Rotate(new Vector3(15, 30, 45) * Time.deltaTime);
}
}
其中 transform.Rotate(Vector3 * Time.deltaTime);是以欧拉角旋转,顺序是ZXY。(什么是欧拉角可以自行百度,我也不懂。。。)编辑好后这个方块便可以旋转了。
完成这一步后,我们还需要将其他的一模一样的方块部署到小球周围。在hierarchy中新建一个空的物体取名叫Pick Ups,将pick up放到这个组织下。点击since窗口右上角的z轴坐标,通过control+c和control+v来复制方块,把它们摆放到小球周围。
接下来,我们需要设置小球碰撞方块后,方块消失的功能了。这个功能的需要在小球中实现,因为是需要小球触碰到方块时,方块才消失。
我们需要在playercontroller中添加一个OnTriggerEnter的方法。
private void OnTriggerEnter(Collider other)
{
if(other.gameObject.CompareTag("Pick Up"))
{
other.gameObject.SetActive(false);
}
}
在这里 collider other 就代表我们将要触碰到的物体,如果这个物体的标记为Pick Up,那么就把他设为不可见。collider的意思是碰撞器,也叫对撞机。如果你想让某个有物理属性的物体可以和其他物体进行互动的化,就必须给这个物体设置collider属性,在unity中创建物体时会自动创建这个属性。
此时,我们点击play按钮,就可以控制小球收集方块了。
接下来,我们需要制作一个记分板,用来记录收集小球的数量,在小球收集完成后,显示出游戏结束的消息。
创建计分板的控件在hierarchy的UI中,点击create->ui->text,我们便创建了一个文本区域。在这里我们一次性创建两个,分别起名叫CountText和WinText。创建好后点击inspector,transform窗口右上角的齿轮,点击reset,完成初始化操作。
我们需要设置这两个文本区域在游戏中的位置。我们让计分板位于游戏区域的左上角,选取CountText,在其inspector窗口中有一个特殊的位置选项按钮,点开它,发现他叫anchor presets(锚点预置)。它的介绍是按住shift键同时设置枢轴(可以理解为中点),按住alt键同时设置位置。这样我们就将CountText设置到左上角了。
wintext相对简单,只需将他设置到游戏窗口正中心即可,也是在inspector窗口中设置
分别将两个文本框的默认值设置为count和you win。接下来我们需要编写脚本来实现计数功能。打开PlayerCountroller,我们需要创建两个text实例和一个私有的count值来记录数字。在start方法中将count值设为0,wintext设为空。我们需要有一个方法来计数以及控制youwin的显示。创建新方法SetCountText,代码如下:
public class PlayerController : MonoBehaviour {
public float speed;
public Rigidbody rb;
public Text CountText;
public Text WinText;
private int count;
// Use this for initialization
void Start () {
rb = GetComponent();
count = 0;
SetCountText();
WinText.text = "";
}
private void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(moveHorizontal,0.0f,moveVertical);
rb.AddForce(movement * speed);
}
private void OnTriggerEnter(Collider other)
{
if(other.gameObject.CompareTag("Pick Up"))
{
other.gameObject.SetActive(false);
count = count + 1;
SetCountText();
}
}
void SetCountText()
{
CountText.text = "Count:" + count.ToString();
if(count >= 9)
{
WinText.text = "You Win!";
}
}
}
最后,我们要做的是在unity中将text组件和脚本文件关联起来,方法很简单,就是将两个text组件拖到PlayerCountroller相应的地方:
好了写到这里,我们这个游戏的功能就算是全部实现了。现在可以在场景中试玩了,也可以将它打包成一个独立的游戏文件(.EXE文件)。