using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using NaughtyAttributes; using RethinkDb.Driver.Net; using TMPro; using UnityEngine; using Unity.Mathematics; using UnityEngine.EventSystems; using static Unity.Mathematics.math; using float2 = Unity.Mathematics.float2; using Random = UnityEngine.Random; public class StrategyGameManager : MonoBehaviour { public bool TestMode; [Section("Scene Links")] public Camera Camera; public TechTreeMsagl TechTree; public MeshRenderer GalaxyBackground; public Transform ZoneRoot; public MeshRenderer ZoneBackground; public MeshRenderer ZoneBoundary; public ClickRaycaster ClickRaycaster; public ReadOnlyPropertiesPanel PropertiesPanel; public ContextMenu ContextMenu; [Section("Tab Links")] public TabGroup PrimaryTabGroup; public TabButton GalaxyTabButton; public TabButton ZoneTabButton; public TabButton TechTabButton; [Section("Prefabs & Prototypes")] public Prototype GalaxyZonePrototype; public Prototype GalaxyZoneLinkPrototype; public ZoneObject ZoneObjectPrefab; public ZoneShip ZoneShipPrefab; public MeshFilter BeltPrefab; [Section("Textures")] public Texture2D PlanetoidSprite; public Texture2D PlanetSprite; public Texture2D GasGiantSprite; public Texture2D OrbitalSprite; public Texture2D SunSprite; public Texture2D WormholeSprite; [Section("UI Properties")] public Color SelectedColor; public Color UnselectedColor; public float GalaxyScale; public float ZoneSizeScale = .01f; public float ZoneMassScale = .01f; public float ZoneMassPower = .5f; public int AsteroidSpritesheetWidth = 4; public int AsteroidSpritesheetHeight = 4; private DatabaseCache _cache; private GameContext _context; // private GalaxyResponseMessage _galaxyResponse; private TabButton _currentTab; private bool _galaxyPopulated; private Guid _populatedZone; private Guid _selectedZone; private GalaxyZone _selectedGalaxyZone; private Dictionary _galaxyZoneObjects = new Dictionary(); private Dictionary _zoneObjects = new Dictionary(); // Key is Orbit private Dictionary _zoneBelts = new Dictionary(); private Dictionary _zoneShips = new Dictionary(); private List _wormholes = new List(); private Vector3 _galaxyCameraPos = -Vector3.forward; private float _galaxyOrthoSize = 50; private Material _boundaryMaterial; private Material _backgroundMaterial; private bool _techLayoutGenerated; private Connection _connection; void Start() { ConsoleController.MessageReceiver = this; _galaxyOrthoSize = GalaxyScale / 2; _cache = new DatabaseCache(); if (TestMode) { _cache.Load(new DirectoryInfo(Application.dataPath).Parent.FullName); _context = new GameContext(_cache, Debug.Log); TechTree.Context = _context; _context.MapLayers = _cache.GetAll().ToDictionary(ml => ml.Name); _context.GalaxyZones = _cache.GetAll() .ToDictionary(z => z.ID, z => new SimplifiedZoneData { Links = z.Wormholes.ToArray(), Name = z.Name, Position = z.Position, ZoneID = z.ID }); } else { // Request galaxy description from the server CultClient.Send(new GalaxyRequestMessage()); // Request blueprints from the server CultClient.Send(new BlueprintsRequestMessage()); // Listen for the server's galaxy description CultClient.AddMessageListener(galaxy => { _context.GalaxyZones = galaxy.Zones.ToDictionary(z => z.ZoneID); _cache.Add(galaxy.GlobalData, true); _context = new GameContext(_cache, Debug.Log); TechTree.Context = _context; _context.MapLayers["StarDensity"] = galaxy.StarDensity; if (_currentTab == GalaxyTabButton && !_galaxyPopulated) PopulateGalaxy(); }); CultClient.AddMessageListener(response => _cache.AddAll(response.Blueprints, true)); // Listen for zone descriptions from the server CultClient.AddMessageListener(zone => { // Cache zone data and contents _cache.Add(zone.Zone); foreach (var entry in zone.Contents) _cache.Add(entry); if(_currentTab==GalaxyTabButton && _selectedZone == zone.Zone.ID) PopulateZoneProperties(_selectedZone); if (_currentTab == ZoneTabButton && _populatedZone != zone.Zone.ID) PopulateZone(); }); } PrimaryTabGroup.OnTabChange += button => { _currentTab = button; if (_currentTab == GalaxyTabButton) { PropertiesPanel.gameObject.SetActive(true); PopulateGalaxyProperties(); if (!_galaxyPopulated) PopulateGalaxy(); Camera.transform.position = _galaxyCameraPos; Camera.orthographicSize = _galaxyOrthoSize; } else if (_currentTab == ZoneTabButton) { PropertiesPanel.gameObject.SetActive(true); var zone = _cache.Get(_selectedZone); if (_populatedZone != _selectedZone && zone != null) PopulateZone(); PopulateZoneProperties(_populatedZone); Camera.transform.position = -Vector3.forward; if (zone != null) Camera.orthographicSize = zone.Radius * ZoneSizeScale; } else if (_currentTab == TechTabButton) { PropertiesPanel.gameObject.SetActive(true); PopulateTechProperties(); if (!_techLayoutGenerated) { TechTree.Initialize(); TechTree.Blueprints = _cache.GetAll().ToArray(); TechTree.GenerateTechs(); } } else PropertiesPanel.gameObject.SetActive(false); }; _boundaryMaterial = ZoneBoundary.material; _backgroundMaterial = ZoneBackground.material; ClickRaycaster.OnClickMiss += () => { ContextMenu.gameObject.SetActive(false); if (_currentTab == GalaxyTabButton) PopulateGalaxyProperties(); else if (_currentTab == ZoneTabButton) PopulateZoneProperties(_populatedZone); else if (_currentTab == TechTabButton) PopulateTechProperties(); }; } private void PopulateGalaxyProperties() { PropertiesPanel.Clear(); PropertiesPanel.Title.text = _context.GlobalData.GalaxyName; PropertiesPanel.AddSection("Galaxy"); PropertiesPanel.AddProperty("Sectors", $"{_context.GalaxyZones.Count}"); } private void PopulateZoneProperties(Guid zone) { PropertiesPanel.Clear(); var zoneData = _cache.Get(zone); PropertiesPanel.Title.text = zoneData.Name; PropertiesPanel.AddSection("Sector"); PropertiesPanel.AddProperty("Planets", $"{zoneData.Planets.Length}"); } private void PopulateTechProperties() { PropertiesPanel.Clear(); PropertiesPanel.Title.text = "Technologies"; var count = _context.Cache.GetAll().Count(); PropertiesPanel.AddProperty("Discovered Techs", $"{count}"); PropertiesPanel.AddProperty("Available Techs", $"{count}"); PropertiesPanel.AddProperty("Researched Techs", $"{count}"); } private void Update() { if (_context != null) { _context.Time = Time.time; //Debug.Log($"Unity delta time: {Time.deltaTime}"); _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(_context.GetOrbitPosition(planet.Key) * ZoneSizeScale, .1f); } foreach (var belt in _zoneBelts) { belt.Value.Transform.position = float3(_context.GetOrbitPosition(belt.Key) * 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[ship.Key.GetAxis()].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(); foreach (var zone in _context.GalaxyZones.Values) { linkedZones.Add(zone.ZoneID); var instance = GalaxyZonePrototype.Instantiate(); instance.position = float3((Vector2) zone.Position - Vector2.one * .5f,0) * GalaxyScale; var instanceZone = instance.GetComponent(); _galaxyZoneObjects[zone.ZoneID] = instanceZone; instanceZone.Label.text = zone.Name; instanceZone.Background.GetComponent().OnClick += (_, pointer) => { if (_selectedGalaxyZone != null) _selectedGalaxyZone.Background.material.SetColor("_TintColor", UnselectedColor); if(_selectedZone != zone.ZoneID) CultClient.Send(new ZoneRequestMessage{ZoneID = zone.ZoneID}); if (TestMode) { if(!_context.Cache.Get(zone.ZoneID).Visited) { GenerateZone(zone.ZoneID); } PopulateZoneProperties(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(); var diff = _context.GalaxyZones[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 GenerateZone(Guid zone) { var zoneData = _cache.Get(zone); 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().Where(i=>i.ResourceDensity.Any()), orbitData: out orbits, planetsData: out planets); _cache.AddAll(orbits); _cache.AddAll(planets); zoneData.Visited = true; } void PopulateZone() { // Delete all the existing zone contents foreach (var zoneObject in _zoneObjects.Values) Destroy(zoneObject.gameObject);//zoneObject.GetComponent().ReturnToPool(); _zoneObjects.Clear(); foreach (var zoneObject in _wormholes) Destroy(zoneObject.gameObject); //zoneObject.GetComponent().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(); _populatedZone = _selectedZone; var zoneData = _cache.Get(_populatedZone); if (TestMode && !zoneData.Visited) { GenerateZone(_populatedZone); } _context.ForceLoadZone = _populatedZone; float zoneDepth = 0; foreach (var planet in _context.ZonePlanets[_populatedZone]) { var planetData = _cache.Get(planet); if (!planetData.Belt) { var planetObject = Instantiate(ZoneObjectPrefab, ZoneRoot); _zoneObjects[planetData.Orbit] = 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().OnClick += (collider, data) => { if (data.button == PointerEventData.InputButton.Left) { PropertiesPanel.Clear(); PropertiesPanel.Title.text = planetData.Name; PropertiesPanel.AddSection(planetData.Mass > _context.GlobalData.SunMass ? "Star" : planetData.Mass > _context.GlobalData.GasGiantMass ? "Gas Giant" : planetData.Mass > _context.GlobalData.PlanetMass ? "Planet" : "Planetoid"); PropertiesPanel.AddProperty("Mass", $"{planetData.Mass}"); PropertiesPanel.AddList("Resources", planetData.Resources.Select(resource => { var itemData = _context.Cache.Get(resource.Key); return new Tuple(itemData.Name, $"{resource.Value:0}"); })); } else if (data.button == PointerEventData.InputButton.Right) { ContextMenu.gameObject.SetActive(true); ContextMenu.SetOptions(new [] { ("Test Option", (Action) (() => Debug.Log("Test Option Selected"))) }); } }; } else { var beltObject = Instantiate(BeltPrefab, ZoneRoot); var collider = beltObject.GetComponent(); var belt = new AsteroidBelt(_context, beltObject, collider, planetData, AsteroidSpritesheetWidth, AsteroidSpritesheetHeight, ZoneSizeScale); _zoneBelts[_cache.Get(planetData.Orbit).Parent] = belt; beltObject.GetComponent().OnClick += (_, data) => { if (data.button == PointerEventData.InputButton.Left) { PropertiesPanel.Clear(); PropertiesPanel.Title.text = planetData.Name; PropertiesPanel.AddSection("Asteroid Belt"); PropertiesPanel.AddProperty("Mass", $"{planetData.Mass}"); PropertiesPanel.AddList("Resources", planetData.Resources.Select(resource => { var itemData = _context.Cache.Get(resource.Key); return new Tuple(itemData.Name, $"{resource.Value:0}"); })); } else if (data.button == PointerEventData.InputButton.Right) { } }; } } 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 = _context.GalaxyZones[wormhole]; var wormholeObject = Instantiate(ZoneObjectPrefab, ZoneRoot); _wormholes.Add(wormholeObject); wormholeObject.transform.position = (Vector2) (_context.WormholePosition(zoneData.ID, wormhole) * ZoneSizeScale); wormholeObject.GravityMesh.gameObject.SetActive(false); wormholeObject.Icon.material.SetTexture("_MainTex", WormholeSprite); wormholeObject.Label.text = otherZone.Name; wormholeObject.Icon.GetComponent().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) return; var zoneData = _cache.Get(_populatedZone); if (zoneData == null) { Debug.Log("Attempted to spawn ship but no zone is populated!"); return; } // Parse first argument as hull name, default to Fighter if argument missing HullData hullData; if (args.Length > 1) { hullData = _cache.GetAll().FirstOrDefault(h => h.Name == args[1]); if (hullData == null) { Debug.Log($"Hull with name \"{args[1]}\" not found!"); return; } } else { hullData = _cache.GetAll().FirstOrDefault(h => h.Name == "Fighter"); } var hull = _context.CreateInstance(hullData.ID, .9f) as Gear; List gear = new List(); if (args.Length > 2) { foreach (string arg in args.Skip(2)) { var gearData = _cache.GetAll().FirstOrDefault(h => h.Name == arg); if (gearData == null) { Debug.Log($"Gear with name \"{arg}\" not found!"); return; } gear.Add(_context.CreateInstance(gearData.ID, .9f) as Gear); } } else { // If no gear arguments supplied and we're spawning a ship, get the first thruster and put it in if (args[0] == "ship") { var thrusterData = _cache.GetAll().FirstOrDefault(g => g.Behaviors.Any(b => b is ThrusterData)); var thruster = _context.CreateInstance(thrusterData.ID, .9f) as Gear; gear.Add(thruster); } } if (args[0] == "ship") { var entity = new Ship(_context, hull.ID, gear.Select(i=>i.ID), Enumerable.Empty(), _populatedZone); _context.Cache.Add(entity); _context.ZoneEntities[_populatedZone][entity.ID] = entity; //_context.Agents.Add(new AgentController(_context, _populatedZone, entity.ID)); var zoneShip = Instantiate(ZoneShipPrefab, ZoneRoot); zoneShip.Label.text = $"Ship {_zoneShips.Count}"; _zoneShips[entity] = zoneShip; } else { Debug.Log($"Unknown entity type: \"{args[0]}\""); } } void newzone(string[] args) { var zoneData = _cache.Get(_selectedZone); if (zoneData == null) { Debug.Log("Attempted to regenerate zone but no zone is selected!"); return; } if(_populatedZone!=Guid.Empty) _context.UnloadZone(_populatedZone); _cache.Delete(zoneData); _context.GalaxyZones.Remove(zoneData.ID); var newZone = zoneData.Copy(); newZone.ID = Guid.NewGuid(); newZone.Name = newZone.ID.ToString().Substring(0, 8); newZone.Visited = false; var linkedZones = _cache.GetAll().Where(z => z.Wormholes.Any(w => w == zoneData.ID)).ToArray(); foreach (var linkedZone in linkedZones) { linkedZone.Wormholes.Remove(zoneData.ID); linkedZone.Wormholes.Add(newZone.ID); } newZone.Wormholes = linkedZones.Select(z => z.ID).ToList(); var zone = _context.GalaxyZones[newZone.ID] = new SimplifiedZoneData { Links = newZone.Wormholes.ToArray(), Name = newZone.Name, Position = newZone.Position, ZoneID = newZone.ID }; var galaxyZone = _galaxyZoneObjects[zoneData.ID]; _galaxyZoneObjects.Remove(zoneData.ID); galaxyZone.Label.text = newZone.Name; _galaxyZoneObjects[newZone.ID] = galaxyZone; var collider = galaxyZone.Background.GetComponent(); collider.Clear(); collider.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 = galaxyZone; _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); }; _cache.Add(newZone); _selectedZone = newZone.ID; _populatedZone = Guid.Empty; if(_currentTab == ZoneTabButton) PopulateZone(); } } 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) { 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]; 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; } public void Update() { for (var i = 0; i < _data.Asteroids.Length; i++) { var rotation = Quaternion.Euler(0, 0, (float) (_context.Time * _data.Asteroids[i].w % 360.0)); var position = (Vector3) (Vector2) OrbitData.Evaluate((float) frac(_context.Time / -_context.OrbitalPeriod(_data.Asteroids[i].x) * _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; } _mesh.vertices = _vertices; _collider.sharedMesh = _mesh; } }