Unity技能系统(二)

Unity技能系统(一)

Demo展示:

五.技能管理和释放

1.CharacterSkillSystem

技能系统类,给外部(技能按钮,按键)提供技能释放方法;

技能释放逻辑:

按顺序判定条件,成立怎继续,否则返回;

最终调用CharacterSkillManager中的DeploySkill方法;传递参数为SkillData;

提供了随机技能方法;

/// <summary>
/// 角色系统
/// </summary>
[RequireComponent(typeof(CharacterSkillManager))]
public class CharacterSkillSystem : MonoBehaviour
{
//技能管理
public CharacterSkillManager chSkillMgr; //角色状态
private CharacterStatus chStatus; //角色动画
private Animator mAnimator; //当前使用的技能
private SkillData currentUseSkill; //当前攻击的目标
private Transform currentSelectedTarget; //初始化
public void Start()
{
mAnimator = GetComponent<Animator>();
chSkillMgr = GetComponent<CharacterSkillManager>();
chStatus = GetComponent<CharacterStatus>();
} /// <summary>
/// 使用指定技能
/// </summary>
/// <param name="skillid">技能编号</param>
/// <param name="isBatter">是否连击</param>
public void AttackUseSkill(int skillid, bool isBatter = false)
{
//如果是连击,找当前技能的下一个连击技能
if (currentUseSkill != null && isBatter)
skillid = currentUseSkill.skill.nextBatterId;
//准备技能
currentUseSkill = chSkillMgr.PrepareSkill(skillid);
if (currentUseSkill != null)
{
//选中释放技能调用
if ((currentUseSkill.skill.damageType & DamageType.Select) == DamageType.Select)
{
var selectedTaget = SelectTarget();
if (currentUseSkill.skill.attckTargetTags.Contains("Player"))
selectedTaget = gameObject; if (selectedTaget != null)
{
CharacterStatus selectStatus = null;
//修改成获取characterStatus中的Selected节点设置隐藏;
if (currentSelectedTarget != null)
{
selectStatus = currentSelectedTarget.GetComponent<CharacterStatus>();
selectStatus.selected.SetActive(false);
}
currentSelectedTarget = selectedTaget.transform;
selectStatus = currentSelectedTarget.GetComponent<CharacterStatus>();
selectStatus.selected.SetActive(true); //buff技能
if ((currentUseSkill.skill.damageType & DamageType.Buff) == DamageType.Buff)
{
foreach (var buff in currentUseSkill.skill.buffType)
{
//加bufficon
GameObject uiPortrait = selectStatus.uiPortrait.gameObject;
MonsterMgr.I.HideAllEnemyPortraits();
uiPortrait.SetActive(true);
uiPortrait.transform.SetAsLastSibling();
selectStatus.uiPortrait.AddBuffIcon(buff, currentUseSkill.skill.buffDuration); //已有该buff刷新
bool exist = false;
var buffs = selectedTaget.GetComponents<BuffRun>();
foreach (var it in buffs)
{
if (it.bufftype == buff)
{
it.Reset();
exist = true;
break;
}
} if (exist)
continue; //添加新buff
var buffRun = selectedTaget.AddComponent<BuffRun>();
buffRun.InitBuff(buff, currentUseSkill.skill.buffDuration,
currentUseSkill.skill.buffValue, currentUseSkill.skill.buffInterval);
}
return;
} //转向目标
//transform.LookAt(currentSelectedTarget);
chSkillMgr.DeploySkill(currentUseSkill);
mAnimator.Play(currentUseSkill.skill.animtionName);
}
}
else
{
chSkillMgr.DeploySkill(currentUseSkill);
mAnimator.Play(currentUseSkill.skill.animtionName);
}
}
} /// <summary>
/// 随机选择技能
/// </summary>
public void RandomSelectSkill()
{
if (chSkillMgr.skills.Count > 0)
{
int index = UnityEngine.Random.Range(0, chSkillMgr.skills.Count);
currentUseSkill = chSkillMgr.PrepareSkill(chSkillMgr.skills[index].skill.skillID);
if (currentUseSkill == null) //随机技能未找到或未冷却结束
currentUseSkill = chSkillMgr.skills[0]; //用技能表中第一个(默认技能)做补充
}
} //选择目标
private GameObject SelectTarget()
{
//发一个球形射线,找出所有碰撞体
var colliders = Physics.OverlapSphere(transform.position, currentUseSkill.skill.attackDisntance);
if (colliders == null || colliders.Length == 0) return null; //从碰撞体列表中挑出所有的敌人
String[] attTags = currentUseSkill.skill.attckTargetTags;
var array = CollectionHelper.Select<Collider, GameObject>(colliders, p => p.gameObject); //正前方,tag正确,血量大于0,处于正前方的敌人
array = CollectionHelper.FindAll<GameObject>(array,
p => Array.IndexOf(attTags, p.tag) >= 0
&& p.GetComponent<CharacterStatus>().HP > 0 &&
Vector3.Angle(transform.forward, p.transform.position - transform.position) <= 90); if (array == null || array.Length == 0) return null; //将所有的敌人,按与技能的发出者之间的距离升序排列,
CollectionHelper.OrderBy<GameObject, float>(array,
p => Vector3.Distance(transform.position, p.transform.position));
return array[0];
}
}

2.CharacterSkillManager

技能数据的管理,加载所有技能特效模板进入对象池;

给CharacterSkillSystem提供技能释放接口DeploySkill;

提供技能冷却计算,预留获取cd剩余时间接口给UI,以及获取技能是否在cd中;

[RequireComponent(typeof(CharacterSkillSystem))]
public class CharacterSkillManager : MonoBehaviour
{
/// <summary>管理所有技能的容器</summary>
public List<SkillData> skills = new List<SkillData>(); /// <summary>技能的拥有者</summary>
private CharacterStatus chStatus = null; private SkillData curSkill; //添加技能数据
private void AddSkill(string path)
{
SkillTemp skTemp = Instantiate(Resources.Load<SkillTemp>(path));
Skill sk = LoadSkill(skTemp);;
SkillData skd = new SkillData();
skd.skill = sk;
skills.Add(skd);
} //初始化技能数据(有什么技能)
public void Start()
{
chStatus = GetComponent<CharacterStatus>(); AddSkill("Skill_1");
AddSkill("Skill_2");
AddSkill("Skill_3");
AddSkill("Skill_4");
AddSkill("Skill_5"); foreach (var item in skills)
{
//动态加载技能特效预制体 //Resources/Skill -- 技能特效预制体
if (item.skillPrefab == null && !string.IsNullOrEmpty(item.skill.prefabName))
item.skillPrefab = LoadFxPrefab("Skill/" + item.skill.prefabName); //Resources/Skill/HitFx 技能伤害特效预制体
if (item.hitFxPrefab == null && !string.IsNullOrEmpty(item.skill.hitFxName))
item.hitFxPrefab = LoadFxPrefab("Skill/" + item.skill.hitFxName);
}
} //将特效预制件载入到对象池,以备将来使用
private GameObject LoadFxPrefab(string path)
{
var key = path.Substring(path.LastIndexOf("/") + 1);
var go = Resources.Load<GameObject>(path);
GameObjectPool.I.Destory(
GameObjectPool.I.CreateObject(
key, go, transform.position, transform.rotation)
);
return go;
} //准备技能
public SkillData PrepareSkill(int id)
{
//从技能容器中找出相应ID的技能
var skillData = skills.Find(p => p.skill.skillID == id);
if (skillData != null && //查找到技能
chStatus.SP >= skillData.skill.costSP && //检查角色SP是否够使用该技能
skillData.coolRemain == 0) //且该技能已经冷却结束
{
skillData.Owner = gameObject;
return skillData;
} return null;
} //释放技能
public void DeploySkill(SkillData skillData)
{
//开始冷却计时
StartCoroutine(CoolTimeDown(skillData)); //动画某一帧触发技能特效,这里写一个延迟调用的方法,使用动画时间的百分解决特效释放时间问题
if (skillData.skill.delayAnimaTime != 0)
{
curSkill = skillData;
Invoke("DelayDeploySkill", skillData.skill.delayAnimaTime);
return;
} GameObject tempGo = null;
//创建技能预制体+创建位置的偏移
if ((skillData.skill.damageType & DamageType.FxOffset) == DamageType.FxOffset)
tempGo = GameObjectPool.I.CreateObject(skillData.skill.prefabName, skillData.skillPrefab,
transform.position + transform.forward * skillData.skill.fxOffset, transform.rotation);
//技能有发射点
else if ((skillData.skill.damageType & DamageType.FirePos) == DamageType.FirePos)
tempGo = GameObjectPool.I.CreateObject(skillData.skill.prefabName, skillData.skillPrefab,
chStatus.FirePos.position, chStatus.FirePos.rotation); if(tempGo == null)
return; //从预制体对象上找到技能释放对象
var deployer = tempGo.GetComponent<SkillDeployer>();
if (deployer == null)
deployer = tempGo.AddComponent<SkillDeployer>(); //设置要释放的技能————划重点
deployer.skillData = skillData;
//调用释放方法
deployer.DeploySkill(); //技能持续时间过后,技能要销毁
if ((skillData.skill.damageType & DamageType.Bullet) != DamageType.Bullet)
{
if (skillData.skill.durationTime > 0)
GameObjectPool.I.Destory(tempGo, skillData.skill.durationTime);
else
GameObjectPool.I.Destory(tempGo, 0.5f);
}
} //延迟释放技能
private void DelayDeploySkill()
{
GameObject tempGo = null;
//创建技能预制体+创建位置的偏移
if ((curSkill.skill.damageType & DamageType.FxOffset) == DamageType.FxOffset)
tempGo = GameObjectPool.I.CreateObject(curSkill.skill.prefabName, curSkill.skillPrefab,
transform.position + transform.forward * curSkill.skill.fxOffset, transform.rotation); else if ((curSkill.skill.damageType & DamageType.FirePos) == DamageType.FirePos)
tempGo = GameObjectPool.I.CreateObject(curSkill.skill.prefabName, curSkill.skillPrefab,
chStatus.FirePos.position, chStatus.FirePos.rotation); //从预制体对象上找到技能释放对象
var deployer = tempGo.GetComponent<SkillDeployer>();
if (deployer == null)
deployer = tempGo.AddComponent<SkillDeployer>(); //设置要释放的技能
deployer.skillData = curSkill;
//调用释放方法
deployer.DeploySkill(); //技能持续时间过后,技能要销毁
if ((curSkill.skill.damageType & DamageType.Bullet) != DamageType.Bullet)
{
if (curSkill.skill.durationTime > 0)
GameObjectPool.I.Destory(tempGo, curSkill.skill.durationTime);
else
GameObjectPool.I.Destory(tempGo, 0.5f);
}
} //冷却时间倒计时
public IEnumerator CoolTimeDown(SkillData skillData)
{
skillData.coolRemain = skillData.skill.coolTime;
while (skillData.coolRemain > 0)
{
yield return new WaitForSeconds(0.1f);
skillData.coolRemain -= 0.1f;
} skillData.coolRemain = 0;
} //取得冷却倒计时的剩余时间(秒)
public float GetSkillCoolRemain(int id)
{
return skills.Find(p => p.skill.skillID == id).coolRemain;
} private Skill LoadSkill(SkillTemp skillTemp)
{
Skill sk = skillTemp.skill;
int count = skillTemp.damageType.Length;
for (int i = 0; i < count; ++i)
{
sk.damageType = sk.damageType | skillTemp.damageType[i];
}
return sk;
}
}

3.SkillDeployer

挂载在技能特效上, 执行技能对释放者造成的影响(消耗MP,刷新MPUI);

对命中目标执行伤害计算,加载受伤特效添加debuff等;

伤害触发分为碰撞触发和目标选择器选中触发;

上面划得重点:

给技能释放器中skillData属性赋值的同时,创建目标选择器,给CharacterStatrus字段赋值;

中间有很多坑点:

1.刷新敌人头像显示,必须要设置显示层级在ui的最下层,同时设置其他UI位置,不能设置Active,禁用buff倒计时计算会失效,也可以将buff倒计时单独管理;

2.检测已有相同buff存在刷新buff时间;

3.多段伤害,每段伤害要重新检测攻击目标,有击退等buff存在;

4.伤害计算单独写方法,方便修改;

5.弹道和碰撞触发伤害的技能,受击特效挂载点不应该是HitFxPos,而是碰撞的接触点,然而使用触发器碰撞没办法返回碰撞点坐标,所以又做了射线检测;但是又会存在新的问题,射线检测只有一条线,没有体积,会造成边缘碰撞时射线未检测到,却已经触发碰撞了;

这里做了处理,射线未检测到却碰撞特效生成在HitFxPos;

可以自行尝试一下在技能特效的前段设置HitFxPos来设置受击特效的位置;

public class SkillDeployer : MonoBehaviour
{
private SkillData m_skillData; ///<summary>敌人选区,选择目标的算法</summary>
public IAttackSelector attackTargetSelector; private DamageMode damageMode; //发出者
private CharacterStatus status; /// <summary> 要释放的技能 </summary>
public SkillData skillData
{
set
{
m_skillData = value;
damageMode = 0;
if ((skillData.skill.damageType & DamageType.Sector) == DamageType.Sector)
damageMode = DamageMode.Sector;
else if ((skillData.skill.damageType & DamageType.Circle) == DamageType.Circle)
damageMode = DamageMode.Circle;
else if ((skillData.skill.damageType & DamageType.Line) == DamageType.Line)
damageMode = DamageMode.Line; if (damageMode != 0)
attackTargetSelector = SelectorFactory.CreateSelector(damageMode); status = value.Owner.GetComponent<CharacterStatus>();
}
get { return m_skillData; }
} /// <summary>技能释放</summary>
public virtual void DeploySkill()
{
if (m_skillData == null) return;
//对自身的影响
SelfImpact(m_skillData.Owner); //执行伤害的计算
if (damageMode != 0)
StartCoroutine(ExecuteDamage());
} //执行伤害的计算
protected virtual IEnumerator ExecuteDamage()
{
//按持续时间及,两次伤害间隔,
float attackTimer = 0; //已持续攻击的时间 ResetTargets();
if (skillData.attackTargets != null && skillData.attackTargets.Length > 0)
{
//Debug.Log(skillData.attackTargets[0].name);
foreach (var item in skillData.attackTargets)
{
//刷新敌人头像显示
CharacterStatus targetStatus = item.GetComponent<CharacterStatus>();
GameObject uiPortrait = targetStatus.uiPortrait.gameObject;
MonsterMgr.I.HideAllEnemyPortraits();
uiPortrait.SetActive(true);
uiPortrait.transform.SetAsLastSibling(); //加buff
foreach (var buff in skillData.skill.buffType)
{
//加bufficon
targetStatus.uiPortrait.AddBuffIcon(buff, skillData.skill.buffDuration); //已有该buff刷新
bool exist = false;
var buffs = item.GetComponents<BuffRun>(); foreach (var it in buffs)
{
if (it.bufftype == buff)
{
it.Reset();
exist = true;
break;
}
} if (exist)
{
continue;
} //添加新buff
var buffRun = item.AddComponent<BuffRun>();
buffRun.InitBuff(buff, skillData.skill.buffDuration, skillData.skill.buffValue,
skillData.skill.buffInterval);
}
}
} do
{
//通过选择器选好攻击目标
ResetTargets();
if (skillData.attackTargets != null && skillData.attackTargets.Length > 0)
{
//Debug.Log(skillData.attackTargets[0].name);
foreach (var item in skillData.attackTargets)
{
//对敌人的影响
TargetImpact(item);
}
} yield return new WaitForSeconds(skillData.skill.damageInterval);
attackTimer += skillData.skill.damageInterval;
//做伤害数值的计算
} while (skillData.skill.durationTime > attackTimer);
} private void ResetTargets()
{
if (m_skillData == null)
return; m_skillData.attackTargets = attackTargetSelector.SelectTarget(m_skillData, transform);
} private float CirculateDamage(GameObject goTarget)
{
CharacterStatus goStatus = goTarget.GetComponent<CharacterStatus>(); //是否命中计算
float rate = status.hitRate / (float) goStatus.dodgeRate;
if (rate < 1)
{
int max = (int) (rate * 100);
int val = Random.Range(0, 100);
if (val < max)
{
//Debug.Log("Miss");
return 0;
}
} //普攻的技能伤害为0; 技能有固定伤害*等级加成 + 普攻伤害
var damageVal = status.damage * (1000 / (1000 + goStatus.defence)) +
skillData.skill.damage * (1 + skillData.level * skillData.skill.damageRatio);
return damageVal;
} ///对敌人的影响nag
public virtual void TargetImpact(GameObject goTarget)
{
//出受伤特效
if (skillData.hitFxPrefab != null)
{
//找到受击特效的挂点
Transform hitFxPos = goTarget.GetComponent<CharacterStatus>().HitFxPos; var go = GameObjectPool.I.CreateObject(
skillData.skill.hitFxName,
skillData.hitFxPrefab,
hitFxPos.position,
hitFxPos.rotation);
go.transform.SetParent(hitFxPos);
GameObjectPool.I.Destory(go, 2f);
} //受伤
var damageVal = CirculateDamage(goTarget);
var targetStatus = goTarget.GetComponent<CharacterStatus>();
targetStatus.OnDamage((int) damageVal, skillData.Owner);
} //碰撞触发目标影响
public virtual void TargetImpact(GameObject goTarget, Collider collider)
{
//敌人buff
foreach (var buff in skillData.skill.buffType)
{
//已有该buff刷新
bool exist = false;
var buffs = goTarget.GetComponents<BuffRun>();
foreach (var it in buffs)
{
if (it.bufftype == buff)
{
it.Reset();
exist = true;
break;
}
} if (exist)
continue; //添加新buff
var buffRun = goTarget.AddComponent<BuffRun>();
buffRun.InitBuff(buff, skillData.skill.buffDuration,
skillData.skill.buffValue, skillData.skill.buffInterval);
} //出受伤特效
if (skillData.hitFxPrefab != null)
{
//找到受击特效的挂点,碰撞但未检测到射线点,生成受击特效在hitFxPos处
Ray ray = new Ray(transform.position, transform.forward);
RaycastHit hit;
Physics.Raycast((Ray) ray, out hit, 1000);
if (hit.collider == collider)
{
var go = GameObjectPool.I.CreateObject(
skillData.skill.hitFxName,
skillData.hitFxPrefab,
hit.point,
transform.rotation);
GameObjectPool.I.Destory(go, 2f);
}
else
{
Transform hitFxPos = goTarget.GetComponent<CharacterStatus>().HitFxPos;
var go = GameObjectPool.I.CreateObject(
skillData.skill.hitFxName,
skillData.hitFxPrefab,
hitFxPos.position,
hitFxPos.rotation);
GameObjectPool.I.Destory(go, 2f);
}
} //受伤
var damageVal = CirculateDamage(goTarget);
var targetStatus = goTarget.GetComponent<CharacterStatus>();
targetStatus.OnDamage((int) damageVal, skillData.Owner);
} ///对自身的影响
public virtual void SelfImpact(GameObject goSelf)
{
//释放者: 消耗SP
var chStaus = goSelf.GetComponent<CharacterStatus>();
if (chStaus.SP != 0)
{
chStaus.SP -= m_skillData.skill.costSP;
chStaus.uiPortrait.RefreshHpMp();
//add+2 魔法条更新
}
} private void OnTriggerEnter(Collider other)
{
if ((skillData.skill.damageType & DamageType.Bullet) == DamageType.Bullet)
{
if (skillData.skill.attckTargetTags.Contains(other.tag))
{
if (skillData.skill.attackNum == 1)
{
CharacterStatus targetStatus = other.GetComponent<CharacterStatus>();
GameObject uiPortrait = targetStatus.uiPortrait.gameObject;
MonsterMgr.I.HideAllEnemyPortraits();
uiPortrait.SetActive(true);
uiPortrait.transform.SetAsLastSibling(); //加buff
foreach (var buff in skillData.skill.buffType)
{
//加bufficon
targetStatus.uiPortrait.AddBuffIcon(buff, skillData.skill.buffDuration);
} TargetImpact(other.gameObject, other);
}
else
{
//通过选择器选好攻击目标
IAttackSelector selector = new CircleAttackSelector();
selector.SelectTarget(m_skillData, transform);
if (skillData.attackTargets != null && skillData.attackTargets.Length > 0)
{
foreach (var item in skillData.attackTargets)
{
//刷新敌人头像显示
CharacterStatus targetStatus = item.GetComponent<CharacterStatus>();
GameObject uiPortrait = targetStatus.uiPortrait.gameObject;
MonsterMgr.I.HideAllEnemyPortraits();
uiPortrait.SetActive(true);
uiPortrait.transform.SetAsLastSibling(); //加buff
foreach (var buff in skillData.skill.buffType)
{
//加bufficon
targetStatus.uiPortrait.AddBuffIcon(buff, skillData.skill.buffDuration);
} //对敌人的影响
TargetImpact(item, other);
}
}
} GameObjectPool.I.Destory(gameObject);
}
else if (other.CompareTag("Wall"))
{
if (skillData.hitFxPrefab != null)
{
Ray ray = new Ray(transform.position, transform.forward);
RaycastHit hit;
Physics.Raycast((Ray) ray, out hit, 1000); if (hit.collider != other)
return; //找到受击特效的挂点
var go = GameObjectPool.I.CreateObject(
skillData.skill.hitFxName,
skillData.hitFxPrefab,
hit.point,
other.transform.rotation);
//go.transform.SetParent(hitFxPos);
GameObjectPool.I.Destory(go, 2f);
} GameObjectPool.I.Destory(gameObject);
}
}
} public static Dictionary<BuffType, string> buffIconName = new Dictionary<BuffType, string>(); public static void InitBuffIconName()
{
buffIconName.Add(BuffType.Burn,"Buff_13");
buffIconName.Add(BuffType.Slow,"Buff_15");
buffIconName.Add(BuffType.Stun,"Buff_12");
buffIconName.Add(BuffType.Poison,"Buff_14");
buffIconName.Add(BuffType.BeatBack,"Buff_5");
buffIconName.Add(BuffType.BeatUp,"Buff_4");
buffIconName.Add(BuffType.Pull,"Buff_6");
buffIconName.Add(BuffType.AddDefence,"Buff_3");
buffIconName.Add(BuffType.RecoverHp,"Buff_7");
buffIconName.Add(BuffType.Light,"Buff_8");
}
}

