附加在游戏物体上用于定义游戏对象行为的指令代码(.cs文件)就是一个类
支持三种高级编程语言:c# 、JavaScript;
unity自带开发工具:MonoDevelop 支持多个集成开发环境;visual studio 主要用这个
更改模板:unity--属性--打开文件位置--data--tools64--resource--scripttemplates--81-C#.txt
using 命名空间;//避免类重名
public class 类名:MonoBehaviour
{
void 方法名(){
Debug.Log("调试显示信息");
print(“本质就是Debug.Log方法”);
}
}
文件名和类名一致;写好的脚本必须附加到物体上才执行;附加到游戏物体的脚本类必须从MOnoBehavior类继承(实际上是,把类的实例对象交给了gameobject)
编译过程:源代码--CLS--中间语言(dll)--Mono Runtime--机器码
必然事件、消息:当满足某种条件unity自动调用的函数
搜索:unity5圣典--monobehaviour / un11ity组件旁边的小书
三个问题:名字 时机 适用性
初始阶段:Awake(物体载入立即调用;常用于游戏开始前进行初始化,可以判断当满足某种条件执行此脚本 this.enble=true) OnEnable(脚本启用就执行) Start
物理阶段:FixedUpdate Update LateUpdate(延迟更新 在update函数被调用后执行 适用于跟随逻辑 实际操作差别不大)
输入事件:OnMouseDown(前提是物体有碰撞器组件)OnMouseEnter OnMouseOver OnMouseUp OnMouseExit
场景渲染:OnBecameVisible 当Mesh Renderer在任何摄像机上可见 OnBecameInVisible:都不可见
结束阶段:OnDestroy (当脚本或者游戏对象销毁) Ondisable(当对象不可用时激活 或者复数游戏对象非激活)OnApplicationQuit(当程序结束)
新建Lifecycle.cs文件,代码示例1:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
///
/// 脚本生命周期/必然事件/消息 Message
///
public class Lifecycle : MonoBehaviour
{
//C#:字段 属性 构造函数 方法
//脚本:字段 方法
public int a=100;//public的对象,在检查器中能显示,可快速更改数据 100是默认情况
//序列化字段 作用:在编辑器中显示私有变量
[SerializeField]
private int b = 100;//不希望被访问 但是希望检查器能看见
//在编译器中隐藏字段 可访问
[HideInInspector]
public int c = 100;
//在编译器中修改的时候有范围限制
[Range(0,100)]
public int d = 50;
//属性在检查器看不见,在脚本中一般不写
public int A
{
get
{
return this.a;
}
set
{
this.a = value;
}
}
//错误情况:不能在子线程中访问主线程成员
//不要在脚本中写构造函数
/*
public float e;
public Lifecycle()
{
e = Time.time;
Debug.Log("构造函数");//相当于writeline 运行时在控制台
}
*/
//**********************初始阶段***********************//
//执行时机:创建游戏对象 执行1次
//作用:初始化
private void Awake()
{
Debug.Log("Awake"+Time.time+"--"+this.name);//Awake0 表示0秒被执行
}
//所有物体的awake执行后再start 但是awake暂时不可以规定谁先
//执行时机:游戏物体创建 脚本启用后 执行1次
//作用:初始化
private void Start()
{
Debug.Log("Start" + Time.time + this.name);//先Awake再Start
}
//**********************物理阶段***********************//
//执行时机:每隔固定时间(0.02)执行(可以修改 不建议)
//适用性:适用于对对象进行物理操作(移动、旋转等) 不会受到渲染影响
//渲染时间不固定 (每帧渲染量不同、机器性能不同)
private void FixedUpdate()
{
Debug.Log("FixedUpdate" + Time.time + "--" + this.name);
}
//执行时机:渲染帧执行,执行间隔不固定
//适用性:处理游戏逻辑 按帧移动
private void Update()
{
}
private void OnMouseDown()
{
Debug.Log("OnMouseDown");
}
private void OnMouseEnter()
{
}
}
1.控制台调试:debug.log print(仅仅在脚本中可以直接使用)
控制台面板:清除 折叠 播放时清除(√) 创建时清空 错误暂停 editor 右边的小图标框也要选中
unity源代码查看:Resource--IL Spy.exe///Library--UnityAssemblies--UnityEngine.dll
/Library--ScriptAssemblies--Assembly-CSharp.dll(自己写了的所有脚本)
2.定义共有变量,程序运行后在检查器面板查看
3.vs:准备工作:安装vs201X工具(2019vs安装好unity部分就可以自动附加)右键--快速监视(或者即时窗口) 可以监视组件(this.transform);调试工作:在出错的行加断点 启动调试 在unity中play场景
单帧调试:启动调试 运行场景 暂停游戏 加断点 单帧执行 结束调试
核心类图
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
///
/// Component类提供了查找(在当前物体、后代、先辈)组件的功能
///
public class ComponentDemo : MonoBehaviour
{
// Start is called before the first frame update
private void OnGUI()
{
if(GUILayout.Button("transform"))
{
this.transform.position = new Vector3(0, 0, 10);
}
if (GUILayout.Button("GetComponent"))
{
this.GetComponent().material.color = Color.red;
}
if (GUILayout.Button("GetComponents"))
{
//获取当前物体所有组件
var allComponent=this.GetComponents();
foreach(var item in allComponent)
{
Debug.Log(item.GetType());
}
}
if (GUILayout.Button("GetComponentsInChildren"))
{
//从自身开始找后辈
//获取后代物体的指定类型组件
//GetComponentsInParent 找父母
var allComponent = this.GetComponentsInChildren();
foreach (var item in allComponent)
{
item.material.color=Color.red;
}
}
}
}
position:在世界坐标系里的位置
localposition:检查器中的position 相对的
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
///
/// Transform类提供了查找变换组件功能(查找父、根、子) 改变位置角度大小功能
///
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 当前物体的位置视为世界坐标
//this.transform.SetParent(tf, true);
//false 当前物体的位置视为localposition
this.transform.SetParent(tf,false);
}
if (GUILayout.Button("Find"))
{
Transform childTF = this.transform.Find("子物体名称");
//Transform childTF = this.transform.Find("子物体名称/子物体名称");
}
if(GUILayout.Button("childTF"))
{
int count = this.transform.childCount;
//根据索引获得子物体
for(int i = 0; i < count; i++)
{
this.transform.GetChild(i);
}
}
//解除子对象父子关系 DetachChildren
//不要这个爸爸了:setParent=null;
////////////////////////////////////////
//////////////////// 改变位置角度大小功能/////////////////////////
if (GUILayout.Button("pos/scale"))
{
//物体相对于世界坐标系原点的位置
//this.transform.position;
//物体相对于父物体轴心点的位置
//this.transform.localPosition;
//物体相对于父物体轴心点的位置 1 2 1 沿着y轴 是父物体的两倍
//this.transform.localScale;
//理解为:物体与模型缩放比例(自身缩放比例*父物体缩放比例)
//this.transform.LossyScale;
//比如:父物体localscale为3 当前物体localscale为2 lossyscale为6
//向自身坐标系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, 1);
//沿着世界坐标系z轴 旋转10度
this.transform.Rotate(0, 0, 1, Space.World);
}
if (GUILayout.RepeatButton("RotateAround"))
{
//绕零点y轴转1度
this.transform.RotateAround(Vector3.zero,Vector3.up,1);
//绕零点z轴转1度
this.transform.RotateAround(Vector3.zero, Vector3.forward, 1);
}
if (GUILayout.RepeatButton("RotateAround"))
{
//绕零点y轴转1度
this.transform.RotateAround(Vector3.zero, Vector3.up, 1);
//绕零点z轴转1度
this.transform.RotateAround(Vector3.zero, Vector3.forward, 1);
}
}
}
activeInHierarchy:实际上的激活状态
activeSelf:自身的激活状态
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameObjectDemo : MonoBehaviour
{
private void OnGUI()
{
//场景中物体激活状态
//this.gameObject.activeInHierarchy
//物体自身激活状态
//this.gameObject.activeSelf
//设置物体禁用启用
//this.gameObject.SetActive(true);
if (GUILayout.Button("添加光源"))
{
//创建物体
GameObject lightGo = new GameObject();
//添加组件
Light light= lightGo.gameObject.AddComponent();
light.color = Color.red;
light.type = LightType.Point;
}
//在场景中根据名称找物体(不建议使用)
//GameObject.Find("游戏名称");
//this.transform.Find("");//可以
//获取所有使用该标签的物体
GameObject[] allEnemy = GameObject.FindGameObjectsWithTag("");
//获取所有使用该标签的物体(单个)
GameObject playerGO = GameObject.FindWithTag("");
}
}
Destory:删除一个游戏对象、组件、资源
DontDestoryOnLoad:加载新场景的时候不删除
FindObjectOfType:根据类型找对象
//根据类型查找对象
Object.FindObjectOfType();
FindObjectsOfType();
//销毁对象
//Object.Destroy
代码示例2:查找血量最低的敌人
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Findenemy : MonoBehaviour
{
private void OnGUI()
{
if(GUILayout.Button("查找血量最低的敌人"))
{
//查找场景中所有Enemy类型的引用
Enemy[] allEnemy = Object.FindObjectsOfType();
//获取血量最低的引用
Enemy min = FindEnemyByMinHP(allEnemy);
//根据Enemy类型引用 获取 其他组件类型的引用
min.GetComponent().material.color = Color.red;
}
}
public Enemy FindEnemyByMinHP(Enemy[] allEnemy)
{
//假设第一个就是血量最低
Enemy min= allEnemy[0];
for(int i=0;i allEnemy[i].HP)
min = allEnemy[i];
}
return min;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
public int HP;
}
代码示例2:层级未知 查找子物体
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TransformHelper
{
///
/// 在层级未知情况下查找子物体
///
/// 父物体变换组件
/// 子物体名称
///
public static Transform AutoGetChild(Transform parentTF,string childName)
{
//在子物体中查找
Transform childTF= parentTF.Find(childName);
if (childTF != null) return childTF;
//将问题交由子物体
int count = parentTF.childCount;
for(int i = 0; i < count; i++)
{
childTF= AutoGetChild(parentTF.GetChild(i),childName);
if(childTF != null) return childTF;
}
return null;
}
}
private void OnGUI()
{
if (GUILayout.Button("查找血量最低的敌人 层级未知 查找子物体"))
{
var childTF= TransformHelper.AutoGetChild(this.transform, "Sphere (4)");
childTF.GetComponent().material.color = Color.yellow;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.SocialPlatforms;
public class TimeDemo : MonoBehaviour
{
public float t;
//Update不会受到timescale影响,Time.deltaTime会受到影响
public void Update()
{
t = Time.time; //受缩放影响的游戏运行时间
t = Time.deltaTime;//完成最后一帧的时间 一次渲染的时间
t = Time.unscaledDeltaTime;//不受缩放影响的游戏运行时间
t =Time.realtimeSinceStartup;//实际游戏运行时间
//每渲染帧 执行1次 旋转一度
//帧多 1s旋转速度很快 希望慢 希望一帧旋转量小(Time.deltaTime)
//帧少 慢
this.transform.Rotate(0, 0, 1);
//旋转速度*每帧消耗时间,可以保证旋转速度不受机器性能,以及渲染影响
this.transform.Rotate(0, 0, 1*Time.deltaTime,0);
}
public int speed = 200;
//固定0.02s执行一次,与渲染无关,可以不乘Time.deltaTime
//FixedUpdate会收timescale影响
public void FixedUpdate()
{
this.transform.Rotate(0, speed, 0);
}
private void OnGUI()
{
if(GUILayout.Button("暂停游戏"))
{
Time.timeScale = 0;
}
if (GUILayout.Button("继续游戏"))
{
Time.timeScale = 1;
}
}
//游戏暂停,个别物体不受影响:代码在update中;Time.deltaTime换成unscaledDeltaTime 不受缩放影响的每帧间隔
}
ui-text :挂在文本上的脚本:倒计时,两种方法
方法1 Time.time :如果到了某时间
方法2 Time.deltatime :如果按下左键 如果到了修改时间 比较适合子弹发射这种场合
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
///
/// 倒计时
///
public class CountDownTimer : MonoBehaviour
{
// Update is called once per frame
private Text txtTimer;
public int second = 120;
public float nextTime=1;//下次修改时间
private void Start()
{
txtTimer = this.GetComponent();
}
private void Update()
{
//需求:1s修改一次文本内容
//1.查找组件引用
//2.定义变量:秒second
//3.120--02.00
//4.修改文本
//5.如何每秒修改一次
if (Time.time>=nextTime)
{
second--;
txtTimer.text = string.Format("{0:d2}:{1:d2}", second / 60, second % 60);
if (second <= 10)
txtTimer.color = Color.red;
nextTime = Time.time + 1;//设置下次修改时间
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
///
/// 倒计时
///
public class CountDownTimer : MonoBehaviour
{
// Update is called once per frame
private Text txtTimer;
public int second = 120;
public float nextTime=1;//下次修改时间
private void Start()
{
txtTimer = this.GetComponent();
}
private void Update()
{
//Timer1();
Timer2();
}
private void Timer1()
{
//需求:1s修改一次文本内容
//1.查找组件引用
//2.定义变量:秒second
//3.120--02.00
//4.修改文本
//5.如何每秒修改一次
if (Time.time>=nextTime)
{
second--;
txtTimer.text = string.Format("{0:d2}:{1:d2}", second / 60, second % 60);
if (second <= 10)
txtTimer.color = Color.red;
nextTime = Time.time + 1;//设置下次修改时间
}
}
private float totalTime;
private void Timer2()
{
//累加每帧间隔
totalTime+=Time.deltaTime;
if(totalTime>=1)
{
second--;
txtTimer.text = string.Format("{0:d2}:{1:d2}", second / 60, second % 60);
if (second <= 10)
txtTimer.color = Color.red;
totalTime = 0;
}
}
}
start中方法重复使用:
方法三invoke
InvokeRepeating("Timer1", 1, 1);//方法名,开始时间,间隔时间
//Invoke(被执行的方法,开始调用时间);
取消所有某方法的执行:
if (second < 0)
{
CancelInvoke("Timer1");
}
将层级中的游戏对象保存到项目中以便下次使用:直接拖给项目
对预制件修改可以同步到所有实例
如果单独修改某实例 则该值不再随预制件变化
select:通过预制件实例选择对应预制件
revert:放弃实例属性值,还原预制件属性值
apply:将某一实例的修改应用到所有实例
动画视图中直接创建和修改动画片段 :windows--animation
创建动画片段:为物体添加Animation组件 在动画视图中创建片段
添加属性->设置动画(具体操作跟AE相似)-->将片段拖动给对象的组件
时间线:60帧1s,使用按钮上下跳帧
动画播放模式:default once(点一次做一次) loop(循环的) pingpong(从头到尾从尾到头) clamp forever(从头播放到尾一直播放最后一帧)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
///
/// 门
///
public class Door : MonoBehaviour
{
public bool doorState = false;
private Animation anim;
public string animName = "Door";
private void Start()
{
anim = GetComponent();
}
private void OnMouseDown()
{
//关门操作1--->0
if(doorState)
{
//当动画正在播放的时候不要重置
if (anim.isPlaying == false)
{
//从最后开始
anim[animName].time = anim[animName].length;
}
anim[animName].speed = -1;//逆着播放
}
else
//开门操作0--->1
{
anim[animName].speed = 1;//正着播放
}
//播放动画
anim.Play(animName);
doorState = !doorState;
}
}