用QFramework重构飞机大战(Siki Andy的)(下01)(06-0? 游戏界面及之后的所有面板)

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

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

06 Scene 战斗

modify ItemCDEffect

stars SetPos、SetScale提取到拓展类

类似的可以延伸 (QF有类似的,为了链式编程没有加Set)
SetPosX
SetPosY
SetPosZ
SetPosXY
SetPosXZ
SetPosYZ
SetLocalPosX
SetLocalPosY
SetLocalPosZ
SetLocalPosXY
SetLocalPosXZ
SetLocalPosYZ
在这里插入图片描述

    public static T SetPos<T>(this T t, Vector3 pos) where T:Component{t.transform.position = pos;return t;}public static T SetScale<T>(this T t, Vector3 scale) where T : Component{t.transform.localScale = scale;return t;}

在这里插入图片描述

bug there is no implicit conversion between ‘method group’ and ‘method group’

在这里插入图片描述

在这里插入图片描述

stars DoIfNotNull

TaskQueue中出现多次含有两个参数的Action

    public void Execute(Action<object[]> complete){_onComplete = complete;_values = new object[_tasks.Count];while (_tasks.Count > 0){_id++;var task = _tasks.Dequeue();task.DoIfNotNull(this, _id);}ResetData();}
    public static Action<T1,T2> DoIfNotNull<T1, T2>(this Action<T1, T2> cb, T1 t1,T2 t2){if (cb != null){cb(t1,t2);}return cb;}

bug 未能实例出面板

回去打开初始工程看情况。
发现 第四季的到这都报了错,在LaunchGame中注释掉 新手引导Mgr的运行,能正常运行

在这里插入图片描述

watch 这里跳到前面的朴素分类法进行分解

