nickmattinson / ZXYZ

Top-Down 2D Dungeon Crawler
1 stars 0 forks source link

Superman #63

Closed MikeMMattinson closed 2 months ago

MikeMMattinson commented 2 months ago

NICK'S THOUGHTS:

Limit health, attack and defense and/or make the enemies harder as the game progresses...

In Player.cs:

In Enemy.cs:

git fetch origin
git checkout 63-superman
MikeMMattinson commented 2 months ago
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using TMPro;
using System;

public class Player : Entity
{
    public StateManager stateManager;
    private int score;
    private string username;
    private TextMeshProUGUI scoreText;

    public new void Awake(){

        score = 0;
        SetLevel(1);
        SetAttack(3);
        SetDefense(2);
        SetHealth(9999);
        username = "Unknown player";

        Debug.Log($"Construct Player: {this}"); // debug

    }

    public void SetUsername(string username){
        this.username = username;
    }

    public string GetUsername(){
        return username;
    }

    public void SetScore(int score){
        this.score = score;
    }

    public int GetScore(){
        return score;
    }   

    void Start()
    {
        // get rid of the Clone reference    
        this.name = this.name.Replace("(Clone)","").Trim();

        //scoreText = GameObject.FindGameObjectWithTag("Score").GetComponent<TextMeshProUGUI>();
        Vector2 vector2d = new Vector2();
        vector2d.x = 0f;
        vector2d.y = 90f;
        stateManager = FindObjectOfType<StateManager>();
        this.transform.position = vector2d;

        // get player prefs PlayerUserName
        username = "";

        Debug.Log($"Start Player: {this}"); // debug

    }

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            // Convert mouse position to world space in 2D
            Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            // Perform a raycast in 2D from the mouse position
            RaycastHit2D hit = Physics2D.Raycast(mousePosition, Vector2.zero);

