Shielding

Shield behavior now provides protection from damage at the expense of heat and energy usage
Weapon scripts check for the presence of a shield when detecting collisions (TODO: TEST ALL WEAPON TYPES)
Shields can be toggled on/off (G key)
Database cache now included in repo (saves some confusion)
This commit is contained in:
Reinier Vens 2021-03-06 01:04:26 +00:00
commit 8920b48977
19 changed files with 377 additions and 95 deletions

View file

@ -177,6 +177,14 @@ public class @AetheriaInput : IInputActionCollection, IDisposable
""expectedControlType"": ""Button"",
""processors"": """",
""interactions"": """"
},
{
""name"": ""Toggle Shield"",
""type"": ""Button"",
""id"": ""5566504f-ee89-4eb9-9bbb-03f4b22dfe7d"",
""expectedControlType"": ""Button"",
""processors"": """",
""interactions"": """"
}
],
""bindings"": [
@ -586,6 +594,17 @@ public class @AetheriaInput : IInputActionCollection, IDisposable
""action"": ""EnterWormhole"",
""isComposite"": false,
""isPartOfComposite"": false
},
{
""name"": """",
""id"": ""d59fb542-6ac5-466d-a668-67fd8c890232"",
""path"": ""<Keyboard>/#(G)"",
""interactions"": """",
""processors"": """",
""groups"": """",
""action"": ""Toggle Shield"",
""isComposite"": false,
""isPartOfComposite"": false
}
]
},
@ -1172,6 +1191,7 @@ public class @AetheriaInput : IInputActionCollection, IDisposable
m_Player_TargetNearest = m_Player.FindAction("Target Nearest", throwIfNotFound: true);
m_Player_ToggleHeatsinks = m_Player.FindAction("Toggle Heatsinks", throwIfNotFound: true);
m_Player_EnterWormhole = m_Player.FindAction("EnterWormhole", throwIfNotFound: true);
m_Player_ToggleShield = m_Player.FindAction("Toggle Shield", throwIfNotFound: true);
// UI
m_UI = asset.FindActionMap("UI", throwIfNotFound: true);
m_UI_Navigate = m_UI.FindAction("Navigate", throwIfNotFound: true);
@ -1257,6 +1277,7 @@ public class @AetheriaInput : IInputActionCollection, IDisposable
private readonly InputAction m_Player_TargetNearest;
private readonly InputAction m_Player_ToggleHeatsinks;
private readonly InputAction m_Player_EnterWormhole;
private readonly InputAction m_Player_ToggleShield;
public struct PlayerActions
{
private @AetheriaInput m_Wrapper;
@ -1281,6 +1302,7 @@ public class @AetheriaInput : IInputActionCollection, IDisposable
public InputAction @TargetNearest => m_Wrapper.m_Player_TargetNearest;
public InputAction @ToggleHeatsinks => m_Wrapper.m_Player_ToggleHeatsinks;
public InputAction @EnterWormhole => m_Wrapper.m_Player_EnterWormhole;
public InputAction @ToggleShield => m_Wrapper.m_Player_ToggleShield;
public InputActionMap Get() { return m_Wrapper.m_Player; }
public void Enable() { Get().Enable(); }
public void Disable() { Get().Disable(); }
@ -1350,6 +1372,9 @@ public class @AetheriaInput : IInputActionCollection, IDisposable
@EnterWormhole.started -= m_Wrapper.m_PlayerActionsCallbackInterface.OnEnterWormhole;
@EnterWormhole.performed -= m_Wrapper.m_PlayerActionsCallbackInterface.OnEnterWormhole;
@EnterWormhole.canceled -= m_Wrapper.m_PlayerActionsCallbackInterface.OnEnterWormhole;
@ToggleShield.started -= m_Wrapper.m_PlayerActionsCallbackInterface.OnToggleShield;
@ToggleShield.performed -= m_Wrapper.m_PlayerActionsCallbackInterface.OnToggleShield;
@ToggleShield.canceled -= m_Wrapper.m_PlayerActionsCallbackInterface.OnToggleShield;
}
m_Wrapper.m_PlayerActionsCallbackInterface = instance;
if (instance != null)
@ -1414,6 +1439,9 @@ public class @AetheriaInput : IInputActionCollection, IDisposable
@EnterWormhole.started += instance.OnEnterWormhole;
@EnterWormhole.performed += instance.OnEnterWormhole;
@EnterWormhole.canceled += instance.OnEnterWormhole;
@ToggleShield.started += instance.OnToggleShield;
@ToggleShield.performed += instance.OnToggleShield;
@ToggleShield.canceled += instance.OnToggleShield;
}
}
}
@ -1613,6 +1641,7 @@ public class @AetheriaInput : IInputActionCollection, IDisposable
void OnTargetNearest(InputAction.CallbackContext context);
void OnToggleHeatsinks(InputAction.CallbackContext context);
void OnEnterWormhole(InputAction.CallbackContext context);
void OnToggleShield(InputAction.CallbackContext context);
}
public interface IUIActions
{

View file

@ -225,6 +225,15 @@ public class ActionGameManager : MonoBehaviour
AkSoundEngine.PostEvent(CurrentShip.HeatsinksEnabled ? "UI_Success" : "UI_Fail", gameObject);
};
_input.Player.ToggleShield.performed += context =>
{
if (CurrentShip.Shield != null)
{
CurrentShip.Shield.Item.Enabled = !CurrentShip.Shield.Item.Enabled;
AkSoundEngine.PostEvent(CurrentShip.Shield.Item.Enabled ? "UI_Success" : "UI_Fail", gameObject);
}
};
#region Targeting
_input.Player.TargetReticle.performed += context =>

