Closed MikeMMattinson closed 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()}";
}
}
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;
}
}
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!");
}
}
}
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;
}
}
// 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();
}
}
// 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();
}
}
// 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();
}
}
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);
}
}
}
}
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();
}
}
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;
}
}
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();
}
}
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;
}
}
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;
}
}
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()}";
}
}
@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:
Also, change the Player health back to 200...
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;
}
}
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!");
}
}
}
}
}
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;
}
}
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;
}
}
Notes from this run...
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;
}
}
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.");
}
new enemies attack/defense:
update players max:
NICK'S THOUGHTS:
Limit health, attack and defense and/or make the enemies harder as the game progresses...
In Player.cs:
In Enemy.cs: