Initial commit
This commit is contained in:
Generated
+13
@@ -0,0 +1,13 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Rider ignored files
|
||||
/contentModel.xml
|
||||
/modules.xml
|
||||
/projectSettingsUpdater.xml
|
||||
/.idea.Scripts.iml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
Generated
+4
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||
</project>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="UserContentModel">
|
||||
<attachedFolders />
|
||||
<explicitIncludes />
|
||||
<explicitExcludes />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,38 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<Languages>
|
||||
<language minSize="67" name="JavaScript" />
|
||||
<language minSize="47" name="Python" />
|
||||
</Languages>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PyCallingNonCallableInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoredPackages">
|
||||
<value>
|
||||
<list size="1">
|
||||
<item index="0" class="java.lang.String" itemvalue="pytest" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PyPep8Inspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="ignoredErrors">
|
||||
<list>
|
||||
<option value="E501" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PyStatementEffectInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoredIdentifiers">
|
||||
<list>
|
||||
<option value="tuple.append" />
|
||||
<option value="str.get_width" />
|
||||
<option value="rental.return_date" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
||||
Generated
+4
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings" defaultProject="true" />
|
||||
</project>
|
||||
@@ -0,0 +1,61 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class Bullet : MonoBehaviour
|
||||
{
|
||||
public float speed = 5f;
|
||||
private int damage = 1;
|
||||
private Transform target;
|
||||
public GameObject shatterEffectPrefab;
|
||||
private Vector2 lastKnownDirection;
|
||||
private bool hasTarget = true; // Track if bullet has an active target
|
||||
|
||||
public void SetTarget(GameObject enemy)
|
||||
{
|
||||
if (enemy != null)
|
||||
{
|
||||
target = enemy.transform;
|
||||
lastKnownDirection = (target.position - transform.position).normalized; // Store initial direction
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDamage(int newDamage)
|
||||
{
|
||||
damage = newDamage;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (hasTarget && target != null)
|
||||
{
|
||||
lastKnownDirection = (target.position - transform.position).normalized; // Keep updating direction
|
||||
}
|
||||
else
|
||||
{
|
||||
hasTarget = false; // The target is gone, continue in last direction
|
||||
}
|
||||
|
||||
// Move bullet in the last known direction
|
||||
transform.position += (Vector3)lastKnownDirection * speed * Time.deltaTime;
|
||||
|
||||
// Destroy bullet after 5 seconds to prevent infinite movement
|
||||
Destroy(gameObject, 5f);
|
||||
}
|
||||
|
||||
void OnTriggerEnter2D(Collider2D other)
|
||||
{
|
||||
if (other.CompareTag("Enemy"))
|
||||
{
|
||||
other.GetComponent<EnemyHealth>().TakeDamage(damage);
|
||||
ShatterEffect();
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
void ShatterEffect()
|
||||
{
|
||||
if (shatterEffectPrefab != null)
|
||||
{
|
||||
Instantiate(shatterEffectPrefab, transform.position, Quaternion.identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc2f4c13183a4fe4aa62f7a8d5d0ee0c
|
||||
@@ -0,0 +1,32 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class Enemy : MonoBehaviour
|
||||
{
|
||||
public float speed = 1.5f;
|
||||
private Transform tower;
|
||||
private EnemyHealth enemyHealth;
|
||||
|
||||
void Start()
|
||||
{
|
||||
GameObject towerObject = GameObject.FindGameObjectWithTag("Tower");
|
||||
|
||||
if (towerObject != null)
|
||||
{
|
||||
tower = towerObject.transform;
|
||||
}
|
||||
enemyHealth = GetComponent<EnemyHealth>();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (tower == null || enemyHealth == null) return;
|
||||
transform.position = Vector2.MoveTowards(transform.position, tower.position, speed * Time.deltaTime);
|
||||
if (Vector2.Distance(transform.position, tower.position) < 0.5f)
|
||||
{
|
||||
int damageDealt = enemyHealth.GetCurrentHealth();
|
||||
tower.GetComponent<TowerHealth>().TakeDamage(damageDealt);
|
||||
enemyHealth.NotifySpawner();
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c389f0cb0e33bc4ca63795950c6d7e5
|
||||
@@ -0,0 +1,55 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class EnemyHealth : MonoBehaviour
|
||||
{
|
||||
public int health = 1;
|
||||
public GameObject shatterEffectPrefab;
|
||||
public EnemySpawner spawner;
|
||||
|
||||
public void TakeDamage(int damage)
|
||||
{
|
||||
health -= damage;
|
||||
if (health <= 0)
|
||||
{
|
||||
NotifySpawner();
|
||||
ShatterEffect();
|
||||
NotifyUpgradeManager();
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public int GetCurrentHealth()
|
||||
{
|
||||
return health;
|
||||
}
|
||||
|
||||
public void SetHealth(int newHealth)
|
||||
{
|
||||
health = newHealth;
|
||||
}
|
||||
|
||||
public void NotifySpawner()
|
||||
{
|
||||
if (spawner != null)
|
||||
{
|
||||
spawner.EnemyDefeated();
|
||||
}
|
||||
}
|
||||
|
||||
void NotifyUpgradeManager()
|
||||
{
|
||||
UpgradeManager upgradeManager = FindObjectOfType<UpgradeManager>();
|
||||
if (upgradeManager != null)
|
||||
{
|
||||
upgradeManager.EnemyKilled();
|
||||
}
|
||||
}
|
||||
|
||||
void ShatterEffect()
|
||||
{
|
||||
if (shatterEffectPrefab != null)
|
||||
{
|
||||
Instantiate(shatterEffectPrefab, transform.position, Quaternion.identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 01e7936326d532c439716d83853feb09
|
||||
@@ -0,0 +1,108 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class EnemySpawner : MonoBehaviour
|
||||
{
|
||||
public GameObject enemyPrefab;
|
||||
public Transform tower;
|
||||
public TextMeshProUGUI waveText;
|
||||
public Button startWaveButton;
|
||||
public float spawnRadius = 10f;
|
||||
private int currentWave = 1;
|
||||
private bool isSpawning = false;
|
||||
private int enemiesRemaining = 0;
|
||||
private int baseEnemyCount = 5;
|
||||
private int enemyCountIncrease = 3;
|
||||
private float enemySpeed = 1.5f;
|
||||
private int enemyBaseHP = 1;
|
||||
private float speedIncreaseRate = 0.2f;
|
||||
private int hpIncreaseRate = 1;
|
||||
private float maxEnemySpeed = 6f;
|
||||
private int maxEnemyHP = 20;
|
||||
|
||||
public void StartWave()
|
||||
{
|
||||
if (!isSpawning)
|
||||
{
|
||||
currentWave++;
|
||||
UpdateWaveText();
|
||||
enemiesRemaining = baseEnemyCount + (currentWave) * enemyCountIncrease;
|
||||
startWaveButton.gameObject.SetActive(false);
|
||||
StartCoroutine(SpawnWave());
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator SpawnWave()
|
||||
{
|
||||
isSpawning = true;
|
||||
int enemiesToSpawn = baseEnemyCount + (currentWave) * enemyCountIncrease;
|
||||
|
||||
for (int i = 0; i < enemiesToSpawn; i++)
|
||||
{
|
||||
SpawnEnemy();
|
||||
yield return new WaitForSeconds(1f);
|
||||
}
|
||||
|
||||
isSpawning = false;
|
||||
}
|
||||
|
||||
void SpawnEnemy()
|
||||
{
|
||||
Vector2 spawnPos = GetRandomSpawnPosition();
|
||||
GameObject newEnemy = Instantiate(enemyPrefab, spawnPos, Quaternion.identity);
|
||||
|
||||
Enemy enemyComponent = newEnemy.GetComponent<Enemy>();
|
||||
if (enemyComponent != null)
|
||||
{
|
||||
// Lower speed scale to 0.1f
|
||||
float waveSpeedBonus = currentWave * 0.1f;
|
||||
enemyComponent.speed = Mathf.Min(maxEnemySpeed, enemySpeed + waveSpeedBonus);
|
||||
}
|
||||
|
||||
EnemyHealth enemyHealth = newEnemy.GetComponent<EnemyHealth>();
|
||||
if (enemyHealth != null)
|
||||
{
|
||||
// For HP: baseHP + wave * 0.3 (round it)
|
||||
int scaledHP = enemyBaseHP + Mathf.RoundToInt(currentWave * 0.3f);
|
||||
scaledHP = Mathf.Min(maxEnemyHP, scaledHP);
|
||||
enemyHealth.SetHealth(scaledHP);
|
||||
|
||||
enemyHealth.spawner = this;
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 GetRandomSpawnPosition()
|
||||
{
|
||||
float angle = Random.Range(0, 360) * Mathf.Deg2Rad;
|
||||
return (Vector2)tower.position + new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * spawnRadius;
|
||||
}
|
||||
|
||||
void UpdateWaveText()
|
||||
{
|
||||
if (waveText != null)
|
||||
{
|
||||
waveText.text = "Wave: " + currentWave;
|
||||
}
|
||||
}
|
||||
|
||||
public void EnemyDefeated()
|
||||
{
|
||||
enemiesRemaining--;
|
||||
if (enemiesRemaining <= 0)
|
||||
{
|
||||
startWaveButton.gameObject.SetActive(true);
|
||||
|
||||
// If wave is multiple of 5, show special upgrade choice
|
||||
if (currentWave % 5 == 0)
|
||||
{
|
||||
UpgradeManager upgradeManager = FindObjectOfType<UpgradeManager>();
|
||||
if (upgradeManager != null)
|
||||
{
|
||||
upgradeManager.ShowSpecialUpgradeChoice();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 26b80a73eb730cb4fb4e079d98235253
|
||||
@@ -0,0 +1,17 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
public class MainMenu : MonoBehaviour
|
||||
{
|
||||
public void StartGame()
|
||||
{
|
||||
Debug.Log("Game Start!");
|
||||
SceneManager.LoadScene("SampleScene");
|
||||
}
|
||||
|
||||
public void QuitGame()
|
||||
{
|
||||
Debug.Log("Game Quit!");
|
||||
Application.Quit();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 04438cc05d1d0f643a51f117e8f28494
|
||||
@@ -0,0 +1,25 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class SpecialChoiceCard : MonoBehaviour
|
||||
{
|
||||
public UpgradeManager upgradeManager;
|
||||
|
||||
void OnMouseDown()
|
||||
{
|
||||
// Identify which UpgradeType this card has
|
||||
UpgradeCard card = GetComponent<UpgradeCard>();
|
||||
if (card != null)
|
||||
{
|
||||
upgradeManager.UnlockSpecialUpgrade(card.upgradeType);
|
||||
}
|
||||
|
||||
// Destroy all other special cards
|
||||
SpecialChoiceCard[] allChoices = FindObjectsOfType<SpecialChoiceCard>();
|
||||
foreach (var choice in allChoices)
|
||||
{
|
||||
Destroy(choice.gameObject);
|
||||
}
|
||||
|
||||
Time.timeScale = 1f; // Resume game
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d508f3bec6b44ffb7914c41f743fcdd
|
||||
timeCreated: 1742472511
|
||||
@@ -0,0 +1,63 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class Tower : MonoBehaviour
|
||||
{
|
||||
public static Tower Instance;
|
||||
public GameObject bulletPrefab;
|
||||
public int damage = 1;
|
||||
public float fireRate = 1f;
|
||||
public float attackRange = 5f;
|
||||
private float nextFireTime;
|
||||
private GameObject currentTarget;
|
||||
public int extraBullets = 0; // For "Shoot +1 bullet"
|
||||
public bool homingEnabled = false;
|
||||
public bool ricochetEnabled = false;
|
||||
public bool pierceEnabled = false;
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (Time.time >= nextFireTime)
|
||||
{
|
||||
RetargetAndFire();
|
||||
nextFireTime = Time.time + fireRate;
|
||||
}
|
||||
}
|
||||
|
||||
void RetargetAndFire()
|
||||
{
|
||||
currentTarget = GetNearestEnemy();
|
||||
if (currentTarget != null)
|
||||
{
|
||||
FireAtTarget(currentTarget);
|
||||
}
|
||||
}
|
||||
|
||||
void FireAtTarget(GameObject target)
|
||||
{
|
||||
GameObject bullet = Instantiate(bulletPrefab, transform.position, Quaternion.identity);
|
||||
bullet.GetComponent<Bullet>().SetDamage(damage);
|
||||
bullet.GetComponent<Bullet>().SetTarget(target);
|
||||
}
|
||||
|
||||
GameObject GetNearestEnemy()
|
||||
{
|
||||
float minDist = float.MaxValue;
|
||||
GameObject nearestEnemy = null;
|
||||
foreach (GameObject enemy in GameObject.FindGameObjectsWithTag("Enemy"))
|
||||
{
|
||||
float dist = Vector2.Distance(transform.position, enemy.transform.position);
|
||||
if (dist < minDist && dist <= attackRange)
|
||||
{
|
||||
minDist = dist;
|
||||
nearestEnemy = enemy;
|
||||
}
|
||||
}
|
||||
|
||||
return nearestEnemy;
|
||||
}
|
||||
public void OnEnemyDestroyed()
|
||||
{
|
||||
RetargetAndFire();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50b372157104f4b408854b557144ecd6
|
||||
@@ -0,0 +1,71 @@
|
||||
using System.Collections; // Required for IEnumerator
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
|
||||
public class TowerHealth : MonoBehaviour
|
||||
{
|
||||
public int maxHealth = 100;
|
||||
private int currentHealth;
|
||||
private SpriteRenderer spriteRenderer;
|
||||
public GameObject floatingTextPrefab;
|
||||
|
||||
void Start()
|
||||
{
|
||||
currentHealth = maxHealth;
|
||||
spriteRenderer = GetComponent<SpriteRenderer>();
|
||||
UpdateColor();
|
||||
}
|
||||
|
||||
public void TakeDamage(int damage)
|
||||
{
|
||||
currentHealth -= damage;
|
||||
if (currentHealth < 0) currentHealth = 0;
|
||||
ShowFloatingDamage(damage);
|
||||
UpdateColor();
|
||||
|
||||
if (currentHealth <= 0)
|
||||
{
|
||||
Debug.Log("Tower Destroyed! Game Over.");
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateColor()
|
||||
{
|
||||
float healthPercentage = (float)currentHealth / maxHealth;
|
||||
spriteRenderer.color = Color.Lerp(Color.red, Color.green, healthPercentage);
|
||||
}
|
||||
|
||||
void ShowFloatingDamage(int damage)
|
||||
{
|
||||
if (floatingTextPrefab != null)
|
||||
{
|
||||
GameObject damageTextInstance = Instantiate(
|
||||
floatingTextPrefab,
|
||||
transform.position + new Vector3(0, 1.5f, 0),
|
||||
Quaternion.identity
|
||||
);
|
||||
TextMeshPro tmp = damageTextInstance.GetComponent<TextMeshPro>();
|
||||
tmp.text = "-" + damage.ToString();
|
||||
StartCoroutine(FadeAndMoveText(damageTextInstance));
|
||||
Destroy(damageTextInstance, 1.5f);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator FadeAndMoveText(GameObject textObj)
|
||||
{
|
||||
float duration = 1f;
|
||||
float elapsed = 0f;
|
||||
Vector3 startPos = textObj.transform.position;
|
||||
Vector3 targetPos = startPos + new Vector3(0, 1f, 0); // Move up
|
||||
TextMeshPro tmp = textObj.GetComponent<TextMeshPro>();
|
||||
Color startColor = tmp.color;
|
||||
while (elapsed < duration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = elapsed / duration;
|
||||
textObj.transform.position = Vector3.Lerp(startPos, targetPos, t);
|
||||
tmp.color = new Color(startColor.r, startColor.g, startColor.b, 1 - t);
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50fa3b33053ba8c45ba59e06db0e2c5f
|
||||
@@ -0,0 +1,70 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
public class UpgradeCard : MonoBehaviour
|
||||
{
|
||||
public enum UpgradeType
|
||||
{
|
||||
FireRate = 0,
|
||||
Range = 1,
|
||||
Damage = 2,
|
||||
MultiShot= 3,
|
||||
Homing = 4,
|
||||
Ricochet = 5,
|
||||
}
|
||||
|
||||
|
||||
|
||||
public UpgradeType upgradeType;
|
||||
public int upgradeLevel = 1;
|
||||
public int upgradeCost;
|
||||
public UpgradeManager upgradeManager;
|
||||
public TextMeshProUGUI upgradeText;
|
||||
public TextMeshProUGUI upgradeDescription;
|
||||
public TextMeshProUGUI upgradeCostText;
|
||||
|
||||
void Start()
|
||||
{
|
||||
// If not assigned in Inspector, try to find them by name
|
||||
if (upgradeText == null)
|
||||
upgradeText = transform.Find("Canvas/UpgradeText").GetComponent<TextMeshProUGUI>();
|
||||
if (upgradeDescription == null)
|
||||
upgradeDescription = transform.Find("Canvas/UpgradeDescription").GetComponent<TextMeshProUGUI>();
|
||||
if (upgradeCostText == null)
|
||||
upgradeCostText = transform.Find("Canvas/UpgradeCost").GetComponent<TextMeshProUGUI>();
|
||||
|
||||
// Update all UI fields
|
||||
UpdateUpgradeUI();
|
||||
}
|
||||
|
||||
void OnMouseDown()
|
||||
{
|
||||
// When clicked, attempt to buy/upgrade
|
||||
upgradeManager.TryUpgrade(upgradeType);
|
||||
}
|
||||
|
||||
public void UpdateUpgradeUI()
|
||||
{
|
||||
if (upgradeText != null)
|
||||
{
|
||||
string roman = ConvertToRoman(upgradeLevel);
|
||||
upgradeText.text = $"{upgradeType} {roman}";
|
||||
}
|
||||
|
||||
// 2) Description is presumably already set in the prefab,
|
||||
// but if you want to set it dynamically, you can do so here.
|
||||
// e.g.: upgradeDescription.text = "This does X, Y, Z..."
|
||||
|
||||
// 3) Cost text, e.g. "Cost: 5 Bits"
|
||||
if (upgradeCostText != null)
|
||||
{
|
||||
upgradeCostText.text = $"Cost: {upgradeCost} Bits";
|
||||
}
|
||||
}
|
||||
|
||||
string ConvertToRoman(int number)
|
||||
{
|
||||
string[] numerals = { "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X" };
|
||||
return number > 10 ? number.ToString() : numerals[number - 1];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 821918f62c41f564fa08120e9bb6db3a
|
||||
@@ -0,0 +1,240 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
|
||||
public class UpgradeManager : MonoBehaviour
|
||||
{
|
||||
public GameObject[] normalUpgradePrefabs; // FireRate, Range, Damage
|
||||
public GameObject[] specialUpgradePrefabs; // MultiShot, Homing, Ricochet, etc.
|
||||
|
||||
[HideInInspector] public List<UpgradeCard.UpgradeType> unlockedUpgrades = new List<UpgradeCard.UpgradeType>();
|
||||
// Stores which special upgrades have been permanently unlocked.
|
||||
|
||||
// UI placeholder to spawn the 3 choices
|
||||
public Transform specialUpgradeSpawnParent; // A center-of-screen parent or coordinates
|
||||
public float specialUpgradeSpacing = 2f;
|
||||
|
||||
public Tower tower;
|
||||
private Dictionary<UpgradeCard.UpgradeType, int> upgradeLevels = new Dictionary<UpgradeCard.UpgradeType, int>();
|
||||
private Dictionary<UpgradeCard.UpgradeType, int> upgradeCosts = new Dictionary<UpgradeCard.UpgradeType, int>();
|
||||
public int bits = 5;
|
||||
public TextMeshProUGUI bitsText;
|
||||
|
||||
void Start()
|
||||
{
|
||||
InitializeUpgrades();
|
||||
UpdateBitsText();
|
||||
Debug.Log($"specialUpgradePrefabs length: {specialUpgradePrefabs.Length}");
|
||||
}
|
||||
|
||||
public void EnemyKilled()
|
||||
{
|
||||
bits++;
|
||||
UpdateBitsText();
|
||||
}
|
||||
|
||||
void InitializeUpgrades()
|
||||
{
|
||||
float spacing = 2.5f;
|
||||
float startX = -((normalUpgradePrefabs.Length - 1) * spacing / 2f);
|
||||
foreach (UpgradeCard.UpgradeType type in System.Enum.GetValues(typeof(UpgradeCard.UpgradeType)))
|
||||
{
|
||||
if (!upgradeLevels.ContainsKey(type))
|
||||
upgradeLevels[type] = 0;
|
||||
if (!upgradeCosts.ContainsKey(type))
|
||||
upgradeCosts[type] = GetBaseCost(type);
|
||||
}
|
||||
|
||||
for (int i = 0; i < normalUpgradePrefabs.Length; i++)
|
||||
{
|
||||
UpgradeCard.UpgradeType upgradeType = (UpgradeCard.UpgradeType)i;
|
||||
SpawnUpgradeCard(upgradeType, startX + (i * spacing));
|
||||
}
|
||||
}
|
||||
|
||||
void SpawnUpgradeCard(UpgradeCard.UpgradeType upgradeType, float xPos)
|
||||
{
|
||||
Vector3 spawnPosition = new Vector3(xPos, -4f, 0);
|
||||
|
||||
// Ensure dictionaries have entries for this type
|
||||
if (!upgradeLevels.ContainsKey(upgradeType))
|
||||
upgradeLevels[upgradeType] = 0;
|
||||
if (!upgradeCosts.ContainsKey(upgradeType))
|
||||
upgradeCosts[upgradeType] = GetBaseCost(upgradeType);
|
||||
|
||||
// Determine this upgrade's current level
|
||||
int currentLevel = upgradeLevels[upgradeType] + 1;
|
||||
|
||||
// 1) Choose which prefab array to use
|
||||
GameObject prefab;
|
||||
if ((int)upgradeType < normalUpgradePrefabs.Length)
|
||||
{
|
||||
// It's one of FireRate=0, Range=1, Damage=2
|
||||
prefab = normalUpgradePrefabs[(int)upgradeType];
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's a special upgrade, e.g. MultiShot, Homing, Ricochet
|
||||
int specialIndex = (int)upgradeType - normalUpgradePrefabs.Length;
|
||||
// e.g. MultiShot=3 => specialIndex=0
|
||||
// Homing=4 => specialIndex=1, etc.
|
||||
prefab = specialUpgradePrefabs[specialIndex];
|
||||
}
|
||||
|
||||
// 2) Instantiate the correct prefab
|
||||
GameObject upgradeCardObj = Instantiate(prefab, spawnPosition, Quaternion.identity);
|
||||
|
||||
// 3) Set up the UpgradeCard component
|
||||
UpgradeCard upgradeCard = upgradeCardObj.GetComponentInChildren<UpgradeCard>();
|
||||
if (upgradeCard != null)
|
||||
{
|
||||
upgradeCard.upgradeType = upgradeType;
|
||||
upgradeCard.upgradeLevel = currentLevel;
|
||||
upgradeCard.upgradeCost = upgradeCosts[upgradeType];
|
||||
upgradeCard.upgradeManager = this;
|
||||
upgradeCard.upgradeText = upgradeCardObj.GetComponentInChildren<TextMeshProUGUI>(true);
|
||||
upgradeCard.UpdateUpgradeUI();
|
||||
}
|
||||
}
|
||||
|
||||
public int GetBaseCost(UpgradeCard.UpgradeType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case UpgradeCard.UpgradeType.FireRate: return 3;
|
||||
case UpgradeCard.UpgradeType.Range: return 2;
|
||||
case UpgradeCard.UpgradeType.Damage: return 5;
|
||||
default: return 1;
|
||||
}
|
||||
}
|
||||
|
||||
public void TryUpgrade(UpgradeCard.UpgradeType type)
|
||||
{
|
||||
if (bits >= upgradeCosts[type])
|
||||
{
|
||||
bits -= upgradeCosts[type];
|
||||
upgradeLevels[type]++;
|
||||
upgradeCosts[type] += (int)(upgradeCosts[type] * 0.5f);
|
||||
ApplyUpgrade(type);
|
||||
UpdateBitsText();
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyUpgrade(UpgradeCard.UpgradeType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case UpgradeCard.UpgradeType.FireRate:
|
||||
tower.fireRate *= 0.9f;
|
||||
break;
|
||||
case UpgradeCard.UpgradeType.Range:
|
||||
tower.attackRange += 2.5f;
|
||||
break;
|
||||
case UpgradeCard.UpgradeType.Damage:
|
||||
tower.damage += 1;
|
||||
break;
|
||||
case UpgradeCard.UpgradeType.Ricochet:
|
||||
tower.ricochetEnabled = true;
|
||||
break;
|
||||
case UpgradeCard.UpgradeType.Homing:
|
||||
tower.homingEnabled = true;
|
||||
break;
|
||||
case UpgradeCard.UpgradeType.MultiShot:
|
||||
tower.extraBullets += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
UpdateUpgradeCards();
|
||||
}
|
||||
|
||||
void UpdateUpgradeCards()
|
||||
{
|
||||
UpgradeCard[] allCards = FindObjectsOfType<UpgradeCard>();
|
||||
foreach (UpgradeCard card in allCards)
|
||||
{
|
||||
card.upgradeLevel = upgradeLevels[card.upgradeType] + 1;
|
||||
card.upgradeCost = upgradeCosts[card.upgradeType];
|
||||
card.UpdateUpgradeUI();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateBitsText()
|
||||
{
|
||||
if (bitsText != null)
|
||||
{
|
||||
bitsText.text = "Bits: " + bits;
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowSpecialUpgradeChoice()
|
||||
{
|
||||
Debug.Log(specialUpgradeSpawnParent.name);
|
||||
Debug.Log("Showing Upgrades...");
|
||||
List<GameObject> available = new List<GameObject>(specialUpgradePrefabs);
|
||||
|
||||
// Shuffle the list to randomize order (Fisher-Yates)
|
||||
for (int i = 0; i < available.Count; i++)
|
||||
{
|
||||
int rand = Random.Range(i, available.Count);
|
||||
var temp = available[i];
|
||||
available[i] = available[rand];
|
||||
available[rand] = temp;
|
||||
}
|
||||
|
||||
// Determine how many upgrades we can actually show
|
||||
int numToShow = Mathf.Min(3, available.Count);
|
||||
|
||||
// If there are no upgrades left, resume game and return
|
||||
if (numToShow == 0)
|
||||
{
|
||||
Debug.Log("No special upgrades available!");
|
||||
Time.timeScale = 1f;
|
||||
return;
|
||||
}
|
||||
|
||||
// Instantiate the first 'numToShow' from the shuffled list
|
||||
float startX = -specialUpgradeSpacing;
|
||||
for (int i = 0; i < numToShow; i++)
|
||||
{
|
||||
float xPos = startX + i * specialUpgradeSpacing;
|
||||
Vector3 spawnPos = specialUpgradeSpawnParent.position + new Vector3(xPos, 0, 0);
|
||||
|
||||
GameObject specialCardObj =
|
||||
Instantiate(available[i], spawnPos, Quaternion.identity, specialUpgradeSpawnParent);
|
||||
Debug.Log("Spawned special card: " + specialCardObj, specialCardObj);
|
||||
// Add your click-to-choose script
|
||||
SpecialChoiceCard choiceCard = specialCardObj.AddComponent<SpecialChoiceCard>();
|
||||
choiceCard.upgradeManager = this;
|
||||
}
|
||||
}
|
||||
|
||||
public void UnlockSpecialUpgrade(UpgradeCard.UpgradeType type)
|
||||
{
|
||||
Debug.Log("Card chosen! Applying upgrade...");
|
||||
// 1) Add this special upgrade type to the dictionary if not present
|
||||
if (!upgradeLevels.ContainsKey(type))
|
||||
{
|
||||
upgradeLevels[type] = 0;
|
||||
upgradeCosts[type] = GetBaseCost(type);
|
||||
}
|
||||
|
||||
// 2) Add to the “unlockedUpgrades” list if you want to track them
|
||||
if (!unlockedUpgrades.Contains(type))
|
||||
unlockedUpgrades.Add(type);
|
||||
|
||||
// 3) Instantiate it at the bottom row with the other upgrades
|
||||
float newXPos = CalculateNextUpgradeXPos(); // A method to place new card to the right
|
||||
SpawnUpgradeCard(type, newXPos);
|
||||
}
|
||||
|
||||
// Example method to find a new X position for the newly unlocked card
|
||||
float CalculateNextUpgradeXPos()
|
||||
{
|
||||
// If you originally placed normal upgrades from -X to +X,
|
||||
// find how many total upgrades are unlocked, and space them out.
|
||||
// For simplicity:
|
||||
int totalUnlocked = FindObjectsOfType<UpgradeCard>().Length;
|
||||
float spacing = 2.5f;
|
||||
return -((totalUnlocked - 1) * spacing / 2f) + (totalUnlocked - 1) * spacing;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57719a5f7440e814890b2e4abbaca663
|
||||
Reference in New Issue
Block a user