Asteroid Belt Upgrade

Asteroids now use custom particle system with collider so they can be clicked, plus they now orbit at varying speeds!
Fixed flags enum inspector; resources were being assigned to wrong body type: gas giants had planet resources, suns had gas giant resources, asteroids had nothing
This commit is contained in:
hyperion51 2020-05-02 01:30:33 +01:00
commit 7c30a72c71
14 changed files with 516 additions and 202 deletions

View file

@ -9,6 +9,7 @@
<e p="Assembly-CSharp-firstpass.csproj" t="IncludeRecursive" />
<e p="Assembly-CSharp.csproj" t="IncludeRecursive" />
<e p="Assets" t="Include">
<e p="Grid.cs" t="Include" />
<e p="Plugins" t="Include">
<e p="AsyncAwaitUtil" t="Include">
<e p="Source" t="Include">

View file

@ -60,6 +60,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Assets\Grid.cs" />
<Compile Include="Assets\Scripts\ConsoleController.cs" />
<Compile Include="Assets\Scripts\ConsoleView.cs" />
<Compile Include="Assets\Scripts\CultClient.cs" />

46
Assets/Grid.cs Normal file
View file

@ -0,0 +1,46 @@
using UnityEngine;
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class Grid : MonoBehaviour {
public int xSize, ySize;
private Mesh mesh;
private Vector3[] vertices;
private void Awake () {
Generate();
}
private void Generate () {
GetComponent<MeshFilter>().mesh = mesh = new Mesh();
mesh.name = "Procedural Grid";
vertices = new Vector3[(xSize + 1) * (ySize + 1)];
Vector2[] uv = new Vector2[vertices.Length];
Vector4[] tangents = new Vector4[vertices.Length];
Vector4 tangent = new Vector4(1f, 0f, 0f, -1f);
for (int i = 0, y = 0; y <= ySize; y++) {
for (int x = 0; x <= xSize; x++, i++) {
vertices[i] = new Vector3(x, y);
uv[i] = new Vector2((float)x / xSize, (float)y / ySize);
tangents[i] = tangent;
}
}
mesh.vertices = vertices;
mesh.uv = uv;
mesh.tangents = tangents;
int[] triangles = new int[xSize * ySize * 6];
for (int ti = 0, vi = 0, y = 0; y < ySize; y++, vi++) {
for (int x = 0; x < xSize; x++, ti += 6, vi++) {
triangles[ti] = vi;
triangles[ti + 3] = triangles[ti + 2] = vi + 1;
triangles[ti + 4] = triangles[ti + 1] = vi + xSize + 1;
triangles[ti + 5] = vi + xSize + 2;
}
}
mesh.triangles = triangles;
mesh.RecalculateNormals();
}
}

12
Assets/Grid.cs.meta Normal file
View file

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 589fc3064d261406a97550f5fc2d62f2
timeCreated: 1432898976
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,107 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &992254348637625916
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1779911639310264026}
- component: {fileID: 349597964696402918}
- component: {fileID: 2844878085845264008}
- component: {fileID: 917803079556930035}
- component: {fileID: 4397878771830533054}
m_Layer: 0
m_Name: Asteroid Belt
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1779911639310264026
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 992254348637625916}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!33 &349597964696402918
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 992254348637625916}
m_Mesh: {fileID: 0}
--- !u!23 &2844878085845264008
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 992254348637625916}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: c018d99199afeca448c64b9022ac7270, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 0
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
--- !u!64 &917803079556930035
MeshCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 992254348637625916}
m_Material: {fileID: 0}
m_IsTrigger: 0
m_Enabled: 1
serializedVersion: 3
m_Convex: 0
m_CookingOptions: 14
m_Mesh: {fileID: 0}
--- !u!114 &4397878771830533054
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 992254348637625916}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 52538a3309c36fc4583c964a1c0b705f, type: 3}
m_Name:
m_EditorClassIdentifier:

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 1f1bfa2175a13b647888e2949e0cb138
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -5139,13 +5139,13 @@ MonoBehaviour:
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_textInfo:
textComponent: {fileID: 258993626}
characterCount: 0
characterCount: 13
spriteCount: 0
spaceCount: 0
wordCount: 0
spaceCount: 2
wordCount: 2
linkCount: 0
lineCount: 0
pageCount: 0
lineCount: 1
pageCount: 1
materialCount: 1
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
@ -19685,13 +19685,13 @@ MonoBehaviour:
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_textInfo:
textComponent: {fileID: 904172350}
characterCount: 0
characterCount: 2
spriteCount: 0
spaceCount: 0
wordCount: 0
wordCount: 1
linkCount: 0
lineCount: 0
pageCount: 0
lineCount: 1
pageCount: 1
materialCount: 1
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
@ -25837,7 +25837,7 @@ MonoBehaviour:
type: 3}
ZoneShipPrefab: {fileID: 795352744099449573, guid: 7c1524f8ce57a9943920988eae00c86e,
type: 3}
BeltPrefab: {fileID: 3696484618621710612, guid: de2171f0e78642f48ac4cb15f3c012c5,
BeltPrefab: {fileID: 349597964696402918, guid: 1f1bfa2175a13b647888e2949e0cb138,
type: 3}
PlanetoidSprite: {fileID: 2800000, guid: 823d8a1c4e071994087624c39f62b319, type: 3}
PlanetSprite: {fileID: 2800000, guid: 0d2acbd593b7fd349b0b26b4844733ef, type: 3}
@ -25851,9 +25851,13 @@ MonoBehaviour:
ZoneSizeScale: 0.02
ZoneMassScale: 10
ZoneMassPower: 0.25
AsteroidSpritesheetWidth: 4
AsteroidSpritesheetHeight: 4
ZonePropertiesPanel: {fileID: 944413849}
ZoneTitle: {fileID: 1359052237}
ZonePlanetProperties: []
ZonePlanetProperties:
- {fileID: 872134618}
- {fileID: 1470234924}
ZonePropertiesName: {fileID: 1709420494}
ZonePropertiesMass: {fileID: 2130830627}
ZonePropertiesResourcesParent: {fileID: 1470234924}

View file

@ -164,9 +164,12 @@ public class DatabaseInspector : EditorWindow
field.SetValue(obj, Inspect(field.Name.SplitCamelCase(), (int) value));
}
else if (type.IsEnum)
{
var isflags = type.GetCustomAttributes<FlagsAttribute>().Any();
var names = Enum.GetNames(field.FieldType);
field.SetValue(obj,
Inspect(field.Name.SplitCamelCase(), (int) field.GetValue(obj), Enum.GetNames(field.FieldType),
type.GetCustomAttributes<FlagsAttribute>().Any()));
Inspect(field.Name.SplitCamelCase(), (int) field.GetValue(obj), isflags ? names.Skip(1).ToArray() : names, isflags));
}
//else if (field.FieldType == typeof(Color)) Inspect(field.Name, () => (Color) field.GetValue(obj), c => field.SetValue(obj, c));
else if (type == typeof(bool)) field.SetValue(obj, Inspect(field.Name.SplitCamelCase(), (bool) value));
else if (type == typeof(string))
@ -523,7 +526,7 @@ public class DatabaseInspector : EditorWindow
LabelField(label, EditorStyles.boldLabel);
using (var v = new VerticalScope(GUI.skin.box))
{
for (var i = 1; i < enumOptions.Length; i++)
for (var i = 0; i < enumOptions.Length; i++)
{
using (var h = new HorizontalScope())
{

View file

@ -69,8 +69,8 @@ public static class Extensions
private static Random? _random;
private static Random Random => (Random) (_random ?? (_random = new Random((uint) (DateTime.Now.Ticks%uint.MaxValue))));
// public static T RandomElement<T>(this IEnumerable<T> enumerable) => enumerable.ElementAt(Random.NextInt(0, enumerable.Count()));
public static float NextUnbounded(this Random random) => 1 / (1 - random.NextFloat()) - 1;
public static float NextUnbounded(this Random random, float bias, float power) => 1 / (1 - pow(random.NextFloat(), 1 - pow(clamp(bias,0,.99f), 1 / power))) - 1;
public static float NextUnbounded(this ref Random random) => 1 / (1 - random.NextFloat()) - 1;
public static float NextUnbounded(this ref Random random, float bias, float power) => 1 / (1 - pow(random.NextFloat(), 1 - pow(clamp(bias,0,.99f), 1 / power))) - 1;
private static Dictionary<Type,Type[]> InterfaceClasses = new Dictionary<Type, Type[]>();
public static Type[] GetAllInterfaceClasses(this Type type)

View file

@ -41,8 +41,8 @@ public class GlobalData : DatabaseEntry
[InspectableField, JsonProperty("gasGiantMass"), Key(10)]
public float GasGiantMass = 2000;
[InspectableField, JsonProperty("dockingDistance"), Key(11)]
public float DockingDistance = 10;
[InspectableField, JsonProperty("planetMass"), Key(11)]
public float PlanetMass = 100f;
[InspectableField, JsonProperty("satelliteCreationMassFloor"), Key(12)]
public float SatelliteCreationMassFloor = 100;
@ -95,10 +95,22 @@ public class GlobalData : DatabaseEntry
[InspectableField, JsonProperty("beltMassExponent"), Key(27)]
public float BeltMassExponent = 100f;
[InspectableField, JsonProperty("planetMass"), Key(28)]
public float PlanetMass = 100f;
[InspectableField, JsonProperty("asteroidSizeMin"), Key(28)]
public float AsteroidSizeMin = 2f;
[InspectableField, JsonProperty("orbitSpeedMultiplier"), Key(29)]
[InspectableField, JsonProperty("asteroidSizeMax"), Key(29)]
public float AsteroidSizeMax = 10f;
[InspectableField, JsonProperty("asteroidSizeExponent"), Key(30)]
public float AsteroidSizeExponent = 2f;
[InspectableField, JsonProperty("asteroidRotationSpeed"), Key(31)]
public float AsteroidRotationSpeed = 2f;
[InspectableField, JsonProperty("dockingDistance"), Key(32)]
public float DockingDistance = 10;
[InspectableField, JsonProperty("orbitSpeedMultiplier"), Key(33)]
public float OrbitSpeedMultiplier = .25f;
public float PlanetRadius(float mass)

View file

@ -92,6 +92,9 @@ public class PlanetData : DatabaseEntry, INamedEntry
[JsonProperty("resources"), Key(6)]
public Dictionary<Guid, float> Resources = new Dictionary<Guid, float>();
[JsonProperty("asteroids"), Key(7)]
public float4[] Asteroids; // Distance, Phase, Size, RotationSpeed
// [JsonProperty("radius")] [Key(5)]
// public float GravityRadius;

View file

@ -67,34 +67,40 @@ public class ZoneGenerator
planetsData = planets.Where(p=>!p.Empty).Select(planet =>
{
var planetData = new PlanetData
Dictionary<Guid, float> dictionary = new Dictionary<Guid, float>();
foreach (var r in resources)
{
var bodyType = (planet.Belt ? BodyType.Asteroid :
planet.Mass > context.GlobalData.SunMass ? BodyType.Sun :
planet.Mass > context.GlobalData.GasGiantMass ? BodyType.GasGiant :
planet.Mass > context.GlobalData.PlanetMass ? BodyType.Planet : BodyType.Planetoid);
if ((bodyType & r.ResourceBodyType) != 0)
{
float quantity = context.Random.NextUnbounded(r.ResourceDensity.Aggregate(1f, (m, rdm) => m * resourceMaps[rdm]), r.ResourceDensityBiasPower);
if (r.ResourceFloor < quantity) dictionary.Add(r.ID, quantity);
}
}
var planetData = new PlanetData
{
Mass = planet.Mass,
ID = Guid.NewGuid(),
Orbit = orbitMap[planet].ID,
Zone = zone.ID,
Belt = planet.Belt,
Resources = resources
// Filter resources where the body type matches the current planet
.Where(r =>
((planet.Belt ? BodyType.Asteroid :
planet.Mass > context.GlobalData.SunMass ? BodyType.Sun :
planet.Mass > context.GlobalData.GasGiantMass ? BodyType.GasGiant :
planet.Mass > context.GlobalData.PlanetMass ? BodyType.Planet : BodyType.Planetoid) & r.ResourceBodyType) != 0)
// NextUnbounded is our extension function containing resource placement formula
// Obtain bias variable by multiplying all resource maps together
.Select(r => new
{
resource = r,
quantity = context.Random.NextUnbounded(
r.ResourceDensity.Aggregate(1f, (m, rdm) => m * resourceMaps[rdm]),
r.ResourceDensityBiasPower)
})
// Only include resources above a minimum quantity
.Where(r => r.resource.ResourceFloor < r.quantity)
.ToDictionary(r => r.resource.ID, r => r.quantity)
Resources = dictionary
};
planetData.Name = planetData.ID.ToString().Substring(0, 8);
if (planet.Belt)
{
planetData.Asteroids =
Enumerable.Range(0, (int) (pow(planetData.Mass, context.GlobalData.BeltMassExponent) / context.GlobalData.BeltMassRatio * orbitMap[planet].Distance))
.Select(_ => float4(context.Random.NextFloat(orbitMap[planet].Distance * .5f, orbitMap[planet].Distance * 1.5f),
context.Random.NextFloat(),
pow(context.Random.NextFloat(), context.GlobalData.AsteroidSizeExponent) * (context.GlobalData.AsteroidSizeMax - context.GlobalData.AsteroidSizeMin) + context.GlobalData.AsteroidSizeMin,
context.Random.NextFloat() * context.GlobalData.AsteroidRotationSpeed))
.ToArray();
}
return planetData;
}).ToArray();

View file

@ -36,7 +36,7 @@ public class StrategyGameManager : MonoBehaviour
public Prototype GalaxyZoneLinkPrototype;
public ZoneObject ZoneObjectPrefab;
public ZoneShip ZoneShipPrefab;
public ParticleSystem BeltPrefab;
public MeshFilter BeltPrefab;
[Section("Textures")]
public Texture2D PlanetoidSprite;
@ -53,6 +53,8 @@ public class StrategyGameManager : MonoBehaviour
public float ZoneSizeScale = .01f;
public float ZoneMassScale = .01f;
public float ZoneMassPower = .5f;
public int AsteroidSpritesheetWidth = 4;
public int AsteroidSpritesheetHeight = 4;
[Section("Zone Properties Panel")]
public RectTransform ZonePropertiesPanel;
@ -74,7 +76,7 @@ public class StrategyGameManager : MonoBehaviour
private Dictionary<Guid, GalaxyResponseZone> _galaxyResponseZones;
private Dictionary<Guid, GalaxyZone> _galaxyZoneObjects = new Dictionary<Guid, GalaxyZone>();
private Dictionary<OrbitalEntity, ZoneObject> _zoneObjects = new Dictionary<OrbitalEntity, ZoneObject>();
private Dictionary<OrbitalEntity, ParticleSystem> _zoneBelts = new Dictionary<OrbitalEntity, ParticleSystem>();
private Dictionary<OrbitalEntity, AsteroidBelt> _zoneBelts = new Dictionary<OrbitalEntity, AsteroidBelt>();
private Dictionary<Ship, ZoneShip> _zoneShips = new Dictionary<Ship, ZoneShip>();
private List<ZoneObject> _wormholes = new List<ZoneObject>();
private List<ZonePropertiesResource> _zonePropertiesResources = new List<ZonePropertiesResource>();
@ -174,6 +176,277 @@ public class StrategyGameManager : MonoBehaviour
ClickRaycaster.OnClickMiss += () => ZonePropertiesPanel.gameObject.SetActive(false);
}
private void Update()
{
if (_context != null)
{
_context.Time = Time.time;
_context.Update();
}
if (_currentTab == GalaxyTabButton)
{
_galaxyCameraPos = Camera.transform.position;
_galaxyOrthoSize = Camera.orthographicSize;
}
if (_currentTab == ZoneTabButton && _populatedZone == _selectedZone)
{
foreach (var planet in _zoneObjects)
{
planet.Value.transform.position = float3(planet.Key.Position * ZoneSizeScale, .1f);
}
foreach (var belt in _zoneBelts)
{
belt.Value.Transform.position = float3(belt.Key.Position * ZoneSizeScale, .15f);
belt.Value.Update();
}
foreach (var ship in _zoneShips)
{
ship.Value.transform.position = float3(ship.Key.Position * ZoneSizeScale, .05f);
ship.Value.Icon.transform.up = (Vector2) ship.Key.Direction;
var thrusterScale = ship.Value.Thruster.localScale;
thrusterScale.x = ship.Key.Axes.First(kvp => kvp.Key is Thruster).Value;
ship.Value.Thruster.localScale = thrusterScale;
}
}
}
private void OnApplicationQuit()
{
if (TestMode)
{
// TODO: Save game state on exit
}
}
void PopulateGalaxy()
{
_galaxyPopulated = true;
GalaxyBackground.transform.localScale = Vector3.one * GalaxyScale;
var galaxyMat = GalaxyBackground.material;
galaxyMat.SetFloat("Arms", _context.GlobalData.Arms);
galaxyMat.SetFloat("Twist", _context.GlobalData.Twist);
galaxyMat.SetFloat("TwistPower", _context.GlobalData.TwistPower);
galaxyMat.SetFloat("SpokeOffset", _context.MapLayers["StarDensity"].SpokeOffset);
galaxyMat.SetFloat("SpokeScale", _context.MapLayers["StarDensity"].SpokeScale);
galaxyMat.SetFloat("CoreBoost", _context.MapLayers["StarDensity"].CoreBoost);
galaxyMat.SetFloat("CoreBoostOffset", _context.MapLayers["StarDensity"].CoreBoostOffset);
galaxyMat.SetFloat("CoreBoostPower", _context.MapLayers["StarDensity"].CoreBoostPower);
galaxyMat.SetFloat("EdgeReduction", _context.MapLayers["StarDensity"].EdgeReduction);
galaxyMat.SetFloat("NoisePosition", _context.MapLayers["StarDensity"].NoisePosition);
galaxyMat.SetFloat("NoiseAmplitude", _context.MapLayers["StarDensity"].NoiseAmplitude);
galaxyMat.SetFloat("NoiseOffset", _context.MapLayers["StarDensity"].NoiseOffset);
galaxyMat.SetFloat("NoiseGain", _context.MapLayers["StarDensity"].NoiseGain);
galaxyMat.SetFloat("NoiseLacunarity", _context.MapLayers["StarDensity"].NoiseLacunarity);
galaxyMat.SetFloat("NoiseFrequency", _context.MapLayers["StarDensity"].NoiseFrequency);
// var zones = _galaxyResponse.Zones.ToDictionary(z=>z.ZoneID);
var linkedZones = new List<Guid>();
foreach (var zone in _galaxyResponseZones.Values)
{
linkedZones.Add(zone.ZoneID);
var instance = GalaxyZonePrototype.Instantiate<Transform>();
instance.position = float3((Vector2) zone.Position - Vector2.one * .5f,0) * GalaxyScale;
var instanceZone = instance.GetComponent<GalaxyZone>();
_galaxyZoneObjects[zone.ZoneID] = instanceZone;
instanceZone.Label.text = zone.Name;
instanceZone.Background.GetComponent<ClickableCollider>().OnClick += (_, pointer) =>
{
if (_selectedGalaxyZone != null)
_selectedGalaxyZone.Background.material.SetColor("_TintColor", UnselectedColor);
if(_selectedZone != zone.ZoneID)
CultClient.Send(new ZoneRequestMessage{ZoneID = zone.ZoneID});
_selectedZone = zone.ZoneID;
_selectedGalaxyZone = instanceZone;
_selectedGalaxyZone.Background.material.SetColor("_TintColor", SelectedColor);
_selectedZone = zone.ZoneID;
// If the user double clicks on a zone, switch to the zone tab
if(pointer.clickCount == 2) ZoneTabButton.OnPointerClick(pointer);
};
foreach (var linkedZone in zone.Links.Where(l=>!linkedZones.Contains(l)))
{
var link = GalaxyZoneLinkPrototype.Instantiate<Transform>();
var diff = _galaxyResponseZones[linkedZone].Position - zone.Position;
link.position = instance.position + Vector3.forward*.1f;
link.rotation = Quaternion.Euler(0,0,atan2(diff.y, diff.x) * Mathf.Rad2Deg);
link.localScale = new Vector3(length(diff) * GalaxyScale, 1, 1);
}
}
}
void PopulateZone()
{
// Delete all the existing zone contents
foreach (var zoneObject in _zoneObjects.Values) Destroy(zoneObject.gameObject);//zoneObject.GetComponent<Prototype>().ReturnToPool();
_zoneObjects.Clear();
foreach (var zoneObject in _wormholes) Destroy(zoneObject.gameObject); //zoneObject.GetComponent<Prototype>().ReturnToPool();
_wormholes.Clear();
foreach (var belt in _zoneBelts.Values) Destroy(belt.Transform.gameObject);
_zoneBelts.Clear();
foreach (var ship in _zoneShips.Values) Destroy(ship.gameObject);
_zoneShips.Clear();
if(_populatedZone!=Guid.Empty)
_context.UnloadZone(_cache.Get<ZoneData>(_populatedZone));
_populatedZone = _selectedZone;
ZoneData zoneData = _cache.Get<ZoneData>(_populatedZone);
ZoneTitle.text = zoneData.Name;
if (TestMode && !zoneData.Visited)
{
float2 position;
do
{
position = float2(Random.value, Random.value);
} while (_context.MapLayers["StarDensity"].Evaluate(position, _context.GlobalData) < .1f);
OrbitData[] orbits;
PlanetData[] planets;
ZoneGenerator.GenerateZone(
context: _context,
zone: zoneData,
mapLayers: _context.MapLayers.Values,
resources: _cache.GetAll<SimpleCommodityData>().Where(i=>i.ResourceDensity.Any()),
orbitData: out orbits,
planetsData: out planets);
_cache.AddAll(orbits);
_cache.AddAll(planets);
zoneData.Visited = true;
}
var zoneContents = _context.InitializeZone(_populatedZone);
float zoneDepth = 0;
foreach (var kvp in zoneContents)
{
var entity = kvp.Value;
if (kvp.Key is PlanetData planetData)
{
if (!planetData.Belt)
{
var planetObject = Instantiate(ZoneObjectPrefab, ZoneRoot);
_zoneObjects[entity as OrbitalEntity] = planetObject;
planetObject.Label.text = planetData.Name;
planetObject.GravityMesh.gameObject.SetActive(true);
planetObject.GravityMesh.transform.localScale =
Vector3.one * (pow(planetData.Mass, _context.GlobalData.GravityRadiusExponent) *
_context.GlobalData.GravityRadiusMultiplier * 2 * ZoneSizeScale);
var depth = pow(planetData.Mass, ZoneMassPower) * ZoneMassScale;
if (depth > zoneDepth)
zoneDepth = depth;
planetObject.GravityMesh.material.SetFloat("_Depth", depth);
planetObject.Icon.material.SetTexture("_MainTex",
planetData.Mass > _context.GlobalData.SunMass ? SunSprite :
planetData.Mass > _context.GlobalData.GasGiantMass ? GasGiantSprite :
planetData.Mass > _context.GlobalData.PlanetMass ? PlanetSprite :
PlanetoidSprite);
planetObject.Icon.GetComponent<ClickableCollider>().OnClick += (collider, data) =>
{
ZonePropertiesPanel.gameObject.SetActive(true);
foreach (var zonePlanetProperty in ZonePlanetProperties)
zonePlanetProperty.gameObject.SetActive(true);
foreach (var zonePropertiesResource in _zonePropertiesResources)
Destroy(zonePropertiesResource.gameObject);
_zonePropertiesResources.Clear();
ZonePropertiesName.text = planetData.Name;
ZonePropertiesMass.text = $"{planetData.Mass}";
foreach (var resource in planetData.Resources)
{
var itemData = _context.Cache.Get<SimpleCommodityData>(resource.Key);
var resourceInstance = Instantiate(ZonePropertiesResourcePrefab, ZonePropertiesResourcesParent);
resourceInstance.NameLabel.text = itemData.Name;
resourceInstance.QuantityLabel.text = $"{resource.Value:0}";
_zonePropertiesResources.Add(resourceInstance);
}
};
}
else
{
var beltObject = Instantiate(BeltPrefab, ZoneRoot);
var collider = beltObject.GetComponent<MeshCollider>();
var belt = new AsteroidBelt(_context, beltObject, collider, planetData, AsteroidSpritesheetWidth, AsteroidSpritesheetHeight, ZoneSizeScale);
_zoneBelts[entity as OrbitalEntity] = belt;
beltObject.GetComponent<ClickableCollider>().OnClick += (_, data) =>
{
ZonePropertiesPanel.gameObject.SetActive(true);
foreach (var zonePlanetProperty in ZonePlanetProperties)
zonePlanetProperty.gameObject.SetActive(true);
foreach (var zonePropertiesResource in _zonePropertiesResources)
Destroy(zonePropertiesResource.gameObject);
_zonePropertiesResources.Clear();
ZonePropertiesName.text = planetData.Name;
ZonePropertiesMass.text = $"{planetData.Mass}";
foreach (var resource in planetData.Resources)
{
var itemData = _context.Cache.Get<SimpleCommodityData>(resource.Key);
var resourceInstance = Instantiate(ZonePropertiesResourcePrefab, ZonePropertiesResourcesParent);
resourceInstance.NameLabel.text = itemData.Name;
resourceInstance.QuantityLabel.text = $"{resource.Value:0}";
_zonePropertiesResources.Add(resourceInstance);
}
};
// var beltEmission = beltObject.emission;
// beltEmission.rateOverTime =
// new ParticleSystem.MinMaxCurve(
// pow(planetData.Mass,_context.GlobalData.BeltMassExponent)
// / _context.GlobalData.BeltMassRatio * orbit.Distance);
// var beltShape = beltObject.shape;
// beltShape.radius = orbit.Distance * ZoneSizeScale;
// beltShape.donutRadius = orbit.Distance * ZoneSizeScale / 2;
// var beltVelocity = beltObject.velocityOverLifetime;
// beltVelocity.orbitalZ = _context.GlobalData.OrbitSpeedMultiplier * orbit.Distance * ZoneSizeScale / orbit.Period;
// beltObject.Simulate(60);
// beltObject.Play();
}
}
}
var radius = (zoneData.Radius * ZoneSizeScale * 2);
_backgroundMaterial.SetFloat("_ClipDistance", radius);
_backgroundMaterial.SetFloat("_HeightRange", zoneDepth + _boundaryMaterial.GetFloat("_Depth"));
ZoneBoundary.transform.localScale = Vector3.one * radius;
foreach (var wormhole in zoneData.Wormholes)
{
var otherZone = _galaxyResponseZones[wormhole];
var wormholeObject = Instantiate(ZoneObjectPrefab, ZoneRoot);
_wormholes.Add(wormholeObject);
var direction = otherZone.Position - zoneData.Position;
wormholeObject.transform.position = (Vector2) (normalize(direction) * zoneData.Radius * .95f * ZoneSizeScale);
wormholeObject.GravityMesh.gameObject.SetActive(false);
wormholeObject.Icon.material.SetTexture("_MainTex", WormholeSprite);
wormholeObject.Label.text = otherZone.Name;
wormholeObject.Icon.GetComponent<ClickableCollider>().OnClick += (_, pointer) =>
{
// If the user double clicks on a wormhole, switch to that zone
if (pointer.clickCount == 2)
{
_selectedGalaxyZone.Background.material.SetColor("_TintColor", UnselectedColor);
if(_selectedZone != wormhole && !TestMode)
CultClient.Send(new ZoneRequestMessage{ZoneID = wormhole});
_selectedZone = wormhole;
if(TestMode)
PopulateZone();
_selectedGalaxyZone = _galaxyZoneObjects[wormhole];
_selectedGalaxyZone.Background.material.SetColor("_TintColor", SelectedColor);
}
};
}
}
void spawn(string[] args)
{
if (!TestMode)
@ -315,252 +588,89 @@ public class StrategyGameManager : MonoBehaviour
if(_currentTab == ZoneTabButton)
PopulateZone();
}
}
private void Update()
public class AsteroidBelt
{
public Transform Transform;
private MeshFilter _filter;
private MeshCollider _collider;
private Vector3[] _vertices;
private Vector3[] _normals;
private Vector2[] _uvs;
private int[] _indices;
private PlanetData _data;
private GameContext _context;
private Mesh _mesh;
private float _zoneScale;
public AsteroidBelt(GameContext context, MeshFilter meshFilter, MeshCollider collider, PlanetData data, int spritesheetWidth, int spritesheetHeight, float zoneScale)
{
if (_context != null)
{
_context.Time = Time.time;
_context.Update();
}
if (_currentTab == GalaxyTabButton)
{
_galaxyCameraPos = Camera.transform.position;
_galaxyOrthoSize = Camera.orthographicSize;
}
if (_currentTab == ZoneTabButton && _populatedZone == _selectedZone)
{
foreach (var planet in _zoneObjects)
{
planet.Value.transform.position = float3(planet.Key.Position * ZoneSizeScale, .1f);
}
Transform = collider.transform;
_context = context;
_data = data;
_filter = meshFilter;
_collider = collider;
_zoneScale = zoneScale;
_vertices = new Vector3[data.Asteroids.Length*4];
_normals = new Vector3[data.Asteroids.Length*4];
_uvs = new Vector2[data.Asteroids.Length*4];
_indices = new int[data.Asteroids.Length*6];
foreach (var belt in _zoneBelts)
{
belt.Value.transform.position = float3(belt.Key.Position * ZoneSizeScale, .15f);
}
foreach (var ship in _zoneShips)
{
ship.Value.transform.position = float3(ship.Key.Position * ZoneSizeScale, .05f);
ship.Value.Icon.transform.up = (Vector2) ship.Key.Direction;
var thrusterScale = ship.Value.Thruster.localScale;
thrusterScale.x = ship.Key.Axes.First(kvp => kvp.Key is Thruster).Value;
ship.Value.Thruster.localScale = thrusterScale;
}
var maxDist = 0f;
var spriteSize = float2(1f / spritesheetWidth, 1f / spritesheetHeight);
// vertex order: bottom left, top left, top right, bottom right
for (var i = 0; i < _data.Asteroids.Length; i++)
{
if (_data.Asteroids[i].x > maxDist)
maxDist = _data.Asteroids[i].x;
var spriteX = Random.Range(0, spritesheetWidth);
var spriteY = Random.Range(0, spritesheetHeight);
_uvs[i * 4] = new Vector2(spriteX * spriteSize.x, spriteY * spriteSize.y);
_uvs[i * 4 + 1] = new Vector2(spriteX * spriteSize.x, spriteY * spriteSize.y + spriteSize.y);
_uvs[i * 4 + 2] = new Vector2(spriteX * spriteSize.x + spriteSize.x, spriteY * spriteSize.y + spriteSize.y);
_uvs[i * 4 + 3] = new Vector2(spriteX * spriteSize.x + spriteSize.x, spriteY * spriteSize.y);
_indices[i * 6] = i * 4;
_indices[i * 6 + 1] = i * 4 + 1;
_indices[i * 6 + 2] = i * 4 + 3;
_indices[i * 6 + 3] = i * 4 + 3;
_indices[i * 6 + 4] = i * 4 + 1;
_indices[i * 6 + 5] = i * 4 + 2;
}
for (var i = 0; i < _normals.Length; i++)
{
_normals[i] = -Vector3.forward;
}
_mesh = new Mesh();
_mesh.vertices = _vertices;
_mesh.uv = _uvs;
_mesh.triangles = _indices;
_mesh.normals = _normals;
_mesh.bounds = new Bounds(Vector3.zero, Vector3.one * maxDist);
_filter.mesh = _mesh;
//_collider.sharedMesh = _mesh;
}
private void OnApplicationQuit()
public void Update()
{
if (TestMode)
for (var i = 0; i < _data.Asteroids.Length; i++)
{
// TODO: Save game state on exit
}
}
void PopulateGalaxy()
{
_galaxyPopulated = true;
GalaxyBackground.transform.localScale = Vector3.one * GalaxyScale;
var galaxyMat = GalaxyBackground.material;
galaxyMat.SetFloat("Arms", _context.GlobalData.Arms);
galaxyMat.SetFloat("Twist", _context.GlobalData.Twist);
galaxyMat.SetFloat("TwistPower", _context.GlobalData.TwistPower);
galaxyMat.SetFloat("SpokeOffset", _context.MapLayers["StarDensity"].SpokeOffset);
galaxyMat.SetFloat("SpokeScale", _context.MapLayers["StarDensity"].SpokeScale);
galaxyMat.SetFloat("CoreBoost", _context.MapLayers["StarDensity"].CoreBoost);
galaxyMat.SetFloat("CoreBoostOffset", _context.MapLayers["StarDensity"].CoreBoostOffset);
galaxyMat.SetFloat("CoreBoostPower", _context.MapLayers["StarDensity"].CoreBoostPower);
galaxyMat.SetFloat("EdgeReduction", _context.MapLayers["StarDensity"].EdgeReduction);
galaxyMat.SetFloat("NoisePosition", _context.MapLayers["StarDensity"].NoisePosition);
galaxyMat.SetFloat("NoiseAmplitude", _context.MapLayers["StarDensity"].NoiseAmplitude);
galaxyMat.SetFloat("NoiseOffset", _context.MapLayers["StarDensity"].NoiseOffset);
galaxyMat.SetFloat("NoiseGain", _context.MapLayers["StarDensity"].NoiseGain);
galaxyMat.SetFloat("NoiseLacunarity", _context.MapLayers["StarDensity"].NoiseLacunarity);
galaxyMat.SetFloat("NoiseFrequency", _context.MapLayers["StarDensity"].NoiseFrequency);
// var zones = _galaxyResponse.Zones.ToDictionary(z=>z.ZoneID);
var linkedZones = new List<Guid>();
foreach (var zone in _galaxyResponseZones.Values)
{
linkedZones.Add(zone.ZoneID);
var instance = GalaxyZonePrototype.Instantiate<Transform>();
instance.position = float3((Vector2) zone.Position - Vector2.one * .5f,0) * GalaxyScale;
var instanceZone = instance.GetComponent<GalaxyZone>();
_galaxyZoneObjects[zone.ZoneID] = instanceZone;
instanceZone.Label.text = zone.Name;
instanceZone.Background.GetComponent<ClickableCollider>().OnClick += (_, pointer) =>
{
if (_selectedGalaxyZone != null)
_selectedGalaxyZone.Background.material.SetColor("_TintColor", UnselectedColor);
if(_selectedZone != zone.ZoneID)
CultClient.Send(new ZoneRequestMessage{ZoneID = zone.ZoneID});
_selectedZone = zone.ZoneID;
_selectedGalaxyZone = instanceZone;
_selectedGalaxyZone.Background.material.SetColor("_TintColor", SelectedColor);
_selectedZone = zone.ZoneID;
// If the user double clicks on a zone, switch to the zone tab
if(pointer.clickCount == 2) ZoneTabButton.OnPointerClick(pointer);
};
foreach (var linkedZone in zone.Links.Where(l=>!linkedZones.Contains(l)))
{
var link = GalaxyZoneLinkPrototype.Instantiate<Transform>();
var diff = _galaxyResponseZones[linkedZone].Position - zone.Position;
link.position = instance.position + Vector3.forward*.1f;
link.rotation = Quaternion.Euler(0,0,atan2(diff.y, diff.x) * Mathf.Rad2Deg);
link.localScale = new Vector3(length(diff) * GalaxyScale, 1, 1);
}
}
}
void PopulateZone()
{
// Delete all the existing zone contents
foreach (var zoneObject in _zoneObjects.Values) Destroy(zoneObject.gameObject);//zoneObject.GetComponent<Prototype>().ReturnToPool();
_zoneObjects.Clear();
foreach (var zoneObject in _wormholes) Destroy(zoneObject.gameObject); //zoneObject.GetComponent<Prototype>().ReturnToPool();
_wormholes.Clear();
foreach (var belt in _zoneBelts.Values) Destroy(belt.gameObject);
_zoneBelts.Clear();
foreach (var ship in _zoneShips.Values) Destroy(ship.gameObject);
_zoneShips.Clear();
if(_populatedZone!=Guid.Empty)
_context.UnloadZone(_cache.Get<ZoneData>(_populatedZone));
_populatedZone = _selectedZone;
ZoneData zoneData = _cache.Get<ZoneData>(_populatedZone);
ZoneTitle.text = zoneData.Name;
if (TestMode && !zoneData.Visited)
{
float2 position;
do
{
position = float2(Random.value, Random.value);
} while (_context.MapLayers["StarDensity"].Evaluate(position, _context.GlobalData) < .1f);
OrbitData[] orbits;
PlanetData[] planets;
ZoneGenerator.GenerateZone(
context: _context,
zone: zoneData,
mapLayers: _context.MapLayers.Values,
resources: _cache.GetAll<SimpleCommodityData>().Where(i=>i.ResourceDensity.Any()),
orbitData: out orbits,
planetsData: out planets);
_cache.AddAll(orbits);
_cache.AddAll(planets);
zoneData.Visited = true;
}
var zoneContents = _context.InitializeZone(_populatedZone);
float zoneDepth = 0;
foreach (var kvp in zoneContents)
{
var entity = kvp.Value;
if (kvp.Key is PlanetData planetData)
{
if (!planetData.Belt)
{
var planetObject = Instantiate(ZoneObjectPrefab, ZoneRoot);
_zoneObjects[entity as OrbitalEntity] = planetObject;
planetObject.Label.text = planetData.Name;
planetObject.GravityMesh.gameObject.SetActive(true);
planetObject.GravityMesh.transform.localScale =
Vector3.one * (pow(planetData.Mass, _context.GlobalData.GravityRadiusExponent) *
_context.GlobalData.GravityRadiusMultiplier * 2 * ZoneSizeScale);
var depth = pow(planetData.Mass, ZoneMassPower) * ZoneMassScale;
if (depth > zoneDepth)
zoneDepth = depth;
planetObject.GravityMesh.material.SetFloat("_Depth", depth);
planetObject.Icon.material.SetTexture("_MainTex",
planetData.Mass > _context.GlobalData.SunMass ? SunSprite :
planetData.Mass > _context.GlobalData.GasGiantMass ? GasGiantSprite :
planetData.Mass > _context.GlobalData.PlanetMass ? PlanetSprite :
PlanetoidSprite);
planetObject.Icon.GetComponent<ClickableCollider>().OnClick += (collider, data) =>
{
ZonePropertiesPanel.gameObject.SetActive(true);
foreach (var zonePlanetProperty in ZonePlanetProperties)
zonePlanetProperty.gameObject.SetActive(true);
foreach (var zonePropertiesResource in _zonePropertiesResources)
Destroy(zonePropertiesResource.gameObject);
_zonePropertiesResources.Clear();
ZonePropertiesName.text = planetData.Name;
ZonePropertiesMass.text = $"{planetData.Mass}";
foreach (var resource in planetData.Resources)
{
var itemData = _context.Cache.Get<SimpleCommodityData>(resource.Key);
var resourceInstance = Instantiate(ZonePropertiesResourcePrefab, ZonePropertiesResourcesParent);
resourceInstance.NameLabel.text = itemData.Name;
resourceInstance.QuantityLabel.text = $"{resource.Value:0}";
_zonePropertiesResources.Add(resourceInstance);
}
};
}
else
{
var beltObject = Instantiate(BeltPrefab, ZoneRoot);
var orbit = _cache.Get<OrbitData>(planetData.Orbit);
_zoneBelts[entity as OrbitalEntity] = beltObject;
var beltEmission = beltObject.emission;
beltEmission.rateOverTime =
new ParticleSystem.MinMaxCurve(
pow(planetData.Mass,_context.GlobalData.BeltMassExponent)
/ _context.GlobalData.BeltMassRatio * orbit.Distance);
var beltShape = beltObject.shape;
beltShape.radius = orbit.Distance * ZoneSizeScale;
beltShape.donutRadius = orbit.Distance * ZoneSizeScale / 2;
var beltVelocity = beltObject.velocityOverLifetime;
beltVelocity.orbitalZ = _context.GlobalData.OrbitSpeedMultiplier * orbit.Distance * ZoneSizeScale / orbit.Period;
beltObject.Simulate(60);
beltObject.Play();
}
}
var rotation = Quaternion.Euler(0, 0, (float) (_context.Time * _data.Asteroids[i].w % 360.0));
var position = (Vector3) (Vector2)
OrbitData.Evaluate((float) (_context.Time / -pow(_data.Asteroids[i].x, _context.GlobalData.OrbitPeriodExponent) * _context.GlobalData.OrbitPeriodMultiplier) *
_context.GlobalData.OrbitSpeedMultiplier + _data.Asteroids[i].y) * (_data.Asteroids[i].x * _zoneScale);
_vertices[i * 4] = rotation * new Vector3(-_data.Asteroids[i].z,-_data.Asteroids[i].z,0) + position;
_vertices[i * 4 + 1] = rotation * new Vector3(-_data.Asteroids[i].z,_data.Asteroids[i].z,0) + position;
_vertices[i * 4 + 2] = rotation * new Vector3(_data.Asteroids[i].z,_data.Asteroids[i].z,0) + position;
_vertices[i * 4 + 3] = rotation * new Vector3(_data.Asteroids[i].z,-_data.Asteroids[i].z,0) + position;
}
var radius = (zoneData.Radius * ZoneSizeScale * 2);
_backgroundMaterial.SetFloat("_ClipDistance", radius);
_backgroundMaterial.SetFloat("_HeightRange", zoneDepth + _boundaryMaterial.GetFloat("_Depth"));
ZoneBoundary.transform.localScale = Vector3.one * radius;
foreach (var wormhole in zoneData.Wormholes)
{
var otherZone = _galaxyResponseZones[wormhole];
var wormholeObject = Instantiate(ZoneObjectPrefab, ZoneRoot);
_wormholes.Add(wormholeObject);
var direction = otherZone.Position - zoneData.Position;
wormholeObject.transform.position = (Vector2) (normalize(direction) * zoneData.Radius * .95f * ZoneSizeScale);
wormholeObject.GravityMesh.gameObject.SetActive(false);
wormholeObject.Icon.material.SetTexture("_MainTex", WormholeSprite);
wormholeObject.Label.text = otherZone.Name;
wormholeObject.Icon.GetComponent<ClickableCollider>().OnClick += (_, pointer) =>
{
// If the user double clicks on a wormhole, switch to that zone
if (pointer.clickCount == 2)
{
_selectedGalaxyZone.Background.material.SetColor("_TintColor", UnselectedColor);
if(_selectedZone != wormhole && !TestMode)
CultClient.Send(new ZoneRequestMessage{ZoneID = wormhole});
_selectedZone = wormhole;
if(TestMode)
PopulateZone();
_selectedGalaxyZone = _galaxyZoneObjects[wormhole];
_selectedGalaxyZone.Background.material.SetColor("_TintColor", SelectedColor);
}
};
}
_mesh.vertices = _vertices;
_collider.sharedMesh = _mesh;
}
}

View file

@ -108,7 +108,9 @@ You can unfold the categories of items in the list view to see what items exist.
If midgard.gamecult.games is not currently up, you can always build and run the economy server yourself, and connect to it by typing localhost into the main menu. To start the game in this mode you open the "Start" scene and type "localhost" into the host field. You will still need to create an account.
Another way to test the game entirely offline doesn't require running the economy server, but you still need to download the database contents. Instead of connecting to the database with the "Connect" button, click "Connect All", which in addition to syncing item data will also sync galaxy data such as the sectors. Once the tools are finished syncing, which can take a while (you know it's done when the console has stopped logging "Received {table} entry"), you can click "Save" to create a local backup of the entire database contents. If you enter Play mode in the "Main" scene with the TestMode parameter set to true in the game manager, the game will use that local copy instead of requiring a connection to the master server.
Another way to test the game entirely offline doesn't require running the economy server, but you still need to download the database contents. Instead of connecting to the database with the "Connect" button, click "Connect All", which in addition to syncing item data will also sync galaxy data such as the sectors. Once the tools are finished syncing, which can take a while (you know it's done when the console has stopped logging "Received {table} entry"), you can click "Save" to create a local backup of the entire database. If you enter Play mode in the "Main" scene with the TestMode parameter set to true in the game manager, the game will use that local copy instead of requiring a connection to the master server.
Note that this process needs to be repeated every time the data model changes or you wish to test the game with updated database contents.
### Debug Console