1. Time

一开始我是希望有一个 ScriptableObject 可以用来计时的
对于一些需要持续计时的事情可以用

1.1 ScriptableTimer

Assets/MeowFramework/Core/Scriptable/ScriptableTimer/ScriptableTimer.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 02/04/2022 23:19
// 最后一次修改于: 11/04/2022 10:31
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------using System;
using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;namespace MeowFramework.Core.Scriptable
{/// <summary>/// 计时器/// </summary>[InlineEditor][CreateAssetMenu(menuName = "MeowFramework/Scriptable Timer/Create Scriptable Timer")]public class ScriptableTimer : SerializedScriptableObject{/// <summary>/// 是否暂停/// </summary>[ShowInInspector]private bool isPasue;/// <summary>/// 是否暂停/// </summary>public bool IsPasue => isPasue;/// <summary>/// 是否停止/// </summary>[ShowInInspector]private bool isStop;/// <summary>/// 是否停止/// </summary>public bool IsStop => isStop;/// <summary>/// 流逝时间/// </summary>[ShowInInspector]private float elapsedTime;/// <summary>/// 流逝时间/// </summary>public float ElapsedTime {get => elapsedTime;set{if (!isStop && !isPasue) elapsedTime = value;}}/// <summary>/// 时长/// </summary>[ShowInInspector]private float duration;/// <summary>/// 时长/// </summary>public float Duration => duration;/// <summary>/// 是否循环/// </summary>[ShowInInspector]private bool isLoop;/// <summary>/// 是否循环/// </summary>public bool IsLoop => isLoop;/// <summary>/// 委托回调/// </summary>[ShowInInspector]private Action<object[]> callback;/// <summary>/// 回调参数/// </summary>private object[] args;/// <summary>/// 计时器的构造函数/// </summary>/// <param name="duration">时长</param>/// <param name="isLoop">是否循环</param>/// <param name="callback">委托回调</param>/// <param name="args">回调参数</param>public ScriptableTimer(float duration, bool isLoop, Action<object[]> callback,params object[] args){this.isPasue = true;this.isStop = false;this.duration = duration;this.isLoop = isLoop;this.callback = callback;this.args = args;}/// <summary>/// 重置计时器/// </summary>public void Reset(){elapsedTime = 0;}/// <summary>/// 启动计时器/// </summary>public void Start(){isPasue = false;}/// <summary>/// 暂停计时器/// </summary>public void Pause(){isPasue = true;}/// <summary>/// 停止计时器/// </summary>public void Stop(){callback?.Invoke(args);if (isLoop){elapsedTime -= duration;}else{isPasue = true;isStop = true;}}}
}

1.2 ScriptableTimerManager

Assets/MeowFramework/Core/Scriptable/ScriptableTimer/ScriptableTimerManager.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 02/04/2022 23:14
// 最后一次修改于: 11/04/2022 10:31
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------using System;
using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;namespace MeowFramework.Core.Scriptable
{/// <summary>/// 可资产化计时器管理器/// </summary>[InlineEditor][CreateAssetMenu(menuName = "MeowFramework/Scriptable Timer/Create Scriptable Timer Manager")]public class ScriptableTimerManager : SerializedScriptableObject{/// <summary>/// 可资产化计时器管理器的时间缩放比例/// </summary>private float timeScale = 1f;/// <summary>/// 可资产化计时器管理器的时间缩放比例/// </summary>public float TimeScale => timeScale;/// <summary>/// 计时器列表 可以在 ForEach 中删除元素/// </summary>public static List<ScriptableTimer> ScriptableTimerList = new List<ScriptableTimer>();/// <summary>/// 创建计时器/// </summary>/// <param name="duration">时长</param>/// <param name="isLoop">是否循环</param>/// <param name="callback">回调函数</param>/// <returns></returns>public ScriptableTimer CreateScriptableTimer(float duration, bool isLoop, Action<object[]> callback){return CreateScriptableTimer(duration, isLoop, callback, null);}/// <summary>/// 创建计时器/// </summary>/// <param name="duration">时长</param>/// <param name="isLoop">是否循环</param>/// <param name="callback">回调函数</param>/// <param name="args">回调参数</param>/// <returns></returns>public ScriptableTimer CreateScriptableTimer(float duration, bool isLoop, Action<object[]> callback,params object[] args){if (duration < 0f)return null;var timer =  new ScriptableTimer(duration, isLoop, callback, args);ScriptableTimerList.Add(timer);return timer;}/// <summary>/// 更新计时器/// </summary>private void UpdateAllScriptableTimers(){// 从尾到头遍历,可以方便在遍历中删除元素for (int i = ScriptableTimerList.Count; i >= 0; --i){ScriptableTimerList[i].ElapsedTime += Time.deltaTime * timeScale;if (ScriptableTimerList[i].ElapsedTime >= ScriptableTimerList[i].Duration)ScriptableTimerList[i].Stop();}}}
}