小结

到目前,所有技能逻辑都结束;下一节介绍buff系统和UI显示相关;

Unity——技能系统(二)的更多相关文章

  1. Unity——技能系统(三)

    Unity技能系统(三) Unity技能系统(一) Unity技能系统(二) Demo展示 六.Buff系统 buff分为增益和减益buff,应该区分开来: /// <summary> / ...

  2. Unity——技能系统(一)

    技能系统(一) 一.Demo展示 二.功能介绍 集成了技能,冷却,buff,UI显示,倒计时,动画等: 技能类型:弹道技能,动画事件根据帧数采用延迟调用技能,自定义释放位置(偏移,发射点两种),buf ...

  3. 一个MMORPG的常规技能系统

    广义的的说,和战斗结算相关的内容都算技能系统,包括技能信息管理.技能调用接口.技能目标查找.技能表现.技能结算.技能创生体(buff/法术场/弹道)管理,此外还涉及的模块包括:AI模块(技能调用者). ...

  4. Unity——射线系统

    Unity射线系统 Demo展示 UI+Physical射线测试: FPS自定义射线测试: UGUI射线工具 实现功能,鼠标点击UI,返回鼠标点击的UI对象: 需要使用到鼠标点击事件-PointerE ...

  5. Win7系统安装Centos7.0双系统(二)

    4.6语言选择

  6. 三维软件转Unity的系统单位设置研究

    Unity的系统单位为米,其他3D软件的模型导入,而保持和Unity的比例一致是非常重要的,下面对各软件进行测试: ㈠. 3dsmax 转 Unity的比例为100:1:也就是说Unity单位是3ds ...

  7. Epicor系统二次开发

    Epicor系统二次开发 一.获取或修改界面EpiDataView的字段数据(Get EpiDataView data) C# EpiDataView edv = (EpiDataView)oTran ...

  8. go语言打造个人博客系统(二)

    go语言打造个人博客系统(二)   在上篇文章go语言打造个人博客系统(一)中,我们了解了go语言的优点和go语言的数据库操作,本次我们会完成博客系统的后端开发. 博客系统后端接口开发 路由测试 ht ...

  9. MMO技能系统的同步机制分析

    转自:http://www.gameres.com/729629.html 此篇文章基于之前文章介绍的技能系统,主要介绍了如何实现MMO中的技能系统的同步.阅读此文章之前,推荐首先阅读前一篇文章:一个 ...