View file

@ -1,6 +1,7 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static Unity.Mathematics.math;
public class ConstantLaser : MonoBehaviour
{
@ -69,20 +70,34 @@ public class ConstantLaser : MonoBehaviour
}
LineRenderer.SetPosition(0, transform.position);
RaycastHit hit;
if (Physics.Raycast(new Ray(transform.position, transform.forward), out hit, Range, 1))
bool hitFound = false;
foreach (var hit in Physics.RaycastAll(new Ray(transform.position, transform.forward), Range, 1 | (1 << 17)))
{
var shield = hit.collider.GetComponent<ShieldManager>();
if (shield)
{
if (!(shield.Entity.Shield != null && shield.Entity.Shield.Item.Active && shield.Entity.Shield.CanTakeHit(DamageType, Damage))) continue;
if (shield.Entity != SourceEntity)
{
shield.Entity.Shield.TakeHit(DamageType, Damage);
shield.ShowHit(hit.point, sqrt(Damage));
LineRenderer.SetPosition(1, hit.point);
hitFound = true;
}
}
var hull = hit.collider.GetComponent<HullCollider>();
if (hull)
{
if (hull.Entity != SourceEntity)
{
hull.SendHit(Damage * Time.deltaTime, Penetration, Spread, DamageType, SourceEntity, hit.textureCoord, transform.forward);
transform.position = hit.point;
LineRenderer.SetPosition(1, hit.point);
hitFound = true;
}
}
LineRenderer.SetPosition(1, hit.point);
}
else
if(!hitFound)
LineRenderer.SetPosition(1, transform.position + transform.forward * Range);
}

View file

@ -1,6 +1,7 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static Unity.Mathematics.math;
public class ConstantLightning : MonoBehaviour
{
@ -50,11 +51,18 @@ public class ConstantLightning : MonoBehaviour
}
Lightning.FixedEndpoint = false;
var hits = Physics.SphereCastAll(Barrel.position, HitRadius, Barrel.forward, Range, 1);
var hits = Physics.SphereCastAll(Barrel.position, HitRadius, Barrel.forward, Range, 1 | (1 << 17));
foreach (var hit in hits)
{
var shield = hit.collider.GetComponent<ShieldManager>();
if (shield && (shield.Entity.Shield != null && shield.Entity.Shield.Item.Active && shield.Entity.Shield.CanTakeHit(DamageType, Damage)))
{
if (shield.Entity == Source.Entity) continue;
shield.Entity.Shield.TakeHit(DamageType, Damage * Time.deltaTime);
shield.ShowHit(hit.point, sqrt(Damage));
}
var hull = hit.collider.GetComponent<HullCollider>();
if (hull)
if (hull && !(hull.Entity.Shield != null && hull.Entity.Shield.Item.Active && hull.Entity.Shield.CanTakeHit(DamageType, Damage)))
{
if (hull.Entity == Source.Entity) continue;
hull.SendHit(Damage * Time.deltaTime, Penetration, Spread, DamageType, Source.Entity, hit.textureCoord, Barrel.forward);

View file

@ -12,12 +12,6 @@ public class GuidedProjectile : MonoBehaviour
{
public Prototype HitEffect;
public Prototype ChildProjectile;
public Prototype AirburstProjectile;
public int AirburstCount;
public float AirburstDirectionality;
public float AirburstDistance;
public float AirburstRange;
public float AirburstVelocity;
public int Children;
public float SplitTime;
public float SplitSeparationForwardness;
@ -81,7 +75,7 @@ public class GuidedProjectile : MonoBehaviour
var position = (float3) t.position;
var sourceDist = length(StartPosition.xz - position.xz);
if (sourceDist > Range || dot(diff,Velocity) < 0 || AirburstCount > 0 && targetDist < AirburstDistance)
if (sourceDist > Range || dot(diff,Velocity) < 0)
{
StartCoroutine(FadeOut());
if (HitEffect != null)
@ -89,27 +83,6 @@ public class GuidedProjectile : MonoBehaviour
var ht = HitEffect.Instantiate<Transform>();
ht.position = t.position;
}
if (AirburstCount > 0 && AirburstProjectile)
{
var targetDiff = Target.position - transform.position;
if (targetDiff.magnitude < AirburstRange)
{
for (int i = 0; i < AirburstCount; i++)
{
var child = AirburstProjectile.Instantiate<Projectile>();
child.StartPosition = child.transform.position = t.position;
var randomDirection = Random.onUnitSphere;
child.Velocity = Vector3.Lerp(randomDirection, targetDiff.normalized, AirburstDirectionality).normalized * AirburstVelocity;
child.Range = AirburstRange;
child.Damage = Damage / AirburstCount;
child.Penetration = Penetration;
child.Spread = Spread;
child.DamageType = DamageType;
child.SourceEntity = SourceEntity;
}
}
}
return;
}
_prevDist = targetDist;
@ -169,15 +142,34 @@ public class GuidedProjectile : MonoBehaviour
if(_alive)
{
var ray = new Ray(t.position, Velocity);
if (Physics.Raycast(ray, out var hit, Velocity.magnitude * Time.deltaTime, 1))
foreach (var hit in Physics.RaycastAll(ray, Velocity.magnitude * Time.deltaTime, 1 | (1 << 17)))
{
var hull = hit.collider.GetComponent<HullCollider>();
if (hull)
var shield = hit.collider.GetComponent<ShieldManager>();
if (shield)
{
hull.SendHit(Damage, Penetration, Spread, DamageType, SourceEntity, hit.textureCoord, Velocity.normalized);
if (!(shield.Entity.Shield != null && shield.Entity.Shield.Item.Active && shield.Entity.Shield.CanTakeHit(DamageType, Damage))) continue;
if (shield.Entity != SourceEntity)
{
shield.Entity.Shield.TakeHit(DamageType, Damage);
shield.ShowHit(hit.point, sqrt(Damage));
}
}
StartCoroutine(Kill());
var hull = hit.collider.GetComponent<HullCollider>();
if (hull && !(hull.Entity.Shield != null && hull.Entity.Shield.Item.Active && hull.Entity.Shield.CanTakeHit(DamageType, Damage)))
{
if (hull.Entity != SourceEntity)
{
hull.SendHit(Damage, Penetration, Spread, DamageType, SourceEntity, hit.textureCoord, transform.forward);
transform.position = hit.point;
StartCoroutine(Kill());
}
}
else// if (hit.transform.gameObject.layer == 1)
{
StartCoroutine(Kill());
return;
}
if (HitEffect != null)
{
var ht = HitEffect.Instantiate<Transform>();

View file

@ -1,6 +1,7 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static Unity.Mathematics.math;
public class HitscanEffect : MonoBehaviour
{
@ -25,17 +26,39 @@ public class HitscanEffect : MonoBehaviour
public void Fire()
{
_startTime = Time.time;
RaycastHit hit;
if (Physics.Raycast(new Ray(transform.position, transform.forward), out hit, Range, 1))
var hitFound = false;
var ray = new Ray(transform.position, transform.forward);
foreach (var hit in Physics.RaycastAll(ray, Range, 1 | (1 << 17)))
{
var shield = hit.collider.GetComponent<ShieldManager>();
if (shield)
{
if (!(shield.Entity.Shield != null && shield.Entity.Shield.Item.Active && shield.Entity.Shield.CanTakeHit(DamageType, Damage))) continue;
if (shield.Entity != SourceEntity)
{
shield.Entity.Shield.TakeHit(DamageType, Damage);
shield.ShowHit(hit.point, sqrt(Damage));
hitFound = true;
}
}
var hull = hit.collider.GetComponent<HullCollider>();
if (hull)
{
if (hull.Entity != SourceEntity)
{
hull.SendHit(Damage, Penetration, Spread, DamageType, SourceEntity, hit.textureCoord, transform.forward);
transform.position = hit.point;
hitFound = true;
}
}
if (hitFound && HitEffect != null)
{
var ht = HitEffect.Instantiate<Transform>();
ht.SetParent(hit.collider.transform);
ht.position = hit.point;
}
var length = (hit.point - transform.position).magnitude;
Line.SetPosition(1, Vector3.forward * length);
var emission = LineEffect.emission;
@ -44,7 +67,7 @@ public class HitscanEffect : MonoBehaviour
shape.position = Vector3.forward * (length / 2);
shape.scale = Vector3.one * (length / 2);
}
else
if(!hitFound)
{
Line.SetPosition(1, Vector3.forward * Range);
var emission = LineEffect.emission;

View file

@ -2,6 +2,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static Unity.Mathematics.math;
public class Laser : MonoBehaviour
{
@ -35,20 +36,34 @@ public class Laser : MonoBehaviour
}
LineRenderer.SetPosition(0, transform.position);
RaycastHit hit;
if (Physics.Raycast(new Ray(transform.position, transform.forward), out hit, Range, 1))
bool hitFound = false;
foreach (var hit in Physics.RaycastAll(new Ray(transform.position, transform.forward), Range, 1 | (1 << 17)))
{
var shield = hit.collider.GetComponent<ShieldManager>();
if (shield)
{
if (!(shield.Entity.Shield != null && shield.Entity.Shield.Item.Active && shield.Entity.Shield.CanTakeHit(DamageType, Damage))) continue;
if (shield.Entity != SourceEntity)
{
shield.Entity.Shield.TakeHit(DamageType, Damage);
shield.ShowHit(hit.point, sqrt(Damage));
LineRenderer.SetPosition(1, hit.point);
hitFound = true;
}
}
var hull = hit.collider.GetComponent<HullCollider>();
if (hull)
{
if (hull.Entity != SourceEntity)
{
hull.SendHit(Damage * (Time.deltaTime / Duration), Penetration, Spread, DamageType, SourceEntity, hit.textureCoord, transform.forward);
transform.position = hit.point;
LineRenderer.SetPosition(1, hit.point);
hitFound = true;
}
}
LineRenderer.SetPosition(1, hit.point);
}
else
if(!hitFound)
LineRenderer.SetPosition(1, transform.position + transform.forward * Range);
LineRenderer.widthMultiplier = IntensityCurve.Evaluate(lerp);

View file

@ -6,6 +6,7 @@ using Unity.Mathematics;
using static Unity.Mathematics.math;
using static Unity.Mathematics.noise;
using Random = UnityEngine.Random;
using static Unity.Mathematics.math;
public class Lightning : MonoBehaviour
{
@ -31,11 +32,21 @@ public class Lightning : MonoBehaviour
_colliderHit = false;
LightningCompute.OnLeaderComplete = null;
LightningCompute.FixedEndpoint = false;
var hits = Physics.SphereCastAll(Barrel.position, HitRadius, Barrel.forward, Range, 1);
var hits = Physics.SphereCastAll(Barrel.position, HitRadius, Barrel.forward, Range, 1 | (1 << 17));
foreach (var hit in hits)
{
var shield = hit.collider.GetComponent<ShieldManager>();
if (shield && (shield.Entity.Shield != null && shield.Entity.Shield.Item.Active && shield.Entity.Shield.CanTakeHit(DamageType, Damage)))
{
if (shield.Entity == Source.Entity) continue;
LightningCompute.OnLeaderComplete = () =>
{
shield.Entity.Shield.TakeHit(DamageType, Damage);
shield.ShowHit(hit.point, sqrt(Damage));
};
}
var hull = hit.collider.GetComponent<HullCollider>();
if (hull)
if (hull && !(hull.Entity.Shield != null && hull.Entity.Shield.Item.Active && hull.Entity.Shield.CanTakeHit(DamageType, Damage)))
{
if (hull.Entity == Source.Entity) continue;
LightningCompute.OnLeaderComplete = () =>

View file

@ -106,10 +106,16 @@ public class Mine : MonoBehaviour
Time.time - _startTime > Lifetime ||
_blastCountdown && Time.time > _blastTime)
{
foreach (var collider in Physics.OverlapSphere(t.position, BlastRange, 1))
foreach (var collider in Physics.OverlapSphere(t.position, BlastRange, 1 | (1 << 17)))
{
var shield = collider.GetComponent<ShieldManager>();
if (shield && (shield.Entity.Shield != null && shield.Entity.Shield.Item.Active && shield.Entity.Shield.CanTakeHit(DamageType, Damage)))
{
shield.Entity.Shield.TakeHit(DamageType, Damage);
shield.ShowHit(t.position, sqrt(Damage));
}
var hull = collider.GetComponent<HullCollider>();
if (hull)
if (hull && !(hull.Entity.Shield != null && hull.Entity.Shield.Item.Active && hull.Entity.Shield.CanTakeHit(DamageType, Damage)))
{
hull.SendSplash(Damage, DamageType, Source.Entity, (collider.transform.position - t.position).normalized);
}

View file

@ -55,10 +55,20 @@ public class Projectile : MonoBehaviour
var forward = Velocity.normalized;
t.forward = forward;
var ray = new Ray(position, Velocity);
if (Physics.Raycast(ray, out var hit, Velocity.magnitude * Time.deltaTime, 1))
foreach (var hit in Physics.RaycastAll(ray, Velocity.magnitude * Time.deltaTime, 1 | (1 << 17)))
{
var shield = hit.collider.GetComponent<ShieldManager>();
var hull = hit.collider.GetComponent<HullCollider>();
if (hull)
if (shield)
{
if (!(shield.Entity.Shield != null && shield.Entity.Shield.Item.Active && shield.Entity.Shield.CanTakeHit(DamageType, Damage))) continue;
if (shield.Entity != SourceEntity)
{
shield.Entity.Shield.TakeHit(DamageType, Damage*DirectHitDamageMultiplier);
shield.ShowHit(hit.point, sqrt(Damage * DirectHitDamageMultiplier));
}
}
else if (hull && !(hull.Entity.Shield != null && hull.Entity.Shield.Item.Active && hull.Entity.Shield.CanTakeHit(DamageType, Damage)))
{
if (hull.Entity != SourceEntity)
{
@ -67,7 +77,7 @@ public class Projectile : MonoBehaviour
StartCoroutine(Kill());
}
}
else// if (hit.transform.gameObject.layer == 1)
else
{
StartCoroutine(Kill());
return;

View file

@ -13,8 +13,8 @@ public class ShieldData : BehaviorData
[InspectableField, JsonProperty("efficiency"), Key(1), RuntimeInspectable]
public PerformanceStat Efficiency = new PerformanceStat();
[InspectableField, JsonProperty("shielding"), Key(2), RuntimeInspectable]
public PerformanceStat Shielding = new PerformanceStat();
[InspectableField, JsonProperty("energy"), Key(2), RuntimeInspectable]
public PerformanceStat EnergyUsage = new PerformanceStat();
public override IBehavior CreateInstance(ItemManager context, Entity entity, EquippedItem item)
{
@ -27,6 +27,9 @@ public class Shield : IBehavior
public Entity Entity { get; }
public EquippedItem Item { get; }
public ItemManager Context { get; }
public float Efficiency { get; private set; }
public float EnergyUsage { get; private set; }
public BehaviorData Data => _data;
@ -38,12 +41,23 @@ public class Shield : IBehavior
_data = data;
Entity = entity;
Item = item;
// TODO: Detect hits on Ship, keep a list of callbacks that modify the hit by reference
}
public bool Execute(float delta)
{
Efficiency = Context.Evaluate(_data.Efficiency, Item);
EnergyUsage = Context.Evaluate(_data.EnergyUsage, Item);
return true;
}
public bool CanTakeHit(DamageType type, float damage)
{
return Entity.CanConsumeEnergy(damage * EnergyUsage);
}
public void TakeHit(DamageType type, float damage)
{
Entity.TryConsumeEnergy(damage * EnergyUsage);
Item.AddHeat(damage / Efficiency);
}
}

View file

@ -96,13 +96,11 @@ public abstract class Entity
get => _weapons;
}
public Shield Shield { get; private set; }
public float TargetRange { get; private set; }
public float MaxTemp { get; private set; }
public float MinTemp { get; private set; }
public bool ShieldEnabled // TODO: MAKE SHIELDS
{
get => true;
}
public ItemManager ItemManager { get; }
public int AssignedPopulation => PopulationAssignments.Sum(pa => pa.AssignedPopulation);
public float Mass { get; private set; }
@ -349,12 +347,14 @@ public abstract class Entity
{
if (b is Weapon weapon)
_weapons.Remove(weapon);
if(b is Capacitor capacitor)
if (b is Capacitor capacitor)
_capacitors.Remove(capacitor);
if(b is Reactor reactor)
if (b is Reactor reactor)
_reactors.Remove(reactor);
if(b is Radiator heatsink)
if (b is Radiator heatsink)
_heatsinks.Remove(heatsink);
if (b is Shield)
Shield = null;
}
return item.EquippableItem;
@ -531,6 +531,8 @@ public abstract class Entity
_reactors.Add(reactor);
if(b is Radiator heatsink)
_heatsinks.Add(heatsink);
if (b is Shield shield)
Shield = shield;
}
equippedItem.OnOnline += () => ItemOnline.OnNext(equippedItem);
@ -584,6 +586,13 @@ public abstract class Entity
return true;
}
public bool CanConsumeEnergy(float energy)
{
var capEnergy = _capacitors.Sum(cap => cap.Charge);
int onlineReactors = _reactors.Count(reactor=>reactor.Item.Online);
return capEnergy > energy || onlineReactors > 0;
}
public bool TryConsumeEnergy(float energy)
{
if (energy < .01f) return true;
@ -860,6 +869,11 @@ public class EquippedItem
public Shape InsetShape { get; }
public int SortPosition;
public bool Active
{
get => _online && Enabled;
}
public bool Online
{
@ -937,7 +951,7 @@ public class EquippedItem
if (!previouslyOnline && _online) OnOnline?.Invoke();
if (previouslyOnline && !_online) OnOffline?.Invoke();
if (Enabled && _online)
if (Active)
{
foreach (var group in BehaviorGroups.Values)
{

View file

@ -18,6 +18,7 @@ public class SchematicDisplay : MonoBehaviour
public Color HeaderElementEnabledColor;
public Color HeaderElementDisabledColor;
public GameObject ShieldIcon;
public Image HeatsinkBackground;
public TextMeshProUGUI EnergyLabel;
@ -215,6 +216,7 @@ public class SchematicDisplay : MonoBehaviour
{
if (!_enemy)
{
ShieldIcon.SetActive(_entity.Shield!=null && _entity.Shield.Item.Active);
if (_radiators.Length == 1)
RadiatorTemperatureLabel.text = $"{((int)(_radiators[0].Temperature - 273.15f)).ToString()}°C";
else if (_radiators.Length > 1)