用QFramework重构飞机大战(Siki Andy的)(上)(00-05 到游戏界面之前的所有面板)

GitHub
//
官网的
全民飞机大战(第一季)-----框架设计篇(Unity 2017.3)
全民飞机大战(第二季)-----游戏逻辑篇(Unity 2017.3)
全民飞机大战(第三季)-----完善功能篇(Unity 2017.3)
全民飞机大战(第四季)-----新手引导篇
//
B站各放几集
全民飞机大战(第一季)-----框架设计篇(Unity 2017.3)
全民飞机大战(第二季)-----游戏逻辑篇(Unity 2017.3)
全民飞机大战(第三季)-----完善功能篇(Unity 2017.3)
全民飞机大战(第四季)-----新手引导篇

watch 案例的脚本数量

534/2(因为.cs.meta)=267个脚本在这里插入图片描述

----------------------------------------------------------------

untiy 2017

bug C#版本untiy2017

项目的原始unity版本是2017,对应的的C#版本是4.6,不支持ref,out,这对QF影响大,所以不用unity2017.
2023-06-19 Untiy进阶 C#知识补充2——C#版本与Unity的关系

-------------------------------------------------------

bug 导入2020.3.23f1c1(入坑时的最新LTS版本)--------------------

bug 不存在NUnit

直接删除using,那里没用掉

bug Dotween报错VectorOptions

看到0引用,先注释掉算了# if false
在这里插入图片描述

在这里插入图片描述

bug 引用缺失using System;using System.Reflection;

补上去
在这里插入图片描述

bug dll重复,删除其中一个是显示 hook引用,删不了

删除另外一个

bug 命名冲突导致报错

modify 作用一样的保留自己的(因为自己的才能导包带走复用),删掉原来的

比如拓展方法

transform.Rect()
transform.AddComponent();
transform.Find(path).gameObject.AddComponent();

比如相同的类
Tags

modify 加上命名空间的限制

在这里插入图片描述

bug加载不到LoadingView

这块报空了
在这里插入图片描述

----------------------------------------------

00 总的流程,大的模块

modify (重点)脚本太多,用一个脚本来汇总,方便查找

/****************************************************文件:Framework_AirCombat.cs作者:lenovo邮箱: 日期:2023/7/31 20:29:31功能: 飞机大战的框架整理汇总
*****************************************************/using LitJson;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.VersionControl;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.XR;
using static BindUtil;
using Random = UnityEngine.Random;public class Framework_AirCombat : MonoBehaviour
{#region 生命/// <summary>首次载入且Go激活</summary>void Start(){//UI{View();LifeTime();Controller();LifeTime_Controller();SpecificUI_MainUI();SpecificUI_Effect();SpecificUI_GameUI();}Manager();Reader();Attribute();Config();Util();Loader();Data();TaskQueue();Message();Action();Pool();Coroutine();Model();Singleton();Test();//游戏中的{ Path();Input();    Behaviour(); Ani();Bullet();BulletMgr();Component();Effect();EffectView();EnemyCreater();GameProcess();Factory();Map();InitGame();PlayerController();Trajectory();SpecialState();View_Logic();GameEvent gameEvent;Guide();}}#endregion#region 辅助private void SpecialState(){LevelUpState levelUpState;//IBuff iBuff;IBuffCarrier iBuffCarrier;IDebuff iDeff;IDebufferCarrier iDebufferCarrier;ISpecialState iSpecialState;SpecialStateMgrBase specialStateMgrBase;//PlayerBuffMgr playerBuffMgr;}private void Trajectory(){ITrajectory iTrajectory;EllipseTrajectory ellipseTrajectory;RotateTrajectory rotateTrajectory;StraightTrajectory straightTrajectory;VTrajectory vTrajectory;}private void PlayerController(){PlayerController playerController;}private void InitGame(){GameLayerMgr gameLayerMgr;GameRoot gameRoot;}private void Map(){MapCloud mapCloud;MapItem mapItem;MapMgr mapMgr;}private void Factory(){ItemFactory itemFactory;PathFactory pathFactory;SpecialStateFactory specialStateFactory;}private void EnemyCreater(){IEnemyCreater iEnemyCreater;MissileEnemyCreater missileEnemyCreater;PlaneEnemyCreater planeEnemyCreater;//ISubEnemyCreaterMgr iSubEnemyCreaterMgr;BossCreaterMgr bossCreaterMgr;ElitesCreaterMgr elitesCreaterMgr;EnemyCreaterMgr enemyCreaterMgr;MissileCreaterMgr missileCreaterMgr;NormalCreaterMgr normalCreaterMgr;//LoadCreaterData loadCreaterData;GameProcess();}private void GameProcess(){GameProcessMgr gameProcessMgr;GameProcessNormalEvent gameProcessNormalEvent;GameProcessTriggerEvent gameProcessTriggerEvent;IGameProcessNormalEvent  iGameProcessNormalEvent;IGameProcessTriggerEvent iGameProcessTriggerEvent;}private void Component(){AutoDespawnComponent autoDespawnComponent;DestroyDelay autoDestroyComponent;//BossBulletEventComponent bossBulletEventComponent;BulletCollideMsgComponent bulletCollideMsgComponent;CameraMove cameraMove;ColliderComponent colliderComponent;EnemyTypeComponent enemyTypeComponent;IColliderMsg colliderMsg;IComponent iComponent;ItemCollideMsgComponent itemCollideMsgComponent;LifeComponent lifeComponent;MoveComponent moveComponent;PlaneCollideMsgComponent planeCollideMsgComponent;RenderComponent renderComponent;}private void BulletMgr(){BulletEffectMgr bulletEffectMgr;EmitBulletMgr emitBulletMgr;EnemyBulletMgr enemyBulletMgr;SpawnBulletPointMgr spawnBulletPointMgr;}private void Bullet(){IBullet iBullet;Bullet bullet;     BulletMgr();}private void Behaviour(){IBehaviour iBehaviour;PlayerBehaviour playerBehaviour;EnemyBehaviour enemyBehaviour;BulletBehaviour bulletBehaviour;}private void Path(){IPath iPath;PathBase pathBase;EllipsePath ellipsePath;EnterPath enterPath;EnterPath.MoveDirection moveDirection;StayOnTopPath stayOnTopPath;StraightPath straightPath;WPath wPath;PathMgr pathMgr;//IEnterPath iEnetrPath;RightToLeft rightToLeft;LeftToRight leftToRight;UpToDown upToDown;}private void Test(){BulletConfigTest bulletConfigTest;ITest iTest;MsgEventTest msgEventTest;ShowFPS showFPS;}private void Manager(){AudioMgr audioMgr;ConfigMgr configMgr;CoroutineMgr coroutineMgr;DataMgr dataMgr;DelayDetalCoroutineMgr delayDetalCoroutineMgr;InputMgr inputMgr;                LifeCycleMgr lifeCycleMgr;LoadMgr loadMgr;MessageMgr messageMgr;PoolMgr poolMgr;ReaderMgr readerMgr;SceneMgr sceneMgr;SubMsgMgr subMsgMgr;TaskQueueMgr taskQueueMgr;TestMgr testMgr;UILayerMgr uiLayerMgr;UIManager uiManager;//PathMgr pathMgr;BulletMgr();//GameDataMgr gameDataMgr;//GuideMgr guideMgr;}private void SpecificUI_GameUI(){GameResultController gameResultController;GameUIController gameUIController;LifeController lifeController;LifeItemController lifeItemController;PowerController powerController;SettingController settingController;ShieldController shieldController;//GameResultView gameResultView;GameUIView gameUIView;Life life;LifeItem lifeItem;Power power;SettingView settingView;Shield shield;Warning warning;}private void Ani(){AniMgr aniMgr;FrameAni frameAni;PlayerEnterAni playerEnterAni;}private void SpecificUI_Effect(){ItemCDEffect itemCDEffect;ItemEffect itemEffect;}/// <summary>具体的面板</summary>private void SpecificUI_MainUI(){HeroItemController heroItemController;LevelItemController levelItemController;LevelRootController levelRootController;LevelsController levelsController;LoadingController loadingController;PlanePropertyController planePropertyController;PropertyItemController propertyItemController;SelectedHeroController selectedHeroController;SelectHeroController selectHeroController;StartController startController;StrengthenController strengthenController;SwitchPlayerController switchPlayerController;//DialogView dialogView;HeroItem heroItem;LevelItem levelItem;LevelRoot levelRoot;LevelsView levelsView;LoadingView loadingView;Money money;PlaneProperty planeProperty;PropertyItem propertyItem;SelectedHeroView selectedHeroView;SelectHero selectHero;StrengthenView strengthenView;SwitchPlayer switchPlayer;}private void Singleton(){MonoSingleton<AMono> monoSingleton;NormalSingleton<A> normalSingleton;}private void LifeTime_Controller(){IControllerInit iControllerInit;IControllerShow iControllerShow;IControllerHide iControllerHide;IControllerUpdate iControllerUpdate;}private void Controller(){IController iController;LifeTime_Controller();ControllerBase controllerBase;}private void Model(){GameModel gameModel;GameStateModel gameStateModel;PlaneSpritesModel planeSpritesModel;//IBullet iBullet;IBulletModel iBulletModel;IEnemyBulletModel iEnemyBulletModel;IEnemyBossBulletModel iEnemyBossBulletModel;EnemyBossBulluetModelBase enemyBossBulluetModelBase;EnemyBoss0BulluetModel enemyBoss0BulluetModel;EnemyBoss1BulluetModel enemyBoss1BulluetModel;EnemyBulluetModel enemyBulluetModel;PlayerBulletModel playerBulletModel;PowerBulletModel powerBulletModel;}private void Coroutine(){CoroutineItem.CoroutineState coroutineState;CoroutineItem coroutineItem;DelayDetalCoroutineItem delayDetalCoroutineItem;CoroutineController coroutineController;}private void Pool(){GameObjectPool gameObjectPool;ObjectPool<A> objectPool;}private void Action(){ActionMgr actionMgr;}private void Message(){IMessageSystem iMessageSystem;MessageSystem messageSystem;}private void Input(){IInputModule iInputModule;InputModule inputModule;InputState inputState;InputMgr inputMgr;}private void View(){LifeTime();IView iView;ViewBase viewBase;//LevelRoot levelRoot;View_Logic();}void View_Logic(){ // EnemyEnemyLifeItem enemyLifeItem;EnemyLifeView enemyLifeView;MissileView missileView;MissileWarning missileWarning;PlaneEnemyView planeEnemyView;// ItemViewAddBulletView addBulletView;AddExpView addExpView;ItemViewBase itemViewBase;PowerItemView powerItemView;ShieldItemView shieldItemView;StarView starView;//BulletDestroyAniView bulletDestroyAniView;IGameView iGameView;PlaneDestroyAniView planeDestroyAniView;PlayerView playerView;PowerView powerView;ShieldView shieldView;    }private void TaskQueue(){TaskQueue taskQueue;TaskQueueMgr taskQueueMgr;LevelRoot levelRoot;}private void Data(){IDataMemory iDataMemory;PlayerPrefsMemory playerPrefsMemory;JsonMemory jsonMemory;DataMgr dataMgr;////Logic/Data{ AllEnemyData allEnemyData;EnemyData enemyData;//AllBulletData allBulletData;BulletData bulletData;NormalBulletData normalBulletData;BossBulletData bossBulletData;//EnemyCreaterConfigData enemyCreaterConfigData;LevelData levelData;ICreaterData iCreaterData;PlaneCreaterData planeCreaterData;MissileCreaterData missileCreaterData;//GameDataMgr gameDataMgr;//EnemyTrajectoryDataMgr enemyTrajectoryDataMgr;ITrajectoryData iTrajectoryData;StraightTrajectoryData straightTrajectoryData;VTrajectoryData vTrajectoryData;EllipseData ellipseData;RotateData rotateData;        }//}private void EffectView(){EffectViewBase effectViewBase;AddBulletEffectView addBulletEffectView;AddExpEffectView addExpEffectView;MissileWarningEffectView missileWarningEffectView;StarEffectView starEffectView;}private void Effect(){IEffect iEffect;IEffectView iEffectView;EffectViewBase effectViewBase;FlyIntoUI flyIntoUI;RotateEffect rotateEffect;ScaleEffect scaleEffect;ShowAndHideEffect showAndHideEffect;SlowSpeedEffect slowSpeedEffect;//}private void Loader(){ILoader loader;ABLoader abLoader;ResourceLoader resourceLoader;}private void Util(){BindUtil bindUtil;BulletUtil bulletUtil;DataMgr.Single.SetJsonData("key", new JsonData());//DataUtilEmpty4Raycast empty4Raycast;transform.ButtonAction("xxx", () => { });GameUtil gameUtil;JsonUtil jsonUtil;KeysUtil keysUtil;UiUtil uiUtil;//BulletTrajectoryDataUtil bulletTrajectoryDataUtil;//Guide_Util();}void Guide_Util(){ GuideGenerateIDTool guideGenerateIDTool;}void Guide(){Guide_Util();//Guide_Frame();Guide_Business();GuideMgr guideMgr;}void Guide_Frame(){ IGuide iGuide;IGuideRoot iGuideRoot;GuideBase guideBase;//IGuideBehaviour  iGuideBehaviour;GuideBehaviourBase guideBehaviourBase;//IGuideGroup iGuideGroup;GuideGroupBase<IGuideGroup> guideGroupBase;//GuideMgr guideMgr;    }void Guide_Business(){//ModuleExplainDialogModule explainDialogModule;HandModule handModule;HighLightModule highLightModule;//GuideSelectedHeroViewGuide selectedHeroViewGuide;StartViewGuide startViewGuide;//GroupShowHerosGroup showHerosGroup;StartViewGroup startViewGroup;//DemoTestDemo.StartViewGuide testDemo_StartViewGuide;TestDemo.DemoGuideGroupA testDemo_DemoGuideGroupA;TestDemo.Demo1GuideGroup testDemo_Demo1GuideGroup;TestDemo.Demo2GuideGroup testDemo_Demo2GuideGroup;TestDemo.ClickButtonA testDemo_ClickButtonA;//TestDemo.GuideMgr testDemo_MuideMgr;//BehaviourShowHerosBehaviour showHerosBehaviour;StartGameBehaviour startGameBehaviour;WelcomeGuideBehaviour welcomeGuideBehaviour;}private void Config(){BulletEffectPoolConfig bulletEffectPoolConfig;LifeCycleAddConfig lifeCycleAddConfig;LifeCycleConfig lifeCycleConfig;PoolConfig poolConfig;ReaderConfig readerConfig;SceneConfig sceneConfig;UILayerConfig uiLayerConfig;}void Reader(){IReader reader;JsonReader jsonReader;ReaderMgr readerMgr;ReaderConfig readerConfig;// 数据单位IKey iKey;Key key;KeyQueue keyQueue;}void Attribute(){InitCustomAttributes initCustomAttributes;BindPrefabAttribute bindPrefabAttribute;BulletAttribute bulletAttribute;//BindUtil bindUtil;BindPriorityComparer bindPriorityComparer;}void LifeTime(){IInit init;IInitParent iInitParent;IShow show;IHide hide;IUpdate update;IDestroy destroy;}#endregion#region 内部类(举例,没有实际用处)
class A
{ }class AMono:MonoBehaviour{ }#endregion
}

