Initial commit
This commit is contained in:
8
Assets/Scripts/Age.meta
Normal file
8
Assets/Scripts/Age.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2e2247a86126c0e4b900c3c1a9f1f2c3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
153
Assets/Scripts/Age/AgingController.cs
Normal file
153
Assets/Scripts/Age/AgingController.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class AgingController : MonoBehaviour
|
||||
{
|
||||
[Header("Ìàòåð³àëè øê³ðè")]
|
||||
public Material faceMaterial;
|
||||
public Material neckMaterial;
|
||||
public Material bodyMaterial;
|
||||
|
||||
[Header("Çà÷³ñêè")]
|
||||
public GameObject youngHair;
|
||||
public GameObject oldHaircut;
|
||||
|
||||
[Header("Áîðîäà")]
|
||||
public GameObject beard;
|
||||
|
||||
[Header("Blend Shapes")]
|
||||
public SkinnedMeshRenderer bodyMesh;
|
||||
public int bellyBlendIndex = 4;
|
||||
public int overweightBlendIndex = 1;
|
||||
|
||||
[Header("×àñ")]
|
||||
public float agingDuration = 20f;
|
||||
|
||||
[HideInInspector] public float currentAge = 25f;
|
||||
[HideInInspector] public bool isFinished = false;
|
||||
|
||||
private Material[] oldHairMats;
|
||||
private Material[] youngHairMats;
|
||||
private Material[] beardMats;
|
||||
private float timer = 0f;
|
||||
private Color currentHairColor = new Color(0.80f, 0.80f, 0.80f);
|
||||
private Color _lastAppliedColor = Color.clear;
|
||||
private int _currentPlanetIndex = 2;
|
||||
|
||||
private HairColorSettings hairColorSettings;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
hairColorSettings = FindObjectOfType<HairColorSettings>();
|
||||
youngHairMats = GetMaterials(youngHair);
|
||||
oldHairMats = GetMaterials(oldHaircut);
|
||||
beardMats = GetMaterials(beard);
|
||||
RestartAging();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (isFinished) return;
|
||||
|
||||
if (hairColorSettings != null)
|
||||
{
|
||||
Color newColor = hairColorSettings.GetHairColor(_currentPlanetIndex);
|
||||
if (newColor != _lastAppliedColor)
|
||||
{
|
||||
_lastAppliedColor = newColor;
|
||||
currentHairColor = newColor;
|
||||
ApplyColorToMats(oldHairMats);
|
||||
ApplyColorToMats(beardMats);
|
||||
}
|
||||
}
|
||||
|
||||
timer += Time.deltaTime;
|
||||
float t = Mathf.Clamp01(timer / agingDuration);
|
||||
currentAge = Mathf.Lerp(25f, 70f, t);
|
||||
|
||||
faceMaterial.SetFloat("_AgingProgress", t);
|
||||
bodyMesh.SetBlendShapeWeight(bellyBlendIndex, t * 100f);
|
||||
bodyMesh.SetBlendShapeWeight(overweightBlendIndex, t * 10f);
|
||||
|
||||
SetAlpha(youngHairMats, 1f - t);
|
||||
|
||||
if (t >= 0.4f)
|
||||
{
|
||||
float hairT = Mathf.Clamp01((t - 0.4f) / 0.6f);
|
||||
SetAlphaWithColor(oldHairMats, hairT);
|
||||
SetAlphaWithColor(beardMats, hairT);
|
||||
}
|
||||
|
||||
if (t >= 1f) isFinished = true;
|
||||
}
|
||||
|
||||
public void RestartAging()
|
||||
{
|
||||
faceMaterial.SetFloat("_AgingProgress", 0f);
|
||||
SetAlpha(oldHairMats, 0f);
|
||||
SetAlpha(beardMats, 0f);
|
||||
SetAlpha(youngHairMats, 1f);
|
||||
bodyMesh.SetBlendShapeWeight(bellyBlendIndex, 0f);
|
||||
bodyMesh.SetBlendShapeWeight(overweightBlendIndex, 0f);
|
||||
timer = 0f;
|
||||
currentAge = 25f;
|
||||
isFinished = false;
|
||||
_lastAppliedColor = Color.clear;
|
||||
}
|
||||
|
||||
public void ApplyHairColor(int planetIndex)
|
||||
{
|
||||
if (hairColorSettings == null) return;
|
||||
_currentPlanetIndex = planetIndex;
|
||||
currentHairColor = hairColorSettings.GetHairColor(planetIndex);
|
||||
_lastAppliedColor = currentHairColor;
|
||||
ApplyColorToMats(oldHairMats);
|
||||
ApplyColorToMats(beardMats);
|
||||
}
|
||||
|
||||
void ApplyColorToMats(Material[] mats)
|
||||
{
|
||||
foreach (var m in mats)
|
||||
{
|
||||
Color c = m.GetColor("_BaseColor");
|
||||
c.r = currentHairColor.r;
|
||||
c.g = currentHairColor.g;
|
||||
c.b = currentHairColor.b;
|
||||
m.SetColor("_BaseColor", c);
|
||||
}
|
||||
}
|
||||
|
||||
Material[] GetMaterials(GameObject obj)
|
||||
{
|
||||
var renderers = obj.GetComponentsInChildren<Renderer>();
|
||||
var list = new List<Material>();
|
||||
foreach (var r in renderers)
|
||||
foreach (var m in r.materials)
|
||||
list.Add(m);
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
void SetAlpha(Material[] mats, float alpha)
|
||||
{
|
||||
foreach (var m in mats)
|
||||
{
|
||||
Color c = m.GetColor("_BaseColor");
|
||||
c.a = alpha;
|
||||
m.SetColor("_BaseColor", c);
|
||||
}
|
||||
}
|
||||
|
||||
void SetAlphaWithColor(Material[] mats, float alpha)
|
||||
{
|
||||
foreach (var m in mats)
|
||||
{
|
||||
Color c = m.GetColor("_BaseColor");
|
||||
c.r = currentHairColor.r;
|
||||
c.g = currentHairColor.g;
|
||||
c.b = currentHairColor.b;
|
||||
c.a = alpha;
|
||||
m.SetColor("_BaseColor", c);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Age/AgingController.cs.meta
Normal file
11
Assets/Scripts/Age/AgingController.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 49e589cdd4d181045ab5adda62877ab3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
18
Assets/Scripts/Age/AgingUI.cs
Normal file
18
Assets/Scripts/Age/AgingUI.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
|
||||
public class AgingUI : MonoBehaviour
|
||||
{
|
||||
public AgingController agingController;
|
||||
public TextMeshProUGUI ageText;
|
||||
public TextMeshProUGUI planetText;
|
||||
|
||||
void Update()
|
||||
{
|
||||
int age = Mathf.RoundToInt(agingController.currentAge);
|
||||
ageText.text = "³ê: " + age + " ³ç 70 ðîê³â";
|
||||
planetText.text = "Íà Çåìë³ ïðîéøëî: 70 ðîê³â";
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Age/AgingUI.cs.meta
Normal file
11
Assets/Scripts/Age/AgingUI.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a416d6325763bd94992f465ce1466203
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
43
Assets/Scripts/Age/HairColorSettings.cs
Normal file
43
Assets/Scripts/Age/HairColorSettings.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class HairColorSettings : MonoBehaviour
|
||||
{
|
||||
[Header("Ęîëłđ ńčâčíč íŕ đłçíčő ďëŕíĺňŕő")]
|
||||
public bool useDefaultGray = true;
|
||||
|
||||
[Header("Ęîëüîđč ńčâčíč äë˙ ęîćíîż ďëŕíĺňč")]
|
||||
public Color mercuryHairColor = new Color(0.85f, 0.85f, 0.85f);
|
||||
public Color venusHairColor = new Color(0.95f, 0.90f, 0.80f);
|
||||
public Color earthHairColor = new Color(0.80f, 0.80f, 0.80f);
|
||||
public Color moonHairColor = new Color(0.90f, 0.90f, 0.95f);
|
||||
public Color marsHairColor = new Color(0.85f, 0.75f, 0.70f);
|
||||
public Color jupiterHairColor = new Color(0.80f, 0.85f, 0.90f);
|
||||
public Color saturnHairColor = new Color(0.90f, 0.85f, 0.75f);
|
||||
public Color uranusHairColor = new Color(0.75f, 0.90f, 0.90f);
|
||||
public Color neptuneHairColor = new Color(0.70f, 0.75f, 0.95f);
|
||||
public Color plutoHairColor = new Color(0.80f, 0.80f, 0.90f);
|
||||
|
||||
private static readonly Color defaultGray = Color.white;
|
||||
|
||||
public Color GetHairColor(int planetIndex)
|
||||
{
|
||||
if (useDefaultGray) return defaultGray;
|
||||
|
||||
switch (planetIndex)
|
||||
{
|
||||
case 0: return mercuryHairColor;
|
||||
case 1: return venusHairColor;
|
||||
case 2: return earthHairColor;
|
||||
case 3: return moonHairColor;
|
||||
case 4: return marsHairColor;
|
||||
case 5: return jupiterHairColor;
|
||||
case 6: return saturnHairColor;
|
||||
case 7: return uranusHairColor;
|
||||
case 8: return neptuneHairColor;
|
||||
case 9: return plutoHairColor;
|
||||
default: return defaultGray;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Age/HairColorSettings.cs.meta
Normal file
11
Assets/Scripts/Age/HairColorSettings.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c2e109373c9aed240a398aabb35c34dc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
133
Assets/Scripts/Age/PlanetSelector.cs
Normal file
133
Assets/Scripts/Age/PlanetSelector.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
public class PlanetSelector : MonoBehaviour
|
||||
{
|
||||
public AgingController agingController;
|
||||
public TimeManager timeManager;
|
||||
|
||||
public Button previousButton;
|
||||
public Button nextButton;
|
||||
public TextMeshProUGUI ageText;
|
||||
public TextMeshProUGUI planetText;
|
||||
|
||||
public Material skyboxMaterial;
|
||||
|
||||
private int currentPlanetIndex = 2;
|
||||
|
||||
private string[] planetNames = {
|
||||
"Ìåðêóð³¿", "Âåíåð³", "Çåìë³", "̳ñÿö³",
|
||||
"Ìàðñ³", "Þï³òåð³", "Ñàòóðí³", "Óðàí³", "Íåïòóí³", "Ïëóòîí³"
|
||||
};
|
||||
|
||||
private float[] dayLengthHours = {
|
||||
1407.6f, 5832.5f, 24f, 708.7f,
|
||||
24.6f, 9.9f, 10.7f, 17.2f, 16.1f, 153.3f
|
||||
};
|
||||
|
||||
private float[] daysInYear = {
|
||||
88f, 225f, 365f, 365f,
|
||||
687f, 4333f, 10759f, 30687f, 60190f, 90560f
|
||||
};
|
||||
|
||||
private float[] agingDurations = {
|
||||
5f, 10f, 20f, 20f, 28f, 40f, 40f, 40f, 40f, 40f
|
||||
};
|
||||
|
||||
private float[] orbitalYears = {
|
||||
0.24f, 0.62f, 1f, 1f, 1.88f, 11.86f, 29.46f, 84.01f, 164.8f, 248f
|
||||
};
|
||||
|
||||
private Color[] skyboxColors =
|
||||
{
|
||||
new Color(0.75f,0.78f,0.85f),
|
||||
new Color(1.25f,0.85f,0.55f),
|
||||
new Color(1f,1f,1f),
|
||||
new Color(0.75f,0.85f,1.2f),
|
||||
new Color(1.35f,0.55f,0.45f),
|
||||
new Color(0.7f,1.15f,1.25f),
|
||||
new Color(0.95f,0.65f,1.35f),
|
||||
new Color(0.55f,1.25f,1.1f),
|
||||
new Color(0.45f,0.65f,1.35f),
|
||||
new Color(0.7f,0.7f,1.35f)
|
||||
};
|
||||
|
||||
private float[] skyboxExposure =
|
||||
{
|
||||
0.7f,
|
||||
0.8f,
|
||||
0.9f,
|
||||
0.95f,
|
||||
1.15f,
|
||||
0.9f,
|
||||
0.8f,
|
||||
0.7f,
|
||||
0.6f,
|
||||
0.9f
|
||||
};
|
||||
|
||||
private float[] skyboxRotation =
|
||||
{
|
||||
10f, 25f, 0f, 5f, 15f,
|
||||
40f, 60f, 90f, 120f, 160f
|
||||
};
|
||||
|
||||
void Start()
|
||||
{
|
||||
ApplyPlanet();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (timeManager.showAge)
|
||||
{
|
||||
int earthAge = Mathf.RoundToInt(agingController.currentAge);
|
||||
ageText.text = "³ê: " + earthAge + " ³ç 70 ðîê³â";
|
||||
|
||||
float planetAge = timeManager.fromBeginning
|
||||
? agingController.currentAge / orbitalYears[currentPlanetIndex]
|
||||
: (agingController.currentAge - 25f) / orbitalYears[currentPlanetIndex];
|
||||
|
||||
planetText.text = "Íà " + planetNames[currentPlanetIndex] + " ïðîéøëî: " + planetAge.ToString("F1") + " ðîê³â";
|
||||
}
|
||||
else
|
||||
{
|
||||
ageText.text = "Òðèâàë³ñòü äîáè íà " + planetNames[currentPlanetIndex] + ": " + dayLengthHours[currentPlanetIndex].ToString("F1") + " ãîäèí";
|
||||
planetText.text = "Ó ðîö³ íà " + planetNames[currentPlanetIndex] + ": " + daysInYear[currentPlanetIndex].ToString("F0") + " ä³á";
|
||||
}
|
||||
}
|
||||
|
||||
public void OnNextButton()
|
||||
{
|
||||
if (currentPlanetIndex < planetNames.Length - 1)
|
||||
{
|
||||
currentPlanetIndex++;
|
||||
ApplyPlanet();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPreviousButton()
|
||||
{
|
||||
if (currentPlanetIndex > 0)
|
||||
{
|
||||
currentPlanetIndex--;
|
||||
ApplyPlanet();
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyPlanet()
|
||||
{
|
||||
agingController.agingDuration = agingDurations[currentPlanetIndex];
|
||||
agingController.RestartAging();
|
||||
agingController.ApplyHairColor(currentPlanetIndex);
|
||||
skyboxMaterial.SetColor("_Tint", skyboxColors[currentPlanetIndex]);
|
||||
skyboxMaterial.SetFloat("_Exposure", skyboxExposure[currentPlanetIndex]);
|
||||
skyboxMaterial.SetFloat("_Rotation", skyboxRotation[currentPlanetIndex]);
|
||||
DynamicGI.UpdateEnvironment();
|
||||
previousButton.interactable = currentPlanetIndex > 0;
|
||||
nextButton.interactable = currentPlanetIndex < planetNames.Length - 1;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Age/PlanetSelector.cs.meta
Normal file
11
Assets/Scripts/Age/PlanetSelector.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a51db86c8a5cf5049b54adefdf69354f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
19
Assets/Scripts/Age/TimeManager.cs
Normal file
19
Assets/Scripts/Age/TimeManager.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class TimeManager : MonoBehaviour
|
||||
{
|
||||
public bool showAge = true;
|
||||
public bool fromBeginning = false;
|
||||
|
||||
public void ToggleMode(bool value)
|
||||
{
|
||||
showAge = value;
|
||||
}
|
||||
|
||||
public void ToggleFromBeginning(bool value)
|
||||
{
|
||||
fromBeginning = value;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Age/TimeManager.cs.meta
Normal file
11
Assets/Scripts/Age/TimeManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d5f0adf8bd0cb840bc2cdd81739a4fc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Scripts/Countries.meta
Normal file
8
Assets/Scripts/Countries.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 403c540f6d109ba4aa01773a8c9a1979
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
85
Assets/Scripts/Countries/CountryData.cs
Normal file
85
Assets/Scripts/Countries/CountryData.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class CountryData : MonoBehaviour
|
||||
{
|
||||
public string countryName = "Unknown";
|
||||
public string countryNameUkr;
|
||||
public float utcOffset = 0f;
|
||||
public string utcLabel = "UTC+0";
|
||||
public bool hasAnomaly = false;
|
||||
public string anomalyFact = "";
|
||||
public Vector3 centerOnGlobe;
|
||||
|
||||
[Header("DST")]
|
||||
public float baseUtcOffset = 0f;
|
||||
public string baseUtcLabel = "UTC+0";
|
||||
public float dstUtcOffset = 0f;
|
||||
public string dstUtcLabel = "UTC+0";
|
||||
public int dstStartMonth = 0;
|
||||
public int dstEndMonth = 0;
|
||||
|
||||
private Material _mat;
|
||||
private static readonly int PropBase = Shader.PropertyToID("_BaseColor");
|
||||
private static readonly int PropHover = Shader.PropertyToID("_HoverStrength");
|
||||
private static readonly int PropSelect = Shader.PropertyToID("_SelectStrength");
|
||||
|
||||
public void Init(Material mat) { _mat = mat; }
|
||||
|
||||
public void SetDefaultColor(Color color)
|
||||
{
|
||||
if (_mat != null) _mat.SetColor(PropBase, color);
|
||||
}
|
||||
|
||||
public void OnHoverEnter()
|
||||
{
|
||||
if (_mat != null) _mat.SetFloat(PropHover, 0.35f);
|
||||
}
|
||||
|
||||
public void OnHoverExit()
|
||||
{
|
||||
if (_mat != null) _mat.SetFloat(PropHover, 0f);
|
||||
}
|
||||
|
||||
public void Select()
|
||||
{
|
||||
if (_mat != null)
|
||||
{
|
||||
_mat.SetFloat(PropHover, 0f);
|
||||
_mat.SetFloat(PropSelect, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
public void Deselect()
|
||||
{
|
||||
if (_mat != null)
|
||||
{
|
||||
_mat.SetFloat(PropHover, 0f);
|
||||
_mat.SetFloat(PropSelect, 0f);
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshDST()
|
||||
{
|
||||
if (dstStartMonth == 0) return;
|
||||
|
||||
int month = System.DateTime.Now.Month;
|
||||
bool isDST;
|
||||
|
||||
if (dstStartMonth > dstEndMonth)
|
||||
isDST = (month >= dstStartMonth || month <= dstEndMonth);
|
||||
else
|
||||
isDST = (month >= dstStartMonth && month <= dstEndMonth);
|
||||
|
||||
utcOffset = isDST ? dstUtcOffset : baseUtcOffset;
|
||||
utcLabel = isDST ? dstUtcLabel : baseUtcLabel;
|
||||
}
|
||||
|
||||
public string GetCurrentTime()
|
||||
{
|
||||
System.TimeSpan offset = System.TimeSpan.FromMinutes(utcOffset * 60.0);
|
||||
System.DateTime local = System.DateTime.UtcNow + offset;
|
||||
return local.ToString("dd MMMM, HH:mm", new System.Globalization.CultureInfo("uk-UA"));
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Countries/CountryData.cs.meta
Normal file
11
Assets/Scripts/Countries/CountryData.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b759dcae01e29714496ed7cb7cd68bb4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
294
Assets/Scripts/Countries/CountrySelector.cs
Normal file
294
Assets/Scripts/Countries/CountrySelector.cs
Normal file
@@ -0,0 +1,294 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
public class CountrySelector : MonoBehaviour
|
||||
{
|
||||
[Header("UI")]
|
||||
public TextMeshProUGUI countryNameText;
|
||||
public TextMeshProUGUI utcText;
|
||||
public TextMeshProUGUI timeText;
|
||||
public TextMeshProUGUI anomalyText;
|
||||
|
||||
[Header("References")]
|
||||
public PlaneController planeController;
|
||||
public GlobeBuilder globeBuilder;
|
||||
public string startCountryName = "Ukraine";
|
||||
|
||||
private CountryData _selected;
|
||||
private CountryData _hovered;
|
||||
private CountryData _startCountry;
|
||||
private Camera _cam;
|
||||
private float _lastClickTime;
|
||||
private CountryData _lastClickedCountry;
|
||||
private const float DoubleClickTime = 0.35f;
|
||||
private bool _startMessageShown = false;
|
||||
private Coroutine _hideCoroutine;
|
||||
|
||||
void Start()
|
||||
{
|
||||
_cam = Camera.main;
|
||||
HideAll();
|
||||
|
||||
CountryData[] all = FindObjectsOfType<CountryData>();
|
||||
foreach (CountryData c in all)
|
||||
{
|
||||
if (c.countryName == startCountryName)
|
||||
{
|
||||
_startCountry = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_startCountry == null && all.Length > 0)
|
||||
_startCountry = all[0];
|
||||
|
||||
if (!_startMessageShown)
|
||||
{
|
||||
_startMessageShown = true;
|
||||
StartCoroutine(ShowStartMessage());
|
||||
}
|
||||
}
|
||||
|
||||
string GetDisplayName(CountryData country)
|
||||
{
|
||||
return !string.IsNullOrEmpty(country.countryNameUkr)
|
||||
? country.countryNameUkr
|
||||
: country.countryName;
|
||||
}
|
||||
|
||||
IEnumerator ShowStartMessage()
|
||||
{
|
||||
if (countryNameText != null)
|
||||
{
|
||||
countryNameText.gameObject.SetActive(true);
|
||||
utcText.gameObject.SetActive(true);
|
||||
timeText.gameObject.SetActive(true);
|
||||
|
||||
countryNameText.text = "Ïî÷èíàºìî íàø ïîë³ò ç Óêðà¿íè!";
|
||||
utcText.text = "UTC+2";
|
||||
timeText.text = "Çàðàç: " + System.DateTime.UtcNow.AddHours(2).ToString("HH:mm");
|
||||
|
||||
yield return new WaitForSeconds(2f);
|
||||
|
||||
float t = 0f;
|
||||
while (t < 1f)
|
||||
{
|
||||
t += Time.deltaTime;
|
||||
float alpha = 1f - t;
|
||||
countryNameText.canvasRenderer.SetAlpha(alpha);
|
||||
utcText.canvasRenderer.SetAlpha(alpha);
|
||||
timeText.canvasRenderer.SetAlpha(alpha);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
HideAll();
|
||||
ResetAlpha();
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (planeController == null || !planeController.IsFlying())
|
||||
{
|
||||
HandleHover();
|
||||
HandleClick();
|
||||
HandleHotkeys();
|
||||
}
|
||||
}
|
||||
|
||||
void HandleHotkeys()
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.Alpha1))
|
||||
FlyToByName("American Samoa");
|
||||
if (Input.GetKeyDown(KeyCode.Alpha2))
|
||||
FlyToByName("Kiribati");
|
||||
}
|
||||
|
||||
void FlyToByName(string name)
|
||||
{
|
||||
CountryData[] all = FindObjectsOfType<CountryData>();
|
||||
foreach (CountryData c in all)
|
||||
{
|
||||
if (c.countryName == name)
|
||||
{
|
||||
FlyTo(c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HandleHover()
|
||||
{
|
||||
Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
|
||||
if (Physics.Raycast(ray, out RaycastHit hit))
|
||||
{
|
||||
CountryData c = hit.collider.GetComponent<CountryData>()
|
||||
?? hit.collider.GetComponentInParent<CountryData>();
|
||||
if (c != _hovered)
|
||||
{
|
||||
if (_hovered != null && _hovered != _selected) _hovered.OnHoverExit();
|
||||
_hovered = c;
|
||||
if (_hovered != null && _hovered != _selected) _hovered.OnHoverEnter();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_hovered != null && _hovered != _selected) _hovered.OnHoverExit();
|
||||
_hovered = null;
|
||||
}
|
||||
}
|
||||
|
||||
void HandleClick()
|
||||
{
|
||||
if (!Input.GetMouseButtonDown(0)) return;
|
||||
if (UnityEngine.EventSystems.EventSystem.current != null &&
|
||||
UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject()) return;
|
||||
|
||||
Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
|
||||
if (!Physics.Raycast(ray, out RaycastHit hit)) { DeselectAll(); return; }
|
||||
|
||||
CountryData clicked = hit.collider.GetComponent<CountryData>()
|
||||
?? hit.collider.GetComponentInParent<CountryData>();
|
||||
if (clicked == null) { DeselectAll(); return; }
|
||||
|
||||
float timeSinceLastClick = Time.time - _lastClickTime;
|
||||
bool isDoubleClick = timeSinceLastClick < DoubleClickTime && _lastClickedCountry == clicked;
|
||||
|
||||
_lastClickTime = Time.time;
|
||||
_lastClickedCountry = clicked;
|
||||
|
||||
if (isDoubleClick)
|
||||
FlyTo(clicked);
|
||||
else
|
||||
SingleClick(clicked);
|
||||
}
|
||||
|
||||
void SingleClick(CountryData country)
|
||||
{
|
||||
if (_hideCoroutine != null) StopCoroutine(_hideCoroutine);
|
||||
ResetAlpha();
|
||||
|
||||
if (_selected != null && _selected != country) _selected.Deselect();
|
||||
_selected = country;
|
||||
_selected.Select();
|
||||
if (globeBuilder != null) globeBuilder.SetRotation(false);
|
||||
|
||||
if (country == _startCountry)
|
||||
ShowFullInfo(country);
|
||||
else
|
||||
ShowBasicInfo(country);
|
||||
}
|
||||
|
||||
void ShowBasicInfo(CountryData country)
|
||||
{
|
||||
HideAll();
|
||||
if (countryNameText != null)
|
||||
{
|
||||
countryNameText.gameObject.SetActive(true);
|
||||
countryNameText.text = GetDisplayName(country);
|
||||
}
|
||||
if (utcText != null)
|
||||
{
|
||||
utcText.gameObject.SetActive(true);
|
||||
utcText.text = country.utcLabel;
|
||||
}
|
||||
}
|
||||
|
||||
void ShowFullInfo(CountryData country)
|
||||
{
|
||||
if (_hideCoroutine != null) StopCoroutine(_hideCoroutine);
|
||||
ResetAlpha();
|
||||
HideAll();
|
||||
|
||||
if (countryNameText != null)
|
||||
{
|
||||
countryNameText.gameObject.SetActive(true);
|
||||
countryNameText.text = GetDisplayName(country);
|
||||
}
|
||||
if (utcText != null)
|
||||
{
|
||||
utcText.gameObject.SetActive(true);
|
||||
utcText.text = country.utcLabel;
|
||||
}
|
||||
if (timeText != null)
|
||||
{
|
||||
timeText.gameObject.SetActive(true);
|
||||
timeText.text = "Çàðàç: " + country.GetCurrentTime();
|
||||
}
|
||||
if (anomalyText != null)
|
||||
{
|
||||
anomalyText.gameObject.SetActive(country.hasAnomaly);
|
||||
if (country.hasAnomaly)
|
||||
anomalyText.text = country.anomalyFact;
|
||||
}
|
||||
|
||||
_hideCoroutine = StartCoroutine(AutoHide());
|
||||
}
|
||||
|
||||
IEnumerator AutoHide()
|
||||
{
|
||||
yield return new WaitForSeconds(5f);
|
||||
float t = 0f;
|
||||
while (t < 1f)
|
||||
{
|
||||
t += Time.deltaTime;
|
||||
float alpha = 1f - t;
|
||||
if (countryNameText != null) countryNameText.canvasRenderer.SetAlpha(alpha);
|
||||
if (utcText != null) utcText.canvasRenderer.SetAlpha(alpha);
|
||||
if (timeText != null) timeText.canvasRenderer.SetAlpha(alpha);
|
||||
if (anomalyText != null) anomalyText.canvasRenderer.SetAlpha(alpha);
|
||||
yield return null;
|
||||
}
|
||||
HideAll();
|
||||
ResetAlpha();
|
||||
}
|
||||
|
||||
void FlyTo(CountryData destination)
|
||||
{
|
||||
if (planeController == null || _startCountry == null) return;
|
||||
if (destination == _startCountry) return;
|
||||
|
||||
if (_hideCoroutine != null) StopCoroutine(_hideCoroutine);
|
||||
HideAll();
|
||||
ResetAlpha();
|
||||
|
||||
if (_selected != null) { _selected.Deselect(); _selected = null; }
|
||||
if (globeBuilder != null) globeBuilder.SetRotation(false);
|
||||
|
||||
planeController.Fly(
|
||||
_startCountry,
|
||||
destination,
|
||||
() =>
|
||||
{
|
||||
_startCountry = destination;
|
||||
ShowFullInfo(destination);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void DeselectAll()
|
||||
{
|
||||
if (_hideCoroutine != null) StopCoroutine(_hideCoroutine);
|
||||
if (_selected != null) { _selected.Deselect(); _selected = null; }
|
||||
HideAll();
|
||||
ResetAlpha();
|
||||
if (globeBuilder != null) globeBuilder.SetRotation(true);
|
||||
}
|
||||
|
||||
void HideAll()
|
||||
{
|
||||
if (countryNameText != null) countryNameText.gameObject.SetActive(false);
|
||||
if (utcText != null) utcText.gameObject.SetActive(false);
|
||||
if (timeText != null) timeText.gameObject.SetActive(false);
|
||||
if (anomalyText != null) anomalyText.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
void ResetAlpha()
|
||||
{
|
||||
if (countryNameText != null) countryNameText.canvasRenderer.SetAlpha(1f);
|
||||
if (utcText != null) utcText.canvasRenderer.SetAlpha(1f);
|
||||
if (timeText != null) timeText.canvasRenderer.SetAlpha(1f);
|
||||
if (anomalyText != null) anomalyText.canvasRenderer.SetAlpha(1f);
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Countries/CountrySelector.cs.meta
Normal file
11
Assets/Scripts/Countries/CountrySelector.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0fee30d2d4a34434b81c3ec6fe81d531
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
38
Assets/Scripts/Countries/DSTManager.cs
Normal file
38
Assets/Scripts/Countries/DSTManager.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class DSTManager : MonoBehaviour
|
||||
{
|
||||
public GameObject globeObject;
|
||||
|
||||
private float _timer;
|
||||
private const float INTERVAL = 3600f;
|
||||
|
||||
void Start()
|
||||
{
|
||||
RefreshAll();
|
||||
_timer = INTERVAL;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
_timer -= Time.deltaTime;
|
||||
if (_timer <= 0f)
|
||||
{
|
||||
RefreshAll();
|
||||
_timer = INTERVAL;
|
||||
}
|
||||
}
|
||||
|
||||
void RefreshAll()
|
||||
{
|
||||
if (globeObject == null) return;
|
||||
foreach (Transform child in globeObject.transform)
|
||||
{
|
||||
if (child.gameObject.name == "Ocean") continue;
|
||||
CountryData cd = child.GetComponent<CountryData>();
|
||||
if (cd != null) cd.RefreshDST();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Countries/DSTManager.cs.meta
Normal file
11
Assets/Scripts/Countries/DSTManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d5ed4cbb71b7fe14ebf089cde731e793
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
77
Assets/Scripts/Countries/GlobeBuilder.cs
Normal file
77
Assets/Scripts/Countries/GlobeBuilder.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class GlobeBuilder : MonoBehaviour
|
||||
{
|
||||
public float globeRadius = 5f;
|
||||
public float rotationSpeed = 3f;
|
||||
public bool autoRotate = true;
|
||||
public Material countryMaterial;
|
||||
|
||||
private static readonly Color[] Palette = new Color[]
|
||||
{
|
||||
new Color(0.98f, 0.85f, 0.65f),
|
||||
new Color(0.65f, 0.85f, 0.72f),
|
||||
new Color(0.72f, 0.82f, 0.95f),
|
||||
new Color(0.95f, 0.78f, 0.72f),
|
||||
new Color(0.88f, 0.95f, 0.68f),
|
||||
new Color(0.95f, 0.90f, 0.65f),
|
||||
new Color(0.78f, 0.88f, 0.95f),
|
||||
new Color(0.95f, 0.72f, 0.85f),
|
||||
new Color(0.72f, 0.95f, 0.88f),
|
||||
new Color(0.90f, 0.80f, 0.95f),
|
||||
new Color(0.95f, 0.88f, 0.78f),
|
||||
new Color(0.75f, 0.92f, 0.75f),
|
||||
};
|
||||
|
||||
void Awake()
|
||||
{
|
||||
SetupCountries();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (autoRotate)
|
||||
transform.Rotate(Vector3.up, rotationSpeed * Time.deltaTime);
|
||||
}
|
||||
|
||||
void SetupCountries()
|
||||
{
|
||||
CountryData[] countries = GetComponentsInChildren<CountryData>();
|
||||
for (int i = 0; i < countries.Length; i++)
|
||||
{
|
||||
CountryData country = countries[i];
|
||||
Renderer rend = country.GetComponent<Renderer>();
|
||||
if (rend == null) rend = country.GetComponentInChildren<Renderer>();
|
||||
if (rend == null) continue;
|
||||
|
||||
Material mat = countryMaterial != null
|
||||
? new Material(countryMaterial)
|
||||
: new Material(rend.sharedMaterial);
|
||||
rend.material = mat;
|
||||
country.Init(mat);
|
||||
|
||||
Color baseColor = Palette[i % Palette.Length];
|
||||
if (country.hasAnomaly)
|
||||
baseColor = Color.Lerp(baseColor, new Color(1f, 0.5f, 0.3f), 0.3f);
|
||||
country.SetDefaultColor(baseColor);
|
||||
|
||||
MeshFilter mf = country.GetComponent<MeshFilter>();
|
||||
if (mf == null) mf = country.GetComponentInChildren<MeshFilter>();
|
||||
if (mf != null && mf.sharedMesh != null)
|
||||
{
|
||||
Vector3 worldCenter = country.transform.TransformPoint(mf.sharedMesh.bounds.center);
|
||||
Vector3 localCenter = transform.InverseTransformPoint(worldCenter);
|
||||
country.centerOnGlobe = localCenter.normalized * globeRadius;
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 localPos = transform.InverseTransformPoint(country.transform.position);
|
||||
country.centerOnGlobe = localPos.normalized * globeRadius;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetRotation(bool enabled) => autoRotate = enabled;
|
||||
}
|
||||
11
Assets/Scripts/Countries/GlobeBuilder.cs.meta
Normal file
11
Assets/Scripts/Countries/GlobeBuilder.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a84917a6b77810746883628c2f7e6dfa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
62
Assets/Scripts/Countries/GlobeRotator.cs
Normal file
62
Assets/Scripts/Countries/GlobeRotator.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class GlobeRotator : MonoBehaviour
|
||||
{
|
||||
public float rotationSpeed = 200f;
|
||||
public float zoomSpeed = 2f;
|
||||
public float minZoom = 5f;
|
||||
public float maxZoom = 25f;
|
||||
public float smoothing = 8f;
|
||||
|
||||
private Vector3 _lastMousePos;
|
||||
private bool _isDragging;
|
||||
private Camera _cam;
|
||||
private float _deltaX;
|
||||
private float _deltaY;
|
||||
|
||||
void Start()
|
||||
{
|
||||
_cam = Camera.main;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (Input.GetMouseButtonDown(1))
|
||||
{
|
||||
_lastMousePos = Input.mousePosition;
|
||||
_isDragging = true;
|
||||
}
|
||||
|
||||
if (Input.GetMouseButtonUp(1))
|
||||
_isDragging = false;
|
||||
|
||||
float targetX = 0f;
|
||||
float targetY = 0f;
|
||||
|
||||
if (_isDragging)
|
||||
{
|
||||
Vector3 delta = Input.mousePosition - _lastMousePos;
|
||||
targetX = -delta.x * rotationSpeed * Time.deltaTime;
|
||||
targetY = delta.y * rotationSpeed * Time.deltaTime;
|
||||
_lastMousePos = Input.mousePosition;
|
||||
}
|
||||
|
||||
_deltaX = Mathf.Lerp(_deltaX, targetX, Time.deltaTime * smoothing);
|
||||
_deltaY = Mathf.Lerp(_deltaY, targetY, Time.deltaTime * smoothing);
|
||||
|
||||
transform.Rotate(Vector3.up, _deltaX, Space.World);
|
||||
|
||||
Vector3 rightAxis = _cam.transform.right;
|
||||
transform.Rotate(rightAxis, _deltaY, Space.World);
|
||||
|
||||
float scroll = Input.GetAxis("Mouse ScrollWheel");
|
||||
if (scroll != 0f && _cam != null)
|
||||
{
|
||||
float dist = Vector3.Distance(_cam.transform.position, transform.position);
|
||||
dist = Mathf.Clamp(dist - scroll * zoomSpeed, minZoom, maxZoom);
|
||||
_cam.transform.position = transform.position - _cam.transform.forward * dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Countries/GlobeRotator.cs.meta
Normal file
11
Assets/Scripts/Countries/GlobeRotator.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3ce1bde26601ec34097dc616cb361d11
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
15
Assets/Scripts/Countries/GlobeStartOrientation.cs
Normal file
15
Assets/Scripts/Countries/GlobeStartOrientation.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class GlobeStartOrientation : MonoBehaviour
|
||||
{
|
||||
public float rotationX = 0f;
|
||||
public float rotationY = 0f;
|
||||
public float rotationZ = 0f;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
transform.rotation = Quaternion.Euler(rotationX, rotationY, rotationZ);
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Countries/GlobeStartOrientation.cs.meta
Normal file
11
Assets/Scripts/Countries/GlobeStartOrientation.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ae5fee76ecb9594199e9e1247f33970
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
191
Assets/Scripts/Countries/PlaneController.cs
Normal file
191
Assets/Scripts/Countries/PlaneController.cs
Normal file
@@ -0,0 +1,191 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class PlaneController : MonoBehaviour
|
||||
{
|
||||
public GameObject planePrefab;
|
||||
public float flightDuration = 5f;
|
||||
public float arcHeight = 0.3f;
|
||||
public float hoverHeight = 0.2f;
|
||||
public float globeRadius = 5f;
|
||||
public float rotateToDuration = 1.5f;
|
||||
|
||||
[Header("Camera Follow")]
|
||||
public float cameraDistance = 3f;
|
||||
public float cameraHeight = 0.5f;
|
||||
public float cameraSmoothing = 3f;
|
||||
|
||||
private bool _flying = false;
|
||||
private GameObject _plane;
|
||||
private LineRenderer _trail;
|
||||
private Transform _globe;
|
||||
private Camera _mainCamera;
|
||||
private Vector3 _cameraStartPos;
|
||||
private Quaternion _cameraStartRot;
|
||||
|
||||
void Start()
|
||||
{
|
||||
_globe = GameObject.Find("Globe")?.transform;
|
||||
_mainCamera = Camera.main;
|
||||
SpawnPlane();
|
||||
PlaceOverCountry("Ukraine");
|
||||
}
|
||||
|
||||
void SpawnPlane()
|
||||
{
|
||||
if (planePrefab == null) return;
|
||||
_plane = Instantiate(planePrefab);
|
||||
if (_globe != null) _plane.transform.SetParent(_globe);
|
||||
|
||||
_trail = _plane.AddComponent<LineRenderer>();
|
||||
_trail.positionCount = 0;
|
||||
_trail.startWidth = 0.03f;
|
||||
_trail.endWidth = 0.03f;
|
||||
_trail.useWorldSpace = true;
|
||||
_trail.material = new Material(Shader.Find("Sprites/Default"));
|
||||
_trail.material.color = new Color(1f, 1f, 1f, 0.8f);
|
||||
}
|
||||
|
||||
Vector3 GetLocalDirection(CountryData c)
|
||||
{
|
||||
Renderer rend = c.GetComponentInChildren<Renderer>();
|
||||
Vector3 worldCenter = rend != null ? rend.bounds.center : c.transform.position;
|
||||
if (_globe == null) return worldCenter.normalized;
|
||||
return _globe.InverseTransformPoint(worldCenter).normalized;
|
||||
}
|
||||
|
||||
public void PlaceOverCountry(string countryName)
|
||||
{
|
||||
if (_plane == null) return;
|
||||
CountryData[] all = FindObjectsOfType<CountryData>();
|
||||
foreach (CountryData c in all)
|
||||
{
|
||||
if (c.countryName == countryName)
|
||||
{
|
||||
SnapToSurface(c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SnapToSurface(CountryData country)
|
||||
{
|
||||
if (_plane == null || _globe == null) return;
|
||||
Vector3 dir = GetLocalDirection(country);
|
||||
_plane.transform.localPosition = dir * (globeRadius + hoverHeight);
|
||||
_plane.transform.up = (_plane.transform.position - _globe.position).normalized;
|
||||
}
|
||||
|
||||
public void Fly(CountryData fromCountry, CountryData toCountry, System.Action onArrived)
|
||||
{
|
||||
if (_flying || _plane == null) return;
|
||||
StartCoroutine(FlyCoroutine(fromCountry, toCountry, onArrived));
|
||||
}
|
||||
|
||||
IEnumerator FlyCoroutine(CountryData fromCountry, CountryData toCountry, System.Action onArrived)
|
||||
{
|
||||
_flying = true;
|
||||
_trail.positionCount = 0;
|
||||
|
||||
_cameraStartPos = _mainCamera.transform.position;
|
||||
_cameraStartRot = _mainCamera.transform.rotation;
|
||||
|
||||
Vector3 fromDir = GetLocalDirection(fromCountry);
|
||||
float elapsed = 0f;
|
||||
|
||||
while (elapsed < flightDuration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = Mathf.Clamp01(elapsed / flightDuration);
|
||||
float smoothT = Mathf.SmoothStep(0f, 1f, t);
|
||||
|
||||
Vector3 toDir = GetLocalDirection(toCountry);
|
||||
Vector3 onSphere = Vector3.Slerp(fromDir, toDir, smoothT);
|
||||
float arc = Mathf.Sin(smoothT * Mathf.PI) * arcHeight;
|
||||
_plane.transform.localPosition = onSphere * (globeRadius + hoverHeight + arc);
|
||||
|
||||
float tNext = Mathf.Min(smoothT + 0.02f, 1f);
|
||||
Vector3 nextOnSphere = Vector3.Slerp(fromDir, toDir, tNext);
|
||||
float nextArc = Mathf.Sin(tNext * Mathf.PI) * arcHeight;
|
||||
Vector3 nextWorld = _globe.TransformPoint(nextOnSphere * (globeRadius + hoverHeight + nextArc));
|
||||
|
||||
Vector3 worldForward = (nextWorld - _plane.transform.position).normalized;
|
||||
Vector3 worldUp = (_plane.transform.position - _globe.position).normalized;
|
||||
if (worldForward.magnitude > 0.001f)
|
||||
_plane.transform.rotation = Quaternion.LookRotation(worldForward, worldUp);
|
||||
|
||||
Vector3 sideDir = Vector3.Cross(worldForward, worldUp).normalized;
|
||||
Vector3 desiredPos = _plane.transform.position
|
||||
+ sideDir * cameraDistance
|
||||
+ worldUp * cameraHeight;
|
||||
Quaternion desiredRot = Quaternion.LookRotation(
|
||||
_plane.transform.position - desiredPos, worldUp);
|
||||
|
||||
_mainCamera.transform.position = Vector3.Lerp(
|
||||
_mainCamera.transform.position, desiredPos,
|
||||
Time.deltaTime * cameraSmoothing);
|
||||
_mainCamera.transform.rotation = Quaternion.Slerp(
|
||||
_mainCamera.transform.rotation, desiredRot,
|
||||
Time.deltaTime * cameraSmoothing);
|
||||
|
||||
_trail.positionCount++;
|
||||
_trail.SetPosition(_trail.positionCount - 1, _plane.transform.position);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
SnapToSurface(toCountry);
|
||||
_trail.positionCount = 0;
|
||||
|
||||
yield return StartCoroutine(RestoreCamera());
|
||||
yield return StartCoroutine(RotateGlobeToCountry(toCountry));
|
||||
|
||||
_flying = false;
|
||||
onArrived?.Invoke();
|
||||
}
|
||||
|
||||
IEnumerator RestoreCamera()
|
||||
{
|
||||
float elapsed = 0f;
|
||||
float duration = 0.8f;
|
||||
Vector3 fromPos = _mainCamera.transform.position;
|
||||
Quaternion fromRot = _mainCamera.transform.rotation;
|
||||
|
||||
while (elapsed < duration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = Mathf.SmoothStep(0f, 1f, elapsed / duration);
|
||||
_mainCamera.transform.position = Vector3.Lerp(fromPos, _cameraStartPos, t);
|
||||
_mainCamera.transform.rotation = Quaternion.Slerp(fromRot, _cameraStartRot, t);
|
||||
yield return null;
|
||||
}
|
||||
_mainCamera.transform.position = _cameraStartPos;
|
||||
_mainCamera.transform.rotation = _cameraStartRot;
|
||||
}
|
||||
|
||||
IEnumerator RotateGlobeToCountry(CountryData country)
|
||||
{
|
||||
if (_globe == null || _mainCamera == null) yield break;
|
||||
|
||||
Vector3 countryWorldPos = _globe.TransformPoint(GetLocalDirection(country) * globeRadius);
|
||||
Vector3 globeCenter = _globe.position;
|
||||
Vector3 camDir = (_mainCamera.transform.position - globeCenter).normalized;
|
||||
|
||||
Quaternion startRot = _globe.rotation;
|
||||
Quaternion targetRot = Quaternion.FromToRotation(
|
||||
(countryWorldPos - globeCenter).normalized, camDir) * _globe.rotation;
|
||||
|
||||
float elapsed = 0f;
|
||||
while (elapsed < rotateToDuration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = Mathf.SmoothStep(0f, 1f, elapsed / rotateToDuration);
|
||||
_globe.rotation = Quaternion.Slerp(startRot, targetRot, t);
|
||||
yield return null;
|
||||
}
|
||||
_globe.rotation = targetRot;
|
||||
}
|
||||
|
||||
public bool IsFlying() => _flying;
|
||||
}
|
||||
11
Assets/Scripts/Countries/PlaneController.cs.meta
Normal file
11
Assets/Scripts/Countries/PlaneController.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b4d4da9516068841af91f9f45d9a1c1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
18
Assets/Scripts/DroneMovement.cs
Normal file
18
Assets/Scripts/DroneMovement.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class DroneMovement : MonoBehaviour
|
||||
{
|
||||
public float speed = 20f;
|
||||
private bool _moving = true;
|
||||
|
||||
public void StopMoving() { _moving = false; }
|
||||
public void ResumeMoving() { _moving = true; }
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!_moving) return;
|
||||
transform.position += Vector3.forward * speed * Time.deltaTime;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/DroneMovement.cs.meta
Normal file
11
Assets/Scripts/DroneMovement.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 921562a23f10f764d804dca0f461fe90
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
63
Assets/Scripts/DroneTrigger.cs
Normal file
63
Assets/Scripts/DroneTrigger.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class DroneTrigger : MonoBehaviour
|
||||
{
|
||||
public LightWave wave1;
|
||||
public LightWave wave2;
|
||||
public DroneMovement droneMovement;
|
||||
public float droneSpeed = 40f;
|
||||
public float davidSpeed = 10f;
|
||||
public float davidSimDelay = 0.5f;
|
||||
private bool _fired = false;
|
||||
|
||||
public void Reset() { _fired = false; }
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (_fired) return;
|
||||
if (transform.position.z >= 0f)
|
||||
{
|
||||
_fired = true;
|
||||
droneMovement.StopMoving();
|
||||
bool isSimulation = GameManager.Instance != null && GameManager.Instance.isSimulation;
|
||||
bool isView2 = GameManager.Instance != null && GameManager.Instance.isView2;
|
||||
if (isView2)
|
||||
StartCoroutine(LaunchView2());
|
||||
else if (isSimulation)
|
||||
StartCoroutine(LaunchSim());
|
||||
else
|
||||
StartCoroutine(LaunchReal());
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator LaunchSim()
|
||||
{
|
||||
float delay = davidSimDelay / (droneSpeed / davidSpeed);
|
||||
wave1.StartWave();
|
||||
wave1.SetDroneText(true, isSimulation: true, simDelay: delay);
|
||||
yield return new WaitForSeconds(delay);
|
||||
wave2.StartWave();
|
||||
wave2.SetDroneText(false, isSimulation: true, simDelay: delay);
|
||||
}
|
||||
|
||||
IEnumerator LaunchReal()
|
||||
{
|
||||
wave1.StartWave();
|
||||
wave1.SetDroneText(true, isSimulation: false, simDelay: 0);
|
||||
wave2.StartWave();
|
||||
wave2.SetDroneText(false, isSimulation: false, simDelay: 0);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
IEnumerator LaunchView2()
|
||||
{
|
||||
wave1.StartWave();
|
||||
wave2.StartWave();
|
||||
wave1.showBothTextsAtOnce = true;
|
||||
wave1.wave2ref = wave2;
|
||||
wave1.ShowTextForBoth();
|
||||
yield return new WaitForSeconds(0.1f);
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/DroneTrigger.cs.meta
Normal file
11
Assets/Scripts/DroneTrigger.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0857b8d92647f6488cca6fef417806d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
146
Assets/Scripts/GameManager.cs
Normal file
146
Assets/Scripts/GameManager.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class GameManager : MonoBehaviour
|
||||
{
|
||||
public static GameManager Instance { get; private set; }
|
||||
|
||||
[Header("Îáåðè òèï ñèìóëÿö³¿")]
|
||||
public bool isSimulation = true;
|
||||
[Header("Âèä")]
|
||||
public bool isView2 = false;
|
||||
[Header("Ãåðîé")]
|
||||
public bool useDrone = false;
|
||||
[Header("Êàìåðè")]
|
||||
public Camera davidCamera;
|
||||
public Camera droneCamera;
|
||||
public Camera droneInnerCamera;
|
||||
public Camera mainCamera;
|
||||
[Header("Îá'ºêòè")]
|
||||
public GameObject david;
|
||||
public GameObject drone;
|
||||
|
||||
[HideInInspector] public double simV = 2000.0;
|
||||
[HideInInspector] public double simVDrone = 8000.0;
|
||||
[HideInInspector] public double view2Jitter = 0.0;
|
||||
|
||||
private bool _lastIsView2;
|
||||
private bool _lastUseDrone;
|
||||
private Vector3 _davidStartPos;
|
||||
private Vector3 _droneStartPos;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (Instance == null) Instance = this;
|
||||
else Destroy(gameObject);
|
||||
GenerateSimV();
|
||||
}
|
||||
|
||||
public void GenerateSimV()
|
||||
{
|
||||
simV = 500.0 + Random.Range(0f, 1000f);
|
||||
simVDrone = 2000.0 + Random.Range(0f, 2000f);
|
||||
view2Jitter = Random.Range(-5.0f, 5.0f);
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (david != null) _davidStartPos = david.transform.position;
|
||||
if (drone != null) _droneStartPos = drone.transform.position;
|
||||
_lastIsView2 = isView2;
|
||||
_lastUseDrone = useDrone;
|
||||
ApplySettings();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (_lastIsView2 != isView2 || _lastUseDrone != useDrone)
|
||||
{
|
||||
_lastIsView2 = isView2;
|
||||
_lastUseDrone = useDrone;
|
||||
ResetAll();
|
||||
}
|
||||
}
|
||||
|
||||
void ResetAll()
|
||||
{
|
||||
GenerateSimV();
|
||||
FindObjectOfType<HeroTrigger>()?.Reset();
|
||||
FindObjectOfType<DroneTrigger>()?.Reset();
|
||||
FindObjectOfType<RestartManager>()?.HideRestart();
|
||||
FindObjectOfType<RewindManager>()?.FullReset();
|
||||
|
||||
LightWave[] waves = FindObjectsOfType<LightWave>(true);
|
||||
foreach (var wave in waves)
|
||||
{
|
||||
wave.ResetSize();
|
||||
wave.ResetText();
|
||||
wave.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
if (david != null) david.transform.position = _davidStartPos;
|
||||
if (drone != null) drone.transform.position = _droneStartPos;
|
||||
|
||||
ApplySettings();
|
||||
|
||||
if (david != null && david.activeInHierarchy)
|
||||
{
|
||||
var hm = david.GetComponentInChildren<HeroMovement>();
|
||||
if (hm != null) hm.ResumeMoving();
|
||||
var anim = david.GetComponent<Animator>();
|
||||
if (anim != null)
|
||||
{
|
||||
anim.Rebind();
|
||||
anim.Play("FastRun", 0, 0f);
|
||||
anim.Update(0f);
|
||||
}
|
||||
}
|
||||
if (drone != null && drone.activeInHierarchy)
|
||||
{
|
||||
var dm = drone.GetComponentInChildren<DroneMovement>();
|
||||
if (dm != null) dm.ResumeMoving();
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
void OnValidate()
|
||||
{
|
||||
UnityEditor.EditorApplication.delayCall += () =>
|
||||
{
|
||||
if (this == null) return;
|
||||
ApplySettings();
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
void ApplySettings()
|
||||
{
|
||||
if (david != null) david.SetActive(!useDrone);
|
||||
if (drone != null) drone.SetActive(useDrone);
|
||||
|
||||
if (isView2)
|
||||
{
|
||||
if (mainCamera != null) mainCamera.enabled = true;
|
||||
if (davidCamera != null) davidCamera.enabled = false;
|
||||
if (droneCamera != null) droneCamera.enabled = false;
|
||||
if (droneInnerCamera != null) droneInnerCamera.enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mainCamera != null) mainCamera.enabled = false;
|
||||
if (useDrone)
|
||||
{
|
||||
if (droneCamera != null) droneCamera.enabled = true;
|
||||
if (droneInnerCamera != null) droneInnerCamera.enabled = true;
|
||||
if (davidCamera != null) davidCamera.enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (davidCamera != null) davidCamera.enabled = true;
|
||||
if (droneCamera != null) droneCamera.enabled = false;
|
||||
if (droneInnerCamera != null) droneInnerCamera.enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/GameManager.cs.meta
Normal file
11
Assets/Scripts/GameManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3968d894f5db4c942a4aba5d0e358007
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
18
Assets/Scripts/HeroMovement.cs
Normal file
18
Assets/Scripts/HeroMovement.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class HeroMovement : MonoBehaviour
|
||||
{
|
||||
public float speed = 5f;
|
||||
private bool _moving = true;
|
||||
|
||||
public void StopMoving() { _moving = false; }
|
||||
public void ResumeMoving() { _moving = true; }
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!_moving) return;
|
||||
transform.position += Vector3.forward * speed * Time.deltaTime;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/HeroMovement.cs.meta
Normal file
11
Assets/Scripts/HeroMovement.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec8eebfd822edc04da976040b29c5285
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
59
Assets/Scripts/HeroTrigger.cs
Normal file
59
Assets/Scripts/HeroTrigger.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class HeroTrigger : MonoBehaviour
|
||||
{
|
||||
public LightWave wave1;
|
||||
public LightWave wave2;
|
||||
public Animator animator;
|
||||
public HeroMovement heroMovement;
|
||||
private bool _fired = false;
|
||||
|
||||
public void Reset() { _fired = false; }
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (_fired) return;
|
||||
if (transform.position.z >= 0f)
|
||||
{
|
||||
_fired = true;
|
||||
heroMovement.StopMoving();
|
||||
bool isView2 = GameManager.Instance != null && GameManager.Instance.isView2;
|
||||
bool isSimulation = GameManager.Instance != null && GameManager.Instance.isSimulation;
|
||||
if (isView2)
|
||||
StartCoroutine(LaunchView2());
|
||||
else
|
||||
StartCoroutine(LaunchView1(isSimulation));
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator LaunchView1(bool isSimulation)
|
||||
{
|
||||
if (isSimulation)
|
||||
{
|
||||
wave1.StartWave();
|
||||
yield return new WaitForSeconds(0.5f);
|
||||
wave2.StartWave();
|
||||
yield return new WaitForSeconds(1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
wave1.StartWave();
|
||||
wave2.StartWave();
|
||||
yield return new WaitForSeconds(1f);
|
||||
}
|
||||
animator.SetTrigger("Fall");
|
||||
}
|
||||
|
||||
IEnumerator LaunchView2()
|
||||
{
|
||||
wave1.StartWave();
|
||||
wave2.StartWave();
|
||||
wave1.showBothTextsAtOnce = true;
|
||||
wave1.wave2ref = wave2;
|
||||
wave1.ShowTextForBoth();
|
||||
yield return new WaitForSeconds(0.1f);
|
||||
animator.SetTrigger("Fall");
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/HeroTrigger.cs.meta
Normal file
11
Assets/Scripts/HeroTrigger.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c97a008d970294a4bb82a052d33dd0cc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
204
Assets/Scripts/LightWave.cs
Normal file
204
Assets/Scripts/LightWave.cs
Normal file
@@ -0,0 +1,204 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
|
||||
public class LightWave : MonoBehaviour
|
||||
{
|
||||
public float growSpeed = 2f;
|
||||
public float maxMultiplier = 9f;
|
||||
public bool isFront = false;
|
||||
public Camera heroCamera;
|
||||
|
||||
public TextMeshProUGUI waveText;
|
||||
|
||||
[HideInInspector] public bool showBothTextsAtOnce = false;
|
||||
[HideInInspector] public LightWave wave2ref;
|
||||
|
||||
[HideInInspector] public float _eventTime;
|
||||
[HideInInspector] public bool _textSet = false;
|
||||
|
||||
private bool _running = false;
|
||||
private float _sizeMultiplier = 1f;
|
||||
private ParticleSystem _ps;
|
||||
private float _baseStartSize;
|
||||
|
||||
private const double SpeedOfLight = 299792458.0;
|
||||
private const double HeroSpeed = 10.0;
|
||||
private const double DroneSpeed = 40.0;
|
||||
private const double DistFront = 9.99;
|
||||
private const double DistBack = 9.57;
|
||||
private const double DistObserver = 20.0;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_ps = GetComponent<ParticleSystem>();
|
||||
var main = _ps.main;
|
||||
_baseStartSize = main.startSizeMultiplier;
|
||||
_ps.Stop();
|
||||
gameObject.SetActive(false);
|
||||
|
||||
if (waveText != null)
|
||||
waveText.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
public void StartWave()
|
||||
{
|
||||
gameObject.SetActive(true);
|
||||
_ps.Play();
|
||||
_running = true;
|
||||
_eventTime = Time.time;
|
||||
_sizeMultiplier = 1f;
|
||||
_textSet = false;
|
||||
showBothTextsAtOnce = false;
|
||||
wave2ref = null;
|
||||
|
||||
bool isDrone = GameManager.Instance != null && GameManager.Instance.useDrone;
|
||||
if (isDrone)
|
||||
{
|
||||
var main = _ps.main;
|
||||
main.startSizeMultiplier = _baseStartSize;
|
||||
return;
|
||||
}
|
||||
|
||||
bool isView2 = GameManager.Instance != null && GameManager.Instance.isView2;
|
||||
if (!isView2)
|
||||
ShowText(this);
|
||||
}
|
||||
|
||||
public void ShowTextForBoth()
|
||||
{
|
||||
ShowText(this);
|
||||
if (wave2ref != null)
|
||||
ShowText(wave2ref);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!_running) return;
|
||||
|
||||
bool isView2 = GameManager.Instance != null && GameManager.Instance.isView2;
|
||||
bool isDrone = GameManager.Instance != null && GameManager.Instance.useDrone;
|
||||
|
||||
if (!isFront && !isView2 && !isDrone)
|
||||
{
|
||||
_sizeMultiplier += growSpeed * Time.deltaTime;
|
||||
_sizeMultiplier = Mathf.Min(_sizeMultiplier, maxMultiplier);
|
||||
var main = _ps.main;
|
||||
main.startSizeMultiplier = _baseStartSize * _sizeMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
void ShowText(LightWave wave)
|
||||
{
|
||||
if (wave.waveText == null) return;
|
||||
|
||||
bool isSimulation = GameManager.Instance != null && GameManager.Instance.isSimulation;
|
||||
bool isView2 = GameManager.Instance != null && GameManager.Instance.isView2;
|
||||
string label = wave.isFront ? "Õâèëþ 1" : "Õâèëþ 2";
|
||||
|
||||
double jitter = isView2 && GameManager.Instance != null ? GameManager.Instance.view2Jitter : 0.0;
|
||||
if (isSimulation)
|
||||
{
|
||||
double simC = 5000.0;
|
||||
double simV = GameManager.Instance != null ? GameManager.Instance.simV : 2000.0;
|
||||
double dist = isView2 ? (DistObserver + jitter) : (wave.isFront ? DistFront : DistBack);
|
||||
double relSpeed = isView2 ? simC : (wave.isFront ? (simC + simV) : (simC - simV));
|
||||
double timeS = dist / relSpeed;
|
||||
wave.waveText.text = $"Çàô³êñóâàëè {label} ÷åðåç {timeS:F5} ñ";
|
||||
}
|
||||
else
|
||||
{
|
||||
double dist = isView2 ? (DistObserver + jitter) : (wave.isFront ? DistFront : DistBack);
|
||||
double relSpeed = isView2 ? SpeedOfLight : (wave.isFront ? (SpeedOfLight + HeroSpeed) : (SpeedOfLight - HeroSpeed));
|
||||
double timeNs = (dist / relSpeed) * 1e9;
|
||||
wave.waveText.text = $"Çàô³êñóâàëè {label} ÷åðåç {timeNs:F2} íñ";
|
||||
}
|
||||
|
||||
wave.waveText.gameObject.SetActive(true);
|
||||
wave._textSet = true;
|
||||
|
||||
if (!wave.isFront)
|
||||
{
|
||||
RestartManager rm = FindObjectOfType<RestartManager>();
|
||||
if (rm != null)
|
||||
rm.ShowRestart();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDroneText(bool front, bool isSimulation, float simDelay)
|
||||
{
|
||||
if (waveText == null) return;
|
||||
|
||||
bool isView2 = GameManager.Instance != null && GameManager.Instance.isView2;
|
||||
string label = front ? "Õâèëþ 1" : "Õâèëþ 2";
|
||||
|
||||
double droneJitter = isView2 && GameManager.Instance != null ? GameManager.Instance.view2Jitter : 0.0;
|
||||
if (isSimulation)
|
||||
{
|
||||
double simC = 5000.0;
|
||||
double simV = GameManager.Instance != null ? GameManager.Instance.simVDrone : 3000.0;
|
||||
double dist = isView2 ? (DistObserver + droneJitter) : (front ? DistFront : DistBack);
|
||||
double relSpeed = isView2 ? simC : (front ? (simC + simV) : (simC - simV));
|
||||
double timeS = dist / relSpeed;
|
||||
waveText.text = $"Çàô³êñóâàëè {label} ÷åðåç {timeS:F5} ñ";
|
||||
}
|
||||
else
|
||||
{
|
||||
double dist = isView2 ? (DistObserver + droneJitter) : (front ? DistFront : DistBack);
|
||||
double relSpeed;
|
||||
if (isView2)
|
||||
relSpeed = SpeedOfLight;
|
||||
else
|
||||
relSpeed = front ? (SpeedOfLight + DroneSpeed) : (SpeedOfLight - DroneSpeed);
|
||||
double timeNs = (dist / relSpeed) * 1e9;
|
||||
waveText.text = $"Çàô³êñóâàëè {label} ÷åðåç {timeNs:F2} íñ";
|
||||
}
|
||||
|
||||
waveText.gameObject.SetActive(true);
|
||||
_textSet = true;
|
||||
|
||||
if (!front)
|
||||
{
|
||||
RestartManager rm = FindObjectOfType<RestartManager>();
|
||||
if (rm != null)
|
||||
rm.ShowRestart();
|
||||
}
|
||||
}
|
||||
|
||||
bool IsAnyPartVisible(Camera cam, Vector3 center, float radius)
|
||||
{
|
||||
Vector3[] points =
|
||||
{
|
||||
center + Vector3.forward * radius,
|
||||
center + Vector3.back * radius,
|
||||
center + Vector3.left * radius,
|
||||
center + Vector3.right * radius,
|
||||
center + Vector3.up * radius,
|
||||
center + Vector3.down * radius
|
||||
};
|
||||
|
||||
foreach (var p in points)
|
||||
{
|
||||
Vector3 v = cam.WorldToViewportPoint(p);
|
||||
if (v.z > 0 && v.x >= 0 && v.x <= 1 && v.y >= 0 && v.y <= 1)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void ResetText()
|
||||
{
|
||||
_textSet = false;
|
||||
if (waveText != null)
|
||||
waveText.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
public void ResetSize()
|
||||
{
|
||||
_sizeMultiplier = 1f;
|
||||
var main = _ps.main;
|
||||
main.startSizeMultiplier = _baseStartSize;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/LightWave.cs.meta
Normal file
11
Assets/Scripts/LightWave.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b2fac9f18fd56554c9199b7c7077c033
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
33
Assets/Scripts/RestartManager.cs
Normal file
33
Assets/Scripts/RestartManager.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
public class RestartManager : MonoBehaviour
|
||||
{
|
||||
public GameObject restartButton;
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (restartButton != null)
|
||||
restartButton.SetActive(false);
|
||||
}
|
||||
|
||||
public void ShowRestart()
|
||||
{
|
||||
FindObjectOfType<RewindManager>()?.ShowSlider();
|
||||
if (restartButton != null)
|
||||
restartButton.SetActive(true);
|
||||
}
|
||||
|
||||
public void HideRestart()
|
||||
{
|
||||
if (restartButton != null)
|
||||
restartButton.SetActive(false);
|
||||
}
|
||||
|
||||
public void RestartSimulation()
|
||||
{
|
||||
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/RestartManager.cs.meta
Normal file
11
Assets/Scripts/RestartManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9cf39e3294a054840b308b54cd2ce697
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
228
Assets/Scripts/RewindManager.cs
Normal file
228
Assets/Scripts/RewindManager.cs
Normal file
@@ -0,0 +1,228 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class RewindManager : MonoBehaviour
|
||||
{
|
||||
[Header("Îá'ºêòè ñöåíè")]
|
||||
public GameObject david;
|
||||
public GameObject drone;
|
||||
public ParticleSystem wave1PS;
|
||||
public ParticleSystem wave2PS;
|
||||
|
||||
[Header("UI")]
|
||||
public Slider rewindSlider;
|
||||
|
||||
private bool _recording = false;
|
||||
private bool _rewinding = false;
|
||||
private bool _animating = false;
|
||||
|
||||
private Vector3 _davidStartPos;
|
||||
private Vector3 _droneStartPos;
|
||||
private Vector3 _davidFinalPos;
|
||||
private Vector3 _droneFinalPos;
|
||||
|
||||
private HeroMovement _heroMovement;
|
||||
private DroneMovement _droneMovement;
|
||||
private Animator _davidAnimator;
|
||||
|
||||
private int _stopFrameIndex = -1;
|
||||
|
||||
private struct FrameState
|
||||
{
|
||||
public float wave1Time;
|
||||
public float wave2Time;
|
||||
public bool wave1Active;
|
||||
public bool wave2Active;
|
||||
public int animStateHash;
|
||||
public float animNormalizedTime;
|
||||
}
|
||||
|
||||
private List<FrameState> _frames = new List<FrameState>();
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (david != null)
|
||||
{
|
||||
_davidStartPos = david.transform.position;
|
||||
_heroMovement = david.GetComponentInChildren<HeroMovement>();
|
||||
_davidAnimator = david.GetComponent<Animator>();
|
||||
}
|
||||
if (drone != null)
|
||||
{
|
||||
_droneStartPos = drone.transform.position;
|
||||
_droneMovement = drone.GetComponentInChildren<DroneMovement>();
|
||||
}
|
||||
|
||||
if (rewindSlider != null)
|
||||
{
|
||||
rewindSlider.gameObject.SetActive(false);
|
||||
rewindSlider.onValueChanged.AddListener(OnSliderChanged);
|
||||
}
|
||||
|
||||
_recording = true;
|
||||
}
|
||||
|
||||
public void ShowSlider()
|
||||
{
|
||||
_recording = false;
|
||||
_stopFrameIndex = _frames.Count - 1;
|
||||
|
||||
if (david != null) _davidFinalPos = david.transform.position;
|
||||
if (drone != null) _droneFinalPos = drone.transform.position;
|
||||
|
||||
if (rewindSlider != null)
|
||||
{
|
||||
rewindSlider.maxValue = _frames.Count - 1;
|
||||
rewindSlider.onValueChanged.RemoveListener(OnSliderChanged);
|
||||
rewindSlider.value = _frames.Count - 1;
|
||||
rewindSlider.onValueChanged.AddListener(OnSliderChanged);
|
||||
rewindSlider.gameObject.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!_recording || _rewinding) return;
|
||||
|
||||
FrameState frame = new FrameState();
|
||||
frame.wave1Active = wave1PS != null && wave1PS.gameObject.activeSelf;
|
||||
frame.wave2Active = wave2PS != null && wave2PS.gameObject.activeSelf;
|
||||
frame.wave1Time = frame.wave1Active ? wave1PS.time : 0f;
|
||||
frame.wave2Time = frame.wave2Active ? wave2PS.time : 0f;
|
||||
|
||||
if (_davidAnimator != null && david != null && david.activeInHierarchy)
|
||||
{
|
||||
AnimatorStateInfo info = _davidAnimator.GetCurrentAnimatorStateInfo(0);
|
||||
frame.animStateHash = info.fullPathHash;
|
||||
frame.animNormalizedTime = info.normalizedTime;
|
||||
}
|
||||
|
||||
_frames.Add(frame);
|
||||
}
|
||||
|
||||
void OnSliderChanged(float value)
|
||||
{
|
||||
if (_animating) return;
|
||||
if (_frames.Count == 0) return;
|
||||
|
||||
_rewinding = true;
|
||||
Time.timeScale = 0f;
|
||||
|
||||
int index = Mathf.RoundToInt(value);
|
||||
index = Mathf.Clamp(index, 0, _frames.Count - 1);
|
||||
|
||||
float t = _frames.Count > 1 ? (float)index / (_frames.Count - 1) : 1f;
|
||||
|
||||
if (david != null) david.transform.position = Vector3.Lerp(_davidStartPos, _davidFinalPos, t);
|
||||
if (drone != null) drone.transform.position = Vector3.Lerp(_droneStartPos, _droneFinalPos, t);
|
||||
|
||||
FrameState frame = _frames[index];
|
||||
|
||||
if (_davidAnimator != null && frame.animStateHash != 0 && david != null && david.activeInHierarchy)
|
||||
{
|
||||
_davidAnimator.Play(frame.animStateHash, 0, frame.animNormalizedTime);
|
||||
_davidAnimator.Update(0f);
|
||||
}
|
||||
|
||||
if (wave1PS != null && frame.wave1Active)
|
||||
{
|
||||
wave1PS.gameObject.SetActive(true);
|
||||
wave1PS.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
|
||||
wave1PS.Simulate(frame.wave1Time, true, true);
|
||||
}
|
||||
|
||||
if (wave2PS != null && frame.wave2Active)
|
||||
{
|
||||
wave2PS.gameObject.SetActive(true);
|
||||
wave2PS.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
|
||||
wave2PS.Simulate(frame.wave2Time, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSliderReleased(float savedValue)
|
||||
{
|
||||
if (_animating) return;
|
||||
|
||||
_animating = true;
|
||||
_rewinding = false;
|
||||
Time.timeScale = 1f;
|
||||
|
||||
int index = Mathf.RoundToInt(savedValue);
|
||||
index = Mathf.Clamp(index, 0, _frames.Count - 1);
|
||||
|
||||
float animateTo = rewindSlider.maxValue;
|
||||
|
||||
if (_stopFrameIndex >= 0 && index < _stopFrameIndex)
|
||||
{
|
||||
GameManager.Instance?.GenerateSimV();
|
||||
if (_heroMovement != null) _heroMovement.ResumeMoving();
|
||||
if (_droneMovement != null) _droneMovement.ResumeMoving();
|
||||
FindObjectOfType<DroneTrigger>()?.Reset();
|
||||
FindObjectOfType<HeroTrigger>()?.Reset();
|
||||
FindObjectOfType<RestartManager>()?.HideRestart();
|
||||
_stopFrameIndex = -1;
|
||||
|
||||
if (_davidAnimator != null && david != null && david.activeInHierarchy)
|
||||
{
|
||||
_davidAnimator.Rebind();
|
||||
_davidAnimator.Play("FastRun", 0, 0f);
|
||||
_davidAnimator.Update(0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (wave1PS != null && !_frames[index].wave1Active)
|
||||
{
|
||||
wave1PS.Stop();
|
||||
wave1PS.gameObject.SetActive(false);
|
||||
wave1PS.GetComponent<LightWave>()?.ResetText();
|
||||
}
|
||||
if (wave2PS != null && !_frames[index].wave2Active)
|
||||
{
|
||||
wave2PS.Stop();
|
||||
wave2PS.gameObject.SetActive(false);
|
||||
wave2PS.GetComponent<LightWave>()?.ResetText();
|
||||
}
|
||||
|
||||
if (wave1PS != null && wave1PS.gameObject.activeSelf) wave1PS.Play();
|
||||
if (wave2PS != null && wave2PS.gameObject.activeSelf) wave2PS.Play();
|
||||
|
||||
StartCoroutine(AnimateSlider(savedValue, animateTo));
|
||||
}
|
||||
|
||||
public void FullReset()
|
||||
{
|
||||
StopAllCoroutines();
|
||||
Time.timeScale = 1f;
|
||||
_frames.Clear();
|
||||
_stopFrameIndex = -1;
|
||||
_rewinding = false;
|
||||
_animating = false;
|
||||
_recording = true;
|
||||
|
||||
if (rewindSlider != null)
|
||||
{
|
||||
rewindSlider.gameObject.SetActive(false);
|
||||
rewindSlider.onValueChanged.RemoveListener(OnSliderChanged);
|
||||
rewindSlider.value = 0f;
|
||||
rewindSlider.onValueChanged.AddListener(OnSliderChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator AnimateSlider(float from, float to)
|
||||
{
|
||||
rewindSlider.onValueChanged.RemoveListener(OnSliderChanged);
|
||||
rewindSlider.maxValue = to;
|
||||
float current = from;
|
||||
while (current < to)
|
||||
{
|
||||
current += 60f * Time.unscaledDeltaTime;
|
||||
current = Mathf.Min(current, to);
|
||||
rewindSlider.value = current;
|
||||
yield return null;
|
||||
}
|
||||
rewindSlider.onValueChanged.AddListener(OnSliderChanged);
|
||||
_animating = false;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/RewindManager.cs.meta
Normal file
11
Assets/Scripts/RewindManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50ca7b84aa023b442a5a2a0909282d07
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
28
Assets/Scripts/SliderReleaseHandler.cs
Normal file
28
Assets/Scripts/SliderReleaseHandler.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class SliderReleaseHandler : MonoBehaviour, IPointerUpHandler, IDragHandler
|
||||
{
|
||||
public RewindManager rewindManager;
|
||||
private Slider _slider;
|
||||
private float _lastDragValue;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_slider = GetComponent<Slider>();
|
||||
_lastDragValue = _slider.value;
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData eventData)
|
||||
{
|
||||
_lastDragValue = _slider.value;
|
||||
}
|
||||
|
||||
public void OnPointerUp(PointerEventData eventData)
|
||||
{
|
||||
rewindManager.OnSliderReleased(_lastDragValue);
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/SliderReleaseHandler.cs.meta
Normal file
11
Assets/Scripts/SliderReleaseHandler.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe4934f350ebb4945b6806938c59bf6e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user