/// <summary> /// 创建弹道2 /// 目标点, 到达目标点为 /// </summary> /// <param name="ball">弹道对象</param> /// <param name="startPos">起始位置</param> /// <param name="direction">飞行起始方向</param> /// <param name="targetPos">目标点</param> /// <param name="speed">飞行速度</param> /// <param name="radius">物体半径</param> /// <param name="hasGravity">是否受重力影响</param> /// <param name="gravity">重力系数, 默认9.8</param> /// <param name="turnaroundWeight">转向权重</param> /// <returns>目标点飞行弹道</returns> public Ballistic CreateBallistic(GameObject ball, Vector3 startPos, Vector3 direction, Vector3 targetPos, float speed, float radius, bool hasGravity = true, float gravity = 9.8f, float turnaroundWeight = 1, TrajectoryAlgorithmType trajectoryType = TrajectoryAlgorithmType.Parabola) { if (ball == null) { return(null); } // 创建基础弹道数据 var result = CreateBallistic(ball, startPos, direction, speed, radius, hasGravity, gravity); result.BallisticArriveTarget = new BallisticArriveTargetForPosition(targetPos); // 移动方法 result.Move = TrajectoryAlgorithm.Single.GetAlgorithm(trajectoryType); return(result); }
/// <summary> /// 创建弹道3 /// 目标对象, 到达目标点 /// </summary> /// <param name="ball">弹道对象</param> /// <param name="startPos">起始位置</param> /// <param name="direction">飞行起始方向</param> /// <param name="targetObj">目标对象</param> /// <param name="speed">飞行速度</param> /// <param name="radius">物体半径</param> /// <param name="hasGravity">是否受重力影响</param> /// <param name="grivity">重力系数, 默认9.8</param> /// <returns>目标点飞行弹道</returns> public Ballistic CreateBallistic(GameObject ball, Vector3 startPos, Vector3 direction, GameObject targetObj, float speed, float radius, bool hasGravity = true, float grivity = 9.8f, TrajectoryAlgorithmType trajectoryType = TrajectoryAlgorithmType.Parabola) { if (ball == null) { return(null); } var result = CreateBallistic(ball, startPos, direction, speed, radius, hasGravity, grivity); result.BallisticArriveTarget = new BallisticArriveTargetForObj(targetObj); // 移动方法 result.Move = TrajectoryAlgorithm.Single.GetAlgorithm(trajectoryType); // 起始时运动一次, 防止出现一帧原始模型状态 result.Move(result, result.BallisticArriveTarget); return(result); }
/// <summary> /// 点对对象范围攻击 /// </summary> /// <param name="attacker">攻击者数据</param> /// <param name="effectKey">子弹预设key(或path)</param> /// <param name="releasePos">子弹飞行起点</param> /// <param name="targetObj">子弹目标单位</param> /// <param name="scopeRaduis">范围半径</param> /// <param name="speed">子弹飞行速度</param> /// <param name="durTime">范围特效持续时间</param> /// <param name="taType">子弹飞行轨迹</param> /// <param name="callback">攻击结束回调</param> /// <param name="callbackForEveryOne">每个受击单位的回调</param> /// <returns></returns> public IGeneralAttack GetPointToObjScopeGeneralAttack(PositionObject attacker, string[] effectKey, Vector3 releasePos, GameObject targetObj, float scopeRaduis, float speed, float durTime, TrajectoryAlgorithmType taType, Action callback, Action <GameObject> callbackForEveryOne = null) { IGeneralAttack result = null; result = new PointToObjScopeGeneralAttack(attacker, effectKey, releasePos, targetObj, scopeRaduis, speed, durTime, taType, callback, callbackForEveryOne); return(result); }
/// <summary> /// 初始化 /// </summary> /// <param name="attacker">攻击者数据</param> /// <param name="effectKey">子弹预设key(或path)</param> /// <param name="releasePos">子弹飞行起点</param> /// <param name="targetObj">子弹目标单位</param> /// <param name="scopeRaduis">范围半径</param> /// <param name="speed">子弹飞行速度</param> /// <param name="durTime">范围特效持续时间</param> /// <param name="taType">子弹飞行轨迹</param> /// <param name="callback">攻击结束回调</param> /// <param name="callbackForEveryOne">每个单位被击回调</param> public PointToObjScopeGeneralAttack(PositionObject attacker, string[] effectKey, Vector3 releasePos, GameObject targetObj, float scopeRaduis, float speed, float durTime, TrajectoryAlgorithmType taType, Action callback, Action <GameObject> callbackForEveryOne = null) { if (attacker == null) { //throw new Exception("攻击者集群数据为空"); return; } var key1 = effectKey[0]; var key2 = effectKey[1]; // 范围伤害 Action scopeDemage = () => { var positionScopeAttack = new PositionScopeGeneralAttack(attacker, key2, targetObj.transform.position, scopeRaduis, durTime, callback, callbackForEveryOne); positionScopeAttack.Begin(); }; var effectData = attacker.AllData.EffectData; var muzzleEffect = effectData.MuzzleFlashEffect; var muzzleDurTime = effectData.MuzzleFlashEffectTime; if (muzzleDurTime > 0) { // 对每个单位播受击特效 var muzzleAngle = Utils.GetAngleWithZ(attacker.MapCellObj.transform.forward); // TODO 使用挂点 EffectsFactory.Single.CreatePointEffect(muzzleEffect, ParentManager.Single.GetParent(ParentManager.BallisticParent).transform, attacker.MapCellObj.transform.position, new Vector3(1, 1, 1), muzzleDurTime, 0, null, Utils.EffectLayer, new Vector2(0, muzzleAngle)).Begin(); } // 飞行轨迹 effect = EffectsFactory.Single.CreatePointToObjEffect(key1, ParentManager.Single.GetParent(ParentManager.BallisticParent).transform, releasePos, targetObj, new Vector3(1, 1, 1), speed, taType, scopeDemage, Utils.EffectLayer); }
/// <summary> /// 点对点特效 /// TODO 加入路径 /// </summary> /// <param name="effectKey">特效key, 可以使路径, 或者AB包中对应的key</param> /// <param name="parent">父级</param> /// <param name="from">起点</param> /// <param name="targetObj">目标对象</param> /// <param name="scale">缩放</param> /// <param name="speed">速度</param> /// <param name="completeCallback">完成回调</param> public PointToTargetEffect(string effectKey, Transform parent, Vector3 from, GameObject targetObj, Vector3 scale, float speed, TrajectoryAlgorithmType flyType = TrajectoryAlgorithmType.Line, Action completeCallback = null, int effectLayer = 0) { this.effectKey = effectKey; this.parent = parent; this.position = from; this.targetObj = targetObj; this.scale = scale; this.speed = speed; this.flyType = flyType; this.completeCallback = completeCallback; this.layer = effectLayer; }
/// <summary> /// 点对点特效 /// TODO 加入路径 /// </summary> /// <param name="effectKey">特效key, 可以使路径, 或者AB包中对应的key</param> /// <param name="parent">父级</param> /// <param name="from">起点</param> /// <param name="to">目标点</param> /// <param name="scale">缩放</param> /// <param name="speed">速度</param> /// <param name="completeCallback">完成回调</param> public PointToPointEffect(string effectKey, Transform parent, Vector3 from, Vector3 to, Vector3 scale, float speed, TrajectoryAlgorithmType flyType, Action completeCallback = null, int effectLayer = 0) { this.effectKey = effectKey; this.parent = parent; this.position = from; this.to = to; this.scale = scale; this.speed = speed; this.flyType = flyType; this.completeCallback = completeCallback; this.layer = effectLayer; }
/// <summary> /// 创建点对点特效 /// 特效会从start按照速度与轨迹飞到目标对象位置 /// </summary> /// <returns>特效对象</returns> public EffectBehaviorAbstract CreatePointToObjEffect(string effectKey, Transform parent, Vector3 position, GameObject targetObj, Vector3 scale, float speed, TrajectoryAlgorithmType flytype = TrajectoryAlgorithmType.Line, Action completeCallback = null, int effectLayer = 0) { EffectBehaviorAbstract result = null; result = new PointToTargetEffect(effectKey, parent, position, targetObj, scale, speed, flytype, completeCallback, effectLayer); return(result); }
/// <summary> /// 常规普通攻击 /// </summary> /// <param name="attacker">攻击者数据</param> /// <param name="beAttackMember">被攻击者数据</param> /// <param name="effectKey">子弹预设key(或path)</param> /// <param name="releasePos">子弹飞行起点</param> /// <param name="targetObj">子弹目标单位</param> /// <param name="speed">子弹飞行速度</param> /// <param name="taType">子弹飞行轨迹</param> /// <param name="callback">攻击结束回调</param> /// <returns></returns> public IGeneralAttack GetNormalGeneralAttack(PositionObject attacker, PositionObject beAttackMember, string effectKey, Vector3 releasePos, GameObject targetObj, float speed, TrajectoryAlgorithmType taType, Action <GameObject> callback) { IGeneralAttack result = null; result = new NormalGeneralAttack(attacker, beAttackMember, effectKey, releasePos, targetObj, speed, taType, callback); return(result); }
/// <summary> /// 点对点范围伤害 /// </summary> /// <param name="attacker">攻击者</param> /// <param name="releasePos">发射点</param> /// <param name="targetPos">目标点</param> /// <param name="scopeRaduis">范围伤害半径</param> /// <param name="speed">飞行速度</param> /// <param name="taType">弹道类型</param> /// <param name="callback">完成回调</param> /// <param name="callbackForEveryOne">每个受击单位的回调</param> /// <returns></returns> public IGeneralAttack GetPointToPositionScopeGeneralAttack(PositionObject attacker, Vector3 releasePos, Vector3 targetPos, float scopeRaduis, float speed, TrajectoryAlgorithmType taType, Action callback, Action <GameObject> callbackForEveryOne = null) { IGeneralAttack result = null; result = new PointToPositionScopeGeneralAttack(attacker, releasePos, targetPos, scopeRaduis, speed, taType, callback, callbackForEveryOne); return(result); }
/// <summary> /// 获取飞行算法 /// </summary> /// <param name="type">算法类型</param> /// <returns>具体算法, 如果列表中不存在该算法类型, 返回null</returns> public Action <Ballistic, BallisticArriveTarget> GetAlgorithm(TrajectoryAlgorithmType type) { Action <Ballistic, BallisticArriveTarget> result = null; switch (type) { // 抛物线移动 case TrajectoryAlgorithmType.Parabola: { #region Parabola result = (ballistic, ballisticArriveTarget) => { if (ballistic != null && ballisticArriveTarget != null) { var tmpTargetPos = GetTargetPos(ballistic, ballisticArriveTarget); var targetDir = tmpTargetPos - ballistic.StartPos; if (targetDir == Vector3.zero) { targetDir = Vector3.one; } // 判断是否有重力效果 if (!ballistic.HasGravity) { var tmpDir = ballistic.Direction.normalized * ballistic.Speed; ballistic.transform.forward = tmpDir; ballistic.Position += tmpDir * Time.deltaTime; // 走直线直奔目标 ballistic.Direction = targetDir; } else { // 使用时间计算当前位置 var passedTime = ballistic.PassedTime; // xz平面向量 //var targetPosWithoutY = new Vector2(tmpTargetPos.x, tmpTargetPos.z); //var theta = Math.Acos(Vector2.Dot(targetPosWithoutY.normalized, targetDir.z < 0 ? Vector2.left : Vector2.right)); // 计算位移比例 //var xOffsetProportion = (float)Math.Cos(theta + (targetDir.x < 0 ? Math.PI : 0)); //var zOffsetProportion = (float)Math.Sin(theta + (targetDir.z < 0 ? Math.PI : 0)); var normalizedTargetDir = targetDir.normalized; var xOffsetProportion = normalizedTargetDir.x; var zOffsetProportion = normalizedTargetDir.z; // X位移 var offsetX = ballistic.Speed * xOffsetProportion * passedTime + ballistic.StartPos.x; // Z位移 var offsetZ = ballistic.Speed * zOffsetProportion * passedTime + ballistic.StartPos.z; // 求起点与目标点的中心点 var center = (ballistic.StartPos + tmpTargetPos) * 0.5f; // 向下位移, 与弧线垂直 center -= new Vector3(0, 10 * ballistic.Gravity, 0); // 求中心点至两端的向量 var centerToStart = ballistic.StartPos - center; var centerToEnd = tmpTargetPos - center; // 使用两向量求差值 // Y位移 按照位置设置曲线 var radianVec = Vector3.Slerp(centerToStart, centerToEnd, (ballistic.Position - ballistic.StartPos).magnitude / (targetDir.magnitude)) + center; //speed * (float)Math.Sin(ballistic.ShootTheta) * passedTime - gravity * passedTime * passedTime / 2; // 计算新位置 var nowPos = Vector3.zero; nowPos.x = offsetX; nowPos.z = offsetZ; nowPos.y = radianVec.y; // 设置新位置 ballistic.Position = nowPos; // 累加已飞行时间 ballistic.PassedTime += Time.deltaTime; } // 判断如果超过目标则设置为到达目标 // 检测位置是否超过目标, 检测目标起始点与结束点的x,z如果与当前位置到结束点的x,z符号不同则判断其超过目标, 设置其位置为目标位置 // 当前位置到目标点的向量 var nowDir = tmpTargetPos - ballistic.Position; if (Math.Sign(nowDir.x) != Math.Sign(targetDir.x) || Math.Sign(nowDir.z) != Math.Sign(targetDir.z)) { // 超过目标位置, 设置其位置为目标位置 ballistic.Position = tmpTargetPos; } } }; #endregion } break; // 直线移动 case TrajectoryAlgorithmType.Line: { #region Line result = (ballistic, ballisticArriveTarget) => { if (ballistic != null && ballisticArriveTarget != null) { // 目标点 var target = GetTargetPos(ballistic, ballisticArriveTarget); // 计算当前移动 var tmpDir = ballistic.Direction.normalized * ballistic.Speed; ballistic.transform.forward = tmpDir; ballistic.Position += tmpDir * Time.deltaTime; ballistic.Direction = (target - ballistic.Position).normalized; } }; #endregion } break; // 正弦线移动 case TrajectoryAlgorithmType.Sine: { #region Sine result = (ballistic, ballisticArriveTarget) => { if (ballistic != null && ballisticArriveTarget != null) { // 目位置 var tmpTargetPos = GetTargetPos(ballistic, ballisticArriveTarget); // 目标方向 // TODO 移动目标可能会有问题 var targetDir = tmpTargetPos - ballistic.StartPos; var nowDir = tmpTargetPos - ballistic.Position; // 使用时间计算当前位置 var passedTime = ballistic.PassedTime; // X,Z向目标移动 // xz平面向量 var targetPosWithoutY = Utils.WithOutY(tmpTargetPos); var theta = Math.Acos(Vector2.Dot(targetPosWithoutY.normalized, targetDir.z < 0 ? Vector2.left : Vector2.right)); // 计算位移比例 var xOffsetProportion = (float)Math.Cos(theta + (targetDir.z < 0 ? Math.PI : 0)); var zOffsetProportion = (float)Math.Sin(theta + (targetDir.z < 0 ? Math.PI : 0)); // X位移 var offsetX = ballistic.Speed * xOffsetProportion * passedTime; // Z位移 var offsetZ = ballistic.Speed * zOffsetProportion * passedTime; // 计算新位置 var nowPos = Vector3.zero; nowPos.x = offsetX; nowPos.z = offsetZ; // Y轴震荡 // 求起点与目标点的中心点 var center = (ballistic.StartPos + tmpTargetPos) * 0.5f; // 向下位移, 与弧线垂直 center -= new Vector3(0, 10 * ballistic.Gravity, 0); // 求中心点至两端的向量 var centerToStart = ballistic.StartPos - center; var centerToEnd = tmpTargetPos - center; // 使用两向量求差值 // Y位移 按照位置设置曲线 var radianVec = Vector3.Slerp(centerToStart, centerToEnd, (ballistic.Position - ballistic.StartPos).magnitude / (targetDir.magnitude)) + center; //speed * (float)Math.Sin(ballistic.ShootTheta) * passedTime - gravity * passedTime * passedTime / 2; // 震荡单位长度 var shockLen = 50f; nowPos.y = radianVec.y + (float)Math.Sin((nowDir.magnitude % shockLen) * 2 / shockLen * Math.PI); // X,Z轴震荡 // 设置新位置 ballistic.Position = nowPos + ballistic.StartPos; // 累加已飞行时间 ballistic.PassedTime += Time.deltaTime; if (Math.Sign(nowDir.x) != Math.Sign(targetDir.x) || Math.Sign(nowDir.z) != Math.Sign(targetDir.z)) { // 超过目标位置, 设置其位置为目标位置 ballistic.Position = tmpTargetPos; } } }; #endregion } break; } return(result); }
/// <summary> /// /// </summary> /// <param name="attacker">攻击者数据</param> /// <param name="beAttackMember">被攻击者数据</param> /// <param name="effectKey">子弹预设key(或path)</param> /// <param name="releasePos">子弹飞行起点</param> /// <param name="targetObj">子弹目标单位</param> /// <param name="speed">子弹飞行速度</param> /// <param name="taType">子弹飞行轨迹</param> /// <param name="callback">攻击结束回调</param> public NormalGeneralAttack(PositionObject attacker, PositionObject beAttackMember, string effectKey, Vector3 releasePos, GameObject targetObj, float speed, TrajectoryAlgorithmType taType, Action <GameObject> callback) { if (attacker == null || beAttackMember == null) { //throw new Exception("被攻击者或攻击者数据为空"); return; } // 特效数据 var effectData = beAttackMember.AllData.EffectData; Action demage = () => { //var attackerDisplayOwner = FightUnitManager.Single.GetElementByPositionObject(attacker); //var beAttackerDisplayOwner = FightUnitManager.Single.GetElementByPositionObject(beAttackMember); //if (beAttackerDisplayOwner == null // || attackerDisplayOwner == null // || null == beAttackerDisplayOwner.ClusterData) //{ // return; //} // 判断是否命中 //var isMiss = HurtResult.AdjustIsMiss(attackerDisplayOwner, beAttackerDisplayOwner); //if (!isMiss) //{ // // 计算伤害 // // TODO 伤害计算加入Buff与技能的计算 // //var hurt = HurtResult.GetHurt(attackerDisplayOwner, beAttackerDisplayOwner); // //// 记录被击触发 记录扣血 伤害结算时结算 // //SkillManager.Single.SetTriggerData(new TriggerData() // //{ // // HealthChangeValue = hurt, // // ReceiveMember = attackerDisplayOwner, // // ReleaseMember = beAttackerDisplayOwner, // // TypeLevel1 = TriggerLevel1.Fight, // // TypeLevel2 = TriggerLevel2.BeAttack, // // DemageType = DemageType.NormalAttackDemage, // // IsCrit = HurtResult.IsCrit // //}); // //// 命中时检测技能 // //SkillManager.Single.SetTriggerData(new TriggerData() // //{ // // // 将造成的伤害带回 // // HealthChangeValue = hurt, // // ReceiveMember = beAttackerDisplayOwner, // // ReleaseMember = attackerDisplayOwner, // // TypeLevel1 = TriggerLevel1.Fight, // // TypeLevel2 = TriggerLevel2.Hit, // // DemageType = DemageType.NormalAttackDemage // //}); // var getHitEffect = effectData.GetHitByBulletEffect; // var getHitDurTime = 0f; // // 分辨特效类型 // switch (effectData.BulletType) // { // case 1: // getHitEffect = effectData.GetHitByBulletEffect; // getHitDurTime = effectData.GetHitByBulletEffectTime; // break; // case 2: // getHitEffect = effectData.GetHitByBombEffect; // getHitDurTime = effectData.GetHitByBombEffectTime; // break; // } // if (getHitDurTime > 0) // { // // 对每个单位播受击特效 // // 计算旋转角度 // var beAttackAngle = Utils.GetAngleWithZ(attacker.MapCellObj.gameObject.transform.forward) + 180; // // TODO 使用挂点 // EffectsFactory.Single.CreatePointEffect(getHitEffect, // ParentManager.Single.GetParent(ParentManager.BallisticParent).transform, // beAttackMember.MapCellObj.transform.position, // new Vector3(1, 1, 1), // getHitDurTime, // 0, // null, // Utils.EffectLayer, // new Vector2(0, beAttackAngle)).Begin(); // } //} //else //{ // //// 闪避时事件 // //SkillManager.Single.SetTriggerData(new TriggerData() // //{ // // ReceiveMember = attackerDisplayOwner, // // ReleaseMember = beAttackerDisplayOwner, // // TypeLevel1 = TriggerLevel1.Fight, // // TypeLevel2 = TriggerLevel2.Dodge // //}); // //var beAttackVOBase = beAttackerDisplayOwner.ClusterData.AllData.MemberData; // // 抛出miss事件 // //FightManager.Single.DoHealthChangeAction(beAttackerDisplayOwner.GameObj, beAttackVOBase.TotalHp, // // beAttackVOBase.CurrentHP, 0f, FightManager.HurtType.Miss, beAttackVOBase.ObjID.ObjType); //} }; // 枪口火焰 var muzzleEffect = effectData.MuzzleFlashEffect; var muzzleDurTime = effectData.MuzzleFlashEffectTime; if (muzzleDurTime > 0) { // 对每个单位播枪口火焰特效 // 计算角度 var muzzleAngle = Utils.GetAngleWithZ(attacker.MapCellObj.transform.forward); // TODO 使用挂点 EffectsFactory.Single.CreatePointEffect(muzzleEffect, ParentManager.Single.GetParent(ParentManager.BallisticParent).transform, attacker.MapCellObj.transform.position, new Vector3(1, 1, 1), muzzleDurTime, 0, null, Utils.EffectLayer, new Vector2(0, muzzleAngle)).Begin(); } Action action = () => { if (callback != null && beAttackMember != null) { callback(beAttackMember.MapCellObj); } }; effect = EffectsFactory.Single.CreatePointToObjEffect(effectKey, ParentManager.Single.GetParent(ParentManager.BallisticParent).transform, releasePos, targetObj, new Vector3(1, 1, 1), speed, taType, demage + action, Utils.EffectLayer); }