您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
170 行
5.1 KiB
170 行
5.1 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using Primitives;
|
|
using Unity.Mathematics;
|
|
using UnityEngine;
|
|
using Unity.Entities;
|
|
|
|
[Serializable]
|
|
public struct SplashDamageSettings
|
|
{
|
|
public float radius;
|
|
public float falloffStartRadius;
|
|
public float damage;
|
|
public float minDamage;
|
|
public float impulse;
|
|
public float minImpulse;
|
|
public float ownerDamageFraction;
|
|
}
|
|
|
|
public struct SplashDamageRequest: IComponentData
|
|
{
|
|
public Entity instigator;
|
|
public int tick;
|
|
public float3 center;
|
|
public int collisionMask;
|
|
public SplashDamageSettings settings;
|
|
|
|
public static void Create(EntityCommandBuffer commandBuffer, int tick, Entity instigator, float3 center,
|
|
int collisionMask, SplashDamageSettings settings)
|
|
{
|
|
var request = new SplashDamageRequest
|
|
{
|
|
instigator = instigator,
|
|
tick = tick,
|
|
center = center,
|
|
collisionMask = collisionMask,
|
|
settings = settings
|
|
};
|
|
commandBuffer.CreateEntity();
|
|
commandBuffer.AddComponent(request);
|
|
}
|
|
}
|
|
|
|
[DisableAutoCreation]
|
|
public class HandleSplashDamageRequests : BaseComponentSystem
|
|
{
|
|
struct Requests
|
|
{
|
|
public EntityArray entities;
|
|
public ComponentDataArray<SplashDamageRequest> requests;
|
|
}
|
|
|
|
struct HitColliders
|
|
{
|
|
public ComponentArray<HitCollisionHistory> hitCollisionArray;
|
|
}
|
|
|
|
[Inject]
|
|
Requests RequestGroup;
|
|
|
|
[Inject]
|
|
HitColliders ColliderGroup;
|
|
|
|
public HandleSplashDamageRequests(GameWorld world) : base(world)
|
|
{
|
|
m_hitCollisionLayer = LayerMask.NameToLayer("hitcollision_enabled");
|
|
}
|
|
|
|
protected override void OnUpdate()
|
|
{
|
|
for (var i = 0; i < RequestGroup.requests.Length; i++)
|
|
{
|
|
var request = RequestGroup.requests[i];
|
|
|
|
var forceIncluded = request.settings.ownerDamageFraction > 0 ? request.instigator : Entity.Null;
|
|
HitCollisionHistory.PrepareColliders(ref ColliderGroup.hitCollisionArray, request.tick, request.collisionMask,
|
|
Entity.Null, forceIncluded, primlib.sphere(request.center, request.settings.radius));
|
|
|
|
var hitColliderMask = 1 << m_hitCollisionLayer;
|
|
var count = Physics.OverlapSphereNonAlloc(request.center, request.settings.radius, g_colliderBuffer, hitColliderMask);
|
|
|
|
|
|
var colliderCollections = new Dictionary<HitCollisionOwner, ClosestCollision>();
|
|
GetClosestCollision(g_colliderBuffer, count, request.center, colliderCollections);
|
|
|
|
foreach (var collision in colliderCollections.Values)
|
|
{
|
|
var collisionOwner = collision.hitCollision.owner;
|
|
|
|
var ownerGameObjectEntity = collisionOwner.GetComponent<GameObjectEntity>();
|
|
var ownerEntity = ownerGameObjectEntity != null ? ownerGameObjectEntity.Entity : Entity.Null;
|
|
|
|
var centerOfMass = collisionOwner.transform.position + Vector3.up * 1.2f; // TODO dont hardcode COM
|
|
|
|
// Calc damage
|
|
var damageVector = centerOfMass - (Vector3)request.center;
|
|
var damageDirection = damageVector.normalized;
|
|
var distance = damageVector.magnitude;
|
|
if (distance > request.settings.radius)
|
|
continue;
|
|
|
|
var damage = request.settings.damage;
|
|
var impulse = request.settings.impulse;
|
|
if (distance > request.settings.falloffStartRadius)
|
|
{
|
|
var falloffFraction = (distance - request.settings.falloffStartRadius) / (request.settings.radius - request.settings.falloffStartRadius);
|
|
damage -= (request.settings.damage - request.settings.minDamage) * falloffFraction;
|
|
impulse -= (request.settings.impulse - request.settings.minImpulse) * falloffFraction;
|
|
}
|
|
|
|
if (request.instigator != Entity.Null && request.instigator == ownerEntity)
|
|
damage = damage * request.settings.ownerDamageFraction;
|
|
|
|
//GameDebug.Log(string.Format("SplashDamage. Target:{0} Inst:{1}", collider.hitCollision, m_world.GetGameObjectFromEntity(instigator) ));
|
|
collisionOwner.damageEvents.Add(new DamageEvent(request.instigator, damage, damageDirection, impulse));
|
|
}
|
|
|
|
|
|
PostUpdateCommands.DestroyEntity(RequestGroup.entities[i]);
|
|
}
|
|
}
|
|
|
|
public struct ClosestCollision
|
|
{
|
|
public HitCollision hitCollision;
|
|
public Vector3 closestPoint;
|
|
public float dist;
|
|
}
|
|
|
|
public static void GetClosestCollision(Collider[] colliders, int colliderCount, Vector3 origin, Dictionary<HitCollisionOwner, ClosestCollision> colliderOwners)
|
|
{
|
|
for (int i = 0; i < colliderCount; i++)
|
|
{
|
|
var collider = colliders[i];
|
|
|
|
var hitCollision = collider.GetComponent<HitCollision>();
|
|
if (hitCollision == null)
|
|
{
|
|
GameDebug.LogError("Collider:" + collider + " has no hitcollision");
|
|
continue;
|
|
}
|
|
|
|
var closestPoint = collider.transform.position;
|
|
float dist = Vector3.Distance(origin, closestPoint);
|
|
|
|
ClosestCollision currentClosest;
|
|
if (colliderOwners.TryGetValue(hitCollision.owner, out currentClosest))
|
|
{
|
|
if (dist < currentClosest.dist)
|
|
{
|
|
currentClosest.hitCollision = hitCollision;
|
|
currentClosest.closestPoint = closestPoint;
|
|
currentClosest.dist = dist;
|
|
colliderOwners[hitCollision.owner] = currentClosest;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
currentClosest.hitCollision = hitCollision;
|
|
currentClosest.closestPoint = closestPoint;
|
|
currentClosest.dist = dist;
|
|
colliderOwners.Add(hitCollision.owner, currentClosest);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private readonly Collider[] g_colliderBuffer = new Collider[128];
|
|
readonly int m_hitCollisionLayer;
|
|
}
|