2018-09-06 10:26:02 qq_29241013 阅读数 576

优点:可以用代码绘制任意形状的图形。

缺点:这个只是一个平面,在Y轴上是没办法拉伸的,或者有但是我并没有找到,如果有神通广大的阅读者知道的话,可以提示一下。

开始上代码,多边形的吧,由三角形扩展来的,所有的图形都是由三角形组成的,如果有看不懂的话可以先研究一下三角形的,可能会有些帮助。

 void DrawTriangle(List<Vector3> points)
{
    GameObject g = new GameObject("Triangle");
    g.AddComponent<MeshFilter>();
    g.AddComponent<MeshRenderer>();
    g.GetComponent<MeshRenderer>().material = mat;
    Mesh mesh = g.GetComponent<MeshFilter>().mesh;
    mesh.Clear();

    Vector3[] vertices = points.ToArray();
    int[] triangles = new int[(points.Count - 2) * 3];

    for (int i = 0; i < points.Count; i++)
    {
        vertices[i] = points[i];
    }
    for (int i = 0, j = 1; i < (points.Count - 2) * 3; i += 3, j++)
    {
        triangles[i] = 0;
        triangles[i + 1] = j;
        triangles[i + 2] = j + 1;
    }
    mesh.vertices = vertices;
    mesh.triangles = triangles;
    mesh.RecalculateNormals();//重绘网格
}

调用方法

public Material mat;
[SerializeField]
List<Vector3> allPoints = new List<Vector3>();

void Update()
{
    if (Input.GetKeyDown(KeyCode.Space))
    {
        DrawTriangle(allPoints);
    }

    if (Input.GetMouseButtonUp(1))
    {
     
                        allPoints.Add(Camera.main.ScreenToWorldPoint(newVector3(Input.mousePosition.x,Input.mousePosition.y, 10)));
    }
}

排版不过来了,将就一下。

2016-12-23 17:05:08 supersunstar 阅读数 226

世界坐标

世界坐标按照笛卡尔坐标系定义出来的绝对坐标系,下面的各种坐标系都建立在世界坐标的基础上。我们知道二维平面内任意一个点可以用二维坐标(x,y)来表示,如果将这个概念延伸到三维空间内,那么三维空间内任意一个点都可以用三维坐标(x,y,z)来表示。这就是世界坐标的概念啦,坐标系通常可以分为左手坐标系和右手坐标系,而Unity3D采用的是左手坐标系。在Unity3D中我们可以使用transform.position来获取场景中一个物体的世界坐标,通常情况下编辑器中的Inspector窗口是以世界坐标来描述一个3D物体的位置的,除非当一个3D物体存在父物体的时候,它会以相对坐标来描述其位置。 

屏幕坐标

屏幕坐标是以像素来定义的,它的范围是以左下角为(0,0),右上角为(Screen.width,Screen.height)定义的这样一个矩形。屏幕坐标是一个3D坐标,Z轴是以相机的世界单位来衡量的。屏幕坐标和相机之间满足:Screen.width = Camera.pixelWidth和Screen.height = Camera.pixelHeight这两个条件。例如我们将相机正对着场景中的原点(0,0,0),相机的Z轴分量为-10,按照屏幕坐标的定义,假设屏幕为800X640的大小,则此时原点转化为屏幕坐标后应该是(400,320,10)。在Unity3D中我们可以使用WorldToScreenPoint来将一个世界坐标转换为屏幕坐标。注:鼠标位置坐标属于屏幕坐标,Input.mousePosition可以获得该位置坐标,手指触摸屏幕也为屏幕坐标,Input.GetTouch(0).position可以获得单个手指触摸屏幕坐标。

视口坐标

视口坐标是标准化后的屏幕坐标。标准化的概念我们可以引申到向量的标准化中,比如一个向量(x,y)标准化后可以得到一个单位向量(x’,y’)。类似地,视口坐标是以0到1间的数字来表示的,它的范围是以左下角为(0,0),右上角为(1,1)定义的这样一个矩形。视口坐标是一个3D坐标,Z轴是以相机的世界单位来衡量的。通过对比可以发现视口坐标和屏幕坐标特别的相似,所以这里大家可以对比着来学习。同样以屏幕坐标中的例子来将这里的转换,例如我们将相机正对着场景中的原点(0,0,0),相机的Z轴分量为-10,按照屏幕坐标的定义,假设屏幕为800X640的大小,则此时原点转化为屏幕坐标后应该是(0.5,0.5,10)。在Unity3D中我们可以使用WorldToViewportPoint来将一个世界坐标转换为视口坐标。 

