2.5d test
This commit is contained in:
@@ -4,6 +4,7 @@ using BumpCombat.Core;
|
||||
using BumpCombat.Constants;
|
||||
using BumpCombat.Enemies;
|
||||
using BumpCombat.Player;
|
||||
using BumpCombat.Defense;
|
||||
using BumpCombat.UI;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -81,6 +82,7 @@ namespace BumpCombat.Combat
|
||||
private readonly HashSet<GameObject> blockedBumpVisuals = new();
|
||||
private readonly HashSet<GameObject> guardBlockImpactVisuals = new();
|
||||
private readonly HashSet<GameObject> artifactImpactVisuals = new();
|
||||
private readonly HashSet<GameObject> towerImpactVisuals = new();
|
||||
private readonly HashSet<GameObject> playerHurtImpactVisuals = new();
|
||||
private readonly Dictionary<string, Sprite[]> artifactImpactFrameCache = new();
|
||||
private SpriteRenderer playerRenderer;
|
||||
@@ -129,6 +131,7 @@ namespace BumpCombat.Combat
|
||||
public int ActiveBlockedBumpVisualCount => blockedBumpVisuals.Count;
|
||||
public int ActiveGuardBlockImpactVisualCount => guardBlockImpactVisuals.Count;
|
||||
public int ActiveArtifactImpactVisualCount => artifactImpactVisuals.Count;
|
||||
public int ActiveTowerImpactVisualCount => towerImpactVisuals.Count;
|
||||
public int ActivePlayerHurtImpactVisualCount => playerHurtImpactVisuals.Count;
|
||||
|
||||
public static string GetPlayerHurtImpactResourcePath()
|
||||
@@ -189,6 +192,69 @@ namespace BumpCombat.Combat
|
||||
+ "-v1";
|
||||
}
|
||||
|
||||
public static string GetTowerImpactResourcePath(DefenseTowerKind kind)
|
||||
{
|
||||
return kind switch
|
||||
{
|
||||
DefenseTowerKind.Direct => "Combat/TowerImpact-Direct-Clean-v1",
|
||||
DefenseTowerKind.Summon => null,
|
||||
DefenseTowerKind.Lightning => "Combat/TowerImpact-Lightning-Clean-v1",
|
||||
DefenseTowerKind.Cold => "Combat/TowerImpact-Cold-Clean-v1",
|
||||
DefenseTowerKind.Seismic => "Combat/TowerImpact-Seismic-Clean-v1",
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
public static void ShowTowerImpact(
|
||||
DefenseTowerKind kind, EnemyController target, Vector2 hitPosition)
|
||||
{
|
||||
CombatFeedback feedback = GetActive();
|
||||
if (feedback != null && feedback.isActiveAndEnabled)
|
||||
{
|
||||
feedback.CreateTowerImpact(kind, target, hitPosition);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateTowerImpact(
|
||||
DefenseTowerKind kind, EnemyController target, Vector2 hitPosition)
|
||||
{
|
||||
string resourcePath = GetTowerImpactResourcePath(kind);
|
||||
if (string.IsNullOrEmpty(resourcePath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Sprite[] frames = LoadBumpImpactFrames(resourcePath);
|
||||
if (frames == null || frames.Length != BumpImpactFrameCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject root = new($"Tower Impact {kind}");
|
||||
root.transform.localScale = Vector3.one * 2f;
|
||||
root.transform.position = hitPosition;
|
||||
SpriteRenderer renderer = root.AddComponent<SpriteRenderer>();
|
||||
renderer.sprite = frames[0];
|
||||
renderer.color = Color.white;
|
||||
SpriteRenderer targetRenderer = target != null
|
||||
? target.GetComponent<SpriteRenderer>() : null;
|
||||
if (targetRenderer != null)
|
||||
{
|
||||
renderer.sortingLayerID = targetRenderer.sortingLayerID;
|
||||
renderer.sortingOrder = targetRenderer.sortingOrder
|
||||
+ DefenseTowerArtBounds.TowerHitSortingOffset;
|
||||
}
|
||||
else if (playerRenderer != null)
|
||||
{
|
||||
renderer.sortingLayerID = playerRenderer.sortingLayerID;
|
||||
renderer.sortingOrder = playerRenderer.sortingOrder
|
||||
+ DefenseTowerArtBounds.TowerHitSortingOffset;
|
||||
}
|
||||
RegisterTransient(root, false);
|
||||
towerImpactVisuals.Add(root);
|
||||
StartCoroutine(AnimateArtifactImpact(root, renderer, frames));
|
||||
}
|
||||
|
||||
public static float GetArtifactImpactFrameDuration(int frameIndex)
|
||||
{
|
||||
return GetBumpImpactFrameDuration(frameIndex);
|
||||
@@ -526,6 +592,7 @@ namespace BumpCombat.Combat
|
||||
ClearBlockedBumpVisuals();
|
||||
ClearGuardBlockImpactVisuals();
|
||||
ClearArtifactImpactVisuals();
|
||||
ClearTowerImpactVisuals();
|
||||
ClearPlayerHurtImpactVisuals();
|
||||
ClearCycloneAfterimages();
|
||||
}
|
||||
@@ -1894,6 +1961,22 @@ namespace BumpCombat.Combat
|
||||
artifactImpactVisuals.Clear();
|
||||
}
|
||||
|
||||
private void ClearTowerImpactVisuals()
|
||||
{
|
||||
if (towerImpactVisuals.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject[] visuals = new GameObject[towerImpactVisuals.Count];
|
||||
towerImpactVisuals.CopyTo(visuals);
|
||||
foreach (GameObject visual in visuals)
|
||||
{
|
||||
DestroyTransient(visual);
|
||||
}
|
||||
towerImpactVisuals.Clear();
|
||||
}
|
||||
|
||||
private void ClearPlayerHurtImpactVisuals()
|
||||
{
|
||||
if (playerHurtImpactVisuals.Count == 0)
|
||||
@@ -2398,6 +2481,7 @@ namespace BumpCombat.Combat
|
||||
blockedBumpVisuals.RemoveWhere(visual => visual == null);
|
||||
guardBlockImpactVisuals.RemoveWhere(visual => visual == null);
|
||||
artifactImpactVisuals.RemoveWhere(visual => visual == null);
|
||||
towerImpactVisuals.RemoveWhere(visual => visual == null);
|
||||
playerHurtImpactVisuals.RemoveWhere(visual => visual == null);
|
||||
return;
|
||||
}
|
||||
@@ -2406,6 +2490,7 @@ namespace BumpCombat.Combat
|
||||
blockedBumpVisuals.Remove(transientObject);
|
||||
guardBlockImpactVisuals.Remove(transientObject);
|
||||
artifactImpactVisuals.Remove(transientObject);
|
||||
towerImpactVisuals.Remove(transientObject);
|
||||
playerHurtImpactVisuals.Remove(transientObject);
|
||||
int instanceId = transientObject.GetInstanceID();
|
||||
activeTransientIds.Remove(instanceId);
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BumpCombat.Combat
|
||||
{
|
||||
// Authored ground geometry shared by the XY controller and XZ comparison.
|
||||
// Sprite frames and decoration consume elapsed time independently of damage ticks.
|
||||
public static class CycloneGeometry
|
||||
{
|
||||
public const float PixelsPerUnit = 32f;
|
||||
public const float ShadowLocalY = -7.5f / PixelsPerUnit;
|
||||
public const float CenterOffsetY = 5f / PixelsPerUnit;
|
||||
public const float FrameSeconds = .05f;
|
||||
|
||||
public static float VisualScale(float range, bool charged) => range / (charged ? 1.25f : .85f);
|
||||
|
||||
public static Vector2 Radii(float range, bool charged) =>
|
||||
(charged ? new Vector2(46f, 18f) : new Vector2(38.0625f, 15.03125f))
|
||||
/ PixelsPerUnit * VisualScale(range, charged);
|
||||
|
||||
public static Vector2 CenterOffset(float range, bool charged, float rootScaleY) =>
|
||||
Vector2.up * (ShadowLocalY * rootScaleY + CenterOffsetY * VisualScale(range, charged));
|
||||
|
||||
public static int ScheduledHitCount(float duration, float interval) =>
|
||||
duration <= 0f || interval <= 0f ? 1
|
||||
: Mathf.Max(1, Mathf.FloorToInt((duration + .0001f) / interval) + 1);
|
||||
|
||||
public static float NormalizedDistance(Vector2 offset, Vector2 radii) =>
|
||||
offset.x * offset.x / (radii.x * radii.x)
|
||||
+ offset.y * offset.y / (radii.y * radii.y);
|
||||
|
||||
// Keep the original closest-point and 64 boundary samples, including tolerances.
|
||||
// The adapter supplies Collider2D.ClosestPoint or an XZ circular footprint.
|
||||
public static bool Overlaps(Vector2 center, Vector2 radii, Func<Vector2, Vector2> closestPoint)
|
||||
{
|
||||
if (NormalizedDistance(closestPoint(center) - center, radii) <= 1.0001f) return true;
|
||||
const int samples = 64;
|
||||
for (int i = 0; i < samples; i++)
|
||||
{
|
||||
float angle = Mathf.PI * 2f * i / samples;
|
||||
Vector2 point = center + new Vector2(Mathf.Cos(angle) * radii.x, Mathf.Sin(angle) * radii.y);
|
||||
if ((closestPoint(point) - point).sqrMagnitude <= .000001f) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a2c269eb2424df68bfbd7d08ffee36d
|
||||
Reference in New Issue
Block a user