            if (hit.collider != null)
            {
                Enemy enemy = hit.collider.GetComponent<Enemy>();
                if (enemy != null)
                {
                    // Deal damage to the enemy
                    Debug.Log("Player's attack is " + GetAttack());
                    enemy.TakeDamage(GetAttack());
                }

                TutorialEnemy tutorialEnemy = hit.collider.GetComponent<TutorialEnemy>();
                if (tutorialEnemy != null)
                {
                    // Deal damage to the enemy
                    Debug.Log("Player's attack is " + GetAttack());
                    tutorialEnemy.TakeDamage(GetAttack());
                }
            }
        }
    }
    public void ActivatePowerUp(string powerUp)
    {
        // attackup +1, but limited to 8
        if (powerUp == "AttackUp")
        {
            SetAttack(Math.Min(GetAttack()+1,8));
        }

        // health + 20, but limited to 200
        if (powerUp == "HealthUp")
        {
            SetHealth(Math.Min(GetHealth()+20,200));
        }

        // defense +1, but limited to 8
        if (powerUp == "DefenseUp")
        {
            SetDefense(Math.Min(GetDefense()+1,8));
        }
    }

    protected override void Die()
    {
        Debug.Log($"Player {username} has died. Score: {score}");
        //scoreText.text = score.ToString();
        stateManager.loadGameOver();
    }

    public override string ToString()
    {
        return $"{username}, Level: {GetLevel()}, Health: {GetHealth()}, Defense: {GetDefense()}, Attack: {GetAttack()}";
    }
}
MikeMMattinson commented 2 months ago
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : Entity
{
    private Player player;
    public LineRenderer lineRenderer;
    private float lineDuration = 0.1f;
    [SerializeField] List<GameObject> powerupList;
    //[SerializeField] List<GameObject> enemyTypeList;
    private int randomNumber;
    private Vector3 spawnPosition;
    private Vector3 deathPosition;
    private Color color;

    public void Initialize(int level, Color color)
    {
        SetLevel(level);
        SetColor(color);
        SetCapability();
    }

    void Start()
    {
        // get rid of the Clone reference    
        this.name = this.name.Replace("(Clone)","").Trim();

        player = FindObjectOfType<Player>();

    }

    public void SetCapability(){
        switch(GetLevel()) 
        {
        case 0:
            // code block
            SetAttack(4);
            SetDefense(1);
            SetHealth(2);            
            break;

        case 1:
            // code block
            SetAttack(4);
            SetDefense(2);
            SetHealth(10);            
            break;

        case 2:
            // code block
            SetAttack(5);
            SetDefense(5);
            SetHealth(40);            
            break;

        case 3:
            // code block
            SetAttack(10);
            SetDefense(10);
            SetHealth(90);            
            break;

        default:
            // code block
            SetAttack(4);
            SetDefense(1);
            SetHealth(10);            
            break;
        }
    }

    public void attackOther(Entity other)
    {

        // if attack > other.defense then attack
        if (this.GetAttack() > other.GetDefense())
        {
            Debug.Log($"{name} at {transform.position} attacks {other.name} at {other.transform.position} with Attack: {this.GetAttack()}");

            // call TakeDamage()
            other.TakeDamage(this.GetAttack());

            // draw attack line from enemy to other
            //drawLineToPlayer();
        }

    }

    public void SetSpawnPosition(Vector3 spawnPosition)
    {
        this.spawnPosition = spawnPosition;
    }

    public Vector3 GetSpawnPosition()
    {
        return spawnPosition;
    }

    // public void drawLineToPlayer()
    // {
    //     // Set the positions for the LineRenderer (start and end points)
    //     lineRenderer.SetPosition(0, transform.position); // Start position: enemy's position
    //     lineRenderer.SetPosition(1, player.transform.position);    // End position: player's position

    //     // Enable the LineRenderer to make the line visible
    //     lineRenderer.enabled = true;

    //     // Start coroutine to disable LineRenderer after duration
    //     StartCoroutine(DisableLineRendererAfterDelay());
    // }
    // // Coroutine to disable LineRenderer after specified duration
    // private IEnumerator DisableLineRendererAfterDelay()
    // {
    //     yield return new WaitForSeconds(lineDuration);
    //     lineRenderer.enabled = false;
    // }
    public void SetPlayerReference(Player player)
    {
        this.player = player;
    }

    protected override void Die()
    {
        player.SetScore(player.GetScore()+1);

        // step 1 - set death position
        deathPosition = transform.position;
        Debug.Log($"{name} was killed by {player.name} at position {deathPosition}.");

        // step 2 - drop a random buf at death position randomly
        int rn = Random.Range(0, 100);
        //Debug.Log($"Random number: {randomNumber}");
        if (rn >= randomNumber)
        {
            GameObject currentPowerupPrefab = powerupList[Random.Range(0, powerupList.Count)];
            GameObject powerupInstance = Instantiate(currentPowerupPrefab, deathPosition, Quaternion.identity);
            Debug.Log($"Power up {powerupInstance} created.");
        }

        // step 3 - after random short delay, spawn new enemy at the spawn position as function of the game level and player health
        StartCoroutine(SpawnEnemyWithDelay());
        transform.position = new Vector3(1000f, 1000f, transform.position.z);
    }

    IEnumerator SpawnEnemyWithDelay()
    /*
        Modify random spawn rate
        Randomly respawn between 4 and 10 seconds.
        Author: ChatGPT3.5
        Author: Mike M
        Modified: 23/Apr/24
    */
    {
        float minimum = 4f; // 4 seconds
        float maximum = 10f; // 10 seconds

        // Generate a random spawn delay within the specified range
        float spawnDelay = Random.Range(minimum, maximum);

        // Wait for the specified delay
        yield return new WaitForSeconds(spawnDelay);

        // Spawn the enemy after the delay
        SpawnEnemy();

        // Destroy the object (assuming this script is attached to the object you want to destroy)
        Destroy(gameObject);
    }

    public void SpawnEnemy()
    {
        Enemy currentEnemyPrefab = FindObjectOfType<Enemy>();
        Enemy enemyInstance = Instantiate(currentEnemyPrefab, spawnPosition, Quaternion.identity);
        enemyInstance.name = enemyInstance.name.Replace("(Clone)","").Trim();

        // Set player reference for the enemy
        Enemy enemyComponent = enemyInstance.GetComponent<Enemy>();

        // set player reference
        if (enemyComponent != null)
        {
            enemyComponent.SetSpawnPosition(enemyComponent.transform.position);
            enemyComponent.SetPlayerReference(player);
        }
        else
        {
            Debug.LogWarning("Enemy component not found on instantiated enemy!");
        }

        Debug.Log($"Replace Enemy {enemyInstance} created at position {spawnPosition}.");
    }

    protected virtual void SetColor(Color color)
    {
        Renderer renderer = GetComponent<Renderer>();
        if (renderer != null)
        {
            renderer.material.color = color;
        }
    }

    public Color GetColor(){
        return this.color;
    }
    public override string ToString()
    {
        string temp = $"{base.ToString()}";
        temp += $", Enemy: {name}";
        temp += $", Spawnpoint: {spawnPosition}";
        return temp;
    }
}
MikeMMattinson commented 2 months ago
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemySpawner : MonoBehaviour
{
    [SerializeField] List<Transform> enemySpawnPoints;
    [SerializeField] StateManager stateManager;
    [SerializeField] List<GameObject> easyEnemies;
    [SerializeField] List<GameObject> medEnemies;
    [SerializeField] List<GameObject> hardEnemies;

    protected int numberOfSpawns;
    private Player player;

    void Start()
    {
        stateManager = FindObjectOfType<StateManager>();
        player = FindObjectOfType<Player>(); // Assuming there's a Player object in the scene

        if (stateManager.gameEnded != true)
        {
            numberOfSpawns = enemySpawnPoints.Count;
            for (int i = 0; i < numberOfSpawns; i++)
            {
                // Retrieve spawn point
                Transform spawnPoint = enemySpawnPoints[i];

                // Instantiate the enemy prefab
                int enemyLevel = Random.Range(1, 4); // Example: Random level between 1 and 3
                GameObject enemyInstance = Instantiate(GetEnemyPrefab(enemyLevel), spawnPoint.position, spawnPoint.rotation);
                enemyInstance.name = enemyInstance.name.Replace("(Clone)", "").Trim();

                // Set enemy level and color based on your logic

                Color enemyColor = GetEnemyColor(enemyLevel); // Example: Get color based on level

                // Set enemy level and color using the appropriate script
                SetEnemyParameters(enemyInstance, enemyLevel, enemyColor);
            }
        }
    }

    GameObject GetEnemyPrefab(int level)
    {
        switch (level)
        {
            case 1: // EasyEnemy
                return easyEnemies[Random.Range(0, easyEnemies.Count)];
            case 2: // MedEnemy
                return medEnemies[Random.Range(0, medEnemies.Count)];
            case 3: // HardEnemy
                return hardEnemies[Random.Range(0, hardEnemies.Count)];
            default: // Default to EasyEnemy if level is not recognized
                Debug.LogWarning("Unknown enemy level, defaulting to EasyEnemy.");
                return easyEnemies[Random.Range(0, easyEnemies.Count)];
        }
    }

    Color GetEnemyColor(int level)
    {
        // Implement your logic to determine enemy color based on level
        // This is just an example, you can modify it as per your needs
        switch (level)
        {
            case 1: return Color.green;
            case 2: return Color.yellow;
            case 3: return Color.red;
            default: return Color.white; // Default color
        }
    }

    void SetEnemyParameters(GameObject enemy, int level, Color color)
    {
        Enemy enemyComponent = enemy.GetComponent<Enemy>();

        if (enemyComponent != null)
        {
            enemyComponent.Initialize(level, color);
            enemyComponent.SetPlayerReference(player);
        }
        else
        {
            Debug.LogWarning("Enemy component not found on instantiated enemy!");
        }
    }
}
MikeMMattinson commented 2 months ago
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
[System.Serializable]
public class Entity : MonoBehaviour
{
    private int level;
    private int health;
    private int attack;
    private int defense;
    public GameObject damageNumberPrefab;

    public void Awake(){
        level = 0;
        health = 10;
        attack = 1;
        defense = 1;
    }

    public void TakeDamage(int damage)
    {
        if (damage > defense)
        {
            //Debug.Log("damage: " + damage + " and defense: " + defense); 
            int actualDamage = damage - defense;
            health -= (actualDamage);
            // Instantiate damage number prefab at enemy's position
            GameObject damageNumberObj = Instantiate(damageNumberPrefab, transform.position, Quaternion.identity);

            if (damageNumberPrefab != null)
            {
                // Set the damage value on the damage number
                DamageNumber damageNumber = damageNumberObj.GetComponent<DamageNumber>();

                damageNumber.SetDamage(actualDamage);
                if (health <= 0)
                {
                    Die();
                }
            }
            else
            {
                Debug.Log("did not create damage number object.");
            }
        }
    }
    protected virtual void Die()
    {
        // Override this method in derived classes
        Debug.Log("Entity died!");
    }

