当前位置: 首页 > news >正文

qframework 架构 (作者:凉鞋)使用笔记

一些准则:

根据VIEW->SYSTEM->MODEL的分层架构

初始架构:

app.

using FrameworkDesign;namespace ShootingEditor2D(项目的命名空间)
{public class ShootingEditor2D (游戏名称): Architecture<ShootingEditor2D>{protected override void Init(){}}
}

该脚本放到scripts文件夹下。

其他model\system等,注册在app.

using FrameworkDesign;namespace ShootingEditor2D
{public class ShootingEditor2D : Architecture<ShootingEditor2D>{protected override void Init(){this.RegisterModel<IPlayerModel>(new PlayerModel());this.RegisterSystem<IStatSystem>(new StatSystem());}}
}

功能列表

在VIEW层和SYSTEM层之间通信

创建VIEW

创建VIEW中的关键角色:UIController,方便快速对UI的显示进行处理。

*注意,VIEW脚本可以获取任何来自SYSTEM和MODEL的信息,以此来更新自己,比如监测是否子弹足够。

namespace ShootingEditor2D
{public class Gun : MonoBehaviour,IController // +{private Bullet mBullet;private GunInfo mGunInfo; // +private void Awake(){mBullet = transform.Find("Bullet").GetComponent<Bullet>();mGunInfo = this.GetSystem<IGunSystem>().CurrentGun; // +}public void Shoot(){if (mGunInfo.BulletCount.Value > 0) // +{var bullet = Instantiate(mBullet.transform, mBullet.transform.position, mBullet.transform.rotation);// 统一缩放值bullet.transform.localScale = mBullet.transform.lossyScale;bullet.gameObject.SetActive(true);this.SendCommand<ShootCommand>(); // +}}public IArchitecture GetArchitecture() // +{return ShootingEditor2D.Interface;}private void OnDestroy() // +{mGunInfo = null; //+}}
}

namespace ShootingEditor2D
{public class UIController : MonoBehaviour,IController{private IStatSystem mStatSystem;private IPlayerModel mPlayerModel;private void Awake(){mStatSystem = this.GetSystem<IStatSystem>();mPlayerModel = this.GetModel<IPlayerModel>();}/// <summary>/// 自定义字体大小/// </summary>private readonly Lazy<GUIStyle> mLabelStyle = new Lazy<GUIStyle>(()=>new GUIStyle(GUI.skin.label){fontSize = 40});private void OnGUI(){GUI.Label(new Rect(10,10,300,100),$"生命:{mPlayerModel.HP.Value}/3",mLabelStyle.Value);GUI.Label(new Rect(Screen.width - 10 - 300,10,300,100),$"击杀数量:{mStatSystem.KillCount.Value}",mLabelStyle.Value);}public IArchitecture GetArchitecture(){return ShootingEditor2D.Interface;}}
}

创建VIEW->SYSTEM的通信方式:命令Command

namespace ShootingEditor2D
{public class KillEnemyCommand : AbstractCommand{protected override void OnExecute(){this.GetSystem<IStatSystem>().KillCount.Value++;}}
}
        protected override void OnExecute(){var gunSystem = this.GetSystem<IGunSystem>();gunSystem.CurrentGun.BulletCountInGun.Value--;gunSystem.CurrentGun.GunState.Value = GunState.Shooting;}

确定在什么运行情况下发出该命令Command。比如,一个小小的子弹销毁时,子弹知道要发出。

namespace ShootingEditor2D
{public class Bullet : MonoBehaviour,IController // +{private Rigidbody2D mRigidbody2D;private void Awake(){mRigidbody2D =  GetComponent<Rigidbody2D>();}private void Start(){mRigidbody2D.velocity = Vector2.right * 10;}private void OnCollisionEnter2D(Collision2D other){if (other.gameObject.CompareTag("Enemy")){this.SendCommand<KillEnemyCommand>(); // +Destroy(other.gameObject);}}public IArchitecture GetArchitecture() // +{return ShootingEditor2D.Interface;}}
}

再比如,如果玩家碰到怪物就掉血,那么针对这个功能可以写一个脚本,挂在再玩家身上

namespace ShootingEditor2D
{public class AttackPlayer : MonoBehaviour,IController{private void OnCollisionEnter2D(Collision2D other){if (other.gameObject.CompareTag("Player")){this.SendCommand<HurtPlayerCommand>();}}public IArchitecture GetArchitecture(){return ShootingEditor2D.Interface;}}

VIEW自己分内的逻辑就自己处理了,比如怪物碰到玩家自己消失。如果不需要记录MODEL以数据的话,就自己删除。

可以建立各种各样的VIEW,别客气。

比如碰到了子弹库来补充弹药:

  public class GunPickItem : MonoBehaviour,IController{public string Name;public int BulletCountInGun;public int BulletCountOutGun;private void OnTriggerEnter2D(Collider2D other){if (other.CompareTag("Player")){this.SendCommand(new PickGunCommand(Name,BulletCountInGun,BulletCountOutGun));}}public IArchitecture GetArchitecture(){return ShootingEditor2D.Interface;}}

条件没问题的话,发送就行。至于这个pickgun要如何运作,有点复杂,但由command交给system去处理,处理之后,发送回一个event,表示枪支变化:

command这样写:

 public class PickGunCommand : AbstractCommand{private readonly string mName;private readonly int mBulletInGun;private readonly int mBulletOutGun;public PickGunCommand(string name, int bulletInGun, int bulletOutGun){mName = name;mBulletInGun = bulletInGun;mBulletOutGun = bulletOutGun;}protected override void OnExecute(){this.GetSystem<IGunSystem>().PickGun(mName, mBulletInGun, mBulletOutGun);}}

system这样写

using System.Collections.Generic;
using System.Linq;
using FrameworkDesign;namespace ShootingEditor2D
{public interface IGunSystem : ISystem{GunInfo CurrentGun { get; }void PickGun(string name, int bulletCountInGun, int bulletCountOutGun); //+}public class OnCurrentGunChanged // +{public string Name { get; set; }}public class GunSystem : AbstractSystem, IGunSystem{protected override void OnInit(){}private Queue<GunInfo> mGunInfos = new Queue<GunInfo>(); // +public GunInfo CurrentGun { get; } = new GunInfo(){BulletCountInGun = new BindableProperty<int>(){Value = 3},BulletCountOutGun = new BindableProperty<int>(){Value = 1},Name = new BindableProperty<string>(){Value = "手枪"},GunState = new BindableProperty<GunState>(){Value = GunState.Idle}};public void PickGun(string name, int bulletCountInGun, int bulletCountOutGun) // +{// 当前枪是同类型if (CurrentGun.Name.Value == name){CurrentGun.BulletCountOutGun.Value += bulletCountInGun;CurrentGun.BulletCountOutGun.Value += bulletCountOutGun;}// 已经拥有这把枪了else if (mGunInfos.Any(info => info.Name.Value == name)){var gunInfo = mGunInfos.First(info => info.Name.Value == name);gunInfo.BulletCountOutGun.Value += bulletCountInGun;gunInfo.BulletCountOutGun.Value += bulletCountOutGun;}else{// 复制当前的枪械信息var currentGunInfo = new GunInfo{Name = new BindableProperty<string>(){Value = CurrentGun.Name.Value},BulletCountInGun = new BindableProperty<int>(){Value = CurrentGun.BulletCountInGun.Value},BulletCountOutGun = new BindableProperty<int>(){Value = CurrentGun.BulletCountOutGun.Value},GunState = new BindableProperty<GunState>(){Value = CurrentGun.GunState.Value}};// 缓存mGunInfos.Enqueue(currentGunInfo);// 新枪设置为当前枪CurrentGun.Name.Value = name;CurrentGun.BulletCountInGun.Value = bulletCountInGun;CurrentGun.BulletCountOutGun.Value = bulletCountOutGun;CurrentGun.GunState.Value = GunState.Idle;// 发送换枪事件this.SendEvent(new OnCurrentGunChanged(){Name = name});}}}
}

SYSTEM中的数据变化如何告知VIEW?——为SYSTEM中的数据套用BindableProperty!

namespace ShootingEditor2D
{public enum GunState{Idle,Shooting,Reload,EmptyBullet,CoolDown}public class GunInfo{[Obsolete("请使用 BulletCountInGame",true)] // 第二个参数改成了 truepublic BindableProperty<int> BulletCount{get => BulletCountInGun;set => BulletCountInGun = value;}public BindableProperty<int> BulletCountInGun;public BindableProperty<string> Name;public BindableProperty<GunState> GunState;public BindableProperty<int> BulletCountOutGun;}
}

也可以设好初始值(但这个和架构无关)

   public GunInfo CurrentGun { get; } = new GunInfo(){BulletCountInGun = new BindableProperty<int>(){Value = 3},BulletCountOutGun = new BindableProperty<int>() // +{Value = 1},Name = new BindableProperty<string>() // +{Value = "手枪"},GunState = new BindableProperty<GunState>() // +{Value = GunState.Idle}};

事件EVENT:作为SYSTEM通知VIEW的方式。VIEW要自己Register

比如:这样

   public class UIController : MonoBehaviour, IController{private IStatSystem mStatSystem;private IPlayerModel mPlayerModel;private IGunSystem mGunSystem;private int mMaxBulletCount;private void Awake(){mStatSystem = this.GetSystem<IStatSystem>();mPlayerModel = this.GetModel<IPlayerModel>();mGunSystem = this.GetSystem<IGunSystem>();// 查询代码mMaxBulletCount = this.SendQuery(new MaxBulletCountQuery(mGunSystem.CurrentGun.Name.Value));this.RegisterEvent<OnCurrentGunChanged>(e =>{mMaxBulletCount = this.SendQuery(new MaxBulletCountQuery(e.Name));}).UnRegisterWhenGameObjectDestroyed(gameObject); // +}

MODEL:作为数据记录层

using System.Collections.Generic;
using FrameworkDesign;namespace ShootingEditor2D
{public interface IGunConfigModel : IModel{GunConfigItem GetItemByName(string name);}public class GunConfigItem{public GunConfigItem(string name, int bulletMaxCount, float attack, float frequency, float shootDistance,bool needBullet, float reloadSeconds, string description){Name = name;BulletMaxCount = bulletMaxCount;Attack = attack;Frequency = frequency;ShootDistance = shootDistance;NeedBullet = needBullet;ReloadSeconds = reloadSeconds;Description = description;}public string Name { get; set; }public int BulletMaxCount { get; set; }public float Attack { get; set; }public float Frequency { get; set; }public float ShootDistance { get; set; }public bool NeedBullet { get; set; }public float ReloadSeconds { get; set; }public string Description { get; set; }}public class GunConfigModel : AbstractModel, IGunConfigModel{private Dictionary<string, GunConfigItem> mItems = new Dictionary<string, GunConfigItem>(){{ "手枪", new GunConfigItem("手枪", 7, 1, 1, 0.5f, false, 3, "默认强") },{ "冲锋枪", new GunConfigItem("冲锋枪", 30, 1, 6, 0.34f, true, 3, "无") },{ "步枪", new GunConfigItem("步枪", 50, 3, 3, 1f, true, 1, "有一定后坐力") },{ "狙击枪", new GunConfigItem("狙击枪", 12, 6, 1, 1f, true, 5, "红外瞄准+后坐力大") },{ "火箭筒", new GunConfigItem("火箭筒", 1, 5, 1, 1f, true, 4, "跟踪+爆炸") },{ "霰弹枪", new GunConfigItem("霰弹枪", 1, 1, 1, 0.5f, true, 1, "一次发射 6 ~ 12 个子弹") },};protected override void OnInit(){}public GunConfigItem GetItemByName(string name){return mItems[name];}}
}

其他好东西:

1.时间冷却系统

            timeSystem.AddDelayTask(0.33f, () =>{gunSystem.CurrentGun.GunState.Value = GunState.Idle;});
using System;
using System.Collections.Generic;
using FrameworkDesign;
using UnityEngine;namespace ShootingEditor2D
{public interface ITimeSystem : ISystem{float CurrentSeconds { get; }void AddDelayTask(float seconds, Action onFinish);}public enum DelayTaskState{NotStart,Started,Finish}public class DelayTask{public float Seconds { get; set; }public Action OnFinish { get; set; }public float StartSeconds { get; set; }public float FinishSeconds { get; set; }public DelayTaskState State { get; set; }}public class TimeSystem : AbstractSystem,ITimeSystem{public class TimeSystemUpdateBehaviour : MonoBehaviour{public event Action OnUpdate;private void Update(){OnUpdate?.Invoke();}}protected override void OnInit(){var updateBehaviourGameObj = new GameObject(nameof(TimeSystemUpdateBehaviour));UnityEngine.Object.DontDestroyOnLoad(updateBehaviourGameObj);// 如果需要销毁,可以缓存为成员变量var updateBehaviour = updateBehaviourGameObj.AddComponent<TimeSystemUpdateBehaviour>();updateBehaviour.OnUpdate += OnUpdate;}public float CurrentSeconds { get;private set; } = 0.0f;private LinkedList<DelayTask> mDelayTasks = new LinkedList<DelayTask>();private void OnUpdate(){CurrentSeconds += Time.deltaTime;if (mDelayTasks.Count > 0){var currentNode = mDelayTasks.First;while (currentNode != null){var delayTask = currentNode.Value;var nextNode = currentNode.Next;if (delayTask.State == DelayTaskState.NotStart){delayTask.State = DelayTaskState.Started;delayTask.StartSeconds = CurrentSeconds;delayTask.FinishSeconds = CurrentSeconds + delayTask.Seconds;} else if (delayTask.State == DelayTaskState.Started){if (CurrentSeconds > delayTask.FinishSeconds){delayTask.State = DelayTaskState.Finish;delayTask.OnFinish.Invoke();delayTask.OnFinish = null;mDelayTasks.Remove(currentNode); // 删除节点}}currentNode = nextNode;}}}public void AddDelayTask(float seconds, Action onFinish){var delayTask = new DelayTask(){Seconds = seconds,OnFinish = onFinish,State = DelayTaskState.NotStart,};mDelayTasks.AddLast(new LinkedListNode<DelayTask>(delayTask));}}
}

2、Query查询类

// 查询代码
var gunConfigModel = this.GetModel<IGunConfigModel>();
var gunConfigItem = gunConfigModel.GetItemByName(mGunSystem.CurrentGun.Name.Value);
mMaxBulletCount = gunConfigItem.BulletMaxCount;

上面的查询显得很臃肿

可以这样:

 mGunSystem = this.GetSystem<IGunSystem>();// 查询代码
mMaxBulletCount = new MaxBulletCountQuery(mGunSystem.CurrentGun.Name.Value).Do(); // -+

做法就是:写一个查询类

using FrameworkDesign;namespace ShootingEditor2D
{public class MaxBulletCountQuery : IBelongToArchitecture,ICanGetModel{private readonly string mGunName;public MaxBulletCountQuery(string gunName){mGunName = gunName;}public int Do(){var gunConfigModel = this.GetModel<IGunConfigModel>();var gunConfigItem = gunConfigModel.GetItemByName(mGunName);return gunConfigItem.BulletMaxCount;}public IArchitecture GetArchitecture(){return ShootingEditor2D.Interface;}}
}

通过一些修改可以直接通过架构Arch来发送查询,做到这样(代码略)

mGunSystem = this.GetSystem<IGunSystem>();// 查询代码
mMaxBulletCount = this.SendQuery(newMaxBulletCountQuery(mGunSystem.CurrentGun.Name.Value)); // -+

3.凉鞋的话

(GamePix 独立游戏学院 - 让独立游戏不再难做 - Powered By EduSoho)欢迎来这里购买决定版的QFRAMEWORK课程。

此文为 决定版群里的聊天记录。

说一下,第一季的整体流程。

课程的最开始,是没有用任何架构就做一个《点点点》这样的项目,做的方式就是用拖拽加一点代码的方式。

但是这种方式有一个问题,就是对象和对象之间的相互访问特别乱,没有规则,也没有限制,这样下去当项目有一定规模了就会变得非常乱。于是就引入了一个规则,就是只有自顶向下的时候可以直接访问对象或者调用对象的方法。然后自底向上的时候使用事件或者委托。而在讲这个规则之前还介绍了对象之间的三种交互方式:方法调用、委托、事件。

然后自底向上和自顶向再加上对象之间的三种交互方式这个构成了一个大的前提,后边的比如层级、业务模块等只要有高低之分的我们就都用这套规则去约束了。

再往下就介绍了一个简单的模块化,介绍了一个单例的模块化。我们在做设计的时候经常听到一个原则,就是高内聚松耦合,意高内聚意思是相同的代码放在一个地方去管理,这个是高内聚,低耦合就是对象之间的引用不要太多,最好就是单向引用或者没有引用,或者是有一定的规则去约束如何互相访问。

再往下就引入了一个概念,就是 Model,Model 是因为什么引入的呢?是因为就是有一些数据,它需要在多个地方去共享,比如角色的攻击力,需要在 UI 界面上显示,或者计算一个伤害的时候需要使用,总之需要在多个地方去使用它,而这种数据就是需要共享的数据,甚至需要把攻击力存储起来,而存储也是一种 共享方式,比如上次游戏关闭到了,现在打开游戏之后角色的攻击力不能变成初始攻击力了,所以数据的存储也是一种共享方式。而这些需要存储的数据,就需要放到 Model 里管理起来。而 Model 在决定版架构的引入就是因为有了需要共享的数据才引入的。

引入完 Model 之后就要考虑一个问题,就是其他的地方怎么跟这个 Model 进行交互,然后交互的部分,一般的方式就是用类似 MVC 的方式,然后其中 MVC 中的 Controller ,它所管理的逻辑分成了交互逻辑和表现逻辑。

大家都说 MVC 中的 Controller 代码容易臃肿起来,那么罪魁祸首就是交互逻辑,只要是有数据操作或者变更游戏数据状态的逻辑都是交互逻辑,而这部分逻辑是非常多的,要想解决 Controller 代码臃肿的问题,一般的共识就是引入命令模式,也就是 Command,让 Command 去分担 Controller 的交互逻辑,Controller 仅仅只是调用相应的 Command 即可。

好多的框架或者方案都是用 Command 去分担交互逻辑的,所以这里就不赘述笔者为啥用 Command 了。

引入了 Command 之后,Controller 就变成了比较薄的一层了,而 Command 并不适合负责所有的交互逻辑,比如有的交互逻辑最好还是统一放在一个对象里,比如分数统计、成就检测、任务检测等,如果分数统计这种逻辑分散在各种 Command 里,会非常不好管理,而分数统计实际上是一种规则类的逻辑,比如打一个敌人得多少分等等,最好是统一放在一个对象里管理,于是就引入了 System 层,System 层就是管理需要统一管理的交互逻辑而引入的,比如成就系统、任务系统等,这些系统一般会写很多死代码,那么这些死代码分散到各个 Command 里,想想都觉得恐怖,所以最好要弄脏就弄脏一个对象就是系统对象,这也是高内聚的一种体现。

到这里架构的一些核心概念就有了雏形了,像事件机制、BindableProperty 等都是一些通用的工具。

再接着架构雏形有了之后,就开始不断打磨这套架构的实现,这部分的内容就是一些 C# 的高级使用方法,用各种技巧达成设计目的,就不多说了。

总之架构中的每一个概念的引入都是为了解决特定的架构问题的,并不是为了做成架构而引入的,然后只要不断地去解决这些架构问题,就会慢慢迭代出来一个比较成型的框架/架构。

最后笔者简单再说一点,就是第一季的内容就是迭代这套架构,在迭代过程中不仅仅只有代码实现的部分,更重要的还是引入这些概念解决哪些问题,所以在学习课程的时候要重点放在概念解决哪些问题上,只要这块了解了,就会对各个概念的使用不会出现问题。

到了第二季 对一些架构本身的问题做了一些改进,比如 BindableProperty 去掉 IEquatable 接口,因为没必要,然后实现了完整的 CQRS 机制,也就是引入了 Query,有了 Query 之后实现充血模型不再是难事。

相关文章:

qframework 架构 (作者:凉鞋)使用笔记

一些准则&#xff1a; 根据VIEW->SYSTEM->MODEL的分层架构 初始架构&#xff1a; app. using FrameworkDesign;namespace ShootingEditor2D&#xff08;项目的命名空间&#xff09; {public class ShootingEditor2D &#xff08;游戏名称&#xff09;: Architecture&l…...

【JMeter】定时器分类以及场景介绍

1. 定时器分类 固定定时器 作用&#xff1a;请求之间设置等待时间应用场景&#xff1a;查询商品列表后&#xff0c;去查看列表商品详情页。针对商品列表数据量比较大的&#xff0c;响应时间会比较长&#xff0c;就需要设置等待时间然后去查看商详 2.定时器的作用域&#xff1…...

Spring Boot 请求/actuator/beans 无法访问 返回404

问题复现 在保证项目加入了spring-boot-starter-actuator依赖&#xff0c;并成功启动后。通过浏览器进行访问&#xff0c;返回如下图结果&#xff1a; 问题排查 1. 查看日志 从日志中可以看到基于路径’/actuator’下只暴露了一个端点 2. 访问http://localhost:8080/actua…...

AVD联网

AVD联网&#xff1a; 解决Android Studio模拟器无法联网_android studio模拟器没有网络-CSDN博客 挺好的&#xff0c;就是访问网站的时候只能用ip&#xff0c;而不能用域名。 AVD设置代理&#xff1a; android studio踩坑记 AVD模拟器代理设置_android studio avd 配置代理-…...

[Vue warn]: Missing required prop: “action“

控制台显示错误信息 vue.runtime.esm.js:4605 [Vue warn]: Missing required prop: "action" found in ---> <ElUpload> at packages/upload/src/index.vue <ElTableRow> <ElTableBody> <ElTable> at pack…...

Python标准库有哪些

概述 可用性注释 内置函数 内置常量 由 site 模块添加的常量 # Author : 小红牛 # 微信公众号&#xff1a;wdPython内置类型 逻辑值检测 布尔运算 — and, or, not 比较运算 数字类型 — int, float, complex 布尔类型 - bool 迭代器类型 序列类型 — list, tuple, range 文本…...

基于ssm的校园办公室报修管理系统

基于ssm的校园办公室报修管理系统 摘要 基于SSM的校园办公室报修管理系统是一个现代化的、高效的报修平台&#xff0c;它能够帮助校园内的教职工和学生更方便、更快捷地提交和处理报修请求。该系统基于Spring、SpringMVC和MyBatis&#xff08;简称SSM&#xff09;开发&#xff…...

1Panel 升级 Halo报错

1Panel 升级 Halo报错 通过 1panel 升级 2.10.0 -> 2.10.1 后启动失败,出现 No value found for protocol 错误&#xff0c; 1Panel-halo-rzxY | Caused by: io.r2dbc.spi.NoSuchOptionException: No value found for protocol 1Panel-halo-rzxY | at io.r2dbc.spi.Conn…...

spring-clound基础开发

一、使用openfeig调用远程另外一个服务接口 1、创建一个spring boot工程,并且创建2个模块来当微服务模块 2、分别配置2个模块的启动文件 3、分别两个模块下创建一个测试的控制器 4、在项目的根目录的pom.xml中添加spring-cloud配置 <properties><java.version>1…...

基于SSM的劳务外包管理系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…...

uni-app学习笔记(二)

目录 一、路由与页面跳转 1、tabar与普通页面跳转例子 2、navigateTo 3、switchTab 二、vue组件 1、传统vue组件的使用 2、easycom 三、uView组件库 1、安装配置 2、引入配置 3、使用 四、Vuex 1、认识 2、state基本使用 3、mapState使用 五、网络请求 1、封装…...

使用axios拦截器解决前端并发冲突问题

使用 axios 拦截器解决「 前端并发冲突 」 问题 背景 并发冲突问题&#xff0c; 是日常开发中一个比较常见的问题。 不同用户在较短时间间隔内变更数据&#xff0c;或者某一个用户进行的重复提交操作都可能导致并发冲突。 并发场景在开发和测试阶段难以排查全面&#xff0c…...

IPv6详解

目录: 第一部分 IPv6的诞生背景和引起的主要变化 第二部分 IPv6数据报的基本首部和扩展首部 第三部分 IPv6地址 第四部分 IPv4向IPv6过渡 第一部分 IPv6的诞生背景和引起的主要变化 一.IPv6的诞生背景 IPv4存在设计缺陷: IPv4的设计者最初并没有想到该协议会在全球范围内广…...

【C++干货铺】STL简述 | string类的使用指南

个人主页点击直达&#xff1a;小白不是程序媛 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 什么是STL STL的版本 STL的六大组件 STL的缺陷 string类 C语言中的字符串 标准库中的string类 string类常用的接口使用指南 string类中常见的构造 strin…...

合肥工业大学数字逻辑实验三

** 数字逻辑 实验报告** ✅作者简介:CSDN内容合伙人、信息安全专业在校大学生🏆 🔥系列专栏 :hfut实验课设 📃新人博主 :欢迎点赞收藏关注,会回访! 💬舞台再大,你不上台,永远是个观众。平台再好,你不参与,永远是局外人。能力再大,你不行动,只能看别人成功!…...

【mmrotate】*** is not in the task util registry

问题&#xff1a; 使用mmrotate-1.x 自定义类时&#xff0c;明明已经注册&#xff0c;并添加到__init__.py中&#xff0c;但提示没有注册 from mmdet.registry import MODELSMODELS.register_module() class RotatedATSSAssigner(BaseAssigner): 分析&#xff1a; 具体看提…...

使用bitmap实现可回收自增id

需求描述 设计一个方法&#xff0c;每次调用返回一个自增id&#xff0c;同时需要满足以下要求。 可更新id的状态为已使用&#xff0c;已使用的id下次调用时不再返回可修改某个id的状态为未使用&#xff0c;下次调用时设为未使用状态的id可重新被返回 思路 思路一&#xff1…...

0基础学习VR全景平台篇第118篇:利用动作录制器功能避免重复操作 - PS教程

上课&#xff01;全体起立~ 大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01; 嗨&#xff0c;大家好。欢迎收看蛙色VR系列教程之PS利用动作记录器节约补地时间。 大家拍摄在补地的时候&#xff0c;利用插件选择输入输出选项的时候&#xff0c;每次重复操作…...

大数据Doris(十九):数据导入(Load)

文章目录 数据导入(Load) 一、Broker load 二、Stream load 三、Insert 四、Multi load...

BP神经网络的数据分类——语音特征信号分类

大家好&#xff0c;我是带我去滑雪&#xff01; BP神经网络&#xff0c;也称为反向传播神经网络&#xff0c;是一种常用于分类和回归任务的人工神经网络&#xff08;ANN&#xff09;类型。它是一种前馈神经网络&#xff0c;通常包括输入层、一个或多个隐藏层和输出层。BP神经网…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台

🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...