private proto.PartFireInfo PartFire(ClientParts part, ShipEntity target) { proto.PartFireInfo fireInfo = new proto.PartFireInfo(); fireInfo.targetid = target.ID; if (part.Reference.missle_vel > 0) { float distance = Vector3.Distance(this.Ship.Position, target.Ship.Position); int delayFrame = Mathf.CeilToInt(distance / (part.Reference.missle_vel * FightServiceDef.SPEED_SCALAR)); fireInfo.delayframe = delayFrame; } else { int delayFrame = Mathf.CeilToInt(part.Reference.continued_time / FightServiceDef.FRAME_INTERVAL_TIME); fireInfo.delayframe = delayFrame; } int baseAtk = GetBaseAtkValue(part, target); if (Ship.Reference.stack) { baseAtk *= StackAliveNum_; } MessageDispatcher.Instance.DispatchMessage(TelegramType.UnderAttack, this.ID, target.ID, fireInfo.delayframe, baseAtk, part.Reference.effect_type); return(fireInfo); }
/// <summary> /// 扇形区域检测算法标准版,先实现这个 /// </summary> /// <param name="parts">攻击部件</param> /// <param name="targetShip">敌方单位</param> /// <param name="squareRange">检测范围平方</param> /// <param name="theta">扇形角度</param> /// <returns></returns> private static bool IsInCritricalSector(ClientParts parts, ClientShip targetShip, float squareRange, float theta) { // float distanceSq = GetDistanceSq( parts.Owner, targetShip ); // if( distanceSq > squareRange ) // return false; // D = P - C float dx = targetShip.Position.x - parts.Owner.Position.x; float dz = targetShip.Position.z - parts.Owner.Position.z; // |D|^2 = (dx^2 + dz^2) float disntaceSq = dx * dx + dz * dz; // |D|^2 > r^2 if (disntaceSq > squareRange) { return(false); } float distance = Mathf.Sqrt(disntaceSq); // Normalize D dx /= distance; dz /= distance; return(true); }
/// <summary> /// 播放子弹 /// </summary> /// <param name="part"></param> /// <param name="target"></param> /// <param name="delayFrame"></param> private void ShowBullet(ClientParts clientPart, List <BulletTarget> targetList, SpellType spellType, string attackPoint, string bulletPath, Effect hurtEffect, Vector3 position, ClientSkill skill = null) { Transform attackTransRoot = GetTransformByName(attackPoint); foreach (Transform attackTrans in attackTransRoot) { BulletDisplay.ShowBullet(attackTrans.position.x, attackTrans, targetList, clientPart, spellType, bulletPath, hurtEffect, position, skill); } }
/// <summary> /// 判断是否在攻击范围内 /// </summary> /// <param name="parts"></param> /// <param name="targetShip"></param> /// <returns></returns> private static bool CheckInAttackRange(ClientParts parts, float distanceSq) { // TODO:暂时不检查角度 float AttackRangeSq = parts.AttackRangeMax * parts.AttackRangeMax; if (distanceSq <= AttackRangeSq) { return(true); } return(false); }
/// <summary> /// 激活指挥技能(这个代码可能就是服务于Demo的) /// </summary> public void ActivateCommanderSkill(ClientParts part) { ClientSkill skill = ClientSkill.CreateSkillByID(part.Reference.skill_attach); if (skill == null) { return; } skill.ControlPart = part; this.SkillDic.Add(skill.ID, skill); }
/// <summary> /// 判断是否进入进入了警戒范围 /// </summary> /// <param name="parts"></param> /// <param name="Distance"></param> /// <returns></returns> private static bool CheckInGuardRange(ClientParts parts, float distanceSq) { // TODO: 暂时不检查角度 float guardRangeSq = parts.MoveAttackRange * parts.MoveAttackRange; if (distanceSq <= guardRangeSq) { return(true); } return(false); }
// 设置优势增幅 private int GetAdvantageIncrease(ClientParts castPart, ShipEntity targetEntity) { if (castPart.Reference.advantage_unitstrait_type == targetEntity.Ship.Reference.unitstrait) { return(15000); } else if (castPart.Reference.disadvantage_unitstrait_type == targetEntity.Ship.Reference.unitstrait) { return(5000); } return(10000); }
private int GetBaseAtkValue(ClientParts castPart, ShipEntity targetEntity) { int baseAtk = 0; // 攻防产生的系数 int coefficient = 10000 + (castPart.AC - targetEntity.Ship.DC) * 10000 / (castPart.AC + targetEntity.Ship.DC); // 应用系数调整 baseAtk = Utility.GetValueByRate(castPart.Reference.effect_val, coefficient); // 优劣式增幅 baseAtk = Utility.GetValueByRate(baseAtk, GetAdvantageIncrease(castPart, targetEntity)); return(baseAtk); }
/// <summary> /// 盲区判定 /// </summary> /// <param name="parts"></param> /// <param name="DistSq"></param> /// <returns></returns> private static bool IsInBlindZone(ClientParts parts, float DistSq) { // 最小攻击距离为0,说明木有盲区 if (parts.AttackRagneMin == 0) { return(false); } int blindZone = parts.AttackRagneMin * parts.AttackRagneMin; if (DistSq < blindZone) { return(true); } return(false); }
/// <summary> /// 扇形区域检测,U3D版本 /// </summary> /// <param name="parts"></param> /// <param name="targetShip"></param> /// <returns></returns> private static bool IsInCricularSector2(ClientParts parts, ShipEntity targetUnit, float squareRange, float theta) { ClientShip targetShip = targetUnit.Ship; float dx = targetShip.Position.x - parts.Owner.Position.x; float dz = targetShip.Position.z - parts.Owner.Position.z; // |D|^2 = (dx^2 + dz^2) float disntaceSq = dx * dx + dz * dz; // |D|^2 > r^2 if (disntaceSq > squareRange) { return(false); } Vector3 targetDir = targetShip.Position - parts.Owner.Position; Vector3 forward = new Vector3(0, 0, 1); if (targetUnit.CampType == FightServiceDef.CampType.Camp_Attacker) { forward.z = -1; } float angle = Vector3.Angle(targetDir.normalized, forward); // 角度小于扇形的角度,说明目标的原型在扇形区域内 if (angle * 2 <= theta) { return(true); } // 近防距离检查 if (parts.Reference.closein_range > 0) { int closein_range = (parts.Reference.closein_range + targetShip.Reference.vol) * ((parts.Reference.closein_range + targetShip.Reference.vol)); if (closein_range >= disntaceSq) { return(true); } } return(false); }
/// <summary> /// 部件开火 /// </summary> /// <param name="fireEvent"></param> /// <param name="part"></param> private void CastPartFire(proto.PartFireEvent fireEvent, Part part) { ShowCast(part); // 范围攻击,只生成一个子弹 if (part.partType == SpellType.AOE) { List <BulletTarget> targetList = new List <BulletTarget>(); for (int i = 0; i < fireEvent.fireinfo_size(); i++) { proto.PartFireInfo info = fireEvent.fireinfo(i); TeamDisplay target = BattleSceneDisplayManager.Instance.GetTeamDisplay(info.targetid); if (target == null) { continue; } BulletTarget bulletTarget = new BulletTarget(); bulletTarget.delayFrame = info.delayframe; bulletTarget.Target = target; targetList.Add(bulletTarget); } ClientParts parts = Team_.GetPartsByID(part.partID); ShowBullet(parts, targetList, part.partType, part.attackPoint, part.bulletPath, part.hitEffect, Vector3.zero); return; } // 个体攻击,每个对象都生成子弹 for (int i = 0; i < fireEvent.fireinfo_size(); i++) { proto.PartFireInfo info = fireEvent.fireinfo(i); TeamDisplay target = BattleSceneDisplayManager.Instance.GetTeamDisplay(info.targetid); if (target == null) { continue; } List <BulletTarget> targetList = new List <BulletTarget>(); BulletTarget bulletTarget = new BulletTarget(); bulletTarget.delayFrame = info.delayframe; bulletTarget.Target = target; targetList.Add(bulletTarget); ClientParts parts = Team_.GetPartsByID(part.partID); ShowBullet(parts, targetList, part.partType, part.attackPoint, part.bulletPath, part.hitEffect, Vector3.zero); } }
/// <summary> /// 部件状态会影响舰艇的状态,具体可以查询文档,状态转换表 /// </summary> /// <returns></returns> public int GetPartState() { // 有部件已经达到攻击射程,则判断整体为 int state = PartState.Idle; for (int i = 0; i < Ship.PartsList.Count; ++i) { ClientParts part = Ship.PartsList[i]; if (part.PartState == PartState.Attack) { return(PartState.Attack); } if (part.PartState == PartState.Guard) { state = PartState.Guard; } } return(state); }
/// <summary> /// 根据部件来搜索敌人 /// </summary> /// <param name="Attacker"></param> /// <returns></returns> public static List <EnemyInfo> FindTarget(ClientParts parts, int campType) { List <EnemyInfo> targeSelecttList = new List <EnemyInfo>(); List <Entity> targetUnitList = EntityManager.Instance.DefenderUnitList; if (campType == FightServiceDef.CampType.Camp_Defender) { targetUnitList = EntityManager.Instance.AttackUnitList; } for (int i = 0; i < targetUnitList.Count; ++i) { ShipEntity targetShip = targetUnitList[i] as ShipEntity; if (!targetShip.IsActive()) { continue; } float distanceSq = GetDistanceSq(parts.Owner, targetShip.Ship); // 先判断是否已经在最小攻击范围内 if (IsInBlindZone(parts, distanceSq)) { continue; } int moveAttackRange = (parts.MoveAttackRange + targetShip.Ship.Reference.vol) * (parts.MoveAttackRange + targetShip.Ship.Reference.vol); if (IsInCricularSector2(parts, targetShip, moveAttackRange, parts.AttackAngle)) { EnemyInfo enemy; enemy.DistanceSQ = distanceSq; enemy.EnemyShip = targetShip; enemy.InAttackRange = false; // 2015/7/8 InAttackRange的检查放到FilterTarget里面去,会省一些计算 //enemy.InAttackRange = CheckInAttackRange(parts, targetShip.Ship.Reference.vol, distanceSq); targeSelecttList.Add(enemy); } } return(FilterTarget(parts, targeSelecttList)); }
private static bool IsPriorityTarget(ClientParts castPart, ShipEntity targetEntity) { if (castPart.Reference.priority_unitstrait == Def.ShipTrait.None && castPart.Reference.priority_unitstrait_extend == Def.ShipExtendTrait.None) { return(false); } if (castPart.Reference.priority_unitstrait == targetEntity.Ship.Reference.unitstrait) { return(true); } if (castPart.Reference.priority_unitstrait == Def.ShipTrait.None && castPart.Reference.priority_unitstrait_extend == targetEntity.Ship.Reference.unitsextendtrait) { return(true); } return(false); }
public void ReadFromId(int id) { ShipProperty_.ClearAll(); Id = id; Level = 1; ReadFromReference(GlobalConfig.GetUnitReference(Id)); ShipProperty_.MaxDurability = Reference.durability; ShipProperty_.MaxArmor = Reference.armor; ShipProperty_.MaxEnergy = Reference.energy; ShipProperty_.MaxShuttleTeam = Reference.shuttle_team; ShipProperty_.MaxEccm = 0; //因为舰船不自带,所以初始化为0 ShipProperty_.MaxSpeed = Reference.speed_max; ShipProperty_.MaxSwspeed = Reference.sw_speed; ShipProperty_.MaxForceShield = 0; //因为舰船不自带,所以初始化为0 Durability = MaxDurability; DefenseClass_ = Reference.dc_initial; // 等级暂时不做处理 // 默认开放所有的部件 if (Reference.parts_1 != 0) { ClientParts parts = new ClientParts(); parts.ReadFromProto(Reference.parts_1); parts.Level = 1; parts.Owner = this; this.PartsDic[parts.Id] = parts; this.PartsList.Add(parts); if (this.Reference.unitstrait == Def.ShipTrait.CommanderShip) { ActivateCommanderSkill(parts); } } if (Reference.parts_2 != 0) { ClientParts parts = new ClientParts(); parts.ReadFromProto(Reference.parts_2); parts.Level = 1; parts.Owner = this; this.PartsDic[parts.Id] = parts; this.PartsList.Add(parts); if (this.Reference.unitstrait == Def.ShipTrait.CommanderShip) { ActivateCommanderSkill(parts); } } if (Reference.parts_3 != 0) { ClientParts parts = new ClientParts(); parts.ReadFromProto(Reference.parts_3); parts.Level = 1; parts.Owner = this; this.PartsDic[parts.Id] = parts; this.PartsList.Add(parts); if (this.Reference.unitstrait == Def.ShipTrait.CommanderShip) { ActivateCommanderSkill(parts); } } }
/// <summary> /// 子弹 /// </summary> /// <param name="attackShipTrans"></param> /// <param name="attackPartTrans"></param> /// <param name="target"></param> /// <param name="attackPart"></param> /// <param name="part"></param> /// <param name="delayTime"></param> public static void ShowBullet(float srcX, Transform attackPartTrans, List <BulletTarget> targetList, ClientParts attackPart, SpellType spellType, string bulletPath, Effect hurtEffect, Vector3 position, ClientSkill skill) { // 范围攻击特殊处理 if (spellType == SpellType.AOE) { BulletDisplay display = InitBullet(attackPartTrans, null, null, spellType, bulletPath, hurtEffect); if (display == null) { return; } display.SetAOE(targetList, position, skill); return; } // 其他攻击,一个子弹只对应一个目标 if (targetList.Count != 1) { return; } if (targetList[0].Target == null) { return; } ShipDisplay targetShip = targetList[0].Target.GetHurtShip(); if (targetShip == null) { return; } float delayTime = FightServiceDef.FRAME_INTERVAL_TIME_F * targetList[0].delayFrame; Transform targetTrans = targetShip.GetTransformByName(targetShip.GetHitPoint(srcX, spellType)); if (targetTrans == null) { targetTrans = targetShip.Trans; } // 导弹特殊处理,从左右发子弹 if (spellType == SpellType.Missile) { // TODO: 临时增加逻辑,防御节点一边扔3颗导弹 // 后面要考虑走配置 int missileCout = 1; if (attackPart.Owner.Reference.unitstrait == Def.ShipTrait.DefenseBuild) { missileCout = 3; } for (int i = 0; i < missileCout; i++) { BulletDisplay display = InitBullet(attackPartTrans, targetShip, targetTrans, spellType, bulletPath, hurtEffect); if (display == null) { return; } display.SetMissile(attackPartTrans.name.Contains("left"), delayTime); } } // 机枪特殊处理,做成扫射效果 else if (spellType == SpellType.MachineGun) { for (int i = 0; i < attackPart.Reference.continuity_times; i++) { BulletDisplay display = InitBullet(attackPartTrans, targetShip, targetTrans, spellType, bulletPath, hurtEffect); display.SetGun(delayTime, (float)attackPart.Reference.continuity_interval / 1000f * i); } } else { BulletDisplay display = InitBullet(attackPartTrans, targetShip, targetTrans, spellType, bulletPath, hurtEffect); display.SetLaserOrConnon(delayTime); } }
/// <summary> /// 扇形区域算法优化版 /// 1、优化半径检测开平方 /// 2、优化夹角选择开平方 /// </summary> /// <param name="?"></param> /// <returns></returns> private static bool IsInCricularSector1(ClientParts parts, ClientShip targetShip) { return(true); }
/// <summary> /// 过滤目标 /// </summary> /// <param name="targetList"></param> /// <returns></returns> private static List <EnemyInfo> FilterTarget(ClientParts part, List <EnemyInfo> targetList) { if (targetList.Count == 0) { return(targetList); } float distanceSq = float.MaxValue; float minDistanceSq = float.MaxValue; int targetIndex = 0; int priorityIndex = -1; // TODO // 此处需要优化和完善 List <EnemyInfo> enemyList = new List <EnemyInfo>(); for (int i = 0; i < targetList.Count; ++i) { // 这里出现了嵌套的if判断 // 主要从优化出发,考虑一趟遍历就做完所有筛选判断 EnemyInfo targetInfo = targetList[i]; // 记录下偏小的一个距离 if (minDistanceSq > targetInfo.DistanceSQ) { minDistanceSq = targetInfo.DistanceSQ; } // 判断是否是高优先级目标 bool prioprityTarget = false; if (IsPriorityTarget(part, targetInfo.EnemyShip)) { if (priorityIndex == -1) { prioprityTarget = true; } else if (targetInfo.DistanceSQ < distanceSq) { prioprityTarget = true; } } if (prioprityTarget) { distanceSq = targetInfo.DistanceSQ; targetIndex = i; priorityIndex = i; continue; } // 如果前面的优先级判定不成立,则遍历出距离最近的目标 if (targetList[i].DistanceSQ < distanceSq) { distanceSq = targetList[i].DistanceSQ; targetIndex = i; } } if (priorityIndex != -1) { targetIndex = priorityIndex; } // 对攻击距离进行修正 EnemyInfo targetEnemy = targetList[targetIndex]; targetEnemy.DistanceSQ = minDistanceSq; targetEnemy.InAttackRange = CheckInAttackRange(part, targetEnemy.EnemyShip.Ship.Reference.vol, minDistanceSq); enemyList.Add(targetEnemy); return(enemyList); }
private static bool CheckInAttackRange(ClientParts parts, int targetRaduis, float distanceSq) { float attackRangeSQ = (parts.AttackRangeMax + targetRaduis) * (parts.AttackRangeMax + targetRaduis); return(distanceSq <= attackRangeSQ); }
private IEnumerator CastSkill(proto.UseSkill useSkill) { Skill skill = GetSkill(useSkill.partid); if (skill == null) { Debug.Log("skill is null"); yield break; } ShowCast(skill); ClientSkill clientSkill = BattleSys.GetCommanderShip().GetSkillById(useSkill.skillid); // 范围攻击,只生成一个子弹 if (skill.partType == SpellType.AOE) { List <BulletTarget> targetList = new List <BulletTarget>(); for (int i = 0; i < useSkill.fireinfolist_size(); i++) { proto.PartFireInfo info = useSkill.fireinfolist(i); TeamDisplay target = BattleSceneDisplayManager.Instance.GetTeamDisplay(info.targetid); if (target == null) { continue; } BulletTarget bulletTarget = new BulletTarget(); bulletTarget.delayFrame = info.delayframe; bulletTarget.Target = target; targetList.Add(bulletTarget); } ClientParts parts = Team_.GetPartsByID(skill.partID); float x = (float)useSkill.posx / 10000f; float y = (float)useSkill.posy / 10000f; float z = (float)useSkill.posz / 10000f; Vector3 position = new Vector3(x, y, z); ShowBullet(parts, targetList, skill.partType, skill.attackPoint, skill.bulletPath, skill.hitEffect, position, clientSkill); } // 个体攻击,每个对象都生成子弹 else { for (int i = 0; i < useSkill.fireinfolist_size(); i++) { proto.PartFireInfo info = useSkill.fireinfolist(i); TeamDisplay target = BattleSceneDisplayManager.Instance.GetTeamDisplay(info.targetid); if (target == null) { continue; } List <BulletTarget> targetList = new List <BulletTarget>(); BulletTarget bulletTarget = new BulletTarget(); bulletTarget.delayFrame = info.delayframe; bulletTarget.Target = target; targetList.Add(bulletTarget); ClientParts parts = Team_.GetPartsByID(skill.partID); ShowBullet(parts, targetList, skill.partType, skill.attackPoint, skill.bulletPath, skill.hitEffect, Vector3.zero, clientSkill); } } yield return(new WaitForSeconds(1.2f)); for (int i = 0; i < SingEffectList_.Count; i++) { if (SingEffectList_[i] == null) { continue; } Destroy(SingEffectList_[i]); } SingEffectList_.Clear(); }