watch 以下,按初学者朴素的理解来划分

玩家

敌人AI轨迹

    /// <summary>轨迹</summary>private void Trajectory(){ITrajectory iTrajectory;EllipseTrajectory ellipseTrajectory;RotateTrajectory rotateTrajectory;StraightTrajectory straightTrajectory;VTrajectory vTrajectory;TrajectoryData();Path();}void TrajectoryData(){ EnemyTrajectoryDataMgr enemyTrajectoryDataMgr;ITrajectoryData iTrajectoryData;StraightTrajectoryData straightTrajectoryData;VTrajectoryData vTrajectoryData;EllipseData ellipseData;RotateData rotateData;     }private void Path(){IPath iPath;PathBase pathBase;EllipsePath ellipsePath;StayOnTopPath stayOnTopPath;StraightPath straightPath;WPath wPath;PathMgr pathMgr;//IEnterPath iEnetrPath;EnterPath enterPath;EnterPath.MoveDirection moveDirection;RightToLeft rightToLeft;LeftToRight leftToRight;UpToDown upToDown;}

总的关系 各种轨迹:PathBase:IPath

方向 IPath.GetDir()

PathMgr中用了PathFactory的GetDir(),就是将变化最频繁的部分摘了出来

public class PathFactory 
{public static IPath GetPath(TrajectoryType trajectoryType){switch (trajectoryType){case TrajectoryType.STRAIGHT:return new StraightPath();case TrajectoryType.W:return new WPath();case TrajectoryType.STAY_ON_TOP:return new StayOnTopPath();case TrajectoryType.ELLIPSE:return new EllipsePath();case TrajectoryType.ROTATE:Debug.LogError("PathFactory未初始该轨道:" + trajectoryType);return null;default:Debug.LogError("PathFactory的当前轨迹未添加,名称:" + trajectoryType);return null;}}
}

初始位置 IPath.GetInitPos()

升级

输赢 ,扣分

声音

动画

读存档、数据

01 流程

