怎么制作简单的饭制关卡 – How to make a fanmade level?

DIY Line v1.0 代码使用教程

转载请注明出处

作者:小唏丶

 

写在前面:

本教程旨在培养大家对于Unity/饭制关卡的兴趣,以及帮助大家对Unity(2017.4.2f2免费版)的使用形成初步的认识。

这个代码功能非常少,仅满足制作一个Dancing Line饭制关卡的最低需求,教程本身也有点填鸭式教育的感觉,一步一步跟着做就行了,非常简单……至于每一步为什么要这样做?这样做会怎么样?我应该会在每一步下面添加备注,因此本教程可能看起来会很冗长。

代码下载链接

本教程的步骤顺序和视频(油管:https://www.youtube.com/watch?v=57O6146uA2Q,B站:https://www.bilibili.com/video/av24232834)中的大不相同(因为录视频的时候是想到什么做什么,甚至漏了许多关键步骤)。

下面是The Winter冬日的项目工程的链接:https://pan.baidu.com/s/1ozyTFC7Pzy6jOhd0yqbVGw 密码:urxa

 

  • Unity的基本操作

既然要用Unity来做东西,肯定要先学会Unity中的一些基本操作。但这并不是本教程的重点(因为百度上都有,这里就不在累述)。掌握在Scene面板中对于物体的移动,以及右键主观旋转,ALT+左键围绕旋转就可以了。

……

 

  • 具体步骤

 

  1. 创建一个工程
  • 双击Unity的图标,然后会有一个窗口
  • 点击右上角的New
  • 依次设置好项目名称、项目存放位置后点击Create Project
  • 然后你会看到Unity的主界面,里面有各种面板(Hierarchy/Scene/Game/Project/Console/Inspector等),请先确定它们的位置,方便后续教程的阅读。

 

  1. 导入素材

什么是素材(asset)?素材就是你在游戏中要使用的东西,比如音乐,模型,代码,甚至一些UI,着色器。一切你不能在Unity中做出来的东西都可以称之为素材。在本篇教程中,使用的代码(line.cs)与音乐(thewinter.mp3)就是素材。

导入素材的方式有两种:

  • 找到项目工程的存放位置,打开Assets文件夹,然后把东西粘贴进去

或者

1)直接把东西粘贴在Project面板中的Assets文件夹下

 

  1. 创建游戏中的主要物体

在一个简单的关卡中,必须有的东西有:一个Cube(线本身)、一个Cube(线的尾巴)、一个Camera(视角)、一个Plane(地板)、一个Cube(墙的原型)、一个Cube(类似于动画的装饰)、皇冠、钻石等……

以下是创建物体的方法:

  • 在Hierarchy面板中,空白处点击右键→选中要创建的物体(基本的几何体在3D Object中,Empty是一个什么都没有的物体)

或者

1)顶部菜单栏 GameObject→选中要创建的物体(基本的几何体在3D Object中,Empty是一个什么都没有的物体)

或者

*1)或者 如果你有模型的话,创建模型的方式如下:在Project面板中找到导入的模型,按住,拖到场景中

阅读完这部分,请依次创建一个Cube(线本身)、一个Cube(线的尾巴)、、一个Plane(地板)、一个Cube(墙的原型)、一个Cube(类似于动画的装饰)、皇冠(用Empty代替)、钻石(用Empty代替)。

 

  1. 给物体插入组件

什么是组件(component)?一个游戏物体往往具备很多性质,比如线,它是实体的,有碰撞体积的,那就需要用到Rigidbody(刚体组件);又比如皇冠吃到后会有光晕,那就要用到Halo组件(本教程中用light组件代替)……等等

在本教程中,用到的组件有:

  • Transform。物体自带,描述物体的位置、旋转、大小。
  • Mesh Filter。物体自带,描述物体显示出的形状。
  • Box Coilder。物体自带,描述物体碰撞(摸得到)的形状与大小。
  • Mesh Renderer。物体自带,描述物体显示出的样子。
  • Rigidbody。在Physics类目下,描述物体一些物理性质。
  • Light。在Rendering类目下,描述物体发出光源的性质。
  • Audio Sourse。在Audio类目下,描述物体携带的声音。
  • Scripts。代码,本教程会用带cs。

 

以下是创建组件的方法:

  • 在Hierarchy或者Scene面板中,选中被插入组件的物体。此时在Inspector面板中会显示物体的信息。
  • 在Inspector面板中,点击Add Component,然后选中相应的组件。

或者

  • 在Hierarchy或者Scene面板中,选中被插入组件的物体。此时在Inspector面板中会显示物体的信息。
  • 顶部菜单栏 Component,然后选中相应的组件。

或者 对于代码来说

1)在Hierarchy或者Scene面板中,选中被插入组件的物体。此时在Inspector面板中会显示物体的信息。

2)在Project面板中,找到代码,直接拖到物体的Inspector面板上。

 

  1. 添加一些物体材质

什么是材质(material)?材质就是物体的材料、质感,一般设置在Mesh Renderer组件下。材质多种多样,透明的,描边的,荧光的都可以弄,但在本文仅使用标准材质。

 

以下是创建并设置材质的方法:

  • 找到project面板,在Assets文件夹下,右键→create→material,并给该材质命名。
  • 在project面板点击相应的材质,此时在inspector面板上会显示信息。
  • 在inspector面板中,找到Albedo,点击右边的色块,设置颜色。
  • 其他的选项你们可以自己动一动,观察有什么变化,网上都有具体说明,这里不累述

 

  1. 设置物体的信息
  • 一个Cube(线本身)

①在视频中,我命名这个Cube为line

②添加Rigidbody组件,并去掉Use Gravity的勾(因为本代码不支持掉落与旋转)

③添加Audio Resource 组件,并点击AudioClip右边的小圆点,然后选择游戏音乐(设置一些东西的方式,一般就是点该项最后的小圆点,具体操作看视频)。并取消掉Audio Resource前的勾。(为什么取消?因为音乐不是一开始就播放,播放代码已经整理在line.cs中)

④添加line.cs的script组件,并依次设置Dline(线头),Tail(线的尾巴),Mcamera(摄像机),Road(墙),Decorates(装饰),Dieeff(死亡特效)。设置方法为点击右边的小圆点,然后找到对应物体。如果没有对应的物体(比如正文没有说到的Dieeff),请额外创建一个Empty并设置给它。

⑤找到Mesh Renderer组件下的Materials,左边有个三角形,点一下三角形能看到,Materials的具体信息,在Element 0 后面选择对应的材质。

⑥调整物体的大小位置(可以更改transform里的数据来微调,也可以直接在Scene面板中进行操作)

 

  • 一个Cube(线的尾巴)

①在视频中,我命名这个Cube为tail

②禁用Box Collider组件(取消Box Collider前面的勾)。为什么?因为线的尾巴不应该有实体,否则会与线头产生物理碰撞。

③找到Mesh Renderer组件下的Materials,左边有个三角形,点一下三角形能看到,Materials的具体信息,在Element 0 后面选择对应的材质。

④调整物体的大小位置(藏起来,丢到最下面或者最上面就行,不要让玩家看到)

 

  • 一个Camera(视角)

相机应该是工程创建出来后自带的。

①在视频中,我命名这个Main Camera为camera

②添加Audio Resource 组件,并点击AudioClip右边的小圆点,然后选择死亡音效,并取消掉Audio Resource前的勾。

③调整物体的位置。(小技巧:对于摄像机来说,可以先在Scene面板中调整好视角,然后在Hierarchy面板中选中camera这个物体,然后再依次点击顶部菜单栏GameObject→Align With View。这样就能调整摄像机的视角到目前编辑状态中Scene的视角。)

 

  • 一个Plane(地板)

①找到Mesh Renderer组件下的Materials,左边有个三角形,点一下三角形能看到,Materials的具体信息,在Element 0 后面选择对应的材质。

②调整物体的大小位置(大小调大一点最好)

 

  • 一个Cube(墙的原型)

①在视频中,我命名这个Cube为road(不要吐槽为什么不是wall,当时脑子抽了)

②设置材质(和前面一样)

③调整物体的大小位置(藏起来,丢到最下面或者最上面就行,不要让玩家看到)

④给它添加一个名为”wall”的标签(tag)。方法:在hierarchy面板中选中该物体,再在Inspector面板中找到Tag(Transform的上面),点击tag右边的选择框→Add Tag。然后跳转到Tags & Layers界面,点击Tags下面的加号,输入wall。然后再回到④开始的时候,给物体选上”wall”的Tag。

 

  • 一个Cube(类似于动画的装饰)

如果你觉得这个装饰没有必要,请创建一个Empty代替创建一个Cube,然后做下列的①③④步。

①在视频中,我命名这个Cube为decorates

②设置材质

③调整物体的大小位置(藏起来,丢到最上面,不要丢到最下面)

④添加一个名为”deco”的标签(这步可能可以不用做,因为我代码好像改过了)

 

  • light(光)

光源应该是工程创建出来后自带的。

①设置Transform下的rotation属性(它的位置改变与否并没有什么实际影响)即光照方向

②设置Shadow Type为Hard Shadows(其实不动也行,但是跳舞的线官方用的是这个。也可以设置成No Shadows,这样降低配置要求)

③其他数据你们也可以调整一下,自行探索

 

  • 皇冠

不管你用的皇冠是什么样子的(哪怕你用Empty来代替皇冠),请执行下面的步骤

①添加名为”crown”的标签(必须设置,不然会报错……代码偷懒所以这么写了= =)

②添加light组件,并勾选draw halo后面的勾,这样就有光晕了,可以通过设置物体大小和光强来调整光晕的大小;然后禁用light组件(把Light前面的勾去掉)为什么禁用?因为只有吃到皇冠的时候才有光晕出现……

 

  • 钻石

不管你用的钻石是什么样子的(哪怕你用Empty来代替皇冠),请执行下面的步骤

①添加名为”dia”的标签(必须设置,不然会报错……代码偷懒所以这么写了= =)

 

  1. 创建路径

相信目前,关卡的基本应该都设置好了。

  • 找到线头(line)物体的line(Script)组件,勾选Road Maker
  • 点击Unity窗口中的播放键(就是屏幕中间那个三角形,可以看看视频中我是怎么操作的)
  • 开始游戏,根据音乐点击,使得线转弯。(这时是没有尾巴的,如果有尾巴,请看看Roadmaker有没有勾上;而且会生成墙壁)
  • 点击完后,点击暂停按钮(一定不要结束!不然墙就都没了)。这时在hierarchy面板中会出现很多road(Clone)。选中它们,复制下来。
  • 点击停止按钮(其实就是播放按钮那个三角形)。在hierarchy面板中,粘贴它们。
  • 找到线头(line)物体的line(Script)组件,取消勾选Road Maker

 

截止到目前为止,你的关卡已经成型,接下来请自行装饰,更多特技请看一下狗带_die的Unity模板和nullptr的UE4模板!以后有空的话,我也许还会写关于Unity中更多功能的使用以及给出的代码怎么自定义更改吧

 

  1. 保存场景

别问我为什么现在才想到保存= =

1.Ctrl+S,把这个场景存在Assets文件夹里面,命名为main.unity(必须是这个,因为代码里面写了main = =)

 

  • 关卡的打包
  1. Windows平台
  • 基本设置

顶部菜单栏依次点击Edit – Project Settings – Player,你会看到有各种选项,Product name填写游戏名称,Default Icon是游戏图标,游戏图标要放在Assets文件夹里面的,其它选项请自行探索。

  • 打包

顶部菜单栏依次点击File – Build Settings,选择Windows平台,再设置一下参数(其实不用动也行),点击build。然后会让你选择输出文件夹,命名……都设置到了以后就等待吧……打包时间视游戏工程和电脑配置决定……如果打包失败,请关注Console面板中的信息,复制过去百度一下,或者在评论区留言(然后我来百度2333)来进行解决。

 

  1. Android 平台

1)基本设置

顶部菜单栏依次点击Edit – Project Settings – Player,你会看到有各种选项,Product name填写游戏名称,Default Icon是游戏图标,游戏图标要放在Assets文件夹里面的,其它选项请自行探索。

然后点击下面的安卓图标,在Other Settings中的Identification里,Package Name要修改一下,改成什么都无所谓。

2)环境配置

这个有点麻烦,要装java sdk 这些,网上也有教程,这里就不写了吧……这块是最麻烦的一块,当时弄了半天才搞明白……= =

  • 打包

和Windows平台同样的操作

  • 调试

毕竟是在电脑上打包的,所以不保证弄出来的apk能在手机上很好地运行,可能会有打不开、闪退等情况;如果这个情况很不幸地发生了……那很不幸,我也不会弄……估计是环境没有配置好的问题。

如果帧数很低,那请尽量减少场景中的物体,以及取消阴影!

 

  • 附件(请把文件命名为cs)

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.SceneManagement;

 

public class line : MonoBehaviour {

//DIY Line v1.0 – script by Pegasi

//Please attach me to the line, then set  dline,tail,mcamera,road,decorates,dieeff.

//You can add more to make this better!

public GameObject dline,tail,mcamera,road,decorates,dieeff;

 

private GameObject tempgo,tempdia,tempcr;

 

public bool direction,alive,start,load,roadmaker;

 

public float cameraspeed,temprm;

 

public Vector3 offset,tempcrgo;

 

private GameObject[] dia,cr;

 

List<GameObject> go =new List<GameObject>();

 

void Start ()

{

start = false;

load = true;

alive = true;

//find diamonds and crowns

dia = GameObject.FindGameObjectsWithTag (“dia”);

cr = GameObject.FindGameObjectsWithTag (“crown”);

//

}

 

void Update ()

{

if (load == true)

{

//save the initial distance between camera and line

offset = mcamera.transform.position – dline.transform.position;

cameraspeed = 0.03f;

load = false;

//

}

//restart

if(Input.GetKeyDown(KeyCode.R)==true){

SceneManager.LoadScene (“main”);

}

//

if (start == false && alive == true)

{//start game

if (Input.GetMouseButtonDown(0) == true || Input.GetKeyDown (KeyCode.Space) == true)

{

start = true;

dline.GetComponent<AudioSource> ().enabled = true;

}

 

}//

 

if (start == true)

{//turn

if (Input.GetMouseButtonDown (0) == true || Input.GetKeyDown (KeyCode.Space) == true )

{

if (direction == true)

{

direction = false;

}

else

{

direction = true;

}

}

}//

//build road/wall more efficiently

if (roadmaker)

{

temprm += 1;

//why there is temprm?to reduce the ammount of roads

//why build one when click?to ensure there is road/wall when line turns(or it will look weird)

if (temprm % 6 == 1 || Input.GetMouseButtonDown(0) == true || Input.GetKeyDown (KeyCode.Space) == true)

{

GameObject.Instantiate (road, dline.transform.position + new Vector3 (3, 0, -3), dline.transform.rotation);

GameObject.Instantiate (road, dline.transform.position + new Vector3 (-3, 0, 3), dline.transform.rotation);

}// // //

}

else

{//when you play …I dont put the part in Update but if(roadmaker) because these actions will create new gameobject and interfere the copying of road

GameObject.Instantiate (tail, dline.transform.position, dline.transform.rotation);

if (Input.GetMouseButtonDown (0) == true || Input.GetKeyDown (KeyCode.Space) == true )

{

if (direction == true)

{

go.Add(GameObject.Instantiate (decorates, dline.transform.position + new Vector3 (8, -9, -5), dline.transform.rotation));

}

else

{

go.Add(GameObject.Instantiate (decorates, dline.transform.position + new Vector3 (-5, -9, 8), dline.transform.rotation));

}

}

}//

}

 

void FixedUpdate ()

{//smooth camera

mcamera.transform.position = Vector3.Lerp (mcamera.transform.position, offset + dline.transform.position, cameraspeed);

//

//some ‘animations’ .I didnt use animation component because I dont know how it works in Unity 🙁

foreach (GameObject tempgo in go)

{

tempgo.transform.position += new Vector3 (0, 0.2f, 0);

}

 

foreach (GameObject tempdia in dia)

{

tempdia.transform.localEulerAngles += new Vector3 (0, 2, 0);

if (Mathf.Abs (dline.transform.position.x – tempdia.transform.position.x) < 1 && Mathf.Abs (dline.transform.position.z – tempdia.transform.position.z) < 1 && tempdia.transform.localScale.z >0)

{

tempdia.transform.localScale -= new Vector3 (0.3f, 0.3f, 0.3f);

}

}

foreach (GameObject tempcr in cr)

{

tempcr.transform.localEulerAngles += new Vector3 (0, 2, 0);

if (Mathf.Abs (dline.transform.position.x – tempcr.transform.position.x) < 2 && Mathf.Abs (dline.transform.position.z – tempcr.transform.position.z) < 2 && tempcr.transform.localScale.z >0)

{

tempcr.transform.localScale -= new Vector3 (0.26f, 0.26f, 0.26f);

tempcrgo = tempcr.transform.position;

}

if (tempcr.transform.localScale.z <=0)

{

tempcrgo += new Vector3 (Random.Range (-2f, 2f), Random.Range (-1f, 2f), Random.Range (-2f, 2f));

tempcr.GetComponent<Light> ().enabled = true;

tempcr.transform.position = Vector3.Lerp (tempcr.transform.position, tempcrgo, 0.02f);

 

}

}

//

if (start == true && alive == true)

{//how the line move

if (direction == true)

{

dline.transform.position += new Vector3 (0.3f,0,0);

}

else

{

dline.transform.position += new Vector3 (0,0,0.3f);

}

}//

}

 

void OnCollisionEnter (Collision x)

{//when die…

if (x.collider.tag == “wall”)

{

alive = false;

mcamera.GetComponent<AudioSource> ().enabled = true;

dieeff.SetActive (true);

}//

//when complete the level…

if (x.collider.tag == “Finish”)

{

offset = offset + offset + offset + offset;

cameraspeed = 0.01f;

}//

}

}

 

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注