最终得到Game场景的脚本分布
在这里插入图片描述

        }void All(){   ......//{    //PoolMgr{BulletPool();PlanePool_Null();ItemPool_Null();FrameAniPool_Null();MissilePool_Null ();LightPool_Null();}//Game游戏中{ GameRoot gameRoot;GameLayerMgr gameLayerMgr;GameEvent gameEvent;{MainCamera();Map();Effect();PlaneEnemy();}}{//DontDestroyOnLoad Mgr();Canvas();}}}private void Canvas(){//GameUI{GameUIView gameUIView;GameUIController gameUIController;UiUtil uiUtil;//Life life;//Shield shield;ShieldController shieldController;ItemEffect itemEffect;ItemCDEffect itemCDEffect;//Power power;PowerController powerController;}//GameResultView{GameResultController gameResultController;GameResultView gameResultView;UiUtil uiUtil; Empty4Raycast empty4Raycast;}}private void Mgr(){CoroutineMgr coroutineMgr;LifeCycleMgr lifeCycleMgr;AudioMgr audioMgr;}private void LightPool_Null(){throw new NotImplementedException();}private void MissilePool_Null(){throw new NotImplementedException();}private void FrameAniPool_Null(){throw new NotImplementedException();}private void ItemPool_Null(){throw new NotImplementedException();}private void PlanePool_Null(){throw new NotImplementedException();}private void BulletPool(){Bullet bullet;BulletEffectMgr bulletEffectMgr;MoveComponent moveComponent;BulletCollideMsgComponent bulletCollideMsgComponent;BulletBehaviour bulletBehaviour;}private void MainCamera(){CameraMove cameraMove;GameProcessMgr gameProcessMgr;MoveComponent moveComponent;}private void PlaneEnemy(){{//Plane节点 PlaneEnemyView planeEnemyView;RenderComponent renderComponent;CameraMove cameraMove;AutoDespawnComponent autoDespawnComponent;EnemyTypeComponent enemyTypeComponent;LifeComponent lifeComponent;SubMsgMgr subMsgMgr;EnemyBehaviour enemyBehaviour;MoveComponent moveComponent;ColliderComponent colliderComponent;PlaneCollideMsgComponent planeCollideMsgComponent;}{ //Plane的子节点BulletRootEnemyBulletMgr enemyBulletMgr;EmitBulletMgr emitBulletMgr;BossBulletEventComponent bossBulletEventComponent;SpawnBulletPointMgr spawnBulletPointMgr;}{Plane的子节点EnemyLife EnemyLifeView enemyLifeView;}{EnemyLife的子节点Item_0,1,2,3EnemyLifeItem enemyLifeItem;}}private void Effect(){BulletDestroyAniView bulletDestroyAniView;PlaneDestroyAniView planeDestroyAniView;FrameAni frameAni;}private void Map(){MapMgr mapMgr;MapItem mapItem;MapCloud mapCloud;}

bug 点击英雄选择时无效,写死是第一个

因为枚举和图像名字是对应的。我可能改动了枚举(头字母小写转成大写)
所以默认成第一个,就是第一张图总亮,也总是她的声音

/// <summary>关联到人物语音的枚举。维持大小写</summary>
public enum Hero
{Player_0,Player_1,Player_2
}

。。。。
需要改动两处
HeroItem(控制颜色)
HeroItemController(控制音效、SelectHero)

统一用这样的写法//String2Enum字符串转枚举,前面应该有提到过

            string spriteName = transform.GetComponent<Image>().sprite.name;_hero = (spriteName.UpperFirstLetter()).String2Enum<Hero>();

。。。。
暴露参数看效果
在这里插入图片描述

bug 第二次点击相同的的英雄,音效会马上停止

自身逻辑问题,只考虑到不同英雄。
可以加上一个相同英雄的音效判定

HeroItemController

    private void Selected(){GameStateModel.Single.SelectedHero = _hero;if (AudioMgr.Single.CurAudioName() == _hero.ToString()){AudioMgr.Single.Replay(_hero.ToString());return;}AudioMgr.Single.Play(_hero.ToString());Debug.Log("HeroItemController "+ _hero.ToString());}

AudioMgr

    public string CurAudioName(){if (GetSource().clip != null){return GetSource().clip.name;}return String.Empty ;}

modify 地图之相机

初始项目

移动的是相机,图是不动的
在这里插入图片描述

启动脚本 GameStart05

主要是这块,其它是复制之前的

void OpenPanelFunc(  ){this.GetModel<IAirCombatAppModel>().SelectPlaneID.Value = 0;this.GetModel<IAirCombatAppModel>().SelectHeroID.Value = 0;this.GetModel<IAirCombatAppModel>().PassedLevel.Value = 10;this.GetModel<IAirCombatAppModel>().SelectLevel.Value = 10;this.SendCommand<OpenGamePanelCommand>();}
using System;
using System.Collections;
using System.Linq;
using LitJson;
using QFramework;
using QFramework.Example;
using UnityEngine;namespace QFramework.AirCombat
{ 
public class GameStart05 : 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.Game;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(3f);//延时让json数据初始化if (true){ResKit.Init();{// OpenPanelFunc();}}}void OpenPanelFunc(  ){this.GetModel<IAirCombatAppModel>().SelectPlaneID.Value = 0;this.GetModel<IAirCombatAppModel>().SelectHeroID.Value = 0;this.GetModel<IAirCombatAppModel>().PassedLevel.Value = 10;this.GetModel<IAirCombatAppModel>().SelectLevel.Value = 10;this.SendCommand<OpenGamePanelCommand>();}#region 重写public IArchitecture GetArchitecture(){return AirCombatApp.Interface;}#endregion  }}

相机移动 OpenGamePanelCommand

地图是已有的预制体解除脚本了的,

    public class OpenGamePanelCommand : AbstractCommand{protected override void OnExecute(){GameStateModel.Single.CurScene = SceneName.Game;Debug.Log("OpenGamePanelCommand");{// Camera.main.GetOrAddComponent<MainCameraCtrl>().Init(1f, Vector2.up);//Camera.main.GetOrAddComponent<CameraMove>();//Camera.main.GetOrAddComponent<MoveComponent>();//Camera.main.GetOrAddComponent<GameProcessMgr>(); //尚未研究           }}}

相机移动脚本

后面在说玩家的MoveCommand时,可以尝试改成MoveUpCommand

/****************************************************文件:MainCameraCtrl.cs作者:lenovo邮箱: 日期:2023/8/16 21:11:50功能:
*****************************************************/using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;namespace QFramework.AirCombat
{public class MainCameraCtrl : MonoBehaviour  ,IController{#region 属性public float _speed;public Vector2 _dir;#endregion#region 生命public void Init(float speed, Vector2 dir){_speed = speed;_dir = dir;}/// <summary>首次载入且Go激活</summary>void Start(){//  CameraMove cameraMove;GameProcessMgr gameProcessMgr;MoveComponent moveComponent;}void Update(){if (_speed != 0 && _dir != null){transform.Translate( _dir * _speed * Time.deltaTime, Space.World );}}#endregion#region 实现public IArchitecture GetArchitecture(){return AirCombatApp.Interface;}#endregion  }
}

效果

按下P
在这里插入图片描述

modify 地图之图片

GameStart05

改一部分,其它照抄前面的

        private void Update(){if (Input.GetKeyDown(KeyCode.Q)) //确定是json数据初始慢导致强化面板获取数据失败{OpenPanelFunc();}if (Input.GetKeyDown(KeyCode.W)){this.GetModel<IAirCombatAppModel>().SelectLevel.Value ++;}}

MapItemCtrl

/****************************************************文件:MainCameraCtrl.cs作者:lenovo邮箱: 日期:2023/8/16 21:11:50功能:
*****************************************************/using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;namespace QFramework.AirCombat
{public class MapItemCtrl : MonoBehaviour,IController{#region 属性private float _offsetY;private MapCloud _cloud;private Transform _camera;private SpriteRenderer _renderer;private static int _curLevel;#endregion#region 生命public void Init(float offsetY, Transform camera){_offsetY = offsetY;_camera = camera;_renderer = GetComponent<SpriteRenderer>();_curLevel = GameCurLevel();_cloud = transform.GetChild(0).GetOrAddComponent<MapCloud>();SetSprite(_curLevel);}void Update(){if (JugdeUpdate(_offsetY, _camera)){UpdatePos(_offsetY);UpdateSprite();UpdateLevel();}}#endregion#region 辅助int GameCurLevel (){//return GameModel.Single.CurLevel;return this.GetModel<IAirCombatAppModel>().SelectLevel;}private bool JugdeUpdate(float offset, Transform camera){return (camera.position.y - transform.position.y) >= offset;}private void UpdateLevel(){bool isActive = (_curLevel != GameCurLevel());_cloud.SetActive(isActive);if (isActive){_curLevel = GameCurLevel();}}private void UpdatePos(float offset){transform.SetPosY(transform.position.y + offset * 2);}private void UpdateSprite(){SetSprite(GameCurLevel());}private void SetSprite(int level){var pre = Paths.PICTURE_MAP_FOLDER + Const.MAP_PREFIX;var sprite = LoadMgr.Single.Load<Sprite>(pre + level);if (sprite == null){Debug.Log("MapItemCtrl 还没有所设关卡数的关卡图片=>"+ level);sprite = LoadMgr.Single.Load<Sprite>(pre + 0);}_renderer.sprite = sprite;}#endregion#region 实现public IArchitecture GetArchitecture(){return AirCombatApp.Interface;}#endregion  }
}

MapCloud不改

OpenGamePanelCommand

    public class OpenGamePanelCommand : AbstractCommand{protected override void OnExecute(){GameStateModel.Single.CurScene = SceneName.Game;Debug.Log("OpenGamePanelCommand");{// Camera.main//Camera.main.GetOrAddComponent<CameraMove>();//Camera.main.GetOrAddComponent<MoveComponent>();//Camera.main.GetOrAddComponent<GameProcessMgr>();//尚未研究//Camera.main.GetOrAddComponent<MainCameraCtrl>().Init(1f, Vector2.up);}{//Map图片Transform mapMgrTrans = Camera.main.transform.FindTop("MapMgr");MapMgr mapMgr;MapItem mapItem;MapCloud mapCloud;//var map0 = mapMgrTrans.Find("map_0");var map1 = mapMgrTrans.Find("map_1");var offsetY = Mathf.Abs(map1.position.y - map0.position.y);Transform camera = Camera.main.transform;map0.GetOrAddComponent<MapItemCtrl>().Init(offsetY, camera);map1.GetOrAddComponent<MapItemCtrl>().Init(offsetY, camera);//}}}

效果

按P运行
按W换图
在这里插入图片描述

stars GetOrAddComponentDeep

    public static T GetOrAddComponentDeep<T>(this Transform root, string childName) where T : Component{Transform result = null;result = root.FindChildDeep(childName);if (result != null){if (result.GetComponent<T>() != null){ return result.GetComponent<T>();}return  result.AddComponent<T>();}else{Debug.LogErrorFormat("{0}未找到子节点{1}", root.name, childName);return null;}}

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

watch 这里同一个Scene也升一下目录,内容比较多

06 Scene 战斗 modify 玩家

在场景中的位置

GameRoot/PLANE/第一个子节点
在这里插入图片描述
在这里插入图片描述

脚本

挂了两个MoveComponent,盲猜两个方向?
void Plane() { PlayerView playerView; RenderComponent renderComponent; PlayerEnterAni playerEnterAni; CameraMove cameraMove; PlayerBehaviour playerBehaviour; MoveComponent moveComponent; PlayerController playerController; ColliderComponent colliderComponent; PlaneCollideMsgComponent planeCollideMsgComponent; PlayerBuffMgr playerBuffMgr; {//BulletRoot EmitBulletMgr emitBulletMgr; BossBulletEventComponent bossBulletEventComponent; SpawnBulletPointMgr spawnBulletPointMgr; } }在这里插入图片描述

modify 基础的四向Move

把MoveComponent改成MoveCommand,少去添加一个组件

MoveComponent

using UnityEngine;public class MoveComponent : MonoBehaviour
{private float _speed;public void Init(float speed){_speed = speed;}public void Move(Vector2 direction){if (_speed != 0){ transform.Translate(direction * _speed * Time.deltaTime,Space.World);}}
}

MoveCommand

类似的上面相机可以改一个名叫MoveUpCommand的

    public class MoveCommand : AbstractCommand{Transform _t;Vector2 _dir;float _speed;public MoveCommand(Transform t, Vector2 dir, float speed){_t = t;_dir = dir;_speed = speed;}protected override void OnExecute(){_t.Translate(_dir * _speed * Time.deltaTime, Space.World);}}

PlayerCtrl

/****************************************************文件:MainCameraCtrl.cs作者:lenovo邮箱: 日期:2023/8/16 21:11:50功能:
*****************************************************/using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;namespace QFramework.AirCombat
{public class PlayerCtrl : MonoBehaviour,IController{#region 属性private float _speed=2f;#endregion#region 生命void Update(){// this.SendCommand(new MoveCommand(transform, _speed));//这种将dir交给外面判断的不行if (Input.GetKey(KeyCode.W)){this.SendCommand(new MoveCommand(transform,Vector2.up,_speed));}if (Input.GetKey(KeyCode.S)){this.SendCommand(new MoveCommand(transform, Vector2.down, _speed));}if (Input.GetKey(KeyCode.A)){this.SendCommand(new MoveCommand(transform, Vector2.left, _speed));}if (Input.GetKey(KeyCode.D)){this.SendCommand(new MoveCommand(transform, Vector2.right, _speed));}}#endregion#region 辅助#endregion#region 实现public IArchitecture GetArchitecture(){return AirCombatApp.Interface;}#endregion  }
}

效果

在这里插入图片描述

modify 加上相机的基础移动

就是CameraMove里面调用了MoveComponent,Update里面同步了相机的向上移动,使得两者相对静止

相机SendCommand里面有CameraMoveUpEvent

原本是相机只是MoveUpCommand。
现在需要玩家监听相机的移动,所以新建CameraMoveUpCommand 。
CameraMoveUpCommand 里面有CameraMoveUpEvent,让玩家去监听

    public class CameraMoveUpCommand : AbstractCommand{Transform _t;float _speed;public CameraMoveUpCommand(Transform t, float speed){_t = t;_speed = speed;}protected override void OnExecute(){_t.Translate(Vector2.up* _speed * Time.deltaTime, Space.World);this.SendEvent(new CameraMoveUpEvent( _speed));}}

玩家去Register这个Event

/****************************************************文件:PlayerCtrl.cs作者:lenovo邮箱: 日期:2023/8/16 21:11:50功能:
*****************************************************/using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;namespace QFramework.AirCombat
{public class PlayerCtrl : MonoBehaviour,IController{#region 属性private float _speed=2f;#endregion#region 生命private void Start(){this.RegisterEvent<CameraMoveUpEvent>((e) => {this.SendCommand(new MoveUpCommand(transform,e.Speed));});}......

效果

可以看到没有原本项目的CameraMove脚本也在跑了
在这里插入图片描述

到现在完成玩家的两个脚本

            {//玩家//CameraMove cameraMove;//MoveComponent moveComponent;PlayerView playerView;RenderComponent renderComponent;PlayerEnterAni playerEnterAni;PlayerBehaviour playerBehaviour;PlayerController playerController;ColliderComponent colliderComponent;PlaneCollideMsgComponent planeCollideMsgComponent;PlayerBuffMgr playerBuffMgr;}

限制移动(边界检测)

原版

using UnityEngine;public class PlayerController : MonoBehaviour
{private MoveComponent _move;//飞机中心点到边界的差值private Vector2 _offset;private SpriteRenderer _renderer;#region 生命// Use this for initializationprivate void Start(){_move = GetComponent<MoveComponent>();_renderer = GetComponent<SpriteRenderer>();InputMgr.Single.AddListener(KeyCode.W);InputMgr.Single.AddListener(KeyCode.A);InputMgr.Single.AddListener(KeyCode.S);InputMgr.Single.AddListener(KeyCode.D);MessageMgr.Single.AddListener(KeyCode.W, InputState.PREE, ReveiveW);MessageMgr.Single.AddListener(KeyCode.A, InputState.PREE, ReveiveA);MessageMgr.Single.AddListener(KeyCode.S, InputState.PREE, ReveiveS);MessageMgr.Single.AddListener(KeyCode.D, InputState.PREE, ReveiveD);InitData();}private void InitData(){_offset = transform.position - _renderer.bounds.min;}private void OnDestroy(){InputMgr.Single.RemoveListener(KeyCode.W);InputMgr.Single.RemoveListener(KeyCode.A);InputMgr.Single.RemoveListener(KeyCode.S);InputMgr.Single.RemoveListener(KeyCode.D);MessageMgr.Single.RemoveListener(KeyCode.W, InputState.PREE, ReveiveW);MessageMgr.Single.RemoveListener(KeyCode.A, InputState.PREE, ReveiveA);MessageMgr.Single.RemoveListener(KeyCode.S, InputState.PREE, ReveiveS);MessageMgr.Single.RemoveListener(KeyCode.D, InputState.PREE, ReveiveD);}#endregion  #region 辅助 pubpublic void ReveiveW(params object[] args){if (!JudgeUpBorder()) _move.Move(Vector2.up);}public void ReveiveA(params object[] args){if (!JudgeLeftBorder()) _move.Move(Vector2.left);}public void ReveiveS(params object[] args){if (!JudgeDownBorder()) _move.Move(Vector2.down);}public void ReveiveD(params object[] args){if (!JudgeRightBorder()) _move.Move(Vector2.right);}#endregion#region priprivate bool JudgeUpBorder(){return _renderer.bounds.max.y >= GameUtil.GetCameraMax().y;}private bool JudgeDownBorder(){return _renderer.bounds.min.y <= GameUtil.GetCameraMin().y;}private bool JudgeLeftBorder(){return _renderer.bounds.min.x <= GameUtil.GetCameraMin().x;}private bool JudgeRightBorder(){return _renderer.bounds.max.x >= GameUtil.GetCameraMax().x;}private void ResetPosX(Vector2 border, Vector2 direction){var pos = transform.localPosition;pos.z = 0;pos.x = border.x - Vector2.Dot(_offset, direction);transform.localPosition = pos;}private void ResetPosY(Vector2 border, Vector2 direction){var pos = transform.localPosition;pos.z = 0;pos.y = border.y - Vector2.Dot(_offset, direction);transform.localPosition = pos;}private void Drag(Vector3 screenPos){var pos = Camera.main.ScreenToWorldPoint(screenPos);pos.z = 0;transform.localPosition = pos;}#endregion#region 系统private void OnMouseDrag(){
#if UNITY_EDITORDrag(Input.mousePosition);
#elseif (Input.touches.Length > 0){Drag(Input.touches[0].position);}
#endifif (JudgeUpBorder())ResetPosY(GameUtil.GetCameraMax(), Vector2.up);else if (JudgeDownBorder()) ResetPosY(GameUtil.GetCameraMin(), Vector2.down);if (JudgeLeftBorder())ResetPosX(GameUtil.GetCameraMin(), Vector2.left);else if (JudgeRightBorder()) ResetPosX(GameUtil.GetCameraMax(), Vector2.right);}#endregion}

改成InCameraBorderCommand

MoveCommand中判断时候用到InCameraBorderCommand
。。。
Camera的拓展看后面的

    public class MoveCommand : AbstractCommand{Transform _t;Vector2 _dir;float _speed;public MoveCommand(Transform t, Vector2 dir, float speed){_t = t;_dir = dir;_speed = speed;}protected override  void OnExecute(){if (this.SendCommand(new InCameraBorderCommand(_t, _dir))){ _t.Translate(_dir * _speed * Time.deltaTime, Space.World);}}}public class InCameraBorderCommand : AbstractCommand<bool>{Camera _camera;Vector2 _dir;SpriteRenderer _sR;public InCameraBorderCommand(Transform t,Vector2 dir){_camera = t.AnyOneCameraFirstMain();_sR = t.gameObject.GetComponent<SpriteRenderer>();_dir = dir;Debug.LogFormat(Common.Log_ClassFunction()+"{0},{1},{2}", _camera,_sR,_dir);}protected override bool OnExecute(){           if (_dir== Vector2.up) return _sR.bounds.max.y <= _camera.CameraSizeMax().y; //upif (_dir== Vector2.down) return _sR.bounds.min.y >= _camera.CameraSizeMin().y; //downif (_dir== Vector2.right) return _sR.bounds.max.x <= _camera.CameraSizeMax().x; //rightif (_dir== Vector2.left) return _sR.bounds.min.x >= _camera.CameraSizeMin().x; //leftreturn true;}}

效果

可以看到 InCameraBorderCommand在跑
在这里插入图片描述

stars Camera

将GameUtils中的方法改成this拓展。
前面的边界检测用到

public static partial class Tags 
{public const string MAINCAMERA = "MainCamera";public const string UICAMERA = "UICamera";
}
/****************************************************文件:ExtendCamera.cs作者:lenovo邮箱: 日期:2023/7/9 19:31:26功能:
*****************************************************/using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;public static class ExtendCamera
{#region Camerapublic static Camera UICamera(this Transform t){return t.gameObject.FindComponentWithTag<Camera>(Tags.UICAMERA);}public static Camera MainCamera(this Transform t){return GameObject.FindGameObjectWithTag(Tags.MAINCAMERA).GetComponent<Camera>();}public static Camera AnyOneCamera(this Transform t){Camera _camera = Object.FindObjectOfType<Camera>();if (_camera == null){if (_camera == null)Debug.LogError("当前场景中没有相机");return _camera;}else{return _camera;}}public static Camera AnyOneCameraFirstMain(this Transform t){Camera camera = t.MainCamera();if (camera == null){return t.AnyOneCamera();}return camera;}#endregion#region CameraSizepublic static Vector2 CameraSize(this Camera camera){Vector2 size = Vector2.zero;if (size == Vector2.zero){var heigth = camera.orthographicSize * 2;var width = heigth * camera.aspect;size = new Vector2(width, heigth);}return size;}public static Vector2 CameraSize(this Transform t){Camera camera = t.AnyOneCameraFirstMain();Vector2 size = Vector2.zero;if (camera != null && size == Vector2.zero){var heigth = camera.orthographicSize * 2;var width = heigth * camera.aspect;size = new Vector2(width, heigth);}return Vector2.zero;}public static Vector2 CameraSizeMin(this Transform t){Camera camera = t.AnyOneCameraFirstMain();return camera.CameraSizeMin();}public static Vector2 CameraSizeMin(this Camera camera){if (camera != null){var pos = camera.transform.position;var size = camera.CameraSize();return new Vector3(pos.x - size.x * 0.5f, pos.y - size.y * 0.5f, pos.z);}return Vector2.zero;}public static Vector2 CameraSizeMax(this Transform t){Camera camera = t.AnyOneCameraFirstMain();return camera.CameraSizeMax();}public static Vector2 CameraSizeMax(this Camera camera){if (camera != null){var pos = camera.transform.position;var size = camera.CameraSize();return new Vector3(pos.x + size.x * 0.5f, pos.y + size.y * 0.5f, pos.z);}return Vector2.zero;}#endregion  }

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

watch QF对象池

在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;namespace QFramework
{public class SimpleObjectPoolExample : MonoBehaviour{private SimpleObjectPool<GameObject> mObjectPool;GameObject _curGo;void Start(){mObjectPool = new SimpleObjectPool<GameObject>(() =>{var gameObj = new GameObject();gameObj.Hide();gameObj.transform.SetParent(transform);return gameObj;}, gameObj => { gameObj.Hide(); }, 5);}// Update is called once per framevoid Update(){if (Input.GetKeyDown(KeyCode.Q)){_curGo = mObjectPool.Allocate();_curGo.Show();_curGo.transform.SetParent(transform);}if (Input.GetKeyDown(KeyCode.W)){mObjectPool.Recycle(_curGo);foreach (Transform t in transform){if (t.gameObject.activeInHierarchy == true){_curGo = t.gameObject;break;}}}if (Input.GetKeyDown(KeyCode.E)){mObjectPool.Clear(go => { Destroy(go); });}}}
}

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

modify 子弹

可以观察到子弹是间歇性自动发射的

位置

父节点在这里,但是根据设置未知的节点挂在对应的飞机下面
在这里插入图片描述

脚本

        private void Bullet(){{//PoolMgr {//BulletPool {//Bullet Bullet bullet;BulletEffectMgr bulletEffectMgr;BulletBehaviour bulletBehaviour;MoveComponent moveComponent;BulletCollideMsgComponent bulletCollideMsgComponent;}}}}

新建一个EmitBulletMgr

给飞机需要实例子弹时,有对应的Pool给GameObject

/****************************************************文件:MainCameraCtrl.cs作者:lenovo邮箱: 日期:2023/8/16 21:11:50功能:
*****************************************************/using System.Collections;
using System.Collections.Generic;
using System.IO;
using UniRx.Triggers;
using UnityEngine;
using static ResourcesName;
using Random = UnityEngine.Random;namespace QFramework.AirCombat
{public class EmitBulletMgr : MonoBehaviour,ISingleton{#region 属性Dictionary<BulletType, SimpleObjectPool<GameObject>> _bulletPrefabDic= new Dictionary<BulletType, SimpleObjectPool<GameObject>>();Dictionary<BulletType, IBulletModel> _bulletModelDic= new Dictionary<BulletType, IBulletModel>();const int _preloadCnt=10;#endregion#region 生命public void OnSingletonInit(){ResKit.Init();ResLoader resLoader = ResLoader.Allocate();//GameObject prefab = resLoader.LoadSync<GameObject>("Bullet");SimpleObjectPool<GameObject> pool = new SimpleObjectPool<GameObject>(() =>{GameObject go = GameObject.Instantiate(prefab, Vector2.zero, Quaternion.identity);go.Identity();go.Hide();return go;}, go =>{go.Identity();go.Hide();}, _preloadCnt);_bulletPrefabDic.Add(BulletType.PLAYER, pool);}#endregion#region 辅助public  GameObject SpawnBullet(BulletType bulletType){SimpleObjectPool<GameObject> pool;_bulletPrefabDic.TryGetValue(bulletType, out  pool);if (pool!= null){GameObject go = pool.Allocate();return go;}return null;}public void RecycleBullet(BulletType bulletType,GameObject old){SimpleObjectPool<GameObject> pool;_bulletPrefabDic.TryGetValue(bulletType, out pool);if (pool != null){pool.Recycle(old);}}#endregion#region 实现public IArchitecture GetArchitecture(){return AirCombatApp.Interface;}public static EmitBulletMgr Instance{get { return MonoSingletonProperty<EmitBulletMgr>.Instance; }}#endregion}
}

玩家 PlayerCtrl (只有子弹间隔,还没有装弹间隔)

使用了UniRX

/****************************************************文件:MainCameraCtrl.cs作者:lenovo邮箱: 日期:2023/8/16 21:11:50功能:
*****************************************************/using System;
using System.Collections;
using System.Collections.Generic;
using UniRx;
using UniRx.Triggers;
using UnityEngine;
using Random = UnityEngine.Random;namespace QFramework.AirCombat
{public class PlayerCtrl : MonoBehaviour,IController{#region 属性private float _bulletSpeed;    //子弹速度Transform _bulletPoolTrans;       //子弹父节点。固定不动的。就是防乱而已Transform _shooterlTrans;       //子弹射出时的初始位置,随飞机变化private float _shootSpanTime; //射击间隔private float _bulletSpanTime; //射击时子弹间隔#endregion#region 生命private void Start(){_bulletPoolTrans = transform.FindTop("Pool").Find("BulletPool");_shooterlTrans = transform.GetChild(0);_bulletSpeed = 2f;_shootSpanTime = 0.5f;_bulletSpanTime = 0.2f;this.RegisterEvent<CameraMoveUpEvent>((e) => {this.SendCommand(new MoveUpCommand(transform,e.Speed));});//gameObject.UpdateAsObservable().Sample(TimeSpan.FromSeconds(_bulletSpanTime)).Subscribe(_ =>{ this.SendCommand(new FireCommand(_bulletPoolTrans, _shooterlTrans.position));}).AddTo(gameObject);}void Update(){UpdateMove();}#endregion#region 辅助  void UpdateMove(){ // this.SendCommand(new MoveCommand(transform, _speed));//这种将dir交给外面判断的不行if (Input.GetKey(KeyCode.W)){this.SendCommand(new MoveCommand(transform,Vector2.up,_bulletSpeed));}if (Input.GetKey(KeyCode.S)){this.SendCommand(new MoveCommand(transform, Vector2.down, _bulletSpeed));}if (Input.GetKey(KeyCode.A)){this.SendCommand(new MoveCommand(transform, Vector2.left, _bulletSpeed));}if (Input.GetKey(KeyCode.D)){this.SendCommand(new MoveCommand(transform, Vector2.right, _bulletSpeed));}        }#endregion#region 实现public IArchitecture GetArchitecture(){return AirCombatApp.Interface;}#endregion  }
}

子弹 PlayerBulletCtrl

/****************************************************文件:MainCameraCtrl.cs作者:lenovo邮箱: 日期:2023/8/16 21:11:50功能:
*****************************************************/using System;
using System.Collections;
using System.Collections.Generic;
using UniRx;
using UnityEngine;
using Random = UnityEngine.Random;namespace QFramework.AirCombat
{public class PlayerBulletCtrl : MonoBehaviour,IController{#region 属性private float _bulletSpeed=3f;//需要大于飞机速度,不然与飞机一起方向事相对静止很难看float _destroyTime = 2f;IBulletModel _model;#endregion#region 生命private void OnEnable(){if (true)  //不确定要不要给加上相机的基础运动矢量{ this.RegisterEvent<CameraMoveUpEvent>((e) => {this.SendCommand(new MoveUpCommand(transform,e.Speed));});            }//Observable.Timer(TimeSpan.FromSeconds(_destroyTime)).RepeatUntilDisable(gameObject).Subscribe(_ =>{EmitBulletMgr.Instance.RecycleBullet(BulletType.PLAYER, gameObject);}).AddTo(gameObject);}void Update(){this.SendCommand(new MoveCommand(transform,Vector2.up,_bulletSpeed));}#endregion#region 系统#endregion#region 实现public IArchitecture GetArchitecture(){return AirCombatApp.Interface;}#endregion  }
}

发射命令 FireComand

    public class ExitGameCommand : AbstractCommand{protected override void OnExecute(){Application.Quit();"退出游戏".LogInfo();}}public class FireCommand : AbstractCommand{Transform _parent;UnityEngine.Vector3 _initPos;public FireCommand(Transform parent, UnityEngine.Vector3 initPos){_parent = parent;_initPos = initPos;}protected override void OnExecute(){GameObject go = EmitBulletMgr.Instance.SpawnBullet(BulletType.PLAYER);go.SetParent(_parent);go.Identity();go.transform.position = _initPos;go. GetOrAddComponent<PlayerBulletCtrl>(); //直接Add防止多个go.Show();//InitComponent();//InitPos(_bulletModel);}}

效果

在这里插入图片描述

换弹时间

效果

在这里插入图片描述

脚本

/****************************************************文件:MainCameraCtrl.cs作者:lenovo邮箱: 日期:2023/8/16 21:11:50功能:
*****************************************************/using System;
using System.Collections;
using System.Collections.Generic;
using UniRx;
using UniRx.Triggers;
using UnityEngine;
using Random = UnityEngine.Random;namespace QFramework.AirCombat
{public class PlayerCtrl : MonoBehaviour,IController{#region 属性private float _bulletSpeed;    //子弹速度Transform _bulletPoolTrans;       //子弹父节点。就是防乱而已Transform _reloadBulletTrans;       //子弹射出时的初始位置,随飞机变化。不是子弹的父节点private float _reloadBulletTime; //射击间隔。也就是装弹间隔public bool _loadingBullet;private float _bulletSpanTime; //射击时子弹间隔private int _loadBulletCnt;  //子弹容量private int _loadBulletCnter;   //子弹存量// private float _fireSpanTime;//这种卡时间有时多一个少一个#endregion#region 生命private void Start(){_bulletPoolTrans = transform.FindTop("Pool").Find("BulletPool");_reloadBulletTrans = transform.GetChild(0);_bulletSpeed = 3f;_bulletSpanTime = 0.2f;// _fireSpanTime = 1f;_loadBulletCnt = 5;_loadBulletCnter = _loadBulletCnt;_reloadBulletTime = 0.5f;_loadingBullet = false;this.RegisterEvent<CameraMoveUpEvent>((e) => {this.SendCommand(new MoveUpCommand(transform,e.Speed));});//{//射速 _reloadBulletTrans.UpdateAsObservable().Where(_=>_loadingBullet==false).Sample(TimeSpan.FromSeconds(_bulletSpanTime)).Subscribe( _=>{if (_loadBulletCnter >0){_loadBulletCnter--;this.SendCommand(new FireCommand(_bulletPoolTrans, _reloadBulletTrans.position));}else{_loadingBullet = true;}}).AddTo(_reloadBulletTrans);            }{  //换弹_reloadBulletTrans.UpdateAsObservable().Where(_ => _loadingBullet == true).Sample(TimeSpan.FromSeconds(_reloadBulletTime)).Subscribe(_ =>{_loadBulletCnter=_loadBulletCnt;_loadingBullet = false;}).AddTo(_reloadBulletTrans);            }}void Update(){UpdateMove();}#endregion#region 辅助  void UpdateMove(){ // this.SendCommand(new MoveCommand(transform, _speed));//这种将dir交给外面判断的不行if (Input.GetKey(KeyCode.W)){this.SendCommand(new MoveCommand(transform,Vector2.up,_bulletSpeed));}if (Input.GetKey(KeyCode.S)){this.SendCommand(new MoveCommand(transform, Vector2.down, _bulletSpeed));}if (Input.GetKey(KeyCode.A)){this.SendCommand(new MoveCommand(transform, Vector2.left, _bulletSpeed));}if (Input.GetKey(KeyCode.D)){this.SendCommand(new MoveCommand(transform, Vector2.right, _bulletSpeed));}        }#endregion#region 实现public IArchitecture GetArchitecture(){return AirCombatApp.Interface;}#endregion  }
}

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

大飞弹

在这里插入图片描述

大飞弹预警线

在这里插入图片描述

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

爆炸特效

位置

在这里插入图片描述

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

爆金币

位置

在这里插入图片描述

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

06 Scene 战斗 modify 敌人

在场景中的位置

GameRoot/PLANE除了第一个子节点(第一个是玩家)
子节点有血条。
在这里插入图片描述

在这里插入图片描述

脚本

跟玩家不同,这里只有一个MoveComponent

        void Enemy(){PlaneEnemyView planeEnemyView;RenderComponent renderComponent;PlayerEnterAni playerEnterAni;CameraMove cameraMove; //没激活AutoDespawnComponent autoDespawnComponent;EnemyTypeComponent enemyTypeComponent;LifeComponent lifeComponen;SubMsgMgr subMsgMgr;EnemyBehaviour enemyBehaviour;MoveComponent moveComponent;ColliderComponent colliderComponent;PlaneCollideMsgComponent planeCollideMsgComponent;{//BulletRoot EnemyBulletMgr enemyBulletMgr;EmitBulletMgr emitBulletMgr;BossBulletEventComponent bossBulletEventComponent;SpawnBulletPointMgr spawnBulletPointMgr;}{//EnemyLife EnemyLifeView enemyLifeView;{//Item EnemyLifeItem enemyLifeItem;}       }}

watch 第一关敌人的生成情况

左5
右5
左5+从左到右的飞机
右5+2个导弹
2个导弹
左5+从左到右的飞机
右5
左5
右5
警告
Boss
也就是LevelDatas[0]的数据
LevelEnemyDataConfig.json

{"LevelDatas": [{"PlaneCreaterDatas": [{"IdMax": 1,"IdMin": 0,"QueuePlaneNum": 5,"QueueNum": 4,"Type": 0,"X": -1.0},{"IdMax": 5,"IdMin": 2,"QueuePlaneNum": 5,"QueueNum": 4,"Type": 0,"X": 1.0},{"IdMax": 2,"IdMin": 0,"QueuePlaneNum": 1,"QueueNum": 2,"Type": 1,"X": 0.0},{"IdMax": 0,"IdMin": 0,"QueuePlaneNum": 1,"QueueNum": 1,"Type": 2,"X": 0.0}],"MissileCreaterDatas": [{"Batch": 0,"X": 1,"NumOfWarning": 2,"EachWarningTime": 0.8,"SpwanCount": 2,"Speed": 4},{"Batch": 0,"X": -1,"NumOfWarning": 2,"EachWarningTime": 0.8,"SpwanCount": 2,"Speed": 4}],"EnemyNumMax": 5,"EnemyNumMin": 5,"NormalDeadNumForSpawnElites": 20},{"PlaneCreaterDatas": [{"IdMax": 1,"IdMin": 0,"QueuePlaneNum": 5,"QueueNum": 4,"Type": 0,"X": -1.0},{"IdMax": 5,"IdMin": 2,"QueuePlaneNum": 5,"QueueNum": 4,"Type": 0,"X": 1.0},{"IdMax": 2,"IdMin": 0,"QueuePlaneNum": 1,"QueueNum": 2,"Type": 1,"X": 0.0},{"IdMax": 0,"IdMin": 0,"QueuePlaneNum": 1,"QueueNum": 1,"Type": 2,"X": 0.0}],"MissileCreaterDatas": [{"Batch": 0,"X": 1,"NumOfWarning": 2,"EachWarningTime": 0.8,"SpwanCount": 2,"Speed": 4},{"Batch": 0,"X": -1,"NumOfWarning": 2,"EachWarningTime": 0.8,"SpwanCount": 2,"Speed": 4}],"EnemyNumMax": 5,"EnemyNumMin": 5,"NormalDeadNumForSpawnElites": 20}]
}

stars 解析json ExtendLitJson

主要是json和Object互转
。。。
这里是用拓展的方式,以及摸清更加细节的注意事项

/****************************************************文件:ExtendLitJson.cs作者:lenovo邮箱: 日期:2023/7/24 22:32:11功能:
*****************************************************/using LitJson;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using UnityEngine;
using Random = UnityEngine.Random;
using System.IO;public static class ExtendLitJson
{#region 内部类public class Heros{public List<Hero> HeroLst = new List<Hero>();public override string ToString(){string str = "";foreach (Hero hero in HeroLst){str += "\n" + hero.ToString();}return str;}}/// <summary>/// 01 里面的属性字段一定要有public/// <para />System.Text.Json.JsonSerializer.Serialize就一定要有publc的属性/// </summary>public class Hero{public Hero(string name, int age){Name = name;Age = age;}public string Name { get; set; }public int Age { get; set; }//或者//string _name;//int _age;//public string Name { get => _name; set => _name = value; }//public int Age { get => _age; set => _age = value; }//public Hero(string name, int age)//{//    this.Name = name;//    this.Age = age;//}public override string ToString(){string str = "";str += "\t" + Name;str += "\t" + Age;return str;}}public class Person{public string Name { get; set; }public int Age { get; set; }//或者//string _name;//int _age;//public string Name { get => _name; set => _name = value; }//public int Age { get => _age; set => _age = value; }public override string ToString(){string str = "";str += "\t" + Name;str += "\t" + Age;return str;}}public class Character{public Character(){}public Character(string name, int age){Name = name;Age = age;}public string Name { get; set; }public int Age { get; set; }//或者//string _name;//int _age;//public string Name { get => _name; set => _name = value; }//public int Age { get => _age; set => _age = value; }public override string ToString(){string str = "";str += "\t" + Name;str += "\t" + Age;return str;}}#endregionpublic static void Example(){if (false){JsonData data = new JsonData();JsonType type = data.GetJsonType();}if (false){ExtendLitJson.Hero hero = new ExtendLitJson.Hero("刘备", 18);Debug.Log(hero.Object2Json());}if (false){ExtendLitJson.Hero hero1 = new ExtendLitJson.Hero("刘备", 18);ExtendLitJson.Hero hero2 = new ExtendLitJson.Hero("关羽", 18);ExtendLitJson.Hero hero3 = new ExtendLitJson.Hero("张飞", 18);ExtendLitJson.Hero[] heroArr = new ExtendLitJson.Hero[3] { hero1, hero2, hero3 };Debug.Log(heroArr.Object2Json());}if (false){ExtendLitJson.Hero hero1 = new ExtendLitJson.Hero("刘备", 18);ExtendLitJson.Hero hero2 = new ExtendLitJson.Hero("关羽", 18);ExtendLitJson.Hero hero3 = new ExtendLitJson.Hero("张飞", 18);ExtendLitJson.Heros heros = new ExtendLitJson.Heros();heros.HeroLst.Add(hero1);heros.HeroLst.Add(hero2);heros.HeroLst.Add(hero3);Debug.Log(heros.Object2Json());}if (false) //想采用 System.Text.Json.JsonSerializer.Serialize。但是引用不到{//string str1 = @"{"Name":"刘备","Age":18}";//string str2 = "  /{/"Name/":/"刘备/",/"Age/":18/}  ";var stream = new ExtendLitJson.Person { Name ="刘备",Age=18 };// string str = System.Text.Json.JsonSerializer.Serialize(stream);string str = "";//ExtendLitJson.Person person;person = str.Json2Object<ExtendLitJson.Person>();Debug.Log(person.ToString());}if (true){ExtendLitJson.Character cPre=new ExtendLitJson.Character("刘备",18);string json = cPre.Object2Json() ;Debug.Log("01 "+json);ExtendLitJson.Character cAfter = json.Json2Object<ExtendLitJson.Character>();Debug.Log("02 " + cAfter.ToString());}}public static JsonType GetJsonType_Common(this JsonData data){return data.GetJsonType();}/// <summary>/// https://blog.csdn.net/weixin_39562801/article/details/90410402/// </summary> public static string Object2Json<T>(this T t){string str = JsonMapper.ToJson(t);Regex reg = new Regex(@"(?i)\\[uU]([0-9a-f]{4})");str = reg.Replace(str, delegate (Match m){return ((char)Convert.ToInt32(m.Groups[1].Value, 16)).ToString();});return str;}/// <summary>/// 01 File.ReadText(path)/// 需要一个无参构造函数/// </summary>public static T Json2Object<T>(this string str){T t = JsonMapper.ToObject<T>(str);return t;}
}

【未完成】用System.Text.Json解析Json

用的原因

手动敲json数据是不用注意转义、两个双引号之类。
还有new{}

bug [未解决] 尝试使用 System.Text.Json,实现匿名new{}的效果

这个界面安装后,对于Common项目还需要去 “添加引用”才有 System.Text.Json
在这里插入图片描述

bug 需要net6

需要net 6.0 及以上版本

bug net6要过时了

支持的版本
在这里插入图片描述

bug name ‘Json’ does not exist in the namespace ‘System.Text’

System.Text.Json下载的是最新的70003,介绍有NetFrame462
所以项目改成462,不报错了
。。。
安装的是System.Text.Json,但是引用显示的Newtosoft.Json。而Newtosoft.Json里面确实没有System.Text.Json
在这里插入图片描述

bug 到文件夹查找

然后“添加引用”,添加了但是没看到。
在这里插入图片描述

bug Vs项目 属性 不能设置版本

之前还可以调出的(从471改成462)
在这里插入图片描述

bug 总结

不管是462还是471,你安装引用了System.Text.Json,实际只显示Newtosoft.Json

用Newtonsoft.Json解析json

modify 用JsonConvert

在这里插入图片描述

    /// <summary>/// LitJson/// <para />File.ReadAllText/// </summary> public static T JsonPath2Object_JsonMapper<T>(this string path){string str = File.ReadAllText(path);Debug.Log("JsonPath2Object_JsonMapper\n" + str);T t = JsonMapper.ToObject<T>(str);Debug.Log("JsonPath2Object_JsonMapper\n" + t.ToString());return t;}/// <summary>/// Newtonsoft.Json/// <para />File.ReadAllText/// </summary> public static T JsonPath2Object_JsonConvert<T>(this string path){string jsonStr = File.ReadAllText(path);Debug.Log("JsonPath2Object_JsonConvert\n" + jsonStr);T t = JsonConvert.DeserializeObject<T>(jsonStr);Debug.Log("JsonPath2Object_JsonConvert\n" + t.ToString());return t;}

bug bulletType

json和EnemyData不一样,可能是被我改了

watch EnemyData的字典加载

EnemyData、AllEnemyData

using System;
using System.Collections.Generic;
using UnityEngine;/// <summary>用来读取所有敌人信息json的一个类</summary>public class AllEnemyData
{/// <summary>Boss怪</summary>public EnemyData[] Boss { get; set; }/// <summary>精英怪</summary>public EnemyData[] Elites {get; set; }/// <summary>小怪</summary>public EnemyData[] Normal {get; set; }#region 构造public AllEnemyData(){}public AllEnemyData(EnemyData[] boss, EnemyData[] elites, EnemyData[] normal){Boss = boss;Elites = elites;Normal = normal;}#endregionpublic EnemyData[] GetData(EnemyType type){switch (type){case EnemyType.NORMAL:return Normal;case EnemyType.ELITES:return Elites;case EnemyType.BOSS:return Boss;default:return null;}}public override string ToString(){string str = "";if (Normal == null) Debug.LogError("EnemyData Normal为null");if (Elites == null) Debug.LogError("EnemyData Elites为null");if (Boss == null)   Debug.LogError("EnemyData Boss为null");foreach (EnemyData item in Normal){str+= item.ToString();}foreach (EnemyData item in Elites){str += item.ToString();}foreach (EnemyData item in Boss){str += item.ToString();}return str;}
}public class EnemyData
{public int id;public int attack;public int life;/// <summary>-1代表当前是随机轨迹,大于0的值,代表轨迹id</summary>public int trajectoryID;public int starNum;public int score;/// <summary> 掉落道具的可能性,例如值为10,就代表百分之十的概率 </summary>public int itemProbability;/// <summary>/// 掉落道具的数量,每个道具都在范围内随机/// <para />例如:数量是2,范围是[0,1],那么可能会出一个0,一1.或者是两个1,或者是两个0/// </summary>public int itemCount;//public double attackTime;public double fireRate;public double speed;//public PathType trajectoryType;public BulletType[] bulletType;   //看json文件没有加s/// <summary> 掉落道具的范围,应该是长度为2的数组 </summary>public ItemType[] itemRange;public override string ToString(){string str = "";str += "\t" + id;str += "\t" + attack;str += "\t" + life;str += "\t" + trajectoryID;str += "\t" + starNum;str += "\t" + score;str += "\t" + itemCount;str += "\t" + attackTime;str += "\t" + fireRate;str += "\t" + speed;str += "\t" + trajectoryType.ToString();str += "\t" ;foreach (var item in bulletType){str += item.ToString()+",";}str += "\t";foreach (var item in itemRange){str += item.ToString() + ",";}return str;}}

解析json部分(放在SpawnPlaneMgr)

{//获取数据AllEnemyData //AllEnemyData allEnemyData= LoadByJson<AllEnemyData>(Paths.CONFIG_ENEMY);AllEnemyData allEnemyData= (Paths.CONFIG_ENEMY).JsonPath2Object_JsonConvert<AllEnemyData>();Debug.Log(Common.Log_ClassFunction()+ allEnemyData.ToString());Dictionary<int,EnemyData> normalDic=new Dictionary<int,EnemyData>();Dictionary<int,EnemyData> elitesDic = new Dictionary<int,EnemyData>();Dictionary<int,EnemyData> bossDic=new Dictionary<int,EnemyData>();foreach (EnemyData item in allEnemyData.Normal){normalDic.Add(item.id,item);}foreach (EnemyData item in allEnemyData.Elites){elitesDic.Add(item.id, item);}foreach (EnemyData item in allEnemyData.Boss){bossDic.Add(item.id, item);}_enemyDataDic.Add(EnemyType.NORMAL, normalDic);_enemyDataDic.Add(EnemyType.ELITES, elitesDic);_enemyDataDic.Add(EnemyType.BOSS, bossDic);foreach (Dictionary<int,EnemyData> i in _enemyDataDic.Values){foreach (EnemyData j in i.Values){Debug.Log("****"+j.ToString());}}            }

效果

在这里插入图片描述

watch 原版敌人飞机挂载的脚本

飞机

在这里插入图片描述

发射子弹

在这里插入图片描述

生命

在这里插入图片描述

在这里插入图片描述

bug 只有一个编译单元可具有顶级语句

想有以下效果。
但是仅能有一个脚本有顶级语句
在这里插入图片描述

bug 匿名 error CS0656: Missing compiler required member ‘Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create’

Unity 报错error CS0656: Missing compiler required member ‘Microsoft.CSharp.RuntimeBinder.CSharpArgumen

stars NewIfNull:new

    /// <summary>/// ==null就New/// <para />:IEnumerable返回的还是null/// </summary>public static T NewIfNull<T>(this T t ) where T :new(){if (t == null){t = new T();}return t;}

bug NewIfNull不支持IEnumerable

下图的_keys的类:IEnumerable ,IEnumerable 返回为null
。。。
因为实现的 public IEnumerator GetEnumerator() 需要至少一个参数
如下图如果传入 keyData,实例时也无法将 keyData塞一个进去
在这里插入图片描述

    /// <summary>/// ==null就New/// <para />:IEnumerable返回的还是null/// </summary>public static T NewIfNull<T>(this T t ) where T :IEnumerable ,new(){if (t == null){t = new T();}return t;}

watch 两种枚举、一个类、配置文件

四者要统一。因为想全改成大写。不统一会导致读取配置文件(敌人啊,子弹啊)报错

public enum BulletType
{PLAYER,ENEMY_NORMAL_0,ENEMY_BOSS_0,ENEMY_BOSS_1,POWER,COUNT
}public enum BulletName
{ENEMY_NORMAL_0,ENEMY_BOSS_0,ENEMY_BOSS_1,COUNT
}public class AllBulletData
{public NormalBulletData PLAYER;//public NormalBulletData Enemy_Normal_0;//public Boss0BulletData Enemy_Boss_0;//public Boss1BulletData Enemy_Boss_1;public NormalBulletData ENEMY_NOAMAL_0;public Boss0BulletData  ENEMY_BOSS_0;public Boss1BulletData  ENEMY_BOSS_1;
}

bug QF打包时 error CS0012

error CS0012: The type ‘Quaternion’ is defined in an assembly that is not referenced. You must add a reference to assembly ‘UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null’.
。。。
如下的问题。和我学习 $“” 时的冲突了。二选一
Net 4x + IL2CPP
Net 2.0+Mono

    /// <summary>缺点Name等没有提示</summary>static void 动态类型处理匿名(){dynamic person = PersonInfo();//Unityerror CS0656: Missing compiler required member 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create'//Net 4x + IL2CPP   //QF在这种情况下打包报错,所以先 Net2.0+Mono打包先。所以先注释下面//https://blog.csdn.net/VAR_720/article/details/132085575// Log($"姓名:{person.Name},年龄:{person.Age}");}

stars RemoveIfExistComponent

    public static GameObject RemoveIfExistComponent<T>(this GameObject go) where T : Component{if (go.GetComponent<T>() != null){GameObject.DestroyImmediate(go.GetComponent<T>());}return go;} 

stars LocalRotation

    public static Transform LocalRotationDown(this Transform t){t.SetLocalRotattionZ(180);return t;}public static Transform SetLocalRotattionX(this Transform t, float x){Quaternion quaternion = t.localRotation;quaternion.x = x;t.localRotation = quaternion;return t;}public static Transform SetLocalRotattionY(this Transform t, float y){Quaternion quaternion = t.localRotation;quaternion.y = y;t.localRotation = quaternion;return t;}public static Transform SetLocalRotattionZ(this Transform t,float z){Quaternion quaternion = t.localRotation;quaternion.z = z;t.localRotation = quaternion;return t;}

stars Vector3Add Vector3Sub

在这里插入图片描述

在这里插入图片描述

    public static void Example(){{Vector3 v1 = new Vector3(1, 1, 1);Vector3 v2 = new Vector3(2, 2, 2);Debug.Log($"{v1}+{v2}={v1.Vector3Add(v2)}");Debug.Log($"v1={v1},v2={v2}");Debug.Log($"{v1}-{v2}={v1.Vector3Sub(v2)}");Debug.Log($"v1={v1},v2={v2}");}{Vector3 v1 = new Vector3(1, 1, 1);Vector3 v2 = new Vector3(2, 2, 2);Debug.Log($"{v1}+{v2}={ExtendVector3.Vector3Add(v1, v2)}");Debug.Log($"v1={v1},v2={v2}");Debug.Log($"{v1}-{v2}={ExtendVector3.Vector3Sub(v1, v2)}");Debug.Log($"v1={v1},v2={v2}");}}#region Add Sub (没有ref的)public static Vector3 Vector3Add(  Vector3 v1, Vector3 v2){return new Vector3(v1.x + v2.x,v1.y + v2.y,v1.z + v2.z);}public static Vector3 Vector3Sub( Vector3 v1, Vector3 v2){return new Vector3(v1.x - v2.x,v1.y - v2.y,v1.z - v2.z);}#endregion  #region Add Sub (ref的,不加ref,v1仍然不变)public static Vector3 Vector3Add(ref this Vector3 v1,Vector3 v2){v1= new Vector3(v1.x + v2.x,v1.y + v2.y,v1.z + v2.z);return v1;}public static Vector3 Vector3Sub(ref this Vector3 v1, Vector3 v2){v1= new Vector3(v1.x - v2.x,v1.y - v2.y,v1.z - v2.z);return v1;}#endregion  

bug 一个敌人都没有实例

PlaneEnemyView.Init
LoadCreatorData.Spawn
if (Waving())这里的条件没理解透,写反了
Waving的意思是还在生成一波一波的敌人中

    /// <summary>生成队的敌人</summary>public void SpawnEnemy() //原名Spawn{ITrajectoryData data = _trajectoryData.GetData(_enemyData.trajectoryType);if (Waving()) //_spawnedQueueNum < _planeCreatorData.QueueNum;{_spawnedQueueNum++;for (int i = 0; i < _planeCreatorData.QueuePlaneNum; i++){_lastEnemy = InitPlaneEnemyView(i,data);}}}

bug 生成玩家的位置不对

因为BoundsSizeY();写成BoundsMinY();里面是什么代码见名知意
//
用了临时变量多是为方便看打点

using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
using UnityEngine;public class PlayerEnterAni : MonoBehaviour 
{// Use this for initializationvoid Start (){Camera camera = transform.AnyOneCameraFirstMain();Vector2 minSize = camera.CameraSizeMin();float yMin = minSize.y;float boundsSizeY = GetComponent<SpriteRenderer>().BoundsSizeY();float fromY = yMin - boundsSizeY * 0.5f;//float toY	= yMin + boundsSizeY; //0.5刚刚贴着,再加0.5多一小段距离,也就是1	Vector3 pos = transform.position;Vector3 toPos = pos.SetY(toY);//transform.SetPosY(fromY); //开始在下面刚刚看不到的地方//var reader = ReaderMgr.Single.GetReader(ResourcesPath.CONFIG_Game_CONFIG);reader[ReaderKey.cameraSpeed].Get<float>(cameraSpeed =>{float time = 1;transform.DOMove(toPos + Vector3.up * cameraSpeed * time, time)//玩家、相机相对静止.OnComplete(()=>{GameStateModel.Single.GameState = GameState.START;} );});}
}

效果

可以看到,玩家位置对了,敌人的位置还不对
在这里插入图片描述

bug 敌人的生成位置的Y值不对

一开始生成就在这位置是不对的
在这里插入图片描述

位置由挂载EnemyCreator的节点提供

PlaneEnemyCreator.InitPos
如下,那就是yMax

    private void InitPos(float x){var yMax = GameUtil.GetCameraMax().y;var xMin = GameUtil.GetCameraMin().x;var xMax = GameUtil.GetCameraMax().x;var pos = new Vector3();pos.x = x;pos.y = yMax;pos.z = GameLayer.PLANE.Enum2Int(); //按不同类型做了一个分层pos.x =(pos.x).Clamp(xMin,xMax);transform.position = pos;}

原版挂在MainCamera下

所以会自动改变位置
。。。
而我把它们拆分出来了
那就加上CameraMove

	//GameProgressMgrprivate void InitCurCreatorMgrGo(out GameObject go){go = new GameObject(GameObjectName.CreatorMgr);go.SetParent(GameObject.Find(GameObjectName.Mgr));go.AddComponent<EnemyCreaterMgr>().Init(InitData);go.AddComponent<CameraMove>();//加上的}

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

bug 导弹、子弹、打掉飞机掉的奖励出现MoveComponent缺失仍然调用的情况,并且此时不会移动

MoveComponent不存在
。。。
有存在过的情况
&& speed第一次等于0过
&& 玩家的子弹也静止了

解决 MoveComponent被多次添加到一个节点,区分问题

加了一个字符串字段,进行说明

解决导弹 t.NewIfNull()不行。需要 t=t.NewIfNull()

if是原版
_effect.NewIfNull();后_effect还是等于null,所以改成_effect=_effect.NewIfNull();

我

    /// <summary>/// ==null就New/// <para />缺点 /// <para />01 t.NewIfNull()不行。需要 t=t.NewIfNull()/// <para />02 非结构,非值不能用ref/// </summary>public static T NewIfNull<T>( this T t) where T : new (){if (t == null){t = new T();}return t;}

bug 奖励不会移动

对比,少了一个MoveComponent

那就是GetOrAdd的事
。。。
GetOrAdd保证的是节点总会有一个该组件
AddIfISNull(ref _move),保证_move为空时会为_move赋值,哪怕节点有多个该组件,只管_move是否为空
在这里插入图片描述
在这里插入图片描述

速度对不上

左边正常,右边有问题
两个组件一个是水平小小的偏移,一个是竖直的的大幅度运动
。。。
通过加Despection, _move.Description = GameObjectName.SlowSpeedEffect;,其它的地方也加了。
发现两个MoveComponent的赋值位置在SlowSpeedEffect
if (false)可以看到是-=的错误
。。。
//SlowSpeedEffect

    public void UpdateFunc(){if (_move == null){ return;}if (false){_speed = (_speed < _speedLimit)? _speedLimit : (_slowSpeed * UnityEngine.Time.deltaTime);}else{if (_speed < _speedLimit){_speed = _speedLimit;}else{_speed -= _slowSpeed * UnityEngine.Time.deltaTime;}}_move.Init(_speed);_move.Move(_axis);_move.Description = GameObjectName.SlowSpeedEffect;}

在这里插入图片描述

bug 玩家不能吃掉奖励

还是这个图,ItemCollideMsgComponent的问题
。。。。。。
给对面传入自身,给自身传入对面

  otherLst.ForEach(colliderMsg => colliderMsg.ColliderMsg(transform));//之前写错成lst

在这里插入图片描述

using System.Collections.Generic;
using System.Linq;
using UnityEngine;public class ColliderComponent : MonoBehaviour
{private void Start(){gameObject.GetOrAddComponent<Rigidbody2D>().gravityScale = 0;}private void OnTriggerEnter2D(Collider2D other){List< IColliderMsg > lst =  GetComponentsInChildren<IColliderMsg>().ToList();List< IColliderMsg > otherLst =  other.GetComponentsInChildren<IColliderMsg>().ToList();//需要判空lst.ForEach(colliderMsg => colliderMsg.ColliderMsg(other.transform));otherLst.ForEach(colliderMsg => colliderMsg.ColliderMsg(transform));}
}

star GetComponentIfNull

        if (false){if (_renderer == null){_renderer = GetComponent<SpriteRenderer>();}}else{ gameObject.GetComponentIfNull(ref _renderer);}
    /// <summary>ref存在值类型、结构约束泛型的问题</summary>public static GameObject GetComponentIfNull<T>( this GameObject go,ref T c) where T:Component{if (c == null){c = go.GetComponent<T>();}return go;}

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

bug 置顶

背景是需要记录运行时,物体上挂在的脚本名。
在用置顶(某个软件串口在最顶层)软件时,VS有时会抢掉,断掉当前的置顶操作

bug untiy 报错GameObject已被销毁

    protected UiUtil UiUtil{get{if (_uiUtil == null){try{_uiUtil = gameObject.GetOrAddComponent<UiUtil>();_uiUtil.Init();}//MissingReferenceException: The object of type 'Life'//has been destroyed but you are still trying to access it.catch (System.Exception e){throw new System.Exception("UiUtil异常:"+e.ToString());}}return _uiUtil;}}

位置GameRoot/GameUI/Life

正常的
在这里插入图片描述
报错的
在这里插入图片描述

原因 脚本移动

Canvas挂了DontDestroyOnLoad(在LaunchGame里面)的脚本
我在移动了LaunchGame时,没有补回去

直接加Canvas会马上归到DontDestroyOnLoad那边,导致canvasTrans找不到,为空

        UIManager.Single.Init(canvasTrans.GetComponent<Canvas>());

所以在 UIManager.Single.Init里面才加上

    public void Init(Canvas canvas){Canvas = canvas;Canvas.AddComponentIfNull<DontDestroyOnLoad>();}

bug[未解决] The type or namespace name ‘Mapster’ could not be found

mapster.tool version 8.2.0

bug 包“Mapster.Tool 8.2.0”具有一个包类型“DotnetTool”,项目“XXX”不支持该类型。

stars Clamp

        float res = para.Clamp(0.0f, 10.0f);
    public static float Clamp(ref this float para,float min,float max){return Mathf.Clamp(para,min,max);}

bug 脚本命名只有一个字母大小不同

不支持,
比如
Extendobject,ExtendObject,这样的命名unity不会允许同时存在

bug 某些类型敌人生成器初始化失败

排查是createrData.EnemyType == type//Normal的
深挖是levelData.PlaneCreaterDatas
深挖是我点击了 Tools下的两个Generate,其中一个的动态生成只有一种EnemyType
总结就是动态生成Config的代码没写好
后面讲json有详细讲到

在这里插入图片描述

    public static List<IEnemyCreator> InitCreator(EnemyType type, Transform parent, AllEnemyData allEnemyData, EnemyTrajectoryDataMgr trajectoryData, LevelData levelData){List<IEnemyCreator> list = new List<IEnemyCreator>();foreach (var createrData in levelData.PlaneCreaterDatas){if (createrData.EnemyType == type){ list.Add(SpawnCreator( parent,createrData,allEnemyData,trajectoryData));            }}if (list.Count == 0){Debug.LogError($"EnemyCreator失败,类型:{type}");}return list;}

json LevelEnemyDataConfiga点击更新后发现变化,里面的类型都是0(Normal)

我修改了字段名,直接贴过来麻烦

bug unity调试总是 busy for stackover

bug untiy 更换版本后场景损坏

就是场景里面大部分节点都没了

bug 获取数据长度为负数

json数据被破坏,导致没有该类型的敌人数据,所以l返回的list为空
//GameUtil

    public static List<IEnemyCreator> InitCreator(EnemyType type, Transform parent, AllEnemyData allEnemyData, EnemyTrajectoryDataMgr trajectoryData, LevelData levelData){List<IEnemyCreator> list = new List<IEnemyCreator>();foreach (PlaneCreatorData data in levelData.PlaneCreaterDatas){if (data.EnemyType == type) //ever error;data都是normal{ list.Add(SpawnCreator( parent,data,allEnemyData,trajectoryData));            }Debug.Log($"data.EnemyType == type=>{data.EnemyType}=={type}");}if (list.IsNotNull() && list.Count > 0){  return list;}else{throw new System.Exception($"Creater初始化失败:{type}");}}

learn 直通过方法名就调用有参方法,怎么传的参数

01 只有一个引用,就是上面01在引用
02 方法中有参数
03 而且参数中是有数据的
所以不清楚这种是怎么把实参传过来的
在这里插入图片描述

Action

public class LoadCreaterData : NormalSingleton<LoadCreaterData> {private AllEnemyData _allEnemyData;private EnemyTrajectoryDataMgr _enemyTrajectoryDataMgr;private EnemyCreaterConfigData _enemyCreaterConfigData;private Action<AllEnemyData, EnemyTrajectoryDataMgr, EnemyCreaterConfigData> _LoadConfigCallBack;public void Init(Action<AllEnemyData,EnemyTrajectoryDataMgr,EnemyCreaterConfigData> callBack){if (_allEnemyData != null&& _enemyTrajectoryDataMgr != null && _enemyCreaterConfigData != null){callBack.DoIfNotNull(_allEnemyData,_enemyTrajectoryDataMgr,_enemyCreaterConfigData);return;}_LoadConfigCallBack = callBack;InitTrajectoryData();InitEnemyData();InitCreaterData();}

json类改了字段名 LevelData

public class LevelData  //有关json,不要随便改字段名
{public PlaneCreatorData[] PlaneCreaterDatas; //敌我飞机public MissileCreatorData[] MissileCreaterDatas; //导弹public int EnemyNumMax;public int EnemyNumMin;/// <summary>/// 每死亡多少个普通怪生成一波精英怪/// </summary>public int  NormalDeadNumForSpawnElites;  //public int NormalPerElitesNum;
}

json类改了字段名 PlaneCreatorData

public class PlaneCreatorData : ICreatorData  //json数据没乱改字段名
{/// <summary>找图用的。同等级下的不同Id敌人飞机</summary>public int IdMax;/// <summary>找图用的。同等级下的不同Id敌人飞机</summary>public int IdMin;/// <summary> 每个飞机队列的飞机数量  </summary>public int QueuePlaneNum;/// <summary>  生成队列的数量 </summary>public int QueueNum;public EnemyType Type; // EnemyType  json数据没乱改字段名public double X;
}

增加一个接口,表示这是和json有关的,不要修改字段名

也是json,有一个拼写错误的字段

json文件也是这个字段名,要改得全改
SpwanCount

/// <summary>导弹</summary>
public class MissileCreatorData : ICreatorData
{/// <summary> 当前导弹的生成批次 </summary>public int Batch;public double X;public int NumOfWarning;public double EachWarningTime;public int SpwanCount; //这里是错了,但是json文件就是这个,先不动public double Speed;
}

modify 两个类NormalCreaterMgr、ElitesCreaterMgr有相同的方法。静态类

public static class CreatorMgrUtil
{public static void SpawnAction(List<IEnemyCreator> creatorLst, IEnemyCreator enemyCreator){var creater = GetValidCreater(creatorLst, enemyCreator);if (creater.IsNotNull()){creater.Spawn();}}/// <summary>有效生成器</summary>public static IEnemyCreator GetValidCreater(List<IEnemyCreator> creatorLst, IEnemyCreator enemyCreator){return GetCreater(creatorLst, enemyCreator);}public static IEnemyCreator GetCreater(List<IEnemyCreator> list, IEnemyCreator enemyCreator){enemyCreator = null;foreach (IEnemyCreator creater in list){if (enemyCreator == null || enemyCreator.GetSpawnRatio() > creater.GetSpawnRatio()){if (!creater.IsSpawning()){enemyCreator = creater;}}}return enemyCreator;}
}

bug 有物体没有清除干净

Some objects were not cleaned up when closing the scene. (Did you spawn new GameObjects from OnDestroy?)
The following scene GameObjects were found:
LifeCycleMgr
CoroutineMgr
AudioMgr
。。。。
后面也发生了(概率小),但比没有的强

在这里插入图片描述

无效 UnityEngine.Object.Destroy

public class LaunchGame : MonoBehaviour
{private void OnApplicationQuit(){//Destroy(AudioMgr.Single.gameObject);//Destroy(CoroutineMgr.Single.gameObject);//Destroy(LifeCycleMgr.Single.gameObject);//DestroyImmediate(AudioMgr.Single.gameObject);//DestroyImmediate(CoroutineMgr.Single.gameObject);//DestroyImmediate(LifeCycleMgr.Single.gameObject);//以上不起作用//后面发现,以下也没起作用//UnityEngine.Object.Destroy(AudioMgr.Single.gameObject);//UnityEngine.Object.Destroy(CoroutineMgr.Single.gameObject);//UnityEngine.Object.Destroy(LifeCycleMgr.Single.gameObject);}

01 解决部分 增加OnDestroy

对对其他人的单例,增加这一个

    protected virtual void OnDestroy(){_single = null;}
public class MonoSingletonSimple<T> : MonoBehaviour where T : MonoBehaviour
{private static T _single;public static T Single{get{if (_single == null){var go = new GameObject(typeof(T).Name);DontDestroyOnLoad(go);_single = go.AddComponent<T>();}return _single;}}protected virtual void OnDestroy(){_single = null;}
}

02 未解决 LifeCycleMgr

盲猜这部分
在这里插入图片描述

stars 条件判断

public static partial class ExtendJugde
{public static bool IsAllNull(params object[] paras){bool res = paras[0].IsNull();for (int i = 0; i < paras.Length; i++){res = res && paras[i].IsNull();}return res;}public static bool IsAllNotNull(params object[] paras){bool res = paras[0].IsNotNull();for (int i = 0; i < paras.Length; i++){res = res && paras[i].IsNotNull();}return res;}public static bool IsEitherNull(params object[] paras){bool res = paras[0].IsNull();for (int i = 0; i < paras.Length; i++){res = res || paras[i].IsNull();}return res;}public static bool IsEitherNotNull(params object[] paras){bool res = paras[0].IsNotNull();for (int i = 0; i < paras.Length; i++){res = res || paras[i].IsNotNull();}return res;}}

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

修改Model

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

stars ShootAt

每次生成文件跳一下
注意, 有可能新建,需要先 AssetDatabase.Refresh();检测到文件的存在

	/// <summary>/// 名字形象,/// </summary>/// <param name="path"></param>public static void ShootAt(this string path){
#if UNITY_EDITORAssetDatabase.Refresh();// 有可能新建,需要先  AssetDatabase.Refresh();检测到文件的存在Selection_ActiveObject(path);
#endif}public static void Selection_ActiveObject(string path){
#if UNITY_EDITORSelection.activeObject = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(path);//"Assets/Config/ABCfg.asset";
#endif}

stars SubStringStartWith

    public static void Selection_ActiveObject(string path){
#if UNITY_EDITORSelection.activeObject = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(path);//"Assets/Config/ABCfg.asset";
#endif}

上面这生效需要路径以“Assets”开头的,而有的是以

    public static readonly string CONFIG_FOLDER = Application.streamingAssetsPath + "/Config";

等开头的(就是D:/),所以有这样一个方法

。。。。。。

    /// <summary>以tagStr为开头截取后面的字符串(包括tarString)</summary>public static string SubStringStartWith( this string str,string  tagStr= StringMark.Assets){List<string> strs=  str.Split('/').ToList();int startIdx = strs.IndexOf(tagStr);string res = "";for (int i = startIdx; i < strs.Count; i++){res += strs[i]+"/"; }res= res.Remove( res.LastIndexOf('/'));return res;}

json之类

音频、每关的敌人,敌人轨迹

提取路径,方便查找

public static class MenuItemPath
{public const string Assets_CreateAudioColumeJson="Assets/CreateAudioColumeJson";public const string Tools_GenerateLevelEnemyConfig= "Tools/GenerateLevelEnemyConfig";public const string Tools_GenerateEnemyTrajectoryData= "Tools/GenerateEnemyTrajectoryData";}

bug cfg错误

如果你点击了这两个,运行游戏后会报错。因为新生成的config内容少了很多。
比如LevelEnemyDataConfig里面的EnemyType只有0,会导致“# bug 某些类型敌人生成器初始化失败”
在这里插入图片描述

音频

主要是 (path.SubStringStartWith(StringMark.Assets)).ShootAt(); //上面临近的stars有介绍到两个方法
在这里插入图片描述

using System.Collections.Generic;
using System.IO;
using System.Linq;
using LitJson;
using UnityEditor;
using UnityEngine;public class JsonDataTool
{[MenuItem(MenuItemPath.Assets_CreateAudioColumeJson)]private static void CreateJson(){var ids = Selection.assetGUIDs;var path = AssetDatabase.GUIDToAssetPath(ids[0]);AudioJson(path);}private static void AudioJson(string selectedPath){if (!selectedPath.EndsWith(ResourcesPath.AUDIO_FOLDER))return;var info = new DirectoryInfo(selectedPath);var fileInfos = info.GetFiles( StringMark.Star , SearchOption.AllDirectories);var path = ResourcesPath.CONFIG_AUDIO_VOLUME_CONFIG;var volumes = new List<AudioVolume>();if (File.Exists(path)){var data = JsonMapper.ToObject<AudioVolume[]>(File.ReadAllText(path));foreach (var fileInfo in fileInfos){if (fileInfo.Name.EndsWith(Affixes.Meta)){ continue;}var name = Path.GetFileNameWithoutExtension(fileInfo.Name);var temp = new AudioVolume(){Name = name,Volume = GetVolume(data, name)};volumes.Add(temp);}}else{foreach (var fileInfo in fileInfos){if (fileInfo.Name.EndsWith(Affixes.Meta))continue;var name = Path.GetFileNameWithoutExtension(fileInfo.Name);var temp = new AudioVolume(){Name = name,Volume = 0.5f};volumes.Add(temp);}}var json = JsonMapper.ToJson(volumes);File.WriteAllText(path, json);Debug.Log("成功生成AudioVolume配置文件");(path.SubStringStartWith(StringMark.Assets)).ShootAt(); }private static double GetVolume(AudioVolume[] data, string key){var item = data.Where(u => u.Name == key).FirstOrDefault();if (item != null)return item.Volume;return 0.5f;}
}public class AudioVolume
{public string Name { get; set; }public double Volume { get; set; }
}

轨迹

其它两个类型数据是抄原始config,方便复原
问题是轨迹数据Data没有W,Config文件又有W

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using LitJson;
using UnityEditor;
using UnityEngine;public class GenerateEnemyTrajectoryData {[MenuItem(MenuItemPath.Tools_GenerateEnemyTrajectoryData)]private static void Execute(){EnemyTrajectoryDataMgr data =  new EnemyTrajectoryDataMgr();data.TrajectoryDataDic = new Dictionary<TrajectoryType, ITrajectoryData[]>();data.TrajectoryDataDic[TrajectoryType.STRAIGHT] = InitStraightData(data);data.TrajectoryDataDic[TrajectoryType.W] = InitWData(data);data.TrajectoryDataDic[TrajectoryType.ELLIPSE] = InitEllipseData(data);//string json = JsonUtil.Dic2Json(data.TrajectoryDataDic);string path = ResourcesPath.CONFIG_ENEMY_TRAJECTORY;File.WriteAllText(path,json);(path.SubStringStartWith(StringMark.Assets)).ShootAt();}private static ITrajectoryData[] InitStraightData(EnemyTrajectoryDataMgr data){List<ITrajectoryData> list = new List<ITrajectoryData>();list.Add(SetStraightData(10f));list.Add(SetStraightData(90f));list.Add(SetStraightData(80f));return list.ToArray();}private static ITrajectoryData[] InitWData(EnemyTrajectoryDataMgr data){List<ITrajectoryData> list = new List<ITrajectoryData>();list.Add(SetEllipseData());return list.ToArray();}private static ITrajectoryData[] InitEllipseData(EnemyTrajectoryDataMgr data){List<ITrajectoryData> list = new List<ITrajectoryData>();list.Add(SetWData(20f));return list.ToArray();}#region priprivate static StraightTrajectoryData SetStraightData(float angle){StraightTrajectoryData data = new StraightTrajectoryData();data.Angle = angle;return data;}private static WTrajectoryData SetWData(float angle){WTrajectoryData data = new WTrajectoryData();data.Angle = angle;return data;}private static EllipseTrajectoryData SetEllipseData(){EllipseTrajectoryData data = new EllipseTrajectoryData(){YRatioInScreen = 0.8f,XRadius = 1,YRadius = 0.5f,Precision = 20};return data;}#endregion}

bug 轨迹数据为空

轨迹字典只有W类型
字典是json读取的
json读取没对接好大小写(枚举是全大写),如下
在这里插入图片描述

bug unity thread loop failded

以前是先打断点,再运行
现在我是先运行起来,因为要断点的部分还不会运行到,再去打断点,再去运行
有局限性,但也好用

star untiy全局宏定义

我的是net4.x,mcs.rsp。跟链接中的好像是反着来的

添加链接描述
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解锁高效软件测试:虚拟机助力提升测试流程的秘诀

众所周知&#xff0c;软件测试在软件开发生命周期中至关重要。它确保软件符合要求&#xff0c;没有漏洞&#xff0c;并帮助开发人员优化性能&#xff0c;验证项目功能。 然而&#xff0c;测试可能既耗时又耗费资源&#xff0c;特别是当需要在不同操作系统和配置上测试软件组件…

Nginx七层(应用层)反向代理:HTTP反向代理proxy_pass篇

Nginx七层&#xff08;应用层&#xff09;反向代理 HTTP反向代理proxy_pass篇 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of thi…

Python3极简教程(一小时学完)中

异常 在这个实验我们学习 Python 的异常以及如何在你的代码中处理它们。 知识点 NameErrorTypeError异常处理&#xff08;try..except&#xff09;异常抛出&#xff08;raise&#xff09;finally 子句 异常 在程序执行过程中发生的任何错误都是异常。每个异常显示一些相关…

07-7.2.1 顺序查找

&#x1f44b; Hi, I’m Beast Cheng &#x1f440; I’m interested in photography, hiking, landscape… &#x1f331; I’m currently learning python, javascript, kotlin… &#x1f4eb; How to reach me --> 458290771qq.com 喜欢《数据结构》部分笔记的小伙伴可以…

Word使用中的一些烦人的小问题

文章目录 前言一、表格满一页后再插入行无法显示二、文字显示半截 前言 使用word的时候有一些莫名其妙的情况出现&#xff0c;想问度娘还很难用文字来描述问题&#xff0c;随时记录一下方便以后看 一、表格满一页后再插入行无法显示 点击表格左上方的全选按钮&#xff0c;下一…

fasttext工具介绍

fastText是由Facebook Research团队于2016年开源的一个词向量计算和文本分类工具。尽管在学术上并未带来巨大创新&#xff0c;但其在实际应用中的表现却非常出色&#xff0c;特别是在文本分类任务中&#xff0c;fastText往往能以浅层网络结构取得与深度网络相媲美的精度&#x…

长沙理工大学本科毕业论文(Latex模板)补充

&#x1f388;&#x1f388;&#x1f388;本模板不是原创&#xff0c;来自于github公开的项目。 具体链接是https://github.com/csust-latex-sig/CSUSTBachelorThesis 某大佬开源的&#xff0c;我用了之后做了点补充说明。&#xff08;&#x1f61d;&#xff09; 一、Latex的安…

用GPT做足球预测案例分享

自从GPT出来后&#xff0c;一直想利用GPT的能力做点什么&#xff0c;想了很多项目&#xff0c;比如用GPT写小说&#xff0c;用GPT做股票分析&#xff0c;用GPT写营销文章&#xff0c;最终我选了一个比较有意思的方向&#xff1a;GPT足球预测。因为每天都有足球比赛&#xff0c;…

Maven一键配置阿里云远程仓库,让你的项目依赖飞起来!

文章目录 引言一、为什么选择阿里云Maven仓库&#xff1f;二、如何设置Maven阿里云远程仓库&#xff1f;三、使用阿里云Maven仓库的注意事项总结 引言 在软件开发的世界里&#xff0c;Maven无疑是一个强大的项目管理工具&#xff0c;它能够帮助我们自动化构建、依赖管理和项目…

比较两个已排过序的文件的命令comm

比较两个已排过序的文件的命令comm There is no nutrition in the blog content. After reading it, you will not only suffer from malnutrition, but also impotence. The blog content is all parallel goods. Those who are worried about being cheated should leave qui…

QT5.14.2与Mysql8.0.16配置笔记

1、前言 我的QT版本为 qt-opensource-windows-x86-5.14.2。这是QT官方能提供的自带安装包的最近版本&#xff0c;更新的版本需要自己编译源代码&#xff0c;可点击此链接进行下载&#xff1a;Index of /archive/qt/5.14/5.14.2&#xff0c;选择下载 qt-opensource-windows-x86…

为什么固定尺寸 AdSense 广告依旧会出现并非指定的尺寸广告?

经常在网站上投放谷歌 AdSense广告的站长应该都碰到过&#xff0c;明明投放的是固定尺寸的广告位里旧会出现并非指定尺寸的AdSense 广告&#xff0c;很诡异的感觉。其实这都是因为你的 AdSense 账号广告优化造成的&#xff0c;其中里面就包含了广告尺寸优化&#xff0c;只需要在…

Spring源码十七:Bean实例化入口探索

上一篇Spring源码十六&#xff1a;Bean名称转化我们讨论doGetBean的第一个方法transformedBeanName方法&#xff0c;了解Spring是如何处理特殊的beanName&#xff08;带&符号前缀&#xff09;与Spring的别名机制。今天我们继续往方法下面看&#xff1a; doGetBean 这个方法…

Vue笔记11-Composition API的优势

Options API存在的问题 使用传统Options API中&#xff0c;新增或者修改一个需求&#xff0c;就需要分别在data&#xff0c;methods&#xff0c;computed里修改&#xff0c;而这些选项分布在代码的各个地方&#xff0c;中间还穿插着其他Optional API&#xff0c;如果代码量上来…

表单代码示例

<template><el-form ref"form" :model"formData" :rules"formRules" label-width"100px"><el-form-item label"姓名" prop"name"><el-input v-model"formData.name"></el-i…

何为vue脚手架?

一. vue脚手架的基本知识 1. Vue脚手架是什么&#xff1f; ① Vue脚手架&#xff0c;也称为Vue CLI或vue-cli&#xff08;Command Line Interface&#xff09;&#xff1b;② Vue脚手架是一个基于Vue.js的快速生成项目股价的工具&#xff0c;它可以帮助开发者快速搭建一个带有r…

hadoop集群常用命令搜集——筑梦之路

服务启停命令 # 脚本启停hadoop全部服务(master节点执行&#xff0c;各节点需配置免密)./start-all.sh # 包含yarn(ResourceManager,NodeManager)和hdfs(JournalNode,NameNode, DataNode, DFSZKFailoverController) ./stop-all.sh# 脚本启停ResourceManager,NodeManager./s…

JAVA之(方法的重载与重写、this关键字、super关键字)

方法的重载与重写 一、方法的重载与重写1、回顾方法的定义2、重载的概念3、重写 二、this关键字1、何为this方法2、使用方法&#xff08;1&#xff09;在构造方法中指构造器所创建的新对象&#xff08;2&#xff09; 方法中指调用该方法的对象&#xff08;3&#xff09; 在类本…

【ARMv8/v9 GIC 系列 6 -- 中断优先级详细介绍】

请阅读【ARM GICv3/v4 实战学习 】 文章目录 Interrupt prioritizationInterrupt Priority ValueSGI And PPI Priority SetSecure And Non-secure Priority AccessInterrupt prioritization 在ARM GICv3和GICv4架构中,中断的优先级化(prioritization)是通过以下几种方式来描…

centos7.9 rpm包安装mysql8.2.0数据库、root设置客户端登录、配置并发、表名大小写敏感、启动重启指令等记录

centos安装mysql8数据库,下载的是rpm-bundle.tar包,这样可以在内网环境离线安装,工作中医院的服务器很多也是内网的,所以这里记录下rpm-bundle.tar包安装的步骤。 lscpu 查看处理器是x86还是arm 下载对应的版本 bundle tar包 ((mysql-8.2.0-1.el7.x86_64.rpm-bundle.tar))…