L03 CSharp 调用 xLua

**1.C#调用Lua变量 **

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void Start()
{
xLuaEnv.Instance.DoString("return require('L2C/CsharpCallVariable')");
//LuaEnv 提供了个成员变量 Globa1,它可以用于 C#获取 Lua 的全局变量
//Global 的数据类型是 c#实现的 LuaTable.LuaTable 是×Lua 实现的 c#和 Lua 中表对应的数据结构
//xLua 会将 Lua 中的全局变量以 Tab1e 的方式全部存储在 G1obal 中
//通过运行环境,导出全局变量,类型是 LuaTable
//LuaTab1e 是 c#的数据对像,用于和 Lua 中的全局变量存储的 tablej 对应
LuaTable g = xLuaEnv.Instance.Global;

//从 Lua 中,将全局变量提取出来/参数:Lua 中全局变量的名称
//类型:Lua 中全局变量的名称所对应的类型/返回值:变量的值
int num = g.Get<int>("num");
float rate = g.Get<float>("rate");
bool isWoman = g.Get<bool>("isWoman");
string name = g.Get<string>("name");
Debug.Log("数字:" + num);
Debug.Log("浮点数:" + nun;
Debug.Log("布尔:" + num);
Debug.Log("字符串:" + num);
}
1
2
3
4
5
//隐性做了{num=108.rate=99.99.isWoman=fa1se.name="admin")
num 100
rate = 99.99
isWoman = false
name = "admin"

**2.C#调用Lua函数 **

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func1 function()
print("这是 Lua 中的 func1")
end

func2 function(name)
print("这是 Lua 中的 func2,参数是:" ..name)
end

func3 function()
return "这是 Lua 中的 func3"
end

func4 function()
return "这是 Lua 中的 func4",100
end

Read More

AB包

加载AB包

1
AssetBundle ab = AssetBundle.loadFromFile(Appliaction.streamingAssetsPath+ "/" + "modle");

加载包中资源

1
2
GameObject obj = ab.LoadAsset<GameObject>("Cube");
Instantiate(obj);

异步加载

1
2
3
4
AssetBundle ab = AssetBundle.loadFromFileAsync(Appliaction.streamingAssetsPath+ "/" + "modle");

GameObject obj = ab.LoadAssetAsync<GameObject>("Cube");
Instantiate(obj);

Read More

L01 xLua 基础

1.c# 调用 lua

1
2
3
4
5
6
7
8
9
void Start(){
//lua 是解释型语言,所以需要获得 1ua 的解析器
//xLua 解析器获得
LuaEnv env new LuaEnv();
//解析器运行 Lua 代码,把字符串当成 Lua 代码执行
env.DoString("print('Hello world!')");
//解析器释放
env.Dispose();
}

**2.lua 调用 c# **

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void Start() {
//LuaCallCSharpCode();
LuaReturnData();
//使用 Lua 调用 C#代码
}

public void LuaCallCSharpCode() {
LuaEnv env new LuaEnv();
//Lua 调用 C#代码(C5.命名空间.类名.方法名(参数))
env.DoString("CS.UnityEngine.Debug.Log('from lua')");
env.Dispose();
}
//Lua 返回值给 C#
public void LuaReturnData() {
LuaEnv env new LuaEnv();
object[]data env.DoString("return 100.true");
Debug.Log("Lua 的第一个返回值:"+data[o].ToString());
Debug.Log("Lua 的第二个返回值:"+data[1].ToString());
env.Dispose();
}

3.Lua加载器

1
2
3
4
5
6
7
void Start(){
LuaEnv env new LuaEnv();
//对应 test.1ua
//内置加载器会扫描预制的目录,查找是否存在 test,1ua /xLua 存在默认加载器,StreamingAssets 目录下可以加载文件
env.DoString("require('test')");
env.Dispose();
}

Read More

04.反射

Type

1.获取Type

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Type(类的信息类)
//它是反射功能的基础!
//它是访问元数据的主要方式。
//使用 Type 的成员获取有关类型声明的信息
//有关类型的成员(如构造函数、方法、字段、属性和类的事件)

#region 获取 Type
//1.万物之父 object 中的 GetType() 可以获取对象的 Type
int a = 42;
Type type = a.GetType();
Console.WriteLine(type);

//2.通过 typeof:关键字传入类名也可以得到对象的
Type type2 = typeof(int);
Console.WriteLine(type2);

//3.通过类的名字也可以获取类型
//注意类名必须包含命名空间不然找不到
Type type3 = Type.GetType("System.Int32");
Console.WriteLine(type3);
#endregion

2.获取程序集信息 Assembly

Read More

数据持久化:二进制

L1各数据转字节

1
2
3
4
5
6
7
8
9
10
11
byte[] bytes = BitConverter.GetBytes(1 << 6);
PrintByte(bytes);
//字节数组转类型
var i = BitConverter.ToInt32(bytes, 0);
print(i);
//字符串指定编码转字节
byte[] bytes1 = Encoding.UTF8.GetBytes("你好世界");
PrintByte(bytes1);
//字节转字符串
string byteString1 = Encoding.UTF8.GetString(bytes1);
print(byteString1);

L2文件操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
//1.判断文件存在
print(File.Exists(Application.dataPath + "/../Lesson"));
//2.创建文件
//FileStream fs = File.Create(Application.dataPath + "/Test.Test");
//3.写入文件
byte[] bytes = Encoding.UTF8.GetBytes("你好世界");
byte[] bytes1 = BitConverter.GetBytes(1 << 8);
File.WriteAllBytes(Application.dataPath + "/Test.Test", bytes1);
//将指定的 string 数组内容一行行写入到指定路径中
string[] strings = new string[] { "sdad", "dsadw" };
File.WriteAllLines(Application.dataPath + "/Test1.Test", strings);
//将指定字符串写入指定路径
string strings1 = "\n你好世界\r\n";
File.WriteAllText(Application.dataPath + "/Test2.Test", strings1);
//4.读取文件
bytes = File.ReadAllBytes(Application.dataPath + "/Test.Test");
PrintByte(bytes);
strings = File.ReadAllLines(Application.dataPath + "/Test1.Test");
PrintStrings(strings);
strings1 = File.ReadAllText(Application.dataPath + "/Test2.Test");
print(strings1);
//5.删除
File.Delete(Application.dataPath + "/Test.Test");
//6.复制文件
// 参数一:现有文件,需要是流关闭状态
// 参数二:目标文件
// 参数三:是否覆盖
File.Copy(AssetURL("Test1.Test"), AssetURL("Test2.Test"), true);
//7.文件替换
// 参数一:用来替换的路径
// 参数二:被替换的路径
// 参数三:备份路径
File.Replace(AssetURL("Test2.Test"), AssetURL("Test1.Test"), AssetURL("Test2Copy.Test"));
//8.以流的形式打开文件并写入或读取
//参数一:路径
//参数二:打开模式
//参数三:访问模式
FileStream fs = File.Open(AssetURL("Test1.Test"), FileMode.OpenOrCreate, FileAccess.Read);

//辅助函数
private String AssetURL(string url)
{
return Application.dataPath + "/" + url;
}

private void PrintByte(byte[] bytes)
{
var byteStr = "";
foreach (byte b in bytes)
{
byteStr += b;
}
print(byteStr);
}
private void PrintStrings(string[] strings)
{
var byteStr = "";
foreach (string b in strings)
{
byteStr += b;
}
print(byteStr);
}`

L3文件流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#region 1.打开或创建指定文件
//方法-:new Filestream
//参数一:路径
//参数二:打开模式
//CreateNew: 创建新文件如果文件存在则报错
//Create: 创建文件,如果文件存在则覆盖
//Open: 打开文件,如果文件不存在报错
//OpenorCreate: 打开或者创建文件根据实际情况操作
//Append: 若存在文件,则打开并查找文件尾,或者创建一个新文件
//Truncate: 打开并清空文件内容
//参数三: 访问模式
//参数四: 共享权限
//None 谢绝共享
//Read 允许别的程序读取当前文件
//Write 允许别的程序写入该文件
//ReadWrite 允许别的程序读写该文件
FileStream fs = new FileStream(PeresistentURL("TestNew.Test"), FileMode.OpenOrCreate, FileAccess.ReadWrite);

//方法三:Fi1e.0pen
//参数一:路径
//参数二:打开模式
FileStream fs1 = File.Open(PeresistentURL("TestNew1.Test"), FileMode.Open);
fs1.Close();
fs1.Dispose();
//方法二:File.Create
//参数一路径
//参数二:缓存大小
//参数三:描述如何创建或覆盖该文件(不常用)
//Asynchronous 可用于异步读写
//DeleteOnclose 不在使用时,自动删除
//Encrypted 加密
//None 不应用其它选项
//RandomAccess 随机访问文件
//Sequentialscan 从头到尾顺序访问文件
//WriteThrough 通过中间缓存直接写入磁盘
FileStream fs2 = File.Create(PeresistentURL("TestNew1.Test"), 2048);
fs2.Close();
fs2.Dispose();
#endregion

#region 2.属性方法
//1. 是否可写
if (fs.CanRead) { }
//2.是否可读
if (fs.CanWrite) { }
//3.将字节写入文件当写入后一定执行一次
fs.Flush();
//4.关闭流当文件读写完毕后一定执行
fs.Close();
//5.缓存资源销毁回收
fs.Dispose();
#endregion

#region 3.写入字节
//方法:Write
//参数一:写入的字节数组
//参数二:数组中的开始索引
//参数三:写入多少个字节
using (fs = new FileStream(PeresistentURL("TestNew.Test"), FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
byte[] bytes = BitConverter.GetBytes(1 << 8);
fs.Write(bytes, 0, bytes.Length);

//写入字符串时
bytes = Encoding.UTF8.GetBytes("hello world");
//先写入长度
byte[] length = BitConverter.GetBytes(bytes.Length);
fs.Write(length, 0, length.Length);
//再写入字符串具体内容
fs.Write(bytes, 0, bytes.Length);

fs.Flush();//3.将字节写入文件当写入后一定执行一次
fs.Close(); //5.缓存资源销毁回收
};

#endregion

#region 4.读取字节
//方法一
using (fs = File.Open(PeresistentURL("TestNew.Test"), FileMode.Open, FileAccess.Read))
{
//参数一:用于存储读取的字节数组的容器
//参数二:容器中开始的位置
//参数三:读取多少个字节装入容器
//返回值:当前流索引前进了几个位置
byte[] bytes2 = new byte[4];
int index = fs.Read(bytes2, 0, 4);
int i = BitConverter.ToInt32(bytes2, 0);
print("取出来的第一个整数" + i);//999
print("索引向前移动" + index + "个位置");

//读取第二个字符串
//读取字符串字节数组长度
index = fs.Read(bytes2, 0, 4);
print("索引向前移动" + index + "个位置");
int length1 = BitConverter.ToInt32(bytes2, 0);
bytes2 = new byte[length1];
index = fs.Read(bytes2, 0, length1);
print("索引向前移动" + index + "个位置");
//得到最终的字符串打印出来
print(Encoding.UTF8.GetString(bytes2));

fs.Flush();
fs.Close();
}

//方法二 一次性读取长度
using (fs = File.Open(PeresistentURL("/TestNew.Test"), FileMode.Open))
{
print("=============================");
//一开始就申明一个和文件字节数组长度一样的容器
byte[] bytes3 = new byte[fs.Length];
fs.Read(bytes3, 0, bytes3.Length);
fs.Dispose();
//读取整数
print(BitConverter.ToInt32(bytes3, 0));
//读取字符串字节数组的长度
int length2 = BitConverter.ToInt32(bytes3, 4);
//得到字符串
print(Encoding.UTF8.GetString(bytes3, 8, length2));
}
#endregion

#region 知识点三更加安全的使用文件流对象
//using 关键字重要用法
//using (申明一个引用对象) I
//使用对象
//无论发生什么情况当 using 语句块结束后会自动调用该对象的销毁方法避免忘记销毁或关闭流
//using 是一种更安全的使用方法/强调:
//目前我们对文件流进行操作为了文件操作安全都用 using 来进行处理最好
#endregion


private String AssetURL(string url)
{
return Application.dataPath + "/" + url;
}

private String PeresistentURL(string url)
{
print(Application.persistentDataPath + "/" + url);
return Application.persistentDataPath + "/" + url;
}

Read More

02.迭代器:遍历集合

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MySetIEnumerator : IEnumerator {//实现IEnumerator
public object Current
{
get {return null}
}
public bool MoveNext()
{
return false;
}
public void Reset()
{

}

解释:

1.Current : 为对象中的当前元素
2.MoveNext 为是否到下一个元表并

实现一个迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class MysetIEnumerator<T> : IEnumerator
{
private int positin;
private MySet<T> myset;//自定义的集合与List差不多
private MySetIEnumerator( MySet <T> myset)
{
position = -1;
this.myset = myset;
}

public object Current
{
get {return myset[position]}
}

public bool MoveNext()
{
position++;
if(position < myset.Count)
{
return true;
}
return false;
}
public Reset()
{
position = -1;
}
}

为自定义集合挂载迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Public cluss Myset<T> : IEnumerable
{
//......
public IEnumerator GetEnumeratr()//实现接口
{
return new MySetIEnumerator<T>(this);
}

//方法二
public IEnumerator GetEnumerator()
{
for(int i; i< _size;i++)
{
yeild return item[i];//挂起一帧
}
}
}

Read More