Добавил скрипты для более реалистичной физики, но они шляпа полная.
This commit is contained in:
parent
f9eb14868d
commit
5f25a8eab4
@ -25,6 +25,9 @@ Material:
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _METALLICSPECGLOSSMAP
|
||||
- _NORMALMAP
|
||||
- _PARALLAXMAP
|
||||
- _SPECGLOSSMAP
|
||||
- _SPECULAR_SETUP
|
||||
m_InvalidKeywords: []
|
||||
@ -65,7 +68,7 @@ Material:
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Texture: {fileID: 2800000, guid: a9a0a885c2eede34587e12cd1414003c, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
|
||||
@ -25,6 +25,9 @@ Material:
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _METALLICSPECGLOSSMAP
|
||||
- _NORMALMAP
|
||||
- _PARALLAXMAP
|
||||
- _SPECGLOSSMAP
|
||||
- _SPECULAR_SETUP
|
||||
m_InvalidKeywords: []
|
||||
@ -65,7 +68,7 @@ Material:
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Texture: {fileID: 2800000, guid: f63b585b494c19e408adc8374a32ff38, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
|
||||
@ -12,6 +12,9 @@ Material:
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _METALLICSPECGLOSSMAP
|
||||
- _NORMALMAP
|
||||
- _PARALLAXMAP
|
||||
- _SPECGLOSSMAP
|
||||
- _SPECULAR_SETUP
|
||||
m_InvalidKeywords: []
|
||||
@ -52,7 +55,7 @@ Material:
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Texture: {fileID: 2800000, guid: d898f1952a888e5459ca4fa61f69aacb, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
|
||||
@ -12,6 +12,9 @@ Material:
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _METALLICSPECGLOSSMAP
|
||||
- _NORMALMAP
|
||||
- _PARALLAXMAP
|
||||
- _SPECGLOSSMAP
|
||||
- _SPECULAR_SETUP
|
||||
m_InvalidKeywords: []
|
||||
@ -52,7 +55,7 @@ Material:
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Texture: {fileID: 2800000, guid: 190b08caee9510e4094d8fb85df30e6a, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
|
||||
@ -25,6 +25,9 @@ Material:
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _METALLICSPECGLOSSMAP
|
||||
- _NORMALMAP
|
||||
- _PARALLAXMAP
|
||||
- _SPECGLOSSMAP
|
||||
- _SPECULAR_SETUP
|
||||
m_InvalidKeywords: []
|
||||
@ -65,7 +68,7 @@ Material:
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Texture: {fileID: 2800000, guid: 348b7b1e9b718254eb222c50d2f1b370, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
|
||||
@ -64,7 +64,7 @@ Material:
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Texture: {fileID: 2800000, guid: 24ae1851ee4bd6b40903851f84596cc5, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
|
||||
@ -12,6 +12,7 @@ Material:
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _METALLICSPECGLOSSMAP
|
||||
- _SPECGLOSSMAP
|
||||
- _SPECULAR_SETUP
|
||||
m_InvalidKeywords:
|
||||
@ -53,7 +54,7 @@ Material:
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Texture: {fileID: 2800000, guid: 027ee668c37651046b8fcc1de158d11b, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
|
||||
@ -25,6 +25,7 @@ Material:
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _METALLICSPECGLOSSMAP
|
||||
- _SPECGLOSSMAP
|
||||
- _SPECULAR_SETUP
|
||||
m_InvalidKeywords: []
|
||||
@ -65,7 +66,7 @@ Material:
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Texture: {fileID: 2800000, guid: 62da88ce44d49764b91100a52cc54548, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
|
||||
@ -12,6 +12,7 @@ Material:
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _METALLICSPECGLOSSMAP
|
||||
- _SPECGLOSSMAP
|
||||
- _SPECULAR_SETUP
|
||||
m_InvalidKeywords:
|
||||
@ -53,7 +54,7 @@ Material:
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Texture: {fileID: 2800000, guid: efce089419136f94492f8f54bf755a5c, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
|
||||
8
Assets/Data/CarPhysicsData.meta
Normal file
8
Assets/Data/CarPhysicsData.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a3efdaab9fd94774aa80108ad4e02503
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
98
Assets/Data/CarPhysicsData/Hirochi_Physics.asset
Normal file
98
Assets/Data/CarPhysicsData/Hirochi_Physics.asset
Normal file
@ -0,0 +1,98 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 396086e692304e97aab2b9b09066d2b5, type: 3}
|
||||
m_Name: Hirochi_Physics
|
||||
m_EditorClassIdentifier: Assembly-CSharp::CarPhysicsData
|
||||
torqueCurve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 1
|
||||
value: 1
|
||||
inSlope: 0.123904884
|
||||
outSlope: 0.123904884
|
||||
tangentMode: 34
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 800
|
||||
value: 100
|
||||
inSlope: 0.082222715
|
||||
outSlope: 0.082222715
|
||||
tangentMode: 34
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 4500
|
||||
value: 250
|
||||
inSlope: -0.0137297325
|
||||
outSlope: -0.0137297325
|
||||
tangentMode: 34
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 7000
|
||||
value: 80
|
||||
inSlope: -0.068
|
||||
outSlope: -0.068
|
||||
tangentMode: 34
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
maxRPM: 7000
|
||||
minRPM: 800
|
||||
shiftUpRPM: 6000
|
||||
shiftDownRPM: 2500
|
||||
gearRatios:
|
||||
- 3.1
|
||||
- 2.2
|
||||
- 1.6
|
||||
- 1.2
|
||||
- 0.9
|
||||
- 0.7
|
||||
finalDrive: 3.4
|
||||
maxSteerAngle: 35
|
||||
steerSmoothing: 10
|
||||
steerAngleBySpeed:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 150
|
||||
value: 0.3
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
centerOfMassOffset: {x: 0, y: -0.2, z: 0}
|
||||
antiRollForce: 5000
|
||||
brakeForce: 3000
|
||||
handbrakeFrictionMultiplier: 0.3
|
||||
8
Assets/Data/CarPhysicsData/Hirochi_Physics.asset.meta
Normal file
8
Assets/Data/CarPhysicsData/Hirochi_Physics.asset.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1865251594a045046b5f77e23e0cb2c6
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,116 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
|
||||
namespace Perekyp.EditorTools
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
public static class SpawnCubesEditor
|
||||
{
|
||||
static SpawnCubesEditor()
|
||||
{
|
||||
EditorApplication.delayCall += SpawnCubesOnce;
|
||||
}
|
||||
|
||||
private static void SpawnCubesOnce()
|
||||
{
|
||||
// Execute spawn of the 6 cubes
|
||||
ExecuteSpawn();
|
||||
}
|
||||
|
||||
[MenuItem("Tools/Spawn 6 Cubes (2 Rows)")]
|
||||
public static void ExecuteSpawn()
|
||||
{
|
||||
// Clean up previous groups if existing
|
||||
GameObject oldGroup1 = GameObject.Find("ThreeCubes");
|
||||
if (oldGroup1 != null)
|
||||
{
|
||||
Undo.DestroyObjectImmediate(oldGroup1);
|
||||
}
|
||||
GameObject oldGroup2 = GameObject.Find("CubesGroup");
|
||||
if (oldGroup2 != null)
|
||||
{
|
||||
Undo.DestroyObjectImmediate(oldGroup2);
|
||||
}
|
||||
|
||||
GameObject parent = new GameObject("CubesGroup");
|
||||
Undo.RegisterCreatedObjectUndo(parent, "Create CubesGroup Parent");
|
||||
|
||||
// Row 1 (first 3 cubes) and Row 2 (3 new cubes next to them)
|
||||
// Player is around Z = 5.24 facing negative Z, so Z = 3.5 and Z = 2.0 are directly in view.
|
||||
Vector3[] positions = new Vector3[]
|
||||
{
|
||||
// Row 1 (first row)
|
||||
new Vector3(-2.0f, 1.0f, 3.5f),
|
||||
new Vector3( 0.0f, 1.0f, 3.5f),
|
||||
new Vector3( 2.0f, 1.0f, 3.5f),
|
||||
|
||||
// Row 2 (second row, right next to / in front of the first row)
|
||||
new Vector3(-2.0f, 1.0f, 2.0f),
|
||||
new Vector3( 0.0f, 1.0f, 2.0f),
|
||||
new Vector3( 2.0f, 1.0f, 2.0f)
|
||||
};
|
||||
|
||||
Color[] colors = new Color[]
|
||||
{
|
||||
// Row 1: Red, Green, Blue
|
||||
new Color(0.95f, 0.26f, 0.21f), // Red
|
||||
new Color(0.30f, 0.69f, 0.31f), // Green
|
||||
new Color(0.13f, 0.59f, 0.95f), // Blue
|
||||
|
||||
// Row 2: Red, Green, Blue (matching set)
|
||||
new Color(0.95f, 0.26f, 0.21f), // Red
|
||||
new Color(0.30f, 0.69f, 0.31f), // Green
|
||||
new Color(0.13f, 0.59f, 0.95f) // Blue
|
||||
};
|
||||
|
||||
string[] names = new string[]
|
||||
{
|
||||
"Cube_Red_Row1",
|
||||
"Cube_Green_Row1",
|
||||
"Cube_Blue_Row1",
|
||||
"Cube_Red_Row2",
|
||||
"Cube_Green_Row2",
|
||||
"Cube_Blue_Row2"
|
||||
};
|
||||
|
||||
Shader urpShader = Shader.Find("Universal Render Pipeline/Lit")
|
||||
?? Shader.Find("URP/Lit")
|
||||
?? Shader.Find("Standard");
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||||
cube.name = names[i];
|
||||
cube.transform.position = positions[i];
|
||||
cube.transform.localScale = Vector3.one;
|
||||
cube.transform.SetParent(parent.transform);
|
||||
|
||||
var renderer = cube.GetComponent<Renderer>();
|
||||
if (renderer != null && urpShader != null)
|
||||
{
|
||||
Material mat = new Material(urpShader);
|
||||
mat.name = $"Mat_{names[i]}";
|
||||
mat.color = colors[i];
|
||||
renderer.sharedMaterial = mat;
|
||||
}
|
||||
|
||||
Undo.RegisterCreatedObjectUndo(cube, $"Create {names[i]}");
|
||||
}
|
||||
|
||||
Selection.activeGameObject = parent;
|
||||
|
||||
var activeScene = EditorSceneManager.GetActiveScene();
|
||||
if (activeScene.IsValid())
|
||||
{
|
||||
EditorSceneManager.MarkSceneDirty(activeScene);
|
||||
EditorSceneManager.SaveScene(activeScene);
|
||||
Debug.Log($"[SpawnCubesEditor] Successfully spawned 6 cubes (2 rows of 3) on scene '{activeScene.name}'!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("[SpawnCubesEditor] Successfully spawned 6 cubes in the scene!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 403983d9c86a19f4a85074eba6aed3fd
|
||||
File diff suppressed because it is too large
Load Diff
@ -7,13 +7,13 @@ public class VehicleInteraction : MonoBehaviour, IInteractable
|
||||
[SerializeField] private UIManager uiManager;
|
||||
|
||||
private CarOrbitCamera globalCarCamera; // Ссылка на глобальную камеру
|
||||
private CarController carController;
|
||||
private AdvancedCarController carController;
|
||||
private GameObject playerInstance;
|
||||
private bool isPlayerInside = false;
|
||||
public bool isPlayerInside = false;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
carController = GetComponent<CarController>();
|
||||
carController = GetComponent<AdvancedCarController>();
|
||||
|
||||
// Автоматически находим камеру на сцене, даже если она выключена
|
||||
globalCarCamera = FindAnyObjectByType<CarOrbitCamera>(FindObjectsInactive.Include);
|
||||
|
||||
3
Assets/Scripts/Car/Part/Data.meta
Normal file
3
Assets/Scripts/Car/Part/Data.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1396ff771764dc2bcb7e90faac08815
|
||||
timeCreated: 1791809673
|
||||
170
Assets/Scripts/Car/Physics/AdvancedCarController.cs
Normal file
170
Assets/Scripts/Car/Physics/AdvancedCarController.cs
Normal file
@ -0,0 +1,170 @@
|
||||
using UnityEngine;
|
||||
|
||||
[RequireComponent(typeof(Rigidbody))]
|
||||
public class AdvancedCarController : MonoBehaviour
|
||||
{
|
||||
public float SpeedKmH => rb.linearVelocity.magnitude * 3.6f;
|
||||
|
||||
[Header("Данные авто")]
|
||||
[SerializeField] private CarPhysicsData data;
|
||||
|
||||
[Header("Колеса (WheelColliders)")]
|
||||
[SerializeField] private WheelCollider[] frontWheels;
|
||||
[SerializeField] private WheelCollider[] rearWheels;
|
||||
|
||||
[Header("Состояние деталей (Для диплома)")]
|
||||
[Range(0.1f, 1f)] public float engineCondition = 1f; // 1 - новое, 0.1 - убитое (не тянет)
|
||||
[Range(0.1f, 1f)] public float tiresCondition = 1f; // Влияет на держак резины
|
||||
|
||||
// Состояние авто
|
||||
public float CurrentSpeedKmH => rb.linearVelocity.magnitude * 3.6f;
|
||||
public float EngineRPM { get; private set; }
|
||||
public int CurrentGear { get; private set; }
|
||||
|
||||
private Rigidbody rb;
|
||||
private float currentSteerAngle;
|
||||
private WheelFrictionCurve originalRearSidewaysFriction;
|
||||
|
||||
// Ввод
|
||||
private float moveInput, steerInput;
|
||||
private bool isBraking, isHandbrake;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
rb = GetComponent<Rigidbody>();
|
||||
rb.centerOfMass = data.centerOfMassOffset; // Понижаем центр масс для стабильности
|
||||
|
||||
// Запоминаем оригинальное трение для ручника
|
||||
if (rearWheels.Length > 0)
|
||||
originalRearSidewaysFriction = rearWheels[0].sidewaysFriction;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// Чтение инпута (можно заменить на новый Input System)
|
||||
moveInput = Input.GetAxis("Vertical");
|
||||
steerInput = Input.GetAxis("Horizontal");
|
||||
isBraking = Input.GetKey(KeyCode.Space) || (moveInput < 0 && CurrentSpeedKmH > 5f);
|
||||
isHandbrake = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.Space);
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
ApplySteering();
|
||||
ProcessEngineAndGears();
|
||||
ApplyAntiRollBar();
|
||||
ProcessHandbrake();
|
||||
}
|
||||
|
||||
public void ProcessInput(float vertical, float horizontal, bool handbrake)
|
||||
{
|
||||
moveInput = vertical;
|
||||
steerInput = horizontal;
|
||||
isHandbrake = handbrake;
|
||||
}
|
||||
|
||||
private void ApplySteering()
|
||||
{
|
||||
// 1. Угол зависит от скорости (на 100 км/ч руль не вывернется на 35 градусов)
|
||||
float speedMultiplier = data.steerAngleBySpeed.Evaluate(CurrentSpeedKmH);
|
||||
float targetSteer = steerInput * data.maxSteerAngle * speedMultiplier;
|
||||
|
||||
// 2. Сглаживание поворота (руль не дергается мгновенно)
|
||||
currentSteerAngle = Mathf.Lerp(currentSteerAngle, targetSteer, Time.fixedDeltaTime * data.steerSmoothing);
|
||||
|
||||
foreach (var wheel in frontWheels)
|
||||
{
|
||||
wheel.steerAngle = currentSteerAngle;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessEngineAndGears()
|
||||
{
|
||||
// Считаем средние обороты ведущих колес (допустим, задний привод)
|
||||
float wheelRPM = 0;
|
||||
foreach (var w in rearWheels) wheelRPM += Mathf.Abs(w.rpm);
|
||||
wheelRPM /= rearWheels.Length;
|
||||
|
||||
// Вычисляем обороты двигателя через передаточные числа
|
||||
float gearRatio = data.gearRatios[CurrentGear];
|
||||
EngineRPM = Mathf.Clamp(wheelRPM * gearRatio * data.finalDrive, data.minRPM, data.maxRPM);
|
||||
|
||||
// Автоматическая коробка передач
|
||||
if (EngineRPM > data.shiftUpRPM && CurrentGear < data.gearRatios.Length - 1)
|
||||
CurrentGear++;
|
||||
else if (EngineRPM < data.shiftDownRPM && CurrentGear > 0)
|
||||
CurrentGear--;
|
||||
|
||||
// Получаем крутящий момент по графику и умножаем на состояние двигателя!
|
||||
float motorTorque = data.torqueCurve.Evaluate(EngineRPM) * gearRatio * data.finalDrive;
|
||||
float finalTorque = moveInput * motorTorque * engineCondition;
|
||||
|
||||
// Применяем газ или тормоз
|
||||
foreach (var wheel in rearWheels)
|
||||
{
|
||||
if (isBraking)
|
||||
{
|
||||
wheel.motorTorque = 0;
|
||||
wheel.brakeTorque = data.brakeForce;
|
||||
}
|
||||
else
|
||||
{
|
||||
wheel.motorTorque = finalTorque / rearWheels.Length;
|
||||
wheel.brakeTorque = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessHandbrake()
|
||||
{
|
||||
foreach (var wheel in rearWheels)
|
||||
{
|
||||
if (isHandbrake)
|
||||
{
|
||||
wheel.brakeTorque = data.brakeForce;
|
||||
|
||||
// ДРИФТ: Уменьшаем боковое сцепление, умножая на износ шин
|
||||
WheelFrictionCurve fc = wheel.sidewaysFriction;
|
||||
fc.stiffness = originalRearSidewaysFriction.stiffness * data.handbrakeFrictionMultiplier * tiresCondition;
|
||||
wheel.sidewaysFriction = fc;
|
||||
}
|
||||
else if (!isBraking)
|
||||
{
|
||||
wheel.brakeTorque = 0;
|
||||
|
||||
// Возвращаем обычное сцепление с поправкой на убитость шин
|
||||
WheelFrictionCurve fc = wheel.sidewaysFriction;
|
||||
fc.stiffness = originalRearSidewaysFriction.stiffness * tiresCondition;
|
||||
wheel.sidewaysFriction = fc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyAntiRollBar()
|
||||
{
|
||||
// Стабилизатор поперечной устойчивости для передней и задней оси
|
||||
ApplyAxleAntiRoll(frontWheels[0], frontWheels[1]);
|
||||
ApplyAxleAntiRoll(rearWheels[0], rearWheels[1]);
|
||||
}
|
||||
|
||||
private void ApplyAxleAntiRoll(WheelCollider left, WheelCollider right)
|
||||
{
|
||||
float travelL = 1.0f;
|
||||
float travelR = 1.0f;
|
||||
|
||||
bool groundedL = left.GetGroundHit(out WheelHit hitL);
|
||||
if (groundedL) travelL = (-left.transform.InverseTransformPoint(hitL.point).y - left.radius) / left.suspensionDistance;
|
||||
|
||||
bool groundedR = right.GetGroundHit(out WheelHit hitR);
|
||||
if (groundedR) travelR = (-right.transform.InverseTransformPoint(hitR.point).y - right.radius) / right.suspensionDistance;
|
||||
|
||||
// Разница сжатия подвески
|
||||
float antiRollVal = (travelL - travelR) * data.antiRollForce;
|
||||
|
||||
// Применяем противодействующую силу (прижимаем поднявшееся колесо)
|
||||
if (groundedL) rb.AddForceAtPosition(left.transform.up * -antiRollVal, left.transform.position);
|
||||
if (groundedR) rb.AddForceAtPosition(right.transform.up * antiRollVal, right.transform.position);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
3
Assets/Scripts/Car/Physics/AdvancedCarController.cs.meta
Normal file
3
Assets/Scripts/Car/Physics/AdvancedCarController.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c02b03f912164de9ae5c7659d886fae9
|
||||
timeCreated: 1791809782
|
||||
3
Assets/Scripts/Car/Physics/Data.meta
Normal file
3
Assets/Scripts/Car/Physics/Data.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50a1732ad7494d0ab29474ca2bc918c1
|
||||
timeCreated: 1791809613
|
||||
28
Assets/Scripts/Car/Physics/Data/CarPhysicsData.cs
Normal file
28
Assets/Scripts/Car/Physics/Data/CarPhysicsData.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using UnityEngine;
|
||||
|
||||
[CreateAssetMenu(fileName = "NewCarPhysics", menuName = "Car System/Physics Data")]
|
||||
public class CarPhysicsData : ScriptableObject
|
||||
{
|
||||
[Header("Двигатель и КПП")]
|
||||
public AnimationCurve torqueCurve; // Кривая: X - обороты (RPM), Y - крутящий момент (Nm)
|
||||
public float maxRPM = 7000f;
|
||||
public float minRPM = 800f;
|
||||
public float shiftUpRPM = 6000f;
|
||||
public float shiftDownRPM = 2500f;
|
||||
public float[] gearRatios = { 3.1f, 2.2f, 1.6f, 1.2f, 0.9f, 0.7f };
|
||||
public float finalDrive = 3.4f;
|
||||
|
||||
[Header("Рулевое управление")]
|
||||
public float maxSteerAngle = 35f;
|
||||
public float steerSmoothing = 10f; // Скорость поворота руля
|
||||
[Tooltip("Как сильно режется угол поворота на высокой скорости")]
|
||||
public AnimationCurve steerAngleBySpeed; // X - скорость (км/ч), Y - множитель угла (0..1)
|
||||
|
||||
[Header("Подвеска и физика")]
|
||||
public Vector3 centerOfMassOffset = new Vector3(0, -0.2f, 0); // Пониженный центр масс
|
||||
public float antiRollForce = 5000f; // Стабилизатор поперечной устойчивости
|
||||
public float brakeForce = 3000f;
|
||||
|
||||
[Header("Дрифт (Ручник)")]
|
||||
public float handbrakeFrictionMultiplier = 0.3f; // Насколько скользкой становится задняя ось
|
||||
}
|
||||
3
Assets/Scripts/Car/Physics/Data/CarPhysicsData.cs.meta
Normal file
3
Assets/Scripts/Car/Physics/Data/CarPhysicsData.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 396086e692304e97aab2b9b09066d2b5
|
||||
timeCreated: 1791809619
|
||||
29
Assets/Scripts/Car/Physics/WheelVisuals.cs
Normal file
29
Assets/Scripts/Car/Physics/WheelVisuals.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class WheelVisuals : MonoBehaviour
|
||||
{
|
||||
[System.Serializable]
|
||||
public struct WheelPair
|
||||
{
|
||||
public WheelCollider collider;
|
||||
public Transform mesh;
|
||||
}
|
||||
|
||||
[Header("Привязка колес")]
|
||||
public WheelPair[] wheels;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
foreach (var w in wheels)
|
||||
{
|
||||
if (w.collider == null || w.mesh == null) continue;
|
||||
|
||||
// Получаем физическую позицию колеса
|
||||
w.collider.GetWorldPose(out Vector3 pos, out Quaternion rot);
|
||||
|
||||
// Применяем к 3D-модели
|
||||
w.mesh.position = pos;
|
||||
w.mesh.rotation = rot;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/Car/Physics/WheelVisuals.cs.meta
Normal file
3
Assets/Scripts/Car/Physics/WheelVisuals.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce1b65bf09494194a68749d417b0e17a
|
||||
timeCreated: 1791809850
|
||||
@ -2,39 +2,74 @@ using UnityEngine;
|
||||
|
||||
public class PlayerInteractor : MonoBehaviour
|
||||
{
|
||||
[Header("Настройки луча")]
|
||||
[SerializeField] private float interactRange = 3f;
|
||||
[SerializeField] private LayerMask interactableLayer; // Создайте слой "Interactable" в Unity
|
||||
[SerializeField] private KeyCode primaryKey = KeyCode.E;
|
||||
[SerializeField] private KeyCode secondaryKey = KeyCode.R;
|
||||
[SerializeField] private LayerMask interactableLayer;
|
||||
|
||||
[Header("References")]
|
||||
[Header("Клавиши управления")]
|
||||
[SerializeField] private KeyCode primaryKey = KeyCode.E; // Работа с деталью (открыть/взять)
|
||||
[SerializeField] private KeyCode secondaryKey = KeyCode.R; // Снять деталь
|
||||
[SerializeField] private KeyCode enterVehicleKey = KeyCode.F; // Сесть в машину
|
||||
|
||||
[Header("Ссылки")]
|
||||
[SerializeField] private UIManager uiManager;
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (uiManager != null) uiManager.HidePrompt();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// Пускаем луч из центра экрана
|
||||
Ray ray = new Ray(transform.position, transform.forward);
|
||||
|
||||
if (Physics.Raycast(ray, out RaycastHit hit, interactRange, interactableLayer, QueryTriggerInteraction.Collide))
|
||||
{
|
||||
// Ищем интерактивную деталь (дверь, капот, крыло)
|
||||
IInteractable interactable = hit.collider.GetComponentInParent<IInteractable>();
|
||||
|
||||
if (interactable != null)
|
||||
// Ищем скрипт автомобиля в родительских объектах
|
||||
VehicleInteraction vehicle = hit.collider.GetComponentInParent<VehicleInteraction>();
|
||||
|
||||
if (interactable != null || vehicle != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(interactable.GetPrompt()) && uiManager!=null)
|
||||
// Формируем комбинированную подсказку
|
||||
string prompt = "";
|
||||
|
||||
if (vehicle != null && !vehicle.isPlayerInside)
|
||||
{
|
||||
uiManager.ShowPrompt(interactable.GetPrompt());
|
||||
}
|
||||
else if (uiManager != null)
|
||||
{
|
||||
uiManager.HidePrompt();
|
||||
prompt += "[F] Сесть в авто ";
|
||||
}
|
||||
|
||||
if (interactable != null)
|
||||
{
|
||||
string partPrompt = interactable.GetPrompt();
|
||||
if (!string.IsNullOrEmpty(partPrompt))
|
||||
{
|
||||
prompt += partPrompt;
|
||||
}
|
||||
}
|
||||
|
||||
if (Input.GetKeyDown(primaryKey))
|
||||
if (!string.IsNullOrEmpty(prompt) && uiManager != null)
|
||||
{
|
||||
uiManager.ShowPrompt(prompt);
|
||||
}
|
||||
|
||||
// 1. Посадка в авто на F
|
||||
if (Input.GetKeyDown(enterVehicleKey) && vehicle != null)
|
||||
{
|
||||
vehicle.Interact(transform.root.gameObject);
|
||||
if (uiManager != null) uiManager.HidePrompt();
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Основное действие с деталью на E (Открыть/Закрыть)
|
||||
if (Input.GetKeyDown(primaryKey) && interactable != null)
|
||||
{
|
||||
interactable.Interact(transform.root.gameObject);
|
||||
}
|
||||
|
||||
// 3. Вторичное действие с деталью на R (Снять в руки)
|
||||
if (Input.GetKeyDown(secondaryKey))
|
||||
{
|
||||
ISecondaryInteractable secondary = hit.collider.GetComponentInParent<ISecondaryInteractable>();
|
||||
@ -50,12 +85,4 @@ public class PlayerInteractor : MonoBehaviour
|
||||
uiManager.HidePrompt();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (uiManager != null)
|
||||
{
|
||||
uiManager.HidePrompt();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user