GUI坐标

GUI坐标是指通过OnGUI方法绘制UI时使用的坐标。这个坐标系和屏幕坐标类似,它同样是以像素来定义的,它的范围是以左上角为(0,0),右下角为(Screen.width,Screen.height)定义的这样一个矩形,GUI坐标是一个 2D 坐标(绝对坐标)。此外我们知道使用绝对坐标来进行布局的话是没有办法做自适应的,UI自适应的一个主要观点就是不要使用绝对坐标!不要使用绝对坐标!不要使用绝对坐标!GUI坐标的要点是:uGUI的坐标本质上是特殊的屏幕坐标,因为uGUI的Anchor决定了该坐标系的原点,pivot决定了元素本身坐标系的原点,正是这两个属性让uGUI的坐标看起来显得扑朔迷离。RectTransform组件继承自Transform,所以它们的position和localPosition是等价的,都是世界坐标;anchoredPosition是UI元素的屏幕坐标,在对UI元素进行操作的时候应该考虑使用这个坐标。 

  • 世界坐标屏幕坐标:Camera.main.WorldToScreenPoint(transform.position);
  • 屏幕坐标世界坐标:Camera.main.ScreenToWorldPoint(transform.position);

  • 屏幕坐标→视口坐标:Camera.main.ScreenToViewportPoint(Input.GetTouch(0).position);

  • 视口坐标→屏幕坐标:Camera.main.ViewportToScreenPoint();

  • 视口坐标→世界坐标:Camera.main.ViewportToWorldPoint();
2017-05-20 12:24:49 marvelgl 阅读数 1291

目标:

写一个程序,实现一个完整的太阳系, 其他星球围绕太阳的转速必须不一样,且不在一个法平面上。
基本思路是在里面创建对象,架构成一个太阳系,sun作为父对象,其他行星作为子对象,并且相对sun的初始位置均不一样,那么角速度相同的情况下转速就不一样了,另外法平面是采取随机分配一个方向给任意一个行星,只要y和z的比值不一样,那么就不会在同一个轨道上。


实现过程:

如图建立对象,并放到合适位置,改好名字
这里写图片描述
把脚本挂到Sun上,并给Script中的Transform对象赋值(把对应对象拉进去就行)
这里写图片描述
另外新建Material挂在星球上可以让星球看上去更好看,以下是地球的,图片网上搜的:
这里写图片描述
这里写图片描述
效果图:
这里写图片描述
这里写图片描述

我给太阳加了光源,让他能有照明的效果(在我的另一篇博客有对光源更多的介绍)
这里写图片描述


实现代码:

sunset.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class sunset : MonoBehaviour {
    public Transform sun;
    public Transform mercury;
    public Transform venus;
    public Transform earth;
    public Transform mars;
    public Transform jupiter;
    public Transform saturn;
    public Transform uranus;
    public Transform neptune;
    public Transform moon;
    // Use this for initialization
    Vector3 []a = new Vector3[9];
    float speed = 40;
    float y, z;
    void Start () {
        int i = 0;
        for (i = 0; i < 9; i++) {
            y = Random.Range(1, 360); // 随机设置角度
            z = Random.Range(1, 360); // 随机设置角度
            a[i] = new Vector3(0, y, z); // 以上是为了制造不同的运动法平面,修改y和z可以使得绕不同的轴转
        }
    }

    // Update is called once per frame
    void Update () { // 每个星球的旋转动作,用到了初始化的a[i]
        mercury.RotateAround(sun.position, a[0], speed*Time.deltaTime);
        mercury.Rotate(Vector3.up *speed *Time.deltaTime);
        venus.RotateAround(sun.position, a[1], speed*Time.deltaTime);
        venus.Rotate(Vector3.up *speed *Time.deltaTime);
        earth.RotateAround(sun.position, a[2], speed*Time.deltaTime);
        earth.Rotate(Vector3.up *speed *Time.deltaTime);
        mars.RotateAround(sun.position, a[3], speed*Time.deltaTime);
        mars.Rotate(Vector3.up *speed *Time.deltaTime);
        jupiter.RotateAround(sun.position, a[4], speed*Time.deltaTime);
        jupiter.Rotate(Vector3.up *speed *Time.deltaTime);
        saturn.RotateAround(sun.position, a[5], speed*Time.deltaTime);
        saturn.Rotate(Vector3.up *speed *Time.deltaTime);
        uranus.RotateAround(sun.position, a[6], speed*Time.deltaTime);
        uranus.Rotate(Vector3.up *speed *Time.deltaTime);
        neptune.RotateAround(sun.position, a[7], speed*Time.deltaTime);
        neptune.Rotate(Vector3.up *speed *Time.deltaTime);
        moon.RotateAround(earth.position, Vector3.right, 400 *Time.deltaTime);
    }
}
2015-02-22 15:09:32 book_longssl 阅读数 2116

