Cleanup Soldiers and Bases (make Entity base class)

This commit is contained in:
Gabriel Ksawery Skowron-Rodriguez 2022-05-23 14:04:53 +02:00
parent 4ff01692aa
commit 42452e6e64
11 changed files with 306 additions and 293 deletions

View File

@ -78,22 +78,22 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: d34caf35d0ce610f8bc87cf815ba1915, type: 3} m_Script: {fileID: 11500000, guid: d34caf35d0ce610f8bc87cf815ba1915, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
myTeam: 0
maxHealthPoints: 100 maxHealthPoints: 100
healthPoints: 100 healthPoints: 100
rangeAttack: 3
rangeView: 1
damageAttack: 1
speedAttack: 2
lastAttackTick: -1
nameText: {fileID: 6838251604148675782} nameText: {fileID: 6838251604148675782}
healthPointsText: {fileID: 8012357605284019061} healthPointsText: {fileID: 8012357605284019061}
target: {fileID: 0} OnDeath:
enemyType: 0
ourType: 0
movementDestination: {x: 0, y: 0}
onDeath:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
rangeAttack: 3
rangeView: 1
damageAttack: 25
speedAttack: 2
lastAttackTick: -1
target: {fileID: 0}
enemyType: 0
movementDestination: {x: 0, y: 0}
--- !u!1 &1997457243244158843 --- !u!1 &1997457243244158843
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -358,12 +358,12 @@ MonoBehaviour:
m_margin: {x: 0, y: 0, z: 0, w: 0} m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0 m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0 m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_renderer: {fileID: 1498494949006888735}
m_maskType: 0
_SortingLayer: 0 _SortingLayer: 0
_SortingLayerID: 0 _SortingLayerID: 0
_SortingOrder: 0 _SortingOrder: 0
m_hasFontAssetChanged: 0
m_renderer: {fileID: 1498494949006888735}
m_maskType: 0
--- !u!1 &2062275012809416088 --- !u!1 &2062275012809416088
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -530,9 +530,9 @@ MonoBehaviour:
m_margin: {x: 0, y: 0, z: 0, w: 0} m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0 m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0 m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_renderer: {fileID: 4083783489867894370}
m_maskType: 0
_SortingLayer: 0 _SortingLayer: 0
_SortingLayerID: 0 _SortingLayerID: 0
_SortingOrder: 0 _SortingOrder: 0
m_hasFontAssetChanged: 0
m_renderer: {fileID: 4083783489867894370}
m_maskType: 0

View File

@ -156,16 +156,15 @@ MonoBehaviour:
WORLD_SPACE_OFFSET: {x: 0.5, y: 1, z: 0.5} WORLD_SPACE_OFFSET: {x: 0.5, y: 1, z: 0.5}
allyBaseCoord: {x: 0, y: 0} allyBaseCoord: {x: 0, y: 0}
soldierStartingPositions: soldierStartingPositions:
- {x: 0, y: 0} - {x: 1, y: 0}
- {x: 1, y: 2} - {x: 1, y: 2}
enemyBaseCoord: {x: 0, y: 0} enemyBaseCoord: {x: 0, y: 0}
enemyStartingPositions: enemyStartingPositions:
- {x: 2, y: 0} - {x: 2, y: 0}
- {x: 9, y: 5}
tilemap: {fileID: 1853262998} tilemap: {fileID: 1853262998}
soldierPrefab: {fileID: 403095692180922766, guid: a87b1aa46b0ed3e0fba621e11dd4f1e2, soldierPrefab: {fileID: 403095692180922766, guid: a87b1aa46b0ed3e0fba621e11dd4f1e2,
type: 3} type: 3}
basePrefab: {fileID: 6141901885681798073, guid: e79038bbfa9535f45be1d0f0ae0626ce, basePrefab: {fileID: 403095692180922766, guid: cff761b70fcb1dc55bfd414849823b2e,
type: 3} type: 3}
--- !u!4 &282616949 --- !u!4 &282616949
Transform: Transform:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2e5f405b6facc6e47a0297f2be93eae4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,9 @@
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class Base : Entity
{
}

View File

@ -1,73 +1,86 @@
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using TMPro; using TMPro;
using UnityEngine; using UnityEngine;
using UnityEngine.Events;
public class Base : MonoBehaviour
{ public class Entity : MonoBehaviour
public enum SoldierType {
{ public enum Team
Ally, {
Enemy Ally,
} Enemy
[SerializeField] protected SoldierType ourType; }
[SerializeField] private float maxHealthPoints = 100; [Header("Values")]
[SerializeField] private float healthPoints = 100; [SerializeField] protected Team myTeam;
[SerializeField] protected float maxHealthPoints = 100;
[SerializeField] private TMP_Text nameText = null; [SerializeField] protected float healthPoints = 100;
[SerializeField] private TMP_Text healthPointsText = null;
[SerializeField] protected TMP_Text nameText = null;
public SoldierType TempGetOwnType() [SerializeField] protected TMP_Text healthPointsText = null;
{
return ourType; [HideInInspector] public UnityEvent<Entity> OnDeath = new UnityEvent<Entity>();
}
// Start is called before the first frame update public Team GetOwnTeam()
protected void Start(){ {
healthPoints = maxHealthPoints; // initialize health return myTeam;
UpdateHPDisplay(); }
Debug.Log("Base: " + ourType.ToString() + " has appeared", gameObject); // Start is called before the first frame update
protected virtual void Start(){
switch (ourType) healthPoints = maxHealthPoints; // initialize health
{ UpdateHPDisplay();
case SoldierType.Ally:
nameText.text = "Ally"; Debug.Log("Entity: " + myTeam.ToString() + " has appeared", gameObject);
nameText.color = Color.blue;
break; switch (myTeam)
case SoldierType.Enemy: {
nameText.text = "Enemy"; case Team.Ally:
nameText.color = Color.red; nameText.text = "Ally";
break; nameText.color = Color.blue;
default: break;
nameText.text = "how did we get here (forever)"; case Team.Enemy:
nameText.color = new Color(255, 192, 203); nameText.text = "Enemy";
break; nameText.color = Color.red;
} break;
} default:
nameText.text = "how did we get here (forever)";
public void setOwnTag(SoldierType type) nameText.color = new Color(255, 192, 203);
{ break;
ourType = type; }
} }
protected void OnDestroy() public void SetOwnTeam(Team type)
{ {
Debug.Log("Soldier: " + ourType.ToString() + " has died", gameObject); myTeam = type;
} }
protected void ReduceHP(float damage)
{ public void ReduceHP(float damage)
healthPoints -= damage; {
healthPoints -= damage;
if (healthPoints <= 0)
Destroy(gameObject); if (healthPoints <= 0)
Destroy(gameObject);
UpdateHPDisplay();
Debug.Log("I took damage, my HP is now: " + healthPoints + " noooo!!!!", gameObject); UpdateHPDisplay();
} Debug.Log("I took damage, my HP is now: " + healthPoints + " noooo!!!!", gameObject);
}
protected void UpdateHPDisplay()
{ protected virtual void Die()
healthPointsText.text = healthPoints.ToString() + "/" + maxHealthPoints.ToString(); {
} OnDeath.Invoke(this);
} Destroy(gameObject);
}
private void OnDestroy()
{
Debug.Log("Soldier: " + myTeam.ToString() + " has died", gameObject);
}
protected void UpdateHPDisplay()
{
healthPointsText.text = healthPoints.ToString() + "/" + maxHealthPoints.ToString();
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d77d5669fae0f57499970c2aed5af02b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,171 +1,157 @@
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using TMPro; using TMPro;
using UnityEngine; using UnityEngine;
using UnityEngine.Events; using UnityEngine.Events;
public class Soldier : Base public class Soldier : Entity
{ {
private Queue<Action> actions = new Queue<Action>(); private Queue<Action> actions = new Queue<Action>();
private Queue<Action> interrupts = new Queue<Action>(); private Queue<Action> interrupts = new Queue<Action>();
#region Action Queue Items #region Action Queue Items
abstract class Action // action "template" abstract class Action // action "template"
{ {
public virtual void Execute(Soldier soldier, TickSystem.OnTickEventArgs tickEventArgs) { } // called by Soldier when action is supposed to be done public virtual void Execute(Soldier soldier, TickSystem.OnTickEventArgs tickEventArgs) { } // called by Soldier when action is supposed to be done
} }
private class Movement : Action private class Movement : Action
{ {
public override void Execute(Soldier soldier, TickSystem.OnTickEventArgs tickEventArgs) public override void Execute(Soldier soldier, TickSystem.OnTickEventArgs tickEventArgs)
{//TO DO: CALL PROPER FUNCTION TO MOVE {//TO DO: CALL PROPER FUNCTION TO MOVE
throw new System.NotImplementedException($"(tick: {tickEventArgs.tickNumber}) Trying to teleport to {soldier.movementDestination}"); throw new System.NotImplementedException($"(tick: {tickEventArgs.tickNumber}) Trying to teleport to {soldier.movementDestination}");
//??tileMap.Teleport(movementDestination) //??tileMap.Teleport(movementDestination)
} }
} }
private class TryAttack : Action private class TryAttack : Action
{ {
public override void Execute(Soldier soldier, TickSystem.OnTickEventArgs tickEventArgs) public override void Execute(Soldier soldier, TickSystem.OnTickEventArgs tickEventArgs)
{ {
//Debug.LogWarning($"(tick: {tickEventArgs.tickNumber}) Looking for enemy in range"); //Debug.LogWarning($"(tick: {tickEventArgs.tickNumber}) Looking for enemy in range");
if(soldier.TryAttackEnemy()) if(soldier.TryAttackEnemy())
soldier.lastAttackTick = tickEventArgs.tickNumber; soldier.lastAttackTick = tickEventArgs.tickNumber;
} }
} }
#endregion #endregion
#region Handling Incoming Orders (Interrupts) #region Handling Incoming Orders (Interrupts)
public void HandleMovementOrder(Vector2Int destination) public void HandleMovementOrder(Vector2Int destination)
{ {
movementDestination = destination; movementDestination = destination;
interrupts.Enqueue(new Movement()); // force soldier to find path to the new destination interrupts.Enqueue(new Movement()); // force soldier to find path to the new destination
} }
#endregion #endregion
[Header("Values")] [Header("Soldier Values")]
[SerializeField] private float rangeAttack = 100; [SerializeField] private float rangeAttack = 100;
[SerializeField] private float rangeView = 1; [SerializeField] private float rangeView = 1;
[SerializeField] private float damageAttack = 1; [SerializeField] private float damageAttack = 1;
[SerializeField] private int speedAttack = 1; // ticks between attacks [SerializeField] private int speedAttack = 1; // ticks between attacks
[SerializeField] private int lastAttackTick = -1; [SerializeField] private int lastAttackTick = -1;
[Header("References")] [Header("References")]
[Header("Do-not-change-in-game values")] [Header("Do-not-change-in-game values")]
[SerializeField] private Soldier target; [SerializeField] private Entity target;
[SerializeField] private SoldierType enemyType; [SerializeField] private Team enemyType;
[SerializeField] private Vector2Int movementDestination = Vector2Int.zero; [SerializeField] private Vector2Int movementDestination = Vector2Int.zero;
// Start is called before the first frame update
protected override void Start(){
// variables not visible in inspector base.Start();
SetEnemyTag();
[HideInInspector] public UnityEvent<Soldier> onDeath = new UnityEvent<Soldier>(); }
public SoldierType GetOwnType() public void SetEnemyTag()
{ {
return ourType; if(myTeam == Team.Ally) enemyType = Team.Enemy;
} else enemyType = Team.Ally;
}
// Start is called before the first frame update
void Start(){ void Awake()
base.Start(); {
setEnemyTag(); TickSystem.OnTick += HandleTick;
} }
public void setEnemyTag() protected override void Die()
{ {
if(ourType == SoldierType.Ally) enemyType = SoldierType.Enemy; TickSystem.OnTick -= HandleTick;
else enemyType = SoldierType.Ally; base.Die();
} }
void Awake() private void HandleTick(TickSystem.OnTickEventArgs tickEventArgs)
{ {
TickSystem.OnTick += HandleTick; ref Queue<Action> queueToHandle = ref interrupts;
} if (interrupts.Count < 1) // if no interrupt actions to do, handle regular queue
queueToHandle = actions;
private void Die()
{ if(queueToHandle.Count > 0)
TickSystem.OnTick -= HandleTick; queueToHandle.Dequeue().Execute(this, tickEventArgs);
onDeath.Invoke(this); else
Destroy(gameObject); {
} if(lastAttackTick + speedAttack <= tickEventArgs.tickNumber)
{
private void OnDestroy() queueToHandle.Enqueue(new TryAttack());
{ queueToHandle.Dequeue().Execute(this, tickEventArgs);
Debug.Log("Soldier: " + ourType.ToString() + " has died", gameObject); }
} }
}
private void HandleTick(TickSystem.OnTickEventArgs tickEventArgs)
{ bool TryAttackEnemy () //returns true if an enemy was attacked
ref Queue<Action> queueToHandle = ref interrupts; {
if (interrupts.Count < 1) // if no interrupt actions to do, handle regular queue // Enemies are the game objects tagged with the "Enemy"
queueToHandle = actions; //GameObject[] enemies = GameObject.FindGameObjectsWithTag(enemyType);
Entity[] soldiers = GameObject.FindObjectsOfType<Entity>();
if(queueToHandle.Count > 0)
queueToHandle.Dequeue().Execute(this, tickEventArgs); List<Entity> enemiesList = new List<Entity>();
else
{ foreach (Entity obj in soldiers)
if(lastAttackTick + speedAttack <= tickEventArgs.tickNumber) {
{ if (obj.GetOwnTeam() == enemyType)
queueToHandle.Enqueue(new TryAttack()); enemiesList.Add(obj);
queueToHandle.Dequeue().Execute(this, tickEventArgs); }
}
} Debug.Log(soldiers.Length);
} Debug.Log(enemiesList.Count);
Entity[] enemies = enemiesList.ToArray();
bool TryAttackEnemy () //returns true if an enemy was attacked
{ // We have not found enemy yet so the distance to enemy is "infinite"
// Enemies are the game objects tagged with the "Enemy" float shortestDistance = Mathf.Infinity;
//GameObject[] enemies = GameObject.FindGameObjectsWithTag(enemyType); Entity nearestEnemy = null;
Soldier[] soldiers = GameObject.FindObjectsOfType<Soldier>(); foreach (Entity enemy in enemies)
{
List<Soldier> enemiesList = new List<Soldier>(); // Go through each enemy existing
// Calculate distance to this enemy
foreach (Soldier obj in soldiers) float distanceToEnemy = Vector3.Distance(transform.position,
{ enemy.transform.position);
if (obj.ourType == enemyType) if (distanceToEnemy < shortestDistance)
enemiesList.Add(obj); {
} shortestDistance = distanceToEnemy;
nearestEnemy = enemy;
Soldier[] enemies = enemiesList.ToArray(); }
}
// We have not found enemy yet so the distance to enemy is "infinite"
float shortestDistance = Mathf.Infinity; if (nearestEnemy != null && shortestDistance <= rangeAttack)
Soldier nearestEnemy = null; {
foreach ( Soldier enemy in enemies) target = nearestEnemy;
{ }
// Go through each enemy existing else
// Calculate distance to this enemy target = null;
float distanceToEnemy = Vector3.Distance(transform.position, enemy.transform.position);
if (distanceToEnemy < shortestDistance) if (target != null)
{ target.ReduceHP(damageAttack);
shortestDistance = distanceToEnemy;
nearestEnemy = enemy; return target != null;
} }
}
// Update is called once per frame
if (nearestEnemy != null && shortestDistance <= rangeAttack) void Update()
{ {
target = nearestEnemy; //if (target == null) return;
} }
else
target = null; /* https://www.youtube.com/watch?v=QKhn2kl9_8I 08:54 Soldier attack
void OnDrawGizmosSelected ()
if (target != null) {
target.ReduceHP(damageAttack);
}
return target != null; */
} }
// Update is called once per frame
void Update()
{
//if (target == null) return;
}
/* https://www.youtube.com/watch?v=QKhn2kl9_8I 08:54 Soldier attack
void OnDrawGizmosSelected ()
{
}
*/
}

View File

@ -27,7 +27,7 @@ public class SquadManager : MonoBehaviour
var soldiers = FindObjectsOfType<Soldier>(); var soldiers = FindObjectsOfType<Soldier>();
foreach(var soldier in soldiers) foreach(var soldier in soldiers)
{ {
if(soldier.GetOwnType() == Soldier.SoldierType.Ally) if(soldier.GetOwnTeam() == Soldier.Team.Ally)
{ {
playerSquad.TempAddSoldierToSquad(soldier); playerSquad.TempAddSoldierToSquad(soldier);
} }

View File

@ -14,7 +14,7 @@ public class TilemapManager : MonoBehaviour
public struct Tile public struct Tile
{ {
public Soldier standingSoldier; public Entity standingEntity;
} }
[Header("Common Values")] [Header("Common Values")]
@ -99,16 +99,16 @@ public class TilemapManager : MonoBehaviour
return false; return false;
if (isBase) if (isBase)
tiles[x, y].standingSoldier = Instantiate(basePrefab, tilemap.CellToWorld(new Vector3Int(x, y, 0)) + WORLD_SPACE_OFFSET, Quaternion.identity).GetComponent<Soldier>(); tiles[x, y].standingEntity = Instantiate(basePrefab, tilemap.CellToWorld(new Vector3Int(x, y, 0)) + WORLD_SPACE_OFFSET, Quaternion.identity).GetComponent<Base>();
if (isBase) else
tiles[x, y].standingSoldier = Instantiate(soldierPrefab, tilemap.CellToWorld(new Vector3Int(x, y, 0)) + WORLD_SPACE_OFFSET, Quaternion.identity).GetComponent<Soldier>(); tiles[x, y].standingEntity = Instantiate(soldierPrefab, tilemap.CellToWorld(new Vector3Int(x, y, 0)) + WORLD_SPACE_OFFSET, Quaternion.identity).GetComponent<Soldier>();
if (isAlly) if (isAlly)
tiles[x, y].standingSoldier.setOwnTag(Soldier.SoldierType.Ally); tiles[x, y].standingEntity.SetOwnTeam(Base.Team.Ally);
else else
tiles[x, y].standingSoldier.setOwnTag(Soldier.SoldierType.Enemy); tiles[x, y].standingEntity.SetOwnTeam(Base.Team.Enemy);
if (tiles[x, y].standingSoldier != null) if (tiles[x, y].standingEntity != null)
return true; return true;
return false; return false;
@ -119,42 +119,29 @@ public class TilemapManager : MonoBehaviour
if (GetTileState(x, y) != TileState.taken) if (GetTileState(x, y) != TileState.taken)
return false; return false;
Destroy(tiles[x, y].standingSoldier.gameObject); Destroy(tiles[x, y].standingEntity.gameObject);
tiles[x, y].standingSoldier = null; tiles[x, y].standingEntity = null;
Debug.Log("Despaned a soldier"); Debug.Log("Despaned a soldier");
return true; return true;
} }
public Soldier GetSoldier(int x, int y) public Entity GetSoldier(int x, int y)
{ {
if (GetTileState(x, y) != TileState.taken) if (GetTileState(x, y) != TileState.taken)
return null; return null;
return tiles[x,y].standingSoldier; return tiles[x,y].standingEntity;
} }
public Soldier[] GetAllSoldiers() public bool MoveEntity(int x1, int y1, int x2, int y2) // old MoveSoldier
{
List<Soldier> list = new List<Soldier>();
foreach (Tile obj in tiles)
{
if (obj.standingSoldier != null)
list.Add(obj.standingSoldier);
}
return list.ToArray();
}
public bool MoveSoldier(int x1, int y1, int x2, int y2)
{ {
if (GetTileState(x1, y1) == TileState.taken && GetTileState(x2, y2) == TileState.free) if (GetTileState(x1, y1) == TileState.taken && GetTileState(x2, y2) == TileState.free)
{ {
tiles[x2, y2].standingSoldier = tiles[x1, y1].standingSoldier; tiles[x2, y2].standingEntity = tiles[x1, y1].standingEntity;
tiles[x1, y1].standingSoldier = null; tiles[x1, y1].standingEntity = null;
tiles[x2, y2].standingSoldier.transform.position = tilemap.CellToWorld(new Vector3Int(x2, y2, 0)); tiles[x2, y2].standingEntity.transform.position = tilemap.CellToWorld(new Vector3Int(x2, y2, 0)) + WORLD_SPACE_OFFSET;
return true; return true;
} }
@ -169,7 +156,7 @@ public class TilemapManager : MonoBehaviour
if (x < 0 || y < 0 || x >= mapSize.x || y >= mapSize.y) if (x < 0 || y < 0 || x >= mapSize.x || y >= mapSize.y)
return TileState.outOfBounds; return TileState.outOfBounds;
if (tiles[x, y].standingSoldier == null) if (tiles[x, y].standingEntity == null)
return TileState.free; return TileState.free;
return TileState.taken; return TileState.taken;