Lua笔记

了解AB包

什么是AB包

AssetBundle简称AB包
它是特定于平台的资产压缩包,有点类似压缩文件
资产包括:模型、贴图、预设体、音效、材质球等等

AB包的作用

相对Resources下的资源AB包更好管理资源


1.能够减小包体大小:压缩资源、减少初始包大小
2.能够实现热更新:资源热更新、脚本热更新

AssetBundle Browser使用

其他选项作用:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class ABTest : MonoBehaviour
{
    public Image img;
    void Start()
    {
        //关于AB包的依赖一个资源身上用到了别的AB包中的资源 这个时候 如果只加载自己的AB包
        //通过它创建对象 会出现资源丢失的情况
        //这种时候 需要把依赖包 一起加载了 才能正常

        //第一步加载AB包
        AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath+'/' + "model");
        //加载依赖包
        //AssetBundle ab2 = AssetBundle.LoadFromFile(Application.streamingAssetsPath + '/' + "texture");

        //往往不会主动加载依赖包,因为一个资源包可能依赖很多其他的资源包,自己一个一个加很麻烦

        //利用主包来得到依赖信息
        //加载主包
        AssetBundle abMain = AssetBundle.LoadFromFile(Application.streamingAssetsPath + '/' + "PC");
        //加载主包中的固定文件
        AssetBundleManifest abManifest = abMain.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
        //从固定文件中得到依赖信息
        string[] strs = abManifest.GetAllDependencies("model");
        for(int i = 0 ; i < strs.Length; i++)
        {
            AssetBundle.LoadFromFile(Application.streamingAssetsPath + '/' + strs[i]);
            Debug.Log(Application.streamingAssetsPath + '/' + strs[i]);
        }
        //第二步加载AB包中的资源
        //只用名字加载会出现同名不同类型资源分不清的问题
        //GameObject obj = ab.LoadAsset<GameObject>("Cube");
        GameObject obj = ab.LoadAsset("Cube", typeof(GameObject)) as GameObject;//lua不支持泛型故建议使用这种
        Instantiate(obj);

        //卸载当前AB包,true为同时删除该包加载出来的资源
        //ab.Unload(false);

        //AB包不能重复加载 否则会报错
        //GameObject obj1 = ab.LoadAsset("Sphere",typeof(GameObject)) as GameObject;
        //Instantiate (obj1);

        
        //异步加载->协程
        //StartCoroutine(LoadABRes("texture", "CPU-Cache"));

    }
    IEnumerator LoadABRes(string ABname,string resName)
    {
        //加载AB包
        AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + '/' + ABname); 
        yield return abcr;
        //加载资源
        AssetBundleRequest abq = abcr.assetBundle.LoadAssetAsync(resName, typeof(Sprite));
        yield return abq;
        img.sprite = abq.asset as Sprite;
    }
    // Update is called once per frame
    void Update()
    {
        //卸载所有加载的AB包 参数若为true 会把通过AB包加载出来的资源也卸载
        if(Input.GetKeyDown(KeyCode.Space)){
            AssetBundle.UnloadAllAssetBundles(true);
        }
    }
}

Lua语法

输出和注释

--末尾不用写分号(单行注释)
print("Hello World")
--[[
多行
注释一
]]

--[[
多行
注释二
]]--

--[[
多行
注释三
--]]

变量

lua中所有的变量申明都不需要申明变量类型,它会自动判断类型,可以随便赋值

nil:类似于C#中的null

number:所有数值都是number

string:用双引号或者单引号包裹(没有char)

bool:true/false

可以通过type()函数得到变量类型,type的返回值是string

a = nil
print(a)
print(type(a))
a=1
print(a)
print(type(a))
a= 1.2
print(a)
print(type(a))
a="123123"
print(a)
print(type(a))
a='123'
print(a)
print(type(a))
a=true
print(a)
a=false
print(a)
print(type(a))

输出如下:

lua中使用没有申明的变量(没赋值过的)不会报错,默认值是nil

print(b)

字符串

获取字符串长度