随机推荐

  1. centos 关于yum无法使用

    一.网络问题 1.1 ping # 确认网络是否可以ping通, 通则不是网络问题(跳过), 不通则是网络问题(往下操作) ping www.baidu.com 1.2 检查网络模式 1.关闭虚拟机 ...

  2. CF1119H-Triple【FWT】

    正题 题目链接:https://www.luogu.com.cn/problem/CF1119H 题目大意 \(n\)个可重集,第\(i\)个里有\(x\)个\(a_i\),\(y\)个\(b_i\) ...

  3. iOS 15 无法弹出授权弹框之解决方案---Your app uses the AppTrackingTransparency framework, but we are unable to locate the App Tracking Transparency permission request when reviewed on iOS 15.0

    2021年9月30日下午:我正愉快的期盼着即将到来的国庆假期,时不时刷新下appstoreconnect的网址,28号就提上去的包,今天还在审核中....由于这个版本刚升级的xcode系统和新出的iO ...

  4. efcore分表分库原理解析

    ShardingCore ShardingCore 易用.简单.高性能.普适性,是一款扩展针对efcore生态下的分表分库的扩展解决方案,支持efcore2+的所有版本,支持efcore2+的所有数据 ...

  5. Redis大集群扩容性能优化实践

    一.背景 在现网环境,一些使用Redis集群的业务随着业务量的上涨,往往需要进行节点扩容操作. 之前有了解到运维同学对一些节点数比较大的Redis集群进行扩容操作后,业务侧反映集群性能下降,具体表现在 ...

  6. Proxychains完成Linux命令行代理

    前言 Proxychains是一个Linux和类Unix平台非常流行的命令行代理工具,它支持强制应用的TCP 连接通过代理,支持 Tor.HTTP与 Socks 代理.与 sshuttle 不同的是, ...

  7. 款阿里开源的 Java 诊断工具Arthas

    Arthas是什么鬼? Arthas是一款阿里巴巴开源的 Java 线上诊断工具,功能非常强大,可以解决很多线上不方便解决的问题. Arthas诊断使用的是命令行交互模式,支持JDK6+,Linux. ...

  8. 保护模式篇——TLB与CPU缓存

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...

  9. flutter页面间跳转和传参-Navigator的使用

    flutter页面间跳转和传参-Navigator的使用 概述 flutter中的默认导航分成两种,一种是命名的路由,一种是构建路由. 命名路由 这种路由需要一开始现在创建App的时候定义 new M ...

  10. 洛谷 P2221 [HAOI2012]高速公路

    链接: P2221 题意: 有 \(n(1\leq n\leq 10^5)\) 个点,从第 \(i(1\leq i< n)\) 个点向第 \(i+1\) 个点连有边.最初所有边长 \(v_i\) ...