今天我们就系统的看一下unity3d编辑器和插件制作,不过有点长,想要学习的话就要耐心看了。好首先我们来想下  IOS 和android的 控件都是以四边形基础的。
接下来 我们来转像unity,在unity中 我们怎么去建立一个四边形那, 依照图形绘制的原理。三点一面的理论。我们可以使用6个点来建立一个两三角形组成的四边形。
我们先学会怎么去绘制一个view,也就是简单的一个色面。
我们知道 unity中得面也是采取这种的绘制方法,绘制一个面就会多一个drawcall,为了面绘制的节省,我们就会使用面合并的原理,来减少drawcall的产生(opengl自动处理)。
好,我们来定义六个点:
  1. [csharp] 
  2. public static int[] initTri(){
  3. int[] triangle = new int[6];
  4. triangle [0] = 0;
  5. triangle [1] = 2;
  6. triangle [2] = 1;
  7. triangle [3] = 2;
  8. triangle [4] = 3;
  9. triangle [5] = 1;
  10. return triangle;
  11. }
有了 6个点,我们就要去定义三角形的大小。
  1. [csharp] 
  2. public static Vector3 [] initVertice(float width ,float height,float ancPointx,float ancPointY){
  3. Vector3 [] viewVer = new Vector3[4];
  4. viewVer [0] = new Vector3 (-ancPointx*-width,-ancPointY*height,0);
  5. viewVer [1] = new Vector3 ((1-ancPointx)*-width,-ancPointY*height,0);
  6. viewVer [2] = new Vector3 (-ancPointx*-width,(1-ancPointY)*height,0);
  7. viewVer [3] = new Vector3 ((1-ancPointx)*-width,(1-ancPointY)*height,0);
  8. return viewVer;
  9. }
其中ancPointx,ancPointy,为 我们经常用到的锚点,width,height就是你要绘制的面的宽和高了。
好了 有了这些东西 现在制作一个没有任何颜色的几条线组成的线框。
我们为了让这个面有颜色,必学要有 法线 和 材质,shader 这样才是一个完整的 色面。
法线
  1. [csharp] 
  2. public static Vector3[] initNormal(){
  3. Vector3[] normals = new Vector3[4];
  4. normals[0] = -Vector3.forward;
  5. normals[1] = -Vector3.forward;
  6. normals[2] = -Vector3.forward;
  7. normals[3] = -Vector3.forward;
  8. return normals;
  9. }
当然如果还想去绘制图片在面上就要有 UV的的定义
  1. [csharp] 
  2. public static Vector2 [] initUV(){
  3. Vector2 [] uv = new Vector2[4];
  4. uv[0] = new Vector2(0, 0);
  5. uv[1] = new Vector2(1, 0);
  6. uv[2] = new Vector2(0, 1);
  7. uv[3] = new Vector2(1, 1);
  8. return uv;
  9. }
想好这些东西,我们就开始定义面了。
源码奉上!
公用类!
  1. [csharp] 
  2. using UnityEngine;
  3. using System.Collections;
  4. public class InitBase : MonoBehaviour {
  5. public static Vector3 [] initVertice(float width ,float height,float ancPointx,float ancPointY){
  6. Vector3 [] viewVer = new Vector3[4];
  7. viewVer [0] = new Vector3 (-ancPointx*-width,-ancPointY*height,0);
  8. viewVer [1] = new Vector3 ((1-ancPointx)*-width,-ancPointY*height,0);
  9. viewVer [2] = new Vector3 (-ancPointx*-width,(1-ancPointY)*height,0);
  10. viewVer [3] = new Vector3 ((1-ancPointx)*-width,(1-ancPointY)*height,0);
  11. return viewVer;
  12. }
  13. public static int[] initTri(){
  14. int[] triangle = new int[6];
  15. triangle [0] = 0;
  16. triangle [1] = 2;
  17. triangle [2] = 1;
  18. triangle [3] = 2;
  19. triangle [4] = 3;
  20. triangle [5] = 1;
  21. return triangle;
  22. }
  23. public static Vector3[] initNormal(){
  24. Vector3[] normals = new Vector3[4];
  25. normals[0] = -Vector3.forward;
  26. normals[1] = -Vector3.forward;
  27. normals[2] = -Vector3.forward;
  28. normals[3] = -Vector3.forward;
  29. return normals;
  30. }
  31. public static Vector2 [] initUV(){
  32. Vector2 [] uv = new Vector2[4];
  33. uv[0] = new Vector2(0, 0);
  34. uv[1] = new Vector2(1, 0);
  35. uv[2] = new Vector2(0, 1);
  36. uv[3] = new Vector2(1, 1);
  37. return uv;
  38. }
  39. }
物体上的类View
  1. [csharp] 
  2. using UnityEngine;
  3. using System.Collections;
  4. [RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
  5. [ExecuteInEditMode]
  6. public class VKView : MonoBehaviour {
  7. Mesh viewMesh;
  8. Material viewDefultMat;
  9. bool isChange;
  10. [HideInInspector] public float ancPointx=0.5f,ancPointy = 0.5f;
  11. [HideInInspector] public int width = 100,height = 100;
  12. public string test;
  13. // Use this for initialization
  14. void Start () {
  15. viewDefultMat = new Material (Shader.Find ("VK/VKViewShader"));
  16. gameObject.GetComponent<MeshRenderer> ().sharedMaterial = viewDefultMat;
  17. viewMesh = new Mesh ();
  18. gameObject.GetComponent<MeshFilter> ().mesh = viewMesh;
  19. updateView();
  20. }
  21. public void updateView(){
  22. if (viewDefultMat != null) {
  23. viewMesh.vertices = InitBase.initVertice(width,height,ancPointx,ancPointy);
  24. viewMesh.triangles = InitBase.initTri();
  25. viewMesh.normals = InitBase.initNormal();
  26. viewMesh.uv = InitBase.initUV();
  27. }
  28. }
  29. #if UNITY_EDITOR
  30. void OnDrawGizmosSelected(){
  31. Gizmos.color = Color.blue;
  32. Gizmos.DrawWireCube (transform.position,new Vector3(width,height,0f));
  33. }
  34. #endif
  35. }
view的编辑器类
  1. [csharp] 
  2. using UnityEngine;
  3. using System.Collections;
  4. using UnityEditor;
  5. [CustomEditor(typeof(VKView))]
  6. [ExecuteInEditMode]
  7. public class VKViewEditor : Editor {
  8. public override void OnInspectorGUI ()
  9. {
  10. base.OnInspectorGUI ();
  11. VKView vkView = (VKView)target;
  12. //      vkView.tex = EditorGUILayout.ObjectField ("Texture",vkView.tex,typeof(Texture),true)as Texture;
  13. vkView.width=EditorGUILayout.IntField("Width",vkView.width);
  14. vkView.height=EditorGUILayout.IntField("Height",vkView.height);
  15. vkView.test = EditorGUILayout.TextField("面板显示的名字:",vkView.test);
  16. vkView.updateView ();
  17. EditorUtility.SetDirty(vkView);
  18. EditorUtility.UnloadUnusedAssets();
  19. }
  20. }
还有shader
  1. [csharp]
  2. Shader "VK/VKViewShader" {
  3. Properties {
  4. _Color ("Main Color", Color) = (1,1,1,1)
  5. }
  6. SubShader {
  7. Pass {
  8. Cull Front
  9. Color [_Color]
  10. }
  11. }
  12. }

现在我们来讲述下,怎么绘制一个图片在场景里面。

首先 我们先做下图片的功课。
在unity中图片的种类分了很多,默认是:Texture, 还有其他的一些属性。

有些人可以会遇到 我放进去的素材为什么编译之后会变模糊那,这是由于,在unity中你没有修改图片的属性,导致的。


在 texture模式下,

我们来分析下这种图片的属性,
wrap mode 这个是图片选择 图片时候四方连续是会用到,也可以减轻,图片白边的影响。
filter mode 是 图片的 文件模式,说白一点就是 点,两角线,三角线。。越高图片质量越大,内存也就越高。
anise level 说白了 这个 我还没用到 ,貌似是位图才会用到。
max size 最大支持图片(注意哦是最大哦,假如我的图是100*100的 你选择1024 没关系的 不会浪费 内存的,因为这里说的是最大的图集支持,如果你的图片超过了1024,那这个值也要跟着变。)

format 这个就是 压缩模式了,决定内存的最重要的部分,三个选项,自动压缩(最节省),16位压缩(还可以说的过去),真彩色可以说没有压缩,保证质量的同时内存相应的增大了。


高级选项模式:最为常用的模式。
Non power of 2 :如果你不想你的图变成 正方形符合2的n次方的图,就选择none,这样可以保证你图的大小的合理性。不然选自动适应,最大适应,最小适应。
cubemap: 一般不使用,这个是用在模型上面的贴图。
read/w:是否支持读写,建议勾选。
其他看下文档。
format:一般我们用32位的,也可以选择16位的。减少内存。
最后 送一句话,小图尽量拼成大图,对UV(也可以使用NGUI的自动压缩图,也可以自己压缩,后面会讲怎么制作自己的图集),大图最好不要超过1024,面的数量尽量的减少,尽量使面合并。 目的减少内存,减少drawcall。
好,下一步。我们开始做把图片渲染到场景里面。
前面讲了,我们绘制片,下面,我们做的之需要两部。
1.把shader换掉,前面使用的是,纯色的shader,下面我们将使用,带贴图的shader。
2. 前面我们使用的是固定的宽和高,因为图片的大小不是固定的,所以我们要把比例进行适配一下。
上代码:
shader部分,很简单:


  1. [cpp]
  2. Shader "VK/VKTextureShader" {
  3. Properties {
  4. _Color ("Main Color", COLOR) = (1,1,1,1)
  5. _MainTex ("Base (RGB) Trans (A)", 2D) =""{}
  6. }
  7. SubShader {
  8. Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
  9. Pass {
  10. Blend SrcAlpha OneMinusSrcAlpha
  11. Cull off
  12. SetTexture [_MainTex] {
  13. constantColor [_Color]
  14. Combine texture *constant
  15. }
  16. }
  17. }
  18. }


调用前面的,绘制片的公用方法类InitBase,继承VKview ,前面已经有,复制就好。
  1. [cpp]
  2. using UnityEngine;
  3. using System.Collections;
  4. public class VKImageView : VKView {
  5. Material imgViewDefultMat;
  6. Mesh imgViewDefultMesh;
  7. [HideInInspector] public Texture imgViewTex,highLightedTex;
  8. [HideInInspector] public float scale =1;
  9. [HideInInspector] public string info= null;
  10. [HideInInspector] public bool highLighted  = false;
  11. [HideInInspector] public float alpha =1;
  12. // Use this for initialization
  13. void Start () {
  14. imgViewDefultMat = new Material (Shader.Find("VK/VKTextureShader"));
  15. imgViewDefultMesh = new Mesh ();
  16. GetComponent<MeshFilter> ().mesh = imgViewDefultMesh;
  17. GetComponent<MeshRenderer>().material = imgViewDefultMat;
  18. updateImageView ();
  19. }
  20. public void updateImageView(){
  21. if(imgViewTex!=null){
  22. if(!highLighted){
  23. if(imgViewDefultMat!=null)
  24. imgViewDefultMat.mainTexture = imgViewTex;
  25. if(imgViewDefultMesh!=null)
  26. imgViewDefultMesh.vertices = InitBase.initVertice(imgViewTex.width *scale,imgViewTex.height*scale,ancPointx,ancPointy);
  27. height = imgViewTex.height;
  28. width = imgViewTex.width;
  29. }else{
  30. if(imgViewDefultMat!=null)
  31. imgViewDefultMat.mainTexture = highLightedTex;
  32. if(imgViewDefultMesh!=null)
  33. imgViewDefultMesh.vertices = InitBase.initVertice(highLightedTex.width *scale,highLightedTex.height*scale,ancPointx,ancPointy);
  34. height = highLightedTex.height;
  35. width = highLightedTex.width;
  36. }
  37. }else{
  38. if(imgViewDefultMat!=null)
  39. imgViewDefultMat.mainTexture = null;
  40. if(imgViewDefultMesh!=null)
  41. imgViewDefultMesh.vertices = InitBase.initVertice(width*scale,height*scale,ancPointx,ancPointy);
  42. }
  43. if(imgViewDefultMat!=null){
  44. Color newcolor = imgViewDefultMat.color;
  45. imgViewDefultMat.color = new Color(newcolor.r,newcolor.g,newcolor.b,alpha);
  46. }
  47. if(imgViewDefultMesh!= null){
  48. imgViewDefultMesh.triangles = InitBase.initTri ();
  49. imgViewDefultMesh.normals = InitBase.initNormal();
  50. imgViewDefultMesh.uv = InitBase.initUV();
  51. }
  52. }
  53. public void switchButton(){ //后面会讲到,可以先删掉,这个是转化按钮来用的。
  54. VKButton button = gameObject.AddComponent<VKButton> ();
  55. button.buttonDefultMesh = imgViewDefultMesh;
  56. button.buttonDefultMat = imgViewDefultMat;
  57. button.buttonTex = imgViewTex;
  58. button.pressButtonTex = highLightedTex;
  59. button.info = info;
  60. button.scale = scale;
  61. button.ancPointx = ancPointx;
  62. button.ancPointy = ancPointy;
  63. button.updateButton ();
  64. DestroyImmediate (GetComponent<VKImageView>());
  65. }
  66. }
Editor下面的 编辑器类
  1. [cpp]
  2. using UnityEngine;
  3. using System.Collections;
  4. using UnityEditor;
  5. [CustomEditor(typeof(VKImageView))]
  6. public class VKImageViewEditor : Editor {
  7. public override void OnInspectorGUI ()
  8. {
  9. base.OnInspectorGUI ();
  10. VKImageView imgView = (VKImageView)target;
  11. imgView.imgViewTex = EditorGUILayout.ObjectField  ("ImageTexture",imgView.imgViewTex,typeof(Texture),true)as Texture;
  12. imgView.highLightedTex = EditorGUILayout.ObjectField  ("HighLightedTex",imgView.highLightedTex,typeof(Texture),true)as Texture;
  13. imgView.alpha = EditorGUILayout.Slider("Alpha",imgView.alpha,0.0f,1.0f);
  14. imgView.highLighted = EditorGUILayout.Toggle ("highLighted",imgView.highLighted);
  15. imgView.info = EditorGUILayout.TextField ("info",imgView.info);
  16. imgView.ancPointx = EditorGUILayout.Slider("AnchorX",imgView.ancPointx,0.0f,1.0f);
  17. imgView.ancPointy = EditorGUILayout.Slider("AnchorY",imgView.ancPointy,0.0f,1.0f);
  18. if(imgView.imgViewTex == null){
  19. imgView.width=EditorGUILayout.IntField("Width",imgView.width);
  20. imgView.height=EditorGUILayout.IntField("Height",imgView.height);
  21. }
  22. GUILayout.BeginHorizontal();
  23. if(GUILayout.Button("2X")){
  24. imgView.scale = 0.5f;
  25. }
  26. if(GUILayout.Button("1X")){
  27. imgView.scale = 1f;
  28. }
  29. if(GUILayout.Button("1.5X")){
  30. imgView.scale = 0.75f;
  31. }
  32. GUILayout.EndHorizontal();
  33. GUILayout.BeginHorizontal();
  34. if(GUILayout.Button("ChangeName")){
  35. if(imgView.imgViewTex!=null){
  36. imgView.name = imgView.imgViewTex.name;
  37. }
  38. }
  39. if(GUILayout.Button("SwitchButton")){
  40. imgView.switchButton();
  41. }
  42. GUILayout.EndHorizontal();
  43. imgView.updateImageView();
  44. if(imgView!=null)
  45. EditorUtility.SetDirty (imgView);
  46. EditorUtility.UnloadUnusedAssets ();
  47. }
  48. }

这里我们要了解 unity的机制,button属性必须有的属性等。

首先 我们先说下 unity的机制:
unity中检测点击事件,使用NGUI的可能知道,NGUI使用的就是SendMessage的方式来进行事件的传递。没错,这也是 unity最为简便的方式,
(要注意一个问题哦,这个方式 如果 你要使用 大于 万次循环的话 会有延迟的哦,一般也不会同时发送万条事件的)。
我们知道了 事件的传送的方式,那么我们就开始制作这个规则,首先 要使用SendMessage的话我们要拿到gameobject的对象才能使用。
所以我们要想办法拿到点击的那个物体。怎么坐那,原理其实很简单,就是射线。我们都知道,unity的射线是用来探测使用的 正好,我们所有可以看到的物体都是存在camera下面,那么我们就可以使用,从camera上发射射线,来达到检测物体的作用,物体要有碰撞体哦。
先贴部分代码等这个章节完了我会贴完整的代码
  1. [cpp] 
  2. Ray cameraRay;
  3. RaycastHit hit;
  4. Vector3 touchPos,pressOffSet;
  5. public static GameObject touchObj = null;
  6. public static VKCamera shareVkCamera;
  7. [cpp] 
  8. void Update ( {
  9. #if UNITY_EDITOR
  10. if(Input.GetMouseButtonDown(0){
  11. onPressDown(Input.mousePosition);
  12. }else if(Input.GetMouseButtonUp(0)){
  13. onPressUp(Input.mousePosition);
  14. }else if(Input.GetMouseButton(0)){
  15. onDrag(Input.mousePosition);
  16. }
  17. #endif
  18. #if UNITY_IPHONE || UNITY_ANDROID
  19. Touch touch;
  20. if(Input.touchCount==1){
  21. touch = Input.GetTouch (0);
  22. switch(touch.phase){
  23. case TouchPhase.Began:
  24. onPressDown(touch.position);
  25. break;
  26. case TouchPhase.Moved:
  27. onPressUp(touch.position);
  28. break;
  29. case TouchPhase.Ended:
  30. case TouchPhase.Canceled:
  31. onDrag(touch.position);
  32. break;
  33. }
  34. }
  35. #else
  36. if(Input.GetMouseButtonDown(0)){
  37. onPressDown(Input.mousePosition);
  38. }else if(Input.GetMouseButtonUp(0)){
  39. onPressUp(Input.mousePosition);
  40. }else if(Input.GetMouseButton(0)){
  41. onDrag(Input.mousePosition);
  42. }
  43. #endif
  44. }
  45. [cpp] 
  46. public void onPressDown(Vector2 vec){
  47. touchPos = vec;
  48. for(int i=0 ; i<Camera.allCameras.Length;i++){
  49. cameraRay = Camera.allCameras[i].ScreenPointToRay(touchPos);
  50. if(Physics.Raycast(cameraRay,out hit,9999,Camera.allCameras[i].cullingMask) && touchObj == null){
  51. touchObj = hit.transform.gameObject;
  52. if(touchObj!=null && touchObj.GetComponent<VKButton>()){
  53. touchPos = Camera.allCameras[i].ScreenToWorldPoint(touchPos);
  54. pressOffSet =touchObj.transform.position-touchPos;
  55. VKButton button = touchObj.GetComponent<VKButton>();
  56. if(!iSNull(button.pressEventName) && button.eventObj!=null)
  57. button.eventObj.SendMessage(button.pressEventName,button);
  58. if(button.pressButtonTex!=null){
  59. button.renderer.sharedMaterial.mainTexture = button.pressButtonTex;
  60. }
  61. if(button.isDrag && !iSNull(button.dragStartEventName)){
  62. button.eventObj.SendMessage(button.dragStartEventName,vec);
  63. }
  64. if(button.isAni){
  65. button.SendMessage("onPressAni");
  66. }
  67. }
  68. }
  69. }
  70. }
  71. [cpp] 
  72. public void onPressUp(Vector2 vec){
  73. if(touchObj!=null){
  74. VKButton button = touchObj.GetComponent<VKButton>();
  75. if(button!=null){
  76. if(button.buttonTex!=null){
  77. touchObj.renderer.sharedMaterial.mainTexture =  touchObj.GetComponent<VKButton>().buttonTex;
  78. }
  79. if(!iSNull(button.clickEventName) && button.eventObj!=null){
  80. button.eventObj.SendMessage(button.clickEventName,button);
  81. }
  82. if(button.isDrag && !iSNull(button.dragEndEventName)){
  83. button.SendMessage(button.dragEndEventName,vec);
  84. }
  85. if(button.isAni){
  86. button.SendMessage("onClickAni");
  87. }
  88. }
  89. touchObj = null;
  90. }
  91. }
  92. [cpp] 
  93. public void onDrag(Vector2 vec){
  94. if(touchObj!=null){
  95. VKButton button = touchObj.GetComponent<VKButton>();
  96. if(button!=null && button.isDrag){
  97. for(int i= 0;i<Camera.allCameras.Length;i++){
  98. Vector2 worldVec =  Camera.allCameras[i].ScreenToWorldPoint(vec);
  99. touchObj.transform.position = new Vector3(worldVec.x+pressOffSet.x,worldVec.y+pressOffSet.y,touchObj.transform.position.z);
  100. if(!iSNull(button.dragEventName))
  101. button.eventObj.SendMessage(button.dragEventName,worldVec);
  102. }
  103. }
  104. }
  105. }
  106. [cpp] 
  107. bool iSNull(string eventName){
  108. bool buttonIsNull = false;
  109. if(eventName== null || eventName.Equals("null")){
  110. buttonIsNull  =true;
  111. }
  112. return buttonIsNull;
  113. }
这些是camera的部分,还有一点这个 我们没有贴我的适配方案 摄像机的适配方案,这里统配是1420*800的设计方案,因为这里我估计还要改下,发现这个摄像机适配方案,超出了unity的物理引擎的范围。不建议,不过可以参考。
  1. [cpp]
  2. public void initVKCamere(){
  3. gameObject.name = "VKCamere";
  4. this.camera.orthographic = true;
  5. this.camera.backgroundColor = Color.black;
  6. this.camera.nearClipPlane = 0;
  7. this.camera.farClipPlane = 9999;
  8. this.camera.orthographic =true;
  9. this.camera.orthographicSize = getCameraSize ();
  10. this.transform.position = new Vector3(0,0,-1000);
  11. this.transform.rotation = Quaternion.Euler(Vector3.zero);
  12. this.transform.localScale = Vector3.one;
  13. Application.targetFrameRate=60;
  14. if(GetComponent<AudioListener>()){
  15. //DestroyImmediate(GetComponent<AudioListener>());
  16. }
  17. }
  18. int getCameraSize(){
  19. int size = 384;
  20. bool isLandscape=(Camera.main.pixelWidth>Camera.main.pixelHeight);
  21. float rad = Camera.main.pixelWidth/Camera.main.pixelHeight;
  22. bool isIPad= (Mathf.Abs(rad-1.3333f)<0.001f) || (Mathf.Abs(rad-0.75f)<0.001f);
  23. if(isIPad){
  24. if(isLandscape){
  25. size=400;
  26. }else{
  27. size=533;
  28. }
  29. }else{
  30. if(isLandscape){
  31. size=400;
  32. }else{
  33. //iPhone 5
  34. if(Camera.main.pixelHeight/Camera.main.pixelWidth>1.6){
  35. size=710;
  36. }else{
  37. size=600;
  38. }
  39. }
  40. }
  41. return size;
  42. }
camera的编辑器类
  1. [cpp]
  2. using UnityEditor;
  3. using UnityEngine;
  4. using System.Collections;
  5. [CustomEditor(typeof(VKCamera))]
  6. public class VKCameraEditor : Editor {
  7. public override void OnInspectorGUI (){
  8. base.OnInspectorGUI();
  9. VKCamera vkCamere = (VKCamera)target;
  10. if(GUILayout.Button("ReSetCamera")){
  11. vkCamere.initVKCamere();
  12. }
  13. EditorUtility.SetDirty(vkCamere);
  14. EditorUtility.UnloadUnusedAssets();
  15. }
  16. }
好,下面我们来讲述下,button的一些东西,其实就很简单了。只是在编辑器方面可能会有些麻烦。
说白了 就是button就来处理 摄像机发来的东西。虽然很简单的一句话,但我们写得东西还是有很多的。
依然,button还是继承前面的view