Browse Source

Kampfsystem auf Flanken, UI

bolt_update
laurids 3 years ago
parent
commit
ce8992fdb9
13 changed files with 319 additions and 129 deletions
  1. +3
    -1
      Assets/GWConquest/Prefabs/ArmyGui.prefab
  2. +1
    -0
      Assets/GWConquest/Prefabs/BattleUnitIcon.prefab
  3. +1
    -0
      Assets/GWConquest/Scenes/GalaxyMap.unity
  4. +133
    -93
      Assets/GWConquest/Scripts/Battle.cs
  5. +29
    -1
      Assets/GWConquest/Scripts/BattleFlank.cs
  6. +1
    -0
      Assets/GWConquest/Scripts/GameManager.cs
  7. +9
    -0
      Assets/GWConquest/Scripts/ServerCallbacks.cs
  8. +6
    -0
      Assets/GWConquest/Scripts/UI/BattleArmyPanel.cs
  9. +10
    -0
      Assets/GWConquest/Scripts/UI/BattleFlankUI.cs
  10. +45
    -7
      Assets/GWConquest/Scripts/UI/BattleUnitIcon.cs
  11. +6
    -1
      Assets/GWConquest/Scripts/UI/DragDropElement.cs
  12. +31
    -24
      Assets/GWConquest/Scripts/UI/IngameUI.cs
  13. +44
    -2
      Assets/GWConquest/Scripts/Unit.cs

+ 3
- 1
Assets/GWConquest/Prefabs/ArmyGui.prefab View File

@ -64,7 +64,7 @@ MonoBehaviour:
m_OnCullStateChanged: m_OnCullStateChanged:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
m_Sprite: {fileID: 0}
m_Sprite: {fileID: 21300000, guid: f2fa446b698637a48bfe48e7cc582cbb, type: 3}
m_Type: 3 m_Type: 3
m_PreserveAspect: 0 m_PreserveAspect: 0
m_FillCenter: 1 m_FillCenter: 1
@ -1355,7 +1355,9 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
FormationsTransform: {fileID: 77748483683952273} FormationsTransform: {fileID: 77748483683952273}
FormationsPanelTransform: {fileID: 7794718298833807266}
SelectedUnitNameText: {fileID: 77748482107769389} SelectedUnitNameText: {fileID: 77748482107769389}
SelectedUnitHealthBar: {fileID: 77748481860671164}
IsOwnPlayer: 1 IsOwnPlayer: 1
FormationUIPrefab: {fileID: 790083374931814115, guid: 5b96168d30f6b44428827c365006875b, FormationUIPrefab: {fileID: 790083374931814115, guid: 5b96168d30f6b44428827c365006875b,
type: 3} type: 3}


+ 1
- 0
Assets/GWConquest/Prefabs/BattleUnitIcon.prefab View File

@ -297,6 +297,7 @@ MonoBehaviour:
mediumColor: {r: 1, g: 0.7411765, b: 0, a: 0.8784314} mediumColor: {r: 1, g: 0.7411765, b: 0, a: 0.8784314}
criticalColor: {r: 0.8980392, g: 0.15686275, b: 0.15686275, a: 0.8784314} criticalColor: {r: 0.8980392, g: 0.15686275, b: 0.15686275, a: 0.8784314}
HitSoundDelay: 0.25 HitSoundDelay: 0.25
IsDraggable: 1
--- !u!95 &2103027038577876570 --- !u!95 &2103027038577876570
Animator: Animator:
serializedVersion: 3 serializedVersion: 3


+ 1
- 0
Assets/GWConquest/Scenes/GalaxyMap.unity View File

@ -24806,6 +24806,7 @@ MonoBehaviour:
GroundTransitionLengthFactor: 30 GroundTransitionLengthFactor: 30
SpaceTransitionLengthFactor: 1 SpaceTransitionLengthFactor: 1
BattleTurnLength: 30 BattleTurnLength: 30
BattleTurnDeviation: 10
MoveToFlankCooldown: 15 MoveToFlankCooldown: 15
MoveToReserveCooldown: 15 MoveToReserveCooldown: 15
SpawnAIPlayer: 1 SpawnAIPlayer: 1


+ 133
- 93
Assets/GWConquest/Scripts/Battle.cs View File

@ -12,26 +12,22 @@ namespace GWConquest
get => FormationList.Select((f,i) => f.GetComponent<Formation>().Player).Distinct(); get => FormationList.Select((f,i) => f.GetComponent<Formation>().Player).Distinct();
} }
private float LastTurnTime = 0f;
private int BattleTurn = 0;
public IEnumerable<Unit> AllUnits {
get => FormationList.SelectMany(e => e.GetComponent<Formation>().Units);
}
private List<UnitAction> UnitActions = new List<UnitAction>(); private List<UnitAction> UnitActions = new List<UnitAction>();
[System.Serializable] [System.Serializable]
private class UnitAction { private class UnitAction {
public Unit Unit; public Unit Unit;
public BattleFlank BattleFlank;
public int WeaponIndex;
public float ActionTime; public float ActionTime;
}
private Dictionary<Player, TargetingPool> TargetingPools = new Dictionary<Player, TargetingPool>();
private TargetingPool GetTargetingPoolForPlayer(Player player)
{
if(!TargetingPools.ContainsKey(player))
{
TargetingPools[player] = new TargetingPool();
public WeaponStats Weapon {
get => Unit.Class.WeaponStatsArray[WeaponIndex];
} }
return TargetingPools[player];
} }
public int FlankCount { public int FlankCount {
@ -133,73 +129,26 @@ namespace GWConquest
base.SimulateOwner(); base.SimulateOwner();
var gm = GameManager.Instance; var gm = GameManager.Instance;
var time = Time.time;
if(time > LastTurnTime + gm.BattleTurnLength)
{
LastTurnTime = time;
BattleTurn++;
BoltLog.Info("Starting turn {0} on battle {1}", BattleTurn, this);
StartNewTurn(time);
}
SimulateTurn(); SimulateTurn();
} }
private void StartNewTurn(float time)
{
var allUnits = FormationList.SelectMany((e, i) => e.GetComponent<Formation>().Units);
var actions = allUnits.Select((u,i) => {
return new UnitAction() {
Unit = u,
ActionTime = Random.value
};
}).ToList();
actions.Sort((a,b) => (int) Mathf.Sign(a.ActionTime - b.ActionTime));
foreach(var action in actions)
{
action.ActionTime *= GameManager.Instance.BattleTurnLength;
action.ActionTime += time;
}
UnitActions = actions;
var allPlayers = AllPlayers;
foreach(Player p in allPlayers)
{
var pool = GetTargetingPoolForPlayer(p);
pool.Clear();
var attackableUnits = allUnits.Where((u,i) => u.Player != p);
foreach(Unit u in attackableUnits)
{
if(!u.IsDead)
{
pool.Add(u, u.Class.Size);
}
}
}
}
private void SimulateTurn() private void SimulateTurn()
{ {
var time = Time.time;
var time = Time.fixedTime;
bool hasChanges = false; bool hasChanges = false;
while(UnitActions.Count > 0 && UnitActions[0].ActionTime <= time)
foreach(UnitAction action in UnitActions.ToList())
{ {
if(action.ActionTime <= time)
{
SimulateUnitAction(action);
var unit = UnitActions[0].Unit;
SimulateUnitAction(unit);
UnitActions.RemoveAt(0);
RenewUnitAction(action);
hasChanges = true; hasChanges = true;
}
} }
if(hasChanges) if(hasChanges)
@ -221,48 +170,131 @@ namespace GWConquest
} }
} }
private void SimulateUnitAction(Unit unit)
private void AddCombatActions(Unit unit)
{ {
BoltLog.Info("Simulating action for unit {0} on turn {1}", unit, BattleTurn);
float time = Time.fixedTime;
if(unit.CurrentFlank != null && !unit.IsDead)
{
var weapons = unit.Class.WeaponStatsArray;
for(int i = 0; i < weapons.Length; i++)
{
var action = new UnitAction() {
Unit = unit,
BattleFlank = unit.CurrentFlank,
WeaponIndex = i
};
RenewUnitAction(action);
UnitActions.Add(action);
}
}
}
private void RenewUnitAction(UnitAction action)
{
var attackCount = action.Weapon.AttackCount;
var gm = GameManager.Instance;
float attackDelay = Random.Range(gm.BattleTurnLength - gm.BattleTurnDeviation, gm.BattleTurnLength + gm.BattleTurnDeviation);
attackDelay /= attackCount;
var pool = GetTargetingPoolForPlayer(unit.Player);
action.ActionTime = Time.fixedTime + attackDelay;
}
if(pool.IsEmpty())
return;
private void RemoveUnitActions(Unit unit)
{
UnitActions.RemoveAll(a => a.Unit == unit);
}
private void SimulateUnitAction(UnitAction action)
{
var unit = action.Unit;
var flank = action.BattleFlank;
BoltLog.Info("Simulating action for unit {0} on flank {1}", unit, flank);
var weapons = unit.Class.WeaponStatsArray;
var weapon = action.Weapon;
foreach(var weapon in weapons)
var target = FindTargetForCombat(action);
if(target == null)
{ {
for(int i = 0; i < weapon.AttackCount; i++)
{
if(pool.IsEmpty())
return;
return;
}
if(!Check(weapon.Accuracy))
return;
if(!Check(weapon.Accuracy))
continue;
if(Check(target.Class.Evasion))
return;
var target = pool.GetRandomUnit();
int damage = weapon.Damage;
float modifier = GetArmourModifier(target.Class.Armour, weapon.Penetration);
if(Check(target.Class.Evasion))
continue;
damage = Mathf.RoundToInt(damage * modifier);
if(damage <= 0)
return;
int damage = weapon.Damage;
float modifier = GetArmourModifier(target.Class.Armour, weapon.Penetration);
BoltLog.Info("Dealing {0} HP damage to unit {1} from unit {2}", damage, target, unit);
target.TakeDamage(damage);
}
private Unit FindTargetForCombat(UnitAction action)
{
IEnumerable<Unit> targets;
if(action.BattleFlank != null)
{
targets = action.BattleFlank.OpposingFlank.Units;
}
else {
throw new System.NotImplementedException();
}
damage = Mathf.RoundToInt(damage * modifier);
targets = targets.Where(u => !u.IsDead);
if(damage <= 0)
continue;
if(targets.FirstOrDefault() == null)
{
return null;
}
BoltLog.Info("Dealing {0} HP damage to unit {1} from unit {2}", damage, target, unit);
float penetration = action.Unit.Class.WeaponStatsArray[action.WeaponIndex].Penetration;
target.TakeDamage(damage);
if(target.IsDead){
pool.RemoveUnit(target);
}
IEnumerable<Unit> penTargets = null;;
for(float p = penetration; p >= 0; p--)
{
penTargets = targets.Where(u => u.Armour <= p && u.Armour > p - 1);
if(penTargets.FirstOrDefault() != null)
{
break;
} }
} }
if(penTargets == null || penTargets.FirstOrDefault() == null)
{
penTargets = targets;
}
var tList = penTargets.ToList();
int randomInd = Random.Range(0, tList.Count);
return tList[randomInd];
}
public void OnBattleStateChanged(Unit unit)
{
RemoveUnitActions(unit);
if(unit.BattleState == BattleUnitState.OnFlank)
{
AddCombatActions(unit);
}
}
public void OnUnitDead(Unit unit)
{
RemoveUnitActions(unit);
} }
public void MoveUnitToFlank(Unit unit, BattleFlank flank, int flankIndex) public void MoveUnitToFlank(Unit unit, BattleFlank flank, int flankIndex)
@ -286,11 +318,19 @@ namespace GWConquest
float movement = unit.Class.Movement <= 0 ? 1f : unit.Class.Movement; float movement = unit.Class.Movement <= 0 ? 1f : unit.Class.Movement;
unit.SetActionCooldown(GameManager.Instance.MoveToFlankCooldown / movement); unit.SetActionCooldown(GameManager.Instance.MoveToFlankCooldown / movement);
flank.SetUnit(flankIndex, unit); flank.SetUnit(flankIndex, unit);
unit.CurrentFlank = flank;
//SetUIDirty(updatePositions: true); //SetUIDirty(updatePositions: true);
} }
} }
public void MoveUnitToReserve(Unit unit)
{
unit.BattleState = BattleUnitState.MovingToReserve;
float movement = unit.Class.Movement <= 0 ? 1f : unit.Class.Movement;
unit.SetActionCooldown(GameManager.Instance.MoveToReserveCooldown / movement);
}
private static bool Check(float chance) { private static bool Check(float chance) {
return Random.Range(0f, 1f) <= chance; return Random.Range(0f, 1f) <= chance;
} }


