Unity3D数字孪生笔记(二)——Unity篇
一、常用API
1、Component
Component类提供了查找(在当前物体、后代、先辈)组件的功能。
- 常用属性
gameObject、transform、collider、renderer… - 常用方法
- GetComponent、GetComponentInChild、GetComponentInParent…
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Component类提供了查找(在当前物体、后代、先辈)组件的功能。
/// </summary>
public class ComponentDemo : MonoBehaviour
{
private void OnGUI()
{
if (GUILayout.Button("transform"))
{
this.transform.position = new Vector3(0, 0, 10);
}
if (GUILayout.Button("GetComponent"))
{
this.GetComponent<MeshRenderer>().material.color = Color.red;
}
if(GUILayout.Button("GetComponents"))
{
//获取当前物体所有组件
var allComponent = this.GetComponents<Component>();
foreach (var item in allComponent)
{
Debug.Log(item.GetType());
}
}
if(GUILayout.Button("GetComponentsInChildren"))
{
//获取后代物体的指定类型组件(从自身开始,从上往下)
var allComponent = this.GetComponentsInChildren<MeshRenderer>();
foreach (var item in allComponent)
{
item.material.color = Color.red;
}
}
if (GUILayout.Button("GetComponentsInParent"))
{
//获取先辈物体的指定类型组件(从自身开始,从下往上)
var allComponent = this.GetComponentsInParent<MeshRenderer>();
foreach (var item in allComponent)
{
item.material.color = Color.red;
}
}
}
}
2、Transform
Transform类 提供了 查找(父、根、子(索引、名称))变换组件、改变位置、角度、大小功能。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Transform类 提供了 查找(父、根、子(索引、名称))变换组件、改变位置、角度、大小功能
/// </summary>
public class TransformDemo : MonoBehaviour
{
//***********查找变换组件****************//
public Transform tf;
private void OnGUI()
{
if(GUILayout.Button("foreach--transform"))
{
foreach (Transform child in this.transform)
{
//child为 每个子物体的变换组件
print(child.name);
}
}
if(GUILayout.Button("root"))
{
//获取根物体变换组件
Transform rootTF = this.transform.root;
}
if (GUILayout.Button("parent"))
{
//获取父物体变换组件
Transform parentTF = this.transform.parent;
}
if (GUILayout.Button("setparent"))
{
//设置父物体,当前物体的位置 视为世界坐标
//this.transform.SetParent(tf,true);
//设置父物体,当前物体的位置 视为localposition
this.transform.SetParent(tf,false);
this.transform.SetParent(null);
}
if(GUILayout.Button("find"))
{
//根据名称获取子物体
Transform childTF = this.transform.Find("子物体名称");
//Transform childTF = this.transform.Find("子物体名称/子物体名称/子物体名称");
}
if (GUILayout.Button("getchild"))
{
//根据索引获取子物体
int count = this.transform.childCount;
for (int i = 0; i < count; i++)
{
Transform childTF = this.transform.GetChild(i);
}
}
//***********改变位置、角度、大小****************//
if (GUILayout.Button("pos/scale"))
{
//物体相对于世界坐标系原点的位置
//this.transform.position
//物体相对于父物体轴心点的位置
//this.transform.localPosition
//相对于父物体缩放比例 1 2 1
//this.transform.localScale
//lossyScale理解为:物体与模型缩放比例(自身缩放比例*父物体缩放比例)
//this.transform .lossyScale
//如:父物体localScale为3 当前物体localScale为2
// lossyScale则为6
}
if (GUILayout.Button("translate"))
{
//向自身坐标系Z轴 移动1米
this.transform.Translate(0, 0, 1);
//向世界坐标系z轴 移动1米
//this.transform.Translate(0, 0, 1, Space.World);
}
if (GUILayout.Button("rotate"))
{
//向自身坐标系Z轴 旋转10°
//this.transform.Rotate(0, 0, 10);
//向世界坐标系y轴 旋转10°
this.transform.Rotate(0, 10, 0, Space.World);
}
if (GUILayout.RepeatButton("rotatearound"))
{
//围绕旋转: 点 轴 角度
this.transform.RotateAround(Vector3.zero, Vector3.up, 1);
}
//练习:在层级未知情况下查找子物体
//递归
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 层级未知情况下寻找依照名称寻找子物体
/// </summary>
public class FindChildrenByName : MonoBehaviour
{
public static Transform FindChild(Transform current,string childname)
{
Transform childTF = current.Find(childname);
if (childTF != null) return childTF;
for (int i = 0; i < current.childCount; i++)
{
childTF = FindChild(current.GetChild(i), childname);
if (childTF != null) return childTF;
}
return null;
}
}
3、GameObject
Gameobject类提供了启用、禁用、新建、查找游戏对象的功能。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// gameobject类提供了 启用、禁用、新建、查找游戏对象的功能
/// </summary>
public class GameObjectDemo : MonoBehaviour
{
public void OnGUI()
{
//在场景中物体激活状态(物体实际激活状态)
//this.gameObject.activeInHierarchy
//物体自身激活状态(物体在Inspector面板中的状态)
//this.gameObject.activeSelf
//设置物体启用/禁用
//this.gameObject.SetActive()
//this.gameObject.AddComponent<Light>()
if (GUILayout.Button("添加光源"))
{
//Light light = new Light();
//创建物体
GameObject lightGo = new GameObject();
//添加组件
Light light = lightGo.AddComponent<Light>();
light.color = Color.red;
light.type = LightType.Point;
}
//在场景中根据名称查找物体(慎用)
//GameObject.Find("游戏对象名称");
//获取所有使用该标签的物体
//GameObject[] allEnemy = GameObject.FindGameObjectsWithTag("enemy");
//获取使用该标签的物体(单个)
GameObject playGo = GameObject.FindWithTag("player");
//练习:查找血量最低的敌人
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 寻找血量最低的敌人
/// </summary>
public class FindBleedLess : MonoBehaviour
{
private void OnGUI()
{
if(GUILayout.Button("查找血量最低的敌人"))
{
//查找场景中所有Ememy类型的引用
Enemy[] allEnemy = Object.FindObjectsOfType<Enemy>();
//获取血量最低的对象引用
Enemy min = FindEnemyByMinHP(allEnemy);
//根据Enemy引用获取其他组件类型引用
min.GetComponent<MeshRenderer>().material.color = Color.red;
}
}
//自己的方法
public static Transform BleedLess(Transform current)
{
float BleedLess = current.GetChild(0).GetComponent<Enemy>().HP;
int count=0;
for (int i = 1; i < current.childCount; i++)
{
if (current.GetChild(i).GetComponent<Enemy>().HP < BleedLess)
{
BleedLess = current.GetChild(i).GetComponent<Enemy>().HP;
count = i;
}
}
return current.GetChild(count);
}
//参考答案
public Enemy FindEnemyByMinHP(Enemy[] allEnemy)
{
//假设第一个人就是血量最低的敌人
Enemy min = allEnemy[0];
//依次查找
for (int i = 1; i < allEnemy.Length; i++)
{
if (min.HP > allEnemy[i].HP)
min = allEnemy[i];
}
return min;
}
}
4、Object
Object类提供了按类型查找对象、销毁对象的功能。
- 常用属性
name… - 常用方法
Instantiate、Destroy、FindObjectOfType、FindObjectsOfType…
5、Time
- 从Unity获取时间信息的接口
- 常用属性
time:从游戏开始到现在所用时间。
timeScale:时间缩放。
deltaTime:以秒计算,表示每帧的经过时间。
unscaledDeltaTime:不受缩放影响的每帧经过时间。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
///
/// </summary>
public class TimeDemo : MonoBehaviour
{
public float a, b, c;
//渲染场景时执行,不受TimeScale影响
public void Update()
{
a = Time.time;//受缩放影响的游戏运行时间
b = Time.unscaledTime;//不受缩放影响的游戏运行时间
c = Time.realtimeSinceStartup;//实际游戏运行时间
//每渲染帧执行1次,旋转1度
//1秒旋转?度
//帧多 1秒旋转速度快 希望1帧旋转角度小 (Time.deltaTime)
// 少 慢 大
//this.transform.Rotate(0, 100*Time.deltaTime, 0);
//旋转速度*每帧消耗时间,可以保证旋转/移动速度不受渲染影响
//个别物体不受影响,Time.unscaledDeltaTime 不受缩放影响的每帧间隔
this.transform.Rotate(0, 100 * Time.unscaledDeltaTime, 0);
}
//固定0.02秒执行一次,与渲染无关,执行受TimeScale影响
public void FixedUpdate()
{
//this.transform.Rotate(0, 1, 0);
}
//游戏暂停 个别物体不受影响
public void OnGUI()
{
if(GUILayout.Button("暂停游戏"))
{
Time.timeScale = 0;
}
if (GUILayout.Button("继续游戏"))
{
Time.timeScale = 1;
}
}
}
练习:倒计时
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
///
/// </summary>
public class TwoSecondDemo : MonoBehaviour
{
//需求:1秒修改一次Text文本内容
//1、查找组件引用 UnityEnigine.UI.Text
//2、定义变量:秒 int second =120;
//3、时间转换: 02:00 01:59
//Update中1秒修改一次
private Text textTime;
public int second = 120;
private float i=0;
private float nextTime = 1;//下次修改时间
public void Start()
{
textTime = this.GetComponent<Text>();
//重复调用(被执行的方法名称,第一次执行时间,每次执行间隔)
InvokeRepeating("Timer1", 1, 1);
//Invoke("被执行的方法名称",开始调用时间);
}
public void Update()
{
//Timer();
}
//方法一:Time.time
public void Timer()
{
#region 上课答案Time.time
if (Time.time >= nextTime)
{
second--;
textTime.text = string.Format("{0:d2}:{1:d2}", second / 60, second % 60); //格式函数
//设置下次修改时间
nextTime = Time.time + 1;
}
#endregion
}
//方法二:InvokeRepeating()
//每隔固定时间,重复执行
public void Timer1()
{
second--;
textTime.text = string.Format("{0:d2}:{1:d2}", second / 60, second % 60); //格式函数
//设置下次修改时间
if (second <= 0)
CancelInvoke("Timer1");
}
//方法三:Time.deltaTime
public void Timer2()
{
#region 自己的方法 Time.deltaTime
i += Time.deltaTime;
if (i >= 1)
{
second--;
if (second <= 10)
textTime.color = Color.red;
if (second == 0)
Time.timeScale = 0;
textTime.text = string.Format("{0:d2}:{1:d2}", second / 60, second % 60); //格式函数
i = 0;
}
#endregion
}
//5、如何每秒修改一次
//重点:在Update每帧执行的方法中,个别语句实现指定间隔执行一次。
//Time.time
}
二、预制件(Prefab)
- 一种资源类型,可以多次在场景进行实例。
- 优点:对预制件的修改,可以同步到所有实例,从而提高开发效率。
- 如果单独修改实例的属性值,则该值不在随预制件变化。
- Selcet键:通过预制件实例选择对应的预制件
- Revert键:放弃实例属性值,还原预制件属性值
- Apply键:将某一实例的修改应用到所有实例
三、动画(Animation)
1.Animation View
- 通过动画视图可以直接创建和修改动画片段(Animation Clips)。
- 显示动画试图:Window——Animation。
2.创建动画片段
- 为物体添加Animation组件
- 在动画试图中创建片段
3.录制动画片段
- 录制步骤:
1.添加关键帧Add Property,选择组件类型
2.点击录制按钮,开始录制动画
3.选择关键帧,调整时间点
4.在Scene或Inspector画板设置属性
5.点击录制按钮,结束录制动画
注意:录制动画时,时间线一定要拖到最后,否则默认为最开始,也就是倒着播放动画
- 任何组件以及材质的属性都可进行动画处理,即使是自定义脚本组件的公共变量。
4.时间线
- 可以点击时间线上的任意位置预览或修改动画片段。
- 数字显示为秒数和帧数。
例如:1:30表示1秒30帧 - 使用按钮跳到上一个或下一个关键帧,也可以键入特定数直接跳到该帧。
5.Animation组件属性
- 动画Animation:当前动画
- 动画列表Animations:可以从脚本访问的动画列表
- 自动播放Play Automatically:启动游戏时自动播放的动画
6.常用API函数
- bool isPlay = animation.isPlaying;
- bool isPlay = animation.IsPlaying(“动画名”);
- animation.Play(“动画名”);//立即播放
- animation.PlayQueued(“动画名”);//播放序列
- animation.CrossFade(“动画名”);//淡入淡出
- animation[“动画名”].speed = 5;
- animation[“动画名”].wrapMode = WrapMode.PingPong;
- animation[“动画名”].length;
- animation[“动画名”].time;