但是后来我悟了,想要记录一个时间,完全可以用一个 ScriptableFloatVariable
要存的委托在游戏退出之后应该都会丢失
所以这两个类就显得很鸡肋了

1.3 TimeComponent v1

所以关于时间唯一需要特意写的就是运行时的数据
运行时的数据就是一个时间缩放系数
虽然也可以做成 ScriptableDictionary……但是不知道有什么需求,就先搁置把

Assets/MeowFramework/Core/FrameworkComponent/TimeComponent.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 12/04/2022 17:16
// 最后一次修改于: 12/04/2022 17:35
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;namespace MeowFramework.Core.FrameworkComponent
{public class TimeComponent : BaseComponent{/// <summary>/// 时间缩放系数字典/// </summary>[ShowInInspector][ReadOnly][Tooltip("时间缩放系数字典")]public static Dictionary<string, float> TimeScaleList = new Dictionary<string, float>();}
}

然后我希望在 ScriptableBuff 中写个 string 记录这个键

        /// <summary>/// 时间缩放系数在时间缩放系数字典中的字符串键/// </summary>[ShowIf("@DurationType == BuffDurationType.Durable || DurationType == BuffDurationType.Infinite")][BoxGroup("Time")][Tooltip("时间缩放系数在时间缩放系数字典中的字符串键")]public string TimeScaleName = "";

但是这样做的话有一个问题就是,每当我申请一个 string 键之后,如果这个键不再使用了,那么我还要设计一套 GC 回收这个键
还有可能有共用的问题,比如原来一个技能 A1 给敌人的 Buff1 的时间缩放系数命名为 T1,那么如果我给敌人堆 E1 加上了 Buff1,再给敌人堆 E2 加上 Buff1 ,我希望这两个敌人堆的时间缩放系数是不同的,但是由于 Buff1 的时间缩放系数名字我已经写好了,所以我还需要多一步操作,在释放 Buff 的时候能够修改时间缩放系数的名字
所以我想想还是不做这个了

2. Buff

2.1 ScriptableBuff v1

ScriptableBuff 负责存 Buff 初始化数据

Assets/MeowFramework/Core/Scriptable/ScriptableBuff/ScriptableBuff.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 27/03/2022 9:51
// 最后一次修改于: 12/04/2022 19:39
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------using System.Collections.Generic;
using FlowCanvas;
using MeowFramework.Core.FrameworkComponent;
using NodeCanvas.Framework;
using Sirenix.OdinInspector;
using UnityEngine;namespace MeowFramework.Core.Scriptable
{/// <summary>/// 可资产化 Buff/// </summary>[CreateAssetMenu(fileName = "New Scriptable Buff", menuName = "MeowFramework/Scriptable Buff/Create Scriptable Buff")]public class ScriptableBuff : SerializedScriptableObject{/// <summary>/// Buff ID/// </summary>[BoxGroup("Basic")][ValidateInput("IDValidate")][Tooltip("Buff ID")]public int BuffID;/// <summary>/// 俗名/// </summary>[BoxGroup("Basic")][Tooltip("俗名")]public string FriendlyName;/// <summary>/// 概述/// </summary>[BoxGroup("Basic")][TextArea][Tooltip("概述")]public string Description = "";/// <summary>/// Buff FlowScript/// </summary>[BoxGroup("Basic")][Tooltip("FlowScript")]public FlowScript BuffFlowScript;/// <summary>/// 堆叠层数限制/// </summary>[EnumToggleButtons][BoxGroup("Layer")][Tooltip("堆叠层数限制")]public BuffLayerStackLimitType LayerStackLimitType;/// <summary>/// 最大堆叠层数/// </summary>[ShowIf("@LayerStackLimitType == BuffLayerStackLimitType.Limited")][ValidateInput("MaxLayersValidate")][BoxGroup("Layer")][Tooltip("最大堆叠层数")]public int MaxLayers;/// <summary>/// 指令持续时间种类/// </summary>[EnumToggleButtons][BoxGroup("Time")][Tooltip("指令持续时间种类")]public BuffDurationType DurationType;/// <summary>/// 指令持续时间/// </summary>[ShowIf("DurationType",BuffDurationType.Durable)][BoxGroup("Time")][ValidateInput("DurationValidate")][Tooltip("指令持续时间")]public float Duration;/// <summary>/// FlowScript 更新模式/// </summary>[EnumToggleButtons][BoxGroup("Time")][Tooltip("FlowScript 更新模式")]public Graph.UpdateMode UpdateMode = Graph.UpdateMode.NormalUpdate;/// <summary>/// Buff 元素 Tag 字典/// </summary>[Tooltip("元素标签字典")]public Dictionary<ElementType, bool> ElementTypeTagDictionary = new Dictionary<ElementType, bool>{{ElementType.Pyro, false},{ElementType.Hydro, false},{ElementType.Anemo, false},{ElementType.Electro, false},{ElementType.Cryo, false},{ElementType.Geo, false},};/// <summary>/// 初始时注册 Buff ID/// </summary>private void OnEnable(){// 根据新的 ID 添加键值对BuffComponent.ScriptableBuffDictionary[BuffID] = this;}/// <summary>/// 验证函数:是否为非负数/// </summary>/// <param name="value"></param>/// <returns></returns>private bool IDValidate(int value) => value >= 0;/// <summary>/// 验证函数:是否为正数/// </summary>/// <param name="value"></param>/// <returns></returns>private bool MaxLayersValidate(int value) => value > 0;/// <summary>/// 验证函数:是否为非负数/// </summary>/// <param name="value"></param>/// <returns></returns>private bool DurationValidate(float value) => value >= 0;}
}

本来想加一个初始层数的
现在想想似乎这个是要在 BornBuff 里面配置的
再一想想,其实在 TryAddBuff 里面提供可以叠加的层数,然后在 ActorEntity 的 OnStart 里面用 TryAddBuff 就行了
所以 ScriptableBuff 和 Actor 都不需要初始层数这个东西了,Actor更是不需要初始 Buff 这东西了

2.2 FlowScriptEntity v1

FlowScriptEntity 是所有逻辑依赖于 FlowScript 实现的实体的基类

Assets/MeowFramework/Core/Entity/FlowScriptEntity.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 11/04/2022 17:49
// 最后一次修改于: 12/04/2022 0:17
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------using FlowCanvas;
using Sirenix.OdinInspector;namespace MeowFramework.Core.Entity
{/// <summary>/// 挂载 FlowScript 的实体/// </summary>public class FlowScriptEntity : SerializedMonoBehaviour{/// <summary>/// FlowScript 控制器/// </summary>public FlowScriptController flowScriptController;private void Awake(){flowScriptController = GetComponent<FlowScriptController>();}}
}

2.3 ActorEntity v1

ActorEntity 是可以保存 Buff 的实体

Assets/MeowFramework/Core/Entity/ActorEntity.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 12/04/2022 14:44
// 最后一次修改于: 12/04/2022 20:36
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------using System.Collections.Generic;
using UnityEngine;namespace MeowFramework.Core.Entity
{public class ActorEntity : FlowScriptEntity{/// <summary>/// 运行时的 Buff 的字典/// </summary>[Sirenix.OdinInspector.ReadOnly][Tooltip("运行时的 Buff 的字典")]public Dictionary<int, BuffEntity> AliveBuffDictionary = new Dictionary<int, BuffEntity>();}
}

本来想用 private List<BuffEntity> aliveBuffList = new List<BuffEntity>();
但是想到要方便某一类型的 Buff 的查找,还是根据 Buff 的 BuffID 作为 Key 比较好

2.4 BuffEntity v1

BuffEntity 是 Buff 执行逻辑的实体

Assets/MeowFramework/Core/Entity/BuffEntity.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 11/04/2022 23:41
// 最后一次修改于: 12/04/2022 20:28
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------using System;
using MeowFramework.Core.Scriptable;
using NodeCanvas.Framework;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.InputSystem.XR.Haptics;namespace MeowFramework.Core.Entity
{/// <summary>/// 挂载 FlowScript 的实体/// </summary>public partial class BuffEntity : FlowScriptEntity{/// <summary>/// 可资产化 Buff/// </summary>[ShowInInspector][ReadOnly][Tooltip("可资产化 Buff")]private ScriptableBuff scriptableBuff;/// <summary>/// Buff 释放者/// 不考虑释放着为多人的情况/// </summary>[ShowInInspector][ReadOnly][Tooltip("Buff 释放者")]private ActorEntity caster;/// <summary>/// Buff 释放者/// 不考虑释放着为多人的情况/// </summary>public ActorEntity Caster{get => caster;set{AfterCasterChange?.Invoke(caster, value);caster = value;}}/// <summary>/// Buff 接受者/// 不考虑接受者为多人的情况/// </summary>[ShowInInspector][ReadOnly][Tooltip("Buff 接受者")]private ActorEntity receiver;/// <summary>/// Buff 接受者/// 不考虑接受者为多人的情况/// </summary>public ActorEntity Receiver{get => receiver;set{AfterReceiverChange?.Invoke(receiver, value);receiver = value;}}/// <summary>/// 层级/// </summary>[ShowInInspector][ReadOnly][Tooltip("层级")]private int layer;/// <summary>/// 层级/// </summary>public int Layer{get => layer;set{// 如果有层级限制,并且超过了层级限制,那么触发层级变化失败委托if (scriptableBuff.LayerStackLimitType == BuffLayerStackLimitType.Limited &&value > scriptableBuff.MaxLayers){AfterLayerChangeFailure?.Invoke(layer, value);return;}// 否则触发层级变化成功委托AfterLayerChangeSuccess?.Invoke(layer, value);layer = value;}}/// <summary>/// 时长/// </summary>[ShowInInspector][ReadOnly][Tooltip("时长")]private float duration;/// <summary>/// 时长/// 允许将时长设置为 0/// </summary>public float Duration{get => duration;set{var validValue = Mathf.Clamp(value, 0, float.MaxValue);AfterDurationChange?.Invoke(duration, validValue);duration = validValue;}}/// <summary>/// 已流逝时间/// </summary>[ShowInInspector][ReadOnly][Tooltip("已流逝时间")]private float elapsedTime;/// <summary>/// 已流逝时间/// </summary>public float ElapsedTime{get => elapsedTime;set{elapsedTime = value;if (elapsedTime < 0){elapsedTime += Duration;Layer -= 1;AfterOneLayerTimeRunOut(Layer);if (Layer == 0 && scriptableBuff.DurationType == BuffDurationType.Durable)EndBuff();}}}/// <summary>/// FlowScript 更新模式/// </summary>[ShowInInspector][ReadOnly][Tooltip("已流逝时间")]private Graph.UpdateMode updateMode;/// <summary>/// FlowScript 更新模式/// </summary>public Graph.UpdateMode UpdateMode{get => updateMode;set{AfterUpdateModeChange?.Invoke();updateMode = value;}}/// <summary>/// 释放者改变时触发的委托/// </summary>[HideInInspector]public Action<ActorEntity, ActorEntity> AfterCasterChange;/// <summary>/// 接受者改变时触发的委托/// </summary>[HideInInspector]public Action<ActorEntity, ActorEntity> AfterReceiverChange;/// <summary>/// 层级变化失败时触发的委托/// </summary>[HideInInspector]public Action<int, int> AfterLayerChangeFailure; /// <summary>/// 层级变化成功时触发的委托/// </summary>[HideInInspector]public Action<int, int> AfterLayerChangeSuccess;/// <summary>/// 时长变化成功时触发的委托/// </summary>[HideInInspector]public Action<float, float> AfterDurationChange;/// <summary>/// 每个层级时间耗尽时/// 采用每层时间独立计算/// 不考虑多层 Buff 只有一个时间的情况/// 可以在触发时间耗尽事件时将层数清零来实现多层 Buff 只有一个时间/// </summary>[HideInInspector]public Action<int> AfterOneLayerTimeRunOut;/// <summary>/// FlowScript 更新模式改变之后触发的委托/// </summary>public Action AfterUpdateModeChange;}
}

Assets/MeowFramework/Core/Entity/BuffEntity.Flow.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 12/04/2022 19:31
// 最后一次修改于: 12/04/2022 20:42
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------using System;
using MeowFramework.Core.Scriptable;
using NodeCanvas.Framework;
using UnityEngine;namespace MeowFramework.Core.Entity
{/// <summary>/// 挂载 FlowScript 的实体/// </summary>public partial class BuffEntity{/// <summary>/// 初始化 Buff/// </summary>public void BuffInitialize(ActorEntity caster, ActorEntity receiver, ScriptableBuff scriptableBuff, int layer = 0){this.caster = caster;this.receiver = receiver;this.scriptableBuff = scriptableBuff;this.layer = layer;updateMode = scriptableBuff.UpdateMode;}/// <summary>/// 启动 Buff/// </summary>public void StartBuffFlow(){flowScriptController.StartBehaviour(updateMode);}/// <summary>/// 更新 Buff/// </summary>public void UpdateBuffFlow(){flowScriptController.UpdateBehaviour();}/// <summary>/// 暂停 Buff/// </summary>public void PauseBuffFlow(){flowScriptController.PauseBehaviour();}/// <summary>/// 结束 Buff/// </summary>public void StopBuffFlow(){flowScriptController.StopBehaviour();}/// <summary>/// 重置 Buff/// </summary>public void ResetBuffFlow(){flowScriptController.RestartBehaviour();}/// <summary>/// Buff 结束/// </summary>public void EndBuff(){GameObject.Destroy(this);}}
}

2.5 BuffUtility v1

BuffUtility 是 Buff 执行逻辑的通用函数

Assets/MeowFramework/Core/Utility/BuffUtility.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 11/04/2022 23:27
// 最后一次修改于: 12/04/2022 20:42
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------using FlowCanvas;
using MeowFramework.Core.Entity;
using MeowFramework.Core.FrameworkComponent;
using UnityEngine;namespace MeowFramework.Core.Utility
{public static class BuffUtility{/// <summary>/// 尝试释放 Buff/// </summary>/// <param name="caster">Buff 释放者</param>/// <param name="receiver">Buff 接受者</param>/// <param name="buffID"> Buff ID</param>/// <returns>Buff 实体</returns>public static BuffEntity TryAddBuff(ActorEntity caster, ActorEntity receiver, int buffID, int layer){// 要检查这个 Buff 是否已经被生成了// 如果每一次 TryAddBuff 都生成一个 Buff 物体,那就没办法做到层数的叠加// 也不用在 root 下面找,因为可能会有很多 Buff// 所以那就直接找 receiver 吧// 所以要约定 receiver 不为 nullif (receiver == null){Debug.LogError($"{caster} 释放的 ID 为 {buffID} 的 Buff 没有接受者!");return null;}// 如果没有这个 Buff,就返回空if (!BuffComponent.ScriptableBuffDictionary.ContainsKey(buffID)){Debug.LogError($"{caster} 释放的 ID 为 {buffID} 的 Buff 在 Buff 组件的字典中不存在!");return null;}// 如果接受者身上已经有了相同 id 的 buff,那么直接增加层数if (receiver.AliveBuffDictionary.ContainsKey(buffID)){var buff = receiver.AliveBuffDictionary[buffID];buff.Layer += layer;return buff;}// 接受者身上没有相同 id 的 buff// 获得 Buff 数据var scriptableBuff = BuffComponent.ScriptableBuffDictionary[buffID];if(!BuffComponent.BuffPoolRoot)Debug.LogError("Buff 组件下面没有对象池的根节点!");// 创建空物体作为 Buff 物体GameObject entity = new GameObject();// Buff 物体放在统一的 root 下entity.transform.SetParent(BuffComponent.BuffPoolRoot);entity.name = scriptableBuff.FriendlyName == "" ? "NewBuffEntity" : scriptableBuff.FriendlyName + "Entity";// 初始化 FlowScript 控制器FlowScriptController flowScriptController = entity.AddComponent<FlowScriptController>();flowScriptController.StopBehaviour();flowScriptController.behaviour = scriptableBuff.BuffFlowScript;// 为 Buff 物体添加 BuffEntity,方便控制var buffEntity =  entity.AddComponent<BuffEntity>();buffEntity.BuffInitialize(caster, receiver, scriptableBuff, layer);// 执行 BuffbuffEntity.StartBuffFlow();return buffEntity;}}
}

[Unity] 战斗系统学习 11:Buff 框架 1相关推荐

  1. [Unity] 战斗系统学习 4:FlowCanvas 中的 LatentActionNode

    [Unity] 战斗系统学习 2:FlowCanvas 中的 SubGraph 1. 并行执行 FlowScript 可能的魔改方向 其实我原本是想魔改 FlowCanvas 使其支持并行 FlowS ...

  2. [Unity] 战斗系统学习 5:构建 TPS 框架 1

    [Unity] ACT 战斗系统学习 4:重构前的第三人称控制器 以前看猴与花果山的文章,感觉大开眼界,但是没做过所以没更多体会 https://zhuanlan.zhihu.com/p/416805 ...

  3. [Unity] 战斗系统学习 9:构建 TPS 框架 4

    1. 技能框架 我的需求是要在 FlowScript 中写技能,然后在角色中引用这个 FlowScript,当需要释放技能的时候就启用这个 FlowScript 1.1 ScriptableAbili ...

  4. [Unity] 战斗系统学习 8:构建 TPS 框架 3:mono 组件

    1. 框架组件 1.1 FrameworkComponent v1 一开始我想的是这样做框架组件嘛,跟 GF 学的 但是后来我才知道 static 变量是默认在监视器上不显示的,怪不得 GF 不在 A ...

  5. [Unity] 战斗系统学习 6:构建 TPS 框架 2

    1. Port 与 BBParameter 我一开始就是公开组件接口,那个时候是因为我还只会用 AddValueInput,不会用 BBParameter 但是后来我发现 BBParameter 很简 ...

  6. [Unity] 战斗系统学习 10:ActorAttribute

    1. ActorAttribute v1 一开始我是想做一个可以使用泛型 ScriptableObject 的角色属性 1.1 ScriptableGenericVariable v1 泛型 Scri ...

  7. [Unity] 战斗系统学习 12:Switchable 1

    1. 批量 SmoothDamp 变量的需求 1.1 例子 这是我一个改到一半的函数--我懒得改了 这个函数的目的是从一个模式转换到另外一个模式的时候开始对一堆变量在一个时间内 SmoothDamp ...

  8. [Unity] 战斗系统学习 13:Switchable 2

    1. Switchable v2 改了这两个 TPSCharacterAnimationController.Mode TPSCharacterLocomotionController.Mode 之后 ...

  9. Scrapy框架的学习(11.scrapy框架中的下载中间件的使用(DownloaderMiddlewares))

    1.Downloader Middlewares (下载中间键):引擎会先把Requets对象交给下载中间键再然后交给Downloader 2.使用方法: (1) 编写一个Downloader Mid ...

最新文章

  1. ORB 特征检测与匹配
  2. Windows 显示环境变量
  3. java 读utf-8 xml_用Java和UTF-8編碼生成有效的XML。
  4. sift计算描述子代码详解_SIFT解析(三)生成特征描述子
  5. hdu 1598(最小生成树变形)
  6. BOOST使用 proto 转换进行任意类型操作的简单示例
  7. php创建表并插入数据,php数据库操作-创建库和表以及插入数据
  8. c++定义一个动态全局变量_静态链接与动态链接的宏观概述及微观详解
  9. java excel 插件开发工具_程序员常用的15 种开发者工具推荐
  10. 使用Listener准备application作用域数据
  11. android获取wifi别名,android-连接WIFI时获取SSID
  12. 樱桃键盘驱动linux,樱桃键盘mx board9.0驱动
  13. 英语单词记忆原理及方法 - 超全思维导图梳理
  14. 减少USB 1.1 2.0 端口驱动程序延时_肉鸡啄羽、啄肛、啄蛋等现象如何减少,养殖的朋友们值得看一看...
  15. opencv-python实际演练(二)军棋自动裁判(1)棋子图像采集设备DIY
  16. [附源码]java毕业设计逸尘房屋销售管理系统
  17. 怎么提高国外服务器速度?
  18. 扫地机器人朋友圈文案_扫地机器人的简单文案
  19. 英特尔酷睿处理器后面的数字和字母含义
  20. 分治法:快速排序棋盘覆盖

热门文章

  1. JavaEE基础(06):Servlet整合C3P0数据库连接池
  2. SpringCloud微服务(05):Zuul组件,实现路由网关控制
  3. Python学习day01_变量字符串与随机数
  4. leetcode题解(二叉树和递归问题)
  5. BZOJ2646 : neerc2011 flight
  6. Deploy过程出错解决
  7. 计算机 科学计算应用邻预,电子计算机的工作特性主要有什么
  8. 华为软件java笔试_华为软件笔试题4.10
  9. 信息学奥赛一本通 1027:输出浮点数 | OpenJudge NOI 1.1 07
  10. 信息学奥赛一本通(1204:爬楼梯)