+ 29
- 1
Assets/GWConquest/Scripts/BattleFlank.cs View File

@ -1,4 +1,5 @@
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
namespace GWConquest { namespace GWConquest {
@ -32,6 +33,33 @@ namespace GWConquest {
{ {
state.Units[index] = unit?.entity; state.Units[index] = unit?.entity;
} }
public int GetUnitIndex(Unit unit)
{
for(int i = 0; i < state.MaxUnitCount; i++)
{
if(state.Units[i] == unit.entity)
{
return i;
}
}
return -1;
}
public void RemoveUnit(Unit unit)
{
int index = GetUnitIndex(unit);
if(index != -1)
{
SetUnit(index, null);
}
}
public IEnumerable<Unit> Units {
get {
return state.Units.Where(e => e != null).Select((e,i) => e.GetComponent<Unit>());
}
}
} }
} }

+ 1
- 0
Assets/GWConquest/Scripts/GameManager.cs View File

@ -13,6 +13,7 @@ namespace GWConquest
public float SpaceTransitionLengthFactor; public float SpaceTransitionLengthFactor;
public float BattleTurnLength; public float BattleTurnLength;
public float BattleTurnDeviation;
public float MoveToFlankCooldown; public float MoveToFlankCooldown;
public float MoveToReserveCooldown; public float MoveToReserveCooldown;


