Files
ScienceLab.FrictionForce/Assets/Scripts/SlidingObject.cs
2026-05-29 18:30:19 +03:00

445 lines
15 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SlidingObject : MonoBehaviour
{
[SerializeField] private ObjectInfoDisplay _display;
private Rigidbody _rb;
private string _currentSurface = "";
private bool _isMoving = false;
private bool _shownStatic = false;
private bool _wasOnShelf = false;
private bool _didSlide = false;
private string _lastShownName = "";
private float _lastMu = 0f;
private FrictionType _lastFrictionType;
private static readonly Dictionary<string, Dictionary<string, (float stat, float slide, float roll)>> _mu = new()
{
{
"Мармур",
new()
{
{ "Дерев'яна поверхня", (0.50f, 0.35f, -1) },
{ "Металева поверхня", (0.40f, 0.28f, -1) },
{ "Крижана поверхня", (0.10f, 0.06f, -1) },
{ "Гумова поверхня", (0.80f, 0.60f, -1) }
}
},
{
"Ядро",
new()
{
{ "Дерев'яна поверхня", (0.49f, 0.32f, 0.10f) },
{ "Металева поверхня", (0.23f, 0.15f, 0.08f) },
{ "Крижана поверхня", (0.05f, 0.03f, 0.02f) },
{ "Гумова поверхня", (0.65f, 0.50f, 0.15f) }
}
},
{
"Колесо гармати",
new()
{
{ "Дерев'яна поверхня", (0.49f, 0.32f, 0.05f) },
{ "Металева поверхня", (0.23f, 0.15f, 0.04f) },
{ "Крижана поверхня", (0.08f, 0.05f, 0.01f) },
{ "Гумова поверхня", (0.75f, 0.58f, 0.08f) }
}
},
{
"Надутий футбольний м'яч",
new()
{
{ "Дерев'яна поверхня", (0.65f, 0.50f, 0.04f) },
{ "Металева поверхня", (0.50f, 0.38f, 0.03f) },
{ "Крижана поверхня", (0.10f, 0.07f, 0.015f) },
{ "Гумова поверхня", (0.90f, 0.75f, 0.07f) }
}
},
{
"Здутий футбольний м'яч",
new()
{
{ "Дерев'яна поверхня", (0.80f, 0.65f, 0.09f) },
{ "Металева поверхня", (0.65f, 0.50f, 0.07f) },
{ "Крижана поверхня", (0.18f, 0.13f, 0.04f) },
{ "Гумова поверхня", (1.05f, 0.88f, 0.12f) }
}
},
{
"Гумова качечка",
new()
{
{ "Дерев'яна поверхня", (0.90f, 0.70f, -1) },
{ "Металева поверхня", (0.70f, 0.55f, -1) },
{ "Крижана поверхня", (0.20f, 0.15f, -1) },
{ "Гумова поверхня", (1.10f, 0.90f, -1) }
}
},
{
"Енциклопедія",
new()
{
{ "Дерев'яна поверхня", (0.50f, 0.35f, -1) },
{ "Металева поверхня", (0.35f, 0.25f, -1) },
{ "Крижана поверхня", (0.08f, 0.05f, -1) },
{ "Гумова поверхня", (0.80f, 0.65f, -1) }
}
},
{
"Авокадо",
new()
{
{ "Дерев'яна поверхня", (0.55f, 0.40f, -1) },
{ "Металева поверхня", (0.40f, 0.30f, -1) },
{ "Крижана поверхня", (0.10f, 0.07f, -1) },
{ "Гумова поверхня", (0.85f, 0.68f, -1) }
}
},
{
"Баскетбольний м'яч",
new()
{
{ "Дерев'яна поверхня", (0.70f, 0.55f, 0.05f) },
{ "Металева поверхня", (0.55f, 0.40f, 0.04f) },
{ "Крижана поверхня", (0.15f, 0.10f, 0.02f) },
{ "Гумова поверхня", (1.00f, 0.85f, 0.08f) }
}
},
{
"Стара шина",
new()
{
{ "Дерев'яна поверхня", (0.90f, 0.70f, 0.08f) },
{ "Металева поверхня", (0.70f, 0.55f, 0.06f) },
{ "Крижана поверхня", (0.18f, 0.12f, 0.02f) },
{ "Гумова поверхня", (1.10f, 0.90f, 0.10f) }
}
},
{
"Дерев'яна дошка",
new()
{
{ "Дерев'яна поверхня", (0.62f, 0.48f, -1) },
{ "Металева поверхня", (0.50f, 0.35f, -1) },
{ "Крижана поверхня", (0.08f, 0.05f, -1) },
{ "Гумова поверхня", (0.75f, 0.60f, -1) }
}
},
{
"Пластикова дошка",
new()
{
{ "Дерев'яна поверхня", (0.40f, 0.28f, -1) },
{ "Металева поверхня", (0.35f, 0.25f, -1) },
{ "Крижана поверхня", (0.06f, 0.04f, -1) },
{ "Гумова поверхня", (0.68f, 0.52f, -1) }
}
},
{
"Сніжок",
new()
{
{ "Дерев'яна поверхня", (0.15f, 0.10f, -1) },
{ "Металева поверхня", (0.10f, 0.07f, -1) },
{ "Крижана поверхня", (0.05f, 0.03f, -1) },
{ "Гумова поверхня", (0.35f, 0.25f, -1) }
}
},
{
"Лід",
new()
{
{ "Дерев'яна поверхня", (0.08f, 0.05f, -1) },
{ "Металева поверхня", (0.06f, 0.04f, -1) },
{ "Крижана поверхня", (0.03f, 0.02f, -1) },
{ "Гумова поверхня", (0.25f, 0.18f, -1) }
}
},
{
"Скло",
new()
{
{ "Дерев'яна поверхня", (0.35f, 0.25f, -1) },
{ "Металева поверхня", (0.56f, 0.40f, -1) },
{ "Крижана поверхня", (0.06f, 0.04f, -1) },
{ "Гумова поверхня", (0.70f, 0.55f, -1) }
}
},
{
"Монета",
new()
{
{ "Дерев'яна поверхня", (0.44f, 0.30f, 0.05f) },
{ "Металева поверхня", (0.57f, 0.44f, 0.04f) },
{ "Крижана поверхня", (0.05f, 0.03f, 0.01f) },
{ "Гумова поверхня", (0.65f, 0.50f, 0.08f) }
}
},
{
"Сталь",
new()
{
{ "Дерев'яна поверхня", (0.50f, 0.35f, -1) },
{ "Металева поверхня", (0.74f, 0.57f, -1) },
{ "Крижана поверхня", (0.06f, 0.04f, -1) },
{ "Гумова поверхня", (0.65f, 0.50f, -1) }
}
},
{
"Мідь",
new()
{
{ "Дерев'яна поверхня", (0.50f, 0.36f, -1) },
{ "Металева поверхня", (0.53f, 0.36f, -1) },
{ "Крижана поверхня", (0.06f, 0.04f, -1) },
{ "Гумова поверхня", (0.70f, 0.55f, -1) }
}
},
{
"Алюміній",
new()
{
{ "Дерев'яна поверхня", (0.50f, 0.35f, -1) },
{ "Металева поверхня", (0.61f, 0.47f, -1) },
{ "Крижана поверхня", (0.06f, 0.04f, -1) },
{ "Гумова поверхня", (0.65f, 0.50f, -1) }
}
},
{
"Чавун",
new()
{
{ "Дерев'яна поверхня", (0.49f, 0.35f, -1) },
{ "Металева поверхня", (0.23f, 0.15f, -1) },
{ "Крижана поверхня", (0.06f, 0.04f, -1) },
{ "Гумова поверхня", (0.70f, 0.55f, -1) }
}
},
{
"Ножиці",
new()
{
{ "Дерев'яна поверхня", (0.50f, 0.35f, -1) },
{ "Металева поверхня", (0.74f, 0.57f, -1) },
{ "Крижана поверхня", (0.06f, 0.04f, -1) },
{ "Гумова поверхня", (0.65f, 0.50f, -1) }
}
},
{
"Скальпель",
new()
{
{ "Дерев'яна поверхня", (0.40f, 0.28f, -1) },
{ "Металева поверхня", (0.74f, 0.57f, -1) },
{ "Крижана поверхня", (0.05f, 0.03f, -1) },
{ "Гумова поверхня", (0.60f, 0.45f, -1) }
}
},
{
"Лічі",
new()
{
{ "Дерев'яна поверхня", (0.55f, 0.40f, -1) },
{ "Металева поверхня", (0.40f, 0.30f, -1) },
{ "Крижана поверхня", (0.08f, 0.06f, -1) },
{ "Гумова поверхня", (0.80f, 0.65f, -1) }
}
},
{
"Гумовий м'яч",
new()
{
{ "Дерев'яна поверхня", (0.90f, 0.70f, 0.05f) },
{ "Металева поверхня", (0.70f, 0.55f, 0.04f) },
{ "Крижана поверхня", (0.18f, 0.12f, 0.02f) },
{ "Гумова поверхня", (1.10f, 0.90f, 0.08f) }
}
},
{
"Асфальт",
new()
{
{ "Дерев'яна поверхня", (0.62f, 0.48f, -1) },
{ "Металева поверхня", (0.50f, 0.35f, -1) },
{ "Крижана поверхня", (0.15f, 0.10f, -1) },
{ "Гумова поверхня", (0.90f, 0.75f, -1) }
}
},
{
"Каміння з мохом",
new()
{
{ "Дерев'яна поверхня", (0.55f, 0.40f, -1) },
{ "Металева поверхня", (0.45f, 0.33f, -1) },
{ "Крижана поверхня", (0.12f, 0.08f, -1) },
{ "Гумова поверхня", (0.80f, 0.65f, -1) }
}
},
{
"Цегла",
new()
{
{ "Дерев'яна поверхня", (0.62f, 0.48f, -1) },
{ "Металева поверхня", (0.50f, 0.36f, -1) },
{ "Крижана поверхня", (0.12f, 0.08f, -1) },
{ "Гумова поверхня", (0.85f, 0.70f, -1) }
}
},
{
"Скляна банка",
new()
{
{ "Дерев'яна поверхня", (0.35f, 0.25f, -1) },
{ "Металева поверхня", (0.56f, 0.40f, -1) },
{ "Крижана поверхня", (0.06f, 0.04f, -1) },
{ "Гумова поверхня", (0.68f, 0.52f, -1) }
}
},
{
"Лоток",
new()
{
{ "Дерев'яна поверхня", (0.50f, 0.35f, -1) },
{ "Металева поверхня", (0.74f, 0.57f, -1) },
{ "Крижана поверхня", (0.05f, 0.03f, -1) },
{ "Гумова поверхня", (0.60f, 0.45f, -1) }
}
},
{
"Блокнот",
new()
{
{ "Дерев'яна поверхня", (0.50f, 0.35f, -1) },
{ "Металева поверхня", (0.35f, 0.25f, -1) },
{ "Крижана поверхня", (0.08f, 0.05f, -1) },
{ "Гумова поверхня", (0.75f, 0.58f, -1) }
}
},
{
"Хірургічна пилка",
new()
{
{ "Дерев'яна поверхня", (0.40f, 0.28f, -1) },
{ "Металева поверхня", (0.74f, 0.57f, -1) },
{ "Крижана поверхня", (0.05f, 0.03f, -1) },
{ "Гумова поверхня", (0.60f, 0.45f, -1) }
}
},
};
private void Awake()
{
_rb = GetComponent<Rigidbody>();
_didSlide = false;
}
private void OnCollisionEnter(Collision collision)
{
string surface = GetSurfaceName(collision.gameObject);
if (surface != "")
{
_wasOnShelf = true;
_currentSurface = surface;
_isMoving = false;
_shownStatic = false;
return;
}
if (collision.gameObject.CompareTag("Floor") && _wasOnShelf && _didSlide)
{
_wasOnShelf = false;
_didSlide = false;
float speed = _rb.velocity.magnitude;
ObjectName objName = GetComponent<ObjectName>();
string name = objName != null ? objName.ukrainianName : gameObject.name;
StartCoroutine(ShowFallAfterSlide(name, speed));
_currentSurface = "";
}
else if (collision.gameObject.CompareTag("Floor"))
{
_wasOnShelf = false;
_didSlide = false;
}
}
private void OnCollisionExit(Collision collision)
{
string surface = GetSurfaceName(collision.gameObject);
if (surface == "") return;
_currentSurface = "";
_isMoving = false;
_shownStatic = false;
}
private void Update()
{
if (_currentSurface == "" || _display == null || _rb == null) return;
ObjectName objName = GetComponent<ObjectName>();
if (objName == null) return;
string rawName = objName.ukrainianName;
string name = _mu.ContainsKey(rawName)
? rawName
: rawName.Contains("Енциклопедія") ? "Енциклопедія" : rawName;
if (!_mu.TryGetValue(name, out var surfaces)) return;
if (!surfaces.TryGetValue(_currentSurface, out var mu)) return;
bool movingNow = _rb.velocity.magnitude > 0.05f;
if (!movingNow && !_shownStatic)
{
_shownStatic = true;
_isMoving = false;
_lastShownName = name;
_lastMu = mu.stat;
_lastFrictionType = FrictionType.Статичне;
_display.ShowSlide(name, _currentSurface, mu.stat, FrictionType.Статичне);
}
else if (movingNow && !_isMoving)
{
_isMoving = true;
_shownStatic = false;
StartCoroutine(ShowAfterDelay(name, mu));
}
}
private IEnumerator ShowAfterDelay(string name, (float stat, float slide, float roll) mu)
{
yield return new WaitForSeconds(0.3f);
if (_rb == null || _currentSurface == "") yield break;
float linearSpeed = _rb.velocity.magnitude;
float angularSpeed = _rb.angularVelocity.magnitude;
bool isRolling = angularSpeed > 0.5f && linearSpeed > 0.05f;
float shownMu;
FrictionType shownType;
if (isRolling && mu.roll >= 0f)
{
shownMu = mu.roll;
shownType = FrictionType.Кочення;
}
else if (isRolling && mu.roll < 0f)
{
shownMu = mu.slide;
shownType = FrictionType.Кочення;
}
else
{
shownMu = mu.slide;
shownType = FrictionType.Ковзання;
}
if (_lastFrictionType == shownType && _lastMu == shownMu) yield break;
_lastShownName = name;
_lastMu = shownMu;
_lastFrictionType = shownType;
_didSlide = true;
_display.ShowSlide(name, _currentSurface, shownMu, shownType);
GameData.AddFriction(name, _currentSurface, shownMu, shownType);
}
private IEnumerator ShowFallAfterSlide(string name, float speed)
{
yield return new WaitForSeconds(_display.displayTime + _display.fadeTime);
_display.ShowFall(name, speed);
}
private string GetSurfaceName(GameObject obj)
{
ObjectName objName = obj.GetComponent<ObjectName>();
if (objName == null)
objName = obj.GetComponentInParent<ObjectName>();
if (objName != null)
return objName.description;
return "";
}
}