mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-28 21:55:42 +00:00
Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
628b5aabf6 | ||
|
|
9006f00d24 | ||
|
|
553b8f6e6c | ||
|
|
a354509941 | ||
|
|
1d4793c0ac | ||
|
|
b7c1f3d0d2 | ||
|
|
5dc0ce093f | ||
|
|
dca08b6101 | ||
|
|
fdcfce8fa8 |
@@ -251506,16 +251506,28 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::Shardok.MeleeAnimator
|
||||
swordSprite: {fileID: 21300000, guid: e91fc63fcd9bb1c4abf7ffdc0848a328, type: 3}
|
||||
maceSprite: {fileID: 21300000, guid: f0322edec49f5cd49b55fc4786a4c823, type: 3}
|
||||
smallSpearSprite: {fileID: 21300000, guid: b4e09b8aafd5a1e46b9338e37690ec11, type: 3}
|
||||
largeSpearSprite: {fileID: 21300000, guid: b303f05c2843e294889c503b4c359c87, type: 3}
|
||||
falchionSprite: {fileID: 21300000, guid: b4e09b8aafd5a1e46b9338e37690ec11, type: 3}
|
||||
twoHandedSwordSprite: {fileID: 21300000, guid: b303f05c2843e294889c503b4c359c87,
|
||||
type: 3}
|
||||
daggerSprite: {fileID: 21300000, guid: 2ed511dd2a8f5194b9d5f2ba49bbcc8b, type: 3}
|
||||
boneSprite: {fileID: 21300000, guid: b002e339cc2ff924599da592d5a8112f, type: 3}
|
||||
swordRotationOffset: 180
|
||||
swordFlipHorizontal: 0
|
||||
maceRotationOffset: 225
|
||||
maceFlipHorizontal: 0
|
||||
falchionRotationOffset: 180
|
||||
falchionFlipHorizontal: 0
|
||||
twoHandedSwordRotationOffset: 45
|
||||
twoHandedSwordFlipHorizontal: 0
|
||||
daggerRotationOffset: -45
|
||||
daggerFlipHorizontal: 0
|
||||
boneRotationOffset: -45
|
||||
boneFlipHorizontal: 0
|
||||
weaponScale: 20
|
||||
clashDuration: 0.15
|
||||
clashCount: 3
|
||||
thrustDistance: 20
|
||||
weaponOffset: 30
|
||||
baseRotationOffset: -45
|
||||
swingArc: 60
|
||||
shakeIntensity: 8
|
||||
--- !u!114 &2088078281
|
||||
@@ -251591,6 +251603,19 @@ MonoBehaviour:
|
||||
explosionColor: {r: 1, g: 0.4, b: 0.1, a: 1}
|
||||
sparkCount: 6
|
||||
sparkSpread: 40
|
||||
chargeSprite: {fileID: -2413806693520163455, guid: 00630274bf61c4899aa743c3fc3d7ccc,
|
||||
type: 3}
|
||||
chargeColor: {r: 1, g: 0.6, b: 0.2, a: 0.7}
|
||||
chargeStartScale: 5
|
||||
chargeEndScale: 25
|
||||
chargeDuration: 0.5
|
||||
targetSprite: {fileID: -2413806693520163455, guid: 00630274bf61c4899aa743c3fc3d7ccc,
|
||||
type: 3}
|
||||
targetColor: {r: 1, g: 0.3, b: 0.1, a: 0.6}
|
||||
targetScale: 30
|
||||
targetDuration: 0.4
|
||||
cancelColor: {r: 0.5, g: 0.5, b: 0.5, a: 0.8}
|
||||
cancelDuration: 0.3
|
||||
fallDuration: 0.4
|
||||
explosionDuration: 0.5
|
||||
--- !u!114 &2088078284
|
||||
@@ -251832,13 +251857,17 @@ MonoBehaviour:
|
||||
largeLanceSprite: {fileID: 21300000, guid: b6e121b3356b95c4d89285c5309bb953, type: 3}
|
||||
daggerSprite: {fileID: 21300000, guid: 2ed511dd2a8f5194b9d5f2ba49bbcc8b, type: 3}
|
||||
boneSprite: {fileID: 21300000, guid: b002e339cc2ff924599da592d5a8112f, type: 3}
|
||||
flashSprite: {fileID: 0}
|
||||
flashColor: {r: 1, g: 1, b: 0.8, a: 0.9}
|
||||
flashScale: 35
|
||||
flashDuration: 0.1
|
||||
weaponScale: 25
|
||||
chargeDuration: 0.15
|
||||
impactCount: 2
|
||||
thrustDistance: 35
|
||||
weaponOffset: 50
|
||||
thrustCount: 2
|
||||
thrustDuration: 0.25
|
||||
pullbackDuration: 0.15
|
||||
startOffset: 60
|
||||
endOffset: 15
|
||||
baseRotationOffset: -45
|
||||
shakeIntensity: 12
|
||||
--- !u!114 &2088078294
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -251930,14 +251959,16 @@ MonoBehaviour:
|
||||
coneSprite: {fileID: 7482667652216324306, guid: 32f7f3d380ec1413590676a13c22324c,
|
||||
type: 3}
|
||||
coneColor: {r: 1, g: 1, b: 0.5, a: 0.3}
|
||||
coneLength: 60
|
||||
coneWidth: 40
|
||||
scanSprite: {fileID: -2413806693520163455, guid: 00630274bf61c4899aa743c3fc3d7ccc,
|
||||
coneRotationOffset: 90
|
||||
glowSprite: {fileID: -2413806693520163455, guid: 00630274bf61c4899aa743c3fc3d7ccc,
|
||||
type: 3}
|
||||
scanLineCount: 3
|
||||
scanColor: {r: 1, g: 1, b: 0.8, a: 0.6}
|
||||
scanDuration: 0.6
|
||||
sweepAngle: 30
|
||||
glowColor: {r: 1, g: 1, b: 0.7, a: 0.5}
|
||||
glowStartScale: 10
|
||||
glowEndRadii: 2.5
|
||||
extendDuration: 0.5
|
||||
holdDuration: 0.4
|
||||
fadeDuration: 0.3
|
||||
--- !u!114 &2088078298
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
+137
-217
@@ -7,7 +7,8 @@ using static Net.Eagle0.Shardok.Api.BattalionView.Types;
|
||||
namespace Shardok {
|
||||
/// <summary>
|
||||
/// Animates charge attacks between two hexes.
|
||||
/// Similar to MeleeAnimator but with more dramatic motion for charging units.
|
||||
/// Shows attacker's weapon thrusting toward defender with accelerating motion
|
||||
/// and a violent flash on impact.
|
||||
/// </summary>
|
||||
public class ChargeAnimator : MonoBehaviour {
|
||||
[Header("Weapon Sprites")]
|
||||
@@ -29,28 +30,41 @@ namespace Shardok {
|
||||
[Tooltip("Bone/claw sprite for undead charge")]
|
||||
public Sprite boneSprite;
|
||||
|
||||
[Header("Impact Flash Settings")]
|
||||
[Tooltip("Sprite for impact flash")]
|
||||
public Sprite flashSprite;
|
||||
|
||||
[Tooltip("Color of impact flash")]
|
||||
public Color flashColor = new Color(1f, 1f, 0.8f, 0.9f);
|
||||
|
||||
[Tooltip("Scale of impact flash")]
|
||||
public float flashScale = 35f;
|
||||
|
||||
[Tooltip("Duration of flash")]
|
||||
public float flashDuration = 0.1f;
|
||||
|
||||
[Header("Animation Settings")]
|
||||
[Tooltip("Base scale of weapon sprites")]
|
||||
public float weaponScale = 25.0f;
|
||||
|
||||
[Tooltip("Duration of the charge thrust in seconds")]
|
||||
public float chargeDuration = 0.15f;
|
||||
[Tooltip("Number of thrusts")]
|
||||
public int thrustCount = 2;
|
||||
|
||||
[Tooltip("Number of impact cycles")]
|
||||
public int impactCount = 2;
|
||||
[Tooltip("Duration of each thrust (slow to fast)")]
|
||||
public float thrustDuration = 0.25f;
|
||||
|
||||
[Tooltip("Distance weapons travel toward each other (in local units)")]
|
||||
public float thrustDistance = 35f;
|
||||
[Tooltip("Duration of pullback between thrusts")]
|
||||
public float pullbackDuration = 0.15f;
|
||||
|
||||
[Tooltip("Offset from center point along attack axis (in local units)")]
|
||||
public float weaponOffset = 50f;
|
||||
[Tooltip("Starting position offset from midpoint (in local units)")]
|
||||
public float startOffset = 60f;
|
||||
|
||||
[Tooltip("End position offset from midpoint (in local units)")]
|
||||
public float endOffset = 15f;
|
||||
|
||||
[Tooltip("Base rotation offset for diagonal sprites (degrees)")]
|
||||
public float baseRotationOffset = -45f;
|
||||
|
||||
[Tooltip("Amount of random shake (in local units)")]
|
||||
public float shakeIntensity = 12f;
|
||||
|
||||
private HexGrid __hexGrid;
|
||||
private Coroutine _activeAnimation;
|
||||
|
||||
@@ -59,10 +73,6 @@ namespace Shardok {
|
||||
/// <summary>
|
||||
/// Starts a charge animation between two hex cells.
|
||||
/// </summary>
|
||||
/// <param name="attackerCellIndex">Grid index of the charging hex</param>
|
||||
/// <param name="defenderCellIndex">Grid index of the defending hex</param>
|
||||
/// <param name="attackerType">Battalion type of the attacker</param>
|
||||
/// <param name="defenderType">Battalion type of the defender</param>
|
||||
public void AnimateCharge(
|
||||
int attackerCellIndex,
|
||||
int defenderCellIndex,
|
||||
@@ -79,8 +89,8 @@ namespace Shardok {
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2? attackerPos = __hexGrid.GetCellLocalPosition(attackerCellIndex);
|
||||
Vector2? defenderPos = __hexGrid.GetCellLocalPosition(defenderCellIndex);
|
||||
Vector2? attackerPos = __hexGrid.GetCellCenterPosition(attackerCellIndex);
|
||||
Vector2? defenderPos = __hexGrid.GetCellCenterPosition(defenderCellIndex);
|
||||
|
||||
if (attackerPos == null || defenderPos == null) {
|
||||
Debug.LogWarning(
|
||||
@@ -90,238 +100,148 @@ namespace Shardok {
|
||||
|
||||
if (_activeAnimation != null) { StopCoroutine(_activeAnimation); }
|
||||
|
||||
Debug.Log(
|
||||
$"ChargeAnimator: Starting charge from cell {attackerCellIndex} ({attackerType}) to {defenderCellIndex} ({defenderType})");
|
||||
_activeAnimation = StartCoroutine(AnimateChargeClash(
|
||||
attackerPos.Value,
|
||||
defenderPos.Value,
|
||||
attackerType,
|
||||
defenderType));
|
||||
_activeAnimation = StartCoroutine(
|
||||
AnimateChargeThrusts(attackerPos.Value, defenderPos.Value, attackerType));
|
||||
}
|
||||
|
||||
private struct WeaponConfig {
|
||||
public Sprite sprite;
|
||||
public float scaleMultiplier;
|
||||
public float violenceMultiplier;
|
||||
}
|
||||
|
||||
private WeaponConfig GetWeaponConfig(BattalionTypeId type) {
|
||||
private Sprite GetWeaponSprite(BattalionTypeId type) {
|
||||
switch (type) {
|
||||
case BattalionTypeId.LightInfantry:
|
||||
return new WeaponConfig {
|
||||
sprite = swordSprite,
|
||||
scaleMultiplier = 1.0f,
|
||||
violenceMultiplier = 1.2f
|
||||
};
|
||||
case BattalionTypeId.HeavyInfantry:
|
||||
return new WeaponConfig {
|
||||
sprite = maceSprite ?? swordSprite,
|
||||
scaleMultiplier = 1.2f,
|
||||
violenceMultiplier = 1.4f
|
||||
};
|
||||
case BattalionTypeId.LightInfantry: return swordSprite;
|
||||
case BattalionTypeId.HeavyInfantry: return maceSprite ?? swordSprite;
|
||||
case BattalionTypeId.LightCavalry:
|
||||
return new WeaponConfig {
|
||||
sprite = smallSpearSprite ?? largeLanceSprite ?? swordSprite,
|
||||
scaleMultiplier = 1.1f,
|
||||
violenceMultiplier = 1.6f
|
||||
};
|
||||
return smallSpearSprite ?? largeLanceSprite ?? swordSprite;
|
||||
case BattalionTypeId.HeavyCavalry:
|
||||
return new WeaponConfig {
|
||||
sprite = largeLanceSprite ?? smallSpearSprite ?? swordSprite,
|
||||
scaleMultiplier = 1.4f,
|
||||
violenceMultiplier = 2.0f
|
||||
};
|
||||
case BattalionTypeId.Longbowmen:
|
||||
return new WeaponConfig {
|
||||
sprite = daggerSprite ?? swordSprite,
|
||||
scaleMultiplier = 0.8f,
|
||||
violenceMultiplier = 1.0f
|
||||
};
|
||||
case BattalionTypeId.Undead:
|
||||
return new WeaponConfig {
|
||||
sprite = boneSprite ?? swordSprite,
|
||||
scaleMultiplier = 1.0f,
|
||||
violenceMultiplier = 1.3f
|
||||
};
|
||||
default:
|
||||
return new WeaponConfig {
|
||||
sprite = swordSprite,
|
||||
scaleMultiplier = 1.0f,
|
||||
violenceMultiplier = 1.2f
|
||||
};
|
||||
return largeLanceSprite ?? smallSpearSprite ?? swordSprite;
|
||||
case BattalionTypeId.Longbowmen: return daggerSprite ?? swordSprite;
|
||||
case BattalionTypeId.Undead: return boneSprite ?? swordSprite;
|
||||
default: return swordSprite;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator AnimateChargeClash(
|
||||
private float GetScaleMultiplier(BattalionTypeId type) {
|
||||
switch (type) {
|
||||
case BattalionTypeId.HeavyInfantry: return 1.2f;
|
||||
case BattalionTypeId.LightCavalry: return 1.1f;
|
||||
case BattalionTypeId.HeavyCavalry: return 1.4f;
|
||||
case BattalionTypeId.Longbowmen: return 0.8f;
|
||||
default: return 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator AnimateChargeThrusts(
|
||||
Vector2 attackerPos,
|
||||
Vector2 defenderPos,
|
||||
BattalionTypeId attackerType,
|
||||
BattalionTypeId defenderType) {
|
||||
// Calculate midpoint and direction
|
||||
BattalionTypeId attackerType) {
|
||||
// Calculate direction toward defender
|
||||
Vector2 midpoint = (attackerPos + defenderPos) / 2f;
|
||||
Vector2 direction = (defenderPos - attackerPos).normalized;
|
||||
float baseAngle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
|
||||
|
||||
// Get weapon configs
|
||||
WeaponConfig attackerConfig = GetWeaponConfig(attackerType);
|
||||
WeaponConfig defenderConfig = GetWeaponConfig(defenderType);
|
||||
// Create attacker weapon
|
||||
Sprite weaponSprite = GetWeaponSprite(attackerType);
|
||||
float scale = weaponScale * GetScaleMultiplier(attackerType);
|
||||
|
||||
// Create weapons
|
||||
GameObject attackerWeapon = CreateWeapon(attackerConfig, baseAngle);
|
||||
GameObject defenderWeapon = CreateWeapon(defenderConfig, baseAngle + 180f);
|
||||
|
||||
float attackerViolence = shakeIntensity * attackerConfig.violenceMultiplier;
|
||||
float defenderViolence = shakeIntensity * defenderConfig.violenceMultiplier;
|
||||
|
||||
// Starting positions offset from midpoint (further back for charge buildup)
|
||||
Vector3 attackerStart = new Vector3(
|
||||
midpoint.x - direction.x * weaponOffset,
|
||||
midpoint.y - direction.y * weaponOffset,
|
||||
10f);
|
||||
Vector3 defenderStart = new Vector3(
|
||||
midpoint.x + direction.x * weaponOffset,
|
||||
midpoint.y + direction.y * weaponOffset,
|
||||
10f);
|
||||
|
||||
// Clash point (closer to midpoint)
|
||||
Vector3 attackerClash = new Vector3(
|
||||
midpoint.x - direction.x * (weaponOffset - thrustDistance),
|
||||
midpoint.y - direction.y * (weaponOffset - thrustDistance),
|
||||
10f);
|
||||
Vector3 defenderClash = new Vector3(
|
||||
midpoint.x + direction.x * (weaponOffset - thrustDistance),
|
||||
midpoint.y + direction.y * (weaponOffset - thrustDistance),
|
||||
10f);
|
||||
|
||||
attackerWeapon.transform.localPosition = attackerStart;
|
||||
defenderWeapon.transform.localPosition = defenderStart;
|
||||
|
||||
// Animate impact cycles
|
||||
for (int i = 0; i < impactCount; i++) {
|
||||
// Charge thrust toward clash point
|
||||
yield return StartCoroutine(AnimateWeaponThrust(
|
||||
attackerWeapon,
|
||||
attackerStart,
|
||||
attackerClash,
|
||||
chargeDuration / 2f,
|
||||
true,
|
||||
attackerViolence));
|
||||
|
||||
yield return StartCoroutine(AnimateWeaponThrust(
|
||||
defenderWeapon,
|
||||
defenderStart,
|
||||
defenderClash,
|
||||
chargeDuration / 2f,
|
||||
true,
|
||||
defenderViolence));
|
||||
|
||||
// Violent impact shake
|
||||
float impactViolence = Mathf.Max(attackerViolence, defenderViolence);
|
||||
yield return StartCoroutine(ImpactShake(
|
||||
attackerWeapon,
|
||||
defenderWeapon,
|
||||
attackerClash,
|
||||
defenderClash,
|
||||
0.08f,
|
||||
impactViolence));
|
||||
|
||||
// Pull back
|
||||
yield return StartCoroutine(AnimateWeaponThrust(
|
||||
attackerWeapon,
|
||||
attackerClash,
|
||||
attackerStart,
|
||||
chargeDuration / 2f,
|
||||
false,
|
||||
attackerViolence * 0.5f));
|
||||
|
||||
yield return StartCoroutine(AnimateWeaponThrust(
|
||||
defenderWeapon,
|
||||
defenderClash,
|
||||
defenderStart,
|
||||
chargeDuration / 2f,
|
||||
false,
|
||||
defenderViolence * 0.5f));
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
if (attackerWeapon != null) { Destroy(attackerWeapon); }
|
||||
if (defenderWeapon != null) { Destroy(defenderWeapon); }
|
||||
_activeAnimation = null;
|
||||
}
|
||||
|
||||
private GameObject CreateWeapon(WeaponConfig config, float angle) {
|
||||
GameObject weapon = new GameObject("ChargeWeapon");
|
||||
weapon.transform.SetParent(__hexGrid.gridCanvas.transform, false);
|
||||
|
||||
SpriteRenderer renderer = weapon.AddComponent<SpriteRenderer>();
|
||||
renderer.sprite = config.sprite;
|
||||
renderer.sprite = weaponSprite;
|
||||
renderer.sortingLayerName = "Effects";
|
||||
|
||||
weapon.transform.localRotation = Quaternion.Euler(0, 0, angle + baseRotationOffset);
|
||||
float scale = weaponScale * config.scaleMultiplier;
|
||||
weapon.transform.localRotation = Quaternion.Euler(0, 0, baseAngle + baseRotationOffset);
|
||||
weapon.transform.localScale = new Vector3(scale, scale, scale);
|
||||
|
||||
return weapon;
|
||||
// Calculate positions
|
||||
Vector3 startPos = new Vector3(
|
||||
midpoint.x - direction.x * startOffset,
|
||||
midpoint.y - direction.y * startOffset,
|
||||
10f);
|
||||
Vector3 endPos = new Vector3(
|
||||
midpoint.x + direction.x * endOffset,
|
||||
midpoint.y + direction.y * endOffset,
|
||||
10f);
|
||||
|
||||
weapon.transform.localPosition = startPos;
|
||||
|
||||
// Animate thrusts
|
||||
for (int i = 0; i < thrustCount; i++) {
|
||||
// Thrust forward - starts slow, accelerates
|
||||
float elapsed = 0f;
|
||||
while (elapsed < thrustDuration) {
|
||||
if (weapon == null) yield break;
|
||||
|
||||
float t = elapsed / thrustDuration;
|
||||
// Cubic ease-in for accelerating thrust
|
||||
float easeT = t * t * t;
|
||||
|
||||
weapon.transform.localPosition = Vector3.Lerp(startPos, endPos, easeT);
|
||||
|
||||
elapsed += Time.deltaTime;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
weapon.transform.localPosition = endPos;
|
||||
|
||||
// Impact flash
|
||||
if (flashSprite != null) {
|
||||
yield return StartCoroutine(ShowImpactFlash(endPos, direction));
|
||||
}
|
||||
|
||||
// Pullback - smooth ease out
|
||||
elapsed = 0f;
|
||||
while (elapsed < pullbackDuration) {
|
||||
if (weapon == null) yield break;
|
||||
|
||||
float t = elapsed / pullbackDuration;
|
||||
// Ease out for smooth pullback
|
||||
float easeT = t * (2f - t);
|
||||
|
||||
weapon.transform.localPosition = Vector3.Lerp(endPos, startPos, easeT);
|
||||
|
||||
elapsed += Time.deltaTime;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
weapon.transform.localPosition = startPos;
|
||||
|
||||
// Brief pause between thrusts
|
||||
if (i < thrustCount - 1) { yield return new WaitForSeconds(0.05f); }
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
if (weapon != null) { Destroy(weapon); }
|
||||
_activeAnimation = null;
|
||||
}
|
||||
|
||||
private IEnumerator AnimateWeaponThrust(
|
||||
GameObject weapon,
|
||||
Vector3 fromPos,
|
||||
Vector3 toPos,
|
||||
float duration,
|
||||
bool isCharging,
|
||||
float violence) {
|
||||
private IEnumerator ShowImpactFlash(Vector3 position, Vector2 direction) {
|
||||
GameObject flash = new GameObject("ChargeFlash");
|
||||
flash.transform.SetParent(__hexGrid.gridCanvas.transform, false);
|
||||
flash.transform.localPosition = position;
|
||||
|
||||
SpriteRenderer renderer = flash.AddComponent<SpriteRenderer>();
|
||||
renderer.sprite = flashSprite;
|
||||
renderer.sortingLayerName = "Effects";
|
||||
renderer.color = flashColor;
|
||||
|
||||
float elapsed = 0f;
|
||||
while (elapsed < flashDuration) {
|
||||
float t = elapsed / flashDuration;
|
||||
|
||||
while (elapsed < duration) {
|
||||
if (weapon == null) { yield break; }
|
||||
// Quick expand then fade
|
||||
float expandT = t < 0.3f ? t / 0.3f : 1f;
|
||||
float scale = flashScale * (0.5f + 0.5f * expandT);
|
||||
flash.transform.localScale = Vector3.one * scale;
|
||||
|
||||
float t = elapsed / duration;
|
||||
// More aggressive ease for charge, smoother for retreat
|
||||
float smoothT = isCharging ? t * t * t : t * (2f - t);
|
||||
|
||||
// Position with shake
|
||||
Vector3 shake = new Vector3(
|
||||
Random.Range(-violence, violence),
|
||||
Random.Range(-violence, violence),
|
||||
0f);
|
||||
weapon.transform.localPosition = Vector3.Lerp(fromPos, toPos, smoothT) + shake;
|
||||
// Fade out
|
||||
Color c = flashColor;
|
||||
c.a = flashColor.a * (1f - t);
|
||||
renderer.color = c;
|
||||
|
||||
elapsed += Time.deltaTime;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
if (weapon != null) { weapon.transform.localPosition = toPos; }
|
||||
}
|
||||
|
||||
private IEnumerator ImpactShake(
|
||||
GameObject weapon1,
|
||||
GameObject weapon2,
|
||||
Vector3 pos1,
|
||||
Vector3 pos2,
|
||||
float duration,
|
||||
float violence) {
|
||||
float elapsed = 0f;
|
||||
float intensity = violence * 2.5f; // Extra intense for charge impact
|
||||
|
||||
while (elapsed < duration) {
|
||||
if (weapon1 == null || weapon2 == null) { yield break; }
|
||||
|
||||
Vector3 shake1 = new Vector3(
|
||||
Random.Range(-intensity, intensity),
|
||||
Random.Range(-intensity, intensity),
|
||||
0f);
|
||||
Vector3 shake2 = new Vector3(
|
||||
Random.Range(-intensity, intensity),
|
||||
Random.Range(-intensity, intensity),
|
||||
0f);
|
||||
|
||||
weapon1.transform.localPosition = pos1 + shake1;
|
||||
weapon2.transform.localPosition = pos2 + shake2;
|
||||
|
||||
elapsed += Time.deltaTime;
|
||||
yield return null;
|
||||
}
|
||||
Destroy(flash);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -18,11 +18,11 @@ namespace Shardok {
|
||||
[Tooltip("Mace/hammer sprite for heavy infantry")]
|
||||
public Sprite maceSprite;
|
||||
|
||||
[Tooltip("Small spear sprite for light cavalry")]
|
||||
public Sprite smallSpearSprite;
|
||||
[Tooltip("Falchion sprite for light cavalry")]
|
||||
public Sprite falchionSprite;
|
||||
|
||||
[Tooltip("Large spear/lance sprite for heavy cavalry")]
|
||||
public Sprite largeSpearSprite;
|
||||
[Tooltip("Two-handed sword sprite for heavy cavalry")]
|
||||
public Sprite twoHandedSwordSprite;
|
||||
|
||||
[Tooltip("Dagger sprite for longbowmen")]
|
||||
public Sprite daggerSprite;
|
||||
@@ -30,15 +30,57 @@ namespace Shardok {
|
||||
[Tooltip("Bone/fist sprite for undead")]
|
||||
public Sprite boneSprite;
|
||||
|
||||
[Header("Weapon Orientation - Sword")]
|
||||
[Tooltip("Base rotation offset for sword (degrees)")]
|
||||
public float swordRotationOffset = -45f;
|
||||
|
||||
[Tooltip("Flip sword horizontally")]
|
||||
public bool swordFlipHorizontal = false;
|
||||
|
||||
[Header("Weapon Orientation - Mace")]
|
||||
[Tooltip("Base rotation offset for mace (degrees)")]
|
||||
public float maceRotationOffset = -45f;
|
||||
|
||||
[Tooltip("Flip mace horizontally")]
|
||||
public bool maceFlipHorizontal = false;
|
||||
|
||||
[Header("Weapon Orientation - Falchion")]
|
||||
[Tooltip("Base rotation offset for falchion (degrees)")]
|
||||
public float falchionRotationOffset = -45f;
|
||||
|
||||
[Tooltip("Flip falchion horizontally")]
|
||||
public bool falchionFlipHorizontal = false;
|
||||
|
||||
[Header("Weapon Orientation - Two-Handed Sword")]
|
||||
[Tooltip("Base rotation offset for two-handed sword (degrees)")]
|
||||
public float twoHandedSwordRotationOffset = -45f;
|
||||
|
||||
[Tooltip("Flip two-handed sword horizontally")]
|
||||
public bool twoHandedSwordFlipHorizontal = false;
|
||||
|
||||
[Header("Weapon Orientation - Dagger")]
|
||||
[Tooltip("Base rotation offset for dagger (degrees)")]
|
||||
public float daggerRotationOffset = -45f;
|
||||
|
||||
[Tooltip("Flip dagger horizontally")]
|
||||
public bool daggerFlipHorizontal = false;
|
||||
|
||||
[Header("Weapon Orientation - Bone")]
|
||||
[Tooltip("Base rotation offset for bone (degrees)")]
|
||||
public float boneRotationOffset = -45f;
|
||||
|
||||
[Tooltip("Flip bone horizontally")]
|
||||
public bool boneFlipHorizontal = false;
|
||||
|
||||
[Header("Animation Settings")]
|
||||
[Tooltip("Base scale of weapon sprites")]
|
||||
public float weaponScale = 20.0f;
|
||||
|
||||
[Tooltip("Duration of a single clash cycle in seconds")]
|
||||
public float clashDuration = 0.12f;
|
||||
[Tooltip("Duration of a single swing cycle in seconds")]
|
||||
public float clashDuration = 0.3f;
|
||||
|
||||
[Tooltip("Number of clash cycles")]
|
||||
public int clashCount = 3;
|
||||
[Tooltip("Number of swing cycles")]
|
||||
public int clashCount = 2;
|
||||
|
||||
[Tooltip("Distance weapons travel toward each other (in local units)")]
|
||||
public float thrustDistance = 25f;
|
||||
@@ -46,14 +88,11 @@ namespace Shardok {
|
||||
[Tooltip("Offset from center point along attack axis (in local units)")]
|
||||
public float weaponOffset = 40f;
|
||||
|
||||
[Tooltip("Base rotation offset for diagonal sprites (degrees)")]
|
||||
public float baseRotationOffset = -45f;
|
||||
|
||||
[Tooltip("Swing arc angle for swinging weapons (degrees)")]
|
||||
public float swingArc = 60f;
|
||||
public float swingArc = 90f;
|
||||
|
||||
[Tooltip("Amount of random shake (in local units)")]
|
||||
public float shakeIntensity = 8f;
|
||||
[Tooltip("Amount of shake at impact only (in local units)")]
|
||||
public float shakeIntensity = 3f;
|
||||
|
||||
private HexGrid __hexGrid;
|
||||
private Coroutine _activeAnimation;
|
||||
@@ -72,8 +111,8 @@ namespace Shardok {
|
||||
int defenderCellIndex,
|
||||
BattalionTypeId attackerType,
|
||||
BattalionTypeId defenderType) {
|
||||
if (swordSprite == null && maceSprite == null && smallSpearSprite == null &&
|
||||
largeSpearSprite == null && daggerSprite == null && boneSprite == null) {
|
||||
if (swordSprite == null && maceSprite == null && falchionSprite == null &&
|
||||
twoHandedSwordSprite == null && daggerSprite == null && boneSprite == null) {
|
||||
Debug.LogWarning("MeleeAnimator: No weapon sprites assigned");
|
||||
return;
|
||||
}
|
||||
@@ -104,7 +143,8 @@ namespace Shardok {
|
||||
public Sprite sprite;
|
||||
public bool swings; // true = swing arc, false = thrust
|
||||
public float scaleMultiplier;
|
||||
public float violenceMultiplier; // shake intensity multiplier
|
||||
public float rotationOffset;
|
||||
public bool flipHorizontal;
|
||||
}
|
||||
|
||||
private WeaponConfig GetWeaponConfig(BattalionTypeId type) {
|
||||
@@ -114,49 +154,66 @@ namespace Shardok {
|
||||
sprite = swordSprite,
|
||||
swings = true,
|
||||
scaleMultiplier = 1.0f,
|
||||
violenceMultiplier = 0.3f
|
||||
rotationOffset = swordRotationOffset,
|
||||
flipHorizontal = swordFlipHorizontal
|
||||
};
|
||||
case BattalionTypeId.HeavyInfantry:
|
||||
return new WeaponConfig {
|
||||
sprite = maceSprite ?? swordSprite,
|
||||
swings = true,
|
||||
scaleMultiplier = 1.2f,
|
||||
violenceMultiplier = 0.4f
|
||||
rotationOffset =
|
||||
maceSprite != null ? maceRotationOffset : swordRotationOffset,
|
||||
flipHorizontal =
|
||||
maceSprite != null ? maceFlipHorizontal : swordFlipHorizontal
|
||||
};
|
||||
case BattalionTypeId.LightCavalry:
|
||||
return new WeaponConfig {
|
||||
sprite = smallSpearSprite ?? largeSpearSprite ?? swordSprite,
|
||||
swings = false,
|
||||
scaleMultiplier = 0.9f,
|
||||
violenceMultiplier = 1.0f
|
||||
sprite = falchionSprite ?? swordSprite,
|
||||
swings = true,
|
||||
scaleMultiplier = 1.0f,
|
||||
rotationOffset = falchionSprite != null ? falchionRotationOffset
|
||||
: swordRotationOffset,
|
||||
flipHorizontal = falchionSprite != null ? falchionFlipHorizontal
|
||||
: swordFlipHorizontal
|
||||
};
|
||||
case BattalionTypeId.HeavyCavalry:
|
||||
return new WeaponConfig {
|
||||
sprite = largeSpearSprite ?? smallSpearSprite ?? swordSprite,
|
||||
swings = false,
|
||||
sprite = twoHandedSwordSprite ?? swordSprite,
|
||||
swings = true,
|
||||
scaleMultiplier = 1.4f,
|
||||
violenceMultiplier = 1.8f
|
||||
rotationOffset = twoHandedSwordSprite != null ? twoHandedSwordRotationOffset
|
||||
: swordRotationOffset,
|
||||
flipHorizontal = twoHandedSwordSprite != null ? twoHandedSwordFlipHorizontal
|
||||
: swordFlipHorizontal
|
||||
};
|
||||
case BattalionTypeId.Longbowmen:
|
||||
return new WeaponConfig {
|
||||
sprite = daggerSprite ?? swordSprite,
|
||||
swings = false,
|
||||
scaleMultiplier = 0.7f,
|
||||
violenceMultiplier = 0.8f
|
||||
rotationOffset =
|
||||
daggerSprite != null ? daggerRotationOffset : swordRotationOffset,
|
||||
flipHorizontal =
|
||||
daggerSprite != null ? daggerFlipHorizontal : swordFlipHorizontal
|
||||
};
|
||||
case BattalionTypeId.Undead:
|
||||
return new WeaponConfig {
|
||||
sprite = boneSprite ?? swordSprite,
|
||||
swings = true,
|
||||
scaleMultiplier = 1.0f,
|
||||
violenceMultiplier = 0.5f
|
||||
rotationOffset =
|
||||
boneSprite != null ? boneRotationOffset : swordRotationOffset,
|
||||
flipHorizontal =
|
||||
boneSprite != null ? boneFlipHorizontal : swordFlipHorizontal
|
||||
};
|
||||
default:
|
||||
return new WeaponConfig {
|
||||
sprite = swordSprite,
|
||||
swings = true,
|
||||
scaleMultiplier = 1.0f,
|
||||
violenceMultiplier = 0.3f
|
||||
rotationOffset = swordRotationOffset,
|
||||
flipHorizontal = swordFlipHorizontal
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -181,8 +238,6 @@ namespace Shardok {
|
||||
|
||||
bool attackerSwings = attackerConfig.swings;
|
||||
bool defenderSwings = defenderConfig.swings;
|
||||
float attackerViolence = shakeIntensity * attackerConfig.violenceMultiplier;
|
||||
float defenderViolence = shakeIntensity * defenderConfig.violenceMultiplier;
|
||||
|
||||
// Starting positions offset from midpoint
|
||||
Vector3 attackerStart = new Vector3(
|
||||
@@ -207,15 +262,15 @@ namespace Shardok {
|
||||
attackerWeapon.transform.localPosition = attackerStart;
|
||||
defenderWeapon.transform.localPosition = defenderStart;
|
||||
|
||||
float attackerBaseAngle = baseAngle + baseRotationOffset;
|
||||
float defenderBaseAngle = baseAngle + 180f + baseRotationOffset;
|
||||
float attackerBaseAngle = baseAngle + attackerConfig.rotationOffset;
|
||||
float defenderBaseAngle = baseAngle + 180f + defenderConfig.rotationOffset;
|
||||
|
||||
// Animate clash cycles with alternating swing directions
|
||||
// Animate swing cycles with alternating swing directions
|
||||
for (int i = 0; i < clashCount; i++) {
|
||||
// Alternate swing direction each cycle
|
||||
float swingDirection = (i % 2 == 0) ? 1f : -1f;
|
||||
|
||||
// Swing/thrust toward clash point
|
||||
// Swing toward clash point
|
||||
yield return StartCoroutine(AnimateWeaponSwing(
|
||||
attackerWeapon,
|
||||
attackerStart,
|
||||
@@ -224,8 +279,7 @@ namespace Shardok {
|
||||
attackerSwings ? -swingArc * swingDirection : 0f,
|
||||
attackerSwings ? 0f : 0f,
|
||||
clashDuration / 2f,
|
||||
true,
|
||||
attackerViolence));
|
||||
true));
|
||||
|
||||
yield return StartCoroutine(AnimateWeaponSwing(
|
||||
defenderWeapon,
|
||||
@@ -235,20 +289,18 @@ namespace Shardok {
|
||||
defenderSwings ? swingArc * swingDirection : 0f,
|
||||
defenderSwings ? 0f : 0f,
|
||||
clashDuration / 2f,
|
||||
true,
|
||||
defenderViolence));
|
||||
true));
|
||||
|
||||
// Brief violent shake at impact (use max violence of both)
|
||||
float impactViolence = Mathf.Max(attackerViolence, defenderViolence);
|
||||
// Brief shake at impact
|
||||
yield return StartCoroutine(ImpactShake(
|
||||
attackerWeapon,
|
||||
defenderWeapon,
|
||||
attackerClash,
|
||||
defenderClash,
|
||||
0.05f,
|
||||
impactViolence));
|
||||
shakeIntensity));
|
||||
|
||||
// Swing/pull back
|
||||
// Swing back
|
||||
yield return StartCoroutine(AnimateWeaponSwing(
|
||||
attackerWeapon,
|
||||
attackerClash,
|
||||
@@ -257,8 +309,7 @@ namespace Shardok {
|
||||
0f,
|
||||
attackerSwings ? -swingArc * swingDirection : 0f,
|
||||
clashDuration / 2f,
|
||||
false,
|
||||
attackerViolence));
|
||||
false));
|
||||
|
||||
yield return StartCoroutine(AnimateWeaponSwing(
|
||||
defenderWeapon,
|
||||
@@ -268,8 +319,7 @@ namespace Shardok {
|
||||
0f,
|
||||
defenderSwings ? swingArc * swingDirection : 0f,
|
||||
clashDuration / 2f,
|
||||
false,
|
||||
defenderViolence));
|
||||
false));
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
@@ -286,9 +336,10 @@ namespace Shardok {
|
||||
renderer.sprite = config.sprite;
|
||||
renderer.sortingLayerName = "Effects";
|
||||
|
||||
weapon.transform.localRotation = Quaternion.Euler(0, 0, angle + baseRotationOffset);
|
||||
weapon.transform.localRotation = Quaternion.Euler(0, 0, angle + config.rotationOffset);
|
||||
float scale = weaponScale * config.scaleMultiplier;
|
||||
weapon.transform.localScale = new Vector3(scale, scale, scale);
|
||||
float xScale = config.flipHorizontal ? -scale : scale;
|
||||
weapon.transform.localScale = new Vector3(xScale, scale, scale);
|
||||
|
||||
return weapon;
|
||||
}
|
||||
@@ -301,25 +352,20 @@ namespace Shardok {
|
||||
float fromAngleOffset,
|
||||
float toAngleOffset,
|
||||
float duration,
|
||||
bool isAttacking,
|
||||
float violence) {
|
||||
bool isAttacking) {
|
||||
float elapsed = 0f;
|
||||
|
||||
while (elapsed < duration) {
|
||||
if (weapon == null) { yield break; }
|
||||
|
||||
float t = elapsed / duration;
|
||||
// Aggressive ease for attack, smoother for retreat
|
||||
// Smooth ease for deliberate swing motion
|
||||
float smoothT = isAttacking ? t * t * (3f - 2f * t) : t * (2f - t);
|
||||
|
||||
// Position with shake (scaled by violence)
|
||||
Vector3 shake = new Vector3(
|
||||
Random.Range(-violence, violence),
|
||||
Random.Range(-violence, violence),
|
||||
0f);
|
||||
weapon.transform.localPosition = Vector3.Lerp(fromPos, toPos, smoothT) + shake;
|
||||
// Clean position interpolation - no shake during swing
|
||||
weapon.transform.localPosition = Vector3.Lerp(fromPos, toPos, smoothT);
|
||||
|
||||
// Rotation (for swinging weapons)
|
||||
// Rotation arc for swinging weapons
|
||||
float currentAngle =
|
||||
Mathf.Lerp(baseAngle + fromAngleOffset, baseAngle + toAngleOffset, smoothT);
|
||||
weapon.transform.localRotation = Quaternion.Euler(0, 0, currentAngle);
|
||||
|
||||
@@ -56,6 +56,42 @@ namespace Shardok {
|
||||
[Tooltip("Spark spread distance")]
|
||||
public float sparkSpread = 40f;
|
||||
|
||||
[Header("Charging Settings (MeteorStart)")]
|
||||
[Tooltip("Sprite for charging glow")]
|
||||
public Sprite chargeSprite;
|
||||
|
||||
[Tooltip("Color of charging effect")]
|
||||
public Color chargeColor = new Color(1f, 0.6f, 0.2f, 0.7f);
|
||||
|
||||
[Tooltip("Starting scale of charge glow")]
|
||||
public float chargeStartScale = 5f;
|
||||
|
||||
[Tooltip("Ending scale of charge glow")]
|
||||
public float chargeEndScale = 25f;
|
||||
|
||||
[Tooltip("Duration of charge animation")]
|
||||
public float chargeDuration = 0.5f;
|
||||
|
||||
[Header("Targeting Settings (MeteorTarget)")]
|
||||
[Tooltip("Sprite for target indicator")]
|
||||
public Sprite targetSprite;
|
||||
|
||||
[Tooltip("Color of target indicator")]
|
||||
public Color targetColor = new Color(1f, 0.3f, 0.1f, 0.6f);
|
||||
|
||||
[Tooltip("Scale of target indicator")]
|
||||
public float targetScale = 30f;
|
||||
|
||||
[Tooltip("Duration of target animation")]
|
||||
public float targetDuration = 0.4f;
|
||||
|
||||
[Header("Cancel Settings (MeteorCancel)")]
|
||||
[Tooltip("Color of fizzle effect")]
|
||||
public Color cancelColor = new Color(0.5f, 0.5f, 0.5f, 0.8f);
|
||||
|
||||
[Tooltip("Duration of cancel animation")]
|
||||
public float cancelDuration = 0.3f;
|
||||
|
||||
[Header("Animation Settings")]
|
||||
[Tooltip("Duration of meteor fall")]
|
||||
public float fallDuration = 0.4f;
|
||||
@@ -87,6 +123,315 @@ namespace Shardok {
|
||||
StartCoroutine(AnimateMeteor(targetPos.Value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Animates meteor charging effect at the caster's position.
|
||||
/// Shows a growing fiery glow gathering energy.
|
||||
/// </summary>
|
||||
public void AnimateMeteorStart(int sourceCellIndex) {
|
||||
if (__hexGrid == null || __hexGrid.gridCanvas == null) {
|
||||
Debug.LogWarning("MeteorAnimator: No _hexGrid or gridCanvas available");
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2? sourcePos = __hexGrid.GetCellCenterPosition(sourceCellIndex);
|
||||
|
||||
if (sourcePos == null) {
|
||||
Debug.LogWarning($"MeteorAnimator: Invalid cell index {sourceCellIndex}");
|
||||
return;
|
||||
}
|
||||
|
||||
StartCoroutine(AnimateCharge(sourcePos.Value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Animates meteor targeting indicator at destination.
|
||||
/// Shows a pulsing circle/crosshairs marking the target.
|
||||
/// </summary>
|
||||
public void AnimateMeteorTarget(int targetCellIndex) {
|
||||
if (__hexGrid == null || __hexGrid.gridCanvas == null) {
|
||||
Debug.LogWarning("MeteorAnimator: No _hexGrid or gridCanvas available");
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2? targetPos = __hexGrid.GetCellCenterPosition(targetCellIndex);
|
||||
|
||||
if (targetPos == null) {
|
||||
Debug.LogWarning($"MeteorAnimator: Invalid cell index {targetCellIndex}");
|
||||
return;
|
||||
}
|
||||
|
||||
StartCoroutine(AnimateTarget(targetPos.Value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Animates meteor cancel/fizzle effect at the caster's position.
|
||||
/// Shows the charging energy dissipating.
|
||||
/// </summary>
|
||||
public void AnimateMeteorCancel(int sourceCellIndex) {
|
||||
if (__hexGrid == null || __hexGrid.gridCanvas == null) {
|
||||
Debug.LogWarning("MeteorAnimator: No _hexGrid or gridCanvas available");
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2? sourcePos = __hexGrid.GetCellCenterPosition(sourceCellIndex);
|
||||
|
||||
if (sourcePos == null) {
|
||||
Debug.LogWarning($"MeteorAnimator: Invalid cell index {sourceCellIndex}");
|
||||
return;
|
||||
}
|
||||
|
||||
StartCoroutine(AnimateCancel(sourcePos.Value));
|
||||
}
|
||||
|
||||
private IEnumerator AnimateCharge(Vector2 source) {
|
||||
Sprite sprite = chargeSprite ?? explosionSprite;
|
||||
if (sprite == null) yield break;
|
||||
|
||||
// Create charging glow
|
||||
GameObject glow = new GameObject("MeteorCharge");
|
||||
glow.transform.SetParent(__hexGrid.gridCanvas.transform, false);
|
||||
glow.transform.localPosition = new Vector3(source.x, source.y, 5f);
|
||||
|
||||
SpriteRenderer renderer = glow.AddComponent<SpriteRenderer>();
|
||||
renderer.sprite = sprite;
|
||||
renderer.sortingLayerName = "Effects";
|
||||
renderer.color = chargeColor;
|
||||
|
||||
// Create rising particles
|
||||
int particleCount = 5;
|
||||
GameObject[] particles = new GameObject[particleCount];
|
||||
Vector2[] particleOffsets = new Vector2[particleCount];
|
||||
|
||||
for (int i = 0; i < particleCount; i++) {
|
||||
if (trailSprite == null) break;
|
||||
|
||||
GameObject particle = new GameObject($"ChargeParticle_{i}");
|
||||
particle.transform.SetParent(__hexGrid.gridCanvas.transform, false);
|
||||
|
||||
SpriteRenderer pRenderer = particle.AddComponent<SpriteRenderer>();
|
||||
pRenderer.sprite = trailSprite;
|
||||
pRenderer.sortingLayerName = "Effects";
|
||||
pRenderer.color = chargeColor;
|
||||
particle.transform.localScale = Vector3.one * trailScale;
|
||||
|
||||
float angle = (float)i / particleCount * Mathf.PI * 2f;
|
||||
particleOffsets[i] = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * 20f;
|
||||
particles[i] = particle;
|
||||
}
|
||||
|
||||
// Animation
|
||||
float elapsed = 0f;
|
||||
while (elapsed < chargeDuration) {
|
||||
float t = elapsed / chargeDuration;
|
||||
float easeT = t * (2f - t); // Ease out
|
||||
|
||||
// Grow glow
|
||||
float scale = Mathf.Lerp(chargeStartScale, chargeEndScale, easeT);
|
||||
glow.transform.localScale = Vector3.one * scale;
|
||||
|
||||
// Pulse alpha
|
||||
Color c = chargeColor;
|
||||
c.a = chargeColor.a * (0.7f + 0.3f * Mathf.Sin(elapsed * 12f));
|
||||
renderer.color = c;
|
||||
|
||||
// Particles spiral inward and upward
|
||||
for (int i = 0; i < particles.Length; i++) {
|
||||
if (particles[i] == null) continue;
|
||||
|
||||
float particleT = (t + (float)i / particleCount) % 1f;
|
||||
float radius = 20f * (1f - particleT);
|
||||
float angle =
|
||||
particleT * Mathf.PI * 4f + (float)i / particleCount * Mathf.PI * 2f;
|
||||
Vector2 offset = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * radius;
|
||||
|
||||
particles[i].transform.localPosition = new Vector3(
|
||||
source.x + offset.x,
|
||||
source.y + offset.y + particleT * 15f,
|
||||
4f);
|
||||
|
||||
var pRenderer = particles[i].GetComponent<SpriteRenderer>();
|
||||
if (pRenderer != null) {
|
||||
Color pc = chargeColor;
|
||||
pc.a = chargeColor.a * (1f - particleT * 0.5f);
|
||||
pRenderer.color = pc;
|
||||
}
|
||||
}
|
||||
|
||||
elapsed += Time.deltaTime;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// Brief flash at end
|
||||
glow.transform.localScale = Vector3.one * chargeEndScale * 1.2f;
|
||||
Color flashColor = chargeColor;
|
||||
flashColor.a = 1f;
|
||||
renderer.color = flashColor;
|
||||
yield return new WaitForSeconds(0.05f);
|
||||
|
||||
// Cleanup
|
||||
Destroy(glow);
|
||||
foreach (var p in particles) {
|
||||
if (p != null) Destroy(p);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator AnimateTarget(Vector2 target) {
|
||||
Sprite sprite = targetSprite ?? explosionSprite;
|
||||
if (sprite == null) yield break;
|
||||
|
||||
// Create target indicator
|
||||
GameObject indicator = new GameObject("MeteorTarget");
|
||||
indicator.transform.SetParent(__hexGrid.gridCanvas.transform, false);
|
||||
indicator.transform.localPosition = new Vector3(target.x, target.y, 5f);
|
||||
|
||||
SpriteRenderer renderer = indicator.AddComponent<SpriteRenderer>();
|
||||
renderer.sprite = sprite;
|
||||
renderer.sortingLayerName = "Effects";
|
||||
renderer.color = targetColor;
|
||||
|
||||
// Create outer ring that contracts
|
||||
GameObject ring = null;
|
||||
SpriteRenderer ringRenderer = null;
|
||||
if (sprite != null) {
|
||||
ring = new GameObject("TargetRing");
|
||||
ring.transform.SetParent(__hexGrid.gridCanvas.transform, false);
|
||||
ring.transform.localPosition = new Vector3(target.x, target.y, 6f);
|
||||
|
||||
ringRenderer = ring.AddComponent<SpriteRenderer>();
|
||||
ringRenderer.sprite = sprite;
|
||||
ringRenderer.sortingLayerName = "Effects";
|
||||
Color ringColor = targetColor;
|
||||
ringColor.a = targetColor.a * 0.5f;
|
||||
ringRenderer.color = ringColor;
|
||||
}
|
||||
|
||||
// Animation - indicator appears, ring contracts to it
|
||||
float elapsed = 0f;
|
||||
while (elapsed < targetDuration) {
|
||||
float t = elapsed / targetDuration;
|
||||
|
||||
// Main indicator pulses
|
||||
float pulse = 0.8f + 0.2f * Mathf.Sin(elapsed * 15f);
|
||||
indicator.transform.localScale = Vector3.one * targetScale * pulse;
|
||||
|
||||
Color c = targetColor;
|
||||
c.a = targetColor.a * pulse;
|
||||
renderer.color = c;
|
||||
|
||||
// Ring contracts inward
|
||||
if (ring != null) {
|
||||
float ringScale = targetScale * (2f - t);
|
||||
ring.transform.localScale = Vector3.one * ringScale;
|
||||
|
||||
Color rc = targetColor;
|
||||
rc.a = targetColor.a * 0.5f * (1f - t);
|
||||
ringRenderer.color = rc;
|
||||
}
|
||||
|
||||
elapsed += Time.deltaTime;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// Final pulse and fade
|
||||
float fadeDuration = 0.15f;
|
||||
elapsed = 0f;
|
||||
while (elapsed < fadeDuration) {
|
||||
float t = elapsed / fadeDuration;
|
||||
|
||||
indicator.transform.localScale = Vector3.one * targetScale * (1f + t * 0.3f);
|
||||
|
||||
Color c = targetColor;
|
||||
c.a = targetColor.a * (1f - t);
|
||||
renderer.color = c;
|
||||
|
||||
elapsed += Time.deltaTime;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
Destroy(indicator);
|
||||
if (ring != null) Destroy(ring);
|
||||
}
|
||||
|
||||
private IEnumerator AnimateCancel(Vector2 source) {
|
||||
Sprite sprite = chargeSprite ?? explosionSprite;
|
||||
if (sprite == null) yield break;
|
||||
|
||||
// Create fizzling glow (starts at charge end size)
|
||||
GameObject glow = new GameObject("MeteorCancel");
|
||||
glow.transform.SetParent(__hexGrid.gridCanvas.transform, false);
|
||||
glow.transform.localPosition = new Vector3(source.x, source.y, 5f);
|
||||
glow.transform.localScale = Vector3.one * chargeEndScale;
|
||||
|
||||
SpriteRenderer renderer = glow.AddComponent<SpriteRenderer>();
|
||||
renderer.sprite = sprite;
|
||||
renderer.sortingLayerName = "Effects";
|
||||
renderer.color = cancelColor;
|
||||
|
||||
// Create dispersing particles
|
||||
int particleCount = 6;
|
||||
GameObject[] particles = new GameObject[particleCount];
|
||||
Vector2[] directions = new Vector2[particleCount];
|
||||
|
||||
for (int i = 0; i < particleCount; i++) {
|
||||
if (trailSprite == null) break;
|
||||
|
||||
GameObject particle = new GameObject($"CancelParticle_{i}");
|
||||
particle.transform.SetParent(__hexGrid.gridCanvas.transform, false);
|
||||
particle.transform.localPosition = new Vector3(source.x, source.y, 4f);
|
||||
|
||||
SpriteRenderer pRenderer = particle.AddComponent<SpriteRenderer>();
|
||||
pRenderer.sprite = trailSprite;
|
||||
pRenderer.sortingLayerName = "Effects";
|
||||
pRenderer.color = cancelColor;
|
||||
particle.transform.localScale = Vector3.one * trailScale;
|
||||
|
||||
float angle = (float)i / particleCount * Mathf.PI * 2f + Random.Range(-0.2f, 0.2f);
|
||||
directions[i] = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
|
||||
particles[i] = particle;
|
||||
}
|
||||
|
||||
// Animation - shrink and fade while particles disperse
|
||||
float elapsed = 0f;
|
||||
while (elapsed < cancelDuration) {
|
||||
float t = elapsed / cancelDuration;
|
||||
|
||||
// Shrink and fade glow
|
||||
float scale = chargeEndScale * (1f - t * 0.7f);
|
||||
glow.transform.localScale = Vector3.one * scale;
|
||||
|
||||
Color c = cancelColor;
|
||||
c.a = cancelColor.a * (1f - t);
|
||||
renderer.color = c;
|
||||
|
||||
// Particles drift outward and fade
|
||||
for (int i = 0; i < particles.Length; i++) {
|
||||
if (particles[i] == null) continue;
|
||||
|
||||
Vector2 pos = source + directions[i] * 30f * t;
|
||||
particles[i].transform.localPosition = new Vector3(pos.x, pos.y, 4f);
|
||||
|
||||
var pRenderer = particles[i].GetComponent<SpriteRenderer>();
|
||||
if (pRenderer != null) {
|
||||
Color pc = cancelColor;
|
||||
pc.a = cancelColor.a * (1f - t);
|
||||
pRenderer.color = pc;
|
||||
particles[i].transform.localScale =
|
||||
Vector3.one * trailScale * (1f - t * 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
elapsed += Time.deltaTime;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
Destroy(glow);
|
||||
foreach (var p in particles) {
|
||||
if (p != null) Destroy(p);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator AnimateMeteor(Vector2 target) {
|
||||
List<GameObject> objects = new List<GameObject>();
|
||||
|
||||
|
||||
+41
-4
@@ -35,7 +35,10 @@ namespace Shardok {
|
||||
Fear,
|
||||
// Magic
|
||||
LightningBolt,
|
||||
MeteorStart,
|
||||
MeteorTarget,
|
||||
MeteorCast,
|
||||
MeteorCancel,
|
||||
HolyWave,
|
||||
RaiseDead,
|
||||
Control,
|
||||
@@ -1343,8 +1346,8 @@ namespace Shardok {
|
||||
case CommandType.MoveCommand: return AnimationType.Move;
|
||||
// Magic
|
||||
case CommandType.LightningBoltCommand: return AnimationType.LightningBolt;
|
||||
case CommandType.MeteorStartCommand:
|
||||
case CommandType.MeteorTargetCommand: return AnimationType.MeteorCast;
|
||||
case CommandType.MeteorStartCommand: return AnimationType.MeteorStart;
|
||||
case CommandType.MeteorTargetCommand: return AnimationType.MeteorTarget;
|
||||
case CommandType.HolyWaveCommand: return AnimationType.HolyWave;
|
||||
case CommandType.RaiseDeadCommand: return AnimationType.RaiseDead;
|
||||
case CommandType.ControlCommand: return AnimationType.Control;
|
||||
@@ -1383,9 +1386,10 @@ namespace Shardok {
|
||||
case ActionType.FearAttack: return AnimationType.Fear;
|
||||
// Magic
|
||||
case ActionType.LightningBolt: return AnimationType.LightningBolt;
|
||||
case ActionType.MeteorStart:
|
||||
case ActionType.MeteorTarget:
|
||||
case ActionType.MeteorStart: return AnimationType.MeteorStart;
|
||||
case ActionType.MeteorTarget: return AnimationType.MeteorTarget;
|
||||
case ActionType.MeteorCast: return AnimationType.MeteorCast;
|
||||
case ActionType.MeteorCancel: return AnimationType.MeteorCancel;
|
||||
case ActionType.HolyWave:
|
||||
case ActionType.HolyWaveDamage: return AnimationType.HolyWave;
|
||||
case ActionType.RaisedUndead: return AnimationType.RaiseDead;
|
||||
@@ -1425,7 +1429,10 @@ namespace Shardok {
|
||||
case AnimationType.Fear: return ActionType.FearAttack;
|
||||
// Magic
|
||||
case AnimationType.LightningBolt: return ActionType.LightningBolt;
|
||||
case AnimationType.MeteorStart: return ActionType.MeteorStart;
|
||||
case AnimationType.MeteorTarget: return ActionType.MeteorTarget;
|
||||
case AnimationType.MeteorCast: return ActionType.MeteorCast;
|
||||
case AnimationType.MeteorCancel: return ActionType.MeteorCancel;
|
||||
case AnimationType.HolyWave: return ActionType.HolyWave;
|
||||
case AnimationType.RaiseDead: return ActionType.RaisedUndead;
|
||||
case AnimationType.Control: return ActionType.Controlled;
|
||||
@@ -1571,11 +1578,26 @@ namespace Shardok {
|
||||
raiseDeadAnimator.AnimateRaiseDead(targetGridIndex);
|
||||
}
|
||||
break;
|
||||
case AnimationType.MeteorStart:
|
||||
if (meteorAnimator != null) {
|
||||
meteorAnimator.AnimateMeteorStart(sourceGridIndex);
|
||||
}
|
||||
break;
|
||||
case AnimationType.MeteorTarget:
|
||||
if (meteorAnimator != null) {
|
||||
meteorAnimator.AnimateMeteorTarget(targetGridIndex);
|
||||
}
|
||||
break;
|
||||
case AnimationType.MeteorCast:
|
||||
if (meteorAnimator != null) {
|
||||
meteorAnimator.AnimateMeteorCast(targetGridIndex);
|
||||
}
|
||||
break;
|
||||
case AnimationType.MeteorCancel:
|
||||
if (meteorAnimator != null) {
|
||||
meteorAnimator.AnimateMeteorCancel(sourceGridIndex);
|
||||
}
|
||||
break;
|
||||
case AnimationType.HolyWave:
|
||||
if (holyWaveAnimator != null) {
|
||||
var undeadCells = FindNearbyUndeadCells(sourceGridIndex, 2);
|
||||
@@ -1719,11 +1741,26 @@ namespace Shardok {
|
||||
raiseDeadAnimator.AnimateRaiseDead(targetGridIndex);
|
||||
}
|
||||
break;
|
||||
case AnimationType.MeteorStart:
|
||||
if (meteorAnimator != null) {
|
||||
meteorAnimator.AnimateMeteorStart(sourceGridIndex);
|
||||
}
|
||||
break;
|
||||
case AnimationType.MeteorTarget:
|
||||
if (meteorAnimator != null) {
|
||||
meteorAnimator.AnimateMeteorTarget(targetGridIndex);
|
||||
}
|
||||
break;
|
||||
case AnimationType.MeteorCast:
|
||||
if (meteorAnimator != null) {
|
||||
meteorAnimator.AnimateMeteorCast(targetGridIndex);
|
||||
}
|
||||
break;
|
||||
case AnimationType.MeteorCancel:
|
||||
if (meteorAnimator != null) {
|
||||
meteorAnimator.AnimateMeteorCancel(sourceGridIndex);
|
||||
}
|
||||
break;
|
||||
case AnimationType.HolyWave:
|
||||
if (holyWaveAnimator != null) {
|
||||
var undeadCells = FindNearbyUndeadCells(sourceGridIndex, 2);
|
||||
|
||||
Reference in New Issue
Block a user