    public void SetLevel(int level)
    {
        this.level = level;
    }

    public int GetLevel(){
        return level;
    }

    public void SetAttack(int attack)
    {
        this.attack = attack;
    }

    public int GetAttack(){
        return attack;
    }

    public void SetDefense(int defense)
    {
        this.defense = defense;
    }

    public int GetDefense(){
        return defense;
    }

    public void SetHealth(int health){
        this.health = health;
    }

    public int GetHealth(){
        return health;
    }
    public override string ToString()
    {
        string temp = $", Level: {level}";
        temp += $", Health: {health}";
        temp += $", Defense: {defense}";
        temp += $", Attack: {attack}";
        temp += $", Position: {transform.position}";
        return temp;
    }
}
MikeMMattinson commented 2 months ago
// EasyEnemy.cs
//using System.Drawing;

using UnityEngine;

public class EasyEnemy : Enemy
{

    // You can override methods or add specific easy enemy functionality here

    public void Start(){
        Initialize(1, Color.green);
        SetCapability();
    }
}
MikeMMattinson commented 2 months ago
// MediumEnemy.cs
using UnityEngine;

public class MediumEnemy : Enemy
{

    // You can override methods or add specific medium enemy functionality here

    public void Start(){
        Initialize(2, Color.yellow);
        SetCapability();
    }
}
MikeMMattinson commented 2 months ago
// HardEnemy.cs
using UnityEngine;

public class HardEnemy : Enemy
{

    // You can override methods or add specific hard enemy functionality here

    public void Start(){
        Initialize(3, Color.magenta);
        SetCapability();
    }
}
MikeMMattinson commented 2 months ago
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PowerUp : MonoBehaviour
{
    [SerializeField] string powerUpName;
    // Define the ability or effect provided by this power-up
    public void ApplyAbility(Player player, string powerUpName)
    {
        player.ActivatePowerUp(powerUpName);
    }

    void OnTriggerEnter2D(Collider2D other)
    {
        // Check if the object entering the trigger is the player
        Player player = other.GetComponent<Player>();
        if (player != null)
        {
            // Apply the power-up ability to non-healthy player
            if(player.GetHealth()<200 && this.powerUpName == "HealthUp") {
                ApplyAbility(player, this.powerUpName);
                Destroy(gameObject);

            } else if(this.powerUpName != "HealthUp") {
                ApplyAbility(player, this.powerUpName); 
                Destroy(gameObject);

            }
        }
    }
}
MikeMMattinson commented 2 months ago
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UIElements;

public class StateManager : MonoBehaviour
{
    public bool gameEnded;
    [SerializeField] GameObject mainMenuCanvas;
    [SerializeField] GameObject settingsCanvas;
    [SerializeField] GameObject gameOverCanvas;
    [SerializeField] GameObject gameCanvas;
    [SerializeField] GameObject leaderboardCanvas;
    [SerializeField] private Player player;

    public UnityEvent<string, int> submitScoreEvent;

    //[SerializeField] private TextMeshProUGUI scoreValue;

    [SerializeField] private TMP_InputField usernameInput;
    [SerializeField] private TextMeshProUGUI usernameIngame; // display
    //[SerializeField] private TextMeshProUGUI playerprefText;

    // Start is called before the first frame update
    void Start()
    {
        // Check if PlayerPrefs has a stored username
        player = FindObjectOfType<Player>();
        string storedUsername = PlayerPrefs.GetString("PlayerUserName");
        if (!string.IsNullOrEmpty(storedUsername))
        {
            // Set usernameInput and usernameIngame
            usernameInput.text = storedUsername;
            usernameIngame.text = storedUsername;
        }

        // setup the canvas
        gameEnded = false;
        Time.timeScale = 0f;
        mainMenuCanvas.SetActive(true);
        settingsCanvas.SetActive(false);
        gameOverCanvas.SetActive(false);
        gameCanvas.SetActive(false);
        leaderboardCanvas.SetActive(false);
    }

    public void loadGame()
    {

        //Check if input is provided in usernameInput
        if (!string.IsNullOrEmpty(usernameInput.text))
        {
            // Set player.username using usernameInput
            player.SetUsername(usernameInput.text);
            PlayerPrefs.SetString("PlayerUserName", player.GetUsername());
        }
        else
        {
            // Set a default username
            player.SetUsername("Player");
            PlayerPrefs.SetString("PlayerUserName", player.GetUsername());
        }

        // Update usernameIngame
        usernameIngame.text = player.GetUsername();

        // Debug logs to check values
        Debug.Log("Player Username to save: " + player.GetUsername());
        Debug.Log("Player Username saved in PlayerPrefs: " + PlayerPrefs.GetString("PlayerUserName"));

        // Rest of your code...
        Time.timeScale = 1f;
        gameCanvas.SetActive(true);
        mainMenuCanvas.SetActive(false);
        settingsCanvas.SetActive(false);
        gameOverCanvas.SetActive(false);
        leaderboardCanvas.SetActive(false);

    }

    public void loadGameOver()
    {
        gameEnded = true;
        Time.timeScale = 0f;
        gameOverCanvas.SetActive(true);
        mainMenuCanvas.SetActive(false);
        settingsCanvas.SetActive(false);
        gameCanvas.SetActive(false);
        leaderboardCanvas.SetActive(false);

    }

    public void loadSettings()
    {
        Time.timeScale = 0f;
        settingsCanvas.SetActive(true);
        gameOverCanvas.SetActive(false);
        mainMenuCanvas.SetActive(false);
        gameCanvas.SetActive(false);
        leaderboardCanvas.SetActive(false);

    }

public void loadLeaderboard()
{
    //Check if input is provided in usernameInput
    if (!string.IsNullOrEmpty(usernameInput.text))
    {
        // Set player.username using usernameInput
        player.SetUsername(usernameInput.text);
        PlayerPrefs.SetString("PlayerUserName", player.GetUsername());
    }
    else
    {
        // Set a default username
        player.SetUsername("Player");
        PlayerPrefs.SetString("PlayerUserName", player.GetUsername());
    }

    if (!string.IsNullOrEmpty(player.GetUsername()))
    {
        // Update high score
        submitScoreEvent.Invoke(player.GetUsername(), player.GetScore());
        Debug.Log($"Loading leaderboard - Player: {player.GetUsername()}, Score: {player.GetScore()}");

        leaderboardCanvas.SetActive(true);
        settingsCanvas.SetActive(false);
        gameOverCanvas.SetActive(false);
        mainMenuCanvas.SetActive(false);
        gameCanvas.SetActive(false);
    }
    else
    {
        Debug.LogError("Player username is null or empty when loading leaderboard!");
    }
}