人物的名称与血条的绘制方法很简单,但是我们需要解决的问题是如何在3D世界中寻找合适的坐标。因为3D世界中的人物是会移动的,它是在3D世界中移动,并不是在2D平面中移动,但是我们需要将3D的人物坐标换算成2D平面中的坐标,继而找到人物头顶在屏幕中的2D坐标最后使用GUI将名称与血条绘制出来。

首先学习本文的重点内容,如何将游戏世界中任意3D坐标转换成屏幕中的2D坐标。根据这个方法计算出的2D坐标屏幕左下角的点为0.0 ,屏幕右上角的坐标为1.1 所以真实的2D坐标还得通过Screen.height 与Screen.width计算一下才行。
1
Vector2 position = camera.WorldToScreenPoint (worldPosition);

在unity工程导入角色控制器组件,不知道角色控制器的朋友请阅读我之前的文章哈。创建一个Plane做为游戏的地面,然后利用角色控制器组件创建两个模型,一个做为主角,一个作为NPC,主角可以通过控制来移动从四周来观察NPC对象。由于地面的面积比较小移动主角时为了避免主角越界掉下去,我们做一个边界的物理层。物理层其实很简单,就是给平面四周放置四个平面在四周将平面包围着,给四周的四个平面绑定上Box Collider组件,这样主角就不会越界掉下去啦。因为没有给贴图所以效果上看不到这四个对象。 如下图所示,在场景是途中主角被四个平面包围这,即时它拼命的想往外条但是还是跳不出去。

 

