first commit

This commit is contained in:
2026-04-07 03:14:32 +03:00
commit b3992fec6b
1026 changed files with 366769 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!134 &13400000
PhysicMaterial:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Ball
dynamicFriction: 0.6
staticFriction: 0.6
bounciness: 0
frictionCombine: 3
bounceCombine: 1

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1e3e49e7b8690b24f8e060e1f8f3f2b8
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 13400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CursorCustom : MonoBehaviour
{
[SerializeField] private Texture2D _cursorTexture;
[SerializeField] private Vector2 _hotspot = Vector2.zero;
private void Start()
{
Cursor.SetCursor(_cursorTexture, _hotspot, CursorMode.Auto);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ea6af50377e1dac498dd8c9337abf6bf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,146 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DraggableObject : MonoBehaviour
{
[HideInInspector] public float mass = 1f;
[HideInInspector] public bool isHeavy = false;
[HideInInspector] public Transform priorityTarget = null;
public Vector3 startPosition { get; private set; }
public Quaternion startRotation { get; private set; }
private Vector3 _mousePosition;
private Vector3 _mouseCameraPos;
private Vector3 _initialPosition;
private Rigidbody _rb;
private Camera _camera;
private Transform _scaleTarget;
private float _lerpPosition;
[HideInInspector] public bool isDragging;
[SerializeField] private float _minY = 0.2f;
[SerializeField] private float _maxDistanceFromStart = 30f;
private void Awake()
{
_rb = GetComponent<Rigidbody>();
}
private void Start()
{
_camera = Camera.main;
_rb.isKinematic = true;
startPosition = transform.position;
startRotation = transform.rotation;
}
private Vector3 GetMousePos()
{
return _camera != null ? _camera.WorldToScreenPoint(transform.position) : Vector3.zero;
}
private Transform GetNearestTargetToCursor()
{
if (priorityTarget != null && priorityTarget.gameObject.activeInHierarchy)
return priorityTarget;
var targets = new List<GameObject>();
targets.AddRange(GameObject.FindGameObjectsWithTag("ScaleTarget"));
targets.AddRange(GameObject.FindGameObjectsWithTag("MainScale"));
Transform nearest = null;
float minDist = float.MaxValue;
foreach (var t in targets)
{
Vector3 screenPos = _camera.WorldToScreenPoint(t.transform.position);
float d = Vector2.Distance(
new Vector2(Input.mousePosition.x, Input.mousePosition.y),
new Vector2(screenPos.x, screenPos.y));
if (d < minDist) { minDist = d; nearest = t.transform; }
}
return nearest;
}
private void OnMouseDown()
{
_rb.isKinematic = false;
_rb.useGravity = false;
_rb.velocity = Vector3.zero;
_scaleTarget = GetNearestTargetToCursor();
_initialPosition = transform.position;
_mousePosition = Input.mousePosition - GetMousePos();
isDragging = true;
}
private void Update()
{
if (!isDragging || _camera == null) return;
_rb.angularVelocity = Vector3.zero;
_mouseCameraPos = _camera.ScreenToWorldPoint(Input.mousePosition - _mousePosition);
float targetZ = _scaleTarget != null ? _scaleTarget.position.z : _initialPosition.z;
_lerpPosition = _scaleTarget != null
? Mathf.InverseLerp(_initialPosition.x, _scaleTarget.position.x, _mouseCameraPos.x)
: 0f;
transform.position = new Vector3(
_mouseCameraPos.x,
Mathf.Max(_mouseCameraPos.y, _minY),
Mathf.Lerp(_initialPosition.z, targetZ, _lerpPosition)
);
if (Input.GetMouseButtonUp(0))
{
isDragging = false;
_rb.useGravity = true;
_rb.isKinematic = false;
}
}
private void FixedUpdate()
{
if (isDragging) return;
if (Vector3.Distance(transform.position, startPosition) > _maxDistanceFromStart)
ResetToStart();
}
public void ResetToStart()
{
_rb.velocity = Vector3.zero;
_rb.angularVelocity = Vector3.zero;
_rb.isKinematic = true;
transform.position = startPosition;
transform.rotation = startRotation;
isDragging = false;
}
private void OnTriggerEnter(Collider other)
{
if (isDragging) return;
if (!other.CompareTag("ScalePan")) return;
StartCoroutine(SnapToPan(other.transform));
}
private IEnumerator SnapToPan(Transform pan)
{
_rb.isKinematic = true;
_rb.useGravity = false;
Vector3 targetPos = pan.position + Vector3.up * 0.1f;
float t = 0f;
Vector3 startPos = transform.position;
while (t < 1f)
{
t += Time.deltaTime * 5f;
transform.position = Vector3.Lerp(startPos, targetPos, t);
yield return null;
}
_rb.isKinematic = false;
_rb.useGravity = true;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2355647c3dcd1024db76db0ee01add9a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,112 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class MainScaleZone : MonoBehaviour
{
[SerializeField] private GameObject _mainScaleObject;
[SerializeField] private Collider _mainScaleTrigger;
[SerializeField] private TextMeshProUGUI _resultText;
[SerializeField] private float _showResultTime = 2f;
private bool _isChecking = false;
private bool _canCheck = false;
private void Start()
{
_mainScaleObject.SetActive(false);
_resultText.gameObject.SetActive(false);
SetTag(false);
}
private void Update()
{
if (Input.GetMouseButtonDown(1))
{
if (_mainScaleObject.activeSelf)
{
_mainScaleObject.SetActive(false);
SetTag(false);
SetPriorityForAllBalls(null);
_canCheck = false;
}
else
{
_mainScaleObject.SetActive(true);
SetTag(true);
SetPriorityForAllBalls(_mainScaleTrigger.transform);
_canCheck = false;
StartCoroutine(EnableCheckDelay());
}
}
if (!_mainScaleObject.activeSelf || _isChecking || !_canCheck) return;
Collider[] cols = Physics.OverlapSphere(
_mainScaleTrigger.bounds.center,
_mainScaleTrigger.bounds.extents.magnitude
);
foreach (var col in cols)
{
DraggableObject ball = col.GetComponent<DraggableObject>();
if (ball == null) continue;
if (ball.isDragging) continue;
Rigidbody rb = col.GetComponent<Rigidbody>();
if (rb != null && rb.velocity.magnitude > 0.1f) continue;
_isChecking = true;
SetTag(false);
if (ball.isHeavy)
StartCoroutine(ShowResultAndRestart("³ðíî!"));
else
StartCoroutine(ShowResultAndContinue("Ñïðîáóé ùå"));
break;
}
}
private void SetPriorityForAllBalls(Transform target)
{
DraggableObject[] balls = FindObjectsOfType<DraggableObject>();
foreach (var ball in balls)
ball.priorityTarget = target;
}
private IEnumerator EnableCheckDelay()
{
yield return new WaitForSeconds(2f);
_canCheck = true;
}
private IEnumerator ShowResultAndRestart(string text)
{
NewScaleZone scaleZone = FindObjectOfType<NewScaleZone>();
scaleZone?.ShowSuccess();
_resultText.text = text;
_resultText.gameObject.SetActive(true);
yield return new WaitForSeconds(_showResultTime);
_mainScaleObject.SetActive(false);
_resultText.gameObject.SetActive(false);
SetPriorityForAllBalls(null);
FindObjectOfType<WeighingManager>()?.FullRestart();
scaleZone?.RestartAttempts();
_isChecking = false;
}
private IEnumerator ShowResultAndContinue(string text)
{
_resultText.text = text;
_resultText.gameObject.SetActive(true);
yield return new WaitForSeconds(_showResultTime);
_mainScaleObject.SetActive(false);
_resultText.gameObject.SetActive(false);
SetPriorityForAllBalls(null);
FindObjectOfType<WeighingManager>()?.ResetAllBalls();
FindObjectOfType<NewScaleZone>()?.RegisterAttempt();
_isChecking = false;
}
private void SetTag(bool active)
{
if (_mainScaleTrigger != null)
_mainScaleTrigger.gameObject.tag = active ? "MainScale" : "Untagged";
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0da993b310702744097f97f6222567ad
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,161 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class NewScaleZone : MonoBehaviour
{
[Header("Scale Parts")]
[SerializeField] private Transform _chainsOriginLeft;
[SerializeField] private Transform _chainsOriginRight;
[SerializeField] private Transform _beam;
[Header("Zones")]
[SerializeField] private Collider _leftZoneCollider;
[SerializeField] private Collider _rightZoneCollider;
[Header("Button")]
[SerializeField] private Button _startButton;
[SerializeField] private Sprite _spriteStart;
[SerializeField] private Sprite _spriteInProgress;
[Header("UI")]
[SerializeField] private TMPro.TextMeshProUGUI _attemptText;
[Header("Settings")]
[SerializeField] private float _tiltSpeed = 1f;
[SerializeField] private float _maxTiltAngle = 15f;
[SerializeField] private float _maxChainOffset = 0.2f;
[SerializeField] private float _showResultTime = 1.5f;
private int _attempt = 1;
private Vector3 _beamStartRot;
private Vector3 _leftChainStartPos;
private Vector3 _rightChainStartPos;
private bool _isWeighing = false;
public int Attempt => _attempt;
private void Start()
{
_beamStartRot = _beam.localEulerAngles;
_leftChainStartPos = _chainsOriginLeft.localPosition;
_rightChainStartPos = _chainsOriginRight.localPosition;
_startButton.onClick.AddListener(OnStartPressed);
UpdateAttemptText();
}
private float GetMassInZone(Collider zone)
{
Collider[] colliders = Physics.OverlapBox(
zone.bounds.center,
zone.bounds.extents,
Quaternion.identity
);
float total = 0f;
foreach (var col in colliders)
{
if (col.gameObject == zone.gameObject) continue;
Rigidbody rb = col.GetComponent<Rigidbody>();
if (rb != null) total += rb.mass;
}
return total;
}
private void OnStartPressed()
{
if (_isWeighing) return;
StartCoroutine(WeighRoutine());
}
private IEnumerator WeighRoutine()
{
_isWeighing = true;
_startButton.image.sprite = _spriteInProgress;
float leftMass = GetMassInZone(_leftZoneCollider);
float rightMass = GetMassInZone(_rightZoneCollider);
float diff = rightMass - leftMass;
float normalized = Mathf.Clamp(diff / 2f, -1f, 1f);
float targetAngle = -normalized * _maxTiltAngle;
float elapsed = 0f;
float duration = 1.5f;
while (elapsed < duration)
{
elapsed += Time.deltaTime * _tiltSpeed;
float t = Mathf.Clamp01(elapsed / duration);
float angle = Mathf.Lerp(0f, targetAngle, t);
_beam.localEulerAngles = new Vector3(
_beamStartRot.x, _beamStartRot.y, _beamStartRot.z + angle);
float offset = normalized * _maxChainOffset * t;
_chainsOriginLeft.localPosition = new Vector3(
_leftChainStartPos.x, _leftChainStartPos.y - offset, _leftChainStartPos.z);
_chainsOriginRight.localPosition = new Vector3(
_rightChainStartPos.x, _rightChainStartPos.y + offset, _rightChainStartPos.z);
yield return null;
}
yield return new WaitForSeconds(_showResultTime);
elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime * _tiltSpeed;
float t = Mathf.Clamp01(elapsed / duration);
float angle = Mathf.Lerp(targetAngle, 0f, t);
_beam.localEulerAngles = new Vector3(
_beamStartRot.x, _beamStartRot.y, _beamStartRot.z + angle);
float offset = normalized * _maxChainOffset * (1f - t);
_chainsOriginLeft.localPosition = new Vector3(
_leftChainStartPos.x, _leftChainStartPos.y - offset, _leftChainStartPos.z);
_chainsOriginRight.localPosition = new Vector3(
_rightChainStartPos.x, _rightChainStartPos.y + offset, _rightChainStartPos.z);
yield return null;
}
_beam.localEulerAngles = _beamStartRot;
_chainsOriginLeft.localPosition = _leftChainStartPos;
_chainsOriginRight.localPosition = _rightChainStartPos;
WeighingManager manager = FindObjectOfType<WeighingManager>();
if (manager != null) manager.ResetAllBalls();
_attempt++;
UpdateAttemptText();
_startButton.image.sprite = _spriteStart;
_isWeighing = false;
}
private void UpdateAttemptText()
{
if (_attemptText != null)
_attemptText.text = "Ñïðîáà " + _attempt;
}
public void ShowSuccess()
{
int count = _attempt <= 1 ? 1 : _attempt - 1;
if (_attemptText != null)
_attemptText.text = "Ïðîéäåíî ç " + count + " ñïðîá!";
}
public void RegisterAttempt()
{
if (_isWeighing) return;
_attempt++;
UpdateAttemptText();
}
public void RestartAttempts()
{
_attempt = 1;
UpdateAttemptText();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2dda24731fdf5b242b6dcd09c60a7e1a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,42 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WeighingManager : MonoBehaviour
{
[SerializeField] private DraggableObject[] _balls;
[SerializeField] private float _normalMass = 1f;
[SerializeField] private float _heavyMass = 1.5f;
private void Start()
{
AssignMasses();
}
public void AssignMasses()
{
foreach (var ball in _balls)
{
ball.mass = _normalMass;
ball.isHeavy = false;
ball.GetComponent<Rigidbody>().mass = _normalMass;
}
int heavyIndex = Random.Range(0, _balls.Length);
_balls[heavyIndex].mass = _heavyMass;
_balls[heavyIndex].isHeavy = true;
_balls[heavyIndex].GetComponent<Rigidbody>().mass = _heavyMass;
}
public void ResetAllBalls()
{
foreach (var ball in _balls)
ball.ResetToStart();
}
public void FullRestart()
{
foreach (var ball in _balls)
ball.ResetToStart();
AssignMasses();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 61ea5660dd2544b4fbe62b90469e654e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: