fix multiple issues
This commit is contained in:
@@ -143,7 +143,7 @@ public class Bullet : MonoBehaviour
|
||||
{
|
||||
Collider2D directCollider = directTarget.GetComponent<Collider2D>();
|
||||
if (directCollider != null)
|
||||
ApplyExplosionControl(directCollider, center);
|
||||
ApplyExplosionControl(directCollider, center - lastKnownDirection * 0.35f);
|
||||
|
||||
int directDamage = CalculateDirectDamage(directTarget);
|
||||
directKilled = directTarget.TakeDamage(directDamage);
|
||||
@@ -228,6 +228,7 @@ public class Bullet : MonoBehaviour
|
||||
if (enemyHealth == null)
|
||||
continue;
|
||||
|
||||
CreateFragmentVisual(center, collider.transform.position);
|
||||
enemyHealth.TakeDamage(Mathf.Max(1, Mathf.RoundToInt(stats.directDamage * 0.35f)));
|
||||
fragmentsLeft--;
|
||||
}
|
||||
@@ -249,7 +250,8 @@ public class Bullet : MonoBehaviour
|
||||
effect.Configure(
|
||||
Mathf.Max(stats.burningGroundDuration, stats.craterDuration),
|
||||
stats.burningGroundDuration > 0f ? Mathf.Max(1, Mathf.RoundToInt(stats.directDamage * 0.18f)) : 0,
|
||||
stats.craterDuration > 0f ? stats.craterSlowMultiplier : 1f);
|
||||
stats.craterDuration > 0f ? stats.craterSlowMultiplier : 1f,
|
||||
stats.splashRadius * 0.72f);
|
||||
}
|
||||
|
||||
void TriggerChainDetonation(Vector2 center)
|
||||
@@ -319,4 +321,23 @@ public class Bullet : MonoBehaviour
|
||||
|
||||
ring.GetComponent<ShockwaveEffect>().Configure(0.28f);
|
||||
}
|
||||
|
||||
static void CreateFragmentVisual(Vector2 start, Vector2 end)
|
||||
{
|
||||
GameObject fragment = new GameObject("ShrapnelFragment", typeof(LineRenderer), typeof(ShockwaveEffect));
|
||||
fragment.transform.position = start;
|
||||
|
||||
LineRenderer line = fragment.GetComponent<LineRenderer>();
|
||||
line.useWorldSpace = true;
|
||||
line.positionCount = 2;
|
||||
line.SetPosition(0, start);
|
||||
line.SetPosition(1, end);
|
||||
line.startWidth = 0.045f;
|
||||
line.endWidth = 0.012f;
|
||||
line.material = new Material(Shader.Find("Sprites/Default"));
|
||||
line.startColor = new Color(0.82f, 0.84f, 0.88f, 0.95f);
|
||||
line.endColor = new Color(0.82f, 0.84f, 0.88f, 0.1f);
|
||||
|
||||
fragment.GetComponent<ShockwaveEffect>().Configure(0.18f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,16 +9,29 @@ public class CannonAreaEffect : MonoBehaviour
|
||||
int damagePerSecond;
|
||||
float slowMultiplier = 1f;
|
||||
float expiresAt;
|
||||
SpriteRenderer visual;
|
||||
|
||||
public void Configure(float effectDuration, int burnDamagePerSecond, float craterSlowMultiplier)
|
||||
public void Configure(float effectDuration, int burnDamagePerSecond, float craterSlowMultiplier, float radius)
|
||||
{
|
||||
duration = effectDuration;
|
||||
damagePerSecond = burnDamagePerSecond;
|
||||
slowMultiplier = Mathf.Clamp(craterSlowMultiplier, 0.1f, 1f);
|
||||
expiresAt = Time.time + duration;
|
||||
CreateVisual(radius);
|
||||
Destroy(gameObject, duration);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (visual == null || duration <= 0f)
|
||||
return;
|
||||
|
||||
float remaining = Mathf.Clamp01((expiresAt - Time.time) / duration);
|
||||
Color color = visual.color;
|
||||
color.a = Mathf.Lerp(0f, color.a, remaining);
|
||||
visual.color = color;
|
||||
}
|
||||
|
||||
void OnTriggerStay2D(Collider2D other)
|
||||
{
|
||||
if (!other.CompareTag("Enemy"))
|
||||
@@ -44,4 +57,44 @@ public class CannonAreaEffect : MonoBehaviour
|
||||
health.TakeDamage(Mathf.Max(1, damagePerSecond));
|
||||
nextDamageTick[health] = Time.time + 1f;
|
||||
}
|
||||
|
||||
void CreateVisual(float radius)
|
||||
{
|
||||
GameObject visualObject = new GameObject("Visual", typeof(SpriteRenderer));
|
||||
visualObject.transform.SetParent(transform, false);
|
||||
visualObject.transform.localScale = Vector3.one * radius * 2f;
|
||||
|
||||
visual = visualObject.GetComponent<SpriteRenderer>();
|
||||
visual.sprite = CreateCircleSprite();
|
||||
visual.sortingOrder = -1;
|
||||
|
||||
if (damagePerSecond > 0 && slowMultiplier < 1f)
|
||||
visual.color = new Color(0.95f, 0.33f, 0.12f, 0.34f);
|
||||
else if (damagePerSecond > 0)
|
||||
visual.color = new Color(1f, 0.32f, 0.08f, 0.34f);
|
||||
else
|
||||
visual.color = new Color(0.34f, 0.24f, 0.16f, 0.38f);
|
||||
}
|
||||
|
||||
static Sprite CreateCircleSprite()
|
||||
{
|
||||
const int size = 64;
|
||||
Texture2D texture = new Texture2D(size, size, TextureFormat.RGBA32, false);
|
||||
texture.filterMode = FilterMode.Bilinear;
|
||||
Vector2 center = new Vector2((size - 1) * 0.5f, (size - 1) * 0.5f);
|
||||
float radius = size * 0.46f;
|
||||
|
||||
for (int y = 0; y < size; y++)
|
||||
{
|
||||
for (int x = 0; x < size; x++)
|
||||
{
|
||||
float distance = Vector2.Distance(new Vector2(x, y), center);
|
||||
float alpha = Mathf.Clamp01((radius - distance) / 5f);
|
||||
texture.SetPixel(x, y, new Color(1f, 1f, 1f, alpha));
|
||||
}
|
||||
}
|
||||
|
||||
texture.Apply();
|
||||
return Sprite.Create(texture, new Rect(0f, 0f, size, size), new Vector2(0.5f, 0.5f), size);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-1
@@ -7,6 +7,8 @@ public class Enemy : MonoBehaviour
|
||||
private EnemyHealth enemyHealth;
|
||||
private float slowMultiplier = 1f;
|
||||
private float slowEndTime;
|
||||
private Vector2 knockbackVelocity;
|
||||
private float knockbackEndTime;
|
||||
|
||||
void Start()
|
||||
{
|
||||
@@ -25,12 +27,21 @@ public class Enemy : MonoBehaviour
|
||||
if (Time.time >= slowEndTime)
|
||||
slowMultiplier = 1f;
|
||||
|
||||
if (Time.time < knockbackEndTime && knockbackVelocity.sqrMagnitude > 0.01f)
|
||||
{
|
||||
transform.position += (Vector3)(knockbackVelocity * Time.deltaTime);
|
||||
knockbackVelocity = Vector2.Lerp(knockbackVelocity, Vector2.zero, 8f * Time.deltaTime);
|
||||
return;
|
||||
}
|
||||
|
||||
transform.position = Vector2.MoveTowards(transform.position, tower.position, speed * slowMultiplier * Time.deltaTime);
|
||||
if (Vector2.Distance(transform.position, tower.position) < 0.5f)
|
||||
{
|
||||
int damageDealt = enemyHealth.GetCurrentHealth();
|
||||
tower.GetComponent<TowerHealth>().TakeDamage(damageDealt);
|
||||
enemyHealth.NotifySpawner();
|
||||
if (enemyHealth.isBoss && enemyHealth.spawner != null)
|
||||
enemyHealth.spawner.HideBossHealth(enemyHealth);
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
@@ -47,6 +58,8 @@ public class Enemy : MonoBehaviour
|
||||
if (direction.sqrMagnitude <= Mathf.Epsilon)
|
||||
return;
|
||||
|
||||
transform.position += (Vector3)(direction * distance);
|
||||
transform.position += (Vector3)(direction * distance * 0.45f);
|
||||
knockbackVelocity = direction * Mathf.Max(2.5f, distance * 12f);
|
||||
knockbackEndTime = Time.time + 0.22f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
public class EnemyHealth : MonoBehaviour
|
||||
@@ -5,6 +6,7 @@ public class EnemyHealth : MonoBehaviour
|
||||
public int health = 1;
|
||||
public GameObject shatterEffectPrefab;
|
||||
public EnemySpawner spawner;
|
||||
public bool isBoss;
|
||||
private int maxHealth = 1;
|
||||
|
||||
public bool TakeDamage(int damage)
|
||||
@@ -12,9 +14,16 @@ public class EnemyHealth : MonoBehaviour
|
||||
if (health <= 0)
|
||||
return false;
|
||||
|
||||
ShowDamageNumber(damage);
|
||||
health -= damage;
|
||||
if (isBoss && spawner != null)
|
||||
spawner.UpdateBossHealth(this, health, maxHealth);
|
||||
|
||||
if (health <= 0)
|
||||
{
|
||||
if (isBoss && spawner != null)
|
||||
spawner.HideBossHealth(this);
|
||||
|
||||
NotifySpawner();
|
||||
ShatterEffect();
|
||||
NotifyUpgradeManager();
|
||||
@@ -34,6 +43,8 @@ public class EnemyHealth : MonoBehaviour
|
||||
{
|
||||
health = newHealth;
|
||||
maxHealth = Mathf.Max(1, newHealth);
|
||||
if (isBoss && spawner != null)
|
||||
spawner.UpdateBossHealth(this, health, maxHealth);
|
||||
}
|
||||
|
||||
public float GetHealthPercent()
|
||||
@@ -45,6 +56,8 @@ public class EnemyHealth : MonoBehaviour
|
||||
{
|
||||
if (spawner != null)
|
||||
{
|
||||
if (isBoss)
|
||||
spawner.HideBossHealth(this);
|
||||
spawner.EnemyDefeated();
|
||||
}
|
||||
}
|
||||
@@ -65,4 +78,18 @@ public class EnemyHealth : MonoBehaviour
|
||||
Instantiate(shatterEffectPrefab, transform.position, Quaternion.identity);
|
||||
}
|
||||
}
|
||||
|
||||
void ShowDamageNumber(int damage)
|
||||
{
|
||||
GameObject textObject = new GameObject("EnemyDamageText", typeof(TextMeshPro));
|
||||
textObject.transform.position = transform.position + new Vector3(Random.Range(-0.18f, 0.18f), 0.72f, 0f);
|
||||
|
||||
TextMeshPro text = textObject.GetComponent<TextMeshPro>();
|
||||
text.text = damage.ToString();
|
||||
text.fontSize = 3.1f;
|
||||
text.alignment = TextAlignmentOptions.Center;
|
||||
text.color = Color.white;
|
||||
text.sortingOrder = 50;
|
||||
textObject.AddComponent<FloatingWorldText>().Configure(0.75f, new Vector3(0f, 0.58f, 0f));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,14 @@ public class EnemySpawner : MonoBehaviour
|
||||
private int enemiesRemaining = 0;
|
||||
private int baseEnemyCount = 5;
|
||||
private int enemyCountIncrease = 3;
|
||||
private float enemySpeed = 1.5f;
|
||||
private float enemySpeed = 1.16f;
|
||||
private int enemyBaseHP = 1;
|
||||
private float maxEnemySpeed = 6f;
|
||||
private int maxEnemyHP = 20;
|
||||
private RectTransform bossHealthBar;
|
||||
private Image bossHealthFill;
|
||||
private TextMeshProUGUI bossHealthText;
|
||||
private EnemyHealth activeBoss;
|
||||
|
||||
void Start()
|
||||
{
|
||||
@@ -74,9 +78,8 @@ public class EnemySpawner : MonoBehaviour
|
||||
Enemy enemyComponent = newEnemy.GetComponent<Enemy>();
|
||||
if (enemyComponent != null)
|
||||
{
|
||||
// Lower speed scale to 0.1f
|
||||
float waveSpeedBonus = currentWave * 0.1f;
|
||||
float stageSpeedBonus = (currentStage - 1) * 0.08f;
|
||||
float waveSpeedBonus = currentWave * 0.028f;
|
||||
float stageSpeedBonus = (currentStage - 1) * 0.025f;
|
||||
enemyComponent.speed = Mathf.Min(maxEnemySpeed, enemySpeed + waveSpeedBonus + stageSpeedBonus);
|
||||
if (boss)
|
||||
enemyComponent.speed *= 0.72f;
|
||||
@@ -85,14 +88,14 @@ public class EnemySpawner : MonoBehaviour
|
||||
EnemyHealth enemyHealth = newEnemy.GetComponent<EnemyHealth>();
|
||||
if (enemyHealth != null)
|
||||
{
|
||||
// For HP: baseHP + wave * 0.3 (round it)
|
||||
int scaledHP = enemyBaseHP + Mathf.RoundToInt(currentWave * 0.3f) + Mathf.RoundToInt((currentStage - 1) * 0.5f);
|
||||
int scaledHP = enemyBaseHP + Mathf.FloorToInt(currentWave * 0.14f) + Mathf.FloorToInt((currentStage - 1) * 0.25f);
|
||||
if (boss)
|
||||
scaledHP = Mathf.RoundToInt((scaledHP + currentStage + currentWave) * 4.5f);
|
||||
scaledHP = Mathf.RoundToInt((scaledHP + currentStage + currentWave * 0.48f) * 3.05f);
|
||||
scaledHP = Mathf.Min(boss ? maxEnemyHP * 4 : maxEnemyHP, scaledHP);
|
||||
enemyHealth.SetHealth(scaledHP);
|
||||
|
||||
enemyHealth.spawner = this;
|
||||
enemyHealth.isBoss = boss;
|
||||
}
|
||||
|
||||
if (boss)
|
||||
@@ -102,6 +105,44 @@ public class EnemySpawner : MonoBehaviour
|
||||
SpriteRenderer spriteRenderer = newEnemy.GetComponent<SpriteRenderer>();
|
||||
if (spriteRenderer != null)
|
||||
spriteRenderer.color = new Color(0.95f, 0.32f, 0.28f, 1f);
|
||||
|
||||
activeBoss = enemyHealth;
|
||||
EnsureBossHealthBar();
|
||||
UpdateBossHealth(enemyHealth, enemyHealth.GetCurrentHealth(), enemyHealth.GetCurrentHealth());
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplyEnemyVariant(newEnemy, enemyComponent, enemyHealth);
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyEnemyVariant(GameObject enemyObject, Enemy enemyComponent, EnemyHealth enemyHealth)
|
||||
{
|
||||
if (enemyComponent == null || enemyHealth == null)
|
||||
return;
|
||||
|
||||
float waveFactor = Mathf.Clamp01(currentWave / 15f);
|
||||
float fastChance = Mathf.Lerp(0.08f, 0.24f, waveFactor);
|
||||
float tankChance = Mathf.Lerp(0.05f, 0.2f, waveFactor);
|
||||
float roll = Random.value;
|
||||
|
||||
SpriteRenderer spriteRenderer = enemyObject.GetComponent<SpriteRenderer>();
|
||||
if (roll < fastChance)
|
||||
{
|
||||
enemyObject.name = "Fast Enemy";
|
||||
enemyComponent.speed *= 1.65f;
|
||||
enemyObject.transform.localScale *= 0.82f;
|
||||
if (spriteRenderer != null)
|
||||
spriteRenderer.color = new Color(0.35f, 0.78f, 1f, 1f);
|
||||
}
|
||||
else if (roll < fastChance + tankChance)
|
||||
{
|
||||
enemyObject.name = "Tank Enemy";
|
||||
enemyComponent.speed *= 0.62f;
|
||||
enemyObject.transform.localScale *= 1.32f;
|
||||
enemyHealth.SetHealth(Mathf.Max(2, Mathf.RoundToInt(enemyHealth.GetCurrentHealth() * 2.35f)));
|
||||
if (spriteRenderer != null)
|
||||
spriteRenderer.color = new Color(0.78f, 0.56f, 0.28f, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +178,7 @@ public class EnemySpawner : MonoBehaviour
|
||||
UpgradeManager upgradeManager = FindAnyObjectByType<UpgradeManager>();
|
||||
if (upgradeManager != null)
|
||||
{
|
||||
upgradeManager.ShowWaveUpgradeChoice(PrepareNextWave);
|
||||
StartCoroutine(ShowUpgradeChoiceAfterIntermission(upgradeManager, IsBossWave(currentWave)));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -152,6 +193,15 @@ public class EnemySpawner : MonoBehaviour
|
||||
UpdateWaveText();
|
||||
}
|
||||
|
||||
IEnumerator ShowUpgradeChoiceAfterIntermission(UpgradeManager upgradeManager, bool bossWave)
|
||||
{
|
||||
yield return new WaitForSeconds(1f);
|
||||
if (upgradeManager != null)
|
||||
upgradeManager.ShowWaveUpgradeChoice(PrepareNextWave, bossWave);
|
||||
else
|
||||
PrepareNextWave();
|
||||
}
|
||||
|
||||
int GetNormalEnemyCount(int wave)
|
||||
{
|
||||
return baseEnemyCount + wave * enemyCountIncrease + Mathf.Max(0, currentStage - 1);
|
||||
@@ -171,12 +221,47 @@ public class EnemySpawner : MonoBehaviour
|
||||
{
|
||||
stageComplete = true;
|
||||
isSpawning = false;
|
||||
HideBossHealth(activeBoss);
|
||||
int nextStage = currentStage + 1;
|
||||
PlayerPrefs.SetInt(CurrentStageKey, nextStage);
|
||||
PlayerPrefs.Save();
|
||||
ShowWinScreen(nextStage);
|
||||
}
|
||||
|
||||
public void UpdateBossHealth(EnemyHealth boss, int currentHealth, int maxHealth)
|
||||
{
|
||||
if (boss == null)
|
||||
return;
|
||||
|
||||
activeBoss = boss;
|
||||
EnsureBossHealthBar();
|
||||
if (bossHealthBar != null)
|
||||
bossHealthBar.gameObject.SetActive(true);
|
||||
|
||||
float percent = maxHealth <= 0 ? 0f : Mathf.Clamp01((float)Mathf.Max(0, currentHealth) / maxHealth);
|
||||
if (bossHealthFill != null)
|
||||
{
|
||||
bossHealthFill.fillAmount = 1f;
|
||||
bossHealthFill.color = Color.Lerp(new Color(0.55f, 0.05f, 0.06f, 1f), new Color(0.95f, 0.2f, 0.18f, 1f), percent);
|
||||
RectTransform fillRect = bossHealthFill.rectTransform;
|
||||
fillRect.anchorMax = new Vector2(percent, fillRect.anchorMax.y);
|
||||
fillRect.offsetMax = Vector2.zero;
|
||||
}
|
||||
|
||||
if (bossHealthText != null)
|
||||
bossHealthText.text = $"BOSS {Mathf.Max(0, currentHealth)}/{maxHealth}";
|
||||
}
|
||||
|
||||
public void HideBossHealth(EnemyHealth boss)
|
||||
{
|
||||
if (boss != null && activeBoss != null && boss != activeBoss)
|
||||
return;
|
||||
|
||||
activeBoss = null;
|
||||
if (bossHealthBar != null)
|
||||
bossHealthBar.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
void ShowWinScreen(int nextStage)
|
||||
{
|
||||
Time.timeScale = 0f;
|
||||
@@ -214,6 +299,66 @@ public class EnemySpawner : MonoBehaviour
|
||||
SceneManager.LoadScene("MainMenu");
|
||||
}
|
||||
|
||||
void EnsureBossHealthBar()
|
||||
{
|
||||
if (bossHealthBar != null)
|
||||
return;
|
||||
|
||||
Canvas canvas = FindAnyObjectByType<Canvas>();
|
||||
if (canvas == null)
|
||||
return;
|
||||
|
||||
Transform existing = canvas.transform.Find("BossHealthBar");
|
||||
bossHealthBar = existing != null ? existing.GetComponent<RectTransform>() : CreateRect("BossHealthBar", canvas.transform);
|
||||
bossHealthBar.anchorMin = new Vector2(0.5f, 1f);
|
||||
bossHealthBar.anchorMax = new Vector2(0.5f, 1f);
|
||||
bossHealthBar.pivot = new Vector2(0.5f, 1f);
|
||||
bossHealthBar.anchoredPosition = new Vector2(0f, -126f);
|
||||
bossHealthBar.sizeDelta = new Vector2(360f, 48f);
|
||||
bossHealthBar.gameObject.SetActive(false);
|
||||
|
||||
Image panel = bossHealthBar.GetComponent<Image>();
|
||||
if (panel == null)
|
||||
panel = bossHealthBar.gameObject.AddComponent<Image>();
|
||||
panel.color = new Color(0.05f, 0.03f, 0.035f, 0.88f);
|
||||
|
||||
RectTransform track = bossHealthBar.Find("Track")?.GetComponent<RectTransform>();
|
||||
if (track == null)
|
||||
{
|
||||
track = CreateRect("Track", bossHealthBar);
|
||||
track.anchorMin = new Vector2(0f, 0f);
|
||||
track.anchorMax = new Vector2(1f, 0f);
|
||||
track.pivot = new Vector2(0.5f, 0f);
|
||||
track.anchoredPosition = new Vector2(0f, 8f);
|
||||
track.sizeDelta = new Vector2(-24f, 16f);
|
||||
Image trackImage = track.gameObject.AddComponent<Image>();
|
||||
trackImage.color = new Color(0.16f, 0.08f, 0.08f, 1f);
|
||||
}
|
||||
|
||||
bossHealthFill = track.Find("Fill")?.GetComponent<Image>();
|
||||
if (bossHealthFill == null)
|
||||
{
|
||||
RectTransform fill = CreateRect("Fill", track);
|
||||
fill.anchorMin = Vector2.zero;
|
||||
fill.anchorMax = Vector2.one;
|
||||
fill.offsetMin = Vector2.zero;
|
||||
fill.offsetMax = Vector2.zero;
|
||||
bossHealthFill = fill.gameObject.AddComponent<Image>();
|
||||
}
|
||||
bossHealthFill.type = Image.Type.Simple;
|
||||
|
||||
bossHealthText = bossHealthBar.Find("Text")?.GetComponent<TextMeshProUGUI>();
|
||||
if (bossHealthText == null)
|
||||
{
|
||||
bossHealthText = CreateOverlayText("Text", bossHealthBar, "BOSS", 15f, FontStyles.Bold);
|
||||
bossHealthText.rectTransform.anchorMin = new Vector2(0f, 1f);
|
||||
bossHealthText.rectTransform.anchorMax = new Vector2(1f, 1f);
|
||||
bossHealthText.rectTransform.pivot = new Vector2(0.5f, 1f);
|
||||
bossHealthText.rectTransform.anchoredPosition = new Vector2(0f, -4f);
|
||||
bossHealthText.rectTransform.sizeDelta = new Vector2(-16f, 20f);
|
||||
}
|
||||
}
|
||||
|
||||
void EnsureWaveText()
|
||||
{
|
||||
if (waveText != null)
|
||||
@@ -345,6 +490,14 @@ public class EnemySpawner : MonoBehaviour
|
||||
return button;
|
||||
}
|
||||
|
||||
static RectTransform CreateRect(string name, Transform parent)
|
||||
{
|
||||
GameObject obj = new GameObject(name, typeof(RectTransform));
|
||||
RectTransform rect = obj.GetComponent<RectTransform>();
|
||||
rect.SetParent(parent, false);
|
||||
return rect;
|
||||
}
|
||||
|
||||
static void PlaceOverlayRect(RectTransform rect, float x, float y, float width, float height)
|
||||
{
|
||||
rect.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
public class FloatingWorldText : MonoBehaviour
|
||||
{
|
||||
TextMeshPro text;
|
||||
Vector3 startPosition;
|
||||
Vector3 offset = new Vector3(0f, 0.6f, 0f);
|
||||
Color startColor = Color.white;
|
||||
float duration = 0.75f;
|
||||
float elapsed;
|
||||
|
||||
public void Configure(float fadeDuration, Vector3 moveOffset)
|
||||
{
|
||||
duration = Mathf.Max(0.05f, fadeDuration);
|
||||
offset = moveOffset;
|
||||
}
|
||||
|
||||
void Awake()
|
||||
{
|
||||
text = GetComponent<TextMeshPro>();
|
||||
startPosition = transform.position;
|
||||
if (text != null)
|
||||
startColor = text.color;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = Mathf.Clamp01(elapsed / duration);
|
||||
transform.position = Vector3.Lerp(startPosition, startPosition + offset, t);
|
||||
|
||||
if (text != null)
|
||||
text.color = new Color(startColor.r, startColor.g, startColor.b, 1f - t);
|
||||
|
||||
if (elapsed >= duration)
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class RarityPulse : MonoBehaviour
|
||||
{
|
||||
Outline outline;
|
||||
Color baseColor = Color.white;
|
||||
|
||||
public void Configure(Outline targetOutline, Color color)
|
||||
{
|
||||
outline = targetOutline;
|
||||
baseColor = color;
|
||||
}
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (outline == null)
|
||||
outline = GetComponent<Outline>();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (outline == null)
|
||||
return;
|
||||
|
||||
float pulse = 0.55f + Mathf.Sin(Time.unscaledTime * 4.5f) * 0.25f;
|
||||
Color color = baseColor;
|
||||
color.a = Mathf.Clamp01(pulse);
|
||||
outline.effectColor = color;
|
||||
float distance = 2.5f + Mathf.Sin(Time.unscaledTime * 4.5f) * 0.8f;
|
||||
outline.effectDistance = new Vector2(distance, -distance);
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,8 @@ public class Tower : MonoBehaviour
|
||||
private int shotsFired;
|
||||
private float cooldownUntil;
|
||||
private bool cannonBaselineApplied;
|
||||
private SpriteRenderer rangeCircle;
|
||||
private Camera mainCamera;
|
||||
public int extraBullets = 0; // For "Shoot +1 bullet"
|
||||
public bool homingEnabled = false;
|
||||
public bool ricochetEnabled = false;
|
||||
@@ -51,10 +53,15 @@ public class Tower : MonoBehaviour
|
||||
void Start()
|
||||
{
|
||||
ApplyCannonBaseline();
|
||||
EnsureRangeCircle();
|
||||
FitCameraToRange();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
UpdateRangeCircle();
|
||||
FitCameraToRange();
|
||||
|
||||
if (Time.time < cooldownUntil)
|
||||
return;
|
||||
|
||||
@@ -65,6 +72,69 @@ public class Tower : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
void EnsureRangeCircle()
|
||||
{
|
||||
if (rangeCircle != null)
|
||||
return;
|
||||
|
||||
GameObject rangeObject = new GameObject("TowerRangeCircle", typeof(SpriteRenderer));
|
||||
rangeObject.transform.position = transform.position;
|
||||
rangeCircle = rangeObject.GetComponent<SpriteRenderer>();
|
||||
rangeCircle.sprite = CreateCircleSprite();
|
||||
rangeCircle.color = new Color(0.72f, 0.74f, 0.78f, 0.16f);
|
||||
rangeCircle.sortingOrder = -10;
|
||||
UpdateRangeCircle();
|
||||
}
|
||||
|
||||
void UpdateRangeCircle()
|
||||
{
|
||||
if (rangeCircle == null)
|
||||
return;
|
||||
|
||||
rangeCircle.transform.position = transform.position;
|
||||
rangeCircle.transform.localScale = Vector3.one * (attackRange * 2.08f);
|
||||
}
|
||||
|
||||
void FitCameraToRange()
|
||||
{
|
||||
if (mainCamera == null)
|
||||
mainCamera = Camera.main;
|
||||
if (mainCamera == null || !mainCamera.orthographic)
|
||||
return;
|
||||
|
||||
float padding = 0.45f;
|
||||
float verticalSize = attackRange + padding;
|
||||
float horizontalSize = (attackRange + padding) / Mathf.Max(0.1f, mainCamera.aspect);
|
||||
mainCamera.orthographicSize = Mathf.Max(5.5f, verticalSize, horizontalSize);
|
||||
Vector3 cameraPosition = transform.position;
|
||||
cameraPosition.z = mainCamera.transform.position.z;
|
||||
mainCamera.transform.position = cameraPosition;
|
||||
}
|
||||
|
||||
static Sprite CreateCircleSprite()
|
||||
{
|
||||
const int size = 128;
|
||||
Texture2D texture = new Texture2D(size, size, TextureFormat.RGBA32, false);
|
||||
texture.filterMode = FilterMode.Bilinear;
|
||||
Vector2 center = new Vector2((size - 1) * 0.5f, (size - 1) * 0.5f);
|
||||
float radius = size * 0.47f;
|
||||
|
||||
for (int y = 0; y < size; y++)
|
||||
{
|
||||
for (int x = 0; x < size; x++)
|
||||
{
|
||||
float distance = Vector2.Distance(new Vector2(x, y), center);
|
||||
float fillAlpha = distance <= radius ? 0.75f : 0f;
|
||||
float edge = Mathf.Clamp01(1f - Mathf.Abs(distance - radius) / 2.2f);
|
||||
float alpha = Mathf.Max(fillAlpha * 0.18f, edge);
|
||||
texture.SetPixel(x, y, new Color(1f, 1f, 1f, alpha));
|
||||
}
|
||||
}
|
||||
|
||||
texture.Apply();
|
||||
return Sprite.Create(texture, new Rect(0f, 0f, size, size), new Vector2(0.5f, 0.5f), size);
|
||||
}
|
||||
|
||||
void ApplyCannonBaseline()
|
||||
{
|
||||
if (cannonBaselineApplied)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.SceneManagement;
|
||||
using System.Collections;
|
||||
|
||||
public class TowerHealth : MonoBehaviour
|
||||
@@ -15,6 +16,7 @@ public class TowerHealth : MonoBehaviour
|
||||
public Color lowHealthColor = new Color(0.95f, 0.22f, 0.18f);
|
||||
|
||||
private int currentHealth;
|
||||
private bool isDead;
|
||||
private SpriteRenderer spriteRenderer;
|
||||
|
||||
void Start()
|
||||
@@ -32,6 +34,9 @@ public class TowerHealth : MonoBehaviour
|
||||
|
||||
public void TakeDamage(int damage)
|
||||
{
|
||||
if (isDead)
|
||||
return;
|
||||
|
||||
currentHealth -= damage;
|
||||
if (currentHealth < 0) currentHealth = 0;
|
||||
ShowFloatingDamage(damage);
|
||||
@@ -39,7 +44,8 @@ public class TowerHealth : MonoBehaviour
|
||||
|
||||
if (currentHealth <= 0)
|
||||
{
|
||||
Debug.Log("Tower Destroyed! Game Over.");
|
||||
isDead = true;
|
||||
ShowStageLostScreen();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +55,12 @@ public class TowerHealth : MonoBehaviour
|
||||
|
||||
if (healthFill != null)
|
||||
{
|
||||
healthFill.fillAmount = healthPercentage;
|
||||
healthFill.fillAmount = 1f;
|
||||
healthFill.color = Color.Lerp(lowHealthColor, highHealthColor, healthPercentage);
|
||||
|
||||
RectTransform fillRect = healthFill.rectTransform;
|
||||
fillRect.anchorMax = new Vector2(healthPercentage, fillRect.anchorMax.y);
|
||||
fillRect.offsetMax = Vector2.zero;
|
||||
}
|
||||
|
||||
if (healthText != null)
|
||||
@@ -152,6 +162,56 @@ public class TowerHealth : MonoBehaviour
|
||||
healthFill.fillOrigin = (int)Image.OriginHorizontal.Left;
|
||||
}
|
||||
}
|
||||
|
||||
healthFill.type = Image.Type.Simple;
|
||||
}
|
||||
|
||||
void ShowStageLostScreen()
|
||||
{
|
||||
Time.timeScale = 0f;
|
||||
|
||||
Canvas canvas = FindAnyObjectByType<Canvas>();
|
||||
if (canvas == null)
|
||||
return;
|
||||
|
||||
GameObject overlay = new GameObject("StageLostOverlay", typeof(RectTransform), typeof(CanvasRenderer), typeof(Image));
|
||||
RectTransform rect = overlay.GetComponent<RectTransform>();
|
||||
rect.SetParent(canvas.transform, false);
|
||||
rect.anchorMin = Vector2.zero;
|
||||
rect.anchorMax = Vector2.one;
|
||||
rect.offsetMin = Vector2.zero;
|
||||
rect.offsetMax = Vector2.zero;
|
||||
rect.SetAsLastSibling();
|
||||
|
||||
Image background = overlay.GetComponent<Image>();
|
||||
background.color = new Color(0f, 0f, 0f, 0.8f);
|
||||
background.raycastTarget = true;
|
||||
|
||||
TextMeshProUGUI title = CreateText("Title", rect, "STAGE LOST", 44f);
|
||||
title.alignment = TextAlignmentOptions.Center;
|
||||
PlaceOverlayRect(title.rectTransform, 0f, 64f, 420f, 68f);
|
||||
|
||||
TextMeshProUGUI subtitle = CreateText("Subtitle", rect, "Wave progress and upgrades were lost.", 19f);
|
||||
subtitle.fontStyle = FontStyles.Normal;
|
||||
subtitle.alignment = TextAlignmentOptions.Center;
|
||||
PlaceOverlayRect(subtitle.rectTransform, 0f, 12f, 520f, 42f);
|
||||
|
||||
Button menuButton = CreateOverlayButton("MenuButton", rect, "MAIN MENU", ReturnToMenu);
|
||||
PlaceOverlayRect(menuButton.GetComponent<RectTransform>(), 0f, -64f, 220f, 54f);
|
||||
|
||||
StartCoroutine(ReturnToMenuAfterDelay());
|
||||
}
|
||||
|
||||
IEnumerator ReturnToMenuAfterDelay()
|
||||
{
|
||||
yield return new WaitForSecondsRealtime(2.25f);
|
||||
ReturnToMenu();
|
||||
}
|
||||
|
||||
void ReturnToMenu()
|
||||
{
|
||||
Time.timeScale = 1f;
|
||||
SceneManager.LoadScene("MainMenu");
|
||||
}
|
||||
|
||||
static RectTransform CreateRect(string name, Transform parent)
|
||||
@@ -177,6 +237,44 @@ public class TowerHealth : MonoBehaviour
|
||||
return label;
|
||||
}
|
||||
|
||||
static Button CreateOverlayButton(string name, Transform parent, string label, UnityEngine.Events.UnityAction onClick)
|
||||
{
|
||||
GameObject obj = new GameObject(name, typeof(RectTransform), typeof(CanvasRenderer), typeof(Image), typeof(Button));
|
||||
RectTransform rect = obj.GetComponent<RectTransform>();
|
||||
rect.SetParent(parent, false);
|
||||
|
||||
Image image = obj.GetComponent<Image>();
|
||||
image.color = new Color(0.18f, 0.5f, 0.74f, 1f);
|
||||
|
||||
Button button = obj.GetComponent<Button>();
|
||||
ColorBlock colors = button.colors;
|
||||
colors.normalColor = image.color;
|
||||
colors.highlightedColor = new Color(0.25f, 0.62f, 0.88f, 1f);
|
||||
colors.pressedColor = new Color(0.12f, 0.36f, 0.56f, 1f);
|
||||
colors.selectedColor = colors.highlightedColor;
|
||||
colors.disabledColor = new Color(0.16f, 0.18f, 0.22f, 1f);
|
||||
colors.colorMultiplier = 1f;
|
||||
button.colors = colors;
|
||||
button.onClick.AddListener(onClick);
|
||||
|
||||
TextMeshProUGUI text = CreateText("Text", rect, label, 18f);
|
||||
text.alignment = TextAlignmentOptions.Center;
|
||||
text.rectTransform.anchorMin = Vector2.zero;
|
||||
text.rectTransform.anchorMax = Vector2.one;
|
||||
text.rectTransform.offsetMin = Vector2.zero;
|
||||
text.rectTransform.offsetMax = Vector2.zero;
|
||||
return button;
|
||||
}
|
||||
|
||||
static void PlaceOverlayRect(RectTransform rect, float x, float y, float width, float height)
|
||||
{
|
||||
rect.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
rect.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
rect.pivot = new Vector2(0.5f, 0.5f);
|
||||
rect.anchoredPosition = new Vector2(x, y);
|
||||
rect.sizeDelta = new Vector2(width, height);
|
||||
}
|
||||
|
||||
void ShowFloatingDamage(int damage)
|
||||
{
|
||||
if (floatingTextPrefab != null)
|
||||
|
||||
@@ -41,9 +41,12 @@ public class UpgradeManager : MonoBehaviour
|
||||
readonly Dictionary<UpgradeCard.UpgradeType, int> upgradeCosts = new Dictionary<UpgradeCard.UpgradeType, int>();
|
||||
|
||||
GameObject choiceOverlay;
|
||||
RectTransform currentCardRow;
|
||||
bool currentGuaranteeEpicOrHigher;
|
||||
Action currentChoiceComplete;
|
||||
int bonusBitsPerKill;
|
||||
float hitBitChance;
|
||||
int rerollCost = 1;
|
||||
|
||||
static readonly CardDefinition[] CannonCards =
|
||||
{
|
||||
@@ -99,7 +102,7 @@ public class UpgradeManager : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowWaveUpgradeChoice(Action onChoiceComplete)
|
||||
public void ShowWaveUpgradeChoice(Action onChoiceComplete, bool guaranteeEpicOrHigher = false)
|
||||
{
|
||||
if (choiceOverlay != null)
|
||||
return;
|
||||
@@ -107,8 +110,10 @@ public class UpgradeManager : MonoBehaviour
|
||||
InitializeUpgrades();
|
||||
EnsureBitsText();
|
||||
currentChoiceComplete = onChoiceComplete;
|
||||
currentGuaranteeEpicOrHigher = guaranteeEpicOrHigher;
|
||||
rerollCost = 1;
|
||||
|
||||
List<UpgradeOffer> offers = BuildOffers();
|
||||
List<UpgradeOffer> offers = BuildOffers(guaranteeEpicOrHigher);
|
||||
if (offers.Count == 0)
|
||||
{
|
||||
CompleteChoice();
|
||||
@@ -117,23 +122,9 @@ public class UpgradeManager : MonoBehaviour
|
||||
|
||||
Time.timeScale = 0f;
|
||||
choiceOverlay = CreateOverlay(offers[0].isFree);
|
||||
RectTransform row = CreateRect("UpgradeChoices", choiceOverlay.transform);
|
||||
row.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
row.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
row.pivot = new Vector2(0.5f, 0.5f);
|
||||
row.anchoredPosition = new Vector2(0f, -12f);
|
||||
row.sizeDelta = new Vector2(700f, 212f);
|
||||
|
||||
HorizontalLayoutGroup layout = row.gameObject.AddComponent<HorizontalLayoutGroup>();
|
||||
layout.spacing = 16f;
|
||||
layout.childAlignment = TextAnchor.MiddleCenter;
|
||||
layout.childControlWidth = true;
|
||||
layout.childControlHeight = true;
|
||||
layout.childForceExpandWidth = false;
|
||||
layout.childForceExpandHeight = false;
|
||||
|
||||
foreach (UpgradeOffer offer in offers)
|
||||
CreateChoiceCard(offer, row);
|
||||
currentCardRow = CreateChoiceRow(choiceOverlay.transform);
|
||||
PopulateChoiceCards(offers);
|
||||
CreateRerollButton(choiceOverlay.transform);
|
||||
}
|
||||
|
||||
public void ShowSpecialUpgradeChoice()
|
||||
@@ -160,7 +151,7 @@ public class UpgradeManager : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
List<UpgradeOffer> BuildOffers()
|
||||
List<UpgradeOffer> BuildOffers(bool guaranteeEpicOrHigher)
|
||||
{
|
||||
List<UpgradeOffer> paidOffers = new List<UpgradeOffer>();
|
||||
foreach (CardDefinition card in CannonCards)
|
||||
@@ -182,7 +173,7 @@ public class UpgradeManager : MonoBehaviour
|
||||
}
|
||||
|
||||
if (paidOffers.Count > 0)
|
||||
return PickRandomWeighted(paidOffers, 3);
|
||||
return PickRandomWeighted(paidOffers, 3, guaranteeEpicOrHigher);
|
||||
|
||||
return new List<UpgradeOffer>
|
||||
{
|
||||
@@ -207,11 +198,28 @@ public class UpgradeManager : MonoBehaviour
|
||||
};
|
||||
}
|
||||
|
||||
static List<UpgradeOffer> PickRandomWeighted(List<UpgradeOffer> source, int count)
|
||||
static List<UpgradeOffer> PickRandomWeighted(List<UpgradeOffer> source, int count, bool guaranteeEpicOrHigher)
|
||||
{
|
||||
List<UpgradeOffer> pool = new List<UpgradeOffer>(source);
|
||||
List<UpgradeOffer> result = new List<UpgradeOffer>();
|
||||
|
||||
if (guaranteeEpicOrHigher)
|
||||
{
|
||||
List<UpgradeOffer> highRarity = new List<UpgradeOffer>();
|
||||
foreach (UpgradeOffer offer in pool)
|
||||
{
|
||||
if (IsEpicOrHigher(offer.rarity))
|
||||
highRarity.Add(offer);
|
||||
}
|
||||
|
||||
if (highRarity.Count > 0)
|
||||
{
|
||||
UpgradeOffer guaranteed = highRarity[UnityEngine.Random.Range(0, highRarity.Count)];
|
||||
result.Add(guaranteed);
|
||||
pool.Remove(guaranteed);
|
||||
}
|
||||
}
|
||||
|
||||
while (pool.Count > 0 && result.Count < count)
|
||||
{
|
||||
float totalWeight = 0f;
|
||||
@@ -237,6 +245,11 @@ public class UpgradeManager : MonoBehaviour
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool IsEpicOrHigher(string rarity)
|
||||
{
|
||||
return rarity == "Epic" || rarity == "Legendary";
|
||||
}
|
||||
|
||||
static float GetRarityWeight(string rarity)
|
||||
{
|
||||
switch (rarity)
|
||||
@@ -265,6 +278,12 @@ public class UpgradeManager : MonoBehaviour
|
||||
Image image = cardObject.GetComponent<Image>();
|
||||
image.color = offer.isFree ? new Color(0.11f, 0.17f, 0.13f, 0.98f) : GetRarityColor(offer.rarity);
|
||||
|
||||
Outline outline = cardObject.AddComponent<Outline>();
|
||||
outline.effectDistance = new Vector2(3f, -3f);
|
||||
outline.effectColor = GetRarityBorderColor(offer.rarity);
|
||||
RarityPulse pulse = cardObject.AddComponent<RarityPulse>();
|
||||
pulse.Configure(outline, GetRarityBorderColor(offer.rarity));
|
||||
|
||||
Button button = cardObject.GetComponent<Button>();
|
||||
ColorBlock colors = button.colors;
|
||||
colors.normalColor = image.color;
|
||||
@@ -288,6 +307,77 @@ public class UpgradeManager : MonoBehaviour
|
||||
PlaceCardText(footer.rectTransform, 12f, 12f, -12f, 28f, false);
|
||||
}
|
||||
|
||||
RectTransform CreateChoiceRow(Transform parent)
|
||||
{
|
||||
RectTransform row = CreateRect("UpgradeChoices", parent);
|
||||
row.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
row.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
row.pivot = new Vector2(0.5f, 0.5f);
|
||||
row.anchoredPosition = new Vector2(0f, -12f);
|
||||
row.sizeDelta = new Vector2(700f, 212f);
|
||||
|
||||
HorizontalLayoutGroup layout = row.gameObject.AddComponent<HorizontalLayoutGroup>();
|
||||
layout.spacing = 16f;
|
||||
layout.childAlignment = TextAnchor.MiddleCenter;
|
||||
layout.childControlWidth = true;
|
||||
layout.childControlHeight = true;
|
||||
layout.childForceExpandWidth = false;
|
||||
layout.childForceExpandHeight = false;
|
||||
return row;
|
||||
}
|
||||
|
||||
void PopulateChoiceCards(List<UpgradeOffer> offers)
|
||||
{
|
||||
if (currentCardRow == null)
|
||||
return;
|
||||
|
||||
for (int i = currentCardRow.childCount - 1; i >= 0; i--)
|
||||
Destroy(currentCardRow.GetChild(i).gameObject);
|
||||
|
||||
foreach (UpgradeOffer offer in offers)
|
||||
CreateChoiceCard(offer, currentCardRow);
|
||||
}
|
||||
|
||||
void CreateRerollButton(Transform parent)
|
||||
{
|
||||
Button rerollButton = CreateButton("RerollButton", parent, GetRerollLabel(), RerollOffers);
|
||||
RectTransform rect = rerollButton.GetComponent<RectTransform>();
|
||||
rect.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
rect.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
rect.pivot = new Vector2(0.5f, 0.5f);
|
||||
rect.anchoredPosition = new Vector2(0f, -156f);
|
||||
rect.sizeDelta = new Vector2(190f, 42f);
|
||||
rerollButton.interactable = bits >= rerollCost;
|
||||
}
|
||||
|
||||
void RerollOffers()
|
||||
{
|
||||
if (bits < rerollCost || currentCardRow == null)
|
||||
return;
|
||||
|
||||
bits -= rerollCost;
|
||||
rerollCost++;
|
||||
UpdateBitsText();
|
||||
PopulateChoiceCards(BuildOffers(currentGuaranteeEpicOrHigher));
|
||||
|
||||
Transform rerollTransform = choiceOverlay != null ? choiceOverlay.transform.Find("RerollButton") : null;
|
||||
if (rerollTransform != null)
|
||||
{
|
||||
TextMeshProUGUI label = rerollTransform.GetComponentInChildren<TextMeshProUGUI>();
|
||||
if (label != null)
|
||||
label.text = GetRerollLabel();
|
||||
|
||||
Button button = rerollTransform.GetComponent<Button>();
|
||||
if (button != null)
|
||||
button.interactable = bits >= rerollCost;
|
||||
}
|
||||
}
|
||||
|
||||
string GetRerollLabel()
|
||||
{
|
||||
return $"REROLL ({rerollCost} BIT{(rerollCost == 1 ? "" : "S")})";
|
||||
}
|
||||
|
||||
static Color GetRarityColor(string rarity)
|
||||
{
|
||||
switch (rarity)
|
||||
@@ -301,6 +391,19 @@ public class UpgradeManager : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
static Color GetRarityBorderColor(string rarity)
|
||||
{
|
||||
switch (rarity)
|
||||
{
|
||||
case "Common": return new Color(0.62f, 0.64f, 0.66f, 0.85f);
|
||||
case "Uncommon": return new Color(0.22f, 0.9f, 0.34f, 0.9f);
|
||||
case "Rare": return new Color(0.22f, 0.48f, 1f, 0.92f);
|
||||
case "Epic": return new Color(0.68f, 0.25f, 1f, 0.95f);
|
||||
case "Legendary": return new Color(1f, 0.55f, 0.08f, 0.98f);
|
||||
default: return new Color(0.62f, 0.64f, 0.66f, 0.85f);
|
||||
}
|
||||
}
|
||||
|
||||
void SelectOffer(UpgradeOffer offer)
|
||||
{
|
||||
if (offer.isFree)
|
||||
@@ -439,6 +542,8 @@ public class UpgradeManager : MonoBehaviour
|
||||
Destroy(choiceOverlay);
|
||||
|
||||
choiceOverlay = null;
|
||||
currentCardRow = null;
|
||||
rerollCost = 1;
|
||||
Time.timeScale = 1f;
|
||||
|
||||
Action callback = currentChoiceComplete;
|
||||
@@ -588,6 +693,34 @@ public class UpgradeManager : MonoBehaviour
|
||||
return rect;
|
||||
}
|
||||
|
||||
static Button CreateButton(string name, Transform parent, string label, UnityEngine.Events.UnityAction onClick)
|
||||
{
|
||||
GameObject obj = new GameObject(name, typeof(RectTransform), typeof(CanvasRenderer), typeof(Image), typeof(Button));
|
||||
RectTransform rect = obj.GetComponent<RectTransform>();
|
||||
rect.SetParent(parent, false);
|
||||
|
||||
Image image = obj.GetComponent<Image>();
|
||||
image.color = new Color(0.18f, 0.5f, 0.74f, 1f);
|
||||
|
||||
Button button = obj.GetComponent<Button>();
|
||||
ColorBlock colors = button.colors;
|
||||
colors.normalColor = image.color;
|
||||
colors.highlightedColor = new Color(0.25f, 0.62f, 0.88f, 1f);
|
||||
colors.pressedColor = new Color(0.12f, 0.36f, 0.56f, 1f);
|
||||
colors.selectedColor = colors.highlightedColor;
|
||||
colors.disabledColor = new Color(0.16f, 0.18f, 0.22f, 0.82f);
|
||||
colors.colorMultiplier = 1f;
|
||||
button.colors = colors;
|
||||
button.onClick.AddListener(onClick);
|
||||
|
||||
TextMeshProUGUI text = CreateText("Text", rect, label, 16f, FontStyles.Bold, TextAlignmentOptions.Center);
|
||||
text.rectTransform.anchorMin = Vector2.zero;
|
||||
text.rectTransform.anchorMax = Vector2.one;
|
||||
text.rectTransform.offsetMin = Vector2.zero;
|
||||
text.rectTransform.offsetMax = Vector2.zero;
|
||||
return button;
|
||||
}
|
||||
|
||||
static TextMeshProUGUI CreateText(string name, Transform parent, string text, float fontSize, FontStyles style, TextAlignmentOptions alignment)
|
||||
{
|
||||
GameObject obj = new GameObject(name, typeof(RectTransform), typeof(CanvasRenderer), typeof(TextMeshProUGUI));
|
||||
|
||||
Reference in New Issue
Block a user