创建脚本NPC.cs 然后把脚本挂在NPC对象身上,在脚本中我们绘制主角的血条以及名称。

  1. NPC.cs
  2. 001
  3. using UnityEngine;
  4. 002
  5. using System.Collections;
  6. 003
  7.   
  8. 004
  9. public class NPC : MonoBehaviour {
  10. 005
  11.   
  12. 006
  13. //主摄像机对象
  14. 007
  15. private Camera camera;
  16. 008
  17. //NPC名称
  18. 009
  19. private string name = "我是雨松MOMO";
  20. 010
  21.   
  22. 011
  23. //主角对象
  24. 012
  25. GameObject hero;
  26. 013
  27. //NPC模型高度
  28. 014
  29. float npcHeight;
  30. 015
  31. //红色血条贴图
  32. 016
  33. public Texture2D blood_red;
  34. 017
  35. //黑色血条贴图
  36. 018
  37. public Texture2D blood_black;
  38. 019
  39. //默认NPC血值
  40. 020
  41. private int HP = 100;
  42. 021
  43.   
  44. 022
  45. void Start ()
  46. 023
  47. {
  48. 024
  49. //根据Tag得到主角对象
  50. 025
  51. hero = GameObject.FindGameObjectWithTag("Player");
  52. 026
  53. //得到摄像机对象
  54. 027
  55. camera = Camera.main;
  56. 028
  57.   
  58. 029
  59. //注解1
  60. 030
  61. //得到模型原始高度
  62. 031
  63. float size_y = collider.bounds.size.y;
  64. 032
  65. //得到模型缩放比例
  66. 033
  67. float scal_y = transform.localScale.y;
  68. 034
  69. //它们的乘积就是高度
  70. 035
  71. npcHeight = (size_y *scal_y) ;
  72. 036
  73.   
  74. 037
  75. }
  76. 038
  77.   
  78. 039
  79. void Update ()
  80. 040
  81. {
  82. 041
  83. //保持NPC一直面朝主角
  84. 042
  85. transform.LookAt(hero.transform);
  86. 043
  87. }
  88. 044
  89.   
  90. 045
  91. void OnGUI()
  92. 046
  93. {
  94. 047
  95. //得到NPC头顶在3D世界中的坐标
  96. 048
  97. //默认NPC坐标点在脚底下,所以这里加上npcHeight它模型的高度即可
  98. 049
  99. Vector3 worldPosition = new Vector3 (transform.position.x , transform.position.y + npcHeight,transform.position.z);
  100. 050
  101. //根据NPC头顶的3D坐标换算成它在2D屏幕中的坐标
  102. 051
  103. Vector2 position = camera.WorldToScreenPoint (worldPosition);
  104. 052
  105. //得到真实NPC头顶的2D坐标
  106. 053
  107. position = new Vector2 (position.x, Screen.height - position.y);
  108. 054
  109. //注解2
  110. 055
  111. //计算出血条的宽高
  112. 056
  113. Vector2 bloodSize = GUI.skin.label.CalcSize (new GUIContent(blood_red));
  114. 057
  115.   
  116. 058
  117. //通过血值计算红色血条显示区域
  118. 059
  119. int blood_width = blood_red.width * HP/100;
  120. 060
  121. //先绘制黑色血条
  122. 061
  123. GUI.DrawTexture(new Rect(position.x - (bloodSize.x/2),position.y - bloodSize.y ,bloodSize.x,bloodSize.y),blood_black);
  124. 062
  125. //在绘制红色血条
  126. 063
  127. GUI.DrawTexture(new Rect(position.x - (bloodSize.x/2),position.y - bloodSize.y ,blood_width,bloodSize.y),blood_red);
  128. 064
  129.   
  130. 065
  131. //注解3
  132. 066
  133. //计算NPC名称的宽高
  134. 067
  135. Vector2 nameSize = GUI.skin.label.CalcSize (new GUIContent(name));
  136. 068
  137. //设置显示颜色为黄色
  138. 069
  139. GUI.color = Color.yellow;
  140. 070
  141. //绘制NPC名称
  142. 071
  143. GUI.Label(new Rect(position.x - (nameSize.x/2),position.y - nameSize.y - bloodSize.y ,nameSize.x,nameSize.y), name);
  144. 072
  145.   
  146. 073
  147. }
  148. 074
  149.   
  150. 075
  151. //下面是经典鼠标点击对象的事件,大家看一下就应该知道是什么意思啦。
  152. 076
  153. void OnMouseDrag ()
  154. 077
  155. {
  156. 078
  157. Debug.Log("鼠标拖动该模型区域时");
  158. 079
  159. }
  160. 080
  161.   
  162. 081
  163. void OnMouseDown()
  164. 082
  165. {
  166. 083
  167. Debug.Log("鼠标按下时");
  168. 084
  169.   
  170. 085
  171. if(HP >0)
  172. 086
  173. {
  174. 087
  175. HP -=5 ;
  176. 088
  177. }
  178. 089
  179.   
  180. 090
  181. }
  182. 091
  183. void OnMouseUp()
  184. 092
  185. {
  186. 093
  187. Debug.Log("鼠标抬起时");
  188. 094
  189. }
  190. 095
  191.   
  192. 096
  193. void OnMouseEnter()
  194. 097
  195. {
  196. 098
  197. Debug.Log("鼠标进入该对象区域时");
  198. 099
  199. }
  200. 100
  201. void OnMouseExit()
  202. 101
  203. {
  204. 102
  205. Debug.Log("鼠标离开该模型区域时");
  206. 103
  207. }
  208. 104
  209. void OnMouseOver()
  210. 105
  211. {
  212. 106
  213. Debug.Log("鼠标停留在该对象区域时");
  214. 107
  215. }
  216. 108
  217.   
  218. 109
  219. }
复制代码


注解1:通过collider.bounds.size 可以拿到模型对应三个轴向的高度,但是模型是可以缩放的,所以真实的模型高度应当是原始高度乘以缩放系数才行。 transform.localScale可以拿到模型对应三个轴向的缩放系数,因为这里我们需要模型的高度,所以忽略X轴与Z轴。
注解2:在这里我们计算血条的宽度,GUI.skin.label.Calcsize()这个方法是以默认的皮肤对象Label对象去参数对象的宽高。参数是new GUIContent(blood_Red)意思是拿红色血条的贴图的宽高,它将保存在返回的size中。最后以宽高将血条绘制在屏幕中,我们的血条采取两层。背景是黑色的,前面是红色的,当人物费血时红色血条减少。
注解3: 这里通过字符串来获取它整体的宽度与高度,因为NPC的名称是可变的,所以我们需要动态的获取整体的显示区域。同样是以GUI.skin.label对象去调用CalcSize。