+ 9
- 0
Assets/GWConquest/Scripts/ServerCallbacks.cs View File

@ -74,5 +74,14 @@ namespace GWConquest
var flank = evnt.Flank.GetComponent<BattleFlank>(); var flank = evnt.Flank.GetComponent<BattleFlank>();
flank.Battle.MoveUnitToFlank(evnt.Unit.GetComponent<Unit>(), flank, evnt.FlankIndex); flank.Battle.MoveUnitToFlank(evnt.Unit.GetComponent<Unit>(), flank, evnt.FlankIndex);
} }
public override void OnEvent(MoveUnitToReserveEvent evnt)
{
var unit = evnt.Unit.GetComponent<Unit>();
if(unit.CurrentBattle != null)
{
unit.CurrentBattle.MoveUnitToReserve(unit);
}
}
} }
} }

+ 6
- 0
Assets/GWConquest/Scripts/UI/BattleArmyPanel.cs View File

@ -8,7 +8,10 @@ namespace GWConquest {
public RectTransform FormationsTransform; public RectTransform FormationsTransform;
public RectTransform FormationsPanelTransform;
public Text SelectedUnitNameText; public Text SelectedUnitNameText;
public Image SelectedUnitHealthBar;
public bool IsOwnPlayer; public bool IsOwnPlayer;
@ -16,6 +19,8 @@ namespace GWConquest {
public GameObject Buttons; public GameObject Buttons;
public BattleUI BattleUI; public BattleUI BattleUI;
public Battle Battle { public Battle Battle {
get => BattleUI.Battle; get => BattleUI.Battle;
@ -127,6 +132,7 @@ namespace GWConquest {
{ {
Buttons.SetActive(true); Buttons.SetActive(true);
SelectedUnitNameText.text = SelectedUnit.Class.FullName; SelectedUnitNameText.text = SelectedUnit.Class.FullName;
SelectedUnitHealthBar.fillAmount = (float) SelectedUnit.Hitpoints / SelectedUnit.Class.Hitpoints;
} }
else { else {


+ 10
- 0
Assets/GWConquest/Scripts/UI/BattleFlankUI.cs View File

@ -61,6 +61,16 @@ namespace GWConquest {
} }
} }
public void OnIconDraggedToPanel(BattleUnitIcon icon, BattleArmyPanel panel)
{
if(icon.Unit.BattleState == BattleUnitState.OnFlank)
{
MoveUnitToReserveEvent ev = MoveUnitToReserveEvent.Create(Bolt.GlobalTargets.OnlyServer);
ev.Unit = icon.Unit.entity;
ev.Send();
}
}
} }
} }

+ 45
- 7
Assets/GWConquest/Scripts/UI/BattleUnitIcon.cs View File

@ -20,6 +20,8 @@ namespace GWConquest {
[System.NonSerialized] [System.NonSerialized]
public Unit Unit; public Unit Unit;
public bool IsDraggable = true;
private RectTransform ImageTransform; private RectTransform ImageTransform;
public static int Compare(Unit a, Unit b) public static int Compare(Unit a, Unit b)
@ -51,7 +53,20 @@ namespace GWConquest {
} }
public void OnClick(){ public void OnClick(){
GetComponentInParent<BattleArmyPanel>()?.OnIconClicked(this);
if(Unit != null)
{
var battleUI = GetComponentInParent<BattleUI>();
BattleArmyPanel panel;
if(Unit.Player == Player.CurrentPlayer)
{
panel = battleUI.PlayerPanel;
}
else {
panel = battleUI.EnemyPanel;
}
panel.OnIconClicked(this);
}
} }
public void UpdateIcon() public void UpdateIcon()
@ -107,22 +122,45 @@ namespace GWConquest {
{ {
if(Unit != null) if(Unit != null)
{ {
foreach(BattleUnitIcon icon in FindObjectsOfType<BattleUnitIcon>())
var armyPanel = GetComponentInParent<BattleArmyPanel>();
var flankUI = GetComponentInParent<BattleFlankUI>();
if (armyPanel != null)
{ {
var iconRT = icon.GetComponent<RectTransform>();
Vector3 mousePos = Input.mousePosition;
if(RectTransformUtility.RectangleContainsScreenPoint(iconRT, mousePos))
foreach (BattleUnitIcon icon in FindObjectsOfType<BattleUnitIcon>())
{
var iconRT = icon.GetComponent<RectTransform>();
Vector3 mousePos = Input.mousePosition;
if (RectTransformUtility.RectangleContainsScreenPoint(iconRT, mousePos))
{
armyPanel.OnIconDragged(this, icon);
break;
}
}
}
else if(flankUI != null){
foreach(BattleArmyPanel panel in FindObjectsOfType<BattleArmyPanel>())
{ {
GetComponentInParent<BattleArmyPanel>()?.OnIconDragged(this, icon);
break;
var panelRT = panel.FormationsPanelTransform;
Vector3 mousePos = Input.mousePosition;
if (RectTransformUtility.RectangleContainsScreenPoint(panelRT, mousePos))
{
flankUI.OnIconDraggedToPanel(this, panel);
break;
}
} }
} }
} }
return true; return true;
} }
public override bool CanDrag()
{
return IsDraggable && Unit != null;
}
} }
} }

+ 6
- 1
Assets/GWConquest/Scripts/UI/DragDropElement.cs View File

@ -20,7 +20,7 @@ namespace GWConquest
private void Update() private void Update()
{ {
if(!isDragging & Input.GetButtonDown("Left Click"))
if(!isDragging & Input.GetButtonDown("Left Click") && CanDrag())
{ {
Vector3 mousePos = Input.mousePosition; Vector3 mousePos = Input.mousePosition;
if(RectTransformUtility.RectangleContainsScreenPoint(rectTransform, mousePos)) if(RectTransformUtility.RectangleContainsScreenPoint(rectTransform, mousePos))
@ -80,5 +80,10 @@ namespace GWConquest
{ {
} }
public virtual bool CanDrag()
{
return true;
}
} }
} }

+ 31
- 24
Assets/GWConquest/Scripts/UI/IngameUI.cs View File

@ -40,6 +40,10 @@ namespace GWConquest
Instance = this; Instance = this;
} }
private void Start() {
DisablePlanetView();
}
private void Update() private void Update()
{ {
if (Input.GetButtonDown("Left Click")) if (Input.GetButtonDown("Left Click"))
@ -67,13 +71,17 @@ namespace GWConquest
if(Input.GetButtonDown("Cancel")) if(Input.GetButtonDown("Cancel"))
{ {
if(PlanetViewEnabled && PlanetView.BattleUI.isActiveAndEnabled)
if(PlanetViewEnabled)
{ {
PlanetView.HideBattleUI();
}
else {
DisablePlanetView();
if(PlanetView.BattleUI.isActiveAndEnabled)
{
PlanetView.HideBattleUI();
}
else {
DisablePlanetView();
}
} }
} }
} }
@ -236,32 +244,31 @@ namespace GWConquest
private void DisablePlanetView() private void DisablePlanetView()
{ {
if(PlanetViewEnabled)
{
PlanetView.HideUI();
PlanetView.gameObject.SetActive(false);
foreach(Planet p in Planet.AllPlanets)
PlanetView.HideUI();
PlanetView.gameObject.SetActive(false);
foreach(Planet p in Planet.AllPlanets)
{
foreach (Renderer r in p.GetComponentsInChildren<Renderer>())
{ {
foreach (Renderer r in p.GetComponentsInChildren<Renderer>())
{
r.enabled = true;
}
r.enabled = true;
} }
}
GWCamera camera = FindObjectOfType<GWCamera>();
camera.ResetCameraTransform();
GWCamera camera = FindObjectOfType<GWCamera>();
camera.ResetCameraTransform();
Camera.main.orthographic = true;
Camera.main.orthographic = true;
viewedPlanet.GetComponent<PlanetScaling>().enabled = true;
PlanetHud.gameObject.SetActive(true);
PlanetNames.SetActive(true);
PlanetConnections.SetActive(true);
viewedPlanet.GetComponent<PlanetScaling>().enabled = true;
PlanetHud.gameObject.SetActive(true);
PlanetNames.SetActive(true);
PlanetConnections.SetActive(true);
viewedPlanet = null;
PlanetViewEnabled = false;
viewedPlanet = null;
PlanetViewEnabled = false;
}
} }


+ 44
- 2
Assets/GWConquest/Scripts/Unit.cs View File

@ -31,6 +31,14 @@ namespace GWConquest
set => state.Hitpoints = value; set => state.Hitpoints = value;
} }
public float Armour {
get => Class.Armour;
}
public float Evasion {
get => Class.Evasion;
}
public bool IsDead { public bool IsDead {
get => Hitpoints <= 0; get => Hitpoints <= 0;
} }
@ -41,7 +49,16 @@ namespace GWConquest
public BattleUnitState BattleState { public BattleUnitState BattleState {
get => (BattleUnitState) state.BattleState; get => (BattleUnitState) state.BattleState;
set => state.BattleState = (int) value;
set {
state.BattleState = (int) value;
if(BoltNetwork.IsServer)
{
if(CurrentBattle != null)
{
CurrentBattle.OnBattleStateChanged(this);
}
}
}
} }
public RevealState RevealState { public RevealState RevealState {
@ -66,6 +83,13 @@ namespace GWConquest
[System.NonSerialized] [System.NonSerialized]
public BattleUnitIcon CurrentIcon; public BattleUnitIcon CurrentIcon;
[System.NonSerialized]
public BattleFlank CurrentFlank;
public Battle CurrentBattle {
get => Formation.currentZone.CurrentBattle;
}
public override void Attached() public override void Attached()
{ {
state.AddCallback("Formation", () => state.AddCallback("Formation", () =>
@ -110,6 +134,11 @@ namespace GWConquest
{ {
CurrentIcon.PlayHitAnim(); CurrentIcon.PlayHitAnim();
} }
if(Hitpoints <= 0)
{
CurrentBattle.OnUnitDead(this);
}
} }
public override void SimulateOwner() public override void SimulateOwner()
@ -122,6 +151,12 @@ namespace GWConquest
{ {
BattleState = BattleUnitState.OnFlank; BattleState = BattleUnitState.OnFlank;
} }
else if (BattleState == BattleUnitState.MovingToReserve)
{
BattleState = BattleUnitState.InReserve;
CurrentFlank.RemoveUnit(this);
CurrentFlank = null;
}
} }
else else
{ {
@ -130,7 +165,14 @@ namespace GWConquest
} }
public bool IsInReserve {
get {
return BattleState == BattleUnitState.InReserve ||
BattleState == BattleUnitState.Arriving ||
BattleState == BattleUnitState.Departing ||
BattleState == BattleUnitState.MovingToReserve;
}
}


Loading…
Cancel
Save