该文对Unity2019 做简单的自学了解,并做相应的笔记
简单的控制台程序
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
System.Console.WriteLine("Hello World");
}
}
}
类型转换
//int->string
int a = 10;
string strA = a.ToString();
//string->int
String b = "10";
int iB = int.Parse(b);
//使用Convert转换
iB = Convert.ToInt32(b);
数组
//一维数组
int[] a = { 1, 2, 3, 4, 5 };
int[] b = new int[5];//注意,只声明数组长度
Array.Copy(a, b, 5);//b的元素必须提前声明好
foreach(int i in b)
{
System.Console.WriteLine(i);
}
System.Console.WriteLine("{0}, 找到1首次出现的位置:{1}", b[0], Array.IndexOf(b, 1));
//多维数组
int[,] c = { { 1, 2, 3 }, { 4, 5, 6 } };
System.Console.WriteLine(c[0, 1]);
//string和stringbuilder
String name = "wang", name2 = "li";
StringBuilder names = new StringBuilder();
names.Append(name);
names.Append(name2);
System.Console.WriteLine(names);
基本使用
class Test
{
private String strTitle;
public string GetMessage()
{
return "Message";
}
public string title
{
get
{
return strTitle;
}
set
{
strTitle = value;
}
}
}
ref和param
class Program
{
/// <summary>
/// 测试使用REF,传递引用类型
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
static void TestRef(ref int a, ref int b)
{
int tmp = a;
a = b;
b = tmp;
}
/// <summary>
/// 测试使用params,传递无限制参数列表
/// </summary>
/// <param name="names"></param>
static void TestParam(params String[] names)
{
foreach(string name in names)
{
System.Console.WriteLine(name);
}
}
static void Main(string[] args)
{
int a = 10, b = 15;
TestRef(ref a, ref b);
System.Console.WriteLine("{0}, {1}", a, b);
TestParam("zhang", "li", "wang");
}
}
继承和多态
interface Study
{
void Read();
void Listen();
void Say();
void Write();
}
abstract public class People
{
private string name;
private int age;
public People(string name, int age)
{
this.name = name;
this.age = age;
}
abstract public void Hello();
}
sealed public class Student: People, Study
{
Student(string name, int age): base(name, age)
{
}
public override void Hello()
{
System.Console.WriteLine("Hello");
}
public void Listen()
{
}
public void Read()
{
}
public void Say()
{
}
public void Write()
{
}
}
集合索引和泛型
//使用arraylist,注意这种类型可以插入任何类型,但需要拆包
//如果不希望拆包,可以使用Array<int>
ArrayList arrayList = new ArrayList(5);
arrayList.Add(1);
int b = (int)arrayList[0];
//使用Stack
Stack objStack = new Stack();
Stack<int> iStack = new Stack<int>();
//使用Queue
Queue queue = new Queue();
//使用List(必须要指定类型)
List<int> iList = new List<int>();
//使用Dictonary(必须要指定类型)
Dictionary<int, string> keyValuePairs = new Dictionary<int, string>();
泛型
//这里使用where是一种约束,也就是T必须继承自Interface1
class TempClass<T> where T: Interface1
{
void TestSay(T obj)
{
obj.Say();
}
}
反射
public class Test
{
private string name;
public Test(String name)
{
this.name = name;
}
public void Print()
{
System.Console.WriteLine(this.name);
}
}
static void Main(string[] args)
{
//创建程序集名
Test t = new Test("t");
Type type = t.GetType();
System.Console.WriteLine(type);
//根据程序集名创建对象
Type type2 = Type.GetType("ConsoleApp1.Program+Test");
object[] constStructParams = new object[] { "t2" };
Object t2 = Activator.CreateInstance(type2, constStructParams);
((Test)t2).Print();
//指定函数名调用
MethodInfo info = type2.GetMethod("Print");
object[] constStructParams2 = new object[] { };
info.Invoke(t2, constStructParams2);
}
调试和异常处理
public static void Test(int a)
{
if(a == 0)
{
throw new Exception("参数不能为0");
}
}
static void Main(string[] args)
{
try
{
Test(0);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
Console.WriteLine("Finially");
}
}
事件和委托
class Program
{
class EventTest
{
public delegate void GetMessage(string msg);
public GetMessage GetMessageDelegate;
public event GetMessage GetMessageEvent;
public void RaiseEvent()
{
GetMessageEvent("Hello");
}
}
static void Main(string[] args)
{
EventTest test = new EventTest();
test.GetMessageDelegate += OnGetMessage;
test.GetMessageDelegate("Delegate");
test.GetMessageEvent += OnGetMessage;
test.RaiseEvent();
}
static void OnGetMessage(string msg)
{
System.Console.WriteLine("OnGetMessage: {0}", msg);
}
}
线程
class Program
{
static void Main(string[] args)
{
{
Thread t = new Thread(new ThreadStart(Run));
t.Start();
}
{
Thread t = new Thread(new ThreadStart(new ThreadTest().MyThread));
t.Start();
}
{
Thread t = new Thread(new ThreadStart(delegate()
{
Console.WriteLine("匿名委托");
}));
t.Start();
}
{
Thread t = new Thread(()=>Console.WriteLine("箭头函数"));
t.Start();
}
{
Thread t = new Thread(new ParameterizedThreadStart(RunPara));
t.IsBackground = true;//后台线程,程序可以直接退出而不等线程结束
t.Start("向线程中传递参数,参数必须是Object类型");
t.Join();
}
}
static void Run()
{
Console.WriteLine("静态函数");
}
static void RunPara(object str)
{
Console.WriteLine(str);
}
}
class ThreadTest
{
public void MyThread()
{
Console.WriteLine("成员函数");
}
}
匿名委托,lambda表达式,Action和Func
public delegate void FuncDelegate(int c);
static void Main(string[] args)
{
Func<int, int> func = delegate (int c) { return c; };
Action<int> action = (int a) => { Console.WriteLine(a); };
FuncDelegate funcDelegate = delegate (int a) { Console.WriteLine(a); };
}
async/await
class Program
{
static void Main(string[] args)
{
{
//直接使用Task,获取异步返回结果
Task<int> task1 = new Task<int>(() => {
return 1;
});
task1.Start();
Console.WriteLine(task1.Result);
}
{
Console.WriteLine(GetResultAsync().Result);
}
}
static public async Task<int> GetResultAsync()
{
//Task<int> task = new Task<int>(()=> { return 1; });
Task<int> task = Task.Run<int>(() => { return 1; });
return await task;
}
}
协程
本次学习使用引擎是Unity 2019.2.12f1版本。
建议使用Unity Hub来管理Unity版本和授权。
Unity官网是unity.cn
Unity在场景的操作方式和UE4基本一致
在[Unity - Manual: Order of Execution for Event Functions](file:///D:/Program Files/Unity/2019.2.12f1/Editor/Data/Documentation/en/Manual/ExecutionOrder.html)可以找到事件函数的执行顺序
Awake:不管脚本是否激活,都会被执行
Start:游戏开始
Update:游戏刷新的时候
FixedUpdate:固定刷新,0.02s调用一次
LateUpdate:在Update之后被调用
素材管理
导入导出图片
视频和音频
导入音频
向Canvas中添加组件 音频源,设置导入的音频
向Canvas中添加音频监听器
导入视频
创建原始图像
创建渲染器纹理
将将渲染器纹理拖拽到原始图像.纹理的选项上
在原始图像创建组件 视频播放器,将渲染器纹理和视频剪辑分辨拖拽到视频播放器中
字体和粒子特效
模型和场景
脚本
同步加载场景
异步加载场景
加载场景时保留物体
首先在文件-build settings,将两个场景拖入到Build中的场景
SceneManager.LoadScene("SampleScene", LoadSceneMode.Additive);
GameObject Cube = GameObject.Find("Sphere");
DontDestroyOnLoad(Cube);
设置某个场景的物体不会被消除
使用协程进行异步加载
void Start()
{
StartCoroutine(Load());
}
private IEnumerator Load()
{
AsyncOperation asyncOperation = SceneManager.LoadSceneAsync("Scenes/SampleScene");
asyncOperation.allowSceneActivation = false;
while(asyncOperation.progress < 0.9f)
{
Debug.Log(asyncOperation.progress);
yield return null;
}
asyncOperation.allowSceneActivation = true;
if(asyncOperation.isDone)
{
Debug.Log("加载跳转完毕");
}
else
{
Debug.Log("加载没有跳转完毕");
}
}
标签和层级主要用于编程中搜索物体和过滤物体
预制件
创建
可以将场景中内容拖拽到资源中,保存成预制件,预制件一般只能保存一份。
预制件默认放在Resources文件夹下,可以通过API索引到预制件
//创建
GameObject go = Resources.Load<GameObject>("Object/Sphere");
GameObject.Instantiate(go);
如果没有放在Resources文件夹下,可通过public 变量传入预制件。
使用脚本对物体交互
//创建
//GameObject go = Resources.Load<GameObject>("Object/Sphere");
//GameObject.Instantiate(go);
查找,如果要查找子物体,可以使用/寻找到子物体。
//GameObject go1 = GameObject.Find("Sphere");
//go1.SetActive(false);
//查找(按照标签查找)
GameObject go2 = GameObject.FindGameObjectWithTag("Hero");
//go2.SetActive(false);
go2.name = "Cube02";
//go2.transform.position = Vector3.zero;
go2.transform.position = new Vector3(0, 0, 0);
//go2.transform.rotation = Quaternion.Euler(0, 90, 90);
go2.transform.eulerAngles = new Vector3(0, 90, 90);
//销毁
Destroy(go2);
查找组件
GameObject go = GameObject.Find("Text");
go.GetComponentInChildren<Text>().text = "查找到组件";
禁用组件
画布与事件系统
文本
输入框
首先先自己尝试按照流程创建用户界面
并实现三个需求:
InputField userInput;
InputField pwdInput;
Button loginBtn;
public Sprite bg;
// Start is called before the first frame update
void Start()
{
userInput = transform.Find("EditAccount").GetComponent<InputField>();
pwdInput = transform.Find("EditPassword").GetComponent<InputField>();
loginBtn = transform.Find("Login").GetComponent<Button>();
loginBtn.onClick.AddListener(LoginBtnOnClick);
//替换背景图片
transform.Find("BG").GetComponent<Image>().sprite = bg;
//打开网页
transform.Find("website").GetComponent<Button>()
.onClick.AddListener(WebSiteOnClick);
}
void LoginBtnOnClick()
{
string account = userInput.text;
string pwd = userInput.text;
Debug.Log("Account:" + account);
Debug.Log("Password:" + pwd);
}
void WebSiteOnClick()
{
Application.OpenURL("http://www.baidu.com");
}
在编程的时候,注意:
Toggle
滑动条
滚动视图
在UI中选择滚动视图,滚动视图中包含content是用来包含其他元素的容器,content的大小就是页面的大小。
可以选择水平Layout、垂直Layout、Grid Layout来对内容进行自动化的排序。
可以使用内容尺寸适配器(Content Size Fitter),内容尺寸适配器在垂直方向或水平方向可以根据内容自动跳转父元素的大小,设置Preferred Size,有时候对于文本也可以对根据内容做自适应。
滚动视图中包含一个Viewport,是使用遮罩的方法将其它的元素不显示,对于创建圆形头像等可以使用遮罩的方法。
GameObject用于预制件,Transform用于场景中任何物体的使用。
public GameObject Hero;
public Transform Content;
void Start()
{
}
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyCode.A))
{
GameObject _hero = GameObject.Instantiate(Hero);
_hero.transform.SetParent(Content);
}
}
可以自定义类似于滑动条的组件
创建父子两个Image
给子Image添加任意一个原图像(实际测试发现对于半透明图像不可用)
设置好父子物体的颜色,选择图像类型为“已填充”,填充方法为水平。
通过代码修改填充总数,可以实现将子控件填充到对应百分比的位置。
其他常用组件
虚拟轴
通过Input.GetAxis获取轴的值。
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
if(h != 0)
{
//transform.position = new Vector3(
// h + transform.position.x,
// transform.position.y,
// transform.position.z
// );
transform.eulerAngles = new Vector3(
h + transform.eulerAngles.x,
transform.eulerAngles.y,
transform.eulerAngles.z
);
}
if(v != 0)
{
//transform.position = new Vector3(
// transform.position.x,
// transform.position.y,
// v + transform.position.z
//);
}
获取键盘事件
获取鼠标事件
移动设备输入
灯光组件
灯光按照类型可以分为:方向光、点光、聚光、区域光。
一般区域光需要进行烘焙才能显示,且只能烘焙静态物体,烘焙在窗口-渲染-照明生成,选择混合照明中烘焙全局照明,然后可以选择自动生成,就会看到烘焙后的照明效果。
可以设置阴影的强度和硬度。
照明设置
可以在照明设置环境光以及天空盒
可以选择混合模式,是否开启烘焙照明
可以选择光照贴图是CPU还是GPU
可以设置雾,当雾的密度调大时,会有浓雾的效果。
可以设置光晕:需要在光源处选择绘制光晕
可以设置炫光
自发光
光照探测器
反射探测器
蒙皮网格与普通网格的对比
材质的使用
换肤功能的实现
能够使用代码替换人物衣服的材质
public SkinnedMeshRenderer body;
public Material m1;
public Material m2;
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyCode.A))
{
//换成第一件衣服
body.material = m1;
}
else if(Input.GetKeyDown(KeyCode.S))
{
//换成第二件衣服
body.material = m2;
}
}
3D物理系统
刚体:提供重力系统的物体
碰撞体:提供碰撞检测的物体,一般直接创建的物体都有碰撞体,碰撞体分为盒装、胶囊、平面等。
常用属性:
恒力组件
绝对力:Force、相对力:RelativeForce:区别是是和世界坐标保持一致还是和自身坐标保持一致
绝对扭矩力:Torque、相对扭矩力:RelativeTorque
API和属性
rig = transform.GetComponent<Rigidbody>();
//设定初始速度
rig.velocity = new Vector3(10, 0, 0);
添加力
rig.AddForce(new Vector3(10, 0, 0));
//使用爆炸力
rig.AddExplosionForce(300, transform.position, 10);
刚体休眠和唤醒
碰撞器和触发器
常用属性
常用API
触发器的使用
private void OnCollisionStay(Collision collision)
{
Debug.Log("OnCollisionStay:" + collision.gameObject.name);
}
private void OnCollisionExit(Collision collision)
{
Debug.Log("OnCollisionExit:" + collision.gameObject.name);
}
private void OnCollisionEnter(Collision collision)
{
Debug.Log("OnCollisionEnter:" + collision.gameObject.name);
}
物理材质
关节组件
射线
绘制射线
Debug.DrawLine/Debug.DrawRay:绘制线段(射线)
Debug.DrawLine(transform.position, transform.position + transform.forward, Color.red, 10, false);
Camera.ScreenPointToRay=>Physics.Raycast
void Update()
{
if(Input.GetMouseButtonDown(0))
{
Ray ray = camera.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if(Physics.Raycast(ray, out hit, 100f))
{
Debug.Log("命中了碰撞: " + hit.point + ",name: " + hit.collider.gameObject.name);
}
else
{
Debug.Log("没有命中碰撞");
}
}
}
Physics.Raycast:检测碰撞
Physics.RaycastAll:返回所有碰撞数组
Physics.OverlapSphere:球形射线,返回碰撞数组
2D物理系统
2D刚体和碰撞器
2D表面效果器
2D区域效果器
2D浮力效果器
2D点效果器
动画启动播放控制
使用按键控制动画播放
创建动画器控制器
将一些动画拖入到动画器控制器中
在动画器选项卡中添加参数id,类型为int
设置动画器控制器的进入不同状态的条件
在模型上添加动画器,设置好动画器控制器和Avatar
编写脚本,控制动画器的值
Animator am;
void Start()
{
am = transform.GetComponent<Animator>();
}
void Update()
{
if(Input.GetKeyDown(KeyCode.Alpha0))
{
am.SetInteger("id", 0);
}
else if(Input.GetKeyDown(KeyCode.Alpha1))
{
am.SetInteger("id", 1);
}
else if (Input.GetKeyDown(KeyCode.Alpha2))
{
am.SetInteger("id", 2);
}
else if (Input.GetKeyDown(KeyCode.Alpha3))
{
am.SetInteger("id", 3);
}
else if (Input.GetKeyDown(KeyCode.Alpha4))
{
am.SetInteger("id", 4);
}
}
选择跳转条件,取消对“可以过度到自己”的勾选。
如果希望动画可以循环,选择动画,勾选循环时间。
如果希望无延迟的切换到其它的动画,可以取消“有退出时间”
人形动画
动画遮罩
动画事件
制作一个点击自动寻路程序
先搭建一个场景
将场景中的物体设置为导航静态(在检查器-静态下拉菜单中设置)
打开烘焙窗口:窗口-ai-烘焙
切换到烘焙选项卡,进行烘焙,如果模型非常的小,需要设置好半径等参数才能看到烘焙的结果。
向人物增加组件——导航网格代理
添加脚本
NavMeshAgent agent;
void Start()
{
agent = GetComponent<NavMeshAgent>();
}
void Update()
{
if(Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
bool isCollider = Physics.Raycast(ray, out hit);
if(isCollider)
{
agent.SetDestination(hit.point);
}
}
}
重要属性
动态障碍物
分离网格跳跃线
运行时动态烘焙网格
使用官方扩展工具 NavMeshComponents工具(https://github.com/Unity-Technologies/NavMeshComponents)将NavMeshComponents/Assets/NavMeshComponents复制到项目中使用。
在需要导航的物体上创建 Nav Mesh Surface组件 并进行烘焙。
实现在点击的位置创建立方体
public GameObject buildPrefab;
NavMeshSurface surface;
void Start()
{
surface = GetComponent<NavMeshSurface>();
}
void Update()
{
if(Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
bool isCollider = Physics.Raycast(ray, out hit);
if(isCollider)
{
GameObject go = Instantiate(buildPrefab, hit.point, Quaternion.identity);
go.transform.SetParent(this.transform);
surface.BuildNavMesh();
}
}
}
音频源组件和音频监听器组件
音频源组件常用函数
AudioSource audio;
void Start()
{
audio = transform.GetComponent<AudioSource>();
audio.clip = Resources.Load<AudioClip>("bj4");
}
void Update()
{
if(Input.GetKeyDown(KeyCode.A))
{
audio.Play();
//audio.Pause();
//audio.Stop();
}
}
音频过滤器和音频混响区(不常用,了解)
粒子系统
使用资源包中的粒子(实践)
使用代码编辑粒子系统
GameObject partivalGo;
ParticleSystem particleSystem;
void Start()
{
partivalGo = GameObject.Instantiate(Resources.Load<GameObject>("22_RFX_Fire_Campfire1"));
partivalGo.transform.position = transform.position;
particleSystem = partivalGo.GetComponent<ParticleSystem>();
//修改属性
ParticleSystem.MainModule mainModule = particleSystem.main;
mainModule.loop = true;
//播放,暂停,停止
particleSystem.Play();
//particleSystem.Stop();
//particleSystem.Pause();
}
粒子触发回调
ParticleSystem particle;
void Start()
{
particle = transform.GetComponent<ParticleSystem>();
}
private void OnParticleTrigger()
{
List<ParticleSystem.Particle> particles = new List<ParticleSystem.Particle>();
//这个地方并没有获取到任何的粒子?
int num = particle.GetTriggerParticles(
ParticleSystemTriggerEventType.Enter,
particles);
for (int i=0;i< num;i++)
{
ParticleSystem.Particle par = particles[i];
par.startColor = Color.red;
particles[i] = par;
}
}
拖尾
粒子立场
文章浏览阅读4.3k次,点赞14次,收藏31次。网上有很多方法,大部分都是让直接新建一个pcb文件,这显然太不现实了。 上述错误可以看出,unknown pin 的错误是在add pin to net的时候发生的 failed to add class member 的错误实在add to component class member发生的 要想根本解决这个问题,要了解net和class的作用。 首先net的作用是..._ad转pcb提示未知引脚
文章浏览阅读136次。
文章浏览阅读272次。#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : ${DATE} ${TIME} # @Author : Aries # @Site : ${SITE} # @File : ${NAME}.py # @Software: ${PRODUCT_NAME}--------------------- 作者:Leo-Woo 来源:CSDN 原文..._python标准的头注释 pycharm
文章浏览阅读503次,点赞2次,收藏2次。oracle计算hash值1、dbms_utility.get_hash_value(name VARCHAR2,base NUMBER,hash_size NUMBER)函数说明name:输入值base:返回hash value的起始值(hash bucket最小值)hash_size:返回hash表的期望大小(hash bucket最大值)这个函数用于计算并返回落在给定范围内的hash值2、o..._oracle中ora_hash用法
文章浏览阅读272次。0. 前言自我在内网发布了一篇关于 Lottie 的原理分析的文章之后,就不断有同事来找我询问关于 Lottie 的各种东西,最近又有同事来问,就想着可能对大家也会有所帮助,就稍作处理后分享出来。需要注意的是,这文章写于两年前,基本版本 2.0.0-beta3,虽然我看过最新版本,主要的类没有什么差别,不过可能还是会存在一些差异。可以感受一下我两年前的实力。_lottie.setanimation原理
文章浏览阅读777次。Activiti7中各种任务的详解_activiti7流程和任务的关系
文章浏览阅读2.1k次。学习Android的小伙伴们一定都听过ADB吧,如果没有听过也没有关系,下面我将介绍ADB及一些ADB命令的使用技巧.ADB的全称是Android Debug Bridge,直接翻译过来就是Android调试桥,它就像一个纽带,可以让我们在电脑上操作手机,我们可以在电脑上对其发送一些指令来调试它._adb iockbrowsor
文章浏览阅读1.3k次。Background去除偏见问题一直在真实对话系统中一直收到广泛的关注,在大型人类产生的语料库上训练的预训练语言模型,很多模型继承了类似人类的偏见和不想要的社会定型,例如,在 mask filling 任务中,BERT 将句子“The man/woman had a job as [MASK]”中的 [MASK] 分别替换为“经理/接待员”,反映了职业的性别偏见。我们认为..._auto-debias
文章浏览阅读3.6k次,点赞2次,收藏2次。画类图最重要的就是抽象出类,先来回忆类的基本内容。一、类1、类的概念:类是面向对象程序设计的中的一个基本概念,类是具有相同属性、方法、语义和关系的一组对象的集合。2、类的分类: 实体类:保存要放进永久存储的信息 边界类:位于系统与外界的交界处。包括所有的窗体、报表、打印机等硬件接口以及与其他系统的接口。 控制类:负责协调其他类的工作。一般每个用例都有一个控制_uml中属于静态视图的是
文章浏览阅读6k次。不用调接口,全由js就可完成Excel文件的生成和导出,示例如下:_js生成excel文件
文章浏览阅读507次,点赞3次,收藏8次。本课题旨在探讨和实现一个基于SpringBoot后端框架和UniApp前端框架的微信商城小程序。SpringBoot作为一种简化的、用于快速开发企业级应用的开源框架,提供了一套全面的基础架构支持,包括自动配置、依赖管理以及安全性等特性,使得开发者能够以最少的配置快速启动和运行项目。结合UniApp,一种使用Vue.js开发所有前端应用的框架,它允许开发者编写一次代码,然后发布到iOS、Android、Web(包括微信小程序及其他小程序平台)等多个平台。_基于springboot的微信小程序商城
文章浏览阅读266次。哈工大计算机组成原理第四章下——>缓存Cache(更新中。。)_主存的效率是什么