转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持!


开篇废话:

在大学时稍微自学过一段时间Unity3D,虽然现在在做安卓,但一直对游戏开发很感兴趣,所以平时偶尔有空也会稍微看看,不过水平还是未入门菜鸟级的。

下面这个demo是看了雨松MOMO大神所写的几篇基础文章后,写的一个练习demo,用来展示简易的3D图表。

这个Demo非常初级,纯粹是为了练习知识点,但是所应用到的知识点非常基础,非常重要,适合初学者学习。截图如下:

 

 


简介:

这个Demo可以分为4个部分

第一部分——建立3D坐标系:

外框首先由四个平面所围成的一个“3D坐标系”,和X、Y、Z三个“坐标”组成。

1.四个平面

这四个平面所用的就是系统自带的cube,创建并调整cube的大小和方向组成上面的形状。

2.创建坐标系prefab

创建一个预设,并将左平面,右平面和后平面添加到下平面中最后添加到预设里,这样他们就变成了一个整体。如下图所示:


3.调整prefab在世界中的位置和他的scale

由于要设立坐标点,所以需要使刚才建立的坐标系的零点对应世界坐标的零点。

在本例中:假设每个单位长度为1,X坐标需要分成12份(12个月)坐标系scale的x值为24(每两份代表一个刻度)。Y轴代表百分比,分为5份(每份一个刻度)。Z轴同理。

通过上面的3个步骤,3D坐标系的样子已经出来了,下面开始为这个坐标系添加“刻度名称”。

第二部分——为坐标添加刻度名称:

刻度名称使用两个知识点:

1.世界坐标转换为屏幕坐标:

添加刻度名称其实就是将世界坐标的坐标值(因为我们已经在上一步中将坐标系和世界坐标同步了)转换为屏幕坐标值。


2.使用GUI.Label写出坐标名称:

通过刚才算出的屏幕坐标处使用GUI.Label函数写出当前坐标点的名称。

下面是本例中这个方法的代码:

[csharp] view plaincopyprint?
  1. // isY代表是不是Y轴
  2. void drawCoordinate (Vector3 point, string name, bool isY) {
  3. // 将世界坐标转换为屏幕坐标
  4. Vector2 position = camera.WorldToScreenPoint (point);
  5. position = new Vector2 (position.x, position.y);
  6. // 设置刻度的大小和颜色
  7. Vector2 nameSize = GUI.skin.label.CalcSize (new GUIContent(name));
  8. GUI.color  = Color.yellow;
  9. // 根据X,Y轴的不同加上适当偏移量画出刻度
  10. if (isY) {
  11. GUI.Label(new Rect(position.x-nameSize.x-coordOffset ,Screen.height-position.y,nameSize.x,nameSize.y), name);
  12. }
  13. else {
  14. GUI.Label(new Rect(position.x-nameSize.x ,Screen.height-position.y,nameSize.x,nameSize.y), name);
  15. }
  16. }

调用方法如下:

[csharp] view plaincopyprint?
  1. void OnGUI()
  2. {
  3. drawCoordinate (new Vector3 (0 , 0, 0), "0.00%", true);
  4. drawCoordinate (new Vector3 (2 , 0, 0), "Jan", false);

最后我贴上从网上找的关于Unity中坐标系的知识点(原文实在找不到了我就不贴连接了):

【Unity中四种坐标系】
1、World Space(世界坐标):
我们在场景中添加物体(如:Cube),他们都是以世界坐标显示在场景中的。
transform.position可以获得该位置坐标。

2、Screen Space(屏幕坐标):
以像素来定义的,以屏幕的左下角为(0,0)点,右上角为(Screen.width,Screen.height),Z的位置是以相机的世界单位来衡量的。
Screen.width = Camera.pixelWidth
Screen.height = Camera.pixelHeigth
鼠标位置坐标属于屏幕坐标,Input.mousePosition可以获得该位置坐标,
手指触摸屏幕也为屏幕坐标,Input.GetTouch(0).position可以获得单个手指触摸屏幕坐标。

3、ViewPort Space(视口坐标):
视口坐标是标准的和相对于相机的。相机的左下角为(0,0)点,右上角为(1,1)点,Z的位置是以相机的世界单位来衡量的。

4、绘制GUI界面的坐标系:
这个坐标系与屏幕坐标系相似,不同的是该坐标系以屏幕的左上角为(0,0)点,右下角为(Screen.width,Screen.height)。

【四种坐标系的转换】
1、世界坐标→屏幕坐标:

camera.WorldToScreenPoint(transform.position);
这样可以将世界坐标转换为屏幕坐标。其中camera为场景中的camera对象。

2、屏幕坐标→视口坐标:
camera.ScreenToViewportPoint(Input.GetTouch(0).position);
这样可以将屏幕坐标转换为视口坐标。其中camera为场景中的camera对象。

3、视口坐标→屏幕坐标:
camera.ViewportToScreenPoint();

4、视口坐标→世界坐标:
camera.ViewportToWorldPoint();

第三部分——在3D坐标系中画折线

坐标系建立好以后我们就可以在这个坐标系中画折线来啦。

坐标系已经和世界坐标系同步,所以每个坐标的坐标点我们已经知道,下面的问题就是如何将点连成线。

Unity提供了LineRenderer来画线,可以通过如下两种方法创建它:

一.Unity编辑器的方式:

1.Unity -> GameObject -> Create Empty 创建一个空的对象,我命名为line。

2.然后点击 Component -> Effects-> Line Renderer 给line添加一个线渲染器的属性

二.脚本的方式:

下面是本例的使用代码:

[csharp] view plaincopyprint?
  1. public class lineScript1 : MonoBehaviour {
  2. private Color c1 = Color.red;
  3. private Color c2 = Color.red;
  4. private LineRenderer lineRenderer;
  5. private Vector3 v0 = new Vector3(0.0f,0.0f,3.0f);
  6. private Vector3 v1 = new Vector3(2.0f,2.0f,0.0f);
  7. private Vector3 v2 = new Vector3(4.0f,3.0f,1.0f);
  8. private Vector3 v3 = new Vector3(10.0f,4.0f,0.0f);
  9. private Vector3 v4 = new Vector3(15.0f,6.0f,2.0f);
  10. private Vector3 v5 = new Vector3(20.0f,8.6f,0.0f);
  11. void Start () {
  12. lineRenderer = lineRenderer = gameObject.AddComponent<LineRenderer>();
  13. lineRenderer.SetColors(c1, c2);
  14. lineRenderer.SetWidth(0.2f,0.2f);
  15. lineRenderer.SetVertexCount(6);
  16. }
  17. void Update () {
  18. lineRenderer.SetPosition (0, v0);
  19. lineRenderer.SetPosition (1, v1);
  20. lineRenderer.SetPosition (2, v2);
  21. lineRenderer.SetPosition (3, v3);
  22. lineRenderer.SetPosition (4, v4);
  23. lineRenderer.SetPosition (5, v5);
  24. }
  25. }

LineRenderer的详细使用请参考雨松momo的文章:Unity3D研究院之游戏对象的访问绘制线与绘制面详解(十七)

第四部分——通过手势/鼠标来放大、缩小、旋转坐标系

简单概括为两个要点:

1.手势和鼠标的识别

在Unity中手势识别有一个插件:FingerGestures

在本例中当然不需要做的这么复杂,只需要判断触摸点来进行一些简单计算就可以。

无论是Android应用还是Unity手势判断最常用的就是简单的通过记录之前的触摸点位置和之后的触摸点位置然后再进行计算。

计算触摸点Unity提供如下几个方法:

Input.touchCount可以判断当前触摸点的数量,所以可以通过这个方法来判断是单点触摸还是多点触摸

Input.GetTouch(0).phase方法会返回一个表示当前触摸类型的枚举(TouchPhase)。

TouchPhase有如下几种类型:

  • Began
    手指已触摸屏幕。
  • Moved
    手指在屏幕上移动。
  • Stationary
    手指触摸屏幕,但并没有移动。
  • Ended
    手指从屏幕上移开。这是一个触摸的最后状态。
  • Canceled
    系统取消跟踪触摸,如用户把屏幕放到他脸上或超过五个接触同时发生。这是一个触摸的最后状态。

更多关于Input的内容强烈建议去看Unity的脚本手册,英文不好的可以去Unity圣典看中文的。

2.控制物体的放大,缩小,旋转

在Unity中放大,缩小,旋转某个物体其实是通过拉近,拉远,旋摄像机来实现的(自动脑补)。

对于如何将触摸判断和对物体控制的结合我推荐看雨松momo的这篇文章——Unity3D研究院之IOS触摸屏手势控制镜头旋转与缩放(八)

最后附上本例的这段代码,雨松文章里用的是js的我这里给改成c#并且加上了鼠标滚轮的放大缩小:

[csharp] view plaincopyprint?
  1. public class controll : MonoBehaviour {
  2. public Transform target;
  3. private float distance = 50.0f;
  4. private float xSpeed = 250.0f;
  5. private float ySpeed = 120.0f;
  6. private int yMinLimit = -20;
  7. private int yMaxLimit = 80;
  8. private float x = 0.0f;
  9. private float y = 0.0f;
  10. private int MouseWheelSensitivity = 5;
  11. private int zoomMin = 10;
  12. private int zoomMax = 50;
  13. private Vector2 oldPosition1;
  14. private Vector2 oldPosition2;
  15. void Start () {
  16. Vector3 angles = transform.eulerAngles;
  17. x = angles.y;
  18. y = angles.x;
  19. }
  20. void Update () {
  21. // 由于要支持鼠标和触摸,所以还需要加一个鼠标的计算
  22. if (Input.GetMouseButton (0)) {
  23. //根据触摸点计算X与Y位置
  24. if (Mathf.Abs(Input.GetAxis("Mouse X") * xSpeed * 0.02f) < 50) {
  25. x += Input.GetAxis("Mouse X") * xSpeed * 0.02f;
  26. }
  27. if (Mathf.Abs(Input.GetAxis("Mouse Y") * ySpeed * 0.02f) < 50) {
  28. y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
  29. }
  30. }
  31. if(Input.touchCount == 1)
  32. {
  33. //触摸类型为移动触摸
  34. if(Input.GetTouch(0).phase==TouchPhase.Moved)
  35. {
  36. //根据触摸点计算X与Y位置
  37. if (Mathf.Abs(Input.GetAxis("Mouse X") * xSpeed * 0.02f) < 50) {
  38. x += Input.GetAxis("Mouse X") * xSpeed * 0.02f;
  39. }
  40. if (Mathf.Abs(Input.GetAxis("Mouse Y") * ySpeed * 0.02f) < 50) {
  41. y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
  42. }
  43. }
  44. }
  45. //判断触摸数量为多点触摸
  46. if(Input.touchCount >1 )
  47. {
  48. //前两只手指触摸类型都为移动触摸
  49. if(Input.GetTouch(0).phase==TouchPhase.Moved||Input.GetTouch(1).phase==TouchPhase.Moved)
  50. {
  51. //计算出当前两点触摸点的位置
  52. Vector2 tempPosition1 = Input.GetTouch(0).position;
  53. Vector2 tempPosition2 = Input.GetTouch(1).position;
  54. //函数返回真为放大,返回假为缩小
  55. if(isEnlarge(oldPosition1,oldPosition2,tempPosition1,tempPosition2))
  56. {
  57. //放大系数超过3以后不允许继续放大
  58. //这里的数据是根据我项目中的模型而调节的,大家可以自己任意修改
  59. if(distance > zoomMin)
  60. {
  61. distance -= 0.5f;
  62. }
  63. }else
  64. {
  65. //缩小洗漱返回18.5后不允许继续缩小
  66. //这里的数据是根据我项目中的模型而调节的,大家可以自己任意修改
  67. if(distance < zoomMax)
  68. {
  69. distance += 0.5f;
  70. }
  71. }
  72. //备份上一次触摸点的位置,用于对比
  73. oldPosition1=tempPosition1;
  74. oldPosition2=tempPosition2;
  75. }
  76. }
  77. // 鼠标滚轮
  78. if (Input.GetAxis("Mouse ScrollWheel") != 0)
  79. {
  80. if (distance >= zoomMin && distance <= zoomMax)
  81. {
  82. distance -= Input.GetAxis("Mouse ScrollWheel") * MouseWheelSensitivity;
  83. }
  84. if (distance < zoomMin)
  85. {
  86. distance = zoomMin;
  87. }
  88. if (distance > zoomMax)
  89. {
  90. distance = zoomMax;
  91. }
  92. }
  93. }
  94. public bool isEnlarge(Vector2 oP1, Vector2 oP2, Vector2 nP1, Vector2 nP2) {
  95. //函数传入上一次触摸两点的位置与本次触摸两点的位置计算出用户的手势
  96. float leng1 =Mathf.Sqrt((oP1.x-oP2.x)*(oP1.x-oP2.x)+(oP1.y-oP2.y)*(oP1.y-oP2.y));
  97. float leng2 =Mathf.Sqrt((nP1.x-nP2.x)*(nP1.x-nP2.x)+(nP1.y-nP2.y)*(nP1.y-nP2.y));
  98. if(leng1<leng2)
  99. {
  100. //放大手势
  101. return true;
  102. }else
  103. {
  104. //缩小手势
  105. return false;
  106. }
  107. }
  108. void LateUpdate(){
  109. if (target) {
  110. //重置摄像机的位置
  111. y = ClampAngle(y, yMinLimit, yMaxLimit);
  112. Quaternion rotation = Quaternion.Euler(y, x, 0);
  113. Vector3 position = rotation * new Vector3(0.0f, 0.0f, -distance) + target.position;
  114. transform.rotation = rotation;
  115. transform.position = position;
  116. }
  117. }
  118. public float ClampAngle (float angle, float min,float max ) {
  119. if (angle < -360)
  120. angle += 360f;
  121. if (angle > 360)
  122. angle -= 360f;
  123. return Mathf.Clamp (angle, min, max);
  124. }
  125. }

写在最后:

这篇文章由于十分简单,而且我觉得逻辑讲的也算清楚,代码也贴了几段,所以源码我就不上传了。

写这个Demo的目的其实是为了下一篇文章,我在9月份的时候参加了一个网站的比赛,做了一个Unity和Android结合的3D语音的天气预报(可惜没获奖),过几天准备给它分享出来。因为我本来就是Unity菜鸟,而且好几个月没看了所以就拿这个demo先热热身。。。

PS:我Unity就会一点基础,挺怕写相关文章的,有错请见谅并恳请指正。。。

Unity制作简单3D图表相关推荐

  1. Unity 制作简单的任务动画

    Unity 制作简单的任务动画 1.添加人物模型到unity 我使用的是unity store中的免费模型: https://assetstore.unity.com/packages/3d/char ...

  2. unity ui框架_用unity制作简单的太空游戏(2)-简单炮台

    多铆蒸刚,炮塔至大! 亿万星辰,亿万炮塔! 多铆蒸刚,炮塔至上! 亿万炮塔,亿万荣光! (PS:我没有咕咕咕,就是比较惨,一口气出了半个月的差,人瘦了,也黑了,心塞塞--赶紧写个文章压压惊--) 这一 ...

  3. 用unity制作简单的太空游戏(1):简单飞船控制

    最近沉迷<Dreadnought>(中文名:无畏战舰,B站CG链接),回想起作为十余年EVE老油条的太空生涯,又萌生了做个太空游戏的情怀,所以这一次就讲讲怎么做个简单的太空飞船的小游戏好了 ...

  4. Unity制作简单拦截近防炮——如何预测打击目标

    突然想尝试一下在Unity中模拟近防炮(拦截炮),该拦截跑应该发射物理子弹并并命中处在运动中的物体,所以在代码中至少应考虑: 子弹发射矢量速度vb(暂不考虑风阻) 目标距离 L 目标当前矢量速度 v ...

  5. unity制作简单的植物大战僵尸

    文章目录 介绍 掉落阳光 卡片恢复透明度 拖拽卡片到方格子上生成植物 僵尸生成器 子弹对象池 源码 介绍 简单制作植物大战僵尸游戏. 协程实现各种相机动画 卡片填充方式修改为:"已填充&qu ...

  6. Unity制作简单的精灵图动画(新手向)

    使用精灵图制作动画步骤: 1.精灵图准备 2.制作动画 一.精灵图导入与切割 第一种情况:导入的是已经切割好的精灵图,请直接跳动到二 第二种情况:导入的是需要切割的精灵图,需要切割,切割步骤: 1按照 ...

  7. 使用unity制作简单的VR时打包APK出现的几个问题

    我的unity版本是2017.3,在打包APK之前都没什么问题,除了一个因为反光扫不出之外,都很顺利,然后到这步的时候就很多错误,然后对这些错误做了一个总结 Error building Player ...

  8. 【功能】Unity 制作简单红框闪烁提示效果

    需求:红框闪烁提示效果 实现方案:1. 特效 2. 单张 Image 原理:设置 alpha 的值,使其能够动态变化,由 0 -1 , 再由 1 - 0 首先给物体挂载 CanvasGroup 组件, ...

  9. html根据字段制作曲线图,canvas制作简单的HTML图表,折线或者矩形统计(原创)

    插件描述:canvas制作简单的HTML图表,折线或者矩形统计 使用canvas制作简单的HTML图表,折线或者矩形统计. 使用canvas制作简单的HTML图表,折线或者矩形统计,简单而实用.图形由 ...

  10. Unity 粒子制作简单飞舞纸片特效

    首先在3dmax里做一个很简单的纸片,并直接贴上带有高光和颜色的材质. 纸片在空中飞舞时会"自转",所以在max里面先做一个简单的旋转动画,并在Renderer Setup中将其序 ...

最新文章

  1. ppt文本框显示缺字,信息显示不全
  2. Serverless的理解
  3. 如何生成项目的chm文档
  4. Java线程的使用及共享协作
  5. 文档屏幕水印_您的文档何时需要屏幕截图?
  6. visualmap超过范围改变颜色_高动态范围(High-Dynamic Range,简称HDR)
  7. 程序员是制造 Bug 的“元凶”?
  8. java gc 例子_Java 中, 为什么一个对象的实例方法在执行完成之前其对象可以被 GC 回收?...
  9. JSK-25 两数之和【暴力】
  10. 告知书页面html样式,纯CSS实现的三种通知栏滚动效果
  11. 安装openstack(pike版本)nova节点,yum安装报错分析
  12. IEqualityComparerT
  13. Nitrux 图标主题与 Faenza 一样的设计 – 漂亮
  14. TyperError: excepted str,byte or os.PathLike object, not io.TextIOWrapper
  15. java线程死锁例子_java死锁例子 - 无情小白龙的个人空间 - OSCHINA - 中文开源技术交流社区...
  16. Missing Values(缺失值)
  17. Glide 显示圆形头像
  18. 什么是 “VLAN” ?
  19. 结对项目之需求分析与原型设计(选择和分配本科毕设导师)
  20. 外媒:朝鲜导弹发射失败或因美国网络攻击所致

热门文章

  1. Gos —— 开启保护模式
  2. Js Switch语句
  3. [转载]网络数据流的java处理
  4. 凸集 凸函数 判定凸函数
  5. 软磁材料种类、特点和应用范围
  6. 科比投篮选择——数据采集
  7. ArcGIS最详细的地图制作教程
  8. allegro 封装shape焊盘问题 Unable to load shape symbol
  9. 计算机的硬盘u盘属于什么,移动硬盘和机械硬盘有什么区别?
  10. 修改植物大战僵尸数据