vampire-like/Assets/GameMain/Scripts/Simulation/SimulationWorld.Presentatio...

233 lines
8.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using CustomEvent;
using Entity;
using Entity.EntityData;
using Entity.Weapon;
using GameFramework.Event;
using UnityEngine;
namespace Simulation
{
public partial class SimulationWorld
{
[Header("投射物命中表现")] [Tooltip("是否监听投射物命中表现事件。")] [SerializeField]
private bool _projectileHitPresentationEnabled = true;
[Tooltip("是否播放投射物命中标记。")] [SerializeField]
private bool _projectileHitMarkerEnabled = true;
[Tooltip("命中标记尺寸。")] [SerializeField]
private float _projectileHitMarkerSize = 0.2f;
[Tooltip("命中标记在目标上的高度偏移。")] [SerializeField]
private float _projectileHitMarkerYOffset = 1.2f;
[Tooltip("命中标记持续时间。")] [SerializeField]
private float _projectileHitMarkerDuration = 0.15f;
[Tooltip("命中标记颜色。")] [SerializeField]
private Color _projectileHitMarkerColor = new(1f, 0f, 0f, 0.95f);
[Tooltip("是否播放投射物命中特效实体。")] [SerializeField]
private bool _projectileHitEffectEnabled;
[Tooltip("投射物命中特效实体类型 Id<=0 表示不启用)。")] [SerializeField]
private int _projectileHitEffectTypeId;
private sealed class Presentation
{
private readonly SimulationWorld _world;
private HandgunHitMarkerAttackEffect _projectileHitMarkerEffect;
private bool _isProjectileHitEventSubscribed;
public Presentation(SimulationWorld world)
{
_world = world;
}
public void OnStart()
{
if (_world == null || !_world._projectileHitPresentationEnabled)
{
return;
}
var eventComponent = GameEntry.Event;
if (eventComponent == null)
{
return;
}
eventComponent.Subscribe(ProjectileHitPresentationEventArgs.EventId, OnProjectileHitPresentationEvent);
_isProjectileHitEventSubscribed = true;
}
public void OnDestroy()
{
if (!_isProjectileHitEventSubscribed)
{
return;
}
var eventComponent = GameEntry.Event;
if (eventComponent != null)
{
eventComponent.Unsubscribe(ProjectileHitPresentationEventArgs.EventId,
OnProjectileHitPresentationEvent);
}
_isProjectileHitEventSubscribed = false;
}
public void OnLateUpdate()
{
if (_world == null || !_world.UseSimulationMovement)
{
return;
}
var enemyManager = GameEntry.EnemyManager;
if (enemyManager == null || enemyManager.Enemies == null)
{
return;
}
var enemies = enemyManager.Enemies;
foreach (var enemy in enemies)
{
if (enemy is not EnemyBase enemyEntity || !enemyEntity.Available)
{
continue;
}
if (!_world.TryGetEnemyData(enemyEntity.Id, out EnemySimData enemyData))
{
continue;
}
ApplyEnemyPresentation(enemyEntity, enemyData);
}
if (!_world.UseJobSimulation)
{
return;
}
var projectiles = _world._projectiles;
for (int i = 0; i < projectiles.Count; i++)
{
ProjectileSimData projectileData = projectiles[i];
if (!projectileData.Active || projectileData.State != ProjectileStateActive)
{
continue;
}
EntityBase projectileEntity = TryGetEntityById(projectileData.EntityId);
if (projectileEntity == null || !projectileEntity.Available)
{
continue;
}
ApplyProjectilePresentation(projectileEntity, projectileData);
}
}
private void OnProjectileHitPresentationEvent(object sender, GameEventArgs e)
{
if (!_isProjectileHitEventSubscribed || _world == null ||
e is not ProjectileHitPresentationEventArgs args)
{
return;
}
if (args.ShowHitMarker && _world._projectileHitMarkerEnabled)
{
PlayHitMarker(args);
}
if (args.ShowHitEffect && _world._projectileHitEffectEnabled)
{
PlayHitEffect(args);
}
}
private void PlayHitMarker(ProjectileHitPresentationEventArgs args)
{
EntityBase targetEntity = TryGetEntityById(args.TargetEntityId);
if (targetEntity == null || !targetEntity.Available)
{
return;
}
_projectileHitMarkerEffect ??= new HandgunHitMarkerAttackEffect(
Mathf.Max(0.01f, _world._projectileHitMarkerSize),
_world._projectileHitMarkerYOffset,
Mathf.Max(0.01f, _world._projectileHitMarkerDuration),
_world._projectileHitMarkerColor);
_projectileHitMarkerEffect.Play(null, args.HitPosition, targetEntity, 0f);
}
private void PlayHitEffect(ProjectileHitPresentationEventArgs args)
{
int effectTypeId = args.EffectEntityTypeId > 0 ? args.EffectEntityTypeId : _world._projectileHitEffectTypeId;
if (effectTypeId <= 0)
{
return;
}
var entityComponent = GameEntry.Entity;
if (entityComponent == null)
{
return;
}
EffectData effectData = new EffectData(entityComponent.GenerateSerialId(), effectTypeId)
{
Position = args.HitPosition
};
entityComponent.ShowEffect(effectData);
}
private static void ApplyEnemyPresentation(EnemyBase enemyEntity, in EnemySimData enemyData)
{
Transform enemyTransform = enemyEntity.CachedTransform;
enemyTransform.position = enemyData.Position;
Quaternion rotation = enemyData.Rotation;
float rotationMagnitude = Mathf.Abs(rotation.x) + Mathf.Abs(rotation.y) + Mathf.Abs(rotation.z) +
Mathf.Abs(rotation.w);
if (rotationMagnitude > float.Epsilon)
{
enemyTransform.rotation = rotation;
return;
}
Vector3 forward = enemyData.Forward;
forward.y = 0f;
if (forward.sqrMagnitude > float.Epsilon)
{
enemyTransform.forward = forward.normalized;
}
}
private static void ApplyProjectilePresentation(EntityBase projectileEntity,
in ProjectileSimData projectileData)
{
Transform projectileTransform = projectileEntity.CachedTransform;
if (projectileTransform == null)
{
return;
}
projectileTransform.position = projectileData.Position;
Vector3 forward = projectileData.Forward;
if (forward.sqrMagnitude <= float.Epsilon)
{
return;
}
projectileTransform.rotation = Quaternion.LookRotation(forward.normalized, Vector3.up);
}
}
}
}