s="123456"
print(#s)
--一个汉字字符占三个长度 英文字符占一个长度
s1="一"
print(#s1)

多行打印

--lua中支持转义字符
print("123\n123")

s = [[1
2
3
4
]]
print(s)

字符串拼接

--字符串拼接通过..
print("123".."456")
s1 = 1
s2 = "2"
print(s1..s2)
s2=2
print(s1..s2)
print(string.format("abcde123%d","4"))

字符串转换

--别的类型转字符串
a = true
print(tostring(a))
a = 123
print(tostring(a))

常用方法

a = "abcDEF"
--大写转小写
print(string.upper(a))
--小写转大写
print(string.lower(a))
--翻转字符
print(string.reverse(a))
--字符串索引查找(索引从1开始)
print(string.find(a,"abc"))
--截取字符串
print(string.sub(a,3))
print(string.sub(a,3,5))
--字符串重复
print(string.rep(a,1))
--字符串修改
print(string.gsub("abcde123","%a","4"))
print(string.gsub("abcde123","a","4"))
print(string.gsub("abcde123","%A","4"))

--字符转ASCII码
a = string.byte("Lua",1)
print(a)

--ASCII码转字符
print(string.char(a))

运算符

算术运算符

+ - * / %
没有自增自减(++ --)没有复合运算符(+= -= /= *= %=)

print("add"..1+2)
a = 1
b = 2
print(a+b)
--字符串自动转换成number
print("123.4"+1)

--幂运算^
print(2^5)

条件运算符

不等于符号:~=

print(1>3)
print(1>=3)
print(1<3)
print(1<=3)
print(1==3)
print(1~=3)

逻辑运算符

与:and,或:or
非: not

逻辑运算支持短路:and前有false and后的不会执行,or前有true or后的不会执行

print(true and false)
print(true and true)

print(false or true)
print(false or false)
print(not true)
print(true and print("123"))

位运算符

不支持位运算,需要自己实现或者使用库

三目运算符

不支持三目运算

条件分支语句 

a = 9
if a > 5 then
	print("111")
end

if a < 5 then
	print("111")
else
	print("222")
end

if a < 5 then
	print("111")
elseif a == 6 then
	print("6")
elseif a == 6 then
	print("7")
else
	print("other")
end
--lua中没有switch语句,要自己实现

循环语句

while语句

a = 0

while a < 5 do
	print(a)
	a = a + 1
end

do while语句

a = 0
repeat 
	print(a)
	a = a + 1
until a > 5 --满足条件跳出 结束条件

for语句

for i = 2 , 5 do--默认递增 i会+1
	print(i)
end

for  i = 1,5,2 do
	print(i)
end

for i = 5, 1,-1 do
	print(i)
end

函数

无参无返回值

--function  函数名()
--end

--a = function()
--end

function F1()
	print("F1")
end
F1()

F2 = function()
	print("F2")
end
F2()

有参

function F3(a)
	print(a)
end
F3(1)
F3("123")
F3(true)
F3()
F3(1,2,3)
--传入参数不匹配,会自动补空nil 或者丢弃多余参数

有返回值

function F4( a )
	return a , "123" , true
end
--返回多个值时 在前面申明多个变量来接取即可
--如果变量不够 接取对应前几个参数
--如果变量多了 多的几个值为nil
temp = F4("123")
print(temp)
temp , temp1 , temp2 , temp3= F4("123")
print(temp)
print(temp1)
print(temp2)
print(temp3)

函数类型

统一是function类型

F5 = function()
	print("123")
	return  "123"
end
print(type(F5))

函数重载

lua中函数不支持重载,默认使用最近的一次申明的函数

function F6( str )
	print(str)
end

function F6()
	print("111")
end
F6("222")

 输出为111

变长参数 

function F7( ... )
	arg = {...}
	for i  = 1 , #arg do
		print(arg[i])
	end
end
F7(1,"123",true,4,5,6,7)

函数嵌套

function F8()
	return function ()
		print("123")
	end
end

f9 = F8()
f9()

--闭包
function F9(x)
	a = 1
	return function ( y )
		return x + y +a
	end
end
--父函数的参数在子函数中仍可使用
f10 = F9(10)
print(f10(5))

复杂数据类型——表

所有复杂类型都是table(表 )

数组及其遍历

a = {1,2,3,4,5,"123",true,nil,nil}
--末尾nil不计入数组长度
for i = 1,#a,1 do
	print(a[i])
end
--中间的nil计入长度
a = {1,2,nil,4,5,"123",true,nil}
print(#a)
for i = 1,#a,1 do
	print(a[i])
end

二维数组

a = {{1,2,3},{4,5,6}}
print(a[1][1])
print(a[1][2])
print(a[1][3])

二维数组遍历

for i = 1,#a do
	b = a[i]
	for j = 1,#a[i] do
		print(b[j])
	end
end

自定义索引

a = {[0] = 0,1,2,[-1] = -1,5}
print(#a)
for i = 1,#a do
	print(a[i])
end
print(a[0])
print(a[-1])

由于 使用#来得到长度遍历 有时会出现bug故更多使用迭代器遍历

迭代器遍历

ipairs遍历
a = {[0] = 1 , 2, [-1] = 3, 4, 5,[5] = 6}

--ipairs遍历 从1开始往后遍历,小于0的键找不到
--只能找到连续索引的键如果中间断序了 就无法遍历后面的内容
for i,k in ipairs(a) do
	print(i..":"..k)
end
pairs遍历
--pairs遍历能够找到所有的键
for i,k in pairs(a) do
	print(i..":"..k)
end

for i in pairs(a) do
	print("key:"..i)
end

复杂数据类型——字典

a = {["name"] = "111",["age"] = 11,["1"] = 5}
--可以通过中括号中填键来访问值
print(a["name"])
print(a["age"])
print(a["1"])
--还可以用类似成员变量的形式来得到值,但不能是数字
print(a.name)
print(a.age)

--修改
a.name = "222"
a["age"]=100
print(a.name)
print(a.age)
--新增
a["sex"] = false
print(a.sex)
--删除
a["sex"] = nil
print(a["sex"])

--遍历要用 pairs
for k,v in pairs(a) do
	--print可以传入多个参数
	print(k,v)
end
for k in pairs(a) do
	--print可以传入多个参数
	print(k)
	print(a[k])
end

复杂数据类型——类和结构体

--lua中默认没有面向对象,需要我们自己来实现
--lua中类的表现是类中的有很多静态变量和静态函数,直接用类名来调用
Student = {
	age = 11,
	sex = true,
	f = function ()
		print("f1")
	end,
	f2 = function ()
		print("f2")
	end
}
print(Student.age)
Student.f()

--申明表后在表外也可以申明新的变量和方法
Student.name = "aaa"
Student.f3 = function ()
	print("f3")
end
function Student.f4()
	print("f4")
end
Student.f3()
print(Student.name)
Student.f4()

想要在表内部函数中调用表本身属性或者方法要指明是哪个表的
故使用 表名.属性  表名.方法 来访问,也可以通过传入参数的形式进行访问
 

Student = {
	age = 11,
	sex = true,
	f = function ()
		print(Student.sex)
		print("f1")
	end,
	f2 = function (t)
		print(t.sex)
		print("f2")
	end
}
Student.f2(Student)
Student.f()
Student:f2()

function Student:f5()
	--lua中关键字self表示冒号申明函数传入的第一个参数
	print(self.age)
end
Student:f5()
Student.f5(Student)

lua中.和:的区别: 冒号调用方法会默认把调用者作为第一个参数传入

表的公共操作

t1 = {{age = 1,name = "123"},{age = 2, name = "345"}}
t2 = {name = "name",sex = true}
--插入
print(#t1)
table.insert(t1,t2)
print(#t1)
print(t1[3].sex)

--删除指定元素
--没有第二个参数默认移除最后一个索引的内容
table.remove(t1)
print(#t1)
print(t1[1].name)
print(t1[2].name)
print(t1[3])
--第二个参数为要移除内容的索引
table.remove(t1,1)
print(t1[1].name)
print(#t1)
--排序
t2 = {5,2,7,9,5}
--默认升序
table.sort(t2)
for _,v in pairs(t2) do
	print(v)
end
--降序排序
table.sort(t2,function(a,b)
	if a>b then
		return true
	end
end)
for _,v in pairs(t2) do
	print(v)
end

--拼接 
tb = {"123","456","789","10101"}
--用于拼接表中元素,返回值是一个字符串,有一定限制,bool和nil不能拼接
str = table.concat( tb, ", ")
print(str)

多脚本执行

全局变量和本地变量

--全局变量
a = 1
b = "123"
for i =  1,2 do
	c = "aaa"
end
print(c)
--局部变量
for i =  1,2 do
	local d = "aaa"
	print(d)
end
print(d)
fun = function ()
	tt = "123123"
end
print(tt)
fun()
print(tt)

多脚本执行

--关键字 require("脚本名")
require("Test")--同一目录下
print(x)--别的脚本的局部变量不可访问,但是可以通过return的方式返回该局部变量使用

Test

print("Test")
testA = "123"
local x = "456"

local的x在另一个脚本中无法访问 

脚本卸载

--如果是require加载执行的脚本  加载一次过后不会再被执行
require("Test")
--package.loaded["Test"]返回bool值,意为改脚本是否被执行
print(package.loaded["Test"])
--卸载已执行过的脚本
package.loaded["Test"] = nil--false也可
print(package.loaded["Test"])
require("Test")

大G表

for k,v in pairs(_G) do
	print(k,v)
end
--局部变量不会存入大G表中

特殊用法 

多变量赋值

a,b,c=1,2,"123"
print(a)
print(b)
print(c)
--多变量赋值 如果后面的值不够 会自动补空
a,b,c = 1,2
print(a)
print(b)
print(c)--ni1
--多变量赋值 如果后面的值多了 会自动省略
a,b,c=1,2,3,4,5,6
print(a)
print(b)
print(c)

多返回值

见函数有返回值内容

and or

--逻辑与 逻辑或
--and or 他们不仅可以连接 boolean 任何东西都可以用来连接
--在lua中 只有 ni1 和 false 才认为是假
--"短路"见逻辑运算符中的解释
--
print( 1 and 2)
print(0 and 1)
print( nil and 1)
print(false and 2)
print(true and 3)
print(true or 1)
print( false or 1)
print( nil or 2)

用and or 来模拟三目运算符

x = 1
y = 2
res = (x>y) and x or y
print(res)

协程

创建

fun = function()
	print("123")
end
--该方法创建协程类型本质是一个线程
co = coroutine.create(fun)
print(co)
print(type(co))
--该方法创建协程本质是一个函数
co2 = coroutine.wrap(fun)
print(co2)
print(type(co2))

运行

--第一种创建方式对应的运行方式
coroutine.resume(co)
--第二种穿件方式对应的运行方式 
co2()

挂起

fun2 = function ()
	local i = 1
	while true do
		print(i)
		i = i + 1
		--挂起函数
		coroutine.yield(i)
	end
end
co3 = coroutine.create(fun2)
--返回值第一个为协程是否启动成功,第二个为yield返回的值
isOk,tempI = coroutine.resume(co3)
print(isOk,tempI)
isOk,tempI = coroutine.resume(co3)
print(isOk,tempI)
--这种方式的协程调用直接返回yield返回的值
co4 = coroutine.wrap(fun2)
print("111"..co4())
print("111"..co4())

状态

--coroutine.status(协程对象)
--dead 结束
--suspend 挂起
--running 进行中
print(coroutine.status(co3))
print(coroutine.status(co))

--这个函数可以得到当前正在运行的协程的线程号
print(coroutine.running(co3))

在协程函数中print(coroutine.status(co3))才能显示running

元表

元表概念

任何表变量都可以作为另一个表变量的元表

任何表变量都可以有自己的元表(父表)

当子表中进行一些特定的操作时,会执行元表中的内容

设置元表

meta = {}
myTable = {}
--设置元表函数
--第一个参数子表
--第二个参数元表
setmetatable(myTable,meta)

特定操作

__tostring
meta2 = {
	--当子表要被当做字符串使用时会默认调用这个元表中的tostring方法
	__tostring = function ()
		return "aaaa"
	end
}
myTable2 = {}
--设置元表函数
--第一个参数子表
--第二个参数元表
setmetatable(myTable2,meta2)
print(myTable2)

meta3 = {
	--默认传入调用者本身
	__tostring = function (t)
		return t.name
	end
}
myTable3 = {
	--不会使用子表的tostring
	__tostring = function()
		print("123")
	end,
	name = "name"
}
setmetatable(myTable3,meta3)
print(myTable3)
__call
meta4 = {
	__tostring = function (t)
		return t.name
	end,
	--当子表被当做 一个函数使用时会默认调用__call函数
	--当希望传入参数时,默认第一个参数是调用者自己类似于 冒号调用方法
	__call =  function(a,b)
		print(a)
		print(b)
		print("call")
	end
}
myTable4 = {
	name = "name"
}
setmetatable(myTable4,meta4)
myTable4(1)
运算符重载
meta5 = {
	--相当于运算符重载 当子表用到+运算符时会调用该方法
	__add = function(t1,t2)
		return t1.age+t2.age
	end,
	--减法
	__sub = function (t1,t2)
		return  t1.age-t2.age
	end,
	--乘法 
	__mul = function (t1,t2)
		return 1
	end,
	--除法 __div
	__div = function (t1,t2)
		return 2
	end,
	--除法 __mod
	__mod = function (t1,t2)
		return 3
	end,
	--阶乘 __pow
	__pow = function (t1,t2)
		return 4
	end,
	-- ==  __eq
	__eq= function (t1,t2)
		return true
	end,
	-- <  __lt
	__lt= function (t1,t2)
		return true
	end,
	--<=   __le
	__le= function (t1,t2)
		return false
	end,
	-- ..(连接运算符) __concat
	__concat =function (t1,t2)
		return "12345"
	end,
	--没有大于

}
myTable5 = {age =1}
myTable6 = {age =2}
setmetatable(myTable5,meta5)
print(myTable5+myTable6)
print(myTable5-myTable6)
print(myTable5*myTable6)
print(myTable5/myTable6)
print(myTable5%myTable6)
print(myTable5^myTable6)
--如果要用 条件运算符来比较两个对象
--这两个对象的元表必须一致 才能准确调用方法
setmetatable(myTable6,meta5)
print(myTable5==myTable6)
print(myTable5<myTable6)
print(myTable5<=myTable6)
print(myTable5..myTable6)
__index和_newIndex
--__index会层层向上找到含有该值的表,没找到则返回nil
meta7Father = {
	age = 1
}
meta7Father.__index = meta7Father
meta7 = {
	--meta7.__index  = meta7 这样写最后输出的是nil故最好写在外面
 	age = 5
}
meta7.__index  = meta7
--也可以直接指向别的表meta7.__index  = {age =3}
--建议将__index写在外面,写在里面会导致指向自己时出现bug
myTable7 = {

}
setmetatable(meta7,meta7Father)
setmetatable(myTable7,meta7)

--__index 当子表中 找不到一个属性时
--会到元表中 __index指定的表去找索引
--得到元表
print(getmetatable(myTable7))
--仅在当前表中寻找是否含有该键
print(rawget(myTable7,"age"))
print(myTable7.age)
--如果子表中找不到要赋值的索引
--那么会一层一层向上找 找到含有该索引的表中进行赋值
meta8 = {

}
meta8.__newindex = {age = 6}
myTable8 = {

}
setmetatable(myTable8,meta8)
myTable8.age = 1
print(myTable8.age)
--只改变当前表中的值
rawset(myTable8,"age",5)
print(myTable8.age)
print(meta8.__newindex.age)

面向对象

封装

Object  =  {}
Object.id = 1
function Object:Test()
	print(self.id)
end
function Object:new()
	local obj = {}
	self.__index = self

	setmetatable(obj,self)
	return obj 
end
local myObj = Object:new()
print(myObj)
print(myObj.id)
myObj:Test()
--在子表(空表)中申明了id属性
myObj.id  = 2
myObj:Test()
-- function myObj:Test()
-- 	print("test")
-- end
-- myObj:Test()

继承

function Object:subClass(className)
	_G[className] = {}
	--写继承相关的规则
	--用到元表
	self.__index = self
	local obj =_G[className]
	setmetatable(obj,self)
end

Object:subClass("Person")
print(Person)
print(Person.id)

local  p1 = Person:new()
print(p1.id)
p1.id = 100
print(p1.id)
p1:Test()

Object:subClass("Monster")
local m1 = Monster:new()
print(m1.id)
m1.id = 200
print(m1.id)
m1:Test()

多态

在继承时加一个base属性

function Object:subClass(className)
	_G[className] = {}
	--写继承相关的规则
	--用到元表
	self.__index = self
	local obj =_G[className]
	--子类  定义一个base属性 base代表父类
	obj.base = self
	setmetatable(obj,self)
end
Object:subClass("GameObject")
GameObject.posX=0;
GameObject.posY=0;
function GameObject:Move()
	self.posX = self.posX + 1
	self.posY = self.posY + 1
	print(self.posX)
	print(self.posY)
end
GameObject:subClass("Player")
function Player:Move()
	--base指的是GameObject表(类)
	--这种调用方式相当于把基类表作为第一个参数传入方法中,改变基类的值
	--所以我们要避免把基类表传入到方法中 这样就相当于是公用一张表的属性
	--self.base:Move()
	--若要使用父类函数 ,不要使用冒号调用要通过.调用传入自己 作为第一个参数
	self.base.Move(self)
end
local p1 = Player:new()
p1:Move()
p1:Move()
local p2 = Player:new()
p2:Move()

总结

Object = {}
--实例化对象方法
function Object:new()
	local obj = {}
	--给空对象设置元表以及元表的__index
	self.__index=self
	setmetatable(obj,self)
	return obj
end
--继承
function Object:subClass(className)
	--根据名字生成一张表 就是一个类
	_G[className] = {}
	local obj = _G[className]
	--设置自己的父类
	obj.base = self
	--给子类设置元表以及元表的__index
	self.__index = self
	setmetatable(obj,self)
end
--申明一个新的类
Object:subClass("GameObject")
--成员变量
GameObject.posX = 0
GameObject.posY = 0
--成员函数

--成员方法
function GameObject:Move()
	self.posX = self.posX + 1
	self.posY = self.posY + 1
end

local obj = GameObject:new()
print(obj.posX)
obj:Move()
print(obj.posX)

local obj2 = GameObject:new()
print(obj2.posX)
obj2:Move()
print(obj2.posX)
--申明新的类Player继承GameObject
GameObject:subClass("Player")
--多态 重写GameObject的Move方法
function Player:Move()
	--利用base调用父类方法将自己作为第一个参数传入
	self.base.Move(self)
end

--实例化Player对象
local p1 = Player:new()
print(p1.posX)
p1:Move()
print(p1.posX)
local p2 = Player:new()
print(p2.posX)
p2:Move()
print(p2.posX)

注意赋值操作会直接在当前对象中创建新的值,而不是到元表中去找,

冒号函数默认就是冒号前的对象的函数,调用时也不会再向上寻找

自带库

时间相关

--系统时间
print(os.time())
--自己传入参数 的到时间
print(os.time({year =2024,month = 3,day = 2}))
local nowTime =os.date("*t")
for k,v in pairs(nowTime) do
	print(k,v)
end
print(nowTime.hour)

 

数学运算

--绝对值
print(math.abs(-11))
--弧度转角度
print(math.deg(math.pi))
--三角函数 传弧度
print(math.cos(math.pi))
 
--向下向上取整
print(math.floor(2.6))
print(math.ceil(5.2))
 
--最大最小值
print(math.max(2,6))
print(math.min(5,2))
 
--小数分离 分成整数部分和小数
print(math.modf(1.2))
 
--幂运算
print(math.pow(2,5))

--随机数
--先设置随机数种子
math.randomseed(os.time())
print(math.random(100))
print(math.random(100))
--开方
print(math.sqrt(4)) 
 

路径相关

print(package.path)
package.path = package.path .. ";C:\\"
print(package.path)

Lua垃圾回收


test = {id = 1,name = "123"}
--垃圾回收关键字
--collectgarbage
--获取当前lua占用内存数 K字节 用返回值*1024 就可以得到具体的内存占用字节数
print(collectgarbage("count"))
--lua中的机制和C#中垃圾回收机制很类似 解除羁绊 就是变垃圾
test = nil
--进行垃圾回收类似于C#的GC
collectgarbage("collect")
print(collectgarbage("count"))
--lua中有自动定时进行GC的方法
--Unity中热更新开发尽量不要取用自动垃圾回收

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值