PlasticSCM:版本管理工具
工程目录结构
(主要)Assets:资源(存放场景、脚本、模型、素材) Assets中.meta文件为属性文件,标识文件id,方便unity管理 (主要)Library:系统的一些库 Logs:日志 Packages:导入的一些包 ProjectSettings:工程相关的设置。 Temp:临时的文件夹(可能放一些临时文件与缓存) UserSettings:也是编辑器设置相关的 SampleScene:游戏场景,通过create=》scene创建游戏场景 packages:包含了一些包和内置插件
unity编辑器的使用
game与Scene窗口可拖动,窗口布局可以通过Layers修改,一般使用Tall project:一般存放工程资源,这块可调整列数与图标大小,project与Assets文件夹是对应的,创建的C#脚本放在Assets文件夹中。
五个面板
Hierarchy: 层级面板,显示当前场景有哪些东西,层级可嵌套、切换。 inspector:检视面板,查看一个游戏物体由哪些“组件”组成。例如Transform、Mesh Renderer、Sphere、Collider这些都是一个组件。 gameObject:游戏物体,场景中的任何东西都叫一个游戏物体, scene:场景面板,用来显示与编辑当前场景。 game:点击运行按钮,当场景运行起来时,玩家看到的游戏场景样子。不可编辑
render:控制渲染的样子(添加的material就放在这里面) collider:控制碰撞(空气墙) unity游戏引擎帮助我们做了碰撞检测,我们只要写游戏的逻辑 Rigidbody组件能给游戏物体添加重力属性。 每个被创建的C#脚本也相当于一个组件,我们在“游戏物体”上通过Add Component添加。 使用组件前要把组件勾选上,不然没有效果。 删除脚本组件时,要把“游戏物体”上对应的脚本文件删除,不然会出现警告。 unity打开控制台:Window=>General=>Console(command+shift+c?)
C#代码介绍: using System.Collections; // 引用系统的类 using System.Collections.Generic; using UnityEngine;
创建的注意文件名要保持与类名一致,创建一个脚本相当于创建了一个类。初次在unity中创建文件时他们的名称是一致的,二次修改文件名时要保证类名也要同样修改。
Start:开始方法 作用:游戏启动时做一些初始化的工作。
Update:更新方法 作用:控制游戏的一些更新,具体根据功能来定。游戏运行时会一直重复调用Update方法(每一帧调用一次)
游戏物体有的有钢体组件,有些没有,通过代码让他们产生关联. 预制体(Prefabs):相当于一个模板,通过模板可以统一修改物体上一些组件、属性之类的,有模板生成的游戏物体会被统一修改。 在Project模板中修改预制体会同步“孩子”都会修改,在Hierarchy模板中修改“孩子”就不会同步其他“孩子”。但“孩子”也能映射到“母亲”身上通过overrides=>Apply All
系统事件: 每个游戏物体都有标签和名字,且可重复。 给预制体添加标签: 勾上 is Trigger,碰撞器变为触发器,可穿模。
编辑UI中的text:设置2D,双击canvas,因为canvas是2D的,画布对应game窗口。 设置text位置:
获取其它游戏物体身上的组件:
定义一个text组件 public Text scoreText; 定义一个游戏物体,因为一会我们要控制游戏物体,目前胜利的游戏物体是禁用的。 public GameObject winText; 碰撞系统事件,unity引擎帮我们检测碰撞,当发生碰撞会调用这个方法,Collision collision:碰撞信息,可知撞到了谁。 private void OnCollisionEnter(Collision collision) 发生碰撞时执行一次 collision.collider.tag 通过碰撞组件获取被碰撞物体的标签。 collision.gameObject.tag == “Food” 通过游戏物体获得标签 OnTriggerEnter 触发检测,当进入某个范围就触发,进入触发区域执行一次 transform.Rotate(Vector3.up); 设置食物的旋转角度,方向:up(向上),多少度:Vector3(一度)。让它围绕自身上方一度一度的旋转 Update方法大概一秒执行60次,一次旋转一度,相当于一秒旋转60度。
UnityAPI常用方法类与组件
public class No1_PrintDebug : MonoBehaviour
{
void Start()
{
Calculate();
Debug.Log("2+3的计算开始了");
int a = 1;
Debug.Log("a赋值完成,具体值是:"+a);
int b = 3;
Debug.Log("b赋值完成,具体值是:"+b);
int num = a + b;
Debug.Log("2+3="+num);
Debug.LogWarning("这是一个警告!");
Debug.LogError("这里有报错!");
}
private void Calculate()
{
Add();
Subtract();
}
private int Add()
{
return 1 + 1;
}
private int Subtract()
{
return 1 - 1;
}
}
public class TestDebugAndPrintClass:MonoBehaviour
{
public void TestPrint()
{
print("使用print必须让当前类继承自monobehavior");
}
public void TestDebug()
{
Debug.Log("使用debug再普通类里进行输出");
}
}
生命周期函数
功能说明:事件函数(生命周期函数),每个游戏物体上的同一钩子函数调用顺序不确定,但可以确定Start一定在Update前被调用,在Awake后执行这种顺序。
public class No2_EventFunction : MonoBehaviour
{
public float attackValue=10000;
public float currentHP;
private void Reset()
{
Debug.Log("调用了Reset方法");
Debug.Log("攻击值重置为默认值");
}
private void Awake()
{
Debug.Log("调用了Awake方法");
attackValue = 1;
}
private void OnEnable()
{
currentHP = 100;
Debug.Log("当前血量为:"+currentHP);
attackValue = 2;
}
void Start()
{
Debug.Log("调用了Start方法");
attackValue = 3;
}
void Update()
{
Debug.Log("调用了Update方法");
}
private void LateUpdate()
{
Debug.Log("调用了LateUpdate方法");
}
private void OnDisable()
{
Debug.Log("调用了OnDisable方法");
}
void OnApplicatoinQuit()
{
Debug.Log("OnApplicationQuit");
}
void OnDestroy()
{
Debug.Log("OnDestroy");
}
}
功能说明:用于测试外部调用或者外部复制时的顺序
public class No2_ExternalCall : MonoBehaviour
{
public No2_EventFunction api;
void Start()
{
api.attackValue = -1;
}
void Update()
{
}
}
创建游戏物体的3种方式
GameObject myGo = new GameObject("MyGameObject");
GameObject.Instantiate(grisGo);
GameObject.CreatePrimitive(PrimitiveType.Plane);
游戏物体的查找和获取(怎样调用自身游戏物体与其他游戏物体的方法与属性)
public class No3_GameObject : MonoBehaviour
{
public GameObject grisGo;
void Start()
{
GameObject myGo = new GameObject("MyGameObject");
GameObject.Instantiate(grisGo);
GameObject.CreatePrimitive(PrimitiveType.Plane);
Debug.Log("挂载这个脚本的游戏物体:"+this.gameObject);
Debug.Log("当前脚本挂载到的游戏物体名称是:"+gameObject.name);
Debug.Log("当前游戏物体标签是:"+gameObject.tag);
Debug.Log("当前游戏物体层级是:"+gameObject.layer);
Debug.Log("当前游戏物体的状态是:"+gameObject.activeInHierarchy);
Debug.Log("当前游戏物体的状态是:" +gameObject.activeSelf);
Debug.Log("gris游戏物体的状态是:"+ grisGo.activeSelf);
gameObject.SetActive(true);
gameObject.SetActive(true);
Debug.Log("grisGo游戏物体的状态:", grisGo.activeSelf);
GameObject mainCameraGo= GameObject.Find("Main Camera");
Debug.Log("mainCamera游戏物体的标签是:" + mainCameraGo.tag);
GameObject mainCameraGo = GameObject.FindGameObjectWithTag("MainCamera");
Debug.Log("mainCamera游戏物体的名字是:" + mainCameraGo.name);
No2_EventFunction no2_EventFunction= GameObject.FindObjectOfType<No2_EventFunction>();
Debug.Log("no2_EventFunction游戏物体的名字是:" + no2_EventFunction.name);
GameObject[] enemyGos= GameObject.FindGameObjectsWithTag("Enemy");
for (int i = 0; i < enemyGos.Length; i++)
{
Debug.Log("查找到的敌人游戏物体名称是:"+enemyGos[i].name);
}
BoxCollider[] colliders= GameObject.FindObjectsOfType<BoxCollider>();
for (int i = 0; i < colliders.Length; i++)
{
Debug.Log("查找到的敌人游戏物体名称是:" + colliders[i].name);
}
}
void Update()
{
}
private void Test() { }
}
GameObject.FindObjectsOfType(); // 查找拥有BoxCollider组件的游戏物体。 为游戏物体添加名为的BoxCollider组件:
MonoBehaviour(子类),派生自Behaviour类,Behaviour类派生自组件脚本Component(基类)
public class No4_MonoBehaviour : MonoBehaviour
{
void Start()
{
Debug.Log("No4_MonoBehaviour组件的激活状态是:"+this.enabled);
Debug.Log("No4_MonoBehaviour组件挂载的对象名称是:" + this.name);
Debug.Log("No4_MonoBehaviour组件挂载的标签名称是:" + this.tag);
Debug.Log("No4_MonoBehaviour组件是否已激活并启用Behaviour:" + this.isActiveAndEnabled);
}
}
组件的获取与使用(2种方法)
public class No5_Component : MonoBehaviour
{
public int testValue;
public GameObject enemyGos;
void Start()
{
No5_Component no5_Component = gameObject.GetComponent<No5_Component>();
Debug.Log(no5_Component.testValue);
GameObject grisGo = GameObject.Find("Gris");
Debug.Log(grisGo.GetComponent<SpriteRenderer>());
Debug.Log(enemyGos.GetComponentInChildren<BoxCollider>());
Debug.Log(enemyGos.GetComponentsInChildren<BoxCollider>());
Debug.Log(enemyGos.GetComponentInParent<BoxCollider>());
SpriteRenderer sr= grisGo.GetComponent<SpriteRenderer>();
sr.GetComponent<Transform>();
}
}
变换组件Transform
场景中的每个对象都有一个变换组件。 它用于存储和操作对象的位置、旋转和缩放。
public class No6_Transform : MonoBehaviour
{
public GameObject grisGo;
public float moveSpeed=1;
void Start()
{
Debug.Log(this.transform);
Debug.Log(grisGo.transform);
Transform grisTrans = grisGo.transform;
Debug.Log("Gris变换组件所挂载的游戏物体名字是:"+grisTrans.name);
Debug.Log("Gris变换组件所挂载的游戏物体引用是:"+grisTrans.gameObject);
Debug.Log("Gris下的子对象(指Transform)的个数是:"+grisTrans.childCount);
Debug.Log("Gris世界空间中的坐标位置是:"+grisTrans.position);
Debug.Log("Gris以四元数形式表示的旋转是:"+grisTrans.rotation);
Debug.Log("Gris以欧拉角形式表示的旋转(以度数为单位)是"+grisTrans.eulerAngles);
Debug.Log("Gris的父级Transform是:"+grisTrans.parent);
Debug.Log("Gris相对于父对象的位置坐标是:"+grisTrans.localPosition);
Debug.Log("Gris相对于父对象以四元数形式表示的旋转是:" + grisTrans.localRotation);
Debug.Log("Gris相对于父对象以欧拉角形式表示的旋转(以度数为单位)是:" + grisTrans.localEulerAngles);
Debug.Log("Gris相对于父对象的变换缩放是:"+grisTrans.localScale);
Debug.Log("Gris的自身坐标正前方(Z轴正方向)是:"+grisTrans.forward);
Debug.Log("Gris的自身坐标正右方(X轴正方向)是:" + grisTrans.right);
Debug.Log("Gris的自身坐标正上方(Y轴正方向)是:" + grisTrans.up);
Debug.Log("当前脚本挂载的游戏对象下的叫Gris的子对象身上的Transform组件是:"+transform.Find("Gris"));
Debug.Log("当前脚本挂载的游戏对象下的第一个(0号索引)子对象的Transform引用是:"+transform.GetChild(0));
Debug.Log("Gris在当前父对象里的索引位置:"+ grisTrans.GetSiblingIndex());
}
void Update()
{
grisGo.transform.Rotate(Vector3.forward,1);
}
}
Vector2(表示2D向量和点)
public class No7_Vector2 : MonoBehaviour
{
public Transform grisTrans;
public Transform targetTrans;
public float percent;
public float lerpSpeed = 0.01;
Vector2 currentVelocity = new Vector2(1, 0);
public struct MyStruct
{
public string name;
public int age;
}
public class MyClass
{
public string name;
public int age;
}
void Start()
{
print(Vector2.down);
print(Vector2.up);
print(Vector2.left);
print(Vector2.right);
print(Vector2.one);
print(Vector2.zero);
Vector2 v2 = new Vector2(2, 2);
print("V2向量是:" + v2);
print("V2向量的模长是:" + v2.magnitude);
print("V2向量的模长的平方是:" + v2.sqrMagnitude);
print("V2向量单位化之后是:" + v2.normalized);
print("V2向量的X、Y值分别是:" + v2.x + "," + v2.y);
print("V2向量的X、Y值分别是(使用索引器形式访问):" + v2[0] + "," + v2[1]);
bool equal = v2.Equals(new Vector2(1, 1));
print("V2向量与向量(1,1)是否相等?" + equal);
Vector2 v2E = new Vector2(1, 3);
bool equalv2E = v2E.Equals(new Vector2(3, 1));
print("v2E向量与向量(3,1)是否相等?" + equal);
print("V2向量的单位化向量是:" + v2.normalized + "但是V2向量的值还是:" + v2);
v2.Normalize();
print("V2向量是:" + v2);
v2.Set(5, 9);
print("V2向量是:" + v2);
transform.position = v2;
transform.position.x = 4;
MyStruct myStruct = new MyStruct();
myStruct.name = "wuky";
myStruct.age = 100;
MyStruct yourStruct = myStruct;
yourStruct.name = "小可爱";
yourStruct.age = 18;
print("原本的结构体对象名字是:" + myStruct.name);
print("修改后的结构体对象名字是:" + yourStruct.name);
MyClass myClass = new MyClass();
myClass.name = "wuky8";
myClass.age = 100;
MyClass yourClass = myClass;
yourClass.name = "小阔爱";
yourClass.age = 18;
print("原本的结构体对象名字是:" + myClass.name);
print("修改后的结构体对象名字是:" + yourClass.name);
transform.position = new Vector2(3, 3);
Vector2 vector2 = transform.position;
vector2.x = 2;
transform.position = vector2;
Vector2 va = new Vector2(1, 0);
Vector2 vb = new Vector2(0, 1);
Debug.Log("从va指向vb方向计算的无符号夹角是:" + Vector2.Angle(va, vb));
print("va点与vb点之间的距离是:" + Vector2.Distance(va, vb));
print("向量va与向量vb的点积是:" + Vector2.Dot(va, vb));
print("向量va和向量vb在各个方向上的「最大分量」组成的新向量是:" + Vector2.Max(va, vb));
print("向量va和向量vb在各个方向上的「最小分量」组成的新向量是:" + Vector2.Min(va, vb));
print("va向vb按照0.5的比例进行线性插值变化之后的结果是" + Vector2.Lerp(va, vb, 0.5f));
print("va向vb按照参数为-1的形式进行(无限制)线性插值变化之后的结果是" + Vector2.LerpUnclamped(va, vb, -1));
print("将点va以最大距离不超过maxDistance为移动步频移向vb" + Vector2.MoveTowards(va, vb, maxDistance));
print("va和vb之间的有符号角度(以度为单位,逆时针为正)是" + Vector2.SignedAngle(va, vb));
print("vb和va之间的有符号角度(以度为单位,逆时针为正)是" + Vector2.SignedAngle(vb, va));
print("va和vb在各个方向上的分量相乘得到的新向量是:" + Vector2.Scale(va, vb));
Vector2 currentVelocity = new Vector2(1, 0);
print(Vector2.SmoothDamp(va, vb, ref currentVelocity, 0.1f));
print("va加上vb向量是:" + (va + vb));
print("va减去vb向量是:" + (va - vb));
print("" + va * 10);
print("va与vb是同一个向量吗" + (va == vb));
}
void Update()
{
grisTrans.position = Vector2.Lerp(grisTrans.position,targetTrans.position,0.01f);
percent += 1 * lerpSpeed * Time.deltaTime;
grisTrans.position = Vector2.Lerp(grisTrans.position, targetTrans.position, percent);
grisTrans.position = Vector2.MoveTowards(grisTrans.position, targetTrans.position, 0.05f);
grisTrans.position = Vector2.SmoothDamp(grisTrans.position,targetTrans.position,ref currentVelocity,1);
}
}
最大分量组成的新向量: 线性插值: (无限制)线性插值:
访问输入系统的接口类Input
public class No8_Input : MonoBehaviour
{
void Start()
{
}
void Update()
{
print("当前玩家输入的水平方向的轴值是:"+Input.GetAxis("Horizontal"));
print("当前玩家输入的垂直方向的轴值是:" + Input.GetAxis("Vertical"));
print("当前玩家输入的水平方向的边界轴值是:" + Input.GetAxisRaw("Horizontal"));
print("当前玩家输入的垂直方向的边界轴值是:" + Input.GetAxisRaw("Vertical"));
print("当前玩家鼠标水平移动增量是:"+Input.GetAxis("Mouse X"));
print("当前玩家鼠标垂直移动增量是:" + Input.GetAxis("Mouse Y"));
if (Input.GetButton("Fire1"))
{
print("当前玩家正在使用武器1进行攻击!");
}
if (Input.GetButton("Fire2"))
{
print("当前玩家正在使用武器2进行攻击!");
}
if (Input.GetButton("RecoverSkill"))
{
print("当前玩家使用了恢复技能回血!");
}
if (Input.GetButtonDown("Jump"))
{
print("当前玩家按下跳跃键");
}
if (Input.GetButtonUp("Squat"))
{
print("当前玩家松开蹲下建");
}
if (Input.GetKeyDown(KeyCode.Q))
{
print("当前玩家按下Q键");
}
if (Input.anyKeyDown)
{
print("当前玩家按下了任意一个按键,游戏开始");
}
if (Input.GetMouseButton(0))
{
print("当前玩家按住鼠标左键");
}
if (Input.GetMouseButtonDown(1))
{
print("当前玩家按下鼠标右键");
}
if (Input.GetMouseButtonUp(2))
{
print("当前玩家抬起鼠标中键(从按下状态松开滚轮)");
}
}
}
给其他组件传送消息
public class No9_Message : MonoBehaviour
{
void Start()
{
gameObject.SendMessage("GetMsg");
SendMessage("GetSrcMsg","wuky");
SendMessage("GetTestMsg",SendMessageOptions.DontRequireReceiver);
BroadcastMessage("GetMsg");
SendMessageUpwards("GetMsg");
}
void Update()
{
}
public void GetMsg()
{
print("测试对象本身接收到消息了");
}
public void GetSrcMsg(string str)
{
print("测试对象本身接收到的消息为:"+str);
}
}
public class No9_MessageChild : MonoBehaviour
{
public void GetMsg()
{
print("测试对象的子对象接收到消息了");
}
}
public class No9_MessageParent : MonoBehaviour
{
public void GetMsg()
{
print("测试对象的父对象接收到消息了");
}
}
public class No9_MessageParent : MonoBehaviour
{
public void GetMsg()
{
print("测试对象的父对象接收到消息了");
}
}
public class No9_MessageTest : MonoBehaviour
{
public void GetMsg()
{
print("测试对象身上的其他组件接收到消息了");
}
public void GetSrcMsg(string str)
{
print("测试对象身上的其他组件接收到的消息为:" + str);
}
}
Animator
持续…
UI部分
创建新的场景,创建后保存到Assets中 为场景添加背景图片:
注意:需要按住option再选择 通常先让图片保持原本大小,再按住shift等比例缩放 直接拖凭感觉那么位置不精准,就要直接设置坐标 为图片添加文字: 注意:这里按住option与shift选择锚点的效果是不一样的。 为图片添加slider组件,让其滑动。图片能修改颜色,同一张图片能搭建出许多效果
文字很清晰: 复制一张图片成为遮罩: 为文字添加边框效果: 为物体创建脚本处理技能冷却效果: 将类在编辑器中打开: 在物体上绑定点击事件,指定点击事件调用的具体方法。
释放技能代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class SkillItem2 : MonoBehaviour
{
private Image coldMask;
private bool isCold = false;
public float coldTime = 2;
public float time = 0;
public KeyCode KeyCode = KeyCode.Alpha1;
void Start()
{
coldMask = transform.Find("ColdMask").GetComponent<Image>();
}
void Update()
{
if (isCold == true) {
time += Time.deltaTime;
coldMask.fillAmount = (coldTime - time) / coldTime;
}
if (time > coldTime) {
isCold = false;
time = 0;
coldMask.fillAmount = 0;
}
if(Input.GetKeyDown(KeyCode))
{
ReleaseSkill();
}
}
public void OnSkillClick() {
ReleaseSkill();
}
public void ReleaseSkill() {
if (isCold == false)
{
isCold = true;
time = 0;
coldMask.fillAmount = 1;
}
}
}
给图片设置边框,防止边框变糊: (蝴蝶结)就是锚点 为图片添加选中与没选中效果。
为图片添加单选效果 网格组件,可以为每一项网格设置父空物体来控制网格的每一项处于正中心: 创建预制体
使用预制体前需要断开连接:
快捷键
按住shift:等比例缩放图片 按住option+左键:能拖拽整个画面 选中文件,再点击一下就能修改文件名 页面上选中物体,commond+D为复制物体
|