1.生命周期函数
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class lesson1 : MonoBehaviour
{
#region 了解帧的概念
//Unity 底层已经帮助我们做好了死循环
//我们需要学习Unity的生命周期函数
//利用它做好的规则来执行我们的游戏逻辑就行了
#endregion
#region 生命周期函数的概念
//所有继承 MonoBehaviour 的脚本 最终都会挂载到GameObject游戏对象上
//生命周期函数 就是该脚本对象依附的GameObject对象从出生到消亡整个生命周期中
//会通过反射自动调用的一些特殊函数
//Unity帮助我们记录了一个GameObject对象依附了哪些脚本
//会自动的得到这些对象,通过反射去执行一些固定名字的函数
#endregion
#region 生命周期函数
//注意:
//生命周期函数的访问修饰符一般为 private和 protected
//因为不需要在外部自己调用生命周期函数 都是 Unity 自己帮助我们调用的
//当对象(自己这个类对象) 被创建时 才会调用该生命周期函数
private void Awake()
{
//在Unity中打印信息的两种方式
//1.没有继承MonoBehaviour类的时候
//Debug.Log("123");
//Debug.LogError("出错了!!!");
//Debug.LogWarning("警告!!!");
//2.继承了MonoBehaviour 有一个线程的方法 可以使用
print("Awake");
}
//对于我们来说 想要当一个对象被激活时 进行一些逻辑处理 就可以写在这个函数
private void OnEnable()
{
print("OnEable");
}
//主要作用还是用于初始化信息的 但是它相对于Awake来说 要晚一点
//因为它是在对象 进行第一次帧更新之前才会执行的
private void Start()
{
print("Strart");
}
//它主要是用于 进行物理更新
//它是每一帧的执行的 但是 这里的帧 和游戏帧 有点不同
//它的时间间隔 是可以在 protect setting中的 Time里去设置的
private void FixedUpdate()
{
print("FixedUpdate");
}
//主要用于处理游戏核心逻辑更新的函数
private void Update()
{
print("Update");
}
//一般这个更新是用来处理 摄像机位置更新相关内容的
//Update 和 LateUpdate 之间 Unity 进行了一些处理 处理我们动画相关的更新
private void LateUpdate()
{
print("LateUpdate");
}
//如果我们希望在一个对象失活时做一些处理 就可以在该函数中写逻辑
private void OnDisable()
{
print("OnDisable");
}
private void OnDestroy()
{
print("OnDestroy");
}
#endregion
#region 生命周期函数 支持继承多态
#endregion
}
//总结
//这些生命周期函数 如果你不打算在其中写逻辑 那就不要写出这些生命周期函数
//
2.inspector窗口可编辑的变量
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum E_TestEnum
{
Normal,
Player,
Monster
}
[System.Serializable]
public struct MyStruct
{
public int age;
public bool sex;
}
[System.Serializable]
public class MyClass
{
public int age;
public bool sex;
}
public class lesson2 : MonoBehaviour
{
#region Inspector显示的可编辑内容就是脚本的成员变量
#endregion
#region 私有和保护无法显示编辑
private int i1;
protected string str1;
#endregion
#region 让私有的和保护的也可以被显示
//加上强制序列化字段特性
//[SerializeField]
//所谓序列化就是把一个对象保存到一个文件或数据库字段中去
[SerializeField]
private int privateInt;
[SerializeField]
protected string protectedStr;
#endregion
#region 公共的可以显示编辑
[HideInInspector]
public int publicInt = 10;
public bool publicBool = false;
#endregion
#region 公共的也不让其显示编辑
//在变量前加上特性
//[HideInInspector]
[HideInInspector]
public int publicInt2 = 50;
#endregion
#region 大部分类型都能显示编辑
public int[] array;
public List<int> list;
public E_TestEnum type;
public GameObject gameObj;
//字典不能被Inspector窗口显示
public Dictionary<int, string> dic;
//自定义类型变量
public MyStruct myStruct;
public MyClass myClass;
#endregion
#region 让自定义类型可以被访问
//加上序列化特性
//[System.Serializable]
//字典怎样都不行
#endregion
#region 一些辅助特性
//1.分组说明特性 Header
//为成员分组
//Header 特性
//[Header("分组说明")]
[Header("基础属性")]
public int age;
public bool sex;
[Header("战斗属性")]
public int atk;
public int def;
//2.悬停注释 Tooltip
//为变量添加说明
//[Tooltip("说明内容")]
[Tooltip("闪避")]
public int miss;
//3.间隔特性 Spcae()
//让两个字段间出现间隔
//[Space()]
[Space()]
public int crit;
//4.修饰数值的滑条范围 Range
//[Range(最大值,最小值)]
[Range(0,10)]
public float luck;
//5.多行显示字符串 默认不写参数显示3行
//写参数就是对应行
//[Multiline(4)]
[Multiline()]
public string tips;
//6.滚动条显示字符串
//默认不写参数就是超过三行显示滚动条
//[TextArea(3,4)]
//最少显示3行,最多4行,超过四行就显示滚动条
[TextArea(3, 4)]
public string MyLife;
//7.为变量添加快捷方法 ContextMenuItem
//参数1 显示按钮名
//参数2 方法名 不能有参数
//[ContestMenuItem("显示按钮名","方法名")]
[ContextMenuItem("重置钱", "Test")]
public int money;
private void Test()
{
money = 0;
}
//8.为方法添加特性能够在Inspector中执行
//[ContextMenu("测试函数")]
[ContextMenu("哈哈哈")]
private void TestFun()
{
print("测试方法");
}
#endregion
#region 注意
//1.Inspector窗口中的变量关联的就是对象的成员变量,运行时改变他们就是在改成员变量
//2.拖曳到GameObject对象后 再改变脚本中变量默认值 界面上不会改变
//3.运行中修改的信息不会保存
#endregion
private void Start()
{
print(privateInt);
print(protectedStr);
}
}
3.Mono中的重要内容
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class lesson3 : MonoBehaviour
{
public lesson3 otherLesson3;
// Start is called before the first frame update
void Start()
{
#region 重要成员
//1.获取依附的GameObject
print(this.gameObject.name);
//2.获取依附的GameObject的位置信息
//得到对象位置信息
print(this.transform.position); //位置
print(this.transform.eulerAngles);//角度
print(this.transform.lossyScale); //缩放大小
//这种写法和上面都是一样的效果 都是得到依附的对象的位置信息
//this.gameObject.transform
//3.获取脚本是否激活
this.enabled = true; //激活
this.enabled = false;//失活
//获取别的脚本对象 衣服的gameObject和transform位置信息
print(otherLesson3.gameObject.name);
print(otherLesson3.transform.position);
#endregion
#region 重要方法
//得到依附对象上挂载的其他脚本
//1.得到自己挂载的单个脚本
//根据脚本名获取
lesson3_Test t=this.GetComponent("lesson3_Test") as lesson3_Test;
print(t);
//根据Type获取
t = this.GetComponent(typeof(lesson3_Test)) as lesson3_Test;
print(t);
//根据泛型获取 建议使用泛型获取 因为不用二次转换
t = this.GetComponent<lesson3_Test>();
if (t != null)
{
print(t);
}
//只要你能够得到场景中别的对象或者对象依附的脚本
//那你就可以获取到它的所有信息
//2.得到自己挂载的多个脚本
lesson3[] array = this.GetComponents<lesson3>();
print(array.Length);
List<lesson3> list = new List<lesson3>();
this.GetComponents<lesson3>(list);
print(list.Count);
//3.得到子对象挂载的脚本(它默认也会找自己身上是否挂载该脚本)
//函数是有一个参数的 默认不传 是false
//意思就是 如果子对象失活 是不会去找这个对象上是否有某个脚本
//如果传 true 即使失活 也会找
t = this.GetComponentInChildren<lesson3_Test>();
print(t);
//得子对象 挂载脚本 多个
lesson3_Test[] lts = this.GetComponentsInChildren<lesson3_Test>(true);
print(lts.Length);
List<lesson3_Test> list2 = new List<lesson3_Test>();
this.GetComponentsInChildren<lesson3_Test>(true, list2);
//4.得到父对象挂载的脚本(它默认也会找自己身上是否挂载了该脚本)
t = this.GetComponentInParent<lesson3_Test>();
print(t);
lts = this.GetComponentsInParent<lesson3_Test>();
print(lts.Length);
//它也有list的 和上面相同的套路
//5.尝试获取脚本
lesson3_Test l3t;
//提供了一个更加安全的 获取单个脚本的方法 如果得到了 会返回true
//然后再来进行逻辑处理即可
if (this.TryGetComponent<lesson3_Test>(out l3t))
{
//逻辑处理
}
#endregion
}
// Update is called once per frame
void Update()
{
}
}
4.最小单位GameObject
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class lesson4 : MonoBehaviour
{
//准备用来克隆的对象
//1.直接是场景上的某个对象
//2.可以是一个预设体对象
public GameObject myObj;
public GameObject myObj2;
// Start is called before the first frame update
void Start()
{
#region GameObject中的成员变量
//名字
print(this.gameObject.name);
this.gameObject.name = "Lesson4改名";
print(this.gameObject.name);
//是否激活
print(this.gameObject.activeSelf);
//是否是静态
print(this.gameObject.isStatic);
//层级
print(this.gameObject.layer);
//标签
print(this.gameObject.tag);
//transform
//this.transform 上一节课讲解的 通过Mono去得到的依附对象的GameObject的位置信息
//他们得到的信息是一样的 都是依附的GameObject的位置信息
print(this.gameObject.transform.position);
#endregion
#region GameObject中的静态方法
//创建自带几何体
//只要得到了一个GmeObject对象 我就可以得到它身上挂载的任何脚本信息
//通过obj.GetComponent来得取
GameObject obj=GameObject.CreatePrimitive(PrimitiveType.Cube);
obj.name = "立方体";
//查找对象相关的知识
//两种找单个对象的相同点
//1.无法找到失活的对象
// 只能找到激活的对象
//2.如果场景中 存在多个满足条件的对象
// 我们无法准确确定找到的是谁
//1.查找单个对象
//通过对象名查找
//这个查找效率比较低下 因为他会在场景中的所有对象去查找
//没有找到 就会返回null
GameObject obj2 = GameObject.Find("立方体");
if (obj2 != null)
{
print(obj2.name);
}
//通过tag来查找对象
//GameObject obj3 = GameObject.FindWithTag("Player");
//该方法和上面这个方法 效果一样 只是名字不一样而已
GameObject obj3 = GameObject.FindGameObjectWithTag("Player");
if (obj3 != null)
{
print("根据tag找的对象" + obj3.name);
}
else
{
print("根据tag没有找到对应对象");
}
//得到某一个单个对象 目前有两种方式了
//1.是 public 从外部面板拖 进行关联
//2.通过API去找
//2.查找多个对象
//找多个对象的API 只能是通过tag去找多个 通过名字 是没有找多个的方法的
//通过tag找到多个对象
//它也是 只能找到 激活对象 无法找到失活对象
GameObject[] objs = GameObject.FindGameObjectsWithTag("Player");
print("找到tag为Player对象的个数" + objs.Length);
//还有几个查找对象相关是用的比较少的方法 是GameObject父类 Object提供的方法
//引出额外知识点 Unity中的Object和C#中的万物之父的区别
//Unity里面的Object 不是指的万物之父object
//Unity里的Object 命名空间在UnityEngine中的 Object类 也是集成万物之父的一个自定义类
//C#中的Object 命名空间是在System中的
//它可以找到场景中挂载的某一个脚本对象
//效率更低 上面的GameObject.Find和通过FindWithTag找 只是遍历对象
//这个方法 不仅要遍历对象 还要遍历对象上挂载的脚本
lesson4 o= GameObject.FindObjectOfType<lesson4>();
print(o.gameObject.name);
//实例化对象(克隆对象)的方法
//实例化(克隆)对象 它的作用 是根据一个GameObject对象 创建出一个和它一模一样的对象
GameObject obj5= GameObject.Instantiate(myObj);
//以后学了更多知识点 就可以在这操作obj5
//如果你继承了 MonoBehavior 其实可以不用写GameObject一样可以使用
//因为 这个方法是Unity里面的 Object基类提供给我们的 所有可以直接使用
//Instantiate(myObj);
//删除对象的方法
GameObject.Destroy(myObj2);
//第二个参数 代表延迟多少秒就会删除
GameObject.Destroy(obj5, 5);
//Destroy 不仅可以删除对象 还可以删除脚本
//GameObject.Destroy(this);
//删除对象有两种作用
//1.是删除指定的一个游戏对象
//2.是删除一个指定的脚本对象
//注意:这个Destroy方法 不会马上移除对象 只是给这个对象jail一个移除标识
// 一般情况下 它会在下一帧时吧这个对象移除并从内存中移除
//如果没有特殊需求 就是一定要马上移除一个对象的话
//建议使用上面的 Destroy方法 因为是异步的 降低卡顿的几率
//下面这个方法 就是立即把对象 从内存中移除了
GameObject.DestroyImmediate(myObj);
//如果是继承MonoBehavior的类 不用写GameObject
//Destroy(myObj);
//DestroyImmediate(myObj);
//过场景不移除
//默认情况 在切换场景时 场景中对象都会被自动删除掉
//如果你希望某个对象 过场景不被移除
//下面这句代码 就是不想谁过场景被移除 就传谁
//一般都是传 依附的GameObject对
//比如下面这句代码的意思 就是自己依附的GameObject对象 过场景不被删除
GameObject.DontDestroyOnLoad(this.gameObject);
//如果继承MonoBehavior也可以直接写
//DontDestroyOnLoad(this.gameObject);
#endregion
#region GameObject中的成员方法
//创建空物体
//new一个GameObject就是在创建一个空物体
GameObject obj6 = new GameObject();
GameObject obj7 = new GameObject("空物体");
GameObject obj8 = new GameObject("加脚本的空物体",typeof(lesson2),typeof(lesson1));
//为对象添加脚本
//继承MonoBehavior的脚本 是不能够去new
//如果想要动态的添加继承MonoBehavior的脚本 在某一个对象上
//直接使用GameObject提供的方法即可
lesson1 lesson1 = obj6.AddComponent(typeof(lesson1)) as lesson1;
//用泛型更方便
lesson2 lesson2 = obj6.AddComponent<lesson2>();
//通过返回值 可以得到加入的脚本信息
//来进行一些处理
//得到脚本的成员方法 和继承Mono的类得到脚本的方法一模一样
//标签比较
//下面两种比较的方法 是一样的
if (this.gameObject.CompareTag("Player"))
{
print("对象的标签是Player");
}
if (this.gameObject.tag == "Player")
{
print("对象的标签是Player");
}
//设置激活失活
//false失活
//true激活
obj6.SetActive(false);
obj7.SetActive(false);
obj8.SetActive(false);
//次要的成员方法 了解即可 不建议使用
//强调
//下面讲的方法 都不建议大家使用 效率比较低
//通过广播或者发送消息的形式 让自己或者别人 执行某些行为方法
//通知自己 执行上面行为
//命令自己 去执行这个TestFun这个函数 会在自己身上挂载的所有脚本去找这个名字的函数
//它会去找到 自己身上所有的脚本 有这个名字的函数去执行
this.gameObject.SendMessage("TestFun");
this.gameObject.SendMessage("TestFun2",199);
//广播行为 让自己和自己的子对象执行
//this.gameObject.BroadcastMessage("函数名");
//向父对象和自己发送消息 并执行
//this.gameObject.SendMessageUpwards("函数名");
#endregion
}
void TestFun()
{
print("Lesson4d TestFun");
}
void TestFun2(int a)
{
print("Lesson4的TestFun2" + a);
}
// Update is called once per frame
void Update()
{
}
//总结
//GameObject的常用内容
//基本成员变量
//名字 失活激活状态 标签 层级 等等
//静态方法相关
//创建自带几何体
//查找场景中对象
//实例化对象
//删除对象
//过场景不移除
//成员方法
//为对象 动态添加指定脚本
//设置失活激活的状态
//和MonoBehavior中相同的 得到脚本相关的方法
}
5.时间相关Time
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class lesson5 : MonoBehaviour
{
void Update()
{
#region Time相关内容主要用来干啥
//时间相关内容 主要 用于游戏中参与唯一、计时、时间暂停等
#endregion
#region 时间缩放比例
//时间停止
//Time.timeScale = 0;
//恢复正常
//Time.timeScale = 1;
//2倍速
//Time.timeScale = 2;
#endregion
#region 帧间隔时间
//帧间隔时间 主要是用来计算位移
//路程=时间*速度
//根据需求选择参与计算的间隔时间
//如果希望 游戏暂停时就不动的 那就使用 deltaTime
//如果希望 不受暂停影响 unscaledDeltaTime
//帧间隔时间:最近的一帧 用了多少时间(秒)
//受scale影响
print("帧间隔时间:"+Time.deltaTime);
//不受scale影响的帧间隔时间
print("不受scale影响的帧间隔时间:" + Time.unscaledDeltaTime);
#endregion
#region 游戏开始到现在的时间
//它主要用来计时 单机游戏中计时
//受scale影响
print("游戏开始到现在的时间"+Time.time);
//不受scale影响
print("不受scale影响的游戏开始到现在的时间" + Time.unscaledTime);
#endregion
#region 帧数
//从开始到现在游戏跑了多少帧(次循环)
print(Time.frameCount);
#endregion
}
private void FixedUpdate()
{
#region 物理帧间隔时间 FixedUpdate
//受scale影响
print(Time.fixedDeltaTime);
//不受scale影响
print(Time.fixedUnscaledDeltaTime);
#endregion
}
//总结
//Time相关的内容
//最常用的 就是我们的
//1.帧间隔时间 就用来计算位移相关内容
//2.时间缩放比例 用来暂停 或者倍速等等
//3.帧数(帧同步)
}
6.位置和位移
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class lesson6 : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
#region Transform主要用来干嘛?
//游戏对象(GameObject)位移、旋转、缩放、父子关系、坐标转换等相关操作都由它处理
//它是Unity提供的极其重要的类
#endregion
#region 必备知识点 Vector3基础
//Vector3主要是用来表示三维坐标系中的 一个点 或者一个向量
//申明
Vector3 v = new Vector3();
v.x = 10;
v.y = 10;
v.z = 10;
//只传x y 默认z是0
Vector3 v2 = new Vector3(10, 10);
//一步到位
Vector3 v3 = new Vector3(10, 10, 10);
Vector3 v4;
v4.x = 10;
v4.y = 10;
v4.z = 10;
//Vector3的基本运算
//+ - * /
Vector3 v1 = new Vector3(1, 1, 1);
Vector3 v12 = new Vector3(2, 2, 2);
//对应用x+或者-x……
print(v1 + v12);
print(v1 - v12);
print(v1 * 10);
print(v12 / 2);
//常用
print(Vector3.zero);//0,0,0
print(Vector3.right);//1,0,0
print(Vector3.left);//-1,0,0
print(Vector3.forward);//0,0,1
print(Vector3.back);//0,0,-1
print(Vector3.up);//0,1,0
print(Vector3.down);//0,-1,0
//常用的一个方法
//计算两个点之间的距离的方法
print(Vector3.Distance(v1, v12));
#endregion
#region 位置
//相对世界坐标系
//this.gameObject.transform
//通过position得到的位置 是相对于 世界坐标系的 原点的位置
//可能和面板上显示的 是不一样的
//因为如果对象有父子关系 并且父对象位置 不在原点 那么 和面板上肯定就是不一样的
print(this.transform.position);
//相对父对象
//这两个坐标 对于我们来说 很重要 如果你想以面板坐标为准来进行坐标设置
//那一定是通过LocalPosition来进行设置的
print(this.transform.localPosition);
//他们两个 可能出现是一样的情况
//1.父对象的坐标 就是世界坐标系原点0,0,0
//2.对象没有父对象
//注意:位置的赋值不能直接改变x,y,z 只能整体改变
//不能单独改x y z某一个值
this.transform.position = new Vector3(10, 10, 10);
this.transform.localPosition = Vector3.up * 10;
//如果只想改一个值 其他值要保持原有坐标一致
//1.直接赋值
this.transform.position = new Vector3(19, this.transform.position.y, this.transform.position.z);
//2.先取出来 再赋值
Vector3 vPos = this.transform.localPosition;
vPos.x = 10;
this.transform.localPosition = vPos;
//如果你想得到对象当前的 一个朝向
//那么就是通过 Transform .出来的
//对象当前的各朝向
//对象当前的面朝向
print(this.transform.forward);
//对象当前的头顶朝向
print(this.transform.up);
//对象当前的右手边
print(this.transform.right);
#endregion
}
// Update is called once per frame
void Update()
{
#region 位移
//理解坐标系下的位移计算公式
//路程 = 方向*速度*时间
//方式一 自己计算
//想要变化的 就是 position
//用当前的位置 + 我要动多长距离 得出最终所在的位置
//this.transform.position = this.transform.position + this.transform.forward * 1 * Time.deltaTime;
//因为我用的是 this.transform.forward 所以他始终会朝向相对于自己的面朝向去动
//this.transform.position+= this.transform.forward * 1 * Time.deltaTime;
//方向非常重要 因为 它决定了你的前进方向
//this.transform.position += Vector3.forward * 1 * Time.deltaTime;
//方式二 API
//参数一:表示位移多少 路程 = 方向*速度*时间
//参数二:表示 相对坐标系 默认 该参数 是相对于自己坐标系的
//1.相对于世界坐标系的 z轴 动 始终是朝 世界坐标系的 z轴正方向移动
//this.transform.Translate(Vector3.forward * 1 * Time.deltaTime,Space.World);
//2.相对于世界坐标的 自己的面朝向去动 始终朝自己的面朝向移动
//this.transform.Translate(this.transform.forward * 1 * Time.deltaTime, Space.World);
//3.相对于自己的坐标系 下的 自己的面朝向向量移动(一定不会这样让物体移动)XXXXXXX
//this.transform.Translate(this.transform.forward * 1 * Time.deltaTime, Space.Self);
//4.相对于自己的坐标系 下的 z轴正方向移动 始终朝自己的面朝向移动
//this.transform.Translate(Vector3.forward * 1 * Time.deltaTime, Space.Self);
//注意:一般使用API来进行位移
#endregion
}
//总结
//Vector3
//如何申明 提供的 常用静态属性 和一个 计算距离的方法
//位置
//相对于世界坐标系 和 相对于父对象 这两个坐标的区别
//不能够 单独修改 xyz 只能一起统一改
//位移
//自己如何计算来进行位移
//API是哪个方法 来进行位移 使用时要注意
}
7.角度和旋转
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class lesson7 : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
#region 角度相关
//相对世界坐标角度
print(this.transform.eulerAngles);//欧拉角
//相对父对象角度
print(this.transform.localEulerAngles);
//注意:设置角度和设置位置一样 不能单独设置xyz 要一起设置
//this.transform.localEulerAngles = new Vector3(10, 10, 10);
//如果我们希望改变的 角度 是面板上显示的内容 那一点是改变 相对父对象的角度
//this.transform.eulerAngles = new Vector3(10, 10, 10);
print(this.transform.localEulerAngles);
#endregion
}
// Update is called once per frame
void Update()
{
#region 旋转相关
//自己计算(省略不讲了 和位置一样 不停改变角度即可)
//API计算
//自转
//第一个参数 相当于是旋转的角度 每一帧
//第二个参数 默认不填 就会相对于自己坐标系 进行旋转
//this.transform.Rotate(new Vector3(0, 10, 0) * Time.deltaTime);
//this.transform.Rotate(new Vector3(0, 10, 0) * Time.deltaTime,Space.World);
//相对于某个轴 转多少度
//参数一:是相对哪个轴进行转动
//参数二:是转动的 角度 是多少
//参数三:默认不填 就是相对于自己的坐标系 进行旋转
// 如果填 可以填相对于 世界坐标系进行旋转
//this.transform.Rotate(Vector3.up, 10 * Time.deltaTime);
//this.transform.Rotate(Vector3.up, 10 * Time.deltaTime,Space.World);
//相对于某一个点转
//参数一:相当于哪一个点 转圈圈
//参数二:相对于哪一个点 的哪一个轴转圈圈
//参数三:转的度数 旋转速度*时间
this.transform.RotateAround(Vector3.zero, Vector3.up, 10 * Time.deltaTime);
#endregion
}
//总结
//角度相关和位置相关 差不多
//如何得到角度
//通过transform 可以得到相对于世界坐标系和相对于父对象的
//如何自传和绕着别人转
//Rotate
//RotateAround
}
8.缩放和看向
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class lesson8 : MonoBehaviour
{
public Transform lookAtObj;
// Start is called before the first frame update
void Start()
{
#region 缩放
//相对世界坐标系
print(this.transform.lossyScale);
//相对本地坐标系(父对象)
print(this.transform.localScale);
//注意:
//1.同样缩放不能只改xyz 只能一起改
//所以 我们一般要修改缩放大小 都是改的相对于父对象的缩放大小 localScale
//this.transform.localScale = new Vector3(3, 3, 3);
#endregion
}
// Update is called once per frame
void Update()
{
//2.Unity没有提供关于缩放的API
//之前的 旋转 位移 都提供了相应的 API 但是缩放没有
//如果你想要 让缩放发生变化 只能自己去写(自己算)
//this.transform.localScale += Vector3.one * Time.deltaTime;
#region 看向
//让一个对象的面朝向 可以一直看向某一个点或者某一个对象
//看向一个点 相对于世界坐标系的
//this.transform.LookAt(Vector3.zero);
//看向一个对象 就传入一个对象的 Transform信息
this.transform.LookAt(lookAtObj);
#endregion
}
//总结
//缩放相关
//相对于 世界坐标系的缩放 只能得 不能改
//只能去修改相对于本地坐标系的缩放(相对于父对象)
//没有提供相对应的API来 缩放变化 只能自己算
//看向
//LookAt 看向一个点 或者一个对象
//一定记住 是写在Update里面 才会不停变化
}
9.父子关系
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class lesson9 : MonoBehaviour
{
public Transform son;
// Start is called before the first frame update
void Start()
{
#region 获取和设置父对象
//获取父对象
//print(this.transform.parent.name);
//设置父对象 断绝父子关系
//this.transform.parent = null;
//设置父对象 认父亲
//this.transform.parent = GameObject.Find("Father2").transform;
//通过API来进行父子关系的设置
//this.transform.SetParent(null);//断绝父子关系
//this.transform.SetParent(GameObject.Find("Fther2").transform);//认父亲
//参数一:父亲
//参数二:是否保留世界坐标的 位置 角度 缩放 信息
// true 会保留 世界坐标下的状态 和 父对象 进行计算 得到本地坐标系的信息
// false 不会保留 会直接吧世界坐标系下的 位置角度缩放 直接赋值到 本地坐标系下
//this.transform.SetParent(GameObject.Find("Fther3").transform,true);
#endregion
#region 抛妻弃子
//就是和自己所有的儿子 断绝关系 没有父子关系了
//只断绝自己和儿子的关系 儿子和孙子的关系不变
this.transform.DetachChildren();
#endregion
#region 获取子对象
//按名字查找儿子
//找到儿子的 transform信息
//Find方法 是能够找到 失活的对象的!!!GameObject相关的 查找 是不能找到失活对象的
print(this.transform.Find("Cube(1)").name);
//它只能找到自己的儿子 找不到自己的孙子!!!
print(this.transform.Find("GameObject").name);
//虽然它的效率 比GameObject.Find相关 要高一些 但是 前提是你必须知道父亲是谁 才能找到
//遍历儿子
//如何得到有多少个儿子
//1.失活的儿子也会算数量
//2.找不到孙子 所有孙子不会算数量
print(this.transform.childCount);
//通过索引号 去得到自己对应的儿子
//如果编号 超出了儿子的数量的范围 那会直接报错的
//返回值 是 transform 可以得到对应儿子的 位置相关信息
this.transform.GetChild(0);
for (int i = 0; i < this.transform.childCount; i++)
{
print("儿子的名字" + this.transform.GetChild(i).name);
}
#endregion
#region 儿子的操作
//判断自己的爸爸是谁
//一个对象 判断自己是不是另一个对象的儿子
if (son.IsChildOf(this.transform))
{
print("是我的儿子");
}
//得到自己作为儿子的编号
print(son.GetSiblingIndex());
//把自己设置为第一个儿子
son.SetAsFirstSibling();
//把自己设置为最后一个儿子
son.SetAsLastSibling();
//把自己设置为指定个儿子
//就算填的数量 超出了范围(负数或者更大的数) 不会报错 会直接设置成最后一个编号
son.SetSiblingIndex(1);
#endregion
}
// Update is called once per frame
void Update()
{
}
//总结
//设置父对象相关的内容
//获取子对象
//抛妻弃子
//儿子的操作
}
10.坐标转换
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class lesson10 : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
#region 世界坐标转本地坐标
print(Vector3.forward);
//世界坐标系 转本地坐标系 可以帮助我们大概判断一个相对位置
//世界坐标系的点 转换为 相对本地坐标系的点
//受到缩放影响
print("转换后的点"+ this.transform.InverseTransformPoint(Vector3.forward));
//世界坐标系的方向 转换为 相对本地坐标系的方向
//不受缩放影响
print("转换后的方向" +this.transform.InverseTransformDirection(Vector3.forward));
//受缩放影响
print("转换后的方向(受缩放影响)" + this.transform.InverseTransformVector(Vector3.forward));
#endregion
#region 本地坐标转世界坐标
//本地坐标系的点 转换为 相对世界坐标系的点 受到缩放影响
print("本地 转 世界 点"+this.transform.TransformPoint(Vector3.forward));
//本地坐标系的方向 转换为 相对世界坐标系的方向
//不受缩放影响
print("本地 转 世界 点" + this.transform.TransformDirection(Vector3.forward));
//受缩放影响
print("本地 转 世界 点" + this.transform.TransformVector(Vector3.forward));
#endregion
}
// Update is called once per frame
void Update()
{
}
//总结
//其中最重要的 就算 本地坐标系的点 转世界坐标系的点
//比如 现在玩家要在自己面前的n个单位前 放一团火 这时候 我不用关心世界坐标系
//通过 相对于本地坐标系的位置 转换为 世界坐标系的点 进行 特效的创建 或者 攻击范围的判断
}
11.输入相关Input
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class lesson11 : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
#region 注意:输入相关内容肯定是写在Update中的
#endregion
#region 鼠标在屏幕位置
//屏幕坐标的原点 是在 屏幕的左下角 往右是x轴正方向 往上是y轴正方向
//返回值是 Vector3 但是只有 x和y有值 z一直是0 是因为屏幕本来就是2D的 不存在z轴
//print(Input.mousePosition);
#endregion
#region 检测鼠标输入
//鼠标按下相关检测 对于我们来说
//比如:1.可以做 发射子弹
// 2.可以控制摄像机 转动
//鼠标按下一瞬间 进入
//0左键 1右键 2中键
//只有按下的这一瞬间 进入一次
//if (Input.GetMouseButtonDown(0))
//{
// print("鼠标左键按下了");
//}
//鼠标抬起一瞬间 进入
//if (Input.GetMouseButtonUp(0))
//{
// print("鼠标左键抬起了");
//}
//鼠标长按按下抬起都会进入
//当按住按键不放时 会一直进入 这个判断
//if (Input.GetMouseButton(1))
//{
// print("右键按下");
//}
//中键滚动
//返回值的 y -1往下滚 0没有滚 1往上滚
//它的返回值 是Vector的值 我们鼠标中键滚动 会改变其中的y值
//print(Input.mouseScrollDelta);
#endregion
#region 检测键盘输入
//比如说 按一个键释放一个技能或者切换武器 等等的操作
//键盘按下
//if (Input.GetKeyDown(KeyCode.W))
//{
// print("W键按下");
//}
//传入字符串的重载
//这里传入的 字符串 不能是大写的 不然会报错
//if (Input.GetKeyDown("q"))
//{
// print("Q键按下");
//}
//键盘抬起
//if (Input.GetKeyUp(KeyCode.W))
//{
// print("W键抬起");
//}
//键盘长按
//if (Input.GetKey(KeyCode.W))
//{
// print("长按W");
//}
#endregion
#region 检测默认轴输入
//我们学习鼠标 键盘输入 主要是用来
//控制玩家 比如 旋转 位移等等
//所以Unity提供了 更方便的方法 来帮助我们控制 对象的 位移和旋转
//键盘AD按下时 返回 -1到1之间的变换
//得到这个值 就是我们的 左右方向 我们可以通过它来控制 对象左右移动 或者左右旋转
//print(Input.GetAxis("Horizontal"));
//键盘SW按下时 返回 -1到1之间的变换
//得到这个值 就是我们的 上下方向 我们可以通过它来控制 对象上下移动 或者上下旋转
//print(Input.GetAxis("Vertical"));
//鼠标横向移动时 返回 -1到1之间的变换
//print(Input.GetAxis("Mouse X"));
//鼠标纵向移动时 返回 -1到1之间的变换
//print(Input.GetAxis("Mouse Y"));
//我们默认的 GetAxis方法 是有渐变的 会从 -1到1之间 渐变 会出现小数
// GetAxisRaw方法 和 GetAxis 使用方式相同
//只不过 它的返回值 只会是 -1 0 1 不会有中间值
#endregion
#region 其他
//是否有任意键或鼠标长按
if (Input.anyKey)
{
print("有一个键 长按");
}
//是否有任意键或鼠标按下
if (Input.anyKeyDown)
{
print("有一个键 按下");
//这一帧的键盘输入
print(Input.inputString);
}
//手柄输入相关
//得到连接的手柄的所有按钮名字
string[] strs = Input.GetJoystickNames();
//某一个手柄键按下
if (Input.GetButtonDown("Jump"))
{
}
//某一个手柄键抬起
if (Input.GetButtonUp("Jump"))
{
}
//某一个手柄键长按
if (Input.GetButton("Jump"))
{
}
//移动设备触摸相关
if (Input.touchCount > 0)
{
Touch t1 = Input.touches[0];
//位置
print(t1.position);
//相对上次位置的变化
print(t1.deltaPosition);
}
//是否启用多点触控
Input.multiTouchEnabled = false;
//陀螺仪(重力感应)
//是否开启陀螺仪 必须开启 才能正常使用
Input.gyro.enabled = true;
//重力加速度向量
print(Input.gyro.gravity);
//旋转速度
print(Input.gyro.rotationRate);
//陀螺仪 当前的旋转四元数
//比如 用这个角度信息 来控制 场景上的一个3D物体受到重力影响
//手机怎么动 它怎么动
print(Input.gyro.attitude);
#endregion
}
//总结
//Input类 提供大部分和输入相关的内容
//鼠标、键盘、触屏、手柄、重力感应
//对于我们目前来说
//鼠标、键盘 是必须掌握的核心知识
//今天必须记住 鼠标键盘输入相关的API
//GetAxis
}
12.屏幕相关Screen
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class lesson12 : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
#region 静态属性
#region 常用
//当前屏幕分辨率
Resolution r = Screen.currentResolution;
print("当前屏幕分辨率的宽" + r.width + "高" + r.height);
//屏幕窗口当前宽高
//这里得到的 是当前 窗口的 宽高 不是设备分辨率的宽高
//一般写代码 是要用窗口的宽高 做计算时 就用他们
print(Screen.width);
print(Screen.height);
//屏幕休眠模式
Screen.sleepTimeout = SleepTimeout.NeverSleep;
#endregion
#region 不常用
//运行时是否全屏模式
//Screen.fullScreen = true;
//窗口模式
//独占全屏 Screen.fullScreenMode = FullScreenMode.ExclusiveFullScreen;
//全屏窗口 Screen.fullScreenMode = FullScreenMode.FullScreenWindow;
//最大化窗口 Screen.fullScreenMode = FullScreenMode.MaximizedWindow;
//窗口模式 Screen.fullScreenMode = FullScreenMode.Windowed;
//移动设备屏幕转向相关
//允许自动旋转为左横向 Home键在左
//Screen.autorotateToLandscapeLeft = true;
//允许自动旋转为右横向 Home键在右
//Screen.autorotateToLandscapeRight = true;
//允许自动旋转为纵向 Home键在下
//Screen.autorotateToPortrait = true;
//允许自动旋转为纵向倒着看 Home键在上
//Screen.autorotateToPortraitUpsideDown = true;
//指定屏幕显示方向
//Screen.orientation = ScreenOrientation.Landscape;
#endregion
#endregion
#region 静态方法
//设置分辨率 一般移动设备不使用
//参数三:是否全屏
Screen.SetResolution(1920, 1080, false);
#endregion
}
// Update is called once per frame
void Update()
{
}
}
14.Camera代码相关
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class lesson14 : MonoBehaviour
{
public Transform obj;
// Start is called before the first frame update
void Start()
{
#region 重要静态成员
//1.获取摄像机
//如果用之前的知识 来获取摄像机
//主摄像机的获取
print(Camera.main.name);
//获取摄像机的数量
print(Camera.allCamerasCount);
//得到所有摄像机
Camera[] allCamrea = Camera.allCameras;
print(allCamrea.Length);
//2.渲染相关委托
//摄像机剔除前处理的委托函数
Camera.onPreCull += (c) =>
{
};
//摄像机 渲染前 处理的委托
Camera.onPreRender += (c) =>
{
};
//摄像机 渲染后 处理的委托
Camera.onPostRender += (c) =>
{
};
#endregion
#region 重要成员
//1.界面上的参数 都可以在Camera中获取到
//比如 下面这句代码 就是得到主摄像机对象 上的深度 进行设置
Camera.main.depth = 10;
//2.世界坐标转屏幕坐标
//转换过后 x和y对应的就是屏幕坐标 z对应的 是 这个3D物体 离我们的摄像机有多远
//我们会用这个来做的功能 最多的 就是头顶血条相关的功能
Vector3 v=Camera.main.WorldToScreenPoint(this.transform.position);
print(v);
#endregion
}
// Update is called once per frame
void Update()
{
//3.屏幕坐标转世界坐标
//之所以改变z轴 是因为 如果不改 z默认为0
//转换过去的世界坐标系的点 永远都是一个点 可以理解为 视口 相交的焦点
//如果改变了z 那么转换过去的 世界坐标的点 就是相对于 摄像机前方多少单位的横截面上的世界坐标点
Vector3 v = Input.mousePosition;
v.z = 10;
obj.position = Camera.main.ScreenToWorldPoint(v);
//print(Camera.main.ScreenToWorldPoint(v));
}
}
15.物理系统-碰撞检测
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class lesson16 : MonoBehaviour
{
#region 知识点回顾
//1.如何让两个游戏物体之间产生碰撞(至少一个刚体 和 两个碰撞器)
//2.如何让两个物体之间碰撞时表现出不同效果(物理材质)
//3.触发器的作用是什么(让两个物体碰撞没有物理效果,只进行碰撞处理)
#endregion
#region 注意:碰撞和触发响应函数 属于 特殊的生命周期函数 也是通过反射调用
#endregion
#region 物理碰撞检测响应函数
//碰撞触发接触时会 自动执行这个函数
private void OnCollisionEnter(Collision collision)
{
//Collision类型的 参数 包含了 碰到自己的对象的相关信息
//关键参数
//1.碰撞到的对象碰撞器的信息
//collision.collider
//2.碰撞对象的依附对象(GameObject)
//collision.gameObject
//3.碰撞对象的依附对象的位置信息
//collision.transform
//4.触碰点数相关
//collision.contactCount
//接触点 具体的坐标
//ContactPoint[] pos = collision.contacts;
//只要得到了 碰撞到的对象的 任意一个信息 就可以得到它所有的信息
print(this.name + "被" + collision.gameObject.name + "撞到了");
}
//碰撞结束分离时 会自动执行的函数
private void OnCollisionExit(Collision collision)
{
print(this.name + "被" + collision.gameObject.name + "结束碰撞了");
}
//两个物体相互接触摩擦时 会不停的调用该函数
private void OnCollisionStay(Collision collision)
{
print(this.name + "一直在和" + collision.gameObject.name + "接触");
}
#endregion
#region 触发器检测响应函数
//触发开始的函数 当第一次接触时 会自动调用
private void OnTriggerEnter(Collider other)
{
print(this.name + "被" + other.gameObject.name + "触发了");
}
//触发结束的函数 当水乳相融的状态结束的时 会调用一次
private void OnTriggerExit(Collider other)
{
print(this.name + "和" + other.gameObject.name + "结束水乳相融的状态了");
}
//当两个对象 水乳交融的时候 会不停调用
private void OnTriggerStay(Collider other)
{
print(this.name + "正在和" + other.gameObject.name + "水乳相融");
}
#endregion
#region 要明确什么时候会响应函数
//1.只要挂载的对象 能和别的物体产生碰撞或者触发 那么对应的这6个函数 就能够被响应
//2.6个函数不是说 我都得写 我们一般是根据需求来进行选择书写
//3.如果是一个异形物体,刚体在父对象上,如果你想通过子对象上挂脚本检测碰撞是不行的 必须挂载到这个刚体父对象上才行
//4.要明确 物理碰撞和触发器响应的区别
#endregion
#region 碰撞和触发器函数都可以写成虚函数 在子类去重写逻辑
//一般会把想要重写的 碰撞和触发函数 写成保护类型的 没有必要写成 public 因为不会自己手动调用
//都是Unity 通过反射帮助我们自动调用的
#endregion
}
16.物理系统-刚体加力
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class lesson17 : MonoBehaviour
{
Rigidbody rigidBody;
// Start is called before the first frame update
void Start()
{
#region 刚体自带添加力的方法
//给刚体加力的目标就是
//让其有一个速度 朝向某一个方向移动
//1.首先应该获取刚体组件
rigidBody = this.GetComponent<Rigidbody>();
//2.添加力
//相对世界坐标
//世界坐标系 z轴正方向加了一个力
//rigidBody.AddForce(Vector3.forward*10);
//如果想要在 世界坐标系方法中 让对象 相对于自己的面朝向动
//rigidBody.AddForce(this.transform.forward * 10);
//相对本地坐标
//本地坐标系 z轴正方向加了一个力
//rigidBody.AddRelativeForce(Vector3.forward * 10);
//3.添加扭矩力,让其旋转
//相对世界坐标
//世界坐标系 y轴正方向加了一个力
//rigidBody.AddTorque(Vector3.up * 10);
//相对本地坐标
//rigidBody.AddRelativeTorque(Vector3.up*10)
//4.直接改变速度
//这个速度方向 是相对于 世界坐标系
//如果要直接通过改变速度 来让其移动 一定要注意这一点
//rigidBody.velocity = Vector3.forward * 5;
//5.模拟爆炸的效果
//参数一:力的大小
//参数二:爆炸点
//参数三:力的范围
//模拟爆炸的力 一定是 所有希望产生爆炸效果影响的对象
//都需要得到他们的刚体 来执行这个方法 才能都有效果
//rigidBody.AddExplosionForce(100, Vector3.zero,10);
#endregion
#region 力的几种模式
//第二个参数 力的模式 主要的作用 就是 计算方式不同而已
//由于4种计算方式的不同 最终的移动速度就会不同
//rigidBody.AddForce(Vector3.forward * 10, ForceMode.Acceleration);
//动量定理
//Ft = mv
//v = Ft/m
//F:力
//t:时间
//m:质量
//v:速度
//1.Acceleration
//给物体增加一个持续的加速度,忽略其质量
//v = Ft/m
//F(0,0,10)
//t:0.02s
//m:默认为1
//v = 10*0.02/1 =0.2m/s
//每物理帧移动0.2m/s*0.02s=0.004m
//2.Force
//给物体添加一个持续的力,与物体的质量有关
//v = Ft/m
//F:(0,0,10)
//t:0.02s
//m:2kg
//v = 10*0.02s/2kg = 0.1m/s
//每物理帧移动 0.1m/s*0.02s = 0.002m
//3.Impulse
//给物体添加一个瞬间的力,与物体的质量有关,忽略时间 默认为1
//v = Ft/m
//F:(0,0,10)
//t:默认为1
//m:2kg
//v = 10*1/2kg = 5m/s
//每物理帧移动 5m/s*0.02s = 0.1m
//4.VelocityChange
//给物体添加一个瞬时速度,忽略时间、质量
//v = Ft/m
//F:(0,0,10)
//t:默认为1
//m:默认为1
//v = 10*1/1kg = 10m/s
//每物理帧移动 10m/s*0.02s = 0.2m
#endregion
#region 力场脚本
//Constant Force
//给物体一个持续的力
#endregion
}
// Update is called once per frame
void Update()
{
//如果你希望即使有阻力 也希望对象一直动 那你就一直推就行了
//rigidBody = this.GetComponent<Rigidbody>();
#region 刚体的休眠
//获取刚体是否处于休眠状态 如果是休眠状态就唤醒它
if (rigidBody.IsSleeping())
{
//唤醒
rigidBody.WakeUp();
}
#endregion
}
}
|