目录
LP科技:
1.说说Ngui和Ugui的区别×
1.UGUI界面展示是在画布下(Canvas),而NGUI是在UIRoot下
2.UGUI继承RectTransform,RectTransform继承Transform,而Ngui直接继承Transform
3.UGUI没有图集Atlas,是直接使用图片,而Ngui需要使用图集,对图集进行管理和维护
4.UGUI有锚点,可以自动适配屏幕,NGUI没有暂未发现此功能
5.UGUI中Btn需要有sprite,button,而NGUI只需要一个UIButton方法,和一个BoxCollider。
6.NGUI基于C#编写的,会产出比较多的GC,UGUI是基于C++,性能比较好。基于canvas渲染
2.xlua如何热更新、热补丁×
https://cloud.tencent.com/developer/article/2239496
lua解析器-LuaEnv+dostring(lua语句的require) --》》lua文件重定向 byte+addloader(File)--》》
C#掉lua:
1.获取全局变量gobal
2.接取函数。若自定义委托[CsharpCallLua],需要先生成Xlua代码,再运行。或者用action。或者用xlua的luafunction
3.lua映射List,Dic,浅拷贝(值拷贝)
4.C#自定义的类可以映射lua的表,浅拷贝(值拷贝)
4.接口用属性可以映射lua的表,[CsharpCallLua],
lua掉C#:
先用C#调用lua,打开入口。
--CS.命名空间.类名
--CS.命名空间.枚举名.枚举成员
用unity自带默认静态方法的用“.”;用类内的方法用“:”。
--Unity的类 比如 GameObject Transform等等 —— CS.UnityEngine.类名
--通过C#中的类 实例化一个对象 lua中没有new 所以我们直接 类名括号就是实例化对象
--默认调用的 相当于就是无参构造
local obj1 = CS.UnityEngine.GameObject()
local obj2 = CS.UnityEngine.GameObject("唐老狮")
--为了方便使用 并且节约性能 定义全局变量存储 C#中的类
--相当于取了一个别名
GameObject = CS.UnityEngine.GameObject
local obj3 = GameObject("唐老狮好爱同学们")
--类中的静态对象 可以直接使用.来调用
local obj4 = GameObject.Find("唐老狮")
--自定义类 使用方法 相同 只是命名空间不同而已
local t = CS.Test()
t:Speak("test说话")
--继承了Mono的类
--继承了Mono的类 是不能直接new
--GameObject(" ")前面有
local obj5 = GameObject("加脚本测试")
--通过GameObject的 AddComponent添加脚本
--xlua提供了一个重要方法 typeof 可以得到类的Type
--xlua中不支持 无参泛型函数 所以 我们要使用另一个重载
obj5:AddComponent(typeof(CS.LuaCallCSharp))
lua调C#数组
local array2 = CS.System.Array.CreateInstance(typeof(CS.System.Int32), 10)
print(array2.Length)
print(array2[0])
print(array2[1])
print(array2)
lua调C#List
--在Lua中创建一个List对象
--老版本
local list2 = CS.System.Collections.Generic["List`1[System.String]"]()
print(list2)
list2:Add("123")
print(list2[0])
--新版本 >v2.1.12
--相当于得到了一个 List<string> 的一个类别名 需要再实例化
local List_String = CS.System.Collections.Generic.List(CS.System.String)
local list3 = List_String()
list3:Add("5555555")
print(list3[0])
lua调C#字典:get_Item / set_Item
--在Lua中创建一个字典对象
--相当于得到了一个 Dictionary<string, Vector3> 的一个类别名 需要再实例化
local Dic_String_Vector3 = CS.System.Collections.Generic.Dictionary(CS.System.String, CS.UnityEngine.Vector3)
local dic2 = Dic_String_Vector3()
dic2:Add("123", CS.UnityEngine.Vector3.right)
for i,v in pairs(dic2) do
print(i,v)
end
--在Lua中创建的字典 直接通过键中括号得 得不到 是nil
print(dic2["123"])
print(dic2:TryGetValue("123"))
--如果要通过键获取值 要通过这个固定方法
print(dic2:get_Item("123"))
dic2:set_Item("123", nil)
print(dic2:get_Item("123"))
--我们不能直接将 lua函数传入到开启协程中!!!!!
--如果要把lua函数当做协程函数传入
--必须 先调用 xlua.util中的cs_generator(lua函数)
lua 热补丁
--我们必须做4个非常重要的操作
--1.加特性
--2.加宏 第一次开发热补丁需要加HOTFIX_ENABLE
--3.生成代码
--4.hotfix 注入 --注入时可能报错 提示你要引入Tools
--热补丁的缺点:只要我们修改了热补丁类的代码,我们就需要重新执行第4步!!!
--需要重新点击 注入
--lua当中 热补丁代码固定写法
--xlua.hotfix(类, "函数名", lua函数)
--xlua.hotfix(类, {函数名 = 函数, 函数名 = 函数....})
--lua当中 热补丁代码固定写法
--xlua.hotfix(类, "函数名", lua函数)
--成员函数 第一个参数 self
xlua.hotfix(CS.HotfixMain, "Add", function(self, a, b)
return a + b
end)
--静态函数 不用传第一个参数
xlua.hotfix(CS.HotfixMain, "Speak", function(a)
print(a)
end)
--xlua.hotfix(类, {函数名 = 函数, 函数名 = 函数....})
xlua.hotfix(CS.HotfixMain, {
Update = function(self)
print(os.time())
end,
Add = function(self, a, b )
return a + b
end,
Speak = function(a)
print(a)
end
})
xlua.hotfix(CS.HotfixTest, {
--构造函数 热补丁固定写法[".ctor"]!!!!
--他们和别的函数不同 不是替换 是先调用原逻辑 再调用lua逻辑
[".ctor"] = function()
print("Lua热补丁构造函数")
end,
--析构函数固定写法Finalize
Finalize = function()
end
})
热补丁协程【util,cs_generator】
--xlua.hotfix(类, {函数名 = 函数, 函数名 = 函数....})
--要在lua中配合C#协程函数 那么必使用它
util = require("xlua.util")
xlua.hotfix(CS.HotfixMain, {
TestCoroutine = function(self)
--返回一个正儿八经的 xlua处理过的lua协程函数
return util.cs_generator(function()
while true do
coroutine.yield(CS.UnityEngine.WaitForSeconds(1))
print("Lua打补丁后的协程函数")
end
end)
end
})
热补丁事件
--此时CS.HotfixMain已经有event UnityAction myEvent
xlua.hotfix(CS.HotfixMain, {
--add_事件名 代表着时间加操作
--remove_事件名 减操作
add_myEvent = function(self, del)
print(del)
print("添加事件函数")
--会去尝试使用lua使用C#事件的方法去添加
--在事件加减的重定向lua函数中
--千万不要把传入的委托往事件里存
--否则会死循环
--会把传入的 函数 存在lua中!!!!!
--self:myEvent("+", del)
end,
remove_myEvent = function(self, del )
print(del)
print("移除事件函数")
end
})
3.谈谈mvc与mvx的思想框架×
开发模式 MVC、MVP、MVVM和MVX框架模式 - 纭卿殇 - 博客园 (cnblogs.com)
MVC、MVP、MVVM架构 - 知乎 (zhihu.com)
三种架构模式——MVC、MVP、MVVM (yii666.com)
MVX框架模式的了解
MVX框架模式:MVC+MVP+MVVM
1、MVC:
Model(模型)+View(视图)+controller(控制器),主要是基于分层的目的,让彼此的职责分开。
View通过Controller来和Model联系,Controller是View和Model的协调者,View和Model不直接联系,基本联系都是单向的。【Model的业务数据改变触发相应事件,通知View业务数据已经发生改变】
用户User通过控制器Controller来操作模板Model从而达到视图View的变化。
2、MVP:
是从MVC模式演变而来的,都是通过Controller/Presenter负责逻辑的处理+Model提供数据+View负责显示。
在MVP中,Presenter完全把View和Model进行了分离,主要的程序逻辑在Presenter里实现。
并且,Presenter和View是没有直接关联的,是通过定义好的接口进行交互,从而使得在变更View的时候可以保持Presenter不变。
3、MVVM:
MVVM是把MVC里的Controller和MVP里的Presenter改成了ViewModel。Model+View+ViewModel。
View的变化会自动更新到ViewModel,ViewModel的变化也会自动同步到View上显示。
这种自动同步是因为ViewModel中的属性实现了Observer,当属性变更时都能触发对应的操作。
4.unity如何导航寻路
-
创建导航网格:
- 打开Unity编辑器,并确保你的场景已经包含了需要进行导航的地形和障碍物。
- 选择需要进行导航的地形区域。
- 在菜单栏中选择"Window" > "AI" > "Navigation"以打开导航窗口。
- 在导航窗口中,点击"Object"选项卡,并选择场景中的地形对象。
- 在"Navigation Area"中选择适当的导航区域类型,例如"Walkable"用于地面导航。
- 点击"Create"按钮,以生成导航网格。
-
设置导航代理:
- 在场景中放置一个代表可移动对象(通常是玩家角色)的GameObject。
- 添加一个NavMesh Agent组件到该GameObject上。
- 调整NavMesh Agent的半径、高度和其他属性,以确保它与导航网格相匹配。
-
寻路目标:
- 在脚本中,你可以通过访问NavMesh Agent组件来设置代理的目标位置。通常,你会使用
NavMeshAgent.destination
属性来设置目标点。
- 在脚本中,你可以通过访问NavMesh Agent组件来设置代理的目标位置。通常,你会使用
//agent 组件
agent.SetDestination(target.position);
/*---------------------------------------------------------------补充--------------------------------------------------------*/
1.AB包的上传与下载
AB相较Resource更灵活
1.减少包体大小-》1.压缩资源2.减少初始包大小
2.热更新-》1.资源热更新2.脚本热更新
AssetBuddleBrower【configure,Build,Inspect】
AB打包出的文件:AB资源文件,AB包文件信息,关键AB包(和目录名一样的包)
以下用例均来自B站唐老狮 ! ! !B站唐老狮 ! ! !B站唐老狮 ! ! !
同步加载【同一个AB包不能重复加载会报错(不能加载两次)!!】二步(非主包名)
// Start is called before the first frame update
void Start(){
//第一步 加载 AB包
AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "model");
//第二步 加载AB包中的资源//只是用名字加载 会出现 同名不同类型资源 分不清//建议大家用 泛型加载或者 是 Type指定类型
GameObject obj = ab.LoadAsset<GameObject>("Cube");
GameObject obj = ab.LoadAsset("Cube",typeof(GameObject)) as GameObject;
Instantiate(obj);
}
异步加载
void Start(){
StartCoroutine(LoadABRes("head23 1110001"));
}
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;
//image img
img.sprite=abq.asset as Sprite;
}
若存在依赖包则也要加载依赖包,四步(主包->固定文件->依赖信息->加载依赖包)
//依赖包的关键知识点一利用主包 获取依赖信息
//加载主包
AssetBundle abMain = AssetBundle.LoadFromFile(Application,streamingAssetsPath + "/"+ "pc");
//加载主包中的固定文件
AssetBundleManifest abManifest = abMain.LoadAsset<AssetBundleManifest>"AssetBundleManifest");
//从固定文件中 得到依赖信息
string[] strs = abManifest.GetAllDependencies("model");
//得到了 依赖包的名字
for (int i =@;i < strs.Length; i++)
AssetBundle,LoadFromFile(Application.streamingAssetsPath +"/" + strs[il);
2.C#调用文件夹、文件流
Unity 常用路径及获取目标路径下的所有文件_unity获取文件夹里所有文件_W-x-W的博客-CSDN博客
3.Scriptable
1.文件配置、2.数据复用、3.更好的处理数据带来的多态
但不具备持久化特性
以下用例均来自B站唐老狮 ! ! !
手动创建ScriptableObject
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "SettingInfo", menuName = "ScriptableObject/ÒôÀÖÒôЧÉèÖÃÐÅÏ¢")]
public class SettingInfo : ScriptableObject
{
//ÒôÀÖºÍÒôЧµÄ¿ª¹Ø
public bool musicIsOpen;
public bool soundIsOpen;
//ÒôÀÖºÍÒôЧµÄ ´óС
public float musicValue;
public float soundValue;
}
start创建
public SettingInfo info;
void Start(){
info = ScriptableObject.CreateInstance<SettingInfo>();
}
多态操作(利用一个基类,继承基类,再父类装子类)
public abstract class ItemEffect : ScriptableObject
{
public abstract void AddEffect(GameObject obj);
}
[CreateAssetMenu]
public class AddAtkItemEffect : ItemEffect
{
public int atk;
public override void AddEffect(GameObject obj)
{
//具体加多少攻击力的逻辑
}
}
[CreateAssetMenu]
public class AddHealthItemEffect : ItemEffect
{
public int num;
public override void AddEffect(GameObject obj)
{
//通过获取到的对象 让其加血了 加num的值
}
}
public class ItemObj : MonoBehaviour
{
public ItemEffect eff;
private void OnTriggerEnter(Collider other)
{
//为和物品产生碰撞的对象加效果
eff.AddEffect(other.gameObject);
}
}
4.InputSystem新输入系统
知识点二 选择开启哪一种输入模式
//选择Inputsystem和 老InputManager的启用情况
// File->Build Setting->Player Setting->0ther->Active Input Handling
//可以同时启用也可以只启用其中之一 每次启用后会重启Unity
//可以处理 任意键 下 拾起 长按 相关的逻辑
//keyBoard. anyKey
//wasPressedThisFrame
//wasReleasedThisFrame
//isPressed
#region 知识点二鼠标各键位 按下抬起 长按//鼠标左键
//mouse.leftButton
//鼠标右键
//mouse.rightButton
//鼠标中键
//mouse.middleButton
//鼠标向前向后键
//mouse.forwardButton;/ /mouse backButton
//按下
if(mouse.leftButton .wasPressedThisFrame){}
InputAction ->AddingBiding(输入) CallbackContext(回调数字)
void Start()
{
#region 知识点一 InputAction是什么?
//顾名思义,InputAction是InputSystem帮助我们封装的输入动作类
//它的主要作用,是不需要我们通过写代码的形式来处理输入
//而是直接在Inspector窗口编辑想要处理的输入类型
//当输入触发时,我们只需要把精力花在输入触发后的逻辑处理上
//我们在想要用于处理输入动作的类中
//申明对应的InputAction类型的成员变量(注意:需要引用命名空间UnityEngine.InputSystem)
#endregion
#region 知识点二 InputAction参数相关
#endregion
#region 知识点三 InputAction的使用
//1.启用输入检测
move.Enable();
//2.操作监听相关
//开始操作
move.started += TestFun;
//真正触发
move.performed += (context) =>
{
print("触发事件调用");
//当前状态
//没有启用 Disabled
//等待 Waiting
//开始 Started
//触发 Performed
//结束 Canceled
//context.phase
print(context.phase);
//动作行为信息
print(context.action.name);
//控件(设备)信息
print(context.control.name);
//获取值
//context.ReadValue<float>
//持续时间
print(context.duration);
//开始时间
print(context.startTime);
};
//结束操作
move.canceled += (context) =>
{
print("结束事件调用");
};
//3.关键参数 CallbackContext
//当前状态
//动作行为信息
//控件信息
//获取值
//持续时间
//开始时间
}
private void TestFun(InputAction.CallbackContext context)
{
print("开始事件调用");
}
输入配置文件,inputaction的集合,以下示例以Lesson9为输入配置文件
Acton1为InputActions的集合,Acton1.Fire为InputAction
//1.创建生成的代码对象
//2.激活输入
//3.事件监听
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson9 : MonoBehaviour
{
Lesson9Input input;
// Start is called before the first frame update
void Start()
{
#region 知识点一 根据配置文件生成C#代码
//1.选择InputActions文件
//2.在Inspector窗口设置生成路径,类名,命名空间
//3.应用后生成代码
#endregion
#region 知识点二 使用C#代码进行监听
//1.创建生成的代码对象
input = new Lesson9Input();
//2.激活输入
input.Enable();
//3.事件监听
input.Action1.Fire.performed += (context) =>
{
print("开火");
};
input.Action2.Space.performed += (context) =>
{
print("跳跃");
};
#endregion
}
// Update is called once per frame
void Update()
{
print(input.Action1.Move.ReadValue<Vector2>());
}
}
5.替身系统avater
【Unity】Avatar与AvatarMask系统介绍(TPS.番外篇)_SaFuFuの绝世的博客-CSDN博客
Unity为我们提供了Avatar,即替身系统。这是一种Unity设置的骨骼模式,只要你是人型的角色,就会识别,并根据角色原本的骨骼及命名,创建对应的Avatar。那么只需要大家的骨骼都转换成这种模式,我们就可以实现动画复用了。
6.三大可持续化
7.自动锁敌
8.Where约束
where(泛型类型约束)_hua@happiness的博客-CSDN博客
9.Lua
number string boolean nil function table userdata thread
10.Xlua和Tolua区别
xLua和tolua都是用于在Unity中进行Lua脚本集成的工具,它们有一些共同点,但也有一些重要区别。以下是它们之间的主要区别:
-
开发语言:
- tolua:tolua是一个使用C++编写的工具,它允许将C#代码绑定到Lua脚本。
- xLua:xLua是一个使用C#编写的工具,它通过ILRuntime库实现了C#和Lua之间的互操作性。
-
运行时性能:
- tolua:tolua的性能较高,因为它将C#代码生成为C++代码,然后与Lua脚本集成。这使得tolua在运行时具有较好的性能。
- xLua:xLua的性能相对较低,因为它使用ILRuntime库来在C#和Lua之间进行交互。ILRuntime的运行时性能比tolua的C++绑定稍差。
-
平台支持:
- tolua:tolua支持多个平台,包括Windows、iOS、Android等。
- xLua:xLua也支持多个平台,但与tolua相比,它在某些平台上的性能可能会有所下降。
11.开闭包??
开包(Unpacking)是将数据结构解构为单独的变量【元组】
而闭包(Closure)是带有捕获外部作用域变量的函数,保留状态和引用。【嵌套函数】