可以看到LifeCycleMgr 初始化时就会读取json
优先用PlayerPrefers拿不到就去取json的

    private void GetDataByPlayerPrefersOrJson(){LifeCycleMgr lifeCycleMgr;LifeCycleAddConfig lifeCycleAddConfig;ConfigMgr configMgr;DataMgr dataMgr;DataMgr.Single.SetObject("key",new object()); //PlayerPrefersDataMgr.Single.SetJsonData("key", new JsonData());//DataUtil}

02 json数据

这段主要在强化面板时用到
它会这么存
key,value
0level,0
0attackTime,1
0atttack,后面那串json
0attackname,攻击
0attackvalue,5

以此类推

{"planes": [{"planeId": 0,"level": 0,"attackTime":1,"attack": {"name":"攻击","value":5,"cost":180,"costUnit":"star","grouth":10,"maxVaue": 500},"fireRate": {"name":"攻速","value":80,"cost":200,"costUnit":"star","grouth":1,"maxVaue": 100},"life": {"name":"生命","value":100,"cost":200,"costUnit":"star","grouth":50,"maxVaue": 1000},"upgrades": {"name":"升级","coefficient": 2,"max":4,"0": 100,"1": 200,"2": 300,"3": 400,"costUnit":"diamond"}},

watch DataMgr

在这里插入图片描述

modify 拆分一下枚举,全部大写加_

在这里插入图片描述

bug 报错

按图二的位置去改成相应的 大写+_(因为前面改了枚举)
但是枚举关联着资源,也就是资源名称,没必要让资源名称也变成枚举的格式,这些就不先不改,主要是AudioVolume
在这里插入图片描述
在这里插入图片描述

地图

两个脚本,两张图轮换

        private void Map(){MapMgr mapMgr;MapItem mapItem;}

在这里插入图片描述

特效

        private void Effect(){BulletDestroyAniView bulletDestroyAniView;PlaneDestroyAniView planeDestroyAniView;FrameAni frameAni;}

在这里插入图片描述

敌人

在这里插入图片描述

-------------------------------------------------------

QF预设置

生成脚本的命名空间

在这里插入图片描述

-------------------------------------------------------

00 Scene Test

modify UI两者之间的位置关系

改写其中的逻辑
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

   /// <summary>基于参照物baseRect(和放置物不同面板placeParent)和间隔offset,上下左右放置物体placeRect</summary>public static Component BaseBy(this Component t, RectTransform placeParent, RectTransform baseRect, Dir dir, float offset) {RectTransform placeRect = t.GetComponent<RectTransform>();LayoutElement placeLayout = placeRect.GetComponent<LayoutElement>();//placeRect要有组件。//float horizontal_LocalX = 0f;float horizontal_LocalY=0f;float vertical_LocalY=0f;float vertical_LocalX = 0f;if (dir == Dir.LEFT || dir == Dir.RIGHT){ float base_HalfW = Mathf.Abs(baseRect.rect.xMin);float panel_HalfW = placeParent.rect.width / 2;float text_AfterW = panel_HalfW - (base_HalfW + offset);placeLayout.preferredWidth = (text_AfterW < placeParent.rect.width) ? text_AfterW : -1;//horizontal_LocalX = (panel_HalfW - text_AfterW / 2);horizontal_LocalY = placeRect.transform.World2Local(baseRect).y;        }if (dir == Dir.UP || dir == Dir.DOWN){float base_HalfH = Mathf.Abs(baseRect.rect.yMin);float panel_HalfH = placeParent.rect.height / 2;float text_AfterH = panel_HalfH - (base_HalfH + offset);placeLayout.preferredWidth = (text_AfterH < placeParent.rect.width) ? text_AfterH : -1;//vertical_LocalY = (panel_HalfH - text_AfterH / 2);vertical_LocalX = placeRect.transform.World2Local(baseRect).x;}switch (dir){case Dir.LEFT:{placeRect.transform.localPosition = new Vector3(-horizontal_LocalX, horizontal_LocalY);}break;case Dir.RIGHT:{placeRect.transform.localPosition = new Vector3(horizontal_LocalX, horizontal_LocalY);}break;case Dir.UP:{placeRect.transform.localPosition = new Vector3(vertical_LocalX, vertical_LocalY);}break;case Dir.DOWN:{placeRect.transform.localPosition = new Vector3(vertical_LocalX, -vertical_LocalY);}break;default: break;}return placeRect;}

---------------------------------------------------------

01 Scene Start面板、Main场景

StartGamePanel

using UnityEngine;
using UnityEngine.UI;
using QFramework;namespace QFramework.Example
{public class StartGamePanelData : UIPanelData{}public partial class StartGamePanel : UIPanel{protected override void OnInit(IUIData uiData = null){mData = uiData as StartGamePanelData ?? new StartGamePanelData();// please add init code hereResKit.Init();if (true){StartGameBtn.onClick.AddListener(() => { UIKit.OpenPanel<SelectHeroPanel>();CloseSelf();});}else //原来的写法。重名了报错{//UIManager.Single.Show(Paths.PREFAB_SELECTED_HERO_VIEW);}AudioMgr.Single.PlayBGM();}protected override void OnOpen(IUIData uiData = null){}protected override void OnShow(){}protected override void OnHide(){}protected override void OnClose(){}}
}

---------------------------------------------------------

02 Scene StartGame

bug 加了DontDestroyOnLoad。设置父节点无效

图一是无效的
图二不加就可以设置
在这里插入图片描述

在这里插入图片描述

watch 从AudioMgr中看资源加载模块

AudioMgr
LoadMgr
ResourceLoade
ILoader

01 开始StartController的 AudioMgr.Single.PlayOnce(UIAduio.UI_StartGame.ToString());

02 在一个字典 _clips中查找

03 字典的初始化

    private void InitClips(){var clips = LoadMgr.Single.LoadAll<AudioClip>(Paths.AUDIO_FOLDER);foreach (var clip in clips){_clips.Add(clip.name, clip);}}

04 初始化用到了LoadMgr中的 ResourceLoader:ILoader

public interface ILoader
{GameObject LoadPrefab(string path);GameObject LoadPrefabAndInstantiate(string path, Transform parent = null);void LoadConfig(string path, Action<object> complete);T Load<T>(string path) where T : Object;T[] LoadAll<T>(string path) where T : Object;
}

05 ResourceLoader中就是熟悉的unity资源加载方法

在这里插入图片描述

watch 从 ResourceLoader 中看 CoroutineMgr

ResourceLoader
CoroutineMgr
CoroutineController
CoroutineItem
CoroutineState

watch COnsole中的打印

相应脚本
Assets/Scripts/Manager/TestMgr.cs
Assets/Scripts/Test
在这里插入图片描述
在这里插入图片描述

bug Unity C# interfaces causing “script class cannot be found”

01 类名与脚本名不一致
02 节点上加的脚本与已有的冲突(两个脚本都:Graphic)
在这里插入图片描述

bug 写完类似 : Graphic的脚本后无效,或者先有后运行后无效

对相应的脚本进行Reimport

watch UGUI的父节点

目前遇到的两个拼UI
01 Andy使用的父节点是有一定的宽和高的(改动过)
02 忘记了是哪个视频(好像是siki学院,Plane的暗黑破坏神教程),他采用的是LeftTopPin(命名方式)的父节点,父节点的高宽都是默认的(100高,100宽)。就是你在某一个分辨率(指Game窗口下的那个分辨率)随便拼UI,最后用空节点(默认)锚定(左上,右上等),将随便拼的UI(在左上,右下等),拖到那个空节点
在这里插入图片描述

watch 面板 DialogView

在这里插入图片描述

watch

发现QF有两种UI思路。
一种是IController+Command,Event
一种是能自动生成Desigher的那种,就没有继承IController

-------------------------------

03 Scene 英雄选择(第二个转QF的界面)

选择效果

在这里插入图片描述

效果

设定选择颜色和时间

主要是这3个属性。整个框架也是复制QF的PointGame的

        /// <summary>实际使用的是在父节点中的索引</summary>BindableProperty<int> SelectHeroID { get; }/// <summary>选中后变化的颜色</summary>BindableProperty<Color> SelectHeroColor { get; }/// <summary>选中后变化颜色需要的时间</summary>BindableProperty<float> SelectHeroColorTime { get; }
    #region Modelinternal class PlaneModel{}internal interface IPlaneModel{}// 1. 定义一个 Model 对象public interface IAirCombatAppModel : IModel{BindableProperty<int> Star { get; }BindableProperty<int> Diamond { get; }BindableProperty<int> SelectPlaneID { get; }/// <summary>实际使用的是在父节点中的索引</summary>BindableProperty<int> SelectHeroID { get; }BindableProperty<Color> SelectHeroColor { get; }BindableProperty<float> SelectHeroColorTime { get; }}public class AirCombatAppModel : AbstractModel, IAirCombatAppModel{public BindableProperty<int> Star { get; } = new BindableProperty<int>();public BindableProperty<int> Diamond { get; } = new BindableProperty<int>();public BindableProperty<int> SelectPlaneID { get; } = new BindableProperty<int>();public BindableProperty<int> SelectHeroID { get; } = new BindableProperty<int>();public BindableProperty<Color> SelectHeroColor { get; } = new BindableProperty<Color>();public BindableProperty<float> SelectHeroColorTime { get; } = new BindableProperty<float>();protected override void OnInit(){IStorage storage = this.GetUtility<IStorage>();// 设置初始值(不触发事件)Star.SetValueWithoutEvent(storage.LoadInt(nameof(Star)));Diamond.SetValueWithoutEvent(storage.LoadInt(nameof(Diamond)));SelectHeroID.SetValueWithoutEvent(storage.LoadInt(nameof(SelectHeroID)));SelectPlaneID.SetValueWithoutEvent(storage.LoadInt(nameof(SelectPlaneID)));SelectHeroColor.SetValueWithoutEvent(storage.LoadString(nameof(SelectHeroColor)).ToColor());SelectHeroColorTime.SetValueWithoutEvent(storage.LoadFloat(nameof(SelectHeroColorTime)));// 当数据变更时 存储数据Star.Register(newCount =>{storage.SaveInt(nameof(Star), newCount);});Diamond.Register(newCount =>{storage.SaveInt(nameof(Diamond), newCount);});SelectHeroID.Register(newCount =>{storage.SaveInt(nameof(SelectHeroID), newCount);});SelectPlaneID.Register(newCount =>{storage.SaveInt(nameof(SelectPlaneID), newCount);});SelectHeroColor.Register(newCount =>{storage.SaveString(nameof(SelectHeroColor), newCount.ToString());});SelectHeroColorTime.Register(newCount =>{storage.SaveFloat(nameof(SelectHeroColorTime), newCount);});}}#endregion

面板代码

主要是
01 Color.gray,0.5f,这个两个参数应该是写死的,但为了方便改动,协程可以设置的
02 HeroSelectable,控制选择效果和其它

			this.SendCommand(new SetSelectHeroParaCommand(Color.gray,0.5f));foreach (RectTransform rect in HeroTrans){_heroRectLst.Add(rect);}foreach (var rect in _heroRectLst){rect.AddComponentIfNull<HeroSelectable>();}
using UnityEngine;
using UnityEngine.UI;
using QFramework;
using System.Collections.Generic;namespace QFramework.AirCombat
{public class SelectHeroPanelData : UIPanelData{}public partial class SelectHeroPanel : UIPanel	,IController{List<RectTransform> _heroRectLst = new List<RectTransform>();protected override void OnInit(IUIData uiData = null){mData = uiData as SelectHeroPanelData ?? new SelectHeroPanelData();// please add init code here#region 原文	/**foreach (Transform trans in HeroTrans){ trans.AddComponent<HeroItem>();trans.AddComponent<HeroItemController>();}HeroItem heroItem;HeroItemController heroItemController;SelectHero selectHero;SelectHeroController selectHeroController;SelectedHeroView selectedHeroView;SelectedHeroController selectedHeroController;**/#endregion#region 初始化this.SendCommand(new SetSelectHeroParaCommand(Color.gray,0.5f));foreach (RectTransform rect in HeroTrans){_heroRectLst.Add(rect);}foreach (var rect in _heroRectLst){rect.AddComponentIfNull<HeroSelectable>();}#endregion#region 按钮StartBtn.onClick.AddListener(() => { //UIManager.Single.Show(Paths.PREFAB_LEVELS_VIEW);"进入游戏".LogInfo();});StrengthenBtn.onClick.AddListener(() => {this.SendCommand < OpenStrengthenPanelCommand>();   CloseSelf();});ExitBtn.onClick.AddListener(() => {this.SendCommand<ExitGameCommand>();});#endregion}#region 辅助protected override void OnOpen(IUIData uiData = null){}protected override void OnShow(){}protected override void OnHide(){}protected override void OnClose(){}public IArchitecture GetArchitecture(){return AirCombatApp.Interface;}#endregion}
}

面板子项和对Event的响应

响应就是 this.RegisterEvent

/****************************************************文件:HeroSelectable.cs作者:lenovo邮箱: 日期:2023/8/12 19:4:2功能:
*****************************************************/using QFramework.AirCombat;
using QFramework;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
using UnityEngine.UI;
using DG.Tweening;namespace QFramework.AirCombat
{public class HeroSelectable : MonoBehaviour ,IController{#region 属性#endregion#region 生命/// <summary>首次载入且Go激活</summary>void Start(){this.RegisterEvent<SelectHeroEvent>( _ => { int idx = transform.GetSiblingIndex();IAirCombatAppModel model = this.GetModel<IAirCombatAppModel>();Image image = GetComponent<Image>();bool selected = idx == model.SelectHeroID;if (selected){image.DOKill();image.DOColor(model.SelectHeroColor, model.SelectHeroColorTime);}else{image.DOKill();image.DOColor(Color.white, model.SelectHeroColorTime);}});GetComponent<Button>().onClick.AddListener(() =>{ IAirCombatAppModel model = this.GetModel<IAirCombatAppModel>();Debug.Log("HeroSelectable");//this.SendCommand(new SelectHeroCommand(transform.GetSiblingIndex()));});}#endregion#region 实现public IArchitecture GetArchitecture(){return AirCombatApp.Interface;}#endregion}
}

选择命令

    public class SelectHeroCommand : AbstractCommand{int _heroIdx = 0;public SelectHeroCommand(int heroIdx){_heroIdx = heroIdx;}protected override void OnExecute(){this.GetModel<IAirCombatAppModel>().SelectHeroID.Value = _heroIdx;this.SendEvent<SelectHeroEvent>();}}

选中时的音效

停止旧的

  AudioMgr.Single.Stop(cur.Index2String<Hero>());
    public class SelectHeroCommand : AbstractCommand{int _heroIdx = 0;public SelectHeroCommand(int heroIdx){_heroIdx = heroIdx;}protected override void OnExecute(){int cur = this.GetModel<IAirCombatAppModel>().SelectHeroID.Value;this.GetModel<IAirCombatAppModel>().SelectHeroID.Value = _heroIdx;AudioMgr.Single.Stop(cur.Index2String<Hero>());this.SendEvent<SelectHeroEvent>();}}

播放新的

AudioMgr.Single.Play(idx.Index2String<Hero>());
/****************************************************文件:HeroSelectable.cs作者:lenovo邮箱: 日期:2023/8/12 19:4:2功能:
*****************************************************/using QFramework.AirCombat;
using QFramework;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
using UnityEngine.UI;
using DG.Tweening;
using System.Runtime.ConstrainedExecution;namespace QFramework.AirCombat
{public class HeroSelectable : MonoBehaviour ,IController{#region 属性#endregion#region 生命/// <summary>首次载入且Go激活</summary>void Start(){this.RegisterEvent<SelectHeroEvent>( _ => { int idx = transform.GetSiblingIndex();IAirCombatAppModel model = this.GetModel<IAirCombatAppModel>();Image image = GetComponent<Image>();bool selected = idx == model.SelectHeroID;if (selected){AudioMgr.Single.Play(idx.Index2String<Hero>());image.DOKill();image.DOColor(model.SelectHeroColor, model.SelectHeroColorTime);}else{image.DOKill();image.DOColor(Color.white, model.SelectHeroColorTime);}});......

stars ExtendEnum转来转去

这块是需要 根据英雄的兄弟索引 去转对应值的 Hero枚举 ,枚举对应的字符串
在这里插入图片描述

/****************************************************文件:ExtendEnum.cs作者:lenovo邮箱: 日期:2023/7/24 18:0:35功能:
*****************************************************/using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;public static partial class ExtendEnum  //转来转去
{public enum ExtendEnum_XXX{A=0,B=1,C=2,}public static void Example(){ExtendEnum_XXX para = ExtendEnum_XXX.A;string str = para.ToString();int idx = (int)para;Debug.LogFormat("String2Enum:({0}){1}" , str.String2Enum<ExtendEnum_XXX>().GetType(), str.String2Enum<ExtendEnum_XXX>()  );Debug.LogFormat("Index2Enum:({0}){1}", idx.Index2Enum<ExtendEnum_XXX>().GetType(), idx.Index2Enum<ExtendEnum_XXX>()  );//      Debug.LogFormat("String2Index:({0}){1}", str.String2Index<ExtendEnum_XXX>().GetType(), str.String2Index<ExtendEnum_XXX>()  );Debug.LogFormat("Enum2Index:({0}){1}" , para.Enum2Index().GetType(), para.Enum2Index()  );//      Debug.LogFormat("Index2String:({0}){1}" , idx.Index2String<ExtendEnum_XXX>().GetType(), idx.Index2String<ExtendEnum_XXX>()  );Debug.LogFormat("Enum2String:({0}){1}" , para.Enum2String().GetType(), para.Enum2String()  );}/// <summary>字符串转枚举</summary>public static T String2Enum<T>(this string str) where T:Enum{return (T)Enum.Parse(typeof(T), str);}/// <summary.值转枚举</summary>public static T Index2Enum<T>(this int idx) where T : Enum{string str= Enum.GetName(typeof(T), idx);return str.String2Enum <T>();}public static int String2Index<T>(this string str) where T : Enum{T t= (T)Enum.Parse(typeof(T), str);return (int)Enum.Parse(typeof(T), str);}public static int Enum2Index<T>(this T t) where T : Enum{string str= t.ToString();return (int)Enum.Parse(typeof(T), str);}public static string Index2String<T>(this int idx) where T : Enum{return Enum.GetName(typeof(T), idx);}public static string Enum2String<T>(this T t) where T : Enum{return t.ToString();}
}

stars btn.onClick.AddListenerAfterRemoveAll();

    public static ButtonClickedEvent AddListenerAfterRemoveAll(this ButtonClickedEvent onClick , UnityAction action){onClick.RemoveAllListeners();onClick.AddListener(action);return onClick;}

-------------------------------------------------------

04 Scene 升级界面(是从这里开始试着转QF)

bug 升级界面的数据没拿到

初始化改成设置父节点时,把数据初始化的方法去掉了

bug untiy卡死

在VS修改脚本后,回到Unity,,此时Unity处于打开带有改脚本的一个预制体中,然后卡死

stars DoIfNotNull

/// <summary>不为空就执行</summary>public static Action DoIfNotNull(this Action cb){if (cb != null){cb();}return cb;}

效果

    public void UpdateFunc(){Image.fillAmount -= Time.deltaTime / Const.CD_EFFECT_TIME;if (Image.fillAmount <= 0){LifeCycleMgr.Single.Remove(LifeName.UPDATE, this);_cb.DoIfNotNull();}}

stars DoIfNotNull(T)(尖括号显示不了)

ActionMgr.Execute(T t)可以改
在这里插入图片描述

    public static void Example(){Action<int> intAction = (para) => { Debug.Log(para.ToString()); };intAction.DoIfNotNull<int>(99);}public static Action<T> DoIfNotNull<T>(this Action<T> cb,T t) {if (cb != null){cb(t);}return cb;}

modify ButtonAction

把主体的代码拆出去以后复用,所以区别就是项目多加了声音事件

using System;
using UnityEngine;
using UnityEngine.UI;public static class ExtendUtil
{/// <summary>/// 类似于  transform.ButtonAction("Add", AddAction);/// <para /> 类似于transform.ButtonAction("OK/Start", () => { UIManager.Single.Show(Paths.PREFAB_LEVELS_VIEW); });/// </summary>public static void ButtonAction(this Transform trans, string path, Action action, bool useDefaultAudio = true){if (useDefaultAudio){action += AddButtonAudio;}trans.ButtonAction_Common(path,action);}private static void AddButtonAudio(){AudioMgr.Single.PlayOnce(UIAduio.UI_ClickButton.ToString());}}

star 拆出来的复用部分

    /// <summary>/// 类似于  transform.ButtonAction("Add", AddAction);/// <para /> 类似于transform.ButtonAction("OK/Start", () => { UIManager.Single.Show(Paths.PREFAB_LEVELS_VIEW); });/// </summary>public static void ButtonAction_Common(this Transform trans, string path, Action action){var tar = trans.Find(path);if (tar == null){Debug.LogError("ButtonAction查找物体为空,路径为:" + path);}else{var button = tar.GetComponent<Button>();if (button == null){Debug.LogError("ButtonAction物体上没有Button组件,物体名称:" + tar.name);}else{button.onClick.AddListener(() => action());}}}

modify 金币钻石的数据

效果

在这里插入图片描述

初始数据

        DataMgr.Single.ClearAll();{ //弄点数据DataMgr.Single.Set(DataKeys.STAR,666);                DataMgr.Single.Set(DataKeys.DIAMOND,100);      //按他的设置来设置的话GameStateModel.Single.SetMoney(DataKeys.STAR,666);GameStateModel.Single.SetMoney(DataKeys.DIAMOND,100);  }   

获得数据和显示

            if (false){// Util.Get("Star/BG/Text").SetText(DataMgr.Single.Get<int>(DataKeys.STAR));//Util.Get("Diamond/BG/Text").SetText(DataMgr.Single.Get<int>(DataKeys.DIAMOND));}else{StarText.SetText(DataMgr.Single.Get<int>(DataKeys.STAR));DiamondText.SetText(DataMgr.Single.Get<int>(DataKeys.DIAMOND));//DataMgr.Single.Get<int>(DataKeys.STAR).LogInfo();//DataMgr.Single.Get<int>(DataKeys.STAR).LogInfo();}

bug Slider在PlayerPrefs的数据拿不到

DataMgr在PlayerPrefs的数据拿不到就去那Json拿。
方法是ConfigMgr在Init()时,
用到了DataUtil.SetObjectData(string oldkey, JsonData data)。
。。。
ConfigMgr由LifeCycleMgr调用LifeCycleAddConfig时用到
。。
结果是数据初始比较慢,导致打开强化面板时数据还没初始好

    private void GetDataByPlayerPrefersOrJson(){LifeCycleMgr lifeCycleMgr;LifeCycleAddConfig lifeCycleAddConfig;ConfigMgr configMgr;DataMgr dataMgr;DataMgr.Single.SetJsonData("key", new JsonData());//DataUtil}

watch 改写的UI

在这里插入图片描述

watch 原本的UI

在这里插入图片描述

stars SetText

    public static Transform SetText(this Transform trans, object obj){Text text = trans.GetComponent<Text>();if (text == null){throw new System.Exception("SetText异常");}if (text != null){text.text = obj.ToString();}//return trans;}public static GameObject SetText(this GameObject go, object obj){Text text = go.GetComponent<Text>();if (text == null){throw new System.Exception("SetText异常");}if (text != null){text.text = obj.ToString();}//return go;}

modify 左右切图和属性强化(星星)

InitAddBtn在切换飞机时变,点击 addBtn不变
UodateAllUI在切换飞机和点击addBtn都变

            //中间的SwitchPlayer{//默认设置GameStateModel.Single.SelectedPlaneId = DataMgr.Single.Get<int>(DataKeys.PLANE_ID);int id, level;id = GameStateModel.Single.SelectedPlaneId;level = GameStateModel.Single.PlaneLevel;InitAddBtn(id);UpdateAllUI(id, level);//LeftBtn.onClick.AddListener(() => {id = SwitchPlaneID( id, -1);level = GameStateModel.Single.PlaneLevel;InitAddBtn(GameStateModel.Single.SelectedPlaneId);UpdateAllUI(id, level);});RightBtn.onClick.AddListener(() => {id = SwitchPlaneID( id, 1);level = GameStateModel.Single.PlaneLevel;InitAddBtn(id);UpdateAllUI(id, level);});}

modify 左右切图和飞机升级(钻石)

modify 强化界面的代码(未使用QF)

效果

在这里插入图片描述

StrengthenPanel : UIPanel (脚本生成的,功能自己加)

using UnityEngine;
using UnityEngine.UI;
using QFramework;
using System.Collections.Generic;
using ItemKey = PropertyItem.ItemKey;
using LitJson;
using System.Numerics;
using Newtonsoft.Json.Linq;namespace QFramework.AirCombat
{public class StrengthenPanelData : UIPanelData{}public partial class StrengthenPanel : UIPanel {#region 字属List<RectTransform> _propertyItemLst=new List<RectTransform>();#endregionprotected override void OnInit(IUIData uiData = null){mData = uiData as StrengthenPanelData ?? new StrengthenPanelData();_propertyItemLst.Add(PropertyItem_Attack);_propertyItemLst.Add(PropertyItem_FireRate);_propertyItemLst.Add(PropertyItem_Life);#region 原文// please add init code here//if (false)//{//    Util.Get("Money").Go.AddComponent<Money>();//    Util.Get("Switchplayer").Go.AddComponent<SwitchPlayer>();//      Util.Get("Property").Go.AddComponent<PlaneProperty>(); //Slider//}//else//{//}//中间的飞机数据,3条Slider。Property做的事//PlaneProperty,PropertyItem{// _propertyItemLst = new List<PropertyItem>((int)Property.COUNT);//for (Property i = 0; i < Property.COUNT; i++)//{//    GameObject go = LoadMgr.Single.LoadPrefabAndInstantiate(Paths.PREFAB_PROPERTY_ITEM, transform);//    PropertyItem item = go.AddComponent<PropertyItem>();//    item.Init(i.ToString());//    _propertyItemLst.Add(item);//}}#endregion//上方的Moneyif (false){// Util.Get("Star/BG/Text").SetText(DataMgr.Single.Get<int>(DataKeys.STAR));//Util.Get("Diamond/BG/Text").SetText(DataMgr.Single.Get<int>(DataKeys.DIAMOND));}else{UpdateMoneyText();//DataMgr.Single.Get<int>(DataKeys.STAR).LogInfo();//DataMgr.Single.Get<int>(DataKeys.STAR).LogInfo();}//中间的SwitchPlayer{//默认设置GameStateModel.Single.SelectedPlaneId = DataMgr.Single.Get<int>(DataKeys.PLANE_ID);int id, level;id = GameStateModel.Single.SelectedPlaneId;UpdateAllUI();//LeftBtn.onClick.AddListener(() => {id = SwitchPlaneID( id, -1);UpdateAllUI();});RightBtn.onClick.AddListener(() => {id = SwitchPlaneID( id, 1);UpdateAllUI();});}InitBackBtn();}#region 重写 其它protected override void OnOpen(IUIData uiData = null){}protected override void OnShow(){}protected override void OnHide(){}protected override void OnClose(){}#endregion#region 辅助/// <summary>更细能改界面所有元素</summary>void UpdateAllUI(){int planeId = GameStateModel.Single.SelectedPlaneId;int level = GameStateModel.Single.PlaneLevel;//UpdateMoneyText();     UpdatePlaneSprite(planeId, level);foreach (var rect in _propertyItemLst){InitAddButton(planeId, rect);UpdateText_Name_Value_Cost(planeId, rect);UpdateSlider_Value_MaxVaue(planeId, rect);}InitUpgradesBtn(planeId, level);UpdateUpgradesText(planeId);}void InitUpgradesBtn(int planeId, int level){UpgradesBtn.onClick.RemoveAllListeners();UpgradesBtn.onClick.AddListener(() => {InitUpgradesBtnAction(planeId);UpdateAllUI();});}void InitBackBtn(){BackBtn.onClick.AddListener(() => {//SelectHeroPanel的push由SelectHeroPanel操作UIKit.Back<SelectHeroPanel>();CloseSelf();});}void UpdateMoneyText(){DiamondText.SetText(GameStateModel.Single.GetDiamond());StarText.SetText(GameStateModel.Single.GetStar());}private void InitUpgradesBtnAction(int planeId){string pre = planeId + DataKeys.UPGRADES;//int curMoney = GameStateModel.Single.GetDiamond(); //自己的前不用加pre//int maxLevel = GameStateModel.Single.PlaneLevelMax;int curLevel = GameStateModel.Single.PlaneLevel;int afterLevel = curLevel;           //string costKey = KeysUtil.GetPropertyKeys(pre + curLevel);//0upgrades0:300 的冒号左边int costMoney = DataMgr.Single.Get<int>(costKey); //300int afterMoney = curMoney - costMoney;if (afterMoney >= 0 && curLevel < maxLevel-1)//有钻石&&上升空间 (0,1,2,3,max=4){if (afterLevel >= maxLevel)//到顶了{afterLevel = maxLevel;}else{afterLevel = curLevel + 1;}GameStateModel.Single.SetDiamond(afterMoney);DataMgr.Single.SetObject(planeId + DataKeys.LEVEL, afterLevel);//var key = KeysUtil.GetPropertyKeysWithoutPlaneId(DataKeys.UPGRADES_RATIO);var level = GameStateModel.Single.PlaneLevel;level++;DataMgr.Single.Set(key, level);}else{Debug.Log("你没钻石了或者等级到顶了!");// UIManager.Single.ShowDialog("你没星星了!");}}private void InitAddButtonAction(int planeId, RectTransform rect){     string property = (rect.name).TrimName(TrimNameType.DashAfter).LowerFirstLetter();//attack,fireRate,lifestring pre = planeId + property  ;int curMoney = GameStateModel.Single.GetStar(); //自己的前不用加pre//string  costKey = KeysUtil.GetPropertyKeys( pre + PropertyItem.ItemKey.cost);int costMoney = DataMgr.Single.Get<int>(costKey);int afterMoney = curMoney - costMoney;//int addValue= DataMgr.Single.Get<int>(pre + ItemKey.grouth);int maxValue= DataMgr.Single.Get<int>(pre + ItemKey.maxVaue);int curValue= DataMgr.Single.Get<int>(pre + ItemKey.value);int afterValue = curValue;if (afterMoney >= 0 && curValue< maxValue)//有钱&&上升空间{if (afterValue >= maxValue)//到顶了{afterValue = maxValue;}else{ afterValue = curValue + addValue;}GameStateModel.Single.SetStar(afterMoney);DataMgr.Single.SetObject(planeId + property + ItemKey.value, afterValue);UpdateAllUI();}else{Debug.Log("你没星星了或者数值到顶了!");   // UIManager.Single.ShowDialog("你没星星了!");}}void InitAddButton(int planeId,RectTransform rect){Button addBtn = rect.GetComponentDeep<Button>("Add");addBtn.onClick.RemoveAllListeners();//切换不同id就重置addBtn.onClick.AddListener(() =>{InitAddButtonAction(planeId, rect);});Debug.Log( "AddBtn数量"+addBtn.onClick.GetPersistentEventCount())  ;}/// <summary>name,value,cost三个文本</summary>private void UpdateText_Name_Value_Cost(int planeId, RectTransform rect){#region 说明/**{"planes": [{"planeId": 0,"level": 0,"attackTime":1,"attack": { "name":"攻击","value":5,"cost":200,"costUnit":"star","grouth":10,"maxVaue": 500},"fireRate": { "name":"攻速","value":80,"cost":200,"costUnit":"star","grouth":1,"maxVaue": 100},"life": { "name":"生命","value":100,"cost":200,"costUnit":"star","grouth":50,"maxVaue": 1000},"upgrades": { "name":"升级","coefficient": 2,"max":4,"0": 100,"1": 200,"2": 300,"3": 400,"costUnit":"diamond"}},......],"planeSpeed": 1.2}**/#endregion// attack,fireRate,life string property =  (rect.name).TrimName(TrimNameType.DashAfter).LowerFirstLetter();//attack,fireRate,life//name,value,cost三个文本for (ItemKey propertyKey = 0; propertyKey < PropertyItem.ItemKey.grouth; propertyKey++) {string transName = PropertyItem.UpperFirstLetter(propertyKey);  //Name           //例如Name,Value,Cost,这个TransformTransform trans = rect.Find( transName );if (trans != null){string key = KeysUtil.GetPropertyKeys(planeId, property + propertyKey); //0attacknameDebug.Log("Text:" + key );object obj = DataMgr.Single.GetObject(key);string value = obj.ToString();Debug.Log("Text:"+key+","+value);trans.SetText(value);}else{Debug.LogError("属性Slider预制名称错误,正确名称:" + transName);}}  }/// <summary>改成根据父节点,去更新子节点</summary>    private void UpdateSlider_Value_MaxVaue(int planeId, Transform trans){string property = (trans.name).TrimName(TrimNameType.DashAfter).LowerFirstLetter();//attackSlider slider = trans.Find("Slider").GetComponent<Slider>();string maxVaueKey = KeysUtil.GetPropertyKeys(planeId, property+ ItemKey.maxVaue); //0attackmaxVaue(原文没加l)string valueKey = KeysUtil.GetPropertyKeys(planeId , property + ItemKey.value);//0attackvalueDebug.LogFormat("Slider:{0},{1}", valueKey, maxVaueKey);slider.minValue = 0;slider.maxValue = DataMgr.Single.Get<int>(maxVaueKey);slider.value = DataMgr.Single.Get<int>(valueKey);Debug.LogFormat("Slider:{0},{1},{2}", slider.minValue, slider.value,slider.maxValue) ;}void UpdateUpgradesText(int planeId){string pre = planeId + DataKeys.UPGRADES;int curLevel = DataMgr.Single.Get<int>(planeId + DataKeys.LEVEL);//string costKey = KeysUtil.GetPropertyKeys(pre + curLevel);//0upgrades0:300 的冒号左边int costMoney = DataMgr.Single.Get<int>(costKey); //300CostText.SetText(costMoney);}private int SwitchPlaneID( int id, int direction){string str = (direction == -1) ? "左" : "右";( str+"键:" + id).LogInfo();   //var max = PlaneSpritesModel.Single.Count;id += direction;id = id.Clamp(0, max-1);                 // id = (id < 0 ) ? 0 : id >= max ? id = max - 1 : id;GameStateModel.Single.SelectedPlaneId = id;return  id;}void UpdatePlaneSprite(int planeID,int level){Sprite planeSprite = PlaneSpritesModel.Single[planeID, level];IconImg.SetSprite(planeSprite);}#endregion}
}

StrengthenPanel(生成的)

using System;
using UnityEngine;
using UnityEngine.UI;
using QFramework;namespace QFramework.AirCombat
{// Generate Id:a3f593c2-800c-45b3-96af-41eaf4781fccpublic partial class StrengthenPanel{public const string Name = "StrengthenPanel";[SerializeField]public UnityEngine.UI.Image BGImg;[SerializeField]public UnityEngine.UI.Text StarText;[SerializeField]public UnityEngine.UI.Text DiamondText;[SerializeField]public UnityEngine.UI.Button LeftBtn;[SerializeField]public UnityEngine.UI.Image IconImg;[SerializeField]public UnityEngine.UI.Button RightBtn;[SerializeField]public UnityEngine.UI.Button UpgradesBtn;[SerializeField]public UnityEngine.RectTransform PropertyItem_Attack;[SerializeField]public UnityEngine.RectTransform PropertyItem_FireRate;[SerializeField]public UnityEngine.RectTransform PropertyItem_Life;[SerializeField]public UnityEngine.UI.Text CostText;[SerializeField]public UnityEngine.UI.Button BackBtn;private StrengthenPanelData mPrivateData = null;protected override void ClearUIComponents(){BGImg = null;StarText = null;DiamondText = null;LeftBtn = null;IconImg = null;RightBtn = null;UpgradesBtn = null;PropertyItem_Attack= null;PropertyItem_FireRate= null;PropertyItem_Life= null;CostText = null;BackBtn = null;mData = null;}public StrengthenPanelData Data{get{return mData;}}StrengthenPanelData mData{get{return mPrivateData ?? (mPrivateData = new StrengthenPanelData());}set{mUIData = value;mPrivateData = value;}}}
}

watch 从QF的“点点点”入手改写强化界面的脚本

watch QF的“点点点”效果

在这里插入图片描述

watch QF的“点点点”脚本

using UnityEngine;
using UnityEngine.UI;namespace QFramework.Example
{class Framework{void All(){Model();System();Utility();Controller();Command();Architecture();}#region 辅助void Command(){IncreaseCountCommand increaseCountCommand;DecreaseCountCommand decreaseCountCommand;}void Model(){IModel iModel;AbstractModel abstractModel;IAirCombatAppModel iCounterAppModel;CounterAppModel counterAppModel;}void System(){ISystem iSystem;IAchievementSystem iAchievementSystem;AchievementSystem achievementSystem;}void Utility(){IUtility iIUtility;IStorage iStorage;Storage storage;}void Controller(){CounterAppController counterAppController;}void Architecture(){CounterApp counterApp;}#endregion}#region Model// 1. 定义一个 Model 对象public interface IAirCombatAppModel : IModel{BindableProperty<int> Star { get; }BindableProperty<int> Diamond{ get; }}public class CounterAppModel : AbstractModel,IAirCombatAppModel{public BindableProperty<int> Star { get; } = new BindableProperty<int>();public BindableProperty<int> Diamond { get; } = new BindableProperty<int>();protected override void OnInit(){IStorage storage = this.GetUtility<IStorage>();// 设置初始值(不触发事件)Star.SetValueWithoutEvent(storage.LoadInt(nameof(Star)));Diamond.SetValueWithoutEvent(storage.LoadInt(nameof(Diamond)));// 当数据变更时 存储数据Star.Register(newCount =>{storage.SaveInt(nameof(Star),newCount);});Diamond.Register(newCount =>{storage.SaveInt(nameof(Diamond), newCount);});}}#endregion#region Systempublic interface IAchievementSystem : ISystem{}public class AchievementSystem : AbstractSystem ,IAchievementSystem{protected override void OnInit(){this.GetModel<IAirCombatAppModel>() // -+.Star.Register(newCount =>{if (newCount == 10){Debug.Log("触发 点击达人 成就");}else if (newCount == 20){Debug.Log("触发 点击专家 成就");}else if (newCount == -10){Debug.Log("触发 点击菜鸟 成就");}});}}#endregion#region Utilitypublic interface IStorage : IUtility{void SaveInt(string key, int value);int LoadInt(string key, int defaultValue = 0);}public class Storage : IStorage{public void SaveInt(string key, int value){PlayerPrefs.SetInt(key,value);}public int LoadInt(string key, int defaultValue = 0){return PlayerPrefs.GetInt(key, defaultValue);}}#endregion#region Architecture// 2.定义一个架构(提供 MVC、分层、模块管理等)public class CounterApp : Architecture<CounterApp>{protected override void Init(){// 注册 System this.RegisterSystem<IAchievementSystem>(new AchievementSystem()); // 注册 Modelthis.RegisterModel<IAirCombatAppModel>(new CounterAppModel());// 注册存储工具的对象this.RegisterUtility<IStorage>(new Storage());}protected override void ExecuteCommand(ICommand command){Debug.Log("Before " + command.GetType().Name + "Execute");base.ExecuteCommand(command);Debug.Log("After " + command.GetType().Name + "Execute");}protected override TResult ExecuteCommand<TResult>(ICommand<TResult> command){Debug.Log("Before " + command.GetType().Name + "Execute");var result =  base.ExecuteCommand(command);Debug.Log("After " + command.GetType().Name + "Execute");return result;}}#endregion#region Command// 引入 Commandpublic class IncreaseCountCommand : AbstractCommand {protected override void OnExecute(){var model = this.GetModel<IAirCombatAppModel>();model.Star.Value++;}}public class DecreaseCountCommand : AbstractCommand{protected override void OnExecute(){this.GetModel<IAirCombatAppModel>().Star.Value--; // -+}}#endregion#region Controller// Controllerpublic class CounterAppController : MonoBehaviour , IController /* 3.实现 IController 接口 */{// Viewprivate Button mBtnAdd;private Button mBtnSub;private Text mCountText;// 4. Modelprivate IAirCombatAppModel mModel;void Start(){// 5. 获取模型mModel = this.GetModel<IAirCombatAppModel>();// View 组件获取mBtnAdd = transform.Find("BtnAdd").GetComponent<Button>();mBtnSub = transform.Find("BtnSub").GetComponent<Button>();mCountText = transform.Find("CountText").GetComponent<Text>();// 监听输入mBtnAdd.onClick.AddListener(() =>{// 交互逻辑this.SendCommand<IncreaseCountCommand>();});mBtnSub.onClick.AddListener(() =>{// 交互逻辑this.SendCommand(new DecreaseCountCommand(/* 这里可以传参(如果有) */));});// 表现逻辑mModel.Star.RegisterWithInitValue(newCount => // -+{UpdateView();}).UnRegisterWhenGameObjectDestroyed(gameObject);}void UpdateView(){mCountText.text = mModel.Star.ToString();}// 3.public IArchitecture GetArchitecture(){return CounterApp.Interface;}private void OnDestroy(){// 8. 将 Model 设置为空mModel = null;}}#endregion}

modify 强化界面的代码(使用QF)

watch 效果

在这里插入图片描述

modify GameStart

大部分是复制原来的,修改了这个

public class GameStart03 : MonoBehaviour ,IController
{......ResKit.Init();{this.SendCommand( new OpenStrengthenPanelCommand(() => {//DataMgr.Single.Set(DataKeys.STAR,666);                //DataMgr.Single.Set(DataKeys.DIAMOND,1000);//按他的设置来设置的话//GameStateModel.Single.SetStar(800);//有的还没改,注释掉会报错//GameStateModel.Single.SetDiamond(1000);this.SendCommand(new SetStarCommand(1002)); //此时强化面板未打开this.SendCommand(new SetDiamondCommand(1002));}));}
using System;
using System.Collections;
using System.Linq;
using LitJson;
using QFramework;
using QFramework.Example;
using UnityEngine;namespace QFramework.AirCombat
{ 
public class GameStart03 : MonoBehaviour ,IController
{// Use this for initialization/// <summary>首次登录,新手引导</summary>public bool IsFirst = false;private void Start(){if (FindObjectsOfType<LaunchGame>().Length > 1){Destroy(gameObject);return;}StartCoroutine(Init());}private void Update(){if (Input.GetKeyDown(KeyCode.P)) //确定是json数据初始慢导致强化面板获取数据失败{OpenPanelFunc();}}private IEnumerator Init(){yield return TestMgr.Single.Init();yield return null;//Transform mgrTrans = transform.FindTop("Mgr");Transform canvasTrans = transform.FindTop("Canvas");//GameStateModel.Single.CurScene = SceneName.Main;LifeCycleMgr.Single.Init(mgrTrans);CoroutineMgr.Single.Init(mgrTrans);AudioMgr.Single.Init(mgrTrans);DataMgr.Single.ClearAll();if (IsFirst){ GuideUiMgr.Single.Init(canvasTrans);//设置Canvas,因为我把启动脚本放外面,不放在Canvas下GuideMgr.Single.InitGuide();        }yield return new WaitForSeconds(5f);//延时让json数据初始化if (true){ResKit.Init();{this.SendCommand( new OpenStrengthenPanelCommand(() => {//DataMgr.Single.Set(DataKeys.STAR,666);                //DataMgr.Single.Set(DataKeys.DIAMOND,1000);//按他的设置来设置的话//GameStateModel.Single.SetStar(800);//有的还没改,注释掉会报错//GameStateModel.Single.SetDiamond(1000);this.SendCommand(new SetStarCommand(1002)); //此时强化面板未打开this.SendCommand(new SetDiamondCommand(1002));}));}}}void OpenPanelFunc(  ){UIKit.OpenPanel<StrengthenPanel>();}public IArchitecture GetArchitecture(){return AirCombatApp.Interface;}}}

modify StrengthenPanel.cs

在这里插入图片描述

using UnityEngine;
using UnityEngine.UI;
using QFramework;
using System.Collections.Generic;
using ItemKey = PropertyItem.ItemKey;
using LitJson;
using System.Numerics;
using Newtonsoft.Json.Linq;
using UniRx.Triggers;
using System;
using System.Data;namespace QFramework.AirCombat
{public class StrengthenPanelData : UIPanelData{}public partial class StrengthenPanel : UIPanel,IController {#region 字属List<RectTransform> _propertyItemLst=new List<RectTransform>();#endregionprotected override void OnInit(IUIData uiData = null){mData = uiData as StrengthenPanelData ?? new StrengthenPanelData();_propertyItemLst.Add(PropertyItem_Attack);_propertyItemLst.Add(PropertyItem_FireRate);_propertyItemLst.Add(PropertyItem_Life);#region Topthis.RegisterEvent<ChangeStarEvent>(e =>{UpdateStarText();});this.RegisterEvent<ChangeDiamondEvent>(e =>{UpdateDiamondText();});#endregion#region Center//UpdateUpgradesButton();LeftBtn.onClick.AddListener(() =>{this.SendCommand(new SwitchPlaneCommand(-1));});RightBtn.onClick.AddListener(() =>{this.SendCommand(new SwitchPlaneCommand(1));});this.RegisterEvent<SelectPlaneIDEvent>(eventId =>{UpdatePlaneSprite();//UpdatePropertyItems();UpdateUpgradesButton();});this.RegisterEvent<IncreasePlanePropertyEvent>(eventId =>//增加属性时{UpdateStarText();//UpdatePropertyItems();});this.RegisterEvent<UpgradesPlaneLevelEvent>(eventId =>//升级时{UpdateDiamondText();UpdatePlaneSprite();//UpdatePropertyItems();UpdateUpgradesButton();});#endregion  #region BottomBackBtn.onClick.AddListener(() => {//SelectHeroPanel的push由SelectHeroPanel操作UIKit.Back<SelectHeroPanel>();CloseSelf();});#endregion#region 初始化{this.SendCommand(new SetPlaneCommand(0));//在跑一次,去触发Register的}#endregion}#region 重写 其它protected override void OnOpen(IUIData uiData = null){}protected override void OnShow(){}protected override void OnHide(){}protected override void OnClose(){}#endregion#region 辅助void UpdatePropertyItems(){UpdateValueText();UpdateSlider();UpdateAddButton();UpdateCostStarText();}private void UpdateAddButton(){foreach (var rect in _propertyItemLst){string property = (rect.name).TrimName(TrimNameType.DashAfter).LowerFirstLetter();//attack,fireRate,lifeint planeID = this.GetModel<IAirCombatAppModel>().SelectPlaneID;string pre = planeID + property;//Button addBtn = rect.Find("Add").GetComponent<Button>();addBtn.onClick.RemoveAllListeners();//切换不同id就重置addBtn.onClick.AddListener(() =>{   string costKey = KeysUtil.GetPropertyKeys(pre + PropertyItem.ItemKey.cost);int cost = DataMgr.Single.Get<int>(costKey);bool can = this.SendCommand(new ChangeStarCommand( -cost) ); if (  can  ){this.SendCommand (new IncreasePlanePropertyCommand( property )  );}});}}private void UpdateUpgradesText(){int planeID = this.GetModel<IAirCombatAppModel>().SelectPlaneID;int cueLevel = DataMgr.Single.Get<int>(planeID + DataKeys.LEVEL);string costKey = KeysUtil.GetPropertyKeys(planeID + DataKeys.UPGRADES + cueLevel);int cost = DataMgr.Single.Get<int>(costKey);//UpgradesBtn.SetButtonText(cost);}private void UpdateUpgradesButton(){#region 说明/**"planes": ["planeId": 0,"level": 0,"attackTime":1,"attack": { "name":"攻击","value":5,"cost":180,"costUnit":"star","grouth":10,"maxVaue": 500},"fireRate": { "name":"攻速","value":80,"cost":200,"costUnit":"star","grouth":1,"maxVaue": 100},"life": { "name":"生命","value":100,"cost":200,"costUnit":"star","grouth":50,"maxVaue": 1000},"upgrades": { "name":"升级","coefficient": 2,"max":4,"0": 100,"1": 200,"2": 300,"3": 400,"costUnit":"diamond"}},**/#endregionint planeID = this.GetModel<IAirCombatAppModel>().SelectPlaneID;int cueLevel = DataMgr.Single.Get<int>(planeID + DataKeys.LEVEL);string costKey = KeysUtil.GetPropertyKeys(planeID + DataKeys.UPGRADES + cueLevel);int cost = DataMgr.Single.Get<int>(costKey);//UpdateUpgradesText();//UpgradesBtn.onClick.RemoveAllListeners();UpgradesBtn.onClick.AddListener(() =>{bool can = this.SendCommand(new ChangeDiamondCommand(-cost));if (can){this.SendCommand(new UpgradesPlaneLevelCommand());}});}private void UpdateCostStarText(){foreach (var rect in _propertyItemLst){string property = (rect.name).TrimName(TrimNameType.DashAfter).LowerFirstLetter();//attack,fireRate,lifeint planeID = this.GetModel<IAirCombatAppModel>().SelectPlaneID;string pre = planeID + property;string key = KeysUtil.GetPropertyKeys(pre + PropertyItem.ItemKey.cost);int value = DataMgr.Single.Get<int>(key);//rect.Find("Cost").SetText(value);}}private void UpdateValueText(){#region 说明/*"planes": [{"planeId": 0,"level": 0,"attackTime":1,"attack": {"name":"攻击","value":5,"cost":180,"costUnit":"star","grouth":10,"maxVaue": 500},"fireRate": {"name":"攻速","value":80,"cost":200,"costUnit":"star","grouth":1,"maxVaue": 100},"life": {"name":"生命","value":100,"cost":200,"costUnit":"star","grouth":50,"maxVaue": 1000},"upgrades": {"name":"升级","coefficient": 2,"max":4,"0": 100,"1": 200,"2": 300,"3": 400,"costUnit":"diamond"}},*/#endregionforeach (var rect in _propertyItemLst){string property = (rect.name).TrimName(TrimNameType.DashAfter).LowerFirstLetter();//attack,fireRate,lifeint planeID = this.GetModel<IAirCombatAppModel>().SelectPlaneID;string valueKey = KeysUtil.GetPropertyKeys(planeID + property + PropertyItem.ItemKey.value);int value = DataMgr.Single.Get<int>(valueKey);//rect.Find("Value").SetText(value);}}void UpdatePlaneSprite(){int planeID = this.GetModel<IAirCombatAppModel>().SelectPlaneID;string levelKey = KeysUtil.GetPropertyKeys(planeID+DataKeys.LEVEL);int level=   DataMgr.Single.Get<int>(levelKey);Sprite planeSprite = PlaneSpritesModel.Single[planeID, level];IconImg.SetSprite(planeSprite);}void UpdateStarText(){int star = this.GetModel<IAirCombatAppModel>().Star;StarText.SetText(star);}void UpdateDiamondText(){int diamond = this.GetModel<IAirCombatAppModel>().Diamond;DiamondText.SetText(diamond);}/// <summary>改成根据父节点,去更新子节点</summary>    private void UpdateSlider(){foreach (var rect in _propertyItemLst){int id = this.GetModel<IAirCombatAppModel>().SelectPlaneID;string property = (rect.name).TrimName(TrimNameType.DashAfter).LowerFirstLetter();//attackstring pre = id + property;Slider slider = rect.Find("Slider").GetComponent<Slider>();string maxVaueKey = KeysUtil.GetPropertyKeys(pre + ItemKey.maxVaue); //0attackmaxVaue(原文没加l)string valueKey = KeysUtil.GetPropertyKeys(pre + ItemKey.value);//0attackvaluefloat maxValue=DataMgr.Single.Get<int>(maxVaueKey);float value= DataMgr.Single.Get<int>(valueKey);Debug.LogFormat("Slider:{0},{1}", valueKey, maxVaueKey);slider.minValue = 0;slider.maxValue = maxValue;slider.value = value;Debug.LogFormat("Slider:{0},{1},{2}", slider.minValue, slider.value, slider.maxValue);}}#endregion#region QFIArchitecture IBelongToArchitecture.GetArchitecture(){return AirCombatApp.Interface;}#endregion}
}

watch QF用到的主要方法

什么都不带的Command
带参数的Command
代返回值的Command

modify QF (增加的内容主要是Command)

总体框架是从PointGame(QF中的例子)中复制的
。。。
AirCombat_QFramework.All()汇总所有的"飞机大战"使用QF的方法,方便查找
。。。
主体是这个Command。Event是对Command后对应的操作。所以Event的命名很多对应这Command

        void Command(){ChangeStarCommand increaseStarCommand;ChangeDiamondCommand increaseDiamondCommand;SetStarCommand setStarCommand;SetDiamondCommand setDiamondCommand;//IncreasePlanePropertyCommand increasePlanePropertyCommand;IncreasePlaneAttackCommand increasePlaneAttackCommand;IncreasePlaneFireRateCommand increasePlaneFireRateCommand;IncreasePlaneLifeCommand increasePlaneLifeCommand;UpgradesPlaneLevelCommand upgradesPlaneLevelCommand;//SetPlaneCommand initPlaneCommand;SwitchPlaneCommand changePlaneCommand;SwitchHeroCommand changeHeroCommand;//OpenStartGamePanelCommand openStartGamePanelCommand;OpenSelectHeroPanelCommand openSelectHeroCommand;OpenStrengthenPanelCommand openStrengthenPanel;ExitGameCommand exitGameCommand;}
/****************************************************文件:QFramework_AirCombat.cs作者:lenovo邮箱: 日期:2023/8/8 20:53:33功能:
*****************************************************/using JetBrains.Annotations;
using QFramework.Example;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Numerics;
using UnityEngine;
using static PropertyItem;
using Random = UnityEngine.Random;namespace QFramework.AirCombat
{public class AirCombat_QFramework : MonoBehaviour ,IController{private void Start(){}void All(){   Architecture();//Model();System();Utility();Controller();//Command();Event();//Test();}#region 辅助 void Test(){if (Input.GetKeyDown(KeyCode.Q)) this.SendCommand(new ChangeStarCommand(100));if (Input.GetKeyDown(KeyCode.W)) this.SendCommand(new ChangeStarCommand(-100));if (Input.GetKeyDown(KeyCode.E)) this.SendCommand(new ChangeDiamondCommand(-100));if (Input.GetKeyDown(KeyCode.R)) this.SendCommand(new ChangeDiamondCommand(-100));}void Event(){ChangeStarEvent changeStarEvent;ChangeDiamondEvent changeDiamondEvent;//SelectHeroIDEvent switchHeroEvent;SelectPlaneIDEvent switchPlaneEvent;//IncreasePlanePropertyEvent increasePlanePropertyEvent;UpgradesPlaneLevelEvent upgradesPlaneLevelEvent; }                      void Command(){ChangeStarCommand increaseStarCommand;ChangeDiamondCommand increaseDiamondCommand;SetStarCommand setStarCommand;SetDiamondCommand setDiamondCommand;//IncreasePlanePropertyCommand increasePlanePropertyCommand;IncreasePlaneAttackCommand increasePlaneAttackCommand;IncreasePlaneFireRateCommand increasePlaneFireRateCommand;IncreasePlaneLifeCommand increasePlaneLifeCommand;UpgradesPlaneLevelCommand upgradesPlaneLevelCommand;//SetPlaneCommand initPlaneCommand;SwitchPlaneCommand changePlaneCommand;SwitchHeroCommand changeHeroCommand;//OpenStartGamePanelCommand openStartGamePanelCommand;OpenSelectHeroPanelCommand openSelectHeroCommand;OpenStrengthenPanelCommand openStrengthenPanel;ExitGameCommand exitGameCommand;}void Model(){IModel iModel;AbstractModel abstractModel;IAirCombatAppModel iAirCombatAppModel;AirCombatAppModel airCombatAppModel;IPlaneModel iPlaneModel;PlaneModel planeModel;}void System(){ISystem iSystem;//IAchievementSystem iAchievementSystem;//AchievementSystem achievementSystem;}void Utility(){IUtility iIUtility;IStorage iStorage;PlayerPrefsStorage playerPrefsStorage;JsonStorage storage;}void Controller(){AirCombatAppController airCombatAppController;}void Architecture(){AirCombatApp counterApp;}public IArchitecture GetArchitecture(){return AirCombatApp.Interface;}#endregion}#region Modelinternal class PlaneModel{}internal interface IPlaneModel{}// 1. 定义一个 Model 对象public interface IAirCombatAppModel : IModel{BindableProperty<int> Star { get; }BindableProperty<int> Diamond { get; }BindableProperty<int> SelectPlaneID { get; }BindableProperty<int> SelectHeroID { get; }}public class AirCombatAppModel : AbstractModel, IAirCombatAppModel{public BindableProperty<int> Star { get; } = new BindableProperty<int>();public BindableProperty<int> Diamond { get; } = new BindableProperty<int>();public BindableProperty<int> SelectHeroID { get; } = new BindableProperty<int>();public BindableProperty<int> SelectPlaneID { get; } = new BindableProperty<int>();protected override void OnInit(){IStorage storage = this.GetUtility<IStorage>();// 设置初始值(不触发事件)Star.SetValueWithoutEvent(storage.LoadInt(nameof(Star)));Diamond.SetValueWithoutEvent(storage.LoadInt(nameof(Diamond)));SelectHeroID.SetValueWithoutEvent(storage.LoadInt(nameof(SelectHeroID)));SelectPlaneID.SetValueWithoutEvent(storage.LoadInt(nameof(SelectPlaneID)));// 当数据变更时 存储数据Star.Register(newCount =>{storage.SaveInt(nameof(Star), newCount);});Diamond.Register(newCount =>{storage.SaveInt(nameof(Diamond), newCount);});SelectHeroID.Register(newCount =>{storage.SaveInt(nameof(SelectHeroID), newCount);});SelectPlaneID.Register(newCount =>{storage.SaveInt(nameof(SelectPlaneID), newCount);});}}#endregion#region Command// 引入 Commandpublic class ChangeStarCommand : AbstractCommand<bool>{int _change = 0;public ChangeStarCommand(int change){_change = change;}protected override bool OnExecute(){var model = this.GetModel<IAirCombatAppModel>();int cur = this.GetModel<IAirCombatAppModel>().Star;int after = cur + _change;if (after >= 0 )//有钱&&上升空间{this.GetModel<IAirCombatAppModel>().Star.Value = after;     this.SendEvent<ChangeStarEvent>();"ChangeStarCommand".LogInfo();return true;}else{string str = "你没星星了!";str += "需要" + _change;str.LogInfo();// UIManager.Single.ShowDialog("你没星星了!");return false;}}}public class SetStarCommand : AbstractCommand{int _after = 0;public SetStarCommand(int after){_after = after;}protected override void OnExecute(){this.GetModel<IAirCombatAppModel>().Star.Value = _after;this.SendEvent<ChangeStarEvent>();}}public class SetDiamondCommand : AbstractCommand{int _after = 0;public SetDiamondCommand(int change){_after = change;}protected override void OnExecute(){this.GetModel<IAirCombatAppModel>().Diamond.Value = _after;this.SendEvent<ChangeDiamondEvent>();}}public class ChangeDiamondCommand : AbstractCommand<bool>{int _change = 0;/// <summary>增加正,减少负</summary>public ChangeDiamondCommand(int change){_change = change;}protected override bool OnExecute(){var model = this.GetModel<IAirCombatAppModel>();int cur = model.Diamond;int after = cur + _change;if (after >= 0)//有钱&&上升空间{model.Diamond.Value = after;this.SendEvent<ChangeDiamondEvent>();return true;}else{string str = "你没钻石了!";str += "需要" + _change;str.LogInfo();// UIManager.Single.ShowDialog("你没星星了!");return false;}}}public class IncreasePlanePropertyCommand : AbstractCommand{PlaneProperty.Property _planeProperty;public IncreasePlanePropertyCommand(PlaneProperty.Property planeProperty){_planeProperty = planeProperty;}public IncreasePlanePropertyCommand(string planePropertyString){_planeProperty = planePropertyString.String2Enum<PlaneProperty.Property>();}protected override void OnExecute(){string planeID = this.GetModel<IAirCombatAppModel>().SelectPlaneID.ToString();string property = "";switch (_planeProperty){case PlaneProperty.Property.attack:{property  = DataKeys.ATTACK;}break;case PlaneProperty.Property.fireRate:{property  = DataKeys.FIRE_RATE;}break;case PlaneProperty.Property.life:{property  = DataKeys.LIFE;}break;default: break;}//string maxKey = KeysUtil.GetPropertyKeys(planeID + property + PropertyItem.ItemKey.maxVaue);string curKey = KeysUtil.GetPropertyKeys(planeID + property + PropertyItem.ItemKey.value);string grouthKey = KeysUtil.GetPropertyKeys(planeID + property + PropertyItem.ItemKey.grouth);int max = DataMgr.Single.Get<int>(maxKey);int cur = DataMgr.Single.Get<int>(curKey);int grouth = DataMgr.Single.Get<int>(grouthKey);int after = cur + grouth;if ( cur < max)//有上升空间{if (after >= max)//到顶了{                                                                  after = max;}string valueKey = KeysUtil.GetPropertyKeys( planeID + property + ItemKey.value);DataMgr.Single.Set<int>(valueKey, after);Debug.LogFormat("IncreasePlanePropertyCommand {0}:{1} ",valueKey, after);this.SendEvent<IncreasePlanePropertyEvent>();}else{("数值到顶了!").LogInfo();// UIManager.Single.ShowDialog("你没星星了!");}}}public class IncreasePlaneAttackCommand : AbstractCommand{int _change;public IncreasePlaneAttackCommand(int change){_change = change;}protected override void OnExecute(){int id = this.GetModel<IAirCombatAppModel>().SelectPlaneID;string pre = id + DataKeys.ATTACK;////int max = DataMgr.Single.Get<int>(pre + ItemKey.maxVaue);int cur = DataMgr.Single.Get<int>(pre + ItemKey.value);int after = cur+_change;if ( after >= 0 && cur < max)//有上升空间{if (after >= max)//到顶了{after = max;}DataMgr.Single.SetObject(pre + ItemKey.value, after);}else{("数值到顶了!").LogInfo();// UIManager.Single.ShowDialog("你没星星了!");}}}public class IncreasePlaneFireRateCommand : AbstractCommand{int _value;public IncreasePlaneFireRateCommand(int value){_value = value;}protected override void OnExecute(){}}public class IncreasePlaneLifeCommand : AbstractCommand{int _value;public IncreasePlaneLifeCommand(int value){_value = value;}protected override void OnExecute(){}}/// <summary>直接升级(费用判断另作处理)</summary>public class UpgradesPlaneLevelCommand : AbstractCommand{protected override void OnExecute(){ChangeLevel();    this.SendEvent<UpgradesPlaneLevelEvent>();ChangeData();this.SendEvent<IncreasePlanePropertyEvent>();//}private void ChangeData(){               //获取升级系数,修改数据var ratioKey = KeysUtil.GetPropertyKeysWithoutPlaneId(DataKeys.UPGRADES_RATIO);var ratio = DataMgr.Single.Get<int>(ratioKey);ChangeData(ratio, PropertyItem.ItemKey.value, PlaneProperty.Property.attack);ChangeData(ratio, PropertyItem.ItemKey.maxVaue, PlaneProperty.Property.attack);ChangeData(ratio, PropertyItem.ItemKey.grouth, PlaneProperty.Property.attack);//ChangeData(ratio, PropertyItem.ItemKey.value, PlaneProperty.Property.life);ChangeData(ratio, PropertyItem.ItemKey.maxVaue, PlaneProperty.Property.life);ChangeData(ratio, PropertyItem.ItemKey.grouth, PlaneProperty.Property.life);}void ChangeLevel(){int planeID = this.GetModel<IAirCombatAppModel>().SelectPlaneID;string curKey = KeysUtil.GetPropertyKeys(planeID + DataKeys.LEVEL);string maxKey = KeysUtil.GetPropertyKeys(planeID + DataKeys.LEVEL_MAX);int cur = DataMgr.Single.Get<int>(curKey);int max = DataMgr.Single.Get<int>(maxKey);int after = cur + 1;after = after.Clamp(0, max - 1);DataMgr.Single.SetObject(curKey, after);}/// <summary>暂时设定为 grouth和max乘以系数</summary>private void ChangeData(int ratio, PropertyItem.ItemKey itemKey, PlaneProperty.Property property){int planeID = this.GetModel<IAirCombatAppModel>().SelectPlaneID;var key = KeysUtil.GetPropertyKeys(planeID + property.ToString() + itemKey);var value = DataMgr.Single.Get<int>(key);value *= ratio;DataMgr.Single.Set(key, value);}}public class SwitchHeroCommand : AbstractCommand{int _heroID = 0;public SwitchHeroCommand(int heroID){_heroID = heroID;}protected override void OnExecute(){this.GetModel<AirCombatAppModel>().SelectHeroID.Value = _heroID;this.SendEvent<SelectHeroIDEvent>();}}public class SwitchPlaneCommand : AbstractCommand{int _change = 0;public SwitchPlaneCommand(int change){_change = change;}protected override void OnExecute(){if (_change != 1 && _change != -1) //飞机的切换是顺序的{return;}int max = PlaneSpritesModel.Single.Count;int id = this.GetModel<IAirCombatAppModel>().SelectPlaneID;id += _change;                             id = id.Clamp(0, max - 1);// id = (id < 0 ) ? 0 : id >= max ? id = max - 1 : id;//string str = (_change == -1) ? "左" : "右";(str + "键:" + id).LogInfo();//this.GetModel<IAirCombatAppModel>().SelectPlaneID.Value = id;this.SendEvent<SelectPlaneIDEvent>();}}public class SetPlaneCommand : AbstractCommand{int _planeID = 0;public SetPlaneCommand(int planeID){_planeID = planeID;}protected override void OnExecute(){int max = PlaneSpritesModel.Single.Count;if (_planeID < 0 || _planeID > max-1) {return;}//this.GetModel<IAirCombatAppModel>().SelectPlaneID.Value = _planeID;GameStateModel.Single.SelectedPlaneId = _planeID;this.SendEvent<SelectPlaneIDEvent>();}}public class OpenSelectHeroPanelCommand : AbstractCommand{protected override void OnExecute(){UIKit.OpenPanel<SelectHeroPanel>();}}public class OpenStartGamePanelCommand : AbstractCommand{protected override void OnExecute(){UIKit.OpenPanel<StartGamePanel>();}}public class OpenStrengthenPanelCommand : AbstractCommand{Action _onComplete;/// <summary>比如设置了金币,但是对金币的监听是在打开面板是才注册的,所以onComplete才好触发</summary>public OpenStrengthenPanelCommand(Action onComplete){_onComplete = onComplete;}public OpenStrengthenPanelCommand(){}protected override void OnExecute(){//这块是上个界面,选择飞机的界面来做的(如果再直接打开升级界面邮箱使用返回按钮的情况下可以用) UIKit.OpenPanel<SelectHeroPanel>();UIKit.Stack.Push<SelectHeroPanel>();UIKit.HidePanel<SelectHeroPanel>();//UIManager.Single.Show(Paths.PREFAB_STRENGTHEN_VIEW);UIKit.OpenPanel<StrengthenPanel>();"打开升级面板".LogInfo();//_onComplete.DoIfNotNull();}}public class ExitGameCommand : AbstractCommand{protected override void OnExecute(){Application.Quit();"退出游戏".LogInfo();}}#endregion#region Utilitypublic interface IStorage : IUtility{void SaveInt(string key, int value);int LoadInt(string key, int defaultValue = 0);void SaveString(string key, string value);string LoadString(string key, string defaultValue = "");void SaveFloat(string key, float value);float LoadFloat(string key, float defaultValue = 0.0f);}public class PlayerPrefsStorage : IStorage{public void SaveInt(string key, int value){PlayerPrefs.SetInt(key, value);}public int LoadInt(string key, int defaultValue = 0){return PlayerPrefs.GetInt(key, defaultValue);}public void SaveString(string key, string value){PlayerPrefs.SetString(key, value);}public string LoadString(string key, string defaultValue = ""){return PlayerPrefs.GetString(key, defaultValue);}public void SaveFloat(string key, float value){PlayerPrefs.SetFloat(key, value);}public float LoadFloat(string key, float defaultValue = 0.0f){return PlayerPrefs.GetFloat(key, defaultValue);}}public class JsonStorage : IStorage{public void SaveInt(string key, int value){PlayerPrefs.SetInt(key, value);}public int LoadInt(string key, int defaultValue = 0){return PlayerPrefs.GetInt(key, defaultValue);}public void SaveString(string key, string value){PlayerPrefs.SetString(key, value);}public string LoadString(string key, string defaultValue = ""){return PlayerPrefs.GetString(key, defaultValue);}public void SaveFloat(string key, float value){PlayerPrefs.SetFloat(key, value);}public float LoadFloat(string key, float defaultValue = 0.0f){return PlayerPrefs.GetFloat(key, defaultValue);}}#endregion#region Eventpublic class UpgradesPlaneLevelEvent{ }public class IncreasePlanePropertyEvent{}public class ChangeStarEvent{}public class ChangeDiamondEvent{}public class SelectHeroIDEvent{}public class SelectPlaneIDEvent{}#endregion#region Architecturepublic class AirCombatApp : Architecture<AirCombatApp>{protected override void Init(){// 注册 System //this.RegisterSystem<IAchievementSystem>(new AchievementSystem());// 注册 Modelthis.RegisterModel<IAirCombatAppModel>(new AirCombatAppModel());// 注册存储工具的对象this.RegisterUtility<IStorage>(new PlayerPrefsStorage());this.RegisterUtility<IStorage>(new JsonStorage());}protected override void ExecuteCommand(ICommand command){Debug.Log("Before " + command.GetType().Name + "Execute");base.ExecuteCommand(command);Debug.Log("After " + command.GetType().Name + "Execute");}protected override TResult ExecuteCommand<TResult>(ICommand<TResult> command){Debug.Log("Before " + command.GetType().Name + "Execute");var result = base.ExecuteCommand(command);Debug.Log("After " + command.GetType().Name + "Execute");return result;}}#endregion}

---------------------------------------------------------

05 Scene 关卡选择

watch 原本的样式

4列乘以6行
这里乱了,是因为原始Panel拖到了QF的UIRoot,还没调整

在这里插入图片描述

modify 关卡选择面板

modify 关卡选择面板,关卡子项,加载面板

同上,创建预制体(复制旧的)
添加Bind
标记QF ABMark和New AB名字(_prefab的格式)
CreateUICode
在这里插入图片描述
在这里插入图片描述

modify 关卡选择面板

打开面板就发送实例Command(将操作从面板中分离开)

using UnityEngine;
using UnityEngine.UI;
using QFramework;namespace QFramework.AirCombat
{public class SelectLevelPanelData : UIPanelData{}public partial class SelectLevelPanel : UIPanel,IController{protected override void OnInit(IUIData uiData = null){mData = uiData as SelectLevelPanelData ?? new SelectLevelPanelData();// please add init code here//LevelsTrans.transform ;//LevelRoot levelRoot;//LevelRootController levelRootController;//LevelsView levelsView;//LevelsController levelsController;//LevelItem levelItem;//LevelItemController levelItemController;this.SendCommand( new InstantiateLevelSelectableCommand(LevelsTrans));this.RegisterEvent<OpenLoadingPanelEvent>(_ => { CloseSelf(); });#region BottomBackBtn.onClick.AddListenerAfterRemoveAll(() => {UIKit.Back<SelectHeroPanel>();CloseSelf();});#endregion}#region 重写 其它protected override void OnOpen(IUIData uiData = null){}protected override void OnShow(){}protected override void OnHide(){}protected override void OnClose(){}public IArchitecture GetArchitecture(){return AirCombatApp.Interface;}#endregion}
}

modify 实例关卡子项

这里看到Andy用了很多脚本。
所以先直接有用QF的ResLoader来达成效果

        void ReaderConfig(){ReaderConfig readerConfig;ReaderMgr readerMgr;string str=Paths.CONFIG_LEVEL_CONFIG;//ILoader iLoader;ResourceLoader resourceLoader;LoadMgr loadMgr;}

。。。
_levelsTrans.LoadAndInstantiateGameObject(“LevelSelectable”,24);是自定义的拓展,看下一 #
在这里插入图片描述

    public class InstantiateLevelSelectableCommand : AbstractCommand{RectTransform _levelsTrans;public InstantiateLevelSelectableCommand(RectTransform levelsTrans){_levelsTrans = levelsTrans;}protected override void OnExecute(){#region Level/*{"levelCount": 24,"eachRow": 4}             */#endregion//原本用到的脚本,写方便切换看{ LevelRoot levelRoot;LevelRootController levelRootController;LevelsView levelsView;LevelsController levelsController;LevelItem levelItem;LevelItemController levelItemController;            }//数量和行列{ IReader reader = ReaderMgr.Single.GetReader(Paths.CONFIG_LEVEL_CONFIG);// int levelCount=  reader[LevelRoot.Name.levelCount.Enum2String()].Get<>;}//实例{//GameObject go = LoadMgr.Single.LoadPrefabAndInstantiate(Paths.PREFAB_LEVEL_ITEM, _levelsTrans);_levelsTrans.LoadAndInstantiateGameObject("LevelSelectable",24);}// TODO 组件{ foreach (Transform trans in _levelsTrans){trans.AddComponent<LevelItem>();trans.AddComponent<LevelItemController>();}            }}}

modify 关卡子项排列

在这里插入图片描述

    public class InstantiateLevelSelectableCommand : AbstractCommand{RectTransform _levelsTrans;public InstantiateLevelSelectableCommand(RectTransform levelsTrans){_levelsTrans = levelsTrans;}protected override void OnExecute(){#region Level/*{"levelCount": 24,"eachRow": 4}             */#endregion//原本用到的脚本{ LevelsView levelsView;LevelsController levelsController;               LevelRoot levelRoot;LevelRootController levelRootController;LevelItem levelItem;LevelItemController levelItemController;            }//数量和行列{ IReader reader = ReaderMgr.Single.GetReader(Paths.CONFIG_LEVEL_CONFIG);// int levelCount=  reader[LevelRoot.Name.levelCount.Enum2String()].Get<>;}int levelCount = 24;int eachRow = 4; //一行多少个//实例{//GameObject go = LoadMgr.Single.LoadPrefabAndInstantiate(Paths.PREFAB_LEVEL_ITEM, _levelsTrans);_levelsTrans.LoadAndInstantiateGameObject("LevelSelectable", levelCount);}//排列{ for (int idx = 0; idx < levelCount; idx++){Transform levelSelectable = _levelsTrans.GetChild(idx);levelSelectable.name = "LevelSelectable_"+idx;SetPos(levelSelectable, GetGrid(idx, eachRow)) ;}              }// TODO 组件{ foreach (Transform trans in _levelsTrans){trans.AddComponent<LevelItem>();trans.AddComponent<LevelItemController>();}            }}#region 辅助 设置位置/// <summary>行,6行4列</summary>private Vector2 GetGrid(int id,int eachRow){var y = id / eachRow; //id/4第几行 var x = id % eachRow; //id%4第几个return new Vector2(x, y);}private void SetPos( Transform t,Vector2 gridId){int _leftOffet = 50; //上下行左右错开的值int _lineSpacing = 20;int _offset = 10;//var width = t.Rect().rect.width * t.localScale.x;var height = t.Rect().rect.height * t.localScale.y;var indention = gridId.y % 2 == 0 ? _leftOffet : 0;var x = indention + width * 0.5f + (_offset + width) * gridId.x;var y = height * 0.5f + (_lineSpacing + height) * gridId.y;t.Rect().anchoredPosition = new Vector2(x, -y);}#endregion}

modify 关卡子项解锁状态

关卡子项选择QF的UI生成代码,为了注册生成关卡子项时的,名字、位置和解锁状态

在这里插入图片描述

效果

在这里插入图片描述

LevelSelectable

using UnityEngine;
using UnityEngine.UI;
using QFramework;
using QFramework.AirCombat;
using UnityEngine.Purchasing;namespace QFramework.AirCombat
{public class LevelSelectableData : UIPanelData{}public partial class LevelSelectable : UIPanel, IController{public void Init(){int cur = transform.GetSiblingIndex();{ gameObject.name = "LevelSelectable_" + (cur);LevelText.SetText(cur+1);//现实的话不从0开始EnterBtn.onClick.AddListenerAfterRemoveAll(() =>{Debug.Log("LevelSelectable 进入关卡" + cur);this.SendCommand(new OpenLoadingPanelCommand(transform));});MaskBtn.onClick.AddListenerAfterRemoveAll(() =>{Debug.Log("LevelSelectable 当前关卡未开放");// UIManager.Single.ShowDialog("当前关卡未开放");});			}//this.RegisterEvent<UpdateLevelSelectableLockStateEvent>(eventId =>{Debug.Log("LevelSelectable RegisterEvent<InstantiateLevelSelectableEvent>");//能挑战已经通关的下一关int tar = this.GetModel<IAirCombatAppModel>().PassedLevel + 1;Debug.Log("LevelSelectable tar "+ tar );bool can = (cur <= tar);if (can){MaskBtn.Hide();}else{MaskBtn.Show();}});}#region 重写实现 protected override void OnInit(IUIData uiData = null){mData = uiData as LevelSelectableData ?? new LevelSelectableData();}protected override void OnOpen(IUIData uiData = null){}protected override void OnShow(){}protected override void OnHide(){}protected override void OnClose(){}public IArchitecture GetArchitecture(){return AirCombatApp.Interface;}#endregion}
}

InstantiateLevelSelectableCommand

    public class InstantiateLevelSelectableCommand : AbstractCommand{RectTransform _levelsTrans;public InstantiateLevelSelectableCommand(RectTransform levelsTrans){_levelsTrans = levelsTrans;}protected override void OnExecute(){#region Level/*{"levelCount": 24,"eachRow": 4}             */#endregion//原本用到的脚本{ LevelsView levelsView;LevelsController levelsController;               LevelRoot levelRoot;LevelRootController levelRootController;LevelItem levelItem;LevelItemController levelItemController;            }//数量和行列{ IReader reader = ReaderMgr.Single.GetReader(Paths.CONFIG_LEVEL_CONFIG);// int levelCount=  reader[LevelRoot.Name.levelCount.Enum2String()].Get<>;}int levelCount = 24;int eachRow = 4; //一行多少个//实例{//GameObject go = LoadMgr.Single.LoadPrefabAndInstantiate(Paths.PREFAB_LEVEL_ITEM, _levelsTrans);_levelsTrans.LoadAndInstantiateGameObject("LevelSelectable", levelCount);}//排列{ for (int idx = 0; idx < levelCount; idx++){Transform levelSelectable = _levelsTrans.GetChild(idx);SetPos(levelSelectable, GetGrid(idx, eachRow)) ;}}// TODO 组件{for (int idx = 0; idx < levelCount; idx++){Transform levelSelectable = _levelsTrans.GetChild(idx);levelSelectable.GetComponent<LevelSelectable>().Init();}}     this.SendEvent<UpdateLevelSelectableLockStateEvent>();}#region 辅助 设置位置/// <summary>行,6行4列</summary>private Vector2 GetGrid(int id,int eachRow){var y = id / eachRow; //id/4第几行 var x = id % eachRow; //id%4第几个return new Vector2(x, y);}private void SetPos( Transform t,Vector2 gridId){int _leftOffet = 50; //上下行左右错开的值int _lineSpacing = 20;int _offset = 10;//var width = t.Rect().rect.width * t.localScale.x;var height = t.Rect().rect.height * t.localScale.y;var indention = gridId.y % 2 == 0 ? _leftOffet : 0;var x = indention + width * 0.5f + (_offset + width) * gridId.x;var y = height * 0.5f + (_lineSpacing + height) * gridId.y;t.Rect().anchoredPosition = new Vector2(x, -y);}#endregion}

stars 拓展 QF的加载和示例

这种拓展用到了很多QF的脚本,建议直接放在QF的文件夹下

namespace QFramework
{public static class ExtndQFramework{public static void Example(Transform parent){LoadAndInstantiateGameObject("WhiteChess", parent);}public static GameObject LoadAndInstantiateGameObject(string likeWhiteChess,Transform parent){//在扫雷案例中测试的,用到WhiteChessResKit.Init();ResLoader loader = ResLoader.Allocate();GameObject prefab = loader.LoadSync<GameObject>(likeWhiteChess);GameObject   go= GameObject.Instantiate(prefab, parent);return go;}public static Transform LoadAndInstantiateGameObject(this Transform parent, string likeWhiteChess, int count){//在扫雷案例中测试的,用到WhiteChessResKit.Init();ResLoader loader = ResLoader.Allocate();GameObject prefab = loader.LoadSync<GameObject>(likeWhiteChess);for (int i = 0; i < count; i++){GameObject go = GameObject.Instantiate(prefab, parent);}return parent;}public static GameObject LoadGameObject(this string likeWhiteChess ){//在扫雷案例中测试的,用到WhiteChessResKit.Init();ResLoader loader = ResLoader.Allocate();GameObject go = loader.LoadSync<GameObject>(likeWhiteChess);return go;}}
}

Modify 加载界面的进度条,加载完打开游戏界面

watch 效果

写死的时间是有点长,但不长看不出效果
在这里插入图片描述

stars 进度条

    #region Smooth、Slider/// <summary>/// 以前看教程收集的一个例子/// </summary>/// <param name="mono">协程Mono</param>/// <param name="slider">滑动条</param>/// <param name="step">步进值</param>/// <param name="stepTime">步进时间</param>/// <param name="stepSmooth">步进平滑值</param>/// <exception cref="System.Exception"></exception>public static void PlayPrgSmooth(this MonoBehaviour mono, Slider slider, Text text, float step = 0.1f, float stepTime = 0.5f, float stepSmooth = 0.01f, Action onCompleted=null){if (step <= stepSmooth){throw new System.Exception("Prg step <= smooth异常");}mono.StartCoroutine(OnValueChangeSmooth(slider,text, step, stepTime, stepSmooth, onCompleted));}/// <summary>平滑点</summary>static IEnumerator OnValueChangeSmooth(Slider slider, Text text, float step, float stepTime, float stepSmooth, Action onCompleted){slider.value = 0f;text.SetText(0.00f);//float process = 0f;while (process < 1f){process += step;//类似帧循环,快点yield return new WaitUntil(() =>{float prg= Mathf.SmoothStep(from: slider.value, to: process, stepSmooth);text.SetText((prg).ToString("0.00%") ); //感觉要乘以100.0f,但不乘就有想要的效果slider.value = prg;return process - slider.value < stepSmooth;});yield return new WaitForSeconds(stepTime);//每0.5s会执行一遍循环体}slider.value = 1.0f;text.SetText("100.00%");onCompleted.DoIfNotNull();}#endregion

modify 打开加载界面时OpenLoadingPanelCommand

    public class OpenLoadingPanelCommand : AbstractCommand{protected override void OnExecute(){this.SendEvent<OpenLoadingPanelEvent>();//关闭关卡选择界面会注册事件//TODO 设置场景状态LoadingPanel panel= UIKit.OpenPanel<LoadingPanel>();panel.PlayPrgSmooth(panel.Slider, panel.PrgText, 0.2f, 0.5f, 0.05f, () => {this.SendCommand<OpenGamePanelCommand>();this.SendEvent<CloseLoadingPanelEvent>();//关闭加载界面会注册事件 });}}

modify TODO 打开游戏界面 OpenGamePanelCommand

    public class OpenGamePanelCommand : AbstractCommand{protected override void OnExecute(){Debug.Log("OpenGamePanelCommand");}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1474092.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

LabVIEW在图像处理中的应用

abVIEW作为一种图形化编程环境&#xff0c;不仅在数据采集和仪器控制领域表现出色&#xff0c;还在图像处理方面具有强大的功能。借助其Vision Development Module&#xff0c;LabVIEW提供了丰富的图像处理工具&#xff0c;广泛应用于工业检测、医学影像、自动化控制等多个领域…

C语言 -- 扫雷游戏

C语言 – 扫雷游戏 游戏规则&#xff1a; 给定一个棋盘&#xff0c;玩家需要排查出所有隐藏的雷&#xff0c;也就是选择出所有不是雷的地方。 玩家选择位置&#xff0c;若此处有雷&#xff0c;玩家被炸死&#xff0c;游戏结束&#xff1b; 若此处无雷&#xff0c;此处提示周围一…

【零基础】学JS

喝下这碗鸡汤 “知识就是力量。” - 弗朗西斯培根 1.三元运算符 目标:能利用三元运算符执行满足条件的语句 使用场景:其实是比if双分支更简单的写法&#xff0c;可以使用三元表达式 语法&#xff1a;条件 ? 满足条件的执行代码 : 不满足条件执行的代码 接下来用一个小案例来展…

【瑞数补环境实战】某网站Cookie补环境与后缀分析还原

文章目录 1. 写在前面2. 特征分析3. 接口分析3. 补JS环境4. 补后缀参数 【&#x1f3e0;作者主页】&#xff1a;吴秋霖 【&#x1f4bc;作者介绍】&#xff1a;擅长爬虫与JS加密逆向分析&#xff01;Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走…

ubuntu22.04+pytorch2.3安装PyG图神经网络库

ubuntu下安装torch-geometric库&#xff0c;图神经网络 开发环境 ubuntu22.04 conda 24.5.0 python 3.9 pytorch 2.0.1 cuda 11.8 pyg的安装网上教程流传着许多安装方式&#xff0c;这些安装方式主要是&#xff1a;预先安装好pyg的依赖库&#xff0c;这些依赖库需要对应上pyth…

代码随想录 数组部分+代码可在本地编译器运行

代码随想录 数组部分&#xff0c;代码可在本地编译器运行 文章目录 数组理论基础704.二分查找题目&#xff1a;思路二分法第一种写法二分法第二种写法 代码 27.移除元素题目&#xff1a;思路-双指针法代码 977.有序数组的平方题目思路-双指针代码 209.长度最小的子数组题目&am…

Lua语言入门

目录 Lua语言1 搭建Lua开发环境1.1 安装Lua解释器WindowsLinux 1.2 IntelliJ安装Lua插件在线安装本地安装 2 Lua语法2.1 数据类型2.2 变量全局变量局部变量命名规范局部变量作用域 2.3 注释单行注释多行注释 2.4 赋值2.5 操作符数学操作符比较操作符逻辑操作符连接操作符取长度…

安卓虚拟位置修改1.25beta支持路线模拟、直接定位修改

导语:更新支持安卓14/15&#xff0c;支持路线模拟、直接定位修改&#xff0c;仅支持单一版本 无root需根据教程搭配下方链接所提供的虚拟机便可进行使用 有root且具备XP环境可直接真机运行 如你有特殊需求 重启问题设置打开XP兼容 针对具有虚拟机检测的软件 建议如下 度娘搜索…

Python结合MobileNetV2:图像识别分类系统实战

一、目录 算法模型介绍模型使用训练模型评估项目扩展 二、算法模型介绍 图像识别是计算机视觉领域的重要研究方向&#xff0c;它在人脸识别、物体检测、图像分类等领域有着广泛的应用。随着移动设备的普及和计算资源的限制&#xff0c;设计高效的图像识别算法变得尤为重要。…

机器学习原理之 -- 神经网络:由来及原理详解

神经网络&#xff08;Neural Networks&#xff09;是受生物神经系统启发而设计的一类计算模型&#xff0c;广泛应用于图像识别、语音识别、自然语言处理等领域。其基本思想是通过模拟人脑神经元的工作方式&#xff0c;实现对复杂数据的自动处理和分类。本文将详细介绍神经网络的…

Http Json参数到x-www-form-urlencoded参数的在线转换工具

Json参数到x-www-form-urlencoded参数的在线转换工具

本周23个Github有趣项目llama-agents等

23个Github有趣的项目、工具和库 1、Positron 下一代数据科学 IDE。 您使用 VS Code 进行数据科学&#xff08;Python 或 R&#xff09;&#xff0c;但希望它包含专用控制台、变量窗格、数据浏览器和其他用于特定数据工作的功能。您使用 Jupyterlab 进行数据科学&#xff08;…

求职成功率的算法,与葫芦娃救爷爷的算法,有哪些相同与不同

1 本节概述 通过在B站百刷葫芦娃这部儿时剧&#xff0c;我觉得可以从中梳理出一些算法&#xff0c;甚至可以用于求职这个场景。所以&#xff0c;大家可以随便问我葫芦娃的一些剧情和感悟&#xff0c;我都可以做一些回答。 2 葫芦娃救爷爷有哪些算法可言&#xff1f; 我们知道…

AE的首选项设置

打开AE,点击 编辑->首选项->常规 显示 点击“所有关键帧”&#xff0c;这样显示路径就会显示所有关键帧 导入 将序列素材改为25帧每秒&#xff0c;作为以后制作的默认 媒体和磁盘缓存 根据个人需求选择磁盘缓存的文件夹&#xff0c;如果d盘空间充足&#xff0c;就改成…

Linux——进程间通信一(共享内存、管道、systrem V)

一、进程间通信介绍 1.1、进程间通信的概念和意义 进程间通信(IPC interprocess communication)是一组编程接口&#xff0c;让不同进程之间相互传递、交换信息(让不同的进程看到同一份资源) 数据传输:一个进程需要将它的数据发送给另外一个进程 资源共享:多个进程之间共享同样…

WY-35A4T三相电压继电器 导轨安装 约瑟JOSEF

功能简述 WY系列电压继电器是带延时功能的数字式交流电压继电器。 可用于发电机&#xff0c;变压器和输电线的继电保护装置中&#xff0c;作为过电压或欠电压闭锁的动作元件 LCD实时显示当前输入电压值 额定输入电压Un:100VAC、200VAC、400VAC产品满足电磁兼容四级标准 产品…

开放式耳机哪个牌子好?悠律、漫步者、韶音全面对比与推荐

对于现在的无线耳机市场而言&#xff0c;开放式耳机迎来的真正的大爆发&#xff0c;关键的是它采用了定向传声方式&#xff0c;我们在运动时除了可以感受到音乐带来的快乐外&#xff0c;还能时刻保持对外界环境音的警觉。 今天&#xff0c;我们将为大家详细对比推荐三款备受瞩…

Docker 容器网络及其配置说明

Docker 容器网络及其配置说明 docker容器网络docker的4种网络模式bridge 模式container模式host 模式none 模式应用场景 docker 容器网络配置Linux 内核实现名称空间的创建创建 Network Namespace操作 Network Namespace 转移设备veth pair创建 veth pair实现 Network Namespac…

力扣双指针算法题目:二叉树的层序遍历(BFS)

目录 1.题目 2.思路解析 3.代码 1.题目 . - 力扣&#xff08;LeetCode&#xff09; 2.思路解析 对二叉树进行层序遍历&#xff0c;顾名思义&#xff0c;就是按每一层的顺序对二叉树一层一层地进行遍历 思路如下 从第一层开始&#xff0c;先将二叉树地头放入队列q&#xff0…

永磁同步电机参数辨识算法--模型参考自适应辨识电感

本文采用 MRAS 在线辨识电感参数&#xff08;Ld、Lq&#xff09; 一、原理介绍 从组成部分来看&#xff0c;MRAS由三个重要部分构成分别为参考、可调以及自适应律。参考模型相当于IPMSM 参数实时变化的准确值&#xff0c;即作为可调模型的参考值&#xff0c;可调模型依据参数…