前言
QF框架内置了不少案例,并且QF文档也详细说明了使用规范。虽然如此,但考虑到说明太过详细导致有的时候翻起来不便,以及工程当中的案例我习惯都清理掉,以下选了部分常用的API记录。
ResKit
//除了Resource加载,每个脚本都需要声明加载器
private ResLoader mResLoader = ResLoader.Allocate();
基本加载1
// 项目启动只调用一次即可
ResKit.Init();
// 通过资源名 + 类型搜索并加载资源(更方便)
var prefab = mResLoader.LoadSync<GameObject>("AssetObj");
// 通过 AssetBundleName 和 资源名搜索并加载资源(更精确)
//prefab = mResLoader.LoadSync<GameObject>("assetobj_prefab", "AssetObj");
var gameObj = Instantiate(prefab);
基本加载2
mResLoader.LoadSync<GameObject("ImageA").InstantiateWithParent(this.transform);
基本加载3
// 加载 Resources 目录里的资源不用调用 ResKit.Init
RawImage.texture = mResLoader.LoadSync<Texture2("resources://TestTexture");
异步加载
private float progress;
ResLoader resLoader;
IEnumerator Load()
{
yield return ResKit.InitAsync();
resLoader = ResLoader.Allocate();
resLoader.Add2Load<GameObject>("AssetObj 1",(b, res) =>
{
if (b)
{
res.Asset.As<GameObject>().Instantiate();
}
});
// AssetBundleName + AssetName
resLoader.Add2Load<GameObject>("assetobj 2_prefab","AssetObj 2",(b, res) =>
{
if (b)
{
res.Asset.As<GameObject>().Instantiate();
}
});
resLoader.LoadAsync(() =>
{
// 加载成功 5 秒后回收
ActionKit.Delay(5.0f, () =>
{
resLoader.Recycle2Cache();
}).Start(this);
});
}
//获得进度
private void SetProgress() {
while (progress < resLoader.Progress * 100)
{
progress += 1;
Debug.Log(progress);
}
}
加载场景
private ResLoader mResLoader = null;
void Start()
{
ResKit.Init();
mResLoader = ResLoader.Allocate();
// 同步加载
mResLoader.LoadSceneSync("SceneRes");
// 异步加载
mResLoader.LoadSceneAsync("SceneRes");
// 异步加载
mResLoader.LoadSceneAsync("SceneRes", onStartLoading: operation =>
{
// 做一些加载操作
});
}
private void OnDestroy()
{
mResLoader.Recycle2Cache();
mResLoader = null;
}
UIKit
初始化
//初始化UIKit
ResKit.Init();
// UIKit 的分辨率设置
UIKit.Root.SetResolution(1920, 1080, 1);
//获取 UIRoot 的摄像机,进行特殊效果的设置
var uiCamera = UIKit.Root.Camera;
打开关闭
//打开UI
UIKit.OpenPanel<UIBasicPanel>()
// 在 Forward 层级打开
UIKit.OpenPanel<UIBasicPanel>(UILevel.Forward)
//关闭UI
UIKit.ClosePanel<UIBasicPanel>();
//UI内部关闭
this.CloseSelf();
给UI传递数据
// 传递初始数据给 UIHomePanel
UIKit.OpenPanel<UIBasicPanel>(new UIHomePanelData()
{
Coin = 10
});
//传递的数据在UI脚本里面需要实现
public class UIBasicPanelData : QFramework.UIPanelData
{
public int Coin;
}
public partial class UIBasicPanel : QFramework.UIPanel
{
protected override void OnInit(QFramework.IUIData uiData)
{
mData = uiData as UIBasicPanelData ?? new UIBasicPanelData();
// please add init code here
// 外边传进来的,第一次初始化的时候使用
Debug.Log(mData.Coin);
}
protected override void OnOpen(QFramework.IUIData uiData)
{
// 每次 OpenPanel 的时候使用
Debug.Log((uiData as UIBasicPanelData).Coin);
}
}
弹窗堆栈
// UIHomePanel 需要确保是打开的状态,如果不打开会报错。以下是压栈和推栈两种方法。
UIKit.Stack.Push(this); // this 是 Panel
UIKit.Stack.Push<UIHomePanel>();
this.Back(); // 弹出 UIHomePanel
UIKit.Back<UIHomePanel>(); // 弹出 this
AudioKit
播放背景音乐,同一时间只能播放一个音乐,播放别的音乐会直接卸载掉正在播放的音乐。
AudioKit.PlayMusic("resources://game_bg");
播放音效,同一时间可以播放多个音效,当多人说话时,也可以用来播放人声。
AudioKit.PlaySound("resources://game_bg");
播放人声,与播放背景音乐一致,同一时间只能播放一个人声,用于播放一些旁白之类的声音非常适合。
AudioKit.PlayVoice("resources://game_bg");
//声音开关
AudioKit.Settings.IsSoundOn.Value
AudioKit.Settings.IsMusicOn.Value
AudioKit.Settings.IsVoiceOn.Value
//音量控制
AudioKit.Settings.MusicVolume.RegisterWithInitValue(v => musicVolumeSlider.value = v);
AudioKit.Settings.VoiceVolume.RegisterWithInitValue(v => voiceVolumeSlider.value = v);
AudioKit.Settings.SoundVolume.RegisterWithInitValue(v => soundVolumeSlider.value = v);
musicVolumeSlider.onValueChanged.AddListener(v => { AudioKit.Settings.MusicVolume.Value = v; });
voiceVolumeSlider.onValueChanged.AddListener(v => { AudioKit.Settings.VoiceVolume.Value = v; });
soundVolumeSlider.onValueChanged.AddListener(v => { AudioKit.Settings.SoundVolume.Value = v; });
SingletonKit
C# 单例类
public class GameDataManager : Singleton<GameDataManager>
{
}
Mono 单例
public class GameDataManager : MonoSingleton<GameDataManager>
{
}
LogKit
日志输出
LogKit.I("一般等级");
LogKit.W("警告等级");
LogKit.E("错误等级");
拼接日志
LogKit.Builder().Append("Hello").Append("World").ToString().LogInfo();
ActionKit
延迟
ActionKit.Delay(1.0f, () =>
{
Debug.Log("End Time:" + Time.time);
}).Start(this);
重复执行
// 每次点击鼠标左键都会输出:Mouse Clicked
ActionKit.Repeat()
.Condition(() => Input.GetMouseButtonDown(0))
.Callback(() => Debug.Log("Mouse Clicked"))
.Start(this);
// 点击鼠标右键,只会输出五次:Mouse right clicked,第五次输出 Right click finished
ActionKit.Repeat(5)
.Condition(() => Input.GetMouseButtonDown(1))
.Callback(() => Debug.Log("Mouse right clicked"))
.Start(this, () =>
{
Debug.Log("Right click finished");
});
条件
ActionKit.Sequence()
.Callback(() => Debug.Log("Before Condition"))
.Condition(() => Input.GetMouseButtonDown(0))
.Callback(() => Debug.Log("Mouse Clicked"))
.Start(this);
FluentAPI
mResLoader.LoadSync<GameObject>("mygameobj")
.InstantiateWithParent(parent)
.transform
.LocalIdentity()
.Name("MyGameObj")
.Show();
EnumEventSystem
定义事件
public enum TestEvent
{
Start,
TestOne,
End,
}
public enum TestEventB
{
Start = TestEvent.End, // 为了保证每个消息 Id 唯一,需要头尾相接
TestB,
End,
}
使用
//注册事件
EnumEventSystem.Global.Register(TestEvent.TestOne, OnEvent);
//发送事件
EnumEventSystem.Global.Send(TestEvent.TestOne, "Hello World!");
//注销事件
EnumEventSystem.Global.UnRegister(TestEvent.TestOne, OnEvent);
//事件触发方法
void OnEvent(int key, params object[] obj)
{
switch (key)
{
case (int) TestEvent.TestOne:
Debug.Log(obj[0]);
break;
}
}
PoolKit
安全对象池(有限制)
使用方法:
SafeObjectPool<Bullet>.Instance.SetFactoryMethod(() =>
{
// bullet can be mono behaviour
return new Bullet();
});
SafeObjectPool<Bullet>.Instance.SetObjectFactory(new DefaultObjectFactory<Bullet>());
//初始化对象池,限制为50个,预先缓存25个
SafeObjectPool<Bullet>.Instance.Init(50,25);
//分配-》从对象池拿出来子弹进行——放到枪口、发射等操作
var bullet = Bullet.Allocate();
Debug.Log(SafeObjectPool<Bullet>.Instance.CurCount);//对象池剩24个预先缓存
//回收刚刚分配的子弹
bullet.Recycle2Cache();
Debug.Log(SafeObjectPool<Bullet>.Instance.CurCount);//对象池剩25个预先缓存
对象缓存:
class Bullet :IPoolable,IPoolType
{
public void OnRecycled()
{
Debug.Log("回收了");
}
public bool IsRecycled { get; set; }
//分配
public static Bullet Allocate()
{
return SafeObjectPool<Bullet>.Instance.Allocate();
}
public void Recycle2Cache()
{
SafeObjectPool<Bullet>.Instance.Recycle(this);
}
}
FSM
以下不是自带的FSMKit,因为状态机自己就能随便写了,而且更通俗易懂
初始化
//示例场景:吊装机械吊起吊物放到结束位置
public enum ModelState
{
Nomal,//初始状态
Hoisting,//吊起
Finish//结束
}
public ModelState modelState = ModelState.Nomal;
//控制者所控制的机器
private StateMachine machine;
void Awake()
{
NormalState normal = new NormalState(0, this);
HoistingState hoisting = new HoistingState(1, this);
FinishState finish = new FinishState(2, this);
machine = new StateMachine(normal);
machine.AddState(hoisting);
machine.AddState(finish);
}
/// <summary>
/// 切换状态,isSave为是否保存位置到本地-这个isSave和事件传参一样,通常是无参,这里项目特殊需求才假的
/// </summary>
public void SwichState(ModelState modelState,bool isSave = true)
{
this.modelState = modelState;
//根据枚举类型去改变动画
switch (modelState)
{
case ModelState.Nomal:
machine.TranslateState(0, isSave);
break;
case ModelState.Hoisting:
machine.TranslateState(1);
break;
case ModelState.Finish:
machine.TranslateState(2);
break;
}
}
void Update()
{
machine.FSMUpdate();
}
//设置物体
public void SetGo(GameObject go, bool b)
{
//省略逻辑
}
//初始状态
public class NormalState : TemplateState<Model>
{
public NormalState(int id, Model o) : base(id, o)
{
}
private bool isSave = true;
public override void OnEnter(params object[] args)
{
base.OnEnter(args);
//重置位置为“某种”状态
owner.SetGo(owner.gameObject, false);
//传参,没有可以不加这个,只要owner就够了
isSave = (bool)args[0];
}
public override void OnStay(params object[] args)
{
base.OnStay(args);
//if (!isSave)
//{
// return;
//}
//记录当时的位置,用来还原、缓存等-这里是用Matrix4x4矩阵来记录位置的逻辑,主要展示owner的作用
owner.transform.GetComponent<DataInfo().PersistModelItemData.InitMatrix4x4(owner.transform);
}
public override void OnExit(params object[] args)
{
base.OnExit(args);
}
}
宏
管理宏,防止重命名只改当前平台的变量名称;有特殊的需求可以自行扩展。
if (PlatformCheck.IsiOS)
{
//TODO
}
if (PlatformCheck.IsEditor)
{
//TODO
}
总结
刚入门推荐去看官方文档,此篇 类笔记总结——QF常用API。