admin 管理员组文章数量: 887021
脚本
脚本执行顺序
默认脚本是无序执行,也就是哪个脚本先执行,哪个脚本后执行是未知的。
也可以手动指定执行顺序,
在如上图所示中,可以点击 加号 按钮,然后添加脚本的顺序,数值越大,执行顺序越靠后。
消息函数
Awake 初始化执行,仅执行一次,在Start方法前,脚本被禁用后依旧会执行,
Start 初始化执行,仅执行一次,脚本被禁用后不会执行
Update , 帧更新,每帧调用一次,
OnEnable, 脚本组件启用时调用一次,
OnDisable, 脚本组件禁用时调用一次,
消息调用
此处的消息调用和消息函数不一样,看起来名字相同而已。
在target物体上挂了一个Script2的脚本,在r物体上挂了一个SimpleExample的脚本。
SimpleExample中代码如下所示,
GameObject target = null;
// Start is called before the first frame update
void Start()
{Application.targetFrameRate = 60;target = GameObject.Find("/empty/target");
}// Update is called once per frame
void Update()
{if (Input.GetKeyDown(KeyCode.UpArrow)){target.SendMessage("musicVolume", 20f);}else if (Input.GetKeyDown(KeyCode.DownArrow)){target.SendMessage("musicVolume", -1f);}
}
获取到target物体后,通过SendMessage就可以通过反射调用Script2脚本中的musicVolume方法,这个方法如下所示,
public void musicVolume(float volume)
{audioSource.volume = volume;
}
此 SendMessage(methodName,Object args); 两个参数中,第一个是方法名,第二个是Object参数,那么也就意味着可以传入一个数组等。
此处不知道为何,第二个参数填0的时候就报错。
target.SendMessage("musicVolume", 0f);
物体增加脚本
右击,Create->C# Script , 新建一个*.cs的文件,然后双击在Visual Studio中打开。
在GameObject上挂载上这个脚本 Add Component --> Script
脚本原始就是这些代码。
简单信息打印
void Start()
{GameObject go = this.gameObject;Debug.Log("info:"+go);Debug.Log("info:" + go.name);Debug.Log("info:" + go.transform.position);
}
this代表的是SimpleExample这个CS脚本,this.gameObject自然就是它挂载的GameObject了。
transform.position打印的是世界坐标系的坐标,只有用localPosition打印的才是本地坐标系的坐标,也就是相对坐标。
本地坐标系和世界坐标系说明
但和界面上本地坐标系和世界坐标系不同在于,世界坐标指的是在Scene中的坐标,而localPosition是相对父物体的坐标。
物体移动
方法一
不断的修改localPosition的数值,
void Update()
{Vector3 localPosition = this.transform.localPosition;localPosition.x += 0.01f;this.transform.localPosition = localPosition;
}
this.transform 是 this.gameObject.transform的缩写。
方法二
Translate(x,y,z)方法,此处的x,y,z是增量值,即 x+= ? ,y+=? , z+=?
void Update()
{this.transform.Translate(0.01f,0,0);
}
这两种方法都可以让物体在X轴上每帧移动0.01的距离。
点击Translate()方法后,反编译发现,其实也是设置世界坐标。
此处会执行else中语句。
TransformDirection_Injected就无法看到了,但从注释可以看出,应该是将本地坐标系转换为世界坐标。
在移动时有两个坐标系参考,一个是世界坐标系,一个是自身的坐标系。
参考
此处为语雀内容卡片,点击链接查看:
所以Translate()方法还有第四个参数,Space.World和Space.Self,分别表示参考世界坐标系,和自身坐标系。
朝物体移动
朝物体移动首先需要转向,用到LookAt方法,这个方法是将物体旋转,使Z轴指向目标物体。
target = GameObject.Find("target");
this.transform.LookAt(target.transform); //Z轴指向目标物体
朝物体移动后还需要判断和物体的距离,
Vector3 positionSelf = this.transform.position;
Vector3 positionTarget = this.target.transform.position;
Vector3 distanceV = positionSelf - positionTarget;
float distance = distanceV.magnitude; //判断距离
if (distance > 2)
{this.transform.Translate(0,0,0.1f,Space.Self);
}
物体旋转
方法一
Vector3 localAngles = this.transform.localEulerAngles;
localAngles.y += 0.5f;
this.transform.localEulerAngles = localAngles;
通过调整localEulerAngles这个角度,能让物体不断的旋转。
方法二
用Rotate方法,
this.transform.Rotate(0, 0.5f, 0, Space.Self);
脚本参数
在脚本中设置全局变量即可,Tooltip是提示,当鼠标悬浮时可以显示提示文字。
[ Tooltip("Y轴移动速度")] public float speed = 0.3f;
鼠标按键
Input.GetMouseButtonDown() 鼠标按下
Input.GetMouseButtonUp() 鼠标抬起
Input.GetMouseButton() 正在按鼠标 鼠标状态的探测
0 鼠标左键
1 鼠标右键
2 鼠标中键
if (Input.GetMouseButtonDown(0))
{Debug.Log("按下鼠标左键");
}
else if (Input.GetMouseButtonDown(1))
{Debug.Log("按下鼠标右键");
}
else if (Input.GetMouseButtonDown(2))
{Debug.Log("按下鼠标中键");
}
鼠标按键问题点
鼠标按下是个全局事件,也就是说并不是像 html页面一样,给某个元素设置一个 @click 事件,所以如何判断鼠标点击了哪个物体?
在3D游戏中,看起来是3D的,但其实屏幕是2D,也就是说其实只存在x,y两个坐标系就可以判断位置在屏幕中的范围。
屏幕左下角是(0,0)坐标,从左下角开始向上和向右。
Vector3 mousePos = Input.mousePosition;//鼠标点击在屏幕中位置
上面就可以获取到鼠标在屏幕中点击的位置。
Vector3 objWorldPos = this.transform.position;
Vector3 objScreenPos = Camera.main.WorldToScreenPoint(objWorldPos);
上面两行代码,获取物体的三维坐标,并将三维坐标转换为屏幕坐标,此时objScreenPos就只有x,y是有效值,z并没有参考价值了。
int screenWidth = Screen.width;
int screenHeight = Screen.height;
上述两行代码可以获取屏幕的宽高,
Vector3 objWorldPos = this.transform.position;
Vector3 objScreenPos = Camera.main.WorldToScreenPoint(objWorldPos);Vector3 mouseWorldPos = Input.mousePosition;
Vector3 mouseScreenPos = Camera.main.WorldToScreenPoint(mouseWorldPos);Vector3 distanceV = objScreenPos-mouseScreenPos;
float distance = distanceV.magnitude;if (objScreenPos.x < 0 || objScreenPos.x > Screen.width || objScreenPos.y < 0 || objScreenPos.y > Screen.height)
{}
键盘事件
Input.GetKeyDown() 按键事件,按下键
Input.GetKeyUp() 按键事件,抬起键
Input.GetKey() 按键状态,某个键正被按着
if (Input.GetKey(KeyCode.W))
{this.transform.Translate(0,0,0.3f,Space.Self);
}else if (Input.GetKey(KeyCode.S))
{this.transform.Translate(0, 0, -0.3f, Space.Self);
}
一般可以用Input.GetKey来让物体移动,其中KeyCode的值可以在unity的api文档中找到。
AudioSource组件调用
给r这个GameObject挂上Audio Source组件,然后就可以通过脚本获取组件,用组件来控制播放的开始和暂停等。
AudioSource audioSource = null;// Start is called before the first frame update
void Start(){Application.targetFrameRate = 60;//获取此脚本上GameObject的AudioSource组件audioSource = GetComponent<AudioSource>();}// Update is called once per frame
void Update(){if (Input.GetMouseButtonDown(0))//鼠标左击{if (audioSource.isPlaying)//正在播放{audioSource.Pause();}else{audioSource.Play();}}}
GetComponent<AudioSource>(); 是 this.gameObject.GetComponent<>的缩写,也可以缩写为this.GetComponent<>。
通过完整的写法可以知道,如果把this改为其他物体的GameObject,那么就能获取到其他物体上挂载的组件。
代码播放音效
如上图所示,不给AudioSource文件指定音乐文件,而是在脚本中指定音乐文件,然后播放。
public AudioClip clip;AudioSource audioSource;// Start is called before the first frame update
void Start()
{Application.targetFrameRate = 60;this.audioSource = GetComponent<AudioSource>();
}// Update is called once per frame
void Update()
{if (Input.GetMouseButtonDown(0)){audioSource.PlayOneShot(clip);}}
PlayOneShot方法常用来播放游戏枪声音效。
物体获取
方法一
在脚本参数中有设置一个speed的参数,在unity编辑器界面就可以设置数值。
那么也可以设置一个变量是GameObject,AudioSource等。
在target上挂载AudioSource组件,在r上挂载脚本,把target作为一个赋值传入。
public GameObject target = null; AudioSource audioSource = null;// Start is called before the first frame updatevoid Start(){Application.targetFrameRate = 60;//target上的组件audioSource = target.GetComponent<AudioSource>();}// Update is called once per framevoid Update(){if (Input.GetMouseButtonDown(0))//鼠标左击{if (audioSource.isPlaying)//正在播放{audioSource.Pause();}else{audioSource.Play();}}}
方法二
GameObject target = GameObject.Find("target");
audioSource = target.GetComponent<AudioSource>();
直接利用GameObject的Find方法
如果Find方法里面的单词写错了,会报下面的空指针异常。
GameObject target = GameObject.Find("/empty/target");GameObject target = GameObject.Find("empty/target");
如果像这种挂载在其他节点下,那么就需要加上路径,上面两种路径都可以找到target。
父物体获取
target = GameObject.Find("/empty/target");
GameObject empty = target.transform.parent.gameObject;
如上代码所示,获取target的父物体empty。
从上面代码也可以看出,维持父子间关系的是transform类,只有获取transform类才能获取到parent,此时获取的也只是父节点的transform,要继续获取GameObject还得加上parent.gameObject才行。
如果维持父子间关系的是GameObject类,那么就可以直接 target.parent,就能获取父节点的GameObject对象了。
父物体设置
如图所示,运行时将target父节点设置为r物体。
target = GameObject.Find("/empty/target");
target.transform.SetParent(this.transform);
当设置为SetParent(null)时,就是放在根节点下。
脚本获取
其实脚本获取和物体获取,组件获取一样,脚本也是组件的一种。
如何获取其他物体上挂载的脚本?
Script2.cs脚本挂载到target上,在SimpleExample中获取Scripts脚本。
Scripts2 scripts2 = null;
// Start is called before the first frame update
void Start()
{Application.targetFrameRate = 60;GameObject target = GameObject.Find("/empty/target");scripts2 = target.GetComponent<Scripts2>();
}
如上述所示,其实和获取组件一样,都是通过GameObject。
void Update()
{scripts2.musicPlay();if (Input.GetKeyDown(KeyCode.UpArrow)){scripts2.volume++;}else if (Input.GetKeyDown(KeyCode.DownArrow)){scripts2.volume--;}
}
在SimpleExample.cs的Update()方法中,就可以调用Script2.cs中public的方法和变量了。
Script2.cs中代码如下,
AudioSource audioSource = null;public float volume = 0f;//音量// Start is called before the first frame updatevoid Start(){audioSource = this.GetComponent<AudioSource>();audioSource.volume = volume;}// Update is called once per framevoid Update(){audioSource.volume = volume;}public void musicPlay(){if (Input.GetMouseButtonDown(0))//鼠标左击{if (audioSource.isPlaying)//正在播放{audioSource.Pause();}else{audioSource.Play();}}}
物体激活和隐藏
对应到界面就是这个小勾。
GameObject target = GameObject.Find("/empty/target");
if (target.activeSelf)
{target.SetActive(false);
}
物体处于激活状态,就隐藏。
修改物体材质
材质使用Meshranderer中material修改即可。
public Material[] materials;int nowIndex = 0;// Start is called before the first frame update
void Start()
{Application.targetFrameRate = 60;
}// Update is called once per frame
void Update()
{if (Input.GetMouseButtonDown(0)){nowIndex = ++nowIndex%materials.Length;MeshRenderer meshRenderer = GetComponent<MeshRenderer>();meshRenderer.material = materials[nowIndex];}}
定时器
有两种定时器,只执行一次的定时器Invoke和重复执行的InvokeRepeat,有点像javascript中的setTimeout和setInterval方法。
Invoke
注意Invoke里是反射,第二个参数单位是秒。
而且放在Start()方法中即可,放在Update中就是重复执行了,Update本身就是重复执行的方法。
此处的this代表的是Script组件,也就是说获取了其他GameObject上的Script组件后,也可以调用其他脚本里的方法。
void Start()
{Application.targetFrameRate = 60;this.Invoke("repeatFunction", 2f);
}// Update is called once per frame
void Update()
{}private void repeatFunction()
{Debug.Log("repeatFuntion:" + Time.time);
}
InvokeRepeating
第二个参数是脚本加载1秒后开始执行第一次,
第三个参数是每隔2秒执行一次。
this.InvokeRepeating("repeatFunction", 1f, 2f);//判断是否要执行,可以取消定时任务
if (this.IsInvoking("repeatFunction"))
{this.CancelInvoke("repeatFunction");
}
获取线程号
using System.Threading;
int threadId = Thread.CurrentThread.ManagedThreadId;
物体向量
长度
使用magnitude即可。
Vector2 vector2 = new Vector2(2, 3);
float magnitude2 = vector2.magnitude;Vector3 vector3 = new Vector3(2,3,3);
float magnitude3 = vector3.magnitude;
单位向量
使用normalized将此向量变为长度为1的单位向量,长度为1即
Vector3 vector3 = new Vector3(2,3,3);
Vector3 v3Normal = vector3.normalized;
常用向量简写
Vector3.zero (0,0,0)
Vector3.up (0,1,0)
Vector3.right (1,0,0)
Vector3.forward (0,0,1)
向量运算
Vector3 a = new Vector3(1,1,1);
Vector3 b = new Vector3(2,2,2);
两个向量相加就是 a+b = (3,3,3) 分别x,y,z相加。
相减就是 a-b = (-1,-1,-1) 分别x,y,z相减。
向量乘以常量 a*2 = (2,2,2) x,y,z分别乘以这个常量。
距离
Vector3 a = new Vector3(2,3,3);
Vector3 b = new Vector3(2, 3, 3);Vector3 c = b - a;
float distance = c.magnitude;//两个向量点位置之间的距离float distance = Vector3.distance(a,b); //这是封装的方法,求距离的
动态创建实例
使用 Object.Instantiate,第一个参数是一个Object对象,即预制体,第二个是挂载到的父节点,是一个Transform对象。
public class SimpleExample : MonoBehaviour
{[ Tooltip("预制体")]public GameObject prefab;// Start is called before the first frame updatevoid Start(){Application.targetFrameRate = 60;}// Update is called once per framevoid Update(){if (Input.GetMouseButtonDown(0)){GameObject go01 = Object.Instantiate(prefab,null);GameObject go02 = Object.Instantiate(prefab);go01.transform.position = Vector3.zero;go02.transform.position = Vector3.zero;}}
}
上面第二个参数null,或者为空都是挂载到根节点下。
销毁实例
使用 Object.Destroy(销毁对象,延迟销毁时间); 时间单位秒,第一个参数通常传GameObject
public class SimpleExample : MonoBehaviour
{[Tooltip("预制体")]public GameObject prefab;private GameObject gameObject;// Start is called before the first frame updatevoid Start(){Application.targetFrameRate = 60;}// Update is called once per framevoid Update(){if (Input.GetMouseButtonDown(0)){if (gameObject != null) { Object.Destroy(gameObject); //销毁实例}else{gameObject = Object.Instantiate(prefab, null);gameObject.transform.position = Vector3.zero;}}}
}
本文标签: 脚本
版权声明:本文标题:脚本 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/jishu/1686619031h17908.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论