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()
{
// Enemy
EnemyLifeItem enemyLifeItem;
EnemyLifeView enemyLifeView;
MissileView missileView;
MissileWarning missileWarning;
PlaneEnemyView planeEnemyView;
// ItemView
AddBulletView 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());//DataUtil
Empty4Raycast 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()
{
//Module
ExplainDialogModule explainDialogModule;
HandModule handModule;
HighLightModule highLightModule;
//Guide
SelectedHeroViewGuide selectedHeroViewGuide;
StartViewGuide startViewGuide;
//Group
ShowHerosGroup showHerosGroup;
StartViewGroup startViewGroup;
//Demo
TestDemo.StartViewGuide testDemo_StartViewGuide;
TestDemo.DemoGuideGroupA testDemo_DemoGuideGroupA;
TestDemo.Demo1GuideGroup testDemo_Demo1GuideGroup;
TestDemo.Demo2GuideGroup testDemo_Demo2GuideGroup;
TestDemo.ClickButtonA testDemo_ClickButtonA;
//
TestDemo.GuideMgr testDemo_MuideMgr;
//Behaviour
ShowHerosBehaviour 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()); //PlayerPrefers
DataMgr.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 here
ResKit.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 Model
internal 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>();
#endregion
protected 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
//上方的Money
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
{
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); //300
int 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,life
string 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,这个Transform
Transform trans = rect.Find( transName );
if (trans != null)
{
string key = KeysUtil.GetPropertyKeys(planeId, property + propertyKey); //0attackname
Debug.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();//attack
Slider slider = trans.Find("Slider").GetComponent<Slider>();
string maxVaueKey = KeysUtil.GetPropertyKeys(planeId, property+ ItemKey.maxVaue); //0attackmaxVaue(原文没加l)
string valueKey = KeysUtil.GetPropertyKeys(planeId , property + ItemKey.value);//0attackvalue
Debug.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); //300
CostText.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-41eaf4781fcc
public 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 System
public 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 Utility
public 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());
// 注册 Model
this.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
// 引入 Command
public 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
// Controller
public class CounterAppController : MonoBehaviour , IController /* 3.实现 IController 接口 */
{
// View
private Button mBtnAdd;
private Button mBtnSub;
private Text mCountText;
// 4. Model
private 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>();
#endregion
protected 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 Top
this.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 Bottom
BackBtn.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,life
int 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"}
},
**/
#endregion
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);
//
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,life
int 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"}
},
*/
#endregion
foreach (var rect in _propertyItemLst)
{
string property = (rect.name).TrimName(TrimNameType.DashAfter).LowerFirstLetter();//attack,fireRate,life
int 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();//attack
string 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);//0attackvalue
float 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 QF
IArchitecture 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 Model
internal 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
// 引入 Command
public 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 Utility
public 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 Event
public class UpgradesPlaneLevelEvent
{
}
public class IncreasePlanePropertyEvent
{
}
public class ChangeStarEvent
{
}
public class ChangeDiamondEvent
{
}
public class SelectHeroIDEvent
{
}
public class SelectPlaneIDEvent
{
}
#endregion
#region Architecture
public class AirCombatApp : Architecture<AirCombatApp>
{
protected override void Init()
{
// 注册 System
//this.RegisterSystem<IAchievementSystem>(new AchievementSystem());
// 注册 Model
this.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 Bottom
BackBtn.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)
{
//在扫雷案例中测试的,用到WhiteChess
ResKit.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)
{
//在扫雷案例中测试的,用到WhiteChess
ResKit.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 )
{
//在扫雷案例中测试的,用到WhiteChess
ResKit.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");
}
}