2023-06-08 14:09:50 +08:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
2023-08-12 01:43:24 +08:00
|
|
|
using System.Linq;
|
|
|
|
using System.Text;
|
2023-10-20 19:31:12 +08:00
|
|
|
using BITFALL.Bullet;
|
2023-06-08 14:09:50 +08:00
|
|
|
using UnityEngine;
|
|
|
|
using BITKit;
|
|
|
|
using BITKit.Entities;
|
|
|
|
using Cysharp.Threading.Tasks;
|
2023-11-15 23:54:54 +08:00
|
|
|
using Unity.Mathematics;
|
2023-08-12 01:43:24 +08:00
|
|
|
using UnityEditor;
|
2023-06-08 14:09:50 +08:00
|
|
|
using UnityEngine.Animations;
|
2023-12-26 20:07:19 +08:00
|
|
|
using UnityEngine.Pool;
|
2023-08-12 01:43:24 +08:00
|
|
|
using UnityEngine.UIElements;
|
|
|
|
|
2023-06-08 14:09:50 +08:00
|
|
|
namespace BITFALL
|
|
|
|
{
|
2023-08-12 01:43:24 +08:00
|
|
|
[Serializable]
|
2023-06-08 14:09:50 +08:00
|
|
|
public record InstanceBullet : SpawnBullet
|
|
|
|
{
|
2023-11-15 23:54:54 +08:00
|
|
|
public Vector3 GraphicsPosition;
|
2023-11-02 20:58:55 +08:00
|
|
|
public Vector3 Velocity;
|
2023-11-15 23:54:54 +08:00
|
|
|
public Vector3 CurrentPos;
|
|
|
|
public float CurrentSpeed = 64;
|
2023-10-29 15:27:13 +08:00
|
|
|
public float ElapsedTime;
|
2023-06-08 14:09:50 +08:00
|
|
|
}
|
2023-10-20 19:31:12 +08:00
|
|
|
[Serializable]
|
|
|
|
public class BulletServiceSingleton : IBulletService
|
|
|
|
{
|
|
|
|
public void Spawn(SpawnBullet bullet)=>BulletService.Spawn?.Invoke(bullet);
|
|
|
|
}
|
|
|
|
public class BulletService : MonoBehaviour, IBulletService
|
2023-06-08 14:09:50 +08:00
|
|
|
{
|
|
|
|
public static Action<SpawnBullet> Spawn;
|
2023-12-15 00:08:02 +08:00
|
|
|
private static readonly List<uint> Tokens = new();
|
2023-08-12 01:43:24 +08:00
|
|
|
|
2023-06-08 14:09:50 +08:00
|
|
|
[Header(Constant.Header.Settings)]
|
2023-11-02 20:58:55 +08:00
|
|
|
[SerializeField] private LayerMask layerMask;
|
|
|
|
[SerializeField] private Material material;
|
2023-11-15 23:54:54 +08:00
|
|
|
[SerializeField] private Optional<AnimationCurve> bulletScaleCurve;
|
|
|
|
|
|
|
|
[Header(Constant.Header.Prefabs)]
|
|
|
|
[SerializeField] private Mesh rectangleMesh;
|
|
|
|
[SerializeField] private Mesh quadMesh;
|
2023-06-17 16:30:53 +08:00
|
|
|
|
|
|
|
[Header(Constant.Header.Providers)]
|
2023-12-15 00:08:02 +08:00
|
|
|
[SerializeReference, SubclassSelector] private IEntitiesService entitiesService;
|
|
|
|
[SerializeReference, SubclassSelector] private INetClient netClient;
|
|
|
|
[SerializeReference, SubclassSelector] private INetServer netServer;
|
|
|
|
[SerializeReference, SubclassSelector] private IDamageService damageService;
|
2023-08-12 01:43:24 +08:00
|
|
|
|
2023-06-08 14:09:50 +08:00
|
|
|
[Header(Constant.Header.InternalVariables)]
|
2023-10-24 23:37:59 +08:00
|
|
|
private readonly List<InstanceBullet> instances = new();
|
2023-08-12 01:43:24 +08:00
|
|
|
private readonly RaycastHit[] _raycastHits = new RaycastHit[16];
|
2023-12-15 00:08:02 +08:00
|
|
|
|
2023-11-02 20:58:55 +08:00
|
|
|
|
2023-11-15 23:54:54 +08:00
|
|
|
private readonly Queue<(Vector3 Position,Vector3 Forward,Quaternion StartRotation,float ElaspedTime,Vector3 StartPosition)> DrawQueue=new();
|
|
|
|
|
|
|
|
private readonly Queue<InstanceBullet> _newBulletQueue = new();
|
|
|
|
|
|
|
|
private readonly Queue<InstanceBullet> _removeBulletQueue = new();
|
2023-11-02 20:58:55 +08:00
|
|
|
|
2023-12-15 00:08:02 +08:00
|
|
|
private INetProvider clientNetProvider => netClient.Source as INetProvider;
|
|
|
|
private INetProvider serverNetProvider => netServer.Source as INetProvider;
|
|
|
|
|
2023-11-30 00:23:23 +08:00
|
|
|
private new Camera camera=>_camera ? _camera : _camera=Camera.main;
|
|
|
|
private Camera _camera;
|
2023-08-12 01:43:24 +08:00
|
|
|
private void Start()
|
2023-06-08 14:09:50 +08:00
|
|
|
{
|
|
|
|
Spawn += SpawnBullet;
|
2023-12-15 00:08:02 +08:00
|
|
|
|
|
|
|
serverNetProvider.AddCommandListener<SpawnBullet>(RpcSpawnBullet);
|
|
|
|
clientNetProvider.AddCommandListener<SpawnBullet>(RpcSpawnBullet);
|
|
|
|
|
|
|
|
destroyCancellationToken.Register(() =>
|
|
|
|
{
|
|
|
|
Spawn -= SpawnBullet;
|
|
|
|
});
|
2023-06-08 14:09:50 +08:00
|
|
|
}
|
2023-11-02 20:58:55 +08:00
|
|
|
private void Update()
|
|
|
|
{
|
|
|
|
if (!camera) return;
|
2023-11-30 00:23:23 +08:00
|
|
|
var cameraTransform = _camera.transform;
|
2023-11-15 23:54:54 +08:00
|
|
|
//var rot = camera.transform.rotation * Quaternion.Euler(0, 180, 0);
|
2023-11-02 20:58:55 +08:00
|
|
|
foreach (var bullet in instances.ToArray())
|
|
|
|
{
|
2023-11-15 23:54:54 +08:00
|
|
|
if (bullet.ElapsedTime < 0.04f) continue;
|
|
|
|
|
|
|
|
bullet.GraphicsPosition =
|
|
|
|
Vector3.MoveTowards(bullet.GraphicsPosition, bullet.CurrentPos, bullet.StartSpeed*Time.deltaTime);
|
|
|
|
|
|
|
|
DrawQueue.Enqueue((bullet.GraphicsPosition,bullet.Forward,bullet.Rotation,bullet.ElapsedTime,bullet.Position));
|
|
|
|
}
|
|
|
|
|
|
|
|
while (DrawQueue.TryDequeue(out var queue))
|
|
|
|
{
|
2023-11-30 00:23:23 +08:00
|
|
|
var rot =
|
|
|
|
// 获取目标方向
|
|
|
|
queue.StartRotation;
|
2023-11-15 23:54:54 +08:00
|
|
|
|
|
|
|
var mesh = rectangleMesh;
|
|
|
|
|
|
|
|
//if (MathV.InFovRange(cameraTransform.position, cameraTransform.forward, bullet.CurrentPos,8))
|
|
|
|
if (Vector3.Angle(cameraTransform.forward, queue.Forward) < 8)
|
2023-11-02 20:58:55 +08:00
|
|
|
{
|
2023-11-15 23:54:54 +08:00
|
|
|
if (Vector3.Distance(queue.StartPosition, queue.Position) < 3.2f)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
mesh = quadMesh;
|
|
|
|
rot = cameraTransform.rotation * Quaternion.Euler(0, 180, 0);
|
2023-11-02 20:58:55 +08:00
|
|
|
}
|
2023-11-15 23:54:54 +08:00
|
|
|
var matrix = Matrix4x4.TRS(
|
|
|
|
queue.Position,
|
|
|
|
rot,
|
|
|
|
Vector3.one *
|
|
|
|
Mathf.Lerp(
|
|
|
|
0,1,Vector3.Distance(queue.StartPosition,queue.Position)
|
|
|
|
)
|
|
|
|
+ Vector3.one *
|
|
|
|
(bulletScaleCurve.Allow ? bulletScaleCurve.Value.Evaluate(queue.ElaspedTime) : 0)
|
|
|
|
);
|
|
|
|
Graphics.DrawMesh(mesh, matrix, material,
|
|
|
|
LayerMask.NameToLayer("TransparentFX"));
|
2023-11-02 20:58:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-12 01:43:24 +08:00
|
|
|
private void FixedUpdate()
|
2023-06-08 14:09:50 +08:00
|
|
|
{
|
2023-11-15 23:54:54 +08:00
|
|
|
foreach (var bullet in instances)
|
2023-06-08 14:09:50 +08:00
|
|
|
{
|
2023-11-15 23:54:54 +08:00
|
|
|
if (destroyCancellationToken.IsCancellationRequested) return;
|
|
|
|
var size = Physics.RaycastNonAlloc(bullet.CurrentPos, bullet.Velocity, _raycastHits, Vector3.Distance(default,bullet.Velocity) * Time.fixedDeltaTime, layerMask);
|
2023-08-12 01:43:24 +08:00
|
|
|
var validHit = false;
|
2023-11-15 23:54:54 +08:00
|
|
|
RaycastHit hit=default;
|
|
|
|
foreach (var raycastHit in _raycastHits.Take(size).OrderBy(x => Vector3.Distance(bullet.Position, x.point)))
|
2023-06-08 14:09:50 +08:00
|
|
|
{
|
2023-12-26 20:07:19 +08:00
|
|
|
if (!IsReleaseHit(raycastHit, bullet))
|
2023-08-12 01:43:24 +08:00
|
|
|
continue;
|
|
|
|
validHit = true;
|
|
|
|
break;
|
2023-06-08 14:09:50 +08:00
|
|
|
}
|
2023-08-12 01:43:24 +08:00
|
|
|
|
2023-11-15 23:54:54 +08:00
|
|
|
if (validHit || bullet.CurrentSpeed <= 0 || bullet.Velocity.sqrMagnitude <= 0.01f ||
|
|
|
|
bullet.ElapsedTime >= 8)
|
2023-06-08 14:09:50 +08:00
|
|
|
{
|
2023-11-15 23:54:54 +08:00
|
|
|
_removeBulletQueue.Enqueue(bullet);
|
|
|
|
|
|
|
|
if (validHit)
|
|
|
|
{
|
|
|
|
DrawQueue.Enqueue((hit.point - bullet.Velocity.normalized * 0.5f, bullet.Forward, bullet.Rotation,
|
|
|
|
bullet.ElapsedTime,bullet.Position));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DrawQueue.Enqueue((bullet.CurrentPos + bullet.Velocity * 0.5f, bullet.Forward, bullet.Rotation,
|
|
|
|
bullet.ElapsedTime,bullet.Position));
|
|
|
|
}
|
2023-06-08 14:09:50 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-11-02 20:58:55 +08:00
|
|
|
bullet.ElapsedTime+=Time.fixedDeltaTime;
|
|
|
|
|
|
|
|
bullet.Velocity+= Physics.gravity * (Time.fixedDeltaTime * bullet.ElapsedTime);
|
|
|
|
|
|
|
|
|
|
|
|
var newVelocity =bullet.Velocity * Time.fixedDeltaTime;
|
|
|
|
|
2023-11-15 23:54:54 +08:00
|
|
|
bullet.CurrentPos+=newVelocity;
|
2023-11-02 20:58:55 +08:00
|
|
|
|
2023-06-08 14:09:50 +08:00
|
|
|
}
|
|
|
|
}
|
2023-11-15 23:54:54 +08:00
|
|
|
|
|
|
|
while (_removeBulletQueue.TryDequeue(out var removeBullet))
|
|
|
|
{
|
|
|
|
instances.Remove(removeBullet);
|
|
|
|
}
|
|
|
|
while (_newBulletQueue.TryDequeue(out var newBullet))
|
|
|
|
{
|
|
|
|
instances.Add(newBullet);
|
|
|
|
}
|
2023-06-08 14:09:50 +08:00
|
|
|
}
|
2023-08-12 01:43:24 +08:00
|
|
|
private async void RpcSpawnBullet(SpawnBullet x)
|
2023-06-08 14:09:50 +08:00
|
|
|
{
|
2023-12-15 00:08:02 +08:00
|
|
|
if (x.Token is not 0)
|
|
|
|
{
|
|
|
|
if (Tokens.Contains(x.Token))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Tokens.Add(x.Token);
|
|
|
|
}
|
2023-06-08 14:09:50 +08:00
|
|
|
await UniTask.SwitchToMainThread();
|
|
|
|
InstanceBullet bullet = new()
|
|
|
|
{
|
2023-12-15 00:08:02 +08:00
|
|
|
Token = x.Token,
|
2023-11-15 23:54:54 +08:00
|
|
|
Initiator = x.Initiator,
|
|
|
|
CurrentPos = x.Position,
|
|
|
|
StartSpeed = x.StartSpeed,
|
|
|
|
Position = x.Position,
|
|
|
|
GraphicsPosition=x.Position,
|
|
|
|
Rotation = x.Rotation,
|
|
|
|
Forward = x.Forward,
|
|
|
|
InitialDamage = x.InitialDamage,
|
2023-10-24 23:37:59 +08:00
|
|
|
InitialForce = x.InitialForce,
|
2023-11-15 23:54:54 +08:00
|
|
|
Velocity =x.Forward * x.StartSpeed,
|
2023-06-08 14:09:50 +08:00
|
|
|
};
|
2023-12-15 00:08:02 +08:00
|
|
|
|
2023-11-15 23:54:54 +08:00
|
|
|
_newBulletQueue.Enqueue(bullet);
|
2023-06-08 14:09:50 +08:00
|
|
|
}
|
2023-12-15 00:08:02 +08:00
|
|
|
|
2023-08-12 01:43:24 +08:00
|
|
|
private void SpawnBullet(SpawnBullet x)
|
|
|
|
{
|
|
|
|
RpcSpawnBullet(x);
|
2023-12-15 00:08:02 +08:00
|
|
|
if (netClient.IsConnected)
|
|
|
|
{
|
|
|
|
clientNetProvider.ServerCommand(x);
|
|
|
|
clientNetProvider.AllClientCommand(x);
|
|
|
|
}
|
|
|
|
else if(netServer.IsRunningServer)
|
|
|
|
{
|
|
|
|
serverNetProvider.AllClientCommand(x);
|
|
|
|
}
|
2023-08-12 01:43:24 +08:00
|
|
|
}
|
2023-12-26 20:07:19 +08:00
|
|
|
private bool IsReleaseHit(RaycastHit raycastHit, InstanceBullet bullet)
|
2023-08-12 01:43:24 +08:00
|
|
|
{
|
2023-08-27 02:58:19 +08:00
|
|
|
if (layerMask.Includes(raycastHit.collider.gameObject.layer) is false) return false;
|
2023-08-12 01:43:24 +08:00
|
|
|
raycastHit.collider.TryGetComponentAny<IPhysicsInfo>(out var physicsInfo);
|
2023-12-26 20:07:19 +08:00
|
|
|
|
|
|
|
var returnTure = true;
|
|
|
|
|
2023-11-15 23:54:54 +08:00
|
|
|
var force = (raycastHit.point - (Vector3)bullet.Position).normalized * (physicsInfo?.AddForceMultiple ?? 64);
|
2023-11-30 00:23:23 +08:00
|
|
|
if (raycastHit.collider.TryGetComponent<IDamagable>(out var damageComponent))
|
2023-08-12 01:43:24 +08:00
|
|
|
{
|
2023-11-30 00:23:23 +08:00
|
|
|
if (damageComponent.UnityEntity?.Id == bullet.Initiator) return false;
|
2023-08-12 01:43:24 +08:00
|
|
|
if (layerMask.Includes(raycastHit.collider.gameObject.layer) is false) return false;
|
2023-12-15 00:08:02 +08:00
|
|
|
entitiesService.TryGetEntity(bullet.Initiator, out var initiator);
|
2023-12-26 20:07:19 +08:00
|
|
|
|
|
|
|
if (damageComponent.Health is { HealthPoint: < 0 })
|
|
|
|
{
|
|
|
|
returnTure = false;
|
|
|
|
}
|
|
|
|
|
2023-08-12 01:43:24 +08:00
|
|
|
var msg = new DamageMessage()
|
|
|
|
{
|
2023-12-15 00:08:02 +08:00
|
|
|
Initiator =initiator as Entity,
|
2023-11-30 00:23:23 +08:00
|
|
|
Target = damageComponent.UnityEntity,
|
|
|
|
Hit = damageComponent,
|
2023-11-15 23:54:54 +08:00
|
|
|
Damage = bullet.InitialDamage,
|
2023-12-30 17:37:48 +08:00
|
|
|
DamageType = new BulletDamageMessage(),
|
2023-11-30 00:23:23 +08:00
|
|
|
Position = bullet.Position,
|
2023-12-26 20:07:19 +08:00
|
|
|
Rotation = Quaternion.LookRotation(raycastHit.normal),
|
|
|
|
RaycastHit =raycastHit,
|
2023-08-12 01:43:24 +08:00
|
|
|
};
|
2023-12-15 00:08:02 +08:00
|
|
|
if (netClient.IsConnected)
|
2023-10-30 01:25:53 +08:00
|
|
|
{
|
2023-12-15 00:08:02 +08:00
|
|
|
|
2023-10-30 01:25:53 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-12-15 00:08:02 +08:00
|
|
|
if (damageComponent is IEntityComponent)
|
|
|
|
{
|
|
|
|
damageService.Execute(msg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
damageComponent.GiveDamage(msg);
|
|
|
|
}
|
2023-10-30 01:25:53 +08:00
|
|
|
}
|
2023-08-12 01:43:24 +08:00
|
|
|
}
|
2023-08-27 02:58:19 +08:00
|
|
|
|
2023-11-30 00:23:23 +08:00
|
|
|
var _rigidbody = (raycastHit.rigidbody,damageComponent?.Rigidbody) switch
|
2023-08-12 01:43:24 +08:00
|
|
|
{
|
2023-10-24 23:37:59 +08:00
|
|
|
(null, null) => null,
|
2023-11-30 00:23:23 +08:00
|
|
|
(null, not null) => damageComponent?.Rigidbody,
|
2023-10-24 23:37:59 +08:00
|
|
|
(not null, null) => raycastHit.rigidbody,
|
2023-11-30 00:23:23 +08:00
|
|
|
(not null, not null) => damageComponent?.Rigidbody,
|
2023-10-24 23:37:59 +08:00
|
|
|
};
|
2023-11-15 23:54:54 +08:00
|
|
|
if (_rigidbody && _rigidbody.gameObject.layer is not 0)
|
2023-10-24 23:37:59 +08:00
|
|
|
{
|
|
|
|
_rigidbody.AddForceAtPositionAsync(force, raycastHit.point, ForceMode.Impulse).Forget();
|
2023-08-12 01:43:24 +08:00
|
|
|
}
|
2023-08-27 02:58:19 +08:00
|
|
|
|
2023-08-12 01:43:24 +08:00
|
|
|
|
2023-12-26 20:07:19 +08:00
|
|
|
// List<string> tags = new()
|
|
|
|
// {
|
|
|
|
// "BulletHit",
|
|
|
|
// };
|
|
|
|
var tags = ListPool<string>.Get();
|
|
|
|
tags.Add("BulletHit");
|
|
|
|
|
2023-11-02 20:58:55 +08:00
|
|
|
if (raycastHit.collider.TryGetComponent<ITag>(out var _tag))
|
2023-08-12 01:43:24 +08:00
|
|
|
{
|
|
|
|
tags.AddRange(_tag.GetTags());
|
|
|
|
}
|
|
|
|
|
|
|
|
Location location = new()
|
|
|
|
{
|
|
|
|
position = raycastHit.point,
|
2023-11-15 23:54:54 +08:00
|
|
|
forward = tags.Contains("IgnoreRotation") ? bullet.Forward : Quaternion.LookRotation(raycastHit.normal) * Vector3.forward,
|
2023-08-12 01:43:24 +08:00
|
|
|
};
|
|
|
|
var vfx = DI.Get<VFXService>().Spawn(location, tags.ToArray());
|
2023-11-15 23:54:54 +08:00
|
|
|
if (_rigidbody is not null && tags.Contains("Fixed") is false)
|
2023-10-29 15:27:13 +08:00
|
|
|
{
|
2023-11-15 23:54:54 +08:00
|
|
|
vfx.SetParentConstraint(_rigidbody.transform);
|
2023-10-29 15:27:13 +08:00
|
|
|
}
|
2023-11-15 23:54:54 +08:00
|
|
|
else
|
2023-08-12 01:43:24 +08:00
|
|
|
{
|
2023-11-15 23:54:54 +08:00
|
|
|
vfx.gameObject.RemoveComponent<ParentConstraint>();
|
|
|
|
}
|
2023-08-12 01:43:24 +08:00
|
|
|
|
2023-12-26 20:07:19 +08:00
|
|
|
tags.Clear();
|
|
|
|
ListPool<string>.Release(tags);
|
|
|
|
return returnTure;
|
2023-08-12 01:43:24 +08:00
|
|
|
}
|
2023-10-20 19:31:12 +08:00
|
|
|
|
|
|
|
void IBulletService.Spawn(SpawnBullet bullet) => SpawnBullet(bullet);
|
2023-11-02 20:58:55 +08:00
|
|
|
|
|
|
|
|
2023-08-12 01:43:24 +08:00
|
|
|
}
|
2023-06-08 14:09:50 +08:00
|
|
|
}
|