Unity知识三:两种方式实现切水果的刀痕

来源:互联网 发布:湖南广电网络控股集团 编辑:程序博客网 时间:2024/04/28 19:39

Unity作为游戏开发平台之一,还是有很多实用的小技巧的,今天来学习一下怎样用两种方式来显示切水果游戏中的刀痕:
1.正常显示下的刀痕:
什么叫正常显示下的呢?我们所接触过的切水果游戏一般都是2D游戏,那我们知道,2D游戏可以用Unity直接来做,还可以使用NGUI、UGUI或者其他方法通过UI来实现。
所以我们第一种方法就是不借助UI来做。
首先来看看我们刀痕的素材:(需要的同学可以右键另存。^_^)
这里写图片描述
打开Unity:
这里写图片描述
新建一个空游戏体,命名为“BackGround”,然后在组件面板中添加组件GUI Texture:(创建出来的物体不要忘记reset一下哦~)
这里写图片描述
找到Texture属性,点击后面的圆圈,为它选择一个背景图片:
这里写图片描述
背景素材:
这里写图片描述
添加好背景图片之后,我们看Scenes面板和Game面板,发现了两个问题:
这里写图片描述
1.在Scenes面板中,添加上去的图片看不到;
2.Game面板中图片的位置有点不对。

Scenes中看不到的情况,由于我也是小白,搞不懂原理,但是我猜是因为GUITexture是UI的一部分,所以在Scenes面板中有时候显示效果不好,至于怎么设置去让它显示出来,我暂时还不知道,我现在是以Game面板上的显示情况做参考的。

Game面板下显示不对,我们把它Transform下的Position设置为(0.5,0.5,0):
这里写图片描述
这样就可以了。

接下来我们再新建一个空游戏体,将其命名为Knife,并为其添加LineRenderer组件:
这里写图片描述 这里写图片描述

我们在上面右图中可以找到Materials属性,下面有Size和Element 0.
因为Materials是一个Materials类型的数组,Size是数组的长度,Element是数组元素的值,此时Size为1,那么它就只有一个元素,索引值为0,Element 0因此而来。

我们刚刚创建的游戏体是用来显示刀痕的,那么我们就要把上面我们的刀片素材给它。
大家会发现,直接把图片拖给Element 0不成功,因为Element 0是Material类型的,而图片还不是材质,它现在只是一张图片,对应的材质还没有生成。
我们直接把图片拖给Knife游戏体,Unity会自动为这张图片创建一个材质Material,并把这个材质赋给Element 0;
这里写图片描述
大家可以在Scenes面板中看到它。

接下来,我们找到Line Renderer下的position属性,发现它也是一个数组,这个数组是干什么用的呢?他就是用来画出Line Renderer的关键属性。

实际上Line Renderer是这样的:你给我几个坐标,我把相应的材质在几个坐标之间渲染出来。现在:Element 0为(0,0,0)Element 1为(0,0,1),那就是说,把图片在坐标(0,0,0)和(0,0,1)之间显示出来,因为两点确定一条直线嘛~对不对?

既然我们了解了Line Renderer的原理,那么我们就知道了,我想用鼠标画出一条线,我只要获取到鼠标左键按下时的坐标和鼠标左键抬起时的坐标,然后把它们分别给Element 0和Element 1,那这条线不就是画出来了吗?

那我们就开始写脚本咯:

using UnityEngine;using System.Collections;public class tes : MonoBehaviour {    Vector3 pos1;     //定义起点坐标    Vector3 pos2;     //定义终点坐标    LineRenderer myLinRenderer;     //定义一个LineRenderer对象    // Use this for initialization    void Start () {        myLinRenderer = GetComponent<LineRenderer>();     //给LineRenderer对象初始化    }    // Update is called once per frame    void Update () {        if (Input.GetMouseButtonDown(0))      //当鼠标左键按下的时候        {            pos1 = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y,1));     //将起点坐标记录下来        }        if (Input.GetMouseButtonUp(0))         {            pos2 = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,Input.mousePosition.y,1));     //将终点坐标记录下来            myLinRenderer.SetPosition(0,pos1);            myLinRenderer.SetPosition(1,pos2);     //分别将起始坐标和终点坐标付给相应的变量        }    }}

写好之后我们先来想一下,LinRenderer是给它设置坐标它就开始渲染了,那上面我们写好的脚本也就是说:当我鼠标松开的时候,这条线才能画出来,而当鼠标一直按下的时候,这条线我们是看不到的。

我们把这个脚本给我们创建的游戏体Knife,运行后:
这里写图片描述

我们可以看到,在Scenes面板中确实有一条类似刀痕的东西,但是有两个问题:
颜色和我们的好像不太一样,那是因为在这里:
这里写图片描述
有Parameters属性,这里可以设置刀片的起始宽度和终点宽度,起始颜色到终点颜色的过渡,默认是白色的。

另一个严重的问题是:在Game面板中根本不显示这条刀痕,左侧的Scenes面板中明明是能显示的!
我们看运行的时候,BackGround的位置是(0.5,0.5,0),摄像机的位置是(0,1,-10),而且是正交摄像机:
(0,1,-10)
此时刀片的两个坐标的Z都是-9,说明不是脚本的问题:
这里写图片描述
按理来说刀片是完全能显示的,我们再检查一下层Layer,即使重新设置了Layer也还是无法显示。

好像有点懵逼了。。。

经过一系列的检查,终于找到了症结所在,从一开始我们就错了,还记得一开始我们说那个BackGround在Scenes面板中看不到对吧?因为我们添加的是GUITexture,这里我们做错了,不应该添加GUITexture组件,而应该是SpriteRenderer:
这里写图片描述
这下我们在Scenes面板和Game面板下都可以看到了:
这里写图片描述

Game下显示不对,我们把BackGround的Scale调整为(2.4,2.4,1):
这里写图片描述

然后我们把BackGround和Knife的Layer都改为默认,(因为大家可能发现截图中他们的Layer是NGUI,那是因为我在做后面的一种方法的时候没有改过来。),同时,摄像机的CullingMask保持默认的Everything。
我们再来运行一下:
鼠标按下,并移动一段距离,没有反应:
这里写图片描述
当松开鼠标的时候:
这里写图片描述

啊哈哈哈哈!
终于粗来了!

而且好帅气的对不对?

没错,就是这样。

之前发现了问题,为什么我没有把之前的内容修改掉,而是在文章中用不少的篇幅来找错误呢?那是因为我觉得我们所犯的每一个错误对我们自身而言都十分有意义,当我有一天回头看看这篇文章的时候,我会对GUITexture和SpriteRenderer有十分深刻的印象,就酱~

言归正传:
但是,我们又发现了一个问题:这里面的刀痕只有一条,那我现在所画的刀痕不是直线,而是有拐点的呢?它还是只是显示一条连接起始点和终点的刀痕,中间的拐点全都没有表现出来。

既然这样,那么我们把中间的拐点也都记录下来不就好了吗?

我们这样来思考:当我鼠标左键按下的时候,每隔0.2秒记录一次鼠标的位置,然后把它加到那个位置坐标数组中:
其实这个位置坐标更像一个泛型,因为它有数组的性质,但是又没有长度限制:
这里写图片描述 这里写图片描述

我们可以这样,每隔0.2秒,就让这个泛型的长度加1,然后把坐标填进去,只要设置了两个或两个以上坐标,这条线就能画得出来:

修改代码如下:

using UnityEngine;using System.Collections;public class tes : MonoBehaviour {    Vector3 pos1;    Vector3 pos2;    LineRenderer myLinRenderer;    int count=0;    //定义一个变量,用来修改泛型的长度    float time = 0.2f;  //定义一个时间间隔    // Use this for initialization    void Start () {        myLinRenderer = GetComponent<LineRenderer>();    }    // Update is called once per frame    void Update () {        if (Input.GetMouseButtonDown(0))         {            pos1 = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y,1));            myLinRenderer.SetVertexCount(1);    //第一次按下鼠标左键时,应该有了一个点,所以把节点的数目设置为1            myLinRenderer.SetPosition(0, pos1);     //有了一个节点就设置一次坐标,而不是单单记录坐标        }        if (Input.GetMouseButton(0))    //当鼠标一直按下的时候        {            time -= Time.deltaTime;     //时间进行递减            if (time <= 0)      //当时间减小到0或0以下时,            {                time = 0.2f;        //把时间重置                count++;        //节点数自增                Vector3 pos = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 1));     //纪录此时的坐标值                myLinRenderer.SetVertexCount(count);        //每隔0.2秒,就增加一个节点,增加一个点的方法就是SetVertexCount()方法                count--;        //count还要自减,因为在设置位置的时候,索引是比节点数小1的                myLinRenderer.SetPosition(count,pos);       //设置这个增加的节点的位置                count++;        //最后,因为增加了一个节点,所以count是要增加1的            }        }        if (Input.GetMouseButtonUp(0))      //当鼠标左键抬起的时候,依旧要纪录最后一个点的坐标,最终把count重置为0        {            count++;            pos2 = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,Input.mousePosition.y,1));            myLinRenderer.SetVertexCount(count);            count--;            myLinRenderer.SetPosition(count,pos2);            count = 0;        }    }}

代码中加了注释的地方就是修改的地方,对于count的值得问题,我用的是这种笨方法,需要思考一下才能理清。

保存运行,就得到了:
这里写图片描述

效果已经出来了,然而,LineRenderer在拐弯的地方自己处理不好,有时候就会变成这样:
这里写图片描述
这是因为拐弯的时候涉及到了宽度的变化,宽度变化就会出现这种情况。

我们把刀片的Parameters属性下的Start width和Endwidth的值设置不同,比如一个为1,一个为3:
在把第一个脚本挂上来,运行一下:
这里写图片描述
我们会发现,怎么都不是一条直线了,因为起始宽度是1,终点宽度是3,1到3不是自然过渡的,所以就好像是在中间突然少了一块一样,这是LineRenderer的问题,同理,我们在转弯的时候遇到的问题与它类似。

不过可以适当调小它们的宽度来使其更自然一些,比如起始和终点宽度都设为0.3:
这里写图片描述
这样就稍微好一点,但是解决不了根本问题,要彻底解决需要自己写脚本来控制。

这里我们就把第一种方法给讲完了,接下来说第二种方法:在NGUI中实现鼠标画刀痕:
Ctrl+N新建一个Scenes,命名随意,导入NGUI的包。
找到NGUI->Open->Prefab Toolbar,
这里写图片描述
这里写图片描述
把左上角的背景拖入Hierarchy面板中:
这里写图片描述
找到BG - Stripes,把它删掉:
这里写图片描述
依次打开:这里写图片描述
这里写图片描述
点击Create,选择目录并命名后,点击保存,不要关闭这个窗口,在Project面板中找到背景图片,我们会发现Create按钮变成了Add/Create,点击它。这张背景图片后面出现了Update字样:
这里写图片描述
现在可以关闭这个窗口了。

选中Hierarchy中的Control - Background,在右侧的Inspector面板中找到UISprite,点击Atlas:
这里写图片描述
弹窗如下窗口:
这里写图片描述
找到你刚才命名的那个prefab,如果没有,就点击下面的Show All,然后点击对应后面的Select,然后在点击Sprite:
这里写图片描述
在弹出的面板中选择背景图片,并双击它。
这里写图片描述
我们发现一片漆黑:这里写图片描述
点击右面的ColorTint(点击它右侧的黑色区域):
这里写图片描述
弹出如下窗口:
这里写图片描述
用鼠标将方框左下角的白色圆圈移到左上方的白色区域:
这里写图片描述
结果就能正常显示了:
这里写图片描述

上面都是一些废话,基本上大家都会操作的。

接下来按照上面相同的方式创建刀片,并把上一个脚本拖给它(做一点点修改):

using UnityEngine;using System.Collections;public class tes : MonoBehaviour {    Vector3 pos1;    Vector3 pos2;    LineRenderer myLinRenderer;    int count=0;       float time = 0.2f;      public Camera myCamera;     //声明一个公开的摄像机类型(天哪,什么类型都有。。。)    // Use this for initialization    void Start () {        myLinRenderer = GetComponent<LineRenderer>();    }    // Update is called once per frame    void Update () {        if (Input.GetMouseButtonDown(0))         {            pos1 = myCamera.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, -1));     //这里要做修改            myLinRenderer.SetVertexCount(1);                myLinRenderer.SetPosition(0, pos1);             }        if (Input.GetMouseButton(0))            {            time -= Time.deltaTime;                if (time <= 0)                  {                time = 0.2f;                        count++;                        Vector3 pos = myCamera.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, -1));       //这里要做修改                   myLinRenderer.SetVertexCount(count);                        count--;                        myLinRenderer.SetPosition(count, pos);                       count++;                    }        }        if (Input.GetMouseButtonUp(0))              {            count++;            pos2 = myCamera.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, -1));     //这里要做修改            myLinRenderer.SetVertexCount(count);            count--;            myLinRenderer.SetPosition(count,pos2);            count = 0;        }    }}

加注释的地方就是修改的地方,把所有Camera.main.ScreenToWorldPoint全部改为myCamera.ScreenToWorldPoint(myCamera要看你的具体命名。)
还有后面的Z轴值也要改为-1.

Ctrl+S保存脚本,回到Unity中,选中刀片,会看到多了一个myCamera:
这里写图片描述

把左侧的Camera沿着箭头拖过去:
这里写图片描述

运行:
这里写图片描述
宽度自己调一下吧,如果不显示,设置一下Knife的Layer和Camera的Culling Mask就好了。

只需要修改一点点的脚本就能运用在NGUI中了。

嗯,这就是我个人目前实现切水果刀痕的两种方式,如果大家有什么好的办法欢迎交流哦~

同时,文章里有什么有误的地方,欢迎大家批评指正!谢谢!

2 0
原创粉丝点击