convert game playing..

This commit is contained in:
2026-09-23 12:53:52 +09:00
parent 37c7942b71
commit 5d11288a6f
136 changed files with 15856 additions and 299 deletions
@@ -6,6 +6,7 @@ using BumpCombat.Constants;
using BumpCombat.Core;
using BumpCombat.Player;
using BumpCombat.Progression;
using BumpCombat.Stage;
using UnityEngine;
namespace BumpCombat.Enemies
@@ -49,6 +50,7 @@ namespace BumpCombat.Enemies
Active,
Recovery,
Dead,
Idle,
}
[RequireComponent(typeof(Rigidbody2D), typeof(Collider2D), typeof(SpriteRenderer))]
@@ -68,6 +70,7 @@ namespace BumpCombat.Enemies
private static readonly int HurtParameter = Animator.StringToHash("Hurt");
private static readonly int DeathState = Animator.StringToHash("Base Layer.Death");
private static readonly Collider2D[] SeparationBuffer = new Collider2D[16];
private static readonly Dictionary<int, HashSet<EnemyController>> EncounterGroups = new();
private static Sprite launchWhiteSprite;
private static int nextSpawnLifetimeIdentity;
[SerializeField] private EnemyDefinition definition;
@@ -85,6 +88,9 @@ namespace BumpCombat.Enemies
private EnemyAttack enemyAttack;
private EnemyModel enemyModel;
private ArtifactStatusVisual statusVisual;
private readonly List<Renderer> fogRenderers = new();
private readonly List<bool> fogRendererForceOffStates = new();
private bool fogVisibilityHidden;
private ActiveArtifactController activeArtifactController;
private Transform player;
private PlayerHealth playerHealth;
@@ -97,6 +103,7 @@ namespace BumpCombat.Enemies
private float igniteNextTickIn;
private float igniteTickInterval;
private float igniteTickDamage;
private EnemyDamageSource igniteDamageSource;
private float shockRemaining;
private float shockIncrease;
private float vulnerabilityRemaining;
@@ -123,6 +130,7 @@ namespace BumpCombat.Enemies
private IEnemyDamageGate damageGate;
private IEnemyAttackPatternGate attackPatternGate;
private IEnemyActionGate actionGate;
private BumpCombat.Defense.DefenseRouteAgent defenseRouteAgent;
private bool summoned;
private bool phaseSummon;
private bool summonedEventLike;
@@ -142,6 +150,15 @@ namespace BumpCombat.Enemies
private readonly HashSet<string> recentArtifactContactKeys = new(StringComparer.Ordinal);
private readonly Queue<string> recentArtifactContactOrder = new();
private const int MaximumRememberedArtifactContacts = 128;
private const int RoamTargetSelectionAttempts = 12;
private bool hasDetectedPlayer;
private int encounterGroupId = -1;
private bool hasRoamAnchor;
private Vector2 roamAnchor;
private Vector2 roamTarget;
private float roamPauseRemaining;
private float sightMemoryRemaining;
private Vector2 lastSeenPlayerPosition;
public static int AliveCount { get; private set; }
public static int CrowdAliveCount { get; private set; }
@@ -160,6 +177,8 @@ namespace BumpCombat.Enemies
public float CurrentHealth { get; private set; }
public float LastAppliedDamage { get; private set; }
public float LastReportedDamage { get; private set; }
public EnemyDamageSource LastDamageSource { get; private set; }
public float MaximumHealthAtDeath { get; private set; }
public int CurrentAttackPatternIndex => attackPatternIndex;
public EnemyAttackPattern CurrentAttackPattern => definition != null
? definition.GetAttackPattern(attackPatternIndex)
@@ -216,6 +235,12 @@ namespace BumpCombat.Enemies
public Vector2 GroundAnchorPosition => body != null
? body.position
: transform.position;
public Transform CurrentVisualTransform => airborneVisualObject != null
? airborneVisualObject.transform
: transform;
public int CurrentVisualSortingOrder => airborneVisualObject != null
? spriteRenderer.sortingOrder + 2
: spriteRenderer.sortingOrder;
public bool IsKnockbackActive => knockbackVelocity.sqrMagnitude > 0.0025f;
public bool IsLaunchVisualActive => launchVisualCoroutine != null;
public bool IsAttackSequenceInProgress => State == EnemyState.Warning
@@ -228,6 +253,11 @@ namespace BumpCombat.Enemies
public EnemyController SummonOwner => summonOwner;
public bool IsProtectedFromCleanup => runEventRole.HasValue || phaseSummon;
public bool HasContactDamage => definition != null && definition.HasContactDamage;
public bool IsFlying => definition != null && definition.IsFlying;
public Collider2D BodyCollider => bodyCollider != null ? bodyCollider : (bodyCollider = GetComponent<Collider2D>());
public bool HasDetectedPlayer => hasDetectedPlayer;
public int EncounterGroupId => encounterGroupId;
public float SightRange => enemyModel != null ? enemyModel.SightRange : (definition != null ? definition.SightRange : 8f);
public bool IsRangedAttackStartAllowed => definition == null
|| !definition.IsRanged
|| CanStartRangedAttack();
@@ -369,6 +399,21 @@ namespace BumpCombat.Enemies
}
#endif
public void ConfigureEncounterGroup(int groupId, Vector2 anchor)
{
UnregisterEncounterGroup();
encounterGroupId = groupId;
roamAnchor = anchor;
roamTarget = anchor;
hasRoamAnchor = true;
RegisterEncounterGroup();
}
public void ConfigureSightRangeMultiplier(float multiplier)
{
EnsureEnemyModel().ConfigureSightRangeMultiplier(multiplier);
}
private void Awake()
{
nextSpawnLifetimeIdentity = nextSpawnLifetimeIdentity == int.MaxValue
@@ -386,6 +431,7 @@ namespace BumpCombat.Enemies
}
bodyCollider = GetComponent<Collider2D>();
spriteRenderer = GetComponent<SpriteRenderer>();
CacheFogRenderers();
animator = GetComponent<Animator>();
enemyAttack = GetComponent<EnemyAttack>();
ConfigureEnemyModel();
@@ -433,6 +479,12 @@ namespace BumpCombat.Enemies
private void OnEnable()
{
if (fogVisibilityHidden)
{
ForceFogRenderersOff();
}
RegisterEncounterGroup();
if (enemyModel != null)
{
enemyModel.OnStatChanged += HandleCharacterStatChanged;
@@ -455,12 +507,20 @@ namespace BumpCombat.Enemies
}
KeepBodyInsideArena();
if (IsFlying)
{
StageObstacle.RegisterFlyingEnemy(this);
}
}
private void Start()
{
InitializeGroggyTierFromDefinition();
KeepBodyInsideArena();
if (IsFlying)
{
StageObstacle.RegisterFlyingEnemy(this);
}
if (definition == null)
{
enabled = false;
@@ -477,8 +537,16 @@ namespace BumpCombat.Enemies
player = playerController.transform;
playerHealth = playerController.GetComponent<PlayerHealth>();
activeArtifactController = playerController.GetComponent<ActiveArtifactController>();
if (!hasRoamAnchor)
{
roamAnchor = body != null ? body.position : (Vector2)transform.position;
roamTarget = roamAnchor;
hasRoamAnchor = true;
}
InitializeInitialShieldColor();
CurrentHealth = MaximumHealth;
LastDamageSource = EnemyDamageSource.None;
MaximumHealthAtDeath = 0f;
float summonDuration = summoned ? GetSummonAnimationDuration() : 0f;
bool playSummonAnimation = summonDuration > 0f;
EnterState(
@@ -507,6 +575,7 @@ namespace BumpCombat.Enemies
private void OnDisable()
{
UnregisterEncounterGroup();
if (enemyModel != null)
{
enemyModel.OnStatChanged -= HandleCharacterStatChanged;
@@ -601,6 +670,13 @@ namespace BumpCombat.Enemies
return;
}
defenseRouteAgent ??= GetComponent<BumpCombat.Defense.DefenseRouteAgent>();
if (defenseRouteAgent != null
&& defenseRouteAgent.TryDriveFixedUpdate(Time.fixedDeltaTime))
{
return;
}
if (!AllowsStateMovement(State, AttackShape))
{
body.linearVelocity = Vector2.zero;
@@ -611,12 +687,35 @@ namespace BumpCombat.Enemies
{
case EnemyState.Spawn:
if (stateTimer <= 0f)
{
if (CheckPlayerDetection())
{
EnterState(EnemyState.Chase, 0f);
}
else
{
EnterState(EnemyState.Idle, 0f);
}
}
break;
case EnemyState.Idle:
SetAttacking(false);
if (CheckPlayerDetection())
{
EnterState(EnemyState.Chase, 0f);
}
else
{
UpdateRoaming();
}
break;
case EnemyState.Chase:
if (!RefreshChaseAwareness())
{
break;
}
if (actionGate != null && actionGate.IsAttackLocked)
{
body.linearVelocity = Vector2.zero;
@@ -731,7 +830,8 @@ namespace BumpCombat.Enemies
Vector2 knockbackDirection,
float knockbackForce,
bool playHurtAnimation = true,
bool isNormalBump = false)
bool isNormalBump = false,
EnemyDamageSource damageSource = EnemyDamageSource.None)
{
return TryTakeDamageWithEffects(
damage,
@@ -741,6 +841,7 @@ namespace BumpCombat.Enemies
isNormalBump,
IsShocked,
IsBumpVulnerable,
damageSource,
out _);
}
@@ -752,9 +853,11 @@ namespace BumpCombat.Enemies
bool isNormalBump,
bool isShockedAtHit,
bool isBumpVulnerableAtHit,
EnemyDamageSource damageSource,
out bool noDamageAfterEffects)
{
noDamageAfterEffects = false;
Alert();
if (IsDead || damage <= 0f)
{
LastAppliedDamage = 0f;
@@ -802,13 +905,16 @@ namespace BumpCombat.Enemies
? damageTaken
: calculatedDamage;
float healthBeforeDamage = CurrentHealth;
float maximumHealthBeforeDamage = MaximumHealth;
CurrentHealth = Mathf.Max(0f, CurrentHealth - damageTaken);
LastAppliedDamage = healthBeforeDamage - CurrentHealth;
LastDamageSource = damageSource;
OnDamageApplied?.Invoke(healthBeforeDamage, LastAppliedDamage);
bool damageReactionBlocked = damageGate != null
&& damageGate.IsDamageBlocked;
if (CurrentHealth <= 0f)
{
MaximumHealthAtDeath = maximumHealthBeforeDamage;
Die();
}
else if (damageReactionBlocked)
@@ -817,13 +923,13 @@ namespace BumpCombat.Enemies
// desperation phase. Do not append the opening hit's
// knockback or hurt reaction after that transition.
knockbackVelocity = Vector2.zero;
body.linearVelocity = Vector2.zero;
if (body != null) body.linearVelocity = Vector2.zero;
}
else
{
if (knockbackVelocity.sqrMagnitude <= 0.0025f)
{
knockbackStartPosition = body.position;
knockbackStartPosition = body != null ? body.position : (Vector2)transform.position;
}
knockbackVelocity += knockbackDirection.normalized
* knockbackForce
@@ -914,7 +1020,8 @@ namespace BumpCombat.Enemies
float knockbackForce,
ArtifactColor artifactColor,
int castIdentity,
bool playHurtAnimation = true)
bool playHurtAnimation = true,
EnemyDamageSource damageSource = EnemyDamageSource.None)
{
lastArtifactContactCounted = false;
if (IsDead)
@@ -956,7 +1063,8 @@ namespace BumpCombat.Enemies
knockbackDirection,
knockbackForce,
playHurtAnimation,
false)
false,
damageSource)
? EnemyArtifactHitResult.DamageApplied
: EnemyArtifactHitResult.Rejected;
}
@@ -1004,7 +1112,8 @@ namespace BumpCombat.Enemies
public bool ApplyIgnite(
float duration,
float tickInterval,
float damagePerTick)
float damagePerTick,
EnemyDamageSource damageSource = EnemyDamageSource.Player)
{
if (IsDead
|| duration <= 0f
@@ -1017,6 +1126,7 @@ namespace BumpCombat.Enemies
bool wasInactive = igniteRemaining <= 0f;
igniteRemaining = Mathf.Max(igniteRemaining, duration);
igniteTickDamage = Mathf.Max(igniteTickDamage, damagePerTick);
igniteDamageSource = damageSource;
if (wasInactive)
{
igniteTickInterval = tickInterval;
@@ -1085,6 +1195,7 @@ namespace BumpCombat.Enemies
false,
isShockedAtTick,
false,
igniteDamageSource,
out bool noDamageAfterEffects);
if ((!damageApplied && !noDamageAfterEffects) || IsDead)
{
@@ -1821,19 +1932,28 @@ namespace BumpCombat.Enemies
Vector2 attackSlot = GetHorizontalRootAttackSlot(
attackTarget,
direction);
if (!IsFlying)
{
ZoneInstance currentZone = StageManager.Instance != null
? StageManager.Instance.CurrentZone
: null;
if (currentZone != null
&& currentZone.Preset != null
&& RoomPathfinder.TryGetNextWaypoint(
currentZone,
body.position,
attackSlot,
false,
out Vector2 waypoint))
{
attackSlot = waypoint;
}
}
Vector2 toAttackSlot = attackSlot - body.position;
movementDirection = toAttackSlot.sqrMagnitude > 0.0001f
? toAttackSlot.normalized
: Vector2.zero;
}
if (IsCrowd)
{
Vector2 toApproachPoint =
(Vector2)player.position + crowdApproachOffset - body.position;
movementDirection = toApproachPoint.sqrMagnitude > 0.01f
? toApproachPoint.normalized
: Vector2.zero;
}
else if (definition.IsRanged && rangedAttackOutsideGate)
{
// A ranged attacker must enter the visible, reachable area
@@ -1845,11 +1965,45 @@ namespace BumpCombat.Enemies
{
movementDirection = -direction;
}
else
{
Vector2 targetPoint = attackTarget;
if (IsCrowd)
{
float distToPlayer = (attackTarget - body.position).magnitude;
targetPoint = distToPlayer > 2.5f
? attackTarget
: (Vector2)player.position + crowdApproachOffset;
}
if (!IsFlying)
{
ZoneInstance currentZone = StageManager.Instance != null ? StageManager.Instance.CurrentZone : null;
if (currentZone != null && currentZone.Preset != null)
{
if (RoomPathfinder.TryGetNextWaypoint(
currentZone,
body.position,
targetPoint,
IsFlying,
out Vector2 waypoint))
{
targetPoint = waypoint;
}
}
}
Vector2 toApproachPoint = targetPoint - body.position;
movementDirection = toApproachPoint.sqrMagnitude > 0.01f
? toApproachPoint.normalized
: Vector2.zero;
}
Vector2 separation = CalculateSeparation();
Vector2 velocity = Vector2.ClampMagnitude(
Vector2 desiredVelocity = Vector2.ClampMagnitude(
movementDirection + separation * separationStrength,
1f) * MoveSpeed;
Vector2 velocity = CalculateWallSlideVelocity(desiredVelocity);
body.MovePosition(ClampEnemyPosition(
body.position + velocity * Time.fixedDeltaTime));
SetMoving(velocity.sqrMagnitude > 0.0001f);
@@ -1864,10 +2018,11 @@ namespace BumpCombat.Enemies
if (bounds != null)
{
Vector2 actorExtents = bounds.SharedActorClampHalfExtents;
Vector2 center = bounds.ZoneCenter;
boundedTarget.y = Mathf.Clamp(
attackTarget.y,
-actorExtents.y,
actorExtents.y);
center.y - actorExtents.y,
center.y + actorExtents.y);
}
// Horizontal-root attacks measure range to the player's collider
@@ -1919,9 +2074,10 @@ namespace BumpCombat.Enemies
EnemyConstants tuning = GameplayConstants.Current.Enemies;
Vector2 reachable = bounds.GetReachableHalfExtents(
tuning.RangedApproachArenaInset);
Vector2 center = bounds.ZoneCenter;
Vector2 interiorTarget = new(
Mathf.Clamp(targetPosition.x, -reachable.x, reachable.x),
Mathf.Clamp(targetPosition.y, -reachable.y, reachable.y));
Mathf.Clamp(targetPosition.x, center.x - reachable.x, center.x + reachable.x),
Mathf.Clamp(targetPosition.y, center.y - reachable.y, center.y + reachable.y));
Camera camera = Camera.main;
if (camera != null)
{
@@ -1933,10 +2089,10 @@ namespace BumpCombat.Enemies
// Keep the approach point in the intersection of the
// reachable and visible interiors. This is essential when
// the player is held against an outer map edge.
float minimumX = Mathf.Max(-reachable.x, cameraCenter.x - visible.x);
float maximumX = Mathf.Min(reachable.x, cameraCenter.x + visible.x);
float minimumY = Mathf.Max(-reachable.y, cameraCenter.y - visible.y);
float maximumY = Mathf.Min(reachable.y, cameraCenter.y + visible.y);
float minimumX = Mathf.Max(center.x - reachable.x, cameraCenter.x - visible.x);
float maximumX = Mathf.Min(center.x + reachable.x, cameraCenter.x + visible.x);
float minimumY = Mathf.Max(center.y - reachable.y, cameraCenter.y - visible.y);
float maximumY = Mathf.Min(center.y + reachable.y, cameraCenter.y + visible.y);
if (minimumX <= maximumX)
{
interiorTarget.x = Mathf.Clamp(
@@ -2095,6 +2251,11 @@ namespace BumpCombat.Enemies
return cachedSeparation;
}
public void SetFacingDirection(Vector2 direction)
{
SetFacing(direction);
}
private void SetFacing(Vector2 direction)
{
if (direction.sqrMagnitude <= 0f)
@@ -2126,6 +2287,276 @@ namespace BumpCombat.Enemies
|| (state == EnemyState.Warning && attackAnimationStarted));
}
public void Alert()
{
MarkPlayerDetected(false);
if (State == EnemyState.Idle)
{
EnterState(EnemyState.Chase, 0f);
}
}
public bool CheckPlayerDetection()
{
if (!CanCurrentlyDetectPlayer()) return false;
MarkPlayerDetected(true);
return true;
}
private bool CanCurrentlyDetectPlayer()
{
EnsurePlayerReference();
if (player == null) return false;
Vector2 myPos = GroundAnchorPosition;
float distance = Vector2.Distance(myPos, player.position);
if (distance > SightRange) return false;
float proximityRange = GameplayConstants.Current.Enemies.ProximityAlertRange;
return distance <= proximityRange
|| RoomPathfinder.HasLineOfSight(myPos, player.position, IsFlying, bodyCollider);
}
private void EnsurePlayerReference()
{
if (player != null) return;
PlayerController playerController = FindAnyObjectByType<PlayerController>();
if (playerController == null) return;
player = playerController.transform;
playerHealth = playerController.GetComponent<PlayerHealth>();
activeArtifactController = playerController.GetComponent<ActiveArtifactController>();
}
private void MarkPlayerDetected(bool alertGroup)
{
EnsurePlayerReference();
hasDetectedPlayer = true;
sightMemoryRemaining = GameplayConstants.Current.Enemies.LostSightMemoryDuration;
if (player != null)
{
lastSeenPlayerPosition = player.position;
}
if (alertGroup && encounterGroupId >= 0
&& EncounterGroups.TryGetValue(encounterGroupId, out HashSet<EnemyController> group))
{
foreach (EnemyController member in group)
{
if (member == null || member == this || member.IsDead || member.IsEventEnemy)
{
continue;
}
member.MarkPlayerDetected(false);
if (member.State == EnemyState.Idle)
{
member.EnterState(EnemyState.Chase, 0f);
}
}
}
}
private bool RefreshChaseAwareness()
{
if (IsEventEnemy)
{
return true;
}
if (CanCurrentlyDetectPlayer())
{
MarkPlayerDetected(false);
return true;
}
sightMemoryRemaining = Mathf.Max(0f, sightMemoryRemaining - Time.fixedDeltaTime);
if (sightMemoryRemaining > 0f)
{
return true;
}
Vector2 toLastSeen = lastSeenPlayerPosition - body.position;
if (toLastSeen.sqrMagnitude <= 0.16f)
{
hasDetectedPlayer = false;
body.linearVelocity = Vector2.zero;
SetMoving(false);
EnterState(EnemyState.Idle, 0f);
return false;
}
MoveTowardPoint(lastSeenPlayerPosition, MoveSpeed);
return false;
}
private void UpdateRoaming()
{
if (IsEventEnemy || !hasRoamAnchor)
{
body.linearVelocity = Vector2.zero;
SetMoving(false);
return;
}
EnemyConstants tuning = GameplayConstants.Current.Enemies;
if (roamPauseRemaining > 0f)
{
roamPauseRemaining = Mathf.Max(0f, roamPauseRemaining - Time.fixedDeltaTime);
body.linearVelocity = Vector2.zero;
SetMoving(false);
return;
}
if ((roamTarget - body.position).sqrMagnitude <= 0.16f)
{
if (!TryChooseRoamTarget(tuning))
{
roamTarget = body.position;
}
roamPauseRemaining = UnityEngine.Random.Range(tuning.RoamPauseMin, tuning.RoamPauseMax);
body.linearVelocity = Vector2.zero;
SetMoving(false);
return;
}
MoveTowardPoint(roamTarget, MoveSpeed * 0.6f);
}
private bool TryChooseRoamTarget(EnemyConstants tuning)
{
ZoneInstance currentZone = StageManager.Instance != null
? StageManager.Instance.CurrentZone
: null;
for (int attempt = 0; attempt < RoamTargetSelectionAttempts; attempt++)
{
float radius = UnityEngine.Random.Range(tuning.RoamRadiusMin, tuning.RoamRadiusMax);
Vector2 offset = UnityEngine.Random.insideUnitCircle.normalized * radius;
Vector2 candidate = ClampEnemyPosition(roamAnchor + offset);
if (currentZone == null || currentZone.Preset == null)
{
roamTarget = candidate;
return true;
}
if (RoomPathfinder.TryGetReachableRoamPoint(
currentZone,
body.position,
candidate,
IsFlying,
out Vector2 reachableTarget))
{
roamTarget = reachableTarget;
return true;
}
}
return false;
}
private void MoveTowardPoint(Vector2 targetPoint, float speed)
{
if (!IsFlying)
{
ZoneInstance currentZone = StageManager.Instance != null
? StageManager.Instance.CurrentZone
: null;
if (currentZone != null && currentZone.Preset != null
&& RoomPathfinder.TryGetNextWaypoint(
currentZone,
body.position,
targetPoint,
false,
out Vector2 waypoint))
{
targetPoint = waypoint;
}
}
Vector2 direction = targetPoint - body.position;
if (direction.sqrMagnitude <= 0.0001f)
{
body.linearVelocity = Vector2.zero;
SetMoving(false);
return;
}
direction.Normalize();
SetFacing(direction);
Vector2 desiredVelocity = direction * speed;
Vector2 velocity = CalculateWallSlideVelocity(desiredVelocity);
body.MovePosition(ClampEnemyPosition(
body.position + velocity * Time.fixedDeltaTime));
SetMoving(velocity.sqrMagnitude > 0.0001f);
}
private void RegisterEncounterGroup()
{
if (encounterGroupId < 0) return;
if (!EncounterGroups.TryGetValue(encounterGroupId, out HashSet<EnemyController> group))
{
group = new HashSet<EnemyController>();
EncounterGroups.Add(encounterGroupId, group);
}
group.Add(this);
}
private void UnregisterEncounterGroup()
{
if (encounterGroupId < 0
|| !EncounterGroups.TryGetValue(encounterGroupId, out HashSet<EnemyController> group))
{
return;
}
group.Remove(this);
if (group.Count == 0)
{
EncounterGroups.Remove(encounterGroupId);
}
}
private Vector2 CalculateWallSlideVelocity(Vector2 velocity)
{
if (velocity.sqrMagnitude < 0.0001f) return Vector2.zero;
float radius = GameplayConstants.Current.Enemies.WallSlideCastRadius;
float distance = GameplayConstants.Current.Enemies.WallSlideCastDistance;
Vector2 dir = velocity.normalized;
RaycastHit2D hit = Physics2D.CircleCast(
body.position,
radius,
dir,
distance);
if (hit.collider != null && !hit.collider.isTrigger && hit.collider != bodyCollider)
{
bool isObstacle = hit.collider.GetComponentInParent<StageObstacle>() != null;
bool isWall = hit.collider.name.StartsWith("Wall_") || hit.collider.gameObject.name.Contains("Wall");
if ((isObstacle && !IsFlying) || isWall)
{
Vector2 normal = hit.normal;
Vector2 tangent = new Vector2(-normal.y, normal.x);
if (Vector2.Dot(velocity, tangent) < 0f)
{
tangent = -tangent;
}
float forwardProjection = Vector2.Dot(velocity, tangent);
if (forwardProjection > 0.01f)
{
return tangent * (forwardProjection * 1.05f);
}
}
}
return velocity;
}
public static bool ShouldStartAttackAnimation(
float warningTimeRemaining,
float leadTime,
@@ -2294,6 +2725,89 @@ namespace BumpCombat.Enemies
ReleaseSpriteVisibilityLease(reason);
}
public void SetFogVisibility(bool visible)
{
if (visible)
{
if (!fogVisibilityHidden)
{
return;
}
for (int i = 0; i < fogRenderers.Count; i++)
{
if (fogRenderers[i] != null)
{
fogRenderers[i].forceRenderingOff = fogRendererForceOffStates[i];
}
}
fogRenderers.Clear();
fogRendererForceOffStates.Clear();
fogVisibilityHidden = false;
return;
}
if (!fogVisibilityHidden)
{
CacheFogRenderers();
fogVisibilityHidden = true;
}
ForceFogRenderersOff();
}
private void CacheFogRenderers()
{
if (fogVisibilityHidden)
{
return;
}
fogRenderers.Clear();
fogRendererForceOffStates.Clear();
Renderer[] renderers = GetComponentsInChildren<Renderer>(true);
for (int i = 0; i < renderers.Length; i++)
{
fogRenderers.Add(renderers[i]);
fogRendererForceOffStates.Add(renderers[i].forceRenderingOff);
}
}
private void ForceFogRenderersOff()
{
for (int i = 0; i < fogRenderers.Count; i++)
{
if (fogRenderers[i] != null)
{
fogRenderers[i].forceRenderingOff = true;
}
}
}
private void OnTransformChildrenChanged()
{
if (!fogVisibilityHidden)
{
CacheFogRenderers();
return;
}
Renderer[] renderers = GetComponentsInChildren<Renderer>(true);
for (int i = 0; i < renderers.Length; i++)
{
if (fogRenderers.Contains(renderers[i]))
{
renderers[i].forceRenderingOff = true;
continue;
}
fogRenderers.Add(renderers[i]);
fogRendererForceOffStates.Add(renderers[i].forceRenderingOff);
renderers[i].forceRenderingOff = true;
}
}
private void AcquireSpriteVisibilityLease(string reason)
{
if (string.IsNullOrEmpty(reason))