192 lines
6.8 KiB
C#
192 lines
6.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using UnityEngine;
|
|
using BITKit;
|
|
using BITKit.Core.Entites;
|
|
using BITKit.Entities;
|
|
using Cysharp.Threading.Tasks;
|
|
using UnityEditor;
|
|
using UnityEngine.Animations;
|
|
using UnityEngine.UIElements;
|
|
|
|
namespace BITFALL
|
|
{
|
|
[Serializable]
|
|
public record InstanceBullet : SpawnBullet
|
|
{
|
|
public Vector3 currentPos;
|
|
public float currentSpeed = 64;
|
|
public BITBullet model;
|
|
}
|
|
public class BulletService : MonoBehaviour
|
|
{
|
|
public static Action<SpawnBullet> Spawn;
|
|
|
|
[Header(Constant.Header.Settings)]
|
|
public LayerMask layerMask;
|
|
|
|
[Header(Constant.Header.Providers)]
|
|
[SerializeField, SerializeReference, SubclassSelector]
|
|
private IEntitiesService entitiesService;
|
|
[SerializeField, SerializeReference, SubclassSelector]
|
|
private INetProvider netProvider;
|
|
[SerializeField, SerializeReference, SubclassSelector]
|
|
private IDamageService damageService;
|
|
|
|
[Header(Constant.Header.Settings)]
|
|
public UnityPool<BITBullet> pool = new();
|
|
|
|
[Header(Constant.Header.InternalVariables)]
|
|
public List<InstanceBullet> instances = new();
|
|
public string Log => _stringBuilder.ToString();
|
|
private readonly StringBuilder _stringBuilder = new();
|
|
private readonly RaycastHit[] _raycastHits = new RaycastHit[16];
|
|
private void Start()
|
|
{
|
|
Spawn += SpawnBullet;
|
|
}
|
|
private void OnDestroy()
|
|
{
|
|
Spawn -= SpawnBullet;
|
|
}
|
|
private void FixedUpdate()
|
|
{
|
|
instances ??= new List<InstanceBullet>();
|
|
foreach (var bullet in instances.ToArray())
|
|
{
|
|
var size = Physics.RaycastNonAlloc(bullet.currentPos, bullet.forward, _raycastHits, bullet.currentSpeed * Time.fixedDeltaTime, layerMask);
|
|
var validHit = false;
|
|
foreach (var raycastHit in _raycastHits.Take(size).OrderBy(x => Vector3.Distance(bullet.pos, x.point)))
|
|
{
|
|
if (!IsValidHit(raycastHit, bullet))
|
|
continue;
|
|
validHit = true;
|
|
break;
|
|
}
|
|
|
|
if (validHit ||bullet.currentSpeed <= 0)
|
|
{
|
|
instances.TryRemove(bullet);
|
|
pool.Return(bullet.model);
|
|
}
|
|
else
|
|
{
|
|
bullet.currentSpeed -= bullet.startSpeed * Time.fixedDeltaTime;
|
|
bullet.currentPos += (Vector3)bullet.forward * (bullet.currentSpeed * Time.fixedDeltaTime);
|
|
bullet.model.transform.position = bullet.currentPos;
|
|
}
|
|
}
|
|
}
|
|
private async void RpcSpawnBullet(SpawnBullet x)
|
|
{
|
|
await UniTask.SwitchToMainThread();
|
|
var instance = pool.Get();
|
|
InstanceBullet bullet = new()
|
|
{
|
|
initiator = x.initiator,
|
|
currentPos = x.pos,
|
|
pos = x.pos,
|
|
rot = x.rot,
|
|
forward = x.forward,
|
|
initialDamage = x.initialDamage,
|
|
model = instance
|
|
};
|
|
var instanceTransform = instance.transform;
|
|
instanceTransform.SetPositionAndRotation(x.pos, x.rot);
|
|
instanceTransform.forward = x.forward;
|
|
instances.Add(bullet);
|
|
}
|
|
private void SpawnBullet(SpawnBullet x)
|
|
{
|
|
RpcSpawnBullet(x);
|
|
}
|
|
|
|
private bool IsValidHit(RaycastHit raycastHit,InstanceBullet bullet)
|
|
{
|
|
if(layerMask.Includes(raycastHit.collider.gameObject.layer) is false) return false;
|
|
raycastHit.collider.TryGetComponentAny<IPhysicsInfo>(out var physicsInfo);
|
|
var force = (raycastHit.point - (Vector3)bullet.pos).normalized * (physicsInfo?.AddForceMultiple ?? 64);
|
|
if (raycastHit.collider.TryGetComponent<IDamagable>(out var damagable))
|
|
{
|
|
if(damagable.Entity.Id == bullet.initiator) return false;
|
|
if (layerMask.Includes(raycastHit.collider.gameObject.layer) is false) return false;
|
|
var msg = new DamageMessage()
|
|
{
|
|
target = damagable.Entity,
|
|
hit = damagable,
|
|
damage = bullet.initialDamage,
|
|
};
|
|
damageService.Execute(msg);
|
|
|
|
if (damagable.Rigidbody is not null)
|
|
damagable.Rigidbody.AddForceAtPositionAsync(force, raycastHit.point, ForceMode.Impulse);
|
|
}
|
|
else
|
|
{
|
|
if (raycastHit.rigidbody is not null)
|
|
raycastHit.rigidbody.AddForceAtPositionAsync(force, raycastHit.point, ForceMode.Impulse);
|
|
}
|
|
|
|
_stringBuilder.AppendLine(
|
|
$"{bullet.initiator}击中了:{raycastHit.collider.name},Layer:{LayerMask.LayerToName(raycastHit.collider.gameObject.layer)}"
|
|
);
|
|
|
|
|
|
|
|
List<string> tags = new()
|
|
{
|
|
"BulletHit",
|
|
};
|
|
if (raycastHit.transform.TryGetComponent<ITag>(out var _tag))
|
|
{
|
|
tags.AddRange(_tag.GetTags());
|
|
}
|
|
|
|
Location location = new()
|
|
{
|
|
position = raycastHit.point,
|
|
forward = raycastHit.normal,
|
|
};
|
|
var vfx = DI.Get<VFXService>().Spawn(location, tags.ToArray());
|
|
var constraint = vfx.gameObject.AddComponent<ParentConstraint>();
|
|
var sourceTransform = raycastHit.transform;
|
|
constraint.AddSource(new ConstraintSource()
|
|
{
|
|
sourceTransform = sourceTransform,
|
|
weight = 1,
|
|
});
|
|
|
|
var positionOffset = sourceTransform.InverseTransformPoint(raycastHit.point);
|
|
var rotationOffset = Quaternion.Inverse(sourceTransform.rotation) * transform.rotation;
|
|
|
|
constraint.SetTranslationOffset(0, positionOffset);
|
|
constraint.SetRotationOffset(0, rotationOffset.eulerAngles);
|
|
|
|
constraint.weight = 1;
|
|
constraint.constraintActive = true;
|
|
return true;
|
|
}
|
|
}
|
|
#if UNITY_EDITOR
|
|
[CustomEditor(typeof(BulletService))]
|
|
public class BulletServiceInspector:BITInspector<BulletService>
|
|
{
|
|
private Label logLabel;
|
|
public override VisualElement CreateInspectorGUI()
|
|
{
|
|
FillDefaultInspector();
|
|
logLabel = root.Create<Label>();
|
|
return root;
|
|
}
|
|
|
|
protected override void OnUpdate()
|
|
{
|
|
if (logLabel is null) return;
|
|
logLabel.text = agent.Log;
|
|
}
|
|
}
|
|
#endif
|
|
}
|