如下图所示,当使用鼠标点击NPC对象时,NPC头顶的血条将开始发生减血。这个例子我使用OnGUI绘制当然大家也可以在Hierarchy 视图中的创建GUI Texture 或者GUI Text对象 来实现,不过原理都是这样的 大家可以试试。


2013-10-13 16:37:08 jbjwpzyl3611421 阅读数 1169

在上一章中已经介绍了Unity for 3D 游戏引擎的构建,从本章以后我将带领大小盆友们一起更进一步的学习Unity游戏引擎。先从Unity平面开始,本章介绍Unity 平面上的多点触摸。


 

点击File->New Project 创建一个工程,可以使用默认 或者 名称随便起一起即可。点击继续完成创建工程。

Scene:游戏场景视图,这里面可以摆放任意场景模型。

Camera Preview:摄像头正对方向屏幕显示内容

MainCamera:创建工程后默认会添加游戏的主摄像头,在场景视图中我们可以看见 MainCamera在三维坐标系中的位置。

我们今天的目标实际上就是让摄像头正对一个平面,在这个平面中实现多点触摸

下面介绍一下脚本的使用,为了让摄像头显示我们须要给主摄像头绑定脚本,如下图所示,点击红框内的Create 出现下拉列表,先创建两个文件夹,Image用来存放图片,Scripts用来存放脚本。 因为iPhone 4 的分辨率是960x640 所以找到一张 960x640的图片做为屏幕背景图,然后在找一张小一点的图片做为触摸后在屏幕中显示的图片。 

Unity支持三种的脚本分别是javascript,C# Script,Boo Script, 官方推荐使用javascript来编写,所以我们也就用javascript。

创建一个脚本名称为menu.js,声明了两个变量 imageMenu 与 imageItem 来储存游戏背景显示与游戏触摸显示的纹理图片。

function OnGUI () : 这个方法用来通知屏幕绘制。

DrawTexture: 绘制纹理。

Label:绘制一个文本。

iPhoneInput.touchCount :得到多点触摸的数量。

iPhoneInput.GetTouch(i).position: 得到循环中每一个多点触摸的位置。

iPos.x : 触摸的x坐标

iPos.y : 触摸的y坐标(左上角为00点的Y坐标)

GUI.DrawTexture(Rect(x,960 - y ,120,120),imageItem);

960 - y : 因为取得的y坐标是左上角00点的坐标,而Unity绘制是以左下角为00点的坐标,不处理直接用y的话坐标就是一个反的,所以这里用 iPhone 4的 高度 960  减去 当前触摸的Y 就算出触摸正确的显示坐标。

[代码]c#/cpp/oc代码:

01 var imageMenu :Texture2D; 
02  
03 var imageItem :Texture2D; 
04  
05 function OnGUI () { 
06  
07     GUI.DrawTexture(Rect(0,0,640,960),imageMenu); 
08  
09      var touchCount = iPhoneInput.touchCount; 
10      for(var i = 0; i < touchCount; i++) 
11      { 
12         var iPos = iPhoneInput.GetTouch(i).position; 
13         var x = iPos.x; 
14         var y = iPos.y; 
15  
16         GUI.DrawTexture(Rect(x,960 - y ,120,120),imageItem); 
17  
18         GUI.Label(Rect(x, 960 - y,120,120),"Touch position is  " + iPos); 
19      } 
20  
21  
22 }

脚本已经添加完毕,接下来是绑定变量。

先将menu.js拖拽到Maincamera中,可以看到右下角红框中出现两个没有赋值的变量 ImageMenu 与ImageItem ,因为上面脚本中声明了这两个变量,这里就会出现。在这里须要对这两个变量赋值。然后拖拽图片放入为其赋值。

OK 接下来就是build and run ,具体方法见上一章,这里就不罗嗦了。 我们看看运行在iPhone上的真机效果图。

因为Unity3D for iPhone 只支持 5点触摸,所以我将5根手指头放入iPhone 4中 图中清楚的记录我的5根手指头所在屏幕中的位置,以及正确的贴上了须要显示的图片。

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