标签:
今天做了一个萤火虫飞舞效果,这个问题类似于一道算法题:一个点想移动到平面上任意一点,但是自身有一个旋转角度限制,每一次旋转时,最大旋转角度是 maxRotateAngle,思维延时(即两次连续执行自身指令的间隔)是 float gap。
大致思路是:
建立了四个指令,分别是:
Blink()—— 萤火虫屁股发光,是闪烁的......闪烁的...
Move()——(默认使用 Vector2 curSpeed 作为移动增量)
ComputeDir() —— 根据目标位置,计算当前运动方向,因为旋转角度限制无法一次直达。
Escape()—— 这个纯属自娱自乐了,哈哈,当鼠标接近萤火虫时,他就会“拼命地”逃离鼠标,我自己瞎搞的玩的。
这里只加了一直萤火虫,可以加更多。
(美术实在太差,,,凑合看看热闹吧....)
*******************************************************
技术细节:
1.转向问题有点棘手,因为要考虑很多方面。其中之一就是坐标系问题我在这个脚本里面用了Graphics.DrawTexture()函数,这个底层函数的坐标原点和其他的不太一样,是左上角为原点的。
如果不熟悉,可以用 print() 多测试几次,我就是这么搞的。(>_<)。
(改了好几次,写了好多个版本。最终敲定了现在手上的版本。)
2.其二考虑的是效率问题了,转向,三角函数是少不了用的,其中我想到了的一种方法以萤火虫自身为原点,前进方向为Y轴建立坐标系,然后进行计算。这个法子很笨的,因为后期还要把目标点切出来转换到屏幕空间,反而繁琐了;也许是我能力不够,没找到优化方法吧。
我所采用的方法是,直接在屏幕空间来进行计算。因为有了统一他标准,少了很多转换,优化手段也多了起来。具体来说也很繁琐。
优化无止境啊... 大概思路还是那句老话:用更少的空间代价,换取更快的速度。
3.说一说Graphics绘图:用过了几次后,(发现这个有点类似于Java的绘图,JAVA绘图很简单,应该说实际上不止JAVA各个绘图API底层都是这样的语法。)
这个底层绘图不能随便用,因为深度测试绕过去了,绘制顺序必须再自己统一规定,不利于模块化;
它的使用有一些点必须注意:
必须是这样的格式,在发生repaint 时才能绘制。联系JAVA、win32的知识,就知道了repaint,这绝对是在最后一个绘制的,前面的深度测试,顶点变换什么的他都不干,直接插队到最后,就是这样一个霸道的站在世界的顶点的男银。
————————————————————————————————————————————————
最后一环,贴代码吧:
自己写的也有很多不足,模块化不像模块化,函数之间的接替性不够,因为是我自己一个人玩玩,所以能用全局变量全部用的全局变量。还有很多,希望童鞋们不吝指教,多多与我交流,^_^
1 using UnityEngine; 2 using System.Collections; 3 4 public class Star : MonoBehaviour { 5 6 public Vector2 initPosPercent; 7 8 public float maxComputeDestGap = 1.0f; 9 public float curComputeDestGap = 0.0f; 10 public float computeDirGap = 0.5f; 11 public float curComputeDirTime = 0.0f; 12 // 纹理 13 public Texture2D starBgd; 14 private Rect bgdRT = new Rect(0,0,0,0); 15 float maxWidth, maxHeight, width, height; 16 17 // 图片宽 18 public float percentWidth = 0.1f; 19 20 // 速度最大值 21 public float maxSpeedAmount = 0.2f; 22 23 // 当期速度值 24 public float curSpeedAmount = 0.2f; 25 26 // 放大种子 27 public float scaleSeed = 0.0f; // 初始扩大系数 28 public float maxScale = 0.8f, minScale = 0.5f; 29 30 // 最大旋转角度 31 public float maxRotateAngle = 0.5f; // 大约30度 32 float curRotateAngle = 0.0f; 33 // 当前速度 34 private Vector2 curSpeed = new Vector2(0.0f,0.0f); 35 // 当前缩放比 36 private float curScale = 1.0f; 37 38 private float destX = 0.0f, destY = 0.0f; 39 40 // 常量 41 private float halfPI; 42 private float PI2; 43 44 // 逃跑警戒距离 45 public float escapeDist; 46 public float escapeSpeedAmount; 47 48 // Use this for initialization 49 void Start () { 50 51 Vector3 pos = new Vector3 (Screen.width * initPosPercent.x, Screen.height * initPosPercent.y, 0.0f); 52 transform.position = pos; 53 54 width = maxWidth = Screen.width * percentWidth; 55 height = maxHeight = width; 56 57 bgdRT = new Rect ( transform.position.x, transform.position.y, width*curScale, height*curScale ); 58 59 60 halfPI = Mathf.PI * 0.5f; 61 PI2 = Mathf.PI * 2.0f; 62 } 63 64 65 // Update is called once per frame 66 void Update () { 67 68 if (curComputeDestGap < maxComputeDestGap ) 69 curComputeDestGap += Time.deltaTime; 70 else 71 { 72 // 生成新目标 73 destX = Random.Range (0, Screen.width); 74 destY = Random.Range (0, Screen.height); 75 76 curComputeDestGap = 0.0f; 77 } 78 79 if (curComputeDirTime < computeDirGap ) 80 curComputeDirTime += Time.deltaTime; 81 else 82 { 83 // 生成新方向 84 ComputeDir ( destX, destY); 85 86 curComputeDirTime = 0.0f; 87 } 88 89 90 // 逃离 91 Escape (); 92 93 // 移动 star 94 Move (); 95 96 } 97 98 99 void OnGUI() 100 { 101 if( Event.current.type.Equals(EventType.Repaint) ) 102 { 103 // print ( x ); 104 float x = transform.position.x - width * 0.5f; 105 float y = transform.position.y - height * 0.5f; 106 bgdRT = new Rect ( x, y, width, height ); 107 108 109 GUI.DrawTexture ( bgdRT, starBgd ); 110 } 111 } 112 113 void Blink() 114 { 115 curScale = (maxScale - minScale)* 0.5f * Mathf.Sin (Time.time + scaleSeed) + maxScale; 116 117 width = maxWidth * curScale; 118 height = width; 119 } 120 121 void Escape() 122 { 123 Vector2 pos = new Vector2 ( transform.position.x, transform.position.y ); 124 Vector2 mousePos = new Vector2 ( 0, 0 ); 125 mousePos.x = Input.mousePosition.x; 126 mousePos.y = Screen.height - Input.mousePosition.y; 127 128 float dist = Vector2.Distance ( mousePos, pos); 129 130 if( dist <= escapeDist ) 131 { 132 Vector2 dir = new Vector2( 0.0f, 0.0f ); 133 134 dir = pos - mousePos; 135 136 dir.Normalize(); 137 curSpeed = dir * escapeSpeedAmount; 138 } 139 } 140 141 142 void Move () 143 { 144 float t = transform.position.x + curSpeed.x; 145 146 // 防越界 147 if ( t < 0.0f || t > Screen.width ) 148 curSpeed.x = -curSpeed.x; 149 t = transform.position.y + curSpeed.y; 150 if (t < 0.0f || t > Screen.height) 151 curSpeed.y = -curSpeed.y; 152 153 154 transform.Translate ( curSpeed.x * Time.deltaTime, curSpeed.y*Time.deltaTime, 0); 155 } 156 157 void ComputeDir( float srcX, float srcY ) 158 { 159 // 根据源位置计算目标位置,旋转角度有限所致 160 float m = srcX - transform.position.x; 161 float n = srcY - transform.position.y; 162 163 // 在自身坐标系中的坐标 164 float angle = Mathf.Atan2 ( n, m ); 165 166 float dAngle = angle - curRotateAngle; 167 168 // 转变成 pi < A - C < -PI 169 if (dAngle < -Mathf.PI) { 170 angle += PI2; 171 } 172 else if( dAngle > Mathf.PI ) 173 { 174 angle -= PI2; 175 } 176 177 dAngle = angle - curRotateAngle; 178 179 180 // 计算最终角度 181 if (dAngle > -maxRotateAngle && dAngle < maxRotateAngle) 182 { 183 // 一步即达的目标方向 184 curRotateAngle = angle; 185 } 186 else 187 { 188 if( dAngle < 0.0f ) 189 { 190 curRotateAngle -= maxRotateAngle; 191 } 192 else 193 { 194 curRotateAngle += maxRotateAngle; 195 } 196 197 } 198 199 // 转换到 -PI 到 PI 空间 200 if (curRotateAngle < -Mathf.PI) { 201 curRotateAngle += PI2; 202 } 203 else if( curRotateAngle > Mathf.PI ) 204 { 205 curRotateAngle -= PI2; 206 } 207 208 // 计算最终速度 209 curSpeed.x = curSpeedAmount * Mathf.Cos ( curRotateAngle ); 210 curSpeed.y = curSpeedAmount * Mathf.Sin ( curRotateAngle ); 211 212 return; 213 } 214 215 }
***************
吐硼:
C#真是够了,虐的我压灭压灭的,一说全是泪啊....
标签:
原文地址:http://www.cnblogs.com/SecretMan001/p/4539753.html