该文对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;
}
}
拖尾
粒子立场
文章浏览阅读2.1k次。见字如面,我是军哥!我很少推荐别人的公众号,因为我能看上的原创公众号并不多,让我主动推荐就更难了。今天这位朋友叫宇宙,认识有两年了,在支付行业里非常有名气,最近闲着无聊翻了他多篇原创文章之后,我发现他对支付这种极其复杂领域的业务架构/产品架构已经到了炉火纯青的地步了,推荐给各位,我相信你一定会回头来感谢我的!下面是他的一篇原创,本文头部和尾部都有他的公号卡片,文章不长,请认真看完~从一次美团外卖的..._美团外卖单子小票有什么信息
文章浏览阅读663次,点赞16次,收藏18次。代码混淆是指将程序中的方法名、属性名等符号重命名,并对代码进行改写,使其加密和混淆,增加应用逆向工程的难度。在移动互联网时代,代码混淆越来越受到开发者的重视。iOS代码混淆可以提高难度,从而防止应用程序被盗用或反编译,保护开发者的权益。但是同时也带来了一些问题,例如混淆后的函数名可能会影响代码的可维护性。因此,在使用代码混淆时需要进行合理规划。
文章浏览阅读625次,点赞9次,收藏10次。数码管是一种能够显示数字的电子元件,常见于数字时钟、计时器、温度计、电子秤等设备中。它通常由多个发光二极管(LED)或荧光显示管(VFD)组成,能够显示从0到9的数字。a.数码管由多个数字或字符的显示单元组成,每个显示单元可以显示一个数字或字符。b.每个显示单元内部包含多个LED或者VFD,排列成特定的数字或字符形状,以便显示。a.数码管通过控制各个LED或VFD的点亮状态来显示数字。b.当所需数字被显示时,控制电路会向相应的LED或VFD施加电压,使其发光,从而形成数字的形状。
文章浏览阅读1.6k次。文章目录摘要1.引言2.相关工作2.1 Vehicle ReID2.2 Vehicle pose estimation2.3 Synthetic data3.提出的方法3.1 随机合成数据集3.2 车辆姿态估计3.3 车辆重识别的多任务学习4.评估4.1 数据集和评估协议4.2 实现细节4.3 与其他方法的比较4.4 属性分类比较4.5 车辆姿态估计比较5.结论PAMTRI:Pose-Aware..._pamtri
文章浏览阅读4k次,点赞3次,收藏12次。工作中需要通过Spark以csv格式输出spark计算结果包括一些指标和维度为了方便普通客户使用表头要求中文。中文识别上遇到了些问题,出现了乱码:解决csv文件中的乱码最直接的思路就是添加BOM,这样Excel在打开Excel的时候就知道使用什么样的编码来解析这篇文档了。方法如下 只需要在csv文件表头字段名称的第一个字段名称的字符串最前面拼接一个BOM字符串就可以了..._spark excel 中文
文章浏览阅读1.3w次,点赞23次,收藏11次。1024程序员节是中国广大程序员的共同节日。1024是2的十次方,二进制计数的基本计量单位之一。程序员(英文Programmer)是从事前端、后端程序开发、系统运维、测试等的专业人员。程序员就像是一个个1024,以最低调、踏实、核心的功能模块搭建起这个科技世界。1G=1024M,而1G与1级谐音,也有一级棒的意思。以下表情包,博君一笑程序员的高级自黑每当想放松的时..._1024程序代码
文章浏览阅读637次,点赞29次,收藏14次。javascript是前端必要掌握的真正算得上是编程语言的语言,学会灵活运用javascript,将对以后学习工作有非常大的帮助。掌握它最重要的首先是学习好基础知识,而后通过不断的实战来提升我们的编程技巧和逻辑思维。这一块学习是持续的,直到我们真正掌握它并且能够灵活运用它。如果最开始学习一两遍之后,发现暂时没有提升的空间,我们可以暂时放一放。继续下面的学习,javascript贯穿我们前端工作中,在之后的学习实现里也会遇到和锻炼到。真正学习起来并不难理解,关键是灵活运用。
文章浏览阅读2.6k次,点赞4次,收藏31次。版权声明:本文为本文为博主原创文章,转载请注明出处。如有错误,欢迎指正。文章目录xenomai 内核系统调用一、32位Linux系统调用二、32位实时系统调用三、 64位系统调用五、 实时系统调用表cobalt_syscalls六、实时系统调用权限控制cobalt_sysmodes参考xenomai 内核系统调用解析系统调用是了解内核架构最有力的一把钥匙,在这之前先搞懂xenomai与linux两个内核共存后系统调用是如何实现的。为什么需要系统调用linux内核中设置了一组用于实现系统功能的子程_xenomai
文章浏览阅读4.8k次,点赞4次,收藏40次。DIY一款基于MySensors的ESP8266+NRF24L01的MQTT(WIFI)和RF无线网关(二)正式DIY正式DIY一、本文参考的国外DIY项目二、本文采用的模块和连接线路1、ESP8266模块2、NRF24L01+ PA版(即所谓的功率增强版)3、硬件连接线路三、在Arduino下载安装MySensors软件库和其他第三方库1、安装MySensors软件库2、Adafruit_Neo..._esp8266接nrf24
文章浏览阅读1.5k次。随着我国“老龄化”问题的日益加重,养老已经成为一个十分严峻的社会话题。数据显示,2018年的时候,我国60岁以上的老龄人口已经达到了2.49亿,这是一个十分庞大的数字。面对需要养老的人群越来越多,全社会的养老压力也越来越大,如果仅仅靠单纯增加人力、物力的投入,基本无法满足未来养老需求的,因此“智慧养老”应运而生。说起智慧养老,很多人都会觉得非常的陌生。其实,智慧养老是面向居家老人、社区及智慧养老机构的传感网系统与信息平台,并在此基础上提供实时、快捷、高效、低成本的,物联化、互联化、智能化的养老服务。..._基于android的智慧养老app的设计与实现
文章浏览阅读813次。微信小程序 swiper禁止手动切换给swiper设置catchtouchmove为true,设置swiper-item的catchtouchmove返回false<swiper class="swiper" indicator-dots="{{false}}" circular autoplay="{{true}}" vertical="{{true}}" interval="{{3000}}" duration="{{300}}" easing-functio_微信小程序swiper组件如何停止循环切换
文章浏览阅读2.4k次,点赞5次,收藏12次。Linux tracepoint 简介和相应的实现原理_tracepoint