You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
618 lines
28 KiB
618 lines
28 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using GAS.Runtime;
|
|
using Sog;
|
|
using UnityEngine;
|
|
using xFrame;
|
|
|
|
namespace CoreGame.Render
|
|
{
|
|
public static class BulletSrv
|
|
{
|
|
private static List<ElementType> s_RandomElementTypes = new List<ElementType>
|
|
{
|
|
ElementType.Fire,
|
|
ElementType.Toxic,
|
|
ElementType.Thunder
|
|
};
|
|
|
|
// 追踪弹可能需要一个目标列表
|
|
public static CombatEntity[] CreateBulletWithEntity(GameAbilityContext ctx, int bulletId)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public static CombatEntity[] CreateBulletWithPoint(GameAbilityContext casterGaCtx, int bulletId,
|
|
Fixed64 rotateAngle, bool randomElementType = false)
|
|
{
|
|
// 发射者死亡,不发射
|
|
|
|
var casterEid = casterGaCtx.ownerEnt.creationIndex;
|
|
var ownerEnt = casterGaCtx.ownerEnt;
|
|
if (ownerEnt.IsValid() == false)
|
|
return null;
|
|
if (ownerEnt.hasBullet)
|
|
casterEid = ownerEnt.bullet.casterEid;
|
|
else if(ownerEnt.hasZone)
|
|
casterEid = ownerEnt.zone.casterEid;
|
|
|
|
var caster = Contexts.Combat.GetEntity(casterEid);
|
|
if (caster.IsValid() == false)
|
|
return null;
|
|
|
|
var casterProp = caster.property.container;
|
|
var level = casterGaCtx.level;
|
|
var gaInitCfg = casterGaCtx.abilitySpec.gaInitCfg;
|
|
|
|
TraceLog.Assert(casterGaCtx.castPos.Count > 0,
|
|
$"{casterGaCtx.abilitySpec.Ability.Name} CreateBulletWithPoint castPos.Count == 0");
|
|
// 释放位置外部已经选好了,必须有
|
|
var targetPos = TargetSelectSrv.GetCastTargetPos(casterGaCtx);
|
|
var eid = casterGaCtx.castTarget.Count > 0 ? casterGaCtx.castTarget[0] : -1;
|
|
var targetEnt = Contexts.Combat.GetEntity(eid);
|
|
|
|
var tbBullet = BulletDescMgr.Instance.GetConfig(bulletId);
|
|
if (tbBullet == null)
|
|
return null;
|
|
|
|
var bulletCount = (int)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(tbBullet.bulletsAmount, casterProp,
|
|
level, gaInitCfg, 3f);
|
|
var existTime = (float)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(tbBullet.duration, casterProp, level,
|
|
gaInitCfg, 3f);
|
|
var maxDistance = (float)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(tbBullet.maxDistance, casterProp,
|
|
level, gaInitCfg, 5f);
|
|
var collisionTimes = (int)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(tbBullet.collisionTimes, casterProp,
|
|
level, gaInitCfg, 1f);
|
|
var collisionInterval = (float)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(tbBullet.collisionInterval,
|
|
casterProp, level, gaInitCfg, 1f);
|
|
var scale = (float)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(tbBullet.scale, casterProp, level,
|
|
gaInitCfg, 1f);
|
|
var bounceTimes = (int)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(tbBullet.bounceTimes, casterProp, level,
|
|
gaInitCfg, 1f);
|
|
var bulletEntities = new CombatEntity[bulletCount];
|
|
|
|
var speed = 0f;
|
|
Fixed64 addAngle = 0;
|
|
Fixed64 nowAngle = 0;
|
|
var distance = 0f;
|
|
var maxRandomAngle = 0f;
|
|
var randomCurvePerpendicularControl = 0f;
|
|
var randomCurveParallelControl = 0f;
|
|
|
|
|
|
if (tbBullet.shootType == ShootType.Direct || tbBullet.shootType == ShootType.Curve)
|
|
{
|
|
maxRandomAngle = (float)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(tbBullet.bulletRandomAngle,
|
|
casterProp, level, gaInitCfg);
|
|
speed = (float)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(tbBullet.speed, casterProp, level,
|
|
gaInitCfg, 10f); //飞行速度
|
|
var bulletAngle = tbBullet.fireAngle * BattleConst.TenThousandReverse;
|
|
if (bulletAngle > 0 && bulletCount > 1)
|
|
{
|
|
var maxCastAngle = (float)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(tbBullet.fireAngleMax,
|
|
casterProp, level, gaInitCfg);
|
|
var totalAngle = (bulletCount - 1) * bulletAngle;
|
|
if (totalAngle > maxCastAngle)
|
|
{
|
|
totalAngle = maxCastAngle;
|
|
bulletAngle = maxCastAngle / (bulletCount - 1);
|
|
}
|
|
nowAngle = -totalAngle * Fixed64._0_50 + rotateAngle;
|
|
addAngle = bulletAngle;
|
|
}
|
|
else
|
|
{
|
|
nowAngle = rotateAngle;
|
|
}
|
|
|
|
if (tbBullet.shootType == ShootType.Curve)
|
|
{
|
|
randomCurvePerpendicularControl = (float)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(
|
|
tbBullet.moveParam1, casterProp, level, gaInitCfg, -1f);
|
|
randomCurveParallelControl = (float)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(
|
|
tbBullet.moveParam2, casterProp, level, gaInitCfg, -1f);
|
|
}
|
|
}
|
|
else if (tbBullet.shootType == ShootType.Surround)
|
|
{
|
|
speed = (float)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(tbBullet.moveParam1, casterProp, level,
|
|
gaInitCfg, 180f); //角速度
|
|
distance = (float)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(tbBullet.moveParam2, casterProp,
|
|
level, gaInitCfg, 2f);
|
|
addAngle = 360f / bulletCount;
|
|
if (targetEnt == null)
|
|
return null;
|
|
}
|
|
|
|
var element = ElementType.None;
|
|
var fromType = BulletFromType.None;
|
|
if (casterGaCtx.gunEid > 0)
|
|
{
|
|
var gun = Contexts.Combat.GetEntity(casterGaCtx.gunEid);
|
|
if (gun != null)
|
|
{
|
|
var gunGunData = gun.gunData;
|
|
if (gunGunData != null)
|
|
{
|
|
var gunCfg = WeaponDescMgr.Instance.GetConfig(gunGunData.gunCfgId);
|
|
element = gunGunData.elementType;
|
|
fromType = (BulletFromType)((int)gunCfg.Type << 2 + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < bulletCount; i++)
|
|
{
|
|
var cb = CreateBulletEntity(caster, element, fromType, tbBullet, existTime, maxDistance, collisionTimes,
|
|
collisionInterval, scale, speed, randomElementType);
|
|
|
|
// 传递技能参数
|
|
cb.AddGaCtxTransfer(casterGaCtx.abilitySpec.gaParams, casterGaCtx.abilitySpec.gaInitCfg,
|
|
casterGaCtx.level);
|
|
cb.AddLogicTransform(Fixed64Vector2.zero, Fixed64Vector2.one,Fixed64Vector2.right);
|
|
// cb.AddTransformProxy(Vector2.zero, Vector2.right, cb);
|
|
|
|
if (tbBullet.shootType == ShootType.Direct)
|
|
{
|
|
AddDirectBullet(ownerEnt, cb, targetPos, nowAngle, maxRandomAngle);
|
|
nowAngle += addAngle;
|
|
}
|
|
else if (tbBullet.shootType == ShootType.Surround)
|
|
{
|
|
AddSurroundBullet(targetEnt, cb, nowAngle, distance);
|
|
nowAngle += addAngle;
|
|
}
|
|
else if (tbBullet.shootType == ShootType.Curve)
|
|
{
|
|
// AddCurveBullet(ownerEnt, cb, targetPos, nowAngle, maxRandomAngle, tbBullet.warningPrefab,
|
|
// tbBullet.warningScale * BattleConst.TenThousandReverse, randomCurvePerpendicularControl,
|
|
// randomCurveParallelControl);
|
|
nowAngle += addAngle;
|
|
}
|
|
|
|
if (bounceTimes > 0)
|
|
{
|
|
var propertyComponent = cb.property;
|
|
propertyComponent.SetProperty(PropertyDef.BulletBounceCount, bounceTimes, true);
|
|
propertyComponent.SetProperty(PropertyDef.MaxBulletBounceCount, bounceTimes, true);
|
|
}
|
|
|
|
if (tbBullet.extraSkill > 0)
|
|
{
|
|
var context = AbilitySrv.GrantTransferAbility(cb, tbBullet.extraSkill, gaInitCfg, null, level);
|
|
if (context == null)
|
|
{
|
|
XLog.LogWarning("AttachActiveAbility failed: " + tbBullet.extraSkill);
|
|
}
|
|
}
|
|
|
|
// cb.LoadAsset();
|
|
bulletEntities[i] = cb;
|
|
}
|
|
caster.DispatchEvent(ClientEvent.OnShootBullets, bulletEntities);
|
|
return bulletEntities;
|
|
}
|
|
|
|
private static CombatEntity CreateBulletEntity(CombatEntity caster, ElementType element,
|
|
BulletFromType fromType, BulletDesc tbBullet, float existTime, float maxDistance, int collisionTimes,
|
|
float collisionInterval, float scale, float speed, bool randomElementType)
|
|
{
|
|
if (caster.IsValid() == false)
|
|
return null;
|
|
|
|
var cb = Contexts.Combat.CreateEntity();
|
|
if (randomElementType)
|
|
element = s_RandomElementTypes[RandomSrv.Range(0, s_RandomElementTypes.Count)];
|
|
|
|
var paramCount = tbBullet.colliderParam.Length;
|
|
var colliderParam1 =
|
|
paramCount > 0 ? tbBullet.colliderParam[0] * BattleConst.TenThousandReverse * scale : 0;
|
|
var colliderParam2 =
|
|
paramCount > 1 ? tbBullet.colliderParam[1] * BattleConst.TenThousandReverse * scale : 0;
|
|
|
|
if (tbBullet.skill == 0 && tbBullet.endSkill == 0)
|
|
{
|
|
XLog.LogError($"{tbBullet.bulletID} 子弹配置不对,没有技能!!!!");
|
|
}
|
|
cb.AddBullet(caster.creationIndex, element, fromType, tbBullet.bulletID, existTime, maxDistance, scale,
|
|
speed, tbBullet.colliderType, colliderParam1, colliderParam2, tbBullet.collideWith, collisionTimes,
|
|
collisionInterval, tbBullet.skill, tbBullet.endSkill, tbBullet.isTriggerHitSkillOnEnd != 0,
|
|
ListPool<HitData>.Pop());
|
|
var casterFaction = caster.faction;
|
|
cb.AddFaction(casterFaction.faction, SelectUseType.Bullet, casterFaction.opposite);
|
|
cb.AddProperty();
|
|
caster.property.TaskSnapShot(cb.property.container);
|
|
cb.property.SetProperty(PropertyDef.BulletFlyDistanceMax, maxDistance, true);
|
|
|
|
var ignore = ListPool<Type>.Pop();
|
|
ignore.Add(typeof(Animator));
|
|
var prefabPath = GetBulletPrefabPathByElementType(element, tbBullet);
|
|
cb.AddAsset(new MainAssetParam()
|
|
{
|
|
path = prefabPath,
|
|
parentNodeName = "RenderWorld",
|
|
scaleParam = scale
|
|
}, ignore);
|
|
cb.AddAudio(cb.creationIndex);
|
|
return cb;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 发射直线子弹
|
|
/// </summary>
|
|
/// <param name="owner">创造者,可能是人,也可能是子弹等</param>
|
|
/// <param name="bullet">子弹实体</param>
|
|
/// <param name="target">目标实体</param>
|
|
/// <param name="nowAngle">偏转角度</param>
|
|
/// <param name="maxRandomAngle">最大随机偏转角度</param>
|
|
private static void AddDirectBullet(CombatEntity owner, CombatEntity bullet,
|
|
Fixed64Vector2 target, Fixed64 nowAngle, Fixed64 maxRandomAngle)
|
|
{
|
|
var randomAngle = maxRandomAngle * RandomSrv.Range(-1f, 1f);
|
|
GetFirePos(owner, bullet, out var pos, out var dir);
|
|
if (target != pos )
|
|
{
|
|
dir = target - pos;
|
|
dir.Normalize();
|
|
}
|
|
|
|
bullet.logicTransform.SetPosition(pos);
|
|
Fixed64 angleRadians = FixedMath.Deg2Rad * (nowAngle + randomAngle);
|
|
Fixed64 x = dir.x * FixedMath.Cos(angleRadians) - dir.y * FixedMath.Sin(angleRadians);
|
|
Fixed64 y = dir.x * FixedMath.Sin(angleRadians) + dir.y * FixedMath.Cos(angleRadians);
|
|
bullet.logicTransform.SetDirection(new Fixed64Vector2(x, y));
|
|
bullet.isDirectBullet = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 发射环绕子弹
|
|
/// </summary>
|
|
/// <param name="targetEnt">环绕目标实体</param>
|
|
/// <param name="bullet">子弹实体</param>
|
|
/// <param name="nowAngle">角度</param>
|
|
/// <param name="distance">子弹和持有者的距离</param>
|
|
private static void AddSurroundBullet(CombatEntity targetEnt, CombatEntity bullet,
|
|
Fixed64 nowAngle, Fixed64 distance)
|
|
{
|
|
var transformProxy = bullet.logicTransform;
|
|
GetFirePos(targetEnt, bullet, out var pos, out var dir);
|
|
transformProxy.SetPosition(pos + Fixed64Vector2.right * distance);
|
|
bullet.AddSurroundBullet(targetEnt.creationIndex, distance);
|
|
bullet.surroundBullet.angle = nowAngle;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 发射抛物线子弹
|
|
/// </summary>
|
|
/// <param name="owner">创造者,可能是人,也可能是子弹等</param>
|
|
/// <param name="bulletEnt">子弹实体</param>
|
|
/// <param name="targetPos">目标位置</param>
|
|
/// <param name="nowAngle">角度</param>
|
|
/// <param name="maxRandomAngle">最大随机偏转角度</param>
|
|
/// <param name="explosionRangePath">爆炸预警prefab路径</param>
|
|
/// <param name="explosionRangeScale">爆炸预警prefab大小</param>
|
|
/// <param name="randomCurvePerpendicularControl">垂直方向控制点随机参数</param>
|
|
/// <param name="randomCurveParallelControl">平行方向控制点随机参数</param>
|
|
private static void AddCurveBullet(CombatEntity owner, CombatEntity bulletEnt,
|
|
Fixed64Vector2 targetPos, Fixed64 nowAngle, Fixed64 maxRandomAngle, string explosionRangePath,
|
|
Fixed64 explosionRangeScale, Fixed64 randomCurvePerpendicularControl, Fixed64 randomCurveParallelControl)
|
|
{
|
|
Fixed64 randomAngle = maxRandomAngle * RandomSrv.Range(-1, 1);
|
|
// var start = caster.transformProxy.position;
|
|
// var dir = caster.transformProxy.direction;
|
|
GetFirePos(owner, bulletEnt, out var start, out var dir);
|
|
Fixed64 distance = 3;
|
|
if (targetPos != start)
|
|
{
|
|
dir = targetPos - start;
|
|
distance = dir.Magnitude;
|
|
}
|
|
var totalFlyTime = distance / bulletEnt.bullet.speed;
|
|
bulletEnt.logicTransform.SetDirection(Fixed64Vector2.up);
|
|
bulletEnt.logicTransform.SetPosition(start);
|
|
|
|
var angleRadians = FixedMath.Deg2Rad * (nowAngle + randomAngle);
|
|
var x = dir.x * FixedMath.Cos(angleRadians) - dir.y * FixedMath.Sin(angleRadians);
|
|
var y = dir.x * FixedMath.Sin(angleRadians) + dir.y * FixedMath.Cos(angleRadians);
|
|
var startToEnd = new Fixed64Vector2(x, y);
|
|
var end = startToEnd + start;
|
|
|
|
// Vector2 control;
|
|
// if (randomCurvePerpendicularControl > 0f)
|
|
// {
|
|
// Fixed64Vector2 parallel = startToEnd.Normalize();
|
|
// var perpendicular = new Fixed64Vector2(-parallel.y, parallel.x);
|
|
// var parallelDisRate = 0.5f;
|
|
// if (randomCurveParallelControl > 0f)
|
|
// {
|
|
// parallelDisRate = RandomSrv.Range(0, randomCurveParallelControl);
|
|
// }
|
|
// var perpendicularDis = RandomSrv.Range(-randomCurvePerpendicularControl, randomCurvePerpendicularControl);
|
|
// control = start + parallel * (distance * parallelDisRate) + perpendicular * perpendicularDis;
|
|
// }
|
|
// else
|
|
// {
|
|
// var halfPoint = (start + end) / 2f;
|
|
// control = distance * BattleConst.CurveBulletControlParam * Vector2.up + halfPoint;
|
|
// }
|
|
|
|
// var explosionRangeEid = 0;
|
|
// if (string.IsNullOrEmpty(explosionRangePath) == false && explosionRangeScale > 0)
|
|
// {
|
|
// var explosionRangeEnt = Contexts.Combat.CreateEntity("ExplosionRange_" + bulletEnt.creationIndex);
|
|
// explosionRangeEnt.AddTransformProxy(targetPos, Vector2.right, explosionRangeEnt);
|
|
// explosionRangeEnt.AddAsset(new MainAssetParam()
|
|
// {
|
|
// path = explosionRangePath,
|
|
// parentNodeName = "RenderWorld",
|
|
// scaleParam = explosionRangeScale
|
|
// }, null);
|
|
// explosionRangeEid = explosionRangeEnt.creationIndex;
|
|
// }
|
|
// bulletEnt.AddCurveBullet(start, end, control, explosionRangeEid, totalFlyTime);
|
|
}
|
|
|
|
private static void DestroyInvalidBulletFromSpec(AbilitySpec abilitySpec)
|
|
{
|
|
var ctxOwnerEnt = abilitySpec.ctx.ownerEnt;
|
|
var bullet = ctxOwnerEnt.bullet;
|
|
// var orDefault = TDRoot.Tables.Bullet.GetOrDefault(1);
|
|
if (bullet == null)
|
|
{
|
|
XLog.LogDebug("DestroyBulletFromSpec bullet == null");
|
|
return;
|
|
}
|
|
|
|
if (bullet.hasInvalidated == false)
|
|
{
|
|
XLog.LogDebug("DestroyBulletFromSpec bullet not invalidated");
|
|
return;
|
|
}
|
|
|
|
bullet.invalidatedCount--;
|
|
if (bullet.invalidatedCount <= 0)
|
|
{
|
|
DestroyBullet(ctxOwnerEnt);
|
|
}
|
|
}
|
|
|
|
public static void DestroyBullet(CombatEntity bullet)
|
|
{
|
|
bullet.isDestroyEnt = true;
|
|
}
|
|
|
|
public static void InvalidateBullet(CombatEntity bullet)
|
|
{
|
|
if (bullet.hasBullet == false)
|
|
{
|
|
XLog.LogDebug("InvalidateBullet bullet.hasBullet == false");
|
|
return;
|
|
}
|
|
|
|
bullet.asset?.HideMainAsset(); // 隐藏模型, 但不销毁
|
|
bullet.isDirectBullet = false;
|
|
bullet.RemoveSurroundBullet();
|
|
bullet.RemoveCurveBullet();
|
|
bullet.bullet.hasInvalidated = true;
|
|
}
|
|
|
|
private static string GetBulletPrefabPathByElementType(ElementType elementType, BulletDesc tbBullet)
|
|
{
|
|
var prefabPath = tbBullet.prefab;
|
|
if (elementType == ElementType.Fire && !string.IsNullOrEmpty(tbBullet.firePrefab))
|
|
prefabPath = tbBullet.firePrefab;
|
|
else if (elementType == ElementType.Toxic && !string.IsNullOrEmpty(tbBullet.toxicPrefab))
|
|
prefabPath = tbBullet.toxicPrefab;
|
|
else if (elementType == ElementType.Thunder && !string.IsNullOrEmpty(tbBullet.thunderPrefab))
|
|
prefabPath = tbBullet.thunderPrefab;
|
|
return prefabPath;
|
|
}
|
|
|
|
private static void GetFirePos(CombatEntity owner, CombatEntity bullet, out Fixed64Vector2 pos, out Fixed64Vector2 dir)
|
|
{
|
|
var tp = owner.logicTransform;
|
|
pos = tp.position;
|
|
dir = tp.forward;
|
|
// pos = tp.position;
|
|
// dir = tp.direction;
|
|
// var bulletCfgId = bullet.bullet.bulletCfgId;
|
|
// var bulletCfg = BulletDescMgr.Instance.GetConfig(bulletCfgId);
|
|
// var bindPoint = owner.bindPointProxy;
|
|
// if (bindPoint == null)
|
|
// return;
|
|
// if (bindPoint.TryGetBindPointOrDefault(bulletCfg.bornPoint, out var point))
|
|
// {
|
|
// pos = point.position;
|
|
// // dir = point.right;
|
|
// }
|
|
}
|
|
|
|
public static CombatEntity CreateBounceBullet(CombatEntity caster, GameAbilityContext middleGaCtx,
|
|
int newBulletId = 0)
|
|
{
|
|
var originEnt = middleGaCtx.ownerEnt;
|
|
if (originEnt.hasBullet == false)
|
|
{
|
|
XLog.LogDebug("CreateBounceBullet originEnt is not a bullet");
|
|
return null;
|
|
}
|
|
|
|
var originBullet = originEnt.bullet;
|
|
if (caster.IsValid() == false)
|
|
return null;
|
|
if (newBulletId == 0)
|
|
newBulletId = originBullet.bulletCfgId;
|
|
var tbBullet = BulletDescMgr.Instance.GetConfig(newBulletId);
|
|
// 释放位置外部已经选好了,必须有
|
|
var targetPos = TargetSelectSrv.GetCastTargetPos(middleGaCtx);
|
|
var bullet = Contexts.Combat.CreateEntity();
|
|
|
|
var casterProp = caster.property.container;
|
|
var level = middleGaCtx.level;
|
|
var gaInitCfg = middleGaCtx.abilitySpec.gaInitCfg;
|
|
var existTime = (float)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(tbBullet.duration, casterProp, level,
|
|
gaInitCfg, 3f);
|
|
var maxDistance = (float)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(tbBullet.maxDistance, casterProp,
|
|
level, gaInitCfg, 5f);
|
|
var scale = (float)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(tbBullet.scale, casterProp, level,
|
|
gaInitCfg, 1f);
|
|
var speed = (float)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(tbBullet.speed, casterProp, level,
|
|
gaInitCfg, 10f);
|
|
var paramCount = tbBullet.colliderParam.Length;
|
|
var colliderParam1 =
|
|
paramCount > 0 ? tbBullet.colliderParam[0] * BattleConst.TenThousandReverse * scale : 0f;
|
|
var colliderParam2 =
|
|
paramCount > 1 ? tbBullet.colliderParam[1] * BattleConst.TenThousandReverse * scale : 0f;
|
|
var collisionTimes = (int)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(tbBullet.collisionTimes, casterProp,
|
|
level, gaInitCfg, 1f);
|
|
var collisionInterval = (float)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(tbBullet.collisionInterval,
|
|
casterProp, level, gaInitCfg, 1f);
|
|
|
|
if (tbBullet.skill == 0 && tbBullet.endSkill == 0)
|
|
{
|
|
XLog.LogError($"{tbBullet.bulletID} 子弹配置不对,没有技能!!!!");
|
|
}
|
|
bullet.AddBullet(originBullet.casterEid, originBullet.elementType, originBullet.bulletFromType,
|
|
tbBullet.bulletID, existTime, maxDistance, scale, speed, tbBullet.colliderType, colliderParam1,
|
|
colliderParam2, tbBullet.collideWith, collisionTimes, collisionInterval, tbBullet.skill,
|
|
tbBullet.endSkill, tbBullet.isTriggerHitSkillOnEnd != 0, ListPool<HitData>.Pop());
|
|
bullet.AddGaCtxTransfer(middleGaCtx.abilitySpec.gaParams, middleGaCtx.abilitySpec.gaInitCfg,
|
|
middleGaCtx.level);
|
|
bullet.AddFaction(caster.faction.faction, SelectUseType.Bullet, caster.faction.opposite);
|
|
bullet.AddProperty();
|
|
caster.property.TaskSnapShot(bullet.property.container);
|
|
bullet.property.SetProperty(PropertyDef.BulletFlyDistanceMax, maxDistance, true);
|
|
|
|
var ignore = ListPool<Type>.Pop();
|
|
ignore.Add(typeof(Animator));
|
|
|
|
var prefabPath = GetBulletPrefabPathByElementType(originBullet.elementType, tbBullet);
|
|
bullet.AddAsset(new MainAssetParam
|
|
{
|
|
path = prefabPath,
|
|
parentNodeName = "RenderWorld",
|
|
scaleParam = scale
|
|
}, ignore);
|
|
bullet.AddAudio(bullet.creationIndex);
|
|
bullet.AddTransformProxy(Vector2.zero, Vector2.right, bullet);
|
|
|
|
|
|
if (tbBullet.shootType == ShootType.Direct)
|
|
{
|
|
AddDirectBullet(originEnt, bullet, targetPos, 0f, 0f);
|
|
}
|
|
else if (tbBullet.shootType == ShootType.Surround)
|
|
{
|
|
XLog.LogDebug("CreateBounceBullet surround bullet not supported");
|
|
return null;
|
|
}
|
|
else if (tbBullet.shootType == ShootType.Curve)
|
|
{
|
|
var randomCurvePerpendicularControl = (float)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(
|
|
tbBullet.moveParam1, casterProp, level, gaInitCfg, -1f);
|
|
var randomCurveParallelControl = (float)ExpressionEvaluator.CalcVal_WithPropAndGaCfg(
|
|
tbBullet.moveParam2, casterProp, level, gaInitCfg, -1f);
|
|
AddCurveBullet(originEnt, bullet, targetPos, 0f, 0f, tbBullet.warningPrefab,
|
|
tbBullet.warningScale * BattleConst.TenThousandReverse, randomCurvePerpendicularControl,
|
|
randomCurveParallelControl);
|
|
}
|
|
|
|
foreach (var filterEid in middleGaCtx.filterEids)
|
|
{
|
|
var hitData = SptPool<HitData>.Malloc();
|
|
hitData.Awake(filterEid, 0f, bullet.transformProxy.position,
|
|
bullet.transformProxy.direction);
|
|
bullet.bullet.hitDatas.Add(hitData);
|
|
}
|
|
|
|
return bullet;
|
|
}
|
|
|
|
public static bool CanCast(GameAbilityContext ctx, string canCastExpr, float defval = 1f)
|
|
{
|
|
if (string.IsNullOrEmpty(canCastExpr))
|
|
{
|
|
return true;
|
|
}
|
|
var casterEid = ctx.ownerEnt.creationIndex;
|
|
var ownerEnt = ctx.ownerEnt;
|
|
if (ownerEnt.IsValid() == false)
|
|
return false;
|
|
if (ownerEnt.hasBullet)
|
|
casterEid = ownerEnt.bullet.casterEid;
|
|
var caster = Contexts.Combat.GetEntity(casterEid);
|
|
if (caster.IsValid() == false)
|
|
return false;
|
|
var casterProp = caster.property.container;
|
|
var level = ctx.level;
|
|
var gaInitCfg = ctx.abilitySpec.gaInitCfg;
|
|
var castRate =
|
|
ExpressionEvaluator.CalcVal_WithPropAndGaCfg(canCastExpr, casterProp, level, gaInitCfg, defval);
|
|
if (RandomSrv.Range(0f, 1f) > castRate)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static void BulletSkillCast(CombatEntity bulletEnt, int targetEid, Fixed64Vector2 targetPos, int abilityId)
|
|
{
|
|
if (!bulletEnt.hasBullet || bulletEnt.isDestroyEnt)
|
|
return;
|
|
|
|
var bullet = bulletEnt.bullet;
|
|
var gaCtxTransfer = bulletEnt.gaCtxTransfer;
|
|
// 不给他不行,发射者死亡的话,子弹也要有伤害
|
|
var context = AbilitySrv.GrantTransferAbility(bulletEnt, abilityId, gaCtxTransfer.gaInitCfg, null,
|
|
gaCtxTransfer.level);
|
|
if (context == null)
|
|
{
|
|
XLog.LogDebug("AttachActiveAbility failed: " + abilityId);
|
|
return;
|
|
}
|
|
|
|
if (targetEid != 0)
|
|
{
|
|
var targetEnt = Contexts.Combat.GetEntity(targetEid);
|
|
// 子弹释放的目标, 具体作用对象由子弹技能的 catchTarget 来决定
|
|
if (targetEnt.isObstacle)
|
|
{
|
|
context.castPos.Add(bulletEnt.logicTransform.position);
|
|
}
|
|
else
|
|
{
|
|
context.castTarget.Add(targetEnt.creationIndex);
|
|
context.castPos.Add(targetEnt.logicTransform.position);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// context.castPos.Add(targetPos);
|
|
}
|
|
|
|
ref var gaParam = ref gaCtxTransfer.gaParams;
|
|
gaParam.SetParam1Int(targetEid);
|
|
|
|
BulletTryRegisterEndAbility(bullet, context);
|
|
context.dropAbilityWhenEnd = true; //TDRoot.Tables.Skill[abilityId].DropAbillity;
|
|
context.AddHitDataByRefs(bullet.hitDatas);
|
|
// XLog.LogDebug("bullet skill cast: " + abilityId + " " + context.abilitySpec.Ability.Name + " " + entity);
|
|
context.asc.TryActivateAbility_WithSeqAndParam(context.gaSeq, gaParam);
|
|
// 是否是枪械发出的子弹
|
|
int bulletFirstType = (int)bullet.bulletFromType & 0b11;
|
|
if (bulletFirstType == 1)
|
|
{
|
|
}
|
|
}
|
|
|
|
private static void BulletTryRegisterEndAbility(BulletComponent bullet, GameAbilityContext context)
|
|
{
|
|
if (bullet.hasInvalidated)
|
|
{
|
|
bullet.invalidatedCount++;
|
|
context.abilitySpec.RegisterEndAbility(DestroyInvalidBulletFromSpec);
|
|
}
|
|
}
|
|
}
|
|
}
|