2015-05-13 11:35:22 yuxikuo_1 阅读数 964
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4712 人正在学习 去看看 张刚

本系列文章由Aimar_Johnny编写,欢迎转载,转载请标明出处,谢谢。

http://blog.csdn.net/lzhq1982/article/details/12783493


在做这个demo的过程中,制作小地图着实刁难了我一把,百度了很多文章,花了好长的时间,需要的知识点实在太多了,尤其是shader语言,好在最后成功把它啃下来了,先声明一下,本篇文章将会是这个系列中最难的,不过如果成功做出来成就感也是大大的,其实按照我的步骤一步一步来也没那么复杂啦,接下来我把这个过程分享给大家,下面上一张截图:


看右上角,那个就是小地图,也许有点不太好看,没办法,谁让我不是美术啊,需要的图素都是自己用Photoshop做的,记得有人说过,不会美术的程序不是好策划,所以自己来吧。


先说一下原理,我们做小地图用的技术就是遮罩,玩过flash的对这个词应该不新鲜,何为遮罩呢,通俗一下讲,你有两张纸,一张纸上画了漂亮的山川河流,另一张纸就是张白纸,中间挖个圆洞,然后你把白纸盖在那张画满山川河流的纸上,只有中间圆洞的地方你能看到,其他地方都被盖住了,保持白纸不动,移动后面的画纸,你会看到连续的不同的地貌,我们的小地图原理就是这样的,时刻保持角色在中间,动的只是后面的背景罢了。只是这里需要多处理一下,就是除了那个圆洞,其他的部分我们要透明掉。


相信这么解释应该没有不懂的了吧。如果还不清楚那要么是我的表达能力有问题,要么你的智商。。。咳咳,言归正传,按照上面的理论,我们都该准备些什么呢。最起码的得有一张完整的地图吧,得有个圆形的遮罩吧,再漂亮点圆形遮罩需要个圆框,地图上得有个小标志显示玩家的位置和方向。

地图好搞,在unity中调到场景的顶视图,然后截个图就好了,缩放一下比例,我的地图是512*512的,取名map,如下图:


丑是丑了点,谁让我的地形简单呢,再一次声明,我是个程序。

遮罩就需要你自己画个了,要保证它和背景图一样大,我这里也是512*512的,中间是个白色的圆,其他地方alpha是透明的。如图:


我这里并没有截全部512的图,不要以为只这么小啊,除了白圆,其他地方都是透明的,其实什么颜色的无所谓,只要是圆的就行。

然后做个圆框,也是512的,圆框和白圆大小一致,中间和其他地方都是透明的。


最后是角色的那个小标记

资源就这些,准备好就可以开干了。


关于NGUI我这里就不解释了,看过我前面文章的童鞋应该知道怎么用了,我们要把小地图放在右上角的锚点上,不是简单的放几个sprite的事情,那我们需要做些什么呢。来,我们倒着说,先看结果,我希望我的右上角先有个Panel,然后Panel下有个Textrue,而我的小地图就是绘制在这个Texture上;那小地图是以什么方式绘制到这个Texture上的呢,当然是靠material(材质),而且是一个能实现遮罩,透明,动态渲染的材质。那只能靠材质中的shader了;先不说遮罩和透明,先说动态渲染,我们以前用到的材质都是静态的,而现在我们要用到的是地图可以移动的动态材质,所以要用动态渲染,要说动态渲染,那最先想到的就是Render Texture,要说什么是Render Texture,看这里好了:渲染纹理。由果推因,我们就知道都该做些什么了,一个一个攻克吧,现在我们由因及果。


1、绘制渲染纹理(Render Texture)

a、先在MainCamera下创建一个UI,选择NGUI->Open the UI Wizard,保持设置,点Create Your UI,然后Anchor下的Panel改名为MiniMapRenderPanel。

b、创建一个Atlas,不知道什么是Atlas的可以看我前面的文章,选NGUI->Open the Atlas Maker,新弹出的界面上修改你的atlas名称,点击那个完整的地图,就是我上面的那个map,然后点Create。


c、在MiniMapRenderPanel下建一个sprite,NGUI->Open the Widget Wizard,Atlas选刚建的那个Atlas,Template选sprite,Sprite选map,其他默认。最后建完了是这个结构。


d、在资源里新建个Render Texture,Assets->Create->Render Texture,起名MiniMapRenderTexture。

e、设置camera,那个NGUI的camera设置如下:


Clear Flags设为Solid Color,Background设为黑色,这样当你走到地图的边缘时,没有地图的地方会绘制成黑色。Projection设为平行投影Orthographic,不了解平行投影和透视投影的话需要补一下3d基础了。Target Texture那里把之前做的那个Render Texture拖上去。这样摄像机投影的地方就会绘制在这个Render Texture上,也就是地图会绘制在它上面了,然后我们就可以做material了。

f、有一点差点忘了,Anchor那里的Side一定要选择TopLeft,地图的原点是从左下角开始的。



2、制作材质(material)

这是本篇的难点,要用到shader语言,如果没有3d基础的可能理解起来有点费劲,不懂也没关系,按着操作也能做出来。

a、创建一个Shader,Assets->Create->Shader。

b、打开shader,把下面的代码覆盖过去。

[csharp] view plaincopy
  1. Shader "Transparent/Mask"  
  2. {  
  3.    Properties  
  4.    {  
  5.       _MainTex ("Base (RGB)", 2D) = "white" {}  
  6.       _Mask ("Culling Mask", 2D) = "white" {}  
  7.       _Cutoff ("Alpha cutoff", Range (0,1)) = 0.1  
  8.    }  
  9.    SubShader  
  10.    {  
  11.       Tags {"Queue"="Transparent"}  
  12.       Lighting Off  
  13.       ZWrite Off  
  14.       Blend Off  
  15.       AlphaTest GEqual [_Cutoff]  
  16.       Pass  
  17.       {           
  18.          SetTexture [_Mask] {combine texture}  
  19.          SetTexture [_MainTex] {combine texture, previous}  
  20.       }  
  21.    }  
  22. }  
你百度遮罩shader的话会有很多,但基本没有解释的,我这里解释一下,第一行是设置你的shader的路径和名称,比如上面的shader就建在了Transparent下,起名Mask,大括号里面有两个部分,第一个部分是属性Properties,第二部分是SubShader。

Properties里是设置渲染的属性,比如这里设置了两张图片和一个滑动条,第一张图片用来加载背景图片,就是我们之前做的那个Render Texture,用来显示地图,第二张图片就是遮罩图片,用我们之前的那个白圆,滑动条范围从0到1,初始值0.1,再看一下语法。

[csharp] view plaincopy
  1. _MainTex ("Base (RGB)", 2D) = "white" {}  

_MainTex是属性名,会在SubShader中用到,Base (RGB)是在界面上显示的名称,你会在属性面板上看到,2D是图片维数,white是默认值。
SubShader是处理渲染的主体,Tags是标签,Queue标签决定被渲染的次序,而Transparent是四个预定义的渲染队列之一,任何有关alpha混合的对象都应该在这里处理,看这里可以了解的更多:SubShader Tags,关闭光照,关闭z缓冲器的写操作,关闭混合,Alpha测试是当Alpha大于等于你之前设定的_Cutoff时有效,也就是说这里当alpha大于等于0.1的图素会被渲染出来,其他的就透明了。Pass通道里处理混合,先设置第一张图片:SetTexture [_Mask] {combine texture},这里是遮罩图片,然后第二张图片和前一张混合:SetTexture [_MainTex] {combine texture, previous},而我们之前关闭了混合,所以第二张图片只是纯粹的显示,但大括号里第二个参数表示alpha,这里previous表示我们用之前那张图片的alpha,而第一张图片的alpha除了白圆部分,其余部分都是0,所以这张图片除了与白圆 重合的地方,其他地方alpha也是0,这样就透明了,只剩下了圆的地方,想了解Pass看这里:着色器语法:Pass,想了解SetTexture看这里:着色器语法:Texturing

写了这么多,纯粹手打,觉得好的麻烦支持一下,哈哈。Shader有一定难度,但据说会shader的程序员薪水都在2万以上啊,望眼欲穿啊,所以大家努力学吧。

如果上面的没看懂,你又不想学,那就跳过吧,反正把代码粘过去就可以了。

c、创建一个material,Assets->Create->Material,然后Shader那里找到你建的那个shader,在Transparent下面。

d、这时界面上会出现Base(RGB)和Culling Mask,Base(RGB)里把你之前那个Render Texture拖上去,Culling Mask把那个白圆的图片拖上去,如下图:


这样你的材质就做完了。坚持到这步的为自己鼓个掌吧,你离成功不远了。


3、在界面的右上角用NGUI建地图

终于到了最后一步了,剩下的工作就简单多了,回到你的界面布局那里,有关NGUI界面布局不了解的看我前面的文章,在右上角的Anchor下建个Panel,起名MiniMapPanel,然后下面加两个sprite和一个Texture,一个sprite是圆框,一个sprite是小箭头,表示地图上的玩家,Texture用来接收之前的材质显示地图,如下图:



Texture那里大小调成512*512的,Material那里把之前做的材质拖上去就ok了,如果显示顺序有问题别忘了调Depth或Z值。

现在你应该可以看到东西了,但小箭头位置不对,当然,还没上代码呢。

创建一个MiniMap的脚本,我把全部代码贴上来。

[csharp] view plaincopy
  1. public class MiniMap : MonoBehaviour {  
  2.   
  3.     // Use this for initialization  
  4.     public GameObject point;  
  5.     public GameObject map;  
  6.     private GameObject hero;  
  7.     private float miniMapScaleRatio;  
  8.       
  9.     void Start () {  
  10.         map.transform.localScale = new Vector3(Screen.height, Screen.height, 1);  
  11.         hero = GameObject.Find("/Blade_Girl_Prefab");  
  12.         GameObject terrain = GameObject.Find("Terrain");  
  13.         Terrain script = terrain.GetComponent<Terrain>();  
  14.         miniMapScaleRatio = (float)map.transform.localScale.x / script.terrainData.size.x;  
  15.     }  
  16.       
  17.     // Update is called once per frame  
  18.     void Update () {  
  19.           
  20.         if (hero && point && map) {  
  21.             point.transform.rotation = Quaternion.Euler(0, 0, -hero.transform.rotation.eulerAngles.y);  
  22.             map.transform.localPosition = new Vector3()  
  23.             {  
  24.                 x = -hero.transform.position.x * miniMapScaleRatio,  
  25.                 y = -hero.transform.position.z * miniMapScaleRatio,  
  26.                 z = 0,  
  27.             };  
  28.         }  
  29.     }  
  30. }  
代码不多吧,point是玩家标志小箭头,map是地图面板,就是1里面那个MiniMapRenderPanel,public属性的,自己拖上去吧。hero是我们的主角,miniMapScaleRatio是地图和真实地形尺寸比例,start里的第一句是在干吗呢,虽然我们的地图是512*512的,但经过实测,发现这个尺寸会随着屏幕的高度而有误差,需要设置成屏幕的高度这种尺寸,好吧,我也需要有人帮我解释下,Update里时刻获得主角的转向,主角在世界中是绕y轴旋转的,小标志是绕z轴旋转的,并且方向相反,这里要注意一下。然后按照角色在地形上的位置乘以地图与地形的比例获得小标志在地图上的位置,噢啦,大功告成,打完收工。
2017-11-07 23:28:02 qq_40695551 阅读数 946
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4712 人正在学习 去看看 张刚

Unity3D技巧之小地图的实现

 首先在UI画布下创建一个空物体改名叫Minmap。并在Minmap下创建Raw Image用来做遮罩。

.
然后再建立一个Sprite于Player的子对象下并且改名为icon,设置Layer为icon。用来作为游戏主人公的在小地图的标识,并把制作好的icon箭头应用于Sprite中(导入的图片记得改为Sprite(2D and UI格式 )。设置好后旋转合适角度并拉到player正上方一段距离。



新建一个Camera 改名为MinpapCam(用作跟随Player的摄像机)并适当调整位置。
调整MinmapCam相机的Culling Mask为地形 icon什么的(想在小地图出现什么选什么)
新建一个Render Texture于Project面板中并托给MinmapCam的Target Texture中。
新建Minmap脚本拖给MinmapCam。并把icon拖给Minmap中。
代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Minmap : MonoBehaviour
{

    private Transform newtransform;
    public GameObject icon;
    void Start()
    {
        newtransform = GetComponent<Transform>();
    }

    void Update()
    {
        transform.position = new Vector3(icon.transform.position.x, 25f, icon.transform.position.z);//修改摄像机的位置 需要适当调整。
    }
}

再把Render Texture拖给Raw Image。

基本已经实现了如果要圆形的话给画布下的Minmap加个Mask遮罩就好了。然后再加个边框什么的。




2018-06-27 22:04:47 m0_37872090 阅读数 4202
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4712 人正在学习 去看看 张刚

    笔者的Unity 3D课程已经结束,这里记录下几个比较常用的功能教程并分享给大家(适用的版本是Unity 3D 5.6.5)。

    接下来我们说一说小地图的制作,具体思路为:在角色头顶创建一个摄像机,并选择二维显示跟踪角色运动然后将场景中的元素分为多个并根据层需要去渲染,最后通过更改摄像机的尺寸放大或缩小小地图。

    1.创建一个摄像机,通过宣传其视角,将它垂直于地面,投影选择Orthegraphic;

    2.将其渲染成一张图片:创建一个Render Texture,把它托给Camera的目标Texture。然后给小地图创建一个材质,Main Texture设置为刚刚的texture,Mask Texture设置一个圆形(哪些地方显示其中地方不现实);

 


    3.添加边框:创建精灵的孩子,然后自己导入一个边框;

   4.将地图上的NPC设置为特定的图标:在层设置一个NPC,然后选择一个角色后创建-3D-四路;设置图片透明:透明漫射并在层中设置为Mininmapsignal然后对于小地图的相机选择渲染Mininmapsignal而不渲染NPC(类似于PS中的图层一样,选择哪些图形显示,哪些图形不显示);


    5.小地图上加放大缩小的功能:添加两个子画面;设置按下效果:在脚本中加两个方法,通过控制相机的尺寸实现地图放大缩小。

    到此呢,小地图就基本实现了,但是有个问题就是此时的小地图是会随着角色旋转而旋转的,要解决这个问题我们只需要找打对应的轴,然后将其设置为不可旋转即可。

2015-09-22 23:30:46 u014725878 阅读数 5313
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4712 人正在学习 去看看 张刚

        一个大场景的游戏,通常在角落里都会设有小地图,方便玩家在小地图中阅览更大的场景,起到了“导航”的作用,防止玩家在游戏中迷失了方向。今天介绍场景的小地图制作,目前我了解的只有UGUI和KGFMapSystem插件两种做法,做法也不难!如果大家有什么更牛更好的制作方法,欢迎共享!

(一)下面先来介绍UGUI的做法

    1.首先在Canvas画布下新建一个空的GameObject,改名为Mask,该组件实现地图的遮罩功能。

    2.在Mask下添加RawImage,实现小地图的动态显示。

    3.在角色对象上添加一个子对象Sprite,改名为Icon,实现角色移动时候的箭头显示。在Sprite上添加一个自己PS的箭头,并且调整Sprite的大小和位置。

    4.创建一个相机,命名为Minimap_Camera,用来追踪小地图。摄像机位置设置在角色正上方X轴90度,调整高度。调整相机只显示,主摄像机Culling Mask不显示Icon。新建一个Render Texture托给Minimap_Camera的Target Texture。

    5.下面为Minimap_Camera加个简单脚本,用来跟踪Icon(箭头)。

      

    6.将刚才新建的Render Texture托给Raw Image

    7.给Mask添加组件Mask和Image,并且修改Image组件的Source Image为圆形。(圆形自己画)

    8.最后给小地图添加个边框,在Canvas下新建一个Image,并且赋予边框图调整好位置即可

最后来看运行效果!


   (二)KGFMapSystem插件的做法还是不介绍了,因为刚才尝试用它做小地图,出现了bug。所以还是建议大家尽量用第一种制作方法,毕竟插件只是辅助作用,不保证取得一定成效,所以还是自己动手做吧!

2015-01-13 09:29:49 alayeshi 阅读数 1234
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4712 人正在学习 去看看 张刚

制作小地图的方法很多,简单介绍最简单的两种方法。

第一种方法比较实用也很简单,我们用一个实例来说明

假如是FPS游戏,当然FPS必然有个Player(玩家)enemy(敌人)。先拿player来举例子,我们可以在player下面建立一个子物体用Sphere这个球体来做子物体,这个子物体就是用来代替player在小地图中的显示的。然后把Sphere的属性中的collider这个属性去掉。然后给把其Shader设置成发光的材质,本例中设为绿色发光的。如图所示:



                                               

给他新建一个layer命名为dd,并且让其在dd这一层里。如图:




下面就可以新建一个摄像机,命名为mincamera,把他的放到整个场景的上方,使其镜头俯视整个场景,然后把属性里的viewport Rect 的数值调整到适合的大小,大小都可以在

camera preview里看到,同时在camera preview里也能看到用来代替Player的发光的绿色小球。如下面3副图:

     

 

这样小地图就已经见到雏形了,然后呢就So easy了。把mincamera的Culling Mask属性的摄像层次只设定到level和dd这两个层就OK了,这样mincamera就只能看到level和dd这两个层的物体了,leve就是我们的场景地图所在层,dd就是我们上面说到的用来代替Player的发光Sphere所在层。如图:


然后呢不要忘记我们的主相机,主相机不能摄像到dd这一层其他的都要摄到,如下图:


看下运行结果有图有真相:那个绿色的小点就是我们的玩家player。无论玩家在场景里怎么走,小地图都能跟踪显示了。那同样的enemy也用这个方法,小地图就可以显示敌人的位置了。ok了,So easy 完成了!简单吧一句代码都没写。。。



下面介绍一下第二种方法,主要使用GUI控制,举例说明:

场景里用plan代替地图,用cube代替玩家,如图:



然后呢很简单,把下面的代码绑定给Maincamera把对应的MAP和mapcube拖给脚本就OK了。如图:


代码如下:

using UnityEngine;
using System.Collections;

public class Script_04_17 : MonoBehaviour 
{
	
	//大地图地形对象
	GameObject plane;
	//大地图主角对象
	GameObject cube;
	
	//大地图的宽度
	float mapWidth;
	//大地图的高度
	float mapHeight;
	//地图边界的检测数值
	float widthCheck;
	float heightCheck;
	
	//小地图主角的位置
	float mapcube_x =0;
	float mapcube_y = 0;
	
	
	//GUI按钮是否被按下
	bool keyUp;
	bool keyDown;
	bool keyLeft;
	bool keyRight;
	
	//小地图的背景贴图
	public Texture map;
	//小地图的主角贴图
	public Texture map_cube;
	
	void Start()
	{
		//得到大地图对象
		plane = GameObject.Find("Plane");
		//得到大地图主角对象
		cube = GameObject.Find("Cube");
		//得到大地图默认宽度
		float size_x = plane.GetComponent<MeshFilter>().mesh.bounds.size.x;
		//得到大地图宽度的缩放比例
		float scal_x = plane.transform.localScale.x;
		//得到大地图默认高度
		float size_z = plane.GetComponent<MeshFilter>().mesh.bounds.size.z;
		//得到大地图高度缩放地理
		float scal_z = plane.transform.localScale.z;
		
		//原始宽度乘以缩放比例计算出真实宽度
		mapWidth = size_x * scal_x;
		mapHeight = size_z * scal_z;
		
		//越界监测的宽度
		widthCheck = mapWidth / 2;
		heightCheck = mapHeight / 2;
		
		check();
	}
	
	void OnGUI()
	{
		keyUp = GUILayout.RepeatButton("向前移动");

		keyDown = GUILayout.RepeatButton("向后移动");
		
		keyLeft = GUILayout.RepeatButton("向左移动");
		
		keyRight = GUILayout.RepeatButton("向右移动");
		
		//绘制小地图背景
		GUI.DrawTexture(new Rect(Screen.width - map.width,0,map.width,map.height),map);
		//绘制小地图上的“主角”
		GUI.DrawTexture(new Rect(mapcube_x,mapcube_y,map_cube.width,map_cube.height),map_cube);
	}
	
	void FixedUpdate()
	{
		

		if(keyUp)
		{
			//向前移动
			cube.transform.Translate(Vector3.forward * Time.deltaTime *5); 
			check();
	
		}
		
		if(keyDown)
		{
			//向后移动
			cube.transform.Translate(-Vector3.forward * Time.deltaTime *5); 
			check();
		}
		
		if(keyLeft)
		{
			//向左移动
			cube.transform.Translate(-Vector3.right * Time.deltaTime *5);  
			check();
		}
		
		if(keyRight)
		{
			//向右移动
			cube.transform.Translate(Vector3.right * Time.deltaTime *5); 
			check();
		}
	 
		
		
		
	}
	
	//越界检测
	void check()
	{
		//得到当前主角在地图中的坐标
		float x = cube.transform.position.x;
		float z = cube.transform.position.z;
		
		//当控制主角超过地图范围时,重新计算主角坐标
		if(x >= widthCheck)
		{
			x = widthCheck;
		}
		if(x <= -widthCheck)
		{
			x = -widthCheck;
		}
		if(z >= heightCheck)
		{
			z = heightCheck;
		}
		if(z <= -heightCheck)
		{
			z = -heightCheck;
		}
		
		cube.transform.position = new Vector3(x,cube.transform.position.y,z);
		
		//根据比例计算小地图“主角”的坐标
		mapcube_x = (map.width/mapWidth * x) + ((map.width / 2) - (map_cube.width/2)) + (Screen.width - map.width);
		mapcube_y =map.height - ((map.height/mapHeight * z) + (map.height / 2));
	}
}

运行结果图:



没有更多推荐了,返回首页