    public void quitGame()
    {
        Application.Quit();
    }
}
MikeMMattinson commented 2 months ago
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TutorialEnemy : Entity
{
    private Player player;
    public LineRenderer lineRenderer;
    private float lineDuration = 0.1f;
    private Vector3 spawnPosition;
    void Start()
    {
        player = GameObject.FindGameObjectWithTag("Player").GetComponent<Player>();
        if (player == null)
        {
            Debug.LogError("Player object not found!");
        }
        Debug.Log(this);
    }
    public void attackOther(Entity other)
    {

        // if attack > other.defense then attack
        if (this.GetAttack() > other.GetDefense())
        {
            Debug.Log($"{name} at {transform.position} attacks {other.name} at {other.transform.position} with Attack: {this.GetAttack()}");

            // call TakeDamage()
            other.TakeDamage(this.GetAttack());

            // draw attack line from enemy to other
            drawLineToPlayer();
        }

    }

    public void drawLineToPlayer()
    {
        // Set the positions for the LineRenderer (start and end points)
        lineRenderer.SetPosition(0, transform.position); // Start position: enemy's position
        lineRenderer.SetPosition(1, player.transform.position);    // End position: player's position

        // Enable the LineRenderer to make the line visible
        lineRenderer.enabled = true;

        // Start coroutine to disable LineRenderer after duration
        StartCoroutine(DisableLineRendererAfterDelay());
    }
    // Coroutine to disable LineRenderer after specified duration
    private IEnumerator DisableLineRendererAfterDelay()
    {
        yield return new WaitForSeconds(lineDuration);
        lineRenderer.enabled = false;
    }
    public void SetPlayerReference(Player player)
    {
        this.player = player;
    }

    protected override void Die()
    {
        Destroy(gameObject);
        Debug.Log("Tutorial enemy died.");
    }

    public override string ToString()
    {
        string temp = $"{base.ToString()}";
        temp += $", Enemy: {name}";
        temp += $", Spawnpoint: {spawnPosition}";
        return temp;
    }
}
MikeMMattinson commented 2 months ago
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;

public class UIManager : MonoBehaviour
{
    [SerializeField] public Player player;
    [SerializeField] TextMeshProUGUI healthText;
    [SerializeField] TextMeshProUGUI attackText;
    [SerializeField] TextMeshProUGUI defenseText;
    [SerializeField] TextMeshProUGUI scoreText;
    [SerializeField] TextMeshProUGUI scoreTextGameOver;
    // Start is called before the first frame update
    void Start()
    {
        player = FindObjectOfType<Player>();
    }

    // Update is called once per frame
    void Update()
    {
        healthText.text = player.GetHealth().ToString();
        attackText.text = player.GetAttack().ToString();
        defenseText.text = player.GetDefense().ToString();
        scoreText.text = player.GetScore().ToString();
        scoreTextGameOver.text = player.GetScore().ToString();
    }
}
MikeMMattinson commented 2 months ago

image

MikeMMattinson commented 2 months ago

image

MikeMMattinson commented 2 months ago

image

MikeMMattinson commented 2 months ago
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : Entity
{
    private Player player;
    public LineRenderer lineRenderer;
    //private float lineDuration = 0.1f;
    [SerializeField] List<GameObject> powerupList;
    [SerializeField] List<GameObject> enemyTypeList;
    [SerializeField] int randomNumber;
    private Vector3 spawnPosition;
    private Vector3 deathPosition;

    public new void Awake(){
        // used for initial setup that
        // doesn't rely on other objects
        // or components being initialized.
        SetLevel(1);
        SetAttack(3);
        SetHealth(10);
        SetDefense(2);
        Debug.Log($"Player {name} awake at {this.transform.position}");

    }

    new void Start()
    {
        // used for initial setup that
        // does rely on other objects
        // or components being initialized.

        // get rid of the Clone reference    
        this.name = this.name.Replace("(Clone)","").Trim();

        player = GameObject.FindGameObjectWithTag("Player").GetComponent<Player>();
        if (player == null)
        {
            Debug.LogError("Player object not found!");
        }
        Debug.Log(this);

        // set the spawn position
        //spawnPosition = transform.position;
    }

    public void SetSpawnPosition(Vector3 spawnPosition)
    {
        this.spawnPosition = spawnPosition;
    }

    public Vector3 GetSpawnPosition()
    {
        return spawnPosition;
    }

    public void SetPlayerReference(Player player)
    {
        this.player = player;
    }

    protected override void Die()
    {
        player.score += 1;

        // step 1 - set death position
        deathPosition = transform.position;
        Debug.Log($"Enemy {name} was killed by player {player.name} at position {deathPosition}.");

        // step 2 - drop a random buf at death position randomly
        int rn = Random.Range(0, 100);
        //Debug.Log($"Random number: {randomNumber}");
        if (rn >= randomNumber)
        {
            GameObject currentPowerupPrefab = powerupList[Random.Range(0, powerupList.Count)];
            GameObject powerupInstance = Instantiate(currentPowerupPrefab, deathPosition, Quaternion.identity);
            Debug.Log($"Power up {powerupInstance} created.");
        }

        // step 3 - after random short delay, spawn new enemy at the spawn position as function of the game level and player health
        StartCoroutine(SpawnEnemyWithDelay());
        transform.position = new Vector3(1000f, 1000f, transform.position.z);
    }

IEnumerator SpawnEnemyWithDelay()
/*
    Modify random spawn rate
    Randomly respawn between 4 and 10 seconds.
    Author: ChatGPT3.5
    Author: Mike M
    Modified: 23/Apr/24
*/
{
    float minimum = 4f; // 4 seconds
    float maximum = 10f; // 10 seconds

    // Generate a random spawn delay within the specified range
    float spawnDelay = Random.Range(minimum, maximum);

    // Wait for the specified delay
    yield return new WaitForSeconds(spawnDelay);

    // Spawn the enemy after the delay
    SpawnEnemy();

    // Destroy the object (assuming this script is attached to the object you want to destroy)
    Destroy(gameObject);
}

    public void SpawnEnemy()
    {
        GameObject currentEnemyPrefab = enemyTypeList[Random.Range(0, enemyTypeList.Count)];
        GameObject enemyInstance = Instantiate(currentEnemyPrefab, spawnPosition, Quaternion.identity);

        // Set player reference for the enemy
        Enemy enemyComponent = enemyInstance.GetComponent<Enemy>();

        // set player reference
        if (enemyComponent != null)
        {
            enemyComponent.SetSpawnPosition(enemyComponent.transform.position);
            enemyComponent.SetPlayerReference(player);
        }
        else
        {
            Debug.LogWarning("Enemy component not found on instantiated enemy!");
        }

        Debug.Log($"Replace Enemy {enemyInstance} created at position {spawnPosition}.");
    }

    public override string ToString()
    {
        string temp = $"{base.ToString()}";
        temp += $", Enemy: {name}";
        temp += $", Spawnpoint: {spawnPosition}";
        return temp;
    }
}
MikeMMattinson commented 2 months ago
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using System;
[System.Serializable]
public class Entity : MonoBehaviour
{
    private int level;
    private int health;
    private int attack;
    private int defense;
    public GameObject damageNumberPrefab;

    public void Awake(){
        // used for initial setup that
        // doesn't rely on other objects
        // or components being initialized.

        // get rid of the Clone reference    
        this.name = this.name.Replace("(Clone)","").Trim();

        SetLevel(1);
        SetAttack(1);
        SetHealth(5);
        SetDefense(1);
        Debug.Log($"[{this.name}] {this} ____ AWAKE.");

    }

    public void Start(){
        // used for initial setup that
        // does rely on other objects
        // or components being initialized.

        Debug.Log($"[{this.name}] {this} ____ STARTED.");

    }

    public void SetLevel(int level)
    {
        this.level = level;
    }

    public int GetLevel()
    {
        return this.level;
    }

    public void LevelUp()
    {
        this.level ++;  // plus 1
    }

public void SetAttack(int attack)
    {
        this.attack = attack;
    }

    public int GetAttack()
    {
        return attack;
    }

    public void AttackUp(int increase = 1){
        // default attack increase is 1
        // max of 8
        SetAttack(Math.Min(GetAttack()+increase,8));
    }

    public void SetDefense(int defense)
    {
        this.defense = defense;
    }

    public int GetDefense()
    {
        return defense;
    }

    public void DefenseUp(int increase = 1){
        // default defense increase is 1
        // max of 8
        SetDefense(Math.Min(GetDefense()+increase,8));        
    }

    public void SetHealth(int health)
    {
        this.health = health;
    }

    public int GetHealth()
    {
        return health;
    }

    public void HealthUp(int increase = 5){
        // default health increase is 5
        // max of 200
        SetHealth(Math.Min(GetHealth()+increase,200));        
    }    

    public void Attack(Entity other)
    {

        // if attack > other.defense then attack
        if (this.attack > other.defense)
        {
            Debug.Log($"{name} at {transform.position} attacks {other.name} at {other.transform.position} with Attack: {attack}");

            // call TakeDamage()
            other.TakeDamage(this);

            // draw attack line from enemy to other
            //drawLineToPlayer();
        }

    }

    public void TakeDamage(Entity other)
    {
        // other.attack > this.defense
        if (other.GetAttack() > this.defense)
        {
            // decrease health by actual damage.
            Debug.Log($"Other's attack > {name} defense.");
            int actualDamage = other.GetAttack() - this.defense;

            health -= (actualDamage);

            // Instantiate damage number prefab at this position
            GameObject damageNumberObj = Instantiate(damageNumberPrefab, transform.position, Quaternion.identity);

            if (damageNumberPrefab != null)
            {
                // Set the damage value on the damage number
                DamageNumber damageNumber = damageNumberObj.GetComponent<DamageNumber>();

                damageNumber.SetDamage(actualDamage);
                if (this.health <= 0)
                {
                    Die();
                }
            }
            else
            {
                Debug.Log("did not create damage number object.");
            }
        }

        // other.attack < this.defense
        else
        {
            Debug.Log($"{other.name}'s attack of {other.GetAttack()} < {name} defense of {this.defense}.");
        }
    }
    protected virtual void Die()
    {
        // Override this method in derived classes
        Debug.Log($"Entity {name} died!");
    }
    // public void drawLineToPlayer()
    // {
    //     // Set the positions for the LineRenderer (start and end points)
    //     lineRenderer.SetPosition(0, transform.position); // Start position: enemy's position
    //     lineRenderer.SetPosition(1, player.transform.position);    // End position: player's position

    //     // Enable the LineRenderer to make the line visible
    //     lineRenderer.enabled = true;

    //     // Start coroutine to disable LineRenderer after duration
    //     StartCoroutine(DisableLineRendererAfterDelay());
    // }
    // // Coroutine to disable LineRenderer after specified duration
    // private IEnumerator DisableLineRendererAfterDelay()
    // {
    //     yield return new WaitForSeconds(lineDuration);
    //     lineRenderer.enabled = false;
    // }

    public override string ToString()
    {
        string temp = $", Level: {level}";
        temp += $", Health: {health}";
        temp += $", Defense: {defense}";
        temp += $", Attack: {attack}";
        temp += $", Position: {transform.position}";
        return temp;
    }
}
MikeMMattinson commented 2 months ago
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using TMPro;
using UnityEngine.AI;

public class Player : Entity
{
    public StateManager stateManager;
    public int score;  // should be private

    public string username;  // should be private

    private TextMeshProUGUI scoreText;

    public new void Awake(){
        // used for initial setup that
        // doesn't rely on other objects
        // or components being initialized.

        // get rid of the Clone reference    
        this.name = this.name.Replace("(Clone)","").Trim();

        SetLevel(1);
        SetAttack(3);
        SetHealth(199);
        SetDefense(2);
        username = "Unknown player";
        //Debug.Log($"[{this.name}] {this} ____ AWAKE.");

    }

    public new void Start(){
        // used for initial setup that
        // does rely on other objects
        // or components being initialized.

        stateManager = FindObjectOfType<StateManager>();
        this.transform.position = new Vector2(0f,90f);
        Debug.Log($"[{this.name}] {this} ____ STARTED.");

    }

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            // Convert mouse position to world space in 2D
            Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            // Perform a raycast in 2D from the mouse position
            RaycastHit2D hit = Physics2D.Raycast(mousePosition, Vector2.zero);

            if (hit.collider != null)
            {
                Enemy enemy = hit.collider.GetComponent<Enemy>();
                if (enemy != null)
                {
                    // Deal damage to the enemy
                    Debug.Log($"Player's attack is {this.GetAttack()}");
                    enemy.TakeDamage(this);
                }

                TutorialEnemy tutorialEnemy = hit.collider.GetComponent<TutorialEnemy>();
                if (tutorialEnemy != null)
                {
                    // Deal damage to the enemy
                    Debug.Log($"Player's attack is {this.GetAttack()}");
                    tutorialEnemy.TakeDamage(this);
                }
            }
        }
    }
    public void ActivatePowerUp(string powerUp)
    {
        switch(powerUp) 
        {
            case "AttackUp":
                // code block
                AttackUp(2);  // max of xx
                break;
            case "HealthUp":
                // code block
                HealthUp(20); // max of xxx
                break;
            case "DefenseUp":
                // code block
                DefenseUp(2);  // max of xxx
                break;
            default:
                // code block
                break;
        }
    }

    protected override void Die()
    {
        Debug.Log($"Player {username} has died. Score: {score}");
        //scoreText.text = score.ToString();
        stateManager.loadGameOver();
    }

    public void SetScore(int score){
        this.score = score;
    }

    public int GetScore(){
        return this.score;
    }

    public void SetUsername(string username){
        this.username = username;
    }

    public string GetUsername(){
        return username;
    }

    public override string ToString()
    {
        return $"{username}, Level: {this.GetLevel()}, Health: {this.GetHealth()}, Defense: {this.GetDefense()}, Attack: {this.GetAttack()}";
    }
}
MikeMMattinson commented 2 months ago

@nickmattinson you can try this one, it is pretty good... the player mouse attack line render is not working but all of the enemy and colored and attacking with a shade of their sprite color. All of that is in either the Entity.cs and or the Enemy.cs. You need to adjust the default values located in the following three files:

  1. Enemy.cs - For all normal enemies...
  2. Player.cs - For player...
  3. GameManager.cs - For NON-RESPAWNABLE tutorial enemies...

Also, change the Player health back to 200...

MikeMMattinson commented 2 months ago
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class Enemy : Entity
{
    private Object enemyRef;

    private Player player;

    private SpriteRenderer spriteRenderer;

    //private float lineDuration = 0.1f;
    [SerializeField] List<GameObject> powerupList;
    [SerializeField] List<GameObject> enemyTypeList;
    [SerializeField] int chanceForPowerUp;
    private Vector3 spawnPosition;
    private Vector3 deathPosition;

    private bool respawn = false;

    private bool scoreable = true;

    //private bool loot = true;

    public new void Awake(){
        // used for initial setup that
        // doesn't rely on other objects
        // or components being initialized.

        // get rid of the Clone reference    
        this.name = this.name.Replace("(Clone)","").Trim();

        // set enemy capability
        SetLevel(Random.Range(1,3));
        SetCapability();

        //Debug.Log($"[{this.name}] {this} ____ AWAKE.");

    }

    new void Start()
    {
        // used for initial setup that
        // does rely on other objects
        // or components being initialized.

        // Get the Player component attached to the GameObject
        player = FindAnyObjectByType<Player>(); 

        enemyRef = Resources.Load("Enemy");

        // set spawn position
        SetSpawnPosition(this.transform.position);

        Debug.Log($"[{this.name}] {this} ____ STARTED.");
    }

    public void SetCapability(){
        switch(GetLevel()) 
        {

        case 1: // easy tutorial
            SetAttack(1);
            SetHealth(5);
            SetDefense(3);
            SetRespawn(false);
            SetSpriteColor(new Vector4(0, 1, 0, 1));
            SetAttackColor(Brighten(GetSpriteColor(), 0.5f));       
            break;

        case 2: // med tutorial
            SetAttack(1);
            SetHealth(5);
            SetDefense(3);
            SetRespawn(false);
            SetSpriteColor(new Vector4(0.83f, 0.68f, 0.39f, 1));
            SetAttackColor(Brighten(GetSpriteColor(), 0.5f));       
            break;

        case 3: // easy
            SetAttack(1);
            SetHealth(5);
            SetDefense(3);
            SetSpriteColor(new Vector4(0, 1, 0, 1));
            SetAttackColor(Brighten(GetSpriteColor(), 0.5f));       
            break;

        case 4: // med
            SetAttack(2);
            SetDefense(4);
            SetHealth(30);   
            SetSpriteColor(new Vector4(0.83f, 0.68f, 0.39f, 1));
            SetAttackColor(Brighten(GetSpriteColor(), 0.5f)); 
            break;

        case 5: // hard)
            SetAttack(3);
            SetDefense(5);
            SetHealth(50); 
            SetSpriteColor(new Vector4(1, 0, 0, 1));
            SetAttackColor(Brighten(GetSpriteColor(), 0.5f));                       
            break;

        default:
            // Default 
            break;
        }
    }

    public void SetSpawnPosition(Vector3 spawnPosition)
    {
        this.spawnPosition = spawnPosition;
    }

    public Vector3 GetSpawnPosition()
    {
        return spawnPosition;
    }

    protected override void Die()
    {
        // Increment player's score or perform other actions upon enemy death
        player.ScoreUp();

        //spriteRenderer.enabled = false;
        gameObject.SetActive(false);
        Invoke("Respawn", 2);

    }

    protected override void Respawn()
    {
        if(respawn){
            GameObject enemyClone = (GameObject)Instantiate(enemyRef);

            // set the respawn position...
            enemyClone.transform.position = GetSpawnPosition();
        }

        Destroy(gameObject);
    }

public void SetRespawn(bool respawn){
    this.respawn = respawn;
}

public bool GetRespawn(){
    return this.respawn;
}

    public override string ToString()
    {
        string temp = $"{base.ToString()}";
        temp += $", Spawnpoint: {this.GetSpawnPosition()}";
        temp += $", Respawn: {this.GetRespawn()}";
        return temp;
    }
}
MikeMMattinson commented 2 months ago
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class EnemySpawner : MonoBehaviour
{
    [SerializeField] List<Transform> enemySpawnPoints;
    [SerializeField] StateManager stateManager;
    [SerializeField] List<GameObject> enemies;
    protected int numberOfSpawns;
    private Player player;

    private Object enemyRef;

    void Start()
    {
        enemyRef = Resources.Load("Enemy");
        stateManager = FindObjectOfType<StateManager>();
        int randomEnemyIndex;

        if (stateManager.gameEnded != true)
        {
            numberOfSpawns = enemySpawnPoints.Count;
            for (int i = 0; i < numberOfSpawns; i++)
            {
                //retrieving spawn point 
                Transform spawnPoint = enemySpawnPoints[i];
                Debug.Log($"i: {i} {enemySpawnPoints[i].transform.position} ___SPAWNPOINT");

                // Randomly select an enemy prefab
                //GameObject currentEnemyPrefab = enemies[randomEnemyIndex];

                // Create enemy instance
                GameObject enemyInstance = (GameObject)Instantiate(enemyRef);

                // Set player reference for the enemy
                Enemy enemyComponent = enemyInstance.GetComponent<Enemy>();

                // set player reference
                if (enemyComponent != null)
                {
                    enemyComponent.SetSpawnPosition(enemySpawnPoints[i].transform.position);
                    //enemyComponent.SetPlayerReference(player);
                    //enemyComponent.SetLevel(randomEnemyIndex+1);
                    //enemyComponent.SetCapability();
                }
                else
                {
                    Debug.LogWarning("Enemy component not found on instantiated enemy!");
                }
            }
        }
    }
}
MikeMMattinson commented 2 months ago
using System.Collections;
using UnityEngine;

[System.Serializable]
public class Entity : MonoBehaviour
{
    private int level;
    private int health;
    private int attack;
    private int defense;
    public GameObject damageNumberPrefab;

    [SerializeField] private LineRenderer lineRenderer; // Reference to LineRenderer component

    private Vector4 spriteColor = new Vector4(1,1,1,1); 

    private Vector4 attackColor = new Vector4(1,1,1,1);

    public void Awake(){
        // used for initial setup that
        // doesn't rely on other objects
        // or components being initialized.

        // get rid of the Clone reference    
        this.name = this.name.Replace("(Clone)","").Trim();

        //Debug.Log($"[{this.name}] {this} ____ AWAKE.");

    }

    public void Start(){
        // used for initial setup that
        // does rely on other objects
        // or components being initialized.

        // Initialize LineRenderer component
        lineRenderer = gameObject.AddComponent(typeof(LineRenderer)) as LineRenderer;

        //Debug.Log($"[{this.name}] {this} ____ STARTED.");

    }

    public void SetRandomLevel(int max = 3){
        this.level = Random.Range(1,max+1);
    }

    public void SetSpriteColor(Vector4 spriteColor){
        this.spriteColor = spriteColor;
    }

    public Vector4 GetSpriteColor(){
        return this.spriteColor;
    }

    public void SetAttackColor(Color attackColor){
        this.attackColor = attackColor;
    }

    public Color GetAttackColor(){
        return this.attackColor;
    }

    public void SetLevel(int level)
    {
        this.level = level;
    }

    public int GetLevel()
    {
        return this.level;
    }

    public void LevelUp()
    {
        this.level ++;  // plus 1
    }

    public void SetAttack(int attack)
    {
        this.attack = attack;
    }

    public int GetAttack()
    {
        return attack;
    }

    public void AttackUp(int increase = 1, int max = 6){
        // default attack increase is 1
        // max of 6
        SetAttack(Mathf.Min(GetAttack()+increase, max));
    }

    public void SetDefense(int defense)
    {
        this.defense = defense;
    }

    public int GetDefense()
    {
        return defense;
    }

    public void DefenseUp(int increase = 1, int max = 6){
        // default defense increase is 1
        // max of 6
        SetDefense(Mathf.Min(GetDefense()+increase, max));        
    }

    public void SetHealth(int health)
    {
        this.health = health;
    }

    public int GetHealth()
    {
        return health;
    }

    public void HealthUp(int increase = 5, int max = 200){
        // default health increase is 5
        // max of 200
        SetHealth(Mathf.Min(GetHealth()+increase, max));        
    }    

    public void Attack(Entity other)
    {

        // if attack > other.defense then attack
        if (this.attack > other.defense)
        {
            //Debug.Log($"{name} at {transform.position} attacks {other.name} at {other.transform.position} with Attack: {attack}");

            // call TakeDamage()
            other.TakeDamage(this);

            // draw attack line from enemy to other
            DrawLineTo(other); 

        }

    }

    public void TakeDamage(Entity other)
    {
        // other.attack > this.defense
        if (other.GetAttack() > this.GetDefense())
        {
            // decrease health by actual damage.
            //Debug.Log($"Other's attack > {name} defense.");
            int actualDamage = other.GetAttack() - this.GetDefense();

            health -= (actualDamage);

            // Instantiate damage number prefab at this position
            GameObject damageNumberObj = Instantiate(damageNumberPrefab, transform.position, Quaternion.identity);

            if (damageNumberPrefab != null)
            {
                // Set the damage value on the damage number
                DamageNumber damageNumber = damageNumberObj.GetComponent<DamageNumber>();

                damageNumber.SetDamage(actualDamage);
                if (this.GetHealth() <= 0)
                {
                    Die();
                }
            }
            else
            {
                Debug.Log("did not create damage number object.");
            }
        }

        // other.attack < this.defense
        else
        {
            //Debug.Log($"{other.name}'s attack of {other.GetAttack()} < {name} defense of {this.GetDefense()}.");
        }
    }

    protected virtual void Die()
    {
        // Implement die actions if needed
    }

    protected virtual void Respawn()
    {
        // implement respawn actions if needed
    }

    private void DrawLineTo(Entity other)
    {
        // Check if the LineRenderer component exists
        if (lineRenderer != null)
        {
            // Set LineRenderer properties
            lineRenderer.startWidth = 0.1f; // Adjust as needed
            lineRenderer.endWidth = 0.1f; // Adjust as needed

            // Set the positions for the LineRenderer (start and end points)
            lineRenderer.SetPosition(0, transform.position); // Start position: enemy's position
            lineRenderer.SetPosition(1, other.transform.position); // End position: other entity's position

            // Set the color of the LineRenderer
            Color customColor = this.GetAttackColor();
            lineRenderer.startColor = customColor;
            lineRenderer.endColor = customColor;

            // Enable the LineRenderer to make the line visible
            lineRenderer.enabled = true;

            // Start coroutine to disable LineRenderer after a duration
            StartCoroutine(DisableLineRendererAfterDelay());
        }
        else
        {
            Debug.LogError("LineRenderer component is missing!");
        }
    }

    // Coroutine to disable LineRenderer after a specified duration
    private IEnumerator DisableLineRendererAfterDelay(float lineDuration = 0.1f)
    {
        // Adjust the duration as needed
        yield return new WaitForSeconds(lineDuration); 
        lineRenderer.enabled = false;
    }

    public static Color Brighten(Color color, float factor = 0.5f)
    {
        return Color.Lerp(color, Color.black, factor);
    }

    public override string ToString()
    {
        string temp = $", Level: {level}";
        temp += $", Health: {health}";
        temp += $", Defense: {defense}";
        temp += $", Attack: {attack}";
        temp += $", Position: {transform.position}";
        temp += $", spriteColor: {spriteColor}";
        temp += $", attackColor: {attackColor}";
        return temp;
    }
}
MikeMMattinson commented 2 months ago
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using TMPro;
using UnityEngine.AI;

public class Player : Entity
{
    public StateManager stateManager;
    public int score;  // should be private

    public string username;  // should be private

    private TextMeshProUGUI scoreText;

    //[SerializeField] LineRenderer lineRenderer; // Reference to LineRenderer component

    public new void Awake(){
        // used for initial setup that
        // doesn't rely on other objects
        // or components being initialized.

        // get rid of the Clone reference    
        this.name = this.name.Replace("(Clone)","").Trim();

        SetLevel(1);
        SetAttack(4);
        SetHealth(99999);
        SetDefense(1);

        // set sprite color
        // then set attack color 30% darker
        SetSpriteColor(new Vector4(.72f, .81f, 1.0f, 1));
        SetAttackColor(Brighten(GetSpriteColor(), 0.5f)); 

        username = "Unknown player";

        //Debug.Log($"[{this.name}] {this} ____ AWAKE.");

    }

    public new void Start(){
        // used for initial setup that
        // does rely on other objects
        // or components being initialized.

        stateManager = FindObjectOfType<StateManager>();
        this.transform.position = new Vector2(0f, 90f);

        // set sprite color
        //SetSpriteColor(GetSpriteColor());

        //Debug.Log($"[{this.name}] {this} ____ STARTED.");

    }

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            // Convert mouse position to world space in 2D
            Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            // Perform a raycast in 2D from the mouse position
            RaycastHit2D hit = Physics2D.Raycast(mousePosition, Vector2.zero);

            if (hit.collider != null)
            {
                Enemy enemy = hit.collider.GetComponent<Enemy>();
                if (enemy != null)
                {
                    // Deal damage to the enemy
                    //Debug.Log($"Player's attack is {this.GetAttack()}");
                    enemy.TakeDamage(this);
                }

            }
        }

        // // check player health
        // if(GetHealth()<=0){
        //     this.Die();
        // }
    }
    public void ActivatePowerUp(string powerUp)
    {
        switch(powerUp) 
        {
            case "AttackUp":
                // code block
                //AttackUp(2);  // max of xx
                this.AttackUp();
                break;
            case "HealthUp":
                // code block
                //HealthUp(20); // max of xxx
                this.HealthUp();
                break;
            case "DefenseUp":
                // code block
                //DefenseUp(2);  // max of xxx
                this.DefenseUp();
                break;
            default:
                // code block
                break;
        }
    }

    protected override void Die()
    {
        Debug.Log($"[{username}] died with score [{score}]  ____SCORE");
        //scoreText.text = score.ToString();
        stateManager.loadGameOver();
        //Destroy(this);
    }

    public void ScoreUp(){
        this.score ++;
    }

    public void SetScore(int score){
        this.score = score;
    }

    public int GetScore(){
        return this.score;
    }

    public void SetUsername(string username){
        this.username = username;
    }

    public string GetUsername(){
        return username;
    }

    public override string ToString()
    {
        string temp = $"{base.ToString()}";
        temp += $", Score: {this.GetScore()}";
        temp += $", Username: {this.GetUsername()}";
        return temp;
    }
}
MikeMMattinson commented 2 months ago

Notes from this run...

MikeMMattinson commented 2 months ago
    public void SetCapability(){
        player = FindObjectOfType<Player>();
        switch(GetLevel()) 
        {

        case 1: // easy
            SetAttack(2);
            SetHealth(10);
            SetDefense(3);
            SetSpriteColor(new Vector4(0, 1, 0, 1));
            SetAttackColor(Brighten(GetSpriteColor(), 0.5f));       
            break;

        case 2: // med
            SetAttack(3);
            SetDefense(4);
            SetHealth(16);            
            SetSpriteColor(new Vector4(0.83f, 0.68f, 0.39f, 1));
            SetAttackColor(Brighten(GetSpriteColor(), 0.5f)); 
            break;

        case 3: // hard)
            SetAttack(5);  // at least
            SetDefense(4); // at least
            SetHealth(24); 
            SetSpriteColor(new Vector4(1, 0, 0, 1));
            SetAttackColor(Brighten(GetSpriteColor(), 0.5f));                       
            break;

        default:
            // Default 
            break;
        }
    }
MikeMMattinson commented 2 months ago
    public new void Awake(){
        // used for initial setup that
        // doesn't rely on other objects
        // or components being initialized.

        // get rid of the Clone reference    
        this.name = this.name.Replace("(Clone)","").Trim();

        SetLevel(1);
        SetAttack(4);
        SetHealth(200);
        SetDefense(1);

        // set sprite color
        // then set attack color 30% darker
        SetSpriteColor(new Vector4(.72f, .81f, 1.0f, 1));
        SetAttackColor(Brighten(GetSpriteColor(), 0.5f)); 

        username = "Unknown player";

        //Debug.Log($"[{this.name}] {this} ____ AWAKE.");

    }
MikeMMattinson commented 2 months ago

new enemies attack/defense:

update players max: