看Unity的视频也有一段时间了,把视频里面遇到的东西稍微记录一下,
这些东西也算是Unity常用的,整理方便日后要用的的时候来搜索查看,
有些东西要用到但是比较少一点,不容易想起,这里记录下。
好记性不如烂笔头,以后会不定期更新。
Invoke("functionName",time)
功能:在time时间之后执行函数functionName(),这里这句话和functionName()在同一个脚本,至于调用其他脚本的函数好像不可行。
这里引用一篇对比介绍Invoke的文章:点击打开链接
InvokeRepeating("functionName",time,repeatTime)
功能: 在time时间之后执行函数functionName(),之后每repeatingTime时间再次执行functionName();
这里再引用一篇介绍InvokeRepeating的文章:点击打开链接
get和set
功能:get和set是属性特有的两个方法。属性是对字段的封装,是为了程序数据的安全性考虑的。
总的来说,字段有两种操作权限,就是获取和修改,就分别对应的是get和set方法了,可以通过制定get和set方法来限定字段的访问权限。
这里遇见的是用在单例模式的时候,将脚本实例化物体赋值给私有变量,然后通过get、set来访问该脚本类型的变量,
然后调用其中的方法和属性,get、set保证数据安全性。
private int _age;//年龄 字段
public int Age
{
get
{
return _age;
}
set
{
if(_age<0 || _age>150) _age=null;
else _age=value;
transform.Find("Label").GetComponent<UILabel>().text=""+age;
}
}
调用的时候直接.Age就可以了,写了set的函数可以直接赋值Age=?,只写了get就不行。
这里引用一篇易懂的文章:点击打开链接
SendMessage("functionName",parameters)
功能:调用函数
这里引用一篇简单的文章:点击打开链接
Params
功能:用在函数声明时候放在数组参数声明前面,用以传递不确定个数的同一类参数。
例如,声明时是method(params int i[]);则调用时候可以是mathod(1)、mathod(2,3)、mathod(1,2,3,4)等等。
这里引用一篇言简意赅的文章:点击打开链接
[HideInInspector]
功能:当你希望有些属性在别的类别的脚本里直接访问到,你把它设置为public属性。
但是在脚本编译好后,你又不希望它出现在unity的Inspector面板,可以在
public前面加上这段话。
这里引用一篇相关术语介绍的文章:点击打开链接
找到在Inspector面板中不启用的物体
如图
这样的物体我们也可以直接在代码中找到他。代码如下:
this.transform.parent.Find("Conatainer");
其中的this是和Container的父物体相同的物体。
比如这个是NGUI的物体,然后他的transform的父物体就是
UIRoot,这种方法可以找到Unity中没有启用的物体的transform,
如果要找GameObject,可以在后面加上后缀.gameobject。
三维世界里物体旋转的几种方法
- 当你的GameObject使用了RigidBody组件,可以调用RigidBody里面的AngularSpeed属性,来给角速度赋值。FixedUpda和Update帧长不同,FixedUpdate是在固定帧调用的,一般Rigidbody物理位移的操作可以放在FixedUpdate里面。例如: 在Update函数中
float h = Input.GetAxis("Horizontal"); rigidbody.angularVelocity = transform.up * h * angularSpeed;
- 当然RigidBody类还提供了 MoveRotation()方法,直接将物体移动至某个角度,所以当你需要移动的过程的时候要注意传进去的参数了。比如:在Update()中
float h = Input.GetAxis("Horizontal"); float v = Input.GetAxis("Vertical");
GetComponent<Rigidbody>().MoveRotation(Quaternion.Euler(transform.rotation.x + h * speed * Time.deltaTime, 0, transform.rotation.z + v * speed * Time.deltaTime));
- 使用transform的Rotate()方法,这个很多人应该都知道了,这个方法有六个重载,具体内容可以查看圣典:点击打开链接
- 使用Vector3.Lerp函数,实现一个有过程的旋转:
<span style="white-space:pre"> </span>targetVector=targetTransform.position-transform.position; transform.forward = Vector3.Lerp(transform.forward,targetVector,rotateSpeed*Time.deltaTime);
- 当你的GameObject使用了RigidBody组件,里面有个方法叫做MovePosition,和MoveRotation一样,直接将物体移动至某一位置,所以传参要注意一下。例如,在Update()中:
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
GetComponent<Rigidbody>().MovePosition(transform.position + new Vector3(h, 0, v) * speed * Time.deltaTime);
- Transform.Translate()函数,这个不多说了,最直接常用的函数,将物体向目标点移动
- 当你的GameObject使用了CharacterController组件,可以调用CharacterController的SimpleMove和Move方法实现移动。下面引用一篇文章可以了解下SimpleMove方法:点击打开链接
使用CharacterController的时候,可以在Update或者FixedUpdate中使用其move方法,在必要的时候(比如按下空格键)添加向上的速度,实现跳跃:
upSpeed = transform.up * jumpSpeed;
upSpeed.y -= gravity * Time.deltaTime;
myController.Move((upSpeed + transform.forward)*Time.deltaTime);
transform.TransformDirection
虽然一直搞不清楚这个函数的具体意思,但是我试用过好多次发现他能把世界坐标的z轴转化为自身的z轴。即如果角色想沿着自身的z轴前进而不是世界的z轴,可以使用这个函数。例如:
transform.TransformDirection(new Vector3(0, 0, 1))
这在有时transform.forward不起效果的时候很有用。
如果在脚本里写有Invoke()来调用方法,然后禁用了该脚本,但是该脚本的某些效果并没有停止,请记得在停用脚本的时候调用CancelInvoke,有参无参
就自己判断了。记得自己在这里找bug找了好久...
Unity更改脚本的执行顺序
单击脚本,然后在Inspector面板可以看到有一个Excution Order按钮
点击之后界面如图:
在这里旋转,格子里的数字越小越在上面,代表越先执行。
继承了UIDragDropItem的类的Start()方法如果要重写记得要在重写的Start()方法里面写上base.Start(),否则会调用出错,以后继承了其他功能类如果遇到错误可以尝试此思路。
获得鼠标位置的方法:
在普通世界坐标中,我们获取物体鼠标位置的方法通常是使用
Camera.main.ScreenToWorldPoint(Input.mousePosition);
这个方法,这里获得的三维坐标的z和摄像机相同,而不是0,所以有必要的话要改z坐标。
然后在NGUI中获得鼠标位置的方法,则是通过
UICamera.currentCamera.ScreenToWorldPoint(Input.mousePosition);
这个方法来获得的
Unity旧版Animation播放结束的判断
在旧版动画中,有时我们需要在前一个动画播放完成后再播放别的动画。
if (!myAnim.isPlaying)
{
myAnim.CrossFade(aniName);
}
可以使用animation.isPalying变量来判断,这里要注意的是该animationClip的WrapMode是Once,如果是Loop
则isPlaying变量不会变化。至于animation的详解可以参看我转载的博客:点击打开链接
查找判断的物体为null,而不能判断子物体或者组件是否为null
我有时需要某物体的transform,我们查找的时候是应该这样:
GameObject gObj=GameObject.FindGameObjectWithTag(GameTags.swordMan) as GameObject;
if ( gObj!= null)
{
player = gObj.transform;
}
else
{
player = GameObject.FindGameObjectWithTag(GameTags.magician).transform;
}
而不是这样:
player = GameObject.Find("Swordman").transform;
if (player == null)
{
player = GameObject.Find("Magician").transform;
}
获取NGUI的鼠标点击及相应信息
NGUI提供了一个方便的方法
void OnPress(bool isPress)
{
this.isPress = isPress;
}
这个方法的isPress代表鼠标是否按下,可以通过这个标志位来在Update
里面做一些操作。
UICamera.LastTouchPosition表示鼠标在UI界面的点击位置,
以NGUI设计界面的Root的左下角为原点。
动态给NGUI按钮添加点击响应事件
EventDelegate NormalAttackEvent = new EventDelegate(this, "OnNormalAttackClick");
GameObject.Find("NormalAttack").GetComponent<UIButton>().onClick.Add(NormalAttackEvent);
给名字叫NormalAttack的游戏物体的按钮组件添加这个脚本的OnNormalAttackClick的函数。
CharacterController的isGrounded属性
CharacterController提供了属性isGrounded以供检测,但是在使用中发现isGrounded总是返回false,个人认为CharacterController的SkinWidth要设置合理,皮肤厚度决定了两个碰撞器可以互相渗入的深度。较大的皮肤厚值度会导致颤抖。小的皮肤厚度值会导致角色被卡住。一个合理的设定是使该值等于半径(Radius)的10%,再小点检测会更准确点,但是不能太小。
当在FixedUpdate里面使用CharacterController.Move或者SimpleMove出现卡顿的时候,不妨把相关代码放在Update里面,卡顿现象可能就会得到解决。
在Unity中一些你想要new出来的类一定不要继承monobehaviour,如果忘记了这一点,你会使劲排查你的程序逻辑却排查不出错误,过了猴年马月后才发现一切正常,只是你要new的类继承了monobehaviour,就new不出来了。