Развитие гоночек
This commit is contained in:
1 parent
ec60c47652
commit
b54083521f
532 files changed
+16091
-28231
No files matched your search
@@ -1,3 +1,4 @@
|
||||
using Code.Infrastructure.App;
|
||||
using Code.Infrastructure.SceneLoader;
|
||||
using Reflex.Attributes;
|
||||
using UnityEngine;
|
||||
@@ -8,10 +9,20 @@ namespace Code.Debug
|
||||
public class SceneChooser : MonoBehaviour
|
||||
{
|
||||
[Inject] private SceneLoader _sceneLoader;
|
||||
|
||||
[Inject] private AppStateMachine _stateMachine;
|
||||
public void ChooseScene(int id)
|
||||
{
|
||||
_sceneLoader.LoadSceneAsync((SceneId)id, LoadSceneMode.Single).Forget();
|
||||
}
|
||||
|
||||
public void ChooseState(int id)
|
||||
{
|
||||
_stateMachine.SwitchState((AppStates)id);
|
||||
}
|
||||
|
||||
public void SwitchGameplay()
|
||||
{
|
||||
_stateMachine.SwitchState(AppStates.Gameplay).AllowStateTransition(AppStates.MainMenu);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Code.Example.Race.Racer;
|
||||
using Code.Example.Race.Track;
|
||||
using Code.Infrastructure.EventBus;
|
||||
using Code.Infrastructure.Loadings;
|
||||
using Reflex.Attributes;
|
||||
|
||||
namespace Code.Example.Race
|
||||
{
|
||||
public class RaceGame : IRacerLoadedHandle, IDisposable
|
||||
{
|
||||
private RaceScores _scores;
|
||||
|
||||
private IRacerFactory _racerFactory;
|
||||
private RaceTrackData _raceTrackData;
|
||||
private EventBus _eventBus;
|
||||
|
||||
public RaceGame(EventBus eventBus, IRacerFactory racerFactory, RaceTrackData raceTrackData, RaceScores scores)
|
||||
{
|
||||
_eventBus = eventBus;
|
||||
_racerFactory = racerFactory;
|
||||
_raceTrackData = raceTrackData;
|
||||
_eventBus.Subscribe(this);
|
||||
|
||||
_scores = scores;
|
||||
|
||||
RandomizeRacers(raceTrackData.trackData.RacerPoints.Count);
|
||||
}
|
||||
|
||||
public void StartRacers()
|
||||
{
|
||||
foreach (var racer in PlacedRacers)
|
||||
{
|
||||
racer.StartRacer();
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG
|
||||
private List<RacerType> _randomizedTypes = new();
|
||||
|
||||
private void RandomizeRacers(int count)
|
||||
{
|
||||
_raceGameLoading = new Loading(count, RacersLoadCompleted);
|
||||
|
||||
_randomizedTypes.Add(RacerType.Player);
|
||||
|
||||
for (var i = 0; i < count - 1; i++)
|
||||
_randomizedTypes.Add((RacerType)UnityEngine.Random.Range(1, 3));
|
||||
|
||||
foreach (var type in _randomizedTypes) _racerFactory.LoadRacer(type);
|
||||
}
|
||||
|
||||
private void RacersLoadCompleted() =>
|
||||
_eventBus.RaiseEvent<IRaceGameInitializedHandle>(x => x.RaceGameReady());
|
||||
|
||||
public List<Racer.AI.Racer> PlacedRacers { get; } = new();
|
||||
|
||||
public void PlaceRacers()
|
||||
{
|
||||
for (var i = 0; i < _raceTrackData.trackData.RacerPoints.Count; i++)
|
||||
{
|
||||
PlacedRacers.Add(UnityEngine.Object.Instantiate(
|
||||
_racerPrefabs[_randomizedTypes[i]],
|
||||
_raceTrackData.trackData.RacerPoints[i].transform).GetComponent<Racer.AI.Racer>());
|
||||
PlacedRacers[^1].SetData(_racerPrefabs[_randomizedTypes[i]].Data);
|
||||
PlacedRacers[^1].Id = i;
|
||||
_scores.SubscribeRacer(i);
|
||||
}
|
||||
|
||||
foreach (var racer in PlacedRacers)
|
||||
{
|
||||
racer.Initialize(_raceTrackData.trackData.Checkpoints);
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<RacerType, Racer.AI.Racer> _racerPrefabs = new();
|
||||
private Loading _raceGameLoading;
|
||||
|
||||
public void RacerLoaded(RacerType type, Racer.AI.Racer racer)
|
||||
{
|
||||
if (racer)
|
||||
_racerPrefabs.Add(type, racer);
|
||||
|
||||
_raceGameLoading.DoProgress();
|
||||
}
|
||||
|
||||
// private Dictionary<RacerType, Racer.AI.Racer> _spawnedRacers = new();
|
||||
public void RacerCreated(RacerType type, Racer.AI.Racer racer)
|
||||
{
|
||||
// _spawnedRacers.Add(type, racer);
|
||||
// _raceGameLoading.DoProgress();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_eventBus.Unsubscribe(this);
|
||||
_racerPrefabs.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public interface IRaceGameInitializedHandle : IGlobalSubscriber
|
||||
{
|
||||
void RaceGameReady();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ffa5c181be7447cb1c41392018b193f
|
||||
timeCreated: 1769692114
|
||||
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Code.Example.Race.Track;
|
||||
using Code.Infrastructure.EventBus;
|
||||
|
||||
namespace Code.Example.Race
|
||||
{
|
||||
public class RaceScores : IRacerPassedCheckpointHandler, IDisposable
|
||||
{
|
||||
private Dictionary<int, int> _scores = new();
|
||||
private EventBus _eventBus;
|
||||
|
||||
public RaceScores(EventBus eventBus)
|
||||
{
|
||||
_eventBus = eventBus;
|
||||
_eventBus.Subscribe(this);
|
||||
}
|
||||
public void SubscribeRacer(int racer)
|
||||
{
|
||||
_scores.Add(racer, 0);
|
||||
}
|
||||
|
||||
public void ChangeScore(int racer, int additionalScore)
|
||||
{
|
||||
_scores[racer] += additionalScore;
|
||||
_eventBus.RaiseEvent<IScoreChangedHandle>(x=> x.ScoreChanged(racer,additionalScore, GetScores()));
|
||||
}
|
||||
|
||||
public void UnsubscribeRacer(int racer)
|
||||
{
|
||||
_scores.Remove(racer);
|
||||
}
|
||||
|
||||
public List<KeyValuePair<int, int>> GetScores()
|
||||
{
|
||||
return _scores.OrderByDescending(x => x.Value).ToList();
|
||||
}
|
||||
|
||||
public void OnRacerPassedCheckpoint(Racer.AI.Racer racer) => ChangeScore(racer.Id,1);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_eventBus.Unsubscribe(this);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IScoreChangedHandle : IGlobalSubscriber
|
||||
{
|
||||
void ScoreChanged(int racer, int additionalScore, List<KeyValuePair<int, int>> scores);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b45fb028abcf43129f5c8100e7215f1f
|
||||
timeCreated: 1770051193
|
||||
@@ -4,7 +4,7 @@ using UnityEngine.AI;
|
||||
|
||||
namespace Code.Example.Race.Racer.AI
|
||||
{
|
||||
public class AIDebugRacer : MonoBehaviour
|
||||
public class AIDebugRacer : Racer
|
||||
{
|
||||
[SerializeField] private NavMeshAgent navMeshAgent;
|
||||
[SerializeField] private List<Transform> waypoints;
|
||||
@@ -15,11 +15,31 @@ namespace Code.Example.Race.Racer.AI
|
||||
_currentWaypointIndex++;
|
||||
}
|
||||
|
||||
public void NextWaypoint()
|
||||
public override void NextWaypoint()
|
||||
{
|
||||
if(_currentWaypointIndex >= waypoints.Count) _currentWaypointIndex = 0;
|
||||
|
||||
navMeshAgent.destination = waypoints[_currentWaypointIndex++].position;
|
||||
}
|
||||
|
||||
public override void StartRacer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void StopRacer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void SetData(RacerData data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Initialize(List<Transform> waypoints)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
|
||||
namespace Code.Example.Race.Racer.AI
|
||||
{
|
||||
public class AIRacer : Racer
|
||||
{
|
||||
[SerializeField] private NavMeshAgent navMeshAgent;
|
||||
|
||||
public override void SetData(RacerData data)
|
||||
{
|
||||
Data = data;
|
||||
navMeshAgent.angularSpeed = data.angularSpeed;
|
||||
navMeshAgent.speed = data.speed;
|
||||
}
|
||||
|
||||
public override void Initialize(List<Transform> waypoints)
|
||||
{
|
||||
navMeshAgent.isStopped = true;
|
||||
|
||||
Waypoints = waypoints;
|
||||
navMeshAgent.destination = Waypoints[CurrentWaypointIndex].position;
|
||||
|
||||
CurrentWaypointIndex++;
|
||||
}
|
||||
public override void StartRacer() => navMeshAgent.isStopped = false;
|
||||
public override void StopRacer() => navMeshAgent.isStopped = true;
|
||||
public override void NextWaypoint()
|
||||
{
|
||||
if(CurrentWaypointIndex >= Waypoints.Count) CurrentWaypointIndex = 0;
|
||||
|
||||
navMeshAgent.destination = Waypoints[CurrentWaypointIndex++].position;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05f30660967e40209aa88719fa498c78
|
||||
timeCreated: 1769694590
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.Example.Race.Racer.AI
|
||||
{
|
||||
public class PlayerRacer : Racer
|
||||
{
|
||||
public override void SetData(RacerData data)
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
|
||||
public override void Initialize(List<Transform> waypoints)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void NextWaypoint()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void StartRacer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void StopRacer()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d3497d41c87415eab67cfc865262b79
|
||||
timeCreated: 1769619757
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.Example.Race.Racer.AI
|
||||
{
|
||||
public abstract class Racer : MonoBehaviour
|
||||
{
|
||||
protected List<Transform> Waypoints;
|
||||
protected int CurrentWaypointIndex;
|
||||
public RacerData Data { get; protected set; }
|
||||
public int Id { get; set; }
|
||||
public abstract void SetData(RacerData data);
|
||||
public abstract void Initialize(List<Transform> waypoints);
|
||||
public abstract void NextWaypoint();
|
||||
public abstract void StartRacer();
|
||||
public abstract void StopRacer();
|
||||
|
||||
[SerializeField] protected Rigidbody carRigidbody;
|
||||
public Rigidbody CarRigidbody => GetComponent<Rigidbody>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f87ed38713d4b779df9e46c83b03fb7
|
||||
timeCreated: 1769619306
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c5dfd92289c4aa38bb9a8bafc07d204
|
||||
timeCreated: 1769699718
|
||||
@@ -0,0 +1,32 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
|
||||
namespace Code.Example.Race.Racer.Car
|
||||
{
|
||||
public class CarWheelRotator : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private NavMeshAgent agent;
|
||||
[SerializeField] private Transform[] wheels;
|
||||
[SerializeField] private bool rotateDebug;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
Vector3 wheelRotation;
|
||||
foreach (var wheel in wheels)
|
||||
{
|
||||
if (rotateDebug)
|
||||
{
|
||||
UnityEngine.Debug.DrawRay(
|
||||
wheel.position,
|
||||
Vector3.Project(agent.velocity, agent.gameObject.transform.right),
|
||||
Color.yellow, 900f);
|
||||
UnityEngine.Debug.Log(Vector3.Project(agent.velocity, agent.gameObject.transform.right).magnitude);
|
||||
}
|
||||
|
||||
wheelRotation = wheel.localRotation.eulerAngles;
|
||||
wheelRotation.y = Vector3.Project(agent.velocity, agent.gameObject.transform.right).magnitude * 10f;
|
||||
wheel.localRotation = Quaternion.Euler(wheelRotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3634956b4d55431b8772a8612e2e3a4d
|
||||
timeCreated: 1769699734
|
||||
@@ -0,0 +1,23 @@
|
||||
using DG.Tweening;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.Example.Race.Racer.Car
|
||||
{
|
||||
public class CarWheelRotatorPlayer : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Transform[] wheels;
|
||||
[SerializeField] private bool rotateDebug;
|
||||
|
||||
public void RotateWheels(float amount)
|
||||
{
|
||||
// UnityEngine.Debug.Log("Rotating Wheels: " + amount);
|
||||
foreach (var wheel in wheels)
|
||||
{
|
||||
var wheelRotation = wheel.localRotation.eulerAngles;
|
||||
wheelRotation.y = amount;
|
||||
wheel.DOLocalRotate(wheelRotation, 1f);
|
||||
// wheel.localRotation = Quaternion.Euler(wheelRotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c90fde90552d48f592b955cbf1ec5c77
|
||||
timeCreated: 1769705011
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d9a0a4882314e2f91bb356ea0f82538
|
||||
timeCreated: 1769705255
|
||||
@@ -0,0 +1,55 @@
|
||||
using Code.Example.Race.Racer.AI;
|
||||
using Code.Example.Race.Racer.Car;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.Example.Race.Racer.Player
|
||||
{
|
||||
public class PlayerCarController : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Rigidbody _rigidbody;
|
||||
[SerializeField] private PlayerCarInput _playerCarInput;
|
||||
[SerializeField] private PlayerRacer _playerRacer;
|
||||
[SerializeField] private CarWheelRotatorPlayer _wheels;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (_playerCarInput.MovementInput == Vector2.zero) return;
|
||||
|
||||
// var movementForward = transform.forward * (_playerCarInput.MovementInput.y * _playerRacer.Data.speed);
|
||||
//
|
||||
// _rigidbody.AddForce(movementForward * Time.fixedDeltaTime, ForceMode.Force);
|
||||
|
||||
var force = transform.forward * (_playerCarInput.MovementInput.y * _playerRacer.Data.speed);
|
||||
_rigidbody.AddForce(force, ForceMode.Force);
|
||||
|
||||
// if (Mathf.Abs(_playerCarInput.MovementInput.y) < 0.1f && _rigidbody.linearVelocity.magnitude > 0.3f)
|
||||
// {
|
||||
// _rigidbody.AddForce(-_rigidbody.linearVelocity * (_playerRacer.Data.brakeForce * Time.fixedDeltaTime),
|
||||
// ForceMode.Force);
|
||||
// }
|
||||
|
||||
var steerInput = _playerCarInput.MovementInput.x;
|
||||
if (_playerCarInput.MovementInput.y < 0)
|
||||
steerInput = -_playerCarInput.MovementInput.x;
|
||||
|
||||
// var steer = steerInput * maxSteerAngle;
|
||||
//
|
||||
// if (frontLeftWheel) frontLeftWheel.localRotation = Quaternion.Euler(0, steer, 0);
|
||||
// if (frontRightWheel) frontRightWheel.localRotation = Quaternion.Euler(0, steer, 0);
|
||||
|
||||
if (!(_rigidbody.linearVelocity.magnitude > 0.5f)) return;
|
||||
|
||||
// var turn = steerInput * _playerRacer.Data.turnSpeed * Time.fixedDeltaTime;
|
||||
// _rigidbody.MoveRotation(_rigidbody.rotation * Quaternion.Euler(0, turn, 0));
|
||||
|
||||
if (!(_rigidbody.linearVelocity.magnitude is > 1f or < -1f)) return;
|
||||
|
||||
var rotateAmount = _playerCarInput.MovementInput.x * _playerRacer.Data.angularSpeed;
|
||||
|
||||
_wheels.RotateWheels(rotateAmount * 10 * Time.fixedDeltaTime);
|
||||
var wheelRotation = transform.rotation.eulerAngles;
|
||||
wheelRotation.y += rotateAmount;
|
||||
transform.rotation = Quaternion.Euler(wheelRotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b9e2e4a3ddc437ab250f609ea7fc33e
|
||||
timeCreated: 1769705285
|
||||
@@ -0,0 +1,166 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Code.Example.Race.Racer.Player
|
||||
{
|
||||
public class PlayerCarControllerRB : MonoBehaviour
|
||||
{
|
||||
public enum ControlMode
|
||||
{
|
||||
Keyboard,
|
||||
Buttons
|
||||
};
|
||||
|
||||
public enum Axel
|
||||
{
|
||||
Front,
|
||||
Rear
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct Wheel
|
||||
{
|
||||
public GameObject wheelModel;
|
||||
public WheelCollider wheelCollider;
|
||||
public GameObject wheelEffectObj;
|
||||
public ParticleSystem smokeParticle;
|
||||
public Axel axel;
|
||||
}
|
||||
|
||||
public ControlMode control;
|
||||
|
||||
public float maxAcceleration = 30.0f;
|
||||
public float brakeAcceleration = 50.0f;
|
||||
|
||||
public float turnSensitivity = 1.0f;
|
||||
public float maxSteerAngle = 30.0f;
|
||||
|
||||
public Vector3 _centerOfMass;
|
||||
|
||||
public List<Wheel> wheels;
|
||||
|
||||
float moveInput;
|
||||
float steerInput;
|
||||
|
||||
private Rigidbody carRb;
|
||||
|
||||
// private CarLights carLights;
|
||||
|
||||
void Start()
|
||||
{
|
||||
carRb = GetComponent<Rigidbody>();
|
||||
carRb.centerOfMass = _centerOfMass;
|
||||
|
||||
carLights = GetComponent<CarLights>();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
GetInputs();
|
||||
AnimateWheels();
|
||||
WheelEffects();
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
Move();
|
||||
Steer();
|
||||
Brake();
|
||||
}
|
||||
|
||||
public void MoveInput(float input)
|
||||
{
|
||||
moveInput = input;
|
||||
}
|
||||
|
||||
public void SteerInput(float input)
|
||||
{
|
||||
steerInput = input;
|
||||
}
|
||||
|
||||
void GetInputs()
|
||||
{
|
||||
if (control == ControlMode.Keyboard)
|
||||
{
|
||||
moveInput = Input.GetAxis("Vertical");
|
||||
steerInput = Input.GetAxis("Horizontal");
|
||||
}
|
||||
}
|
||||
|
||||
void Move()
|
||||
{
|
||||
foreach (var wheel in wheels)
|
||||
{
|
||||
wheel.wheelCollider.motorTorque = moveInput * 600 * maxAcceleration * Time.deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
void Steer()
|
||||
{
|
||||
foreach (var wheel in wheels)
|
||||
{
|
||||
if (wheel.axel == Axel.Front)
|
||||
{
|
||||
var _steerAngle = steerInput * turnSensitivity * maxSteerAngle;
|
||||
wheel.wheelCollider.steerAngle = Mathf.Lerp(wheel.wheelCollider.steerAngle, _steerAngle, 0.6f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Brake()
|
||||
{
|
||||
if (Input.GetKey(KeyCode.Space) || moveInput == 0)
|
||||
{
|
||||
foreach (var wheel in wheels)
|
||||
{
|
||||
wheel.wheelCollider.brakeTorque = 300 * brakeAcceleration * Time.deltaTime;
|
||||
}
|
||||
|
||||
carLights.isBackLightOn = true;
|
||||
carLights.OperateBackLights();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var wheel in wheels)
|
||||
{
|
||||
wheel.wheelCollider.brakeTorque = 0;
|
||||
}
|
||||
|
||||
carLights.isBackLightOn = false;
|
||||
carLights.OperateBackLights();
|
||||
}
|
||||
}
|
||||
|
||||
void AnimateWheels()
|
||||
{
|
||||
foreach (var wheel in wheels)
|
||||
{
|
||||
Quaternion rot;
|
||||
Vector3 pos;
|
||||
wheel.wheelCollider.GetWorldPose(out pos, out rot);
|
||||
wheel.wheelModel.transform.position = pos;
|
||||
wheel.wheelModel.transform.rotation = rot;
|
||||
}
|
||||
}
|
||||
|
||||
void WheelEffects()
|
||||
{
|
||||
foreach (var wheel in wheels)
|
||||
{
|
||||
//var dirtParticleMainSettings = wheel.smokeParticle.main;
|
||||
|
||||
if (Input.GetKey(KeyCode.Space) && wheel.axel == Axel.Rear && wheel.wheelCollider.isGrounded == true &&
|
||||
carRb.linearVelocity.magnitude >= 10.0f)
|
||||
{
|
||||
wheel.wheelEffectObj.GetComponentInChildren<TrailRenderer>().emitting = true;
|
||||
wheel.smokeParticle.Emit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
wheel.wheelEffectObj.GetComponentInChildren<TrailRenderer>().emitting = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f093c913ff54cb99cd22d7e473931e7
|
||||
timeCreated: 1770299509
|
||||
@@ -0,0 +1,32 @@
|
||||
using Code.Infrastructure.Input;
|
||||
using Reflex.Attributes;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace Code.Example.Race.Racer.Player
|
||||
{
|
||||
public class PlayerCarInput : MonoBehaviour
|
||||
{
|
||||
private IInputService _inputService;
|
||||
public Vector2 MovementInput { get; private set; }
|
||||
|
||||
[Inject]
|
||||
public void Construct(IInputService inputService)
|
||||
{
|
||||
_inputService = inputService;
|
||||
_inputService.BindActionPerformed((int)ActionMappings.Gameplay, (int)GameplayActions.Move, MovementPerformed);
|
||||
_inputService.BindActionCancel((int)ActionMappings.Gameplay, (int)GameplayActions.Move, MovementEnded);
|
||||
}
|
||||
|
||||
private void MovementPerformed(InputAction.CallbackContext context) => MovementInput = context.ReadValue<Vector2>();
|
||||
|
||||
private void MovementEnded(InputAction.CallbackContext context) => MovementInput = Vector2.zero;
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (_inputService == null) return;
|
||||
_inputService.UnbindActionPerformed((int)ActionMappings.Gameplay, (int)GameplayActions.Move, MovementPerformed);
|
||||
_inputService.UnbindActionCanceled((int)ActionMappings.Gameplay, (int)GameplayActions.Move, MovementEnded);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e52315b65c57499981981e2507aaf7bc
|
||||
timeCreated: 1769705872
|
||||
@@ -0,0 +1,96 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Code.Infrastructure.Configs;
|
||||
using Code.Infrastructure.EventBus;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using EventBus = Code.Infrastructure.EventBus.EventBus;
|
||||
|
||||
namespace Code.Example.Race.Racer
|
||||
{
|
||||
public interface IRacerFactory
|
||||
{
|
||||
RacerSettingsConfig GetConfig(RacerType racerType);
|
||||
UniTaskVoid LoadRacer(RacerType racerType);
|
||||
void ReleaseRacer(RacerType racerType);
|
||||
}
|
||||
|
||||
public class RacerFactory : IDisposable, IRacerFactory
|
||||
{
|
||||
private Dictionary<RacerType, RacerSettingsConfig> _racerConfigs;
|
||||
private Dictionary<RacerType, AsyncOperationHandle<GameObject>> _racerPrefabsHandle = new();
|
||||
|
||||
private string _racerConfigsLabel;
|
||||
private AsyncOperationHandle<IList<RacerSettingsConfig>> _racerConfigsHandle;
|
||||
|
||||
private EventBus _eventBus;
|
||||
|
||||
public RacerFactory(IConfigLocator configLocator, EventBus eventBus)
|
||||
{
|
||||
_eventBus = eventBus;
|
||||
_racerConfigsLabel = configLocator.TryGetManyConfigAssetReferences<RacerSettingsConfig>();
|
||||
|
||||
LoadConfigs().Forget();
|
||||
}
|
||||
|
||||
private async UniTaskVoid LoadConfigs()
|
||||
{
|
||||
_racerConfigsHandle = Addressables.LoadAssetsAsync<RacerSettingsConfig>(_racerConfigsLabel);
|
||||
|
||||
await _racerConfigsHandle.ToUniTask();
|
||||
|
||||
_racerConfigs = _racerConfigsHandle.Result.ToDictionary(x => x.racerData.type);
|
||||
|
||||
_eventBus.RaiseEvent<IRacerFactoryInitializedHandle>(x => x.RacerFactoryInitialized());
|
||||
}
|
||||
|
||||
public RacerSettingsConfig GetConfig(RacerType racerType) => _racerConfigs[racerType];
|
||||
|
||||
public async UniTaskVoid LoadRacer(RacerType racerType)
|
||||
{
|
||||
if (_racerPrefabsHandle.ContainsKey(racerType))
|
||||
{
|
||||
_eventBus.RaiseEvent<IRacerLoadedHandle>(x => x.RacerLoaded(racerType, null));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_racerPrefabsHandle.Add(racerType,
|
||||
Addressables.LoadAssetAsync<GameObject>(_racerConfigs[racerType].prefabReference));
|
||||
|
||||
await _racerPrefabsHandle[racerType].ToUniTask();
|
||||
var racer = _racerPrefabsHandle[racerType].Result.GetComponent<AI.Racer>();
|
||||
racer.SetData(_racerConfigs[racerType].racerData);
|
||||
|
||||
_eventBus.RaiseEvent<IRacerLoadedHandle>(x => x.RacerLoaded(racerType, racer));
|
||||
}
|
||||
|
||||
public void ReleaseRacer(RacerType racerType)
|
||||
{
|
||||
_racerPrefabsHandle[racerType].Release();
|
||||
_racerPrefabsHandle.Remove(racerType);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var prefab in _racerPrefabsHandle)
|
||||
prefab.Value.Release();
|
||||
|
||||
_racerConfigsHandle.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public interface IRacerFactoryInitializedHandle : IGlobalSubscriber
|
||||
{
|
||||
public void RacerFactoryInitialized();
|
||||
}
|
||||
|
||||
public interface IRacerLoadedHandle : IGlobalSubscriber
|
||||
{
|
||||
public void RacerLoaded(RacerType type, AI.Racer racer);
|
||||
public void RacerCreated(RacerType type, AI.Racer racer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ab404f94a89460eae107b9d453fa64d
|
||||
timeCreated: 1769620039
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using Code.Infrastructure.Generators;
|
||||
using UnityEngine.AddressableAssets;
|
||||
|
||||
namespace Code.Example.Race.Racer
|
||||
{
|
||||
[Config("Configs/Gameplay/RacerSettings", true)]
|
||||
public class RacerSettings
|
||||
{
|
||||
[ToConfig] public RacerData racerData;
|
||||
|
||||
[ToConfig] public AssetReference prefabReference;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct RacerData
|
||||
{
|
||||
public string name;
|
||||
public float speed;
|
||||
public float angularSpeed;
|
||||
public float maxAcceleration;
|
||||
public float brakeAcceleration;
|
||||
public float turnSensitivity;
|
||||
public float maxSteerAngle;
|
||||
public RacerType type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f25b32b493144bfc9ca0c5016741d012
|
||||
timeCreated: 1769619229
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Code.Example.Race.Racer
|
||||
{
|
||||
public enum RacerType
|
||||
{
|
||||
Player,
|
||||
AIGreen,
|
||||
AIRed
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 488f864fcf6f4632b8d50b39038f5472
|
||||
timeCreated: 1769619126
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Code.Example.Race.Racer
|
||||
{
|
||||
public class RacistSpawnListDebug
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a9506da417a249929493862133eef179
|
||||
timeCreated: 1769685790
|
||||
@@ -1,14 +1,24 @@
|
||||
using Code.Example.Race.Racer.AI;
|
||||
using Code.Infrastructure.EventBus;
|
||||
using Reflex.Attributes;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.Example.Race.Track
|
||||
{
|
||||
public class CheckPoint : MonoBehaviour
|
||||
{
|
||||
[Inject] private EventBus _eventBus;
|
||||
private void OnTriggerEnter(Collider other)
|
||||
{
|
||||
var racer = other.GetComponent<AIDebugRacer>();
|
||||
var racer = other.GetComponent<Racer.AI.Racer>();
|
||||
racer.NextWaypoint();
|
||||
|
||||
_eventBus.RaiseEvent<IRacerPassedCheckpointHandler>(h => h.OnRacerPassedCheckpoint(racer));
|
||||
}
|
||||
}
|
||||
|
||||
public interface IRacerPassedCheckpointHandler : IGlobalSubscriber
|
||||
{
|
||||
void OnRacerPassedCheckpoint(Racer.AI.Racer racer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.Example.Race.Track
|
||||
{
|
||||
public class RaceTrackData : MonoBehaviour
|
||||
{
|
||||
public Transform CameraPosition;
|
||||
public TrackData trackData;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public struct TrackData
|
||||
{
|
||||
public List<Transform> RacerPoints;
|
||||
public List<Transform> Checkpoints;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1847a22e722c47c48ec0ce7d5a929580
|
||||
timeCreated: 1769686034
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af09293375544928a9b19a6b697f214e
|
||||
timeCreated: 1770036714
|
||||
@@ -0,0 +1,39 @@
|
||||
namespace Code.Example.Race.Track.WellEditor
|
||||
{
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
public static class CheckPointAsset
|
||||
{
|
||||
[MenuItem("GameObject/Track/CheckPoint", false, 1)]
|
||||
private static void CreateCustomPrefab()
|
||||
{
|
||||
// Define the path to your prefab in the Project (must be in an "Assets" relative path)
|
||||
var prefabPath = "Assets/Resources/Example/Misc/Point.prefab"; // Update with your actual path
|
||||
|
||||
// Load the prefab asset
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
|
||||
|
||||
if (!prefab)
|
||||
{
|
||||
Debug.LogError("Prefab not found at path: " + prefabPath);
|
||||
return;
|
||||
}
|
||||
|
||||
// Instantiate the prefab in the scene
|
||||
var newInstance = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
|
||||
|
||||
// Ensure it is placed correctly in the Hierarchy and is undoable
|
||||
Undo.RegisterCreatedObjectUndo(newInstance, "Create Custom Prefab");
|
||||
Selection.activeGameObject = newInstance;
|
||||
|
||||
// Set parent if an object is selected
|
||||
if (!Selection.activeTransform)
|
||||
{
|
||||
newInstance.transform.parent = Selection.activeTransform;
|
||||
newInstance.transform.localPosition = Vector3.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d55e4bcf05848eea361440799c21d7e
|
||||
timeCreated: 1770036738
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b875d3daf0cc42e997366fb0b9f0a722
|
||||
timeCreated: 1770042347
|
||||
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Code.Example.Race.Racer;
|
||||
using Code.Example.Race.Track;
|
||||
using Code.Infrastructure.EventBus;
|
||||
using Code.Infrastructure.UI;
|
||||
using Reflex.Attributes;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace Code.Example.Race.UI
|
||||
{
|
||||
public class PlayerScoreCounter : UIPanel, IScoreChangedHandle
|
||||
{
|
||||
[SerializeField] private TMP_Text playerScore;
|
||||
private EventBus _eventBus;
|
||||
|
||||
[Inject]
|
||||
private void Construct(EventBus eventBus)
|
||||
{
|
||||
_eventBus = eventBus;
|
||||
_eventBus.Subscribe(this);
|
||||
}
|
||||
public override void Open(Action callback = null)
|
||||
{
|
||||
playerScore.gameObject.SetActive(true);
|
||||
// image.DOColor(shownColor, 1f).onComplete = () => callback?.Invoke();
|
||||
}
|
||||
|
||||
public override void Close(Action callback = null)
|
||||
{
|
||||
playerScore.gameObject.SetActive(true);
|
||||
// image.DOColor(hiddenColor, 1f).onComplete += () => callback?.Invoke();
|
||||
}
|
||||
|
||||
public void OnRacerPassedCheckpoint(Racer.AI.Racer racer)
|
||||
{
|
||||
}
|
||||
|
||||
public void ScoreChanged(int racer, int additionalScore, List<KeyValuePair<int,int>> scores)
|
||||
{
|
||||
// if (racer.Data.type == RacerType.Player)
|
||||
string output = "";
|
||||
foreach (var score in scores) output += $@"{score.Key}: {score.Value}\n";
|
||||
playerScore.text = output;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf68a9a9d3a946f086dccd6d11741dcf
|
||||
timeCreated: 1770042362
|
||||
@@ -1,5 +1,6 @@
|
||||
using Code.Infrastructure.Audio;
|
||||
using Code.Infrastructure.Camera;
|
||||
using Code.Infrastructure.Input;
|
||||
using Code.Infrastructure.UI;
|
||||
using Reflex.Attributes;
|
||||
|
||||
@@ -19,6 +20,7 @@ namespace Code.Infrastructure.App
|
||||
[Inject] public IUIService UIService { get; set; }
|
||||
[Inject] public IAudioFactory AudioFactory { get; set; }
|
||||
[Inject] public IAudioService AudioService { get; set; }
|
||||
[Inject] public IInputService InputService { get; set; }
|
||||
}
|
||||
|
||||
[Generators.StateMachine(typeof(AppStateMachineContext),typeof(AppStates))]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Code.Debug;
|
||||
using Code.Infrastructure.Audio;
|
||||
using Code.Infrastructure.Camera;
|
||||
using Code.Infrastructure.Configs;
|
||||
@@ -114,7 +115,7 @@ namespace Code.Infrastructure.App
|
||||
{
|
||||
_thatRightContainer.Resolve<CameraStateMachineContext>().cameraLoadedData = data;
|
||||
_thatRightContainer.Resolve<CameraStateMachine>().SwitchState(CameraMode.None)
|
||||
.AllowStateTransition(CameraMode.FirstPerson);
|
||||
.AllowStateTransition(CameraMode.ThirdPerson);
|
||||
|
||||
data.Camera.GetUniversalAdditionalCameraData().renderPostProcessing = true;
|
||||
|
||||
@@ -128,6 +129,7 @@ namespace Code.Infrastructure.App
|
||||
_initialLoading.DoProgress();
|
||||
|
||||
_thatRightContainer.Resolve<IUIService>().TryLoadPanel(UIPanelType.Logo);
|
||||
_thatRightContainer.Resolve<IUIService>().TryLoadPanel(UIPanelType.Loading);
|
||||
}
|
||||
|
||||
public void UILoaded(UIPanelType uiPanelType)
|
||||
|
||||
@@ -1,19 +1,34 @@
|
||||
using Code.Debug;
|
||||
using Code.Example.Race;
|
||||
using Code.Example.Race.Racer;
|
||||
using Code.Example.Race.Track;
|
||||
using Code.Infrastructure.SceneLoader;
|
||||
using Reflex.Core;
|
||||
using Reflex.Enums;
|
||||
using UnityEngine;
|
||||
using Resolution = Reflex.Enums.Resolution;
|
||||
|
||||
namespace Code.Infrastructure.App.SceneInstallers
|
||||
{
|
||||
public class GameplaySceneInstaller : MonoBehaviour, IInstaller
|
||||
{
|
||||
[SerializeField] private RaceTrackData _raceTrackData;
|
||||
|
||||
public void InstallBindings(ContainerBuilder containerBuilder)
|
||||
{
|
||||
|
||||
{
|
||||
containerBuilder.RegisterType(typeof(RacerFactory), new[] { typeof(IRacerFactory) }, Lifetime.Scoped,
|
||||
Resolution.Lazy);
|
||||
containerBuilder.RegisterType(typeof(RaceScores), Lifetime.Scoped,
|
||||
Resolution.Lazy);
|
||||
containerBuilder.RegisterValue(_raceTrackData);
|
||||
|
||||
containerBuilder.OnContainerBuilt += PostInstall;
|
||||
}
|
||||
|
||||
private void PostInstall(Container container)
|
||||
{
|
||||
|
||||
{
|
||||
container.Resolve<EventBus.EventBus>()
|
||||
.RaiseEvent<IOnGameplaySceneLoadedHandler>(x => x.OnGameplaySceneInitialized(container));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
using System.Threading;
|
||||
using Code.Example.Race.Racer;
|
||||
using Code.Example.Race.Track;
|
||||
using Code.Infrastructure.Audio;
|
||||
using Code.Infrastructure.Generators;
|
||||
using Code.Infrastructure.SceneLoader;
|
||||
using Code.Infrastructure.UI;
|
||||
using Reflex.Core;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Code.Infrastructure.App.States
|
||||
{
|
||||
@@ -29,7 +33,7 @@ namespace Code.Infrastructure.App.States
|
||||
|
||||
protected override void OnExitState()
|
||||
{
|
||||
Context.AudioFactory.ReleaseAudios(AudioNames.UISounds);
|
||||
// Context.AudioFactory.ReleaseAudios(AudioNames.UISounds);
|
||||
Context.UIService.TryRemovePanel(UIPanelType.DebugSceneChooser);
|
||||
_eventBus.Unsubscribe(this);
|
||||
}
|
||||
@@ -40,10 +44,10 @@ namespace Code.Infrastructure.App.States
|
||||
|
||||
Context.UIService.OpenPanel(uiPanelType);
|
||||
}
|
||||
|
||||
public void OnReadyToPlay(AudioNames groupName)
|
||||
{
|
||||
Context.AudioService.PlayRepeatedly(AudioNames.UISounds,0,new CancellationTokenSource());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,102 @@
|
||||
using Code.Example.Race;
|
||||
using Code.Example.Race.Racer;
|
||||
using Code.Example.Race.Track;
|
||||
using Code.Infrastructure.Camera;
|
||||
using Code.Infrastructure.Camera.CameraStates;
|
||||
using Code.Infrastructure.Generators;
|
||||
using Code.Infrastructure.SceneLoader;
|
||||
using UnityEngine;
|
||||
using Code.Infrastructure.Input;
|
||||
using Code.Infrastructure.Loadings;
|
||||
using Code.Infrastructure.SceneLoader;
|
||||
using Code.Infrastructure.UI;
|
||||
using Reflex.Core;
|
||||
using Reflex.Injectors;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Code.Infrastructure.App.States
|
||||
{
|
||||
[State(typeof(AppStates),typeof(AppStateMachineContext))]
|
||||
[StateRaisingEvent]
|
||||
public partial class GameplayState : IOnGameplaySceneLoadedHandler
|
||||
[State(typeof(AppStates), typeof(AppStateMachineContext))]
|
||||
[StateRaisingEvent]
|
||||
public partial class GameplayState : IOnGameplaySceneLoadedHandler, IRaceGameInitializedHandle, IRacerFactoryInitializedHandle, IUIPanelLoaded
|
||||
{
|
||||
public GameplayState(AppStateMachineContext context, EventBus.EventBus eventBus) : base(context, eventBus)
|
||||
{
|
||||
}
|
||||
|
||||
public override AppStates myState => AppStates.Gameplay;
|
||||
|
||||
private Loading _gameplayLoading;
|
||||
|
||||
protected override void OnEnterState()
|
||||
{
|
||||
|
||||
EventBus.Subscribe(this);
|
||||
Context.UIService.OpenPanel(UIPanelType.Loading);
|
||||
|
||||
// Scene
|
||||
// RaceGame
|
||||
// Factory
|
||||
// PlayerCounter
|
||||
_gameplayLoading = new Loading(4, GameplayLoadingCompleted);
|
||||
Context.UIService.TryLoadPanel(UIPanelType.PlayerScoreCounter);
|
||||
Context.SceneLoader.LoadSceneAsync(SceneId.Gameplay, LoadSceneMode.Single).Forget();
|
||||
Context.InputService.EnableMap(ActionMappings.Gameplay);
|
||||
}
|
||||
|
||||
private void GameplayLoadingCompleted()
|
||||
{
|
||||
_raceGame.PlaceRacers();
|
||||
|
||||
Context.Camera.SwitchState(CameraMode.ThirdPerson).AllowStateTransition(CameraMode.None);
|
||||
((ThirdPersonState)Context.Camera.CurrentBaseState).SetFollowTarget(_raceGame.PlacedRacers[0].gameObject.transform, _raceGame.PlacedRacers[0].CarRigidbody);
|
||||
|
||||
Context.UIService.ClosePanel(UIPanelType.Loading);
|
||||
_raceGame.StartRacers();
|
||||
}
|
||||
|
||||
protected override void OnExitState()
|
||||
{
|
||||
Context.InputService.DisableMap(ActionMappings.Gameplay);
|
||||
Context.UIService.TryRemovePanel(UIPanelType.PlayerScoreCounter);
|
||||
EventBus.Unsubscribe(this);
|
||||
}
|
||||
|
||||
public void OnGameplaySceneLoaded()
|
||||
{
|
||||
}
|
||||
|
||||
private RaceTrackData _raceTrackData;
|
||||
private RaceGame _raceGame;
|
||||
private Container UNTILTHEYFIXCONTAINERS;
|
||||
public void OnGameplaySceneInitialized(Container container)
|
||||
{
|
||||
_raceTrackData = container.Resolve<RaceTrackData>();
|
||||
|
||||
Context.Camera.Camera.transform.position = _raceTrackData.CameraPosition.transform.position;
|
||||
Context.Camera.Camera.transform.rotation = _raceTrackData.CameraPosition.transform.rotation;
|
||||
|
||||
UNTILTHEYFIXCONTAINERS = container;
|
||||
_gameplayLoading.DoProgress();
|
||||
|
||||
container.Resolve<IRacerFactory>();
|
||||
}
|
||||
|
||||
public void RaceGameReady()
|
||||
{
|
||||
_gameplayLoading.DoProgress();
|
||||
}
|
||||
|
||||
public void RacerFactoryInitialized()
|
||||
{
|
||||
_raceGame = (RaceGame)ConstructorInjector.Construct(typeof(RaceGame), UNTILTHEYFIXCONTAINERS);
|
||||
|
||||
_gameplayLoading.DoProgress();
|
||||
}
|
||||
|
||||
public void UILoaded(UIPanelType uiPanelType)
|
||||
{
|
||||
if (uiPanelType != UIPanelType.PlayerScoreCounter) return;
|
||||
|
||||
Context.UIService.OpenPanel(UIPanelType.PlayerScoreCounter);
|
||||
_gameplayLoading.DoProgress();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,9 @@ namespace Code.Infrastructure.Audio
|
||||
[ToConfig] public int id;
|
||||
[ToConfig] public AssetReference fileReference;
|
||||
}
|
||||
[Config("Configs/Audio/AudioServiceSettings")]
|
||||
public class AudioServiceSettings
|
||||
[Config("Configs/Audio/AudioSourceSettings")]
|
||||
public class AudioSourcePrefab
|
||||
{
|
||||
[ToConfig] public AssetReference sourcePrefab;
|
||||
[ToConfig] public AssetReference mixerPrefab;
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@ namespace Code.Infrastructure.Audio
|
||||
|
||||
UniTaskVoid PlayRepeatedly(AudioNames groupName, int id,
|
||||
CancellationTokenSource cancellationTokenSource, AudioSourceType sourceType = AudioSourceType.NoBlend, AudioSource audioSource = null);
|
||||
|
||||
bool CheckClip(AudioNames groupName, int id);
|
||||
}
|
||||
|
||||
public partial class AudioService : IAudioClipsEventHandle, IAudioService
|
||||
@@ -40,7 +42,7 @@ namespace Code.Infrastructure.Audio
|
||||
for (int i = 0; i < typeof(AudioNames).GetEnumValues().Length; i++)
|
||||
_audioClips.Add((AudioNames)i, new Dictionary<int, AudioClip>());
|
||||
|
||||
InitializeMixer();
|
||||
//InitializeMixer();
|
||||
}
|
||||
|
||||
private partial void InitializeMixer();
|
||||
@@ -53,6 +55,8 @@ namespace Code.Infrastructure.Audio
|
||||
AudioSourceType sourceType = AudioSourceType.NoBlend,
|
||||
AudioSource audioSource = null)
|
||||
{
|
||||
if (!CheckClip(groupName, id)) return;
|
||||
|
||||
if (!audioSource) audioSource = _pool.GetSource(sourceType);
|
||||
|
||||
audioSource.transform.position = position;
|
||||
@@ -67,6 +71,8 @@ namespace Code.Infrastructure.Audio
|
||||
public async UniTaskVoid PlayRepeatedly(AudioNames groupName, int id,
|
||||
CancellationTokenSource cancellationTokenSource, AudioSourceType sourceType = AudioSourceType.NoBlend, AudioSource audioSource = null)
|
||||
{
|
||||
if (!CheckClip(groupName, id)) return;
|
||||
|
||||
if (!audioSource) audioSource = _pool.GetSource(sourceType);
|
||||
if(!audioSource.resource) audioSource.resource = GetClip(groupName, id);
|
||||
|
||||
@@ -91,6 +97,7 @@ namespace Code.Infrastructure.Audio
|
||||
}
|
||||
|
||||
public AudioClip GetClip(AudioNames groupName, int id) => _audioClips[groupName][id];
|
||||
public bool CheckClip(AudioNames groupName, int id) => _audioClips[groupName].ContainsKey(id);
|
||||
|
||||
public void AudioClipsLoaded(AudioNames groupname, Dictionary<int, AudioClip> clips)
|
||||
{
|
||||
@@ -100,6 +107,7 @@ namespace Code.Infrastructure.Audio
|
||||
|
||||
public void AudioClipsUnLoaded(AudioNames groupName)
|
||||
{
|
||||
_audioClips[groupName].Clear();
|
||||
_audioClips[groupName] = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Code.Infrastructure.Audio
|
||||
private string _configsLabel;
|
||||
private AsyncOperationHandle<IList<AudioSourceSettingsConfig>> _handles;
|
||||
private AssetReference _sourcePrefabConfigReference;
|
||||
private AsyncOperationHandle<AudioServiceSettingsConfig> _prefabConfigHandle;
|
||||
private AsyncOperationHandle<AudioSourcePrefabConfig> _prefabConfigHandle;
|
||||
private AsyncOperationHandle<GameObject> _prefabHandle;
|
||||
private EventBus.EventBus _eventBus;
|
||||
|
||||
@@ -42,14 +42,14 @@ namespace Code.Infrastructure.Audio
|
||||
_eventBus = eventBus;
|
||||
|
||||
_configsLabel = configLocator.TryGetManyConfigAssetReferences<AudioSourceSettingsConfig>();
|
||||
_sourcePrefabConfigReference = configLocator.TryGetConfigAssetReference<AudioServiceSettingsConfig>();
|
||||
_sourcePrefabConfigReference = configLocator.TryGetConfigAssetReference<AudioSourcePrefabConfig>();
|
||||
|
||||
LoadConfigs().Forget();
|
||||
}
|
||||
|
||||
private async UniTaskVoid LoadConfigs()
|
||||
{
|
||||
_prefabConfigHandle = Addressables.LoadAssetAsync<AudioServiceSettingsConfig>(_sourcePrefabConfigReference);
|
||||
_prefabConfigHandle = Addressables.LoadAssetAsync<AudioSourcePrefabConfig>(_sourcePrefabConfigReference);
|
||||
_handles = Addressables.LoadAssetsAsync<AudioSourceSettingsConfig>(_configsLabel);
|
||||
|
||||
await UniTask.WhenAll(
|
||||
@@ -102,58 +102,7 @@ namespace Code.Infrastructure.Audio
|
||||
{
|
||||
Object.Destroy(source.gameObject);
|
||||
}
|
||||
//
|
||||
// public async UniTaskVoid PlayOneShot(AudioClip clip, Vector3 position, AudioMixerGroup audioMixerGroup, AudioSourceType audioSourceType = AudioSourceType.NoBlend, Action onComplete = null)
|
||||
// {
|
||||
// AudioSource source = _pool.Get();
|
||||
// source.PlayOneShot(clip);
|
||||
// source.spatialBlend = _settings[audioSourceType].spatialBlend;
|
||||
// source.transform.position = position;
|
||||
// source.outputAudioMixerGroup = audioMixerGroup;
|
||||
//
|
||||
// await UniTask.WaitUntilValueChanged(source, x => x.isPlaying);
|
||||
// onComplete?.Invoke();
|
||||
// _pool.Release(source);
|
||||
// }
|
||||
// public async UniTaskVoid PlayOneShot(AudioClip clip, AudioMixerGroup audioMixerGroup, AudioSourceType audioSourceType = AudioSourceType.NoBlend, Action onComplete = null)
|
||||
// {
|
||||
// AudioSource source = _pool.Get();
|
||||
// source.PlayOneShot(clip);
|
||||
// source.spatialBlend = _settings[audioSourceType].spatialBlend;
|
||||
// source.outputAudioMixerGroup = audioMixerGroup;
|
||||
//
|
||||
// await UniTask.WaitUntilValueChanged(source, x => x.isPlaying);
|
||||
// onComplete?.Invoke();
|
||||
// _pool.Release(source);
|
||||
// }
|
||||
// public async UniTaskVoid PlayOneShot(AudioSource audioSource, AudioClip clip, AudioMixerGroup audioMixerGroup, AudioSourceType audioSourceType = AudioSourceType.NoBlend, Action onComplete = null)
|
||||
// {
|
||||
// audioSource.PlayOneShot(clip);
|
||||
// audioSource.spatialBlend = _settings[audioSourceType].spatialBlend;
|
||||
// audioSource.outputAudioMixerGroup = audioMixerGroup;
|
||||
//
|
||||
// // TODO Потом сделать. Можно с cancellation, но сейчас лень. Ну правда
|
||||
// await UniTask.WaitUntilValueChanged(audioSource, x => x.isPlaying);
|
||||
//
|
||||
// if (!audioSource) return;
|
||||
//
|
||||
// _pool.Release(audioSource);
|
||||
// onComplete?.Invoke();
|
||||
// }
|
||||
// public async UniTaskVoid PlayOneShot(AudioClip clip, AudioMixerGroup audioMixerGroup, CancellationTokenSource cancellationToken, AudioSourceType audioSourceType = AudioSourceType.NoBlend, Action onComplete = null)
|
||||
// {
|
||||
// AudioSource source = _pool.Get();
|
||||
// source.PlayOneShot(clip);
|
||||
// source.spatialBlend = _settings[audioSourceType].spatialBlend;
|
||||
// source.outputAudioMixerGroup = audioMixerGroup;
|
||||
//
|
||||
// var (isCanceled, _) = await UniTask.WaitUntilValueChanged(source, x => x.isPlaying, cancellationToken: cancellationToken.Token).SuppressCancellationThrow();
|
||||
//
|
||||
// _pool.Release(source);
|
||||
//
|
||||
// if(!isCanceled) onComplete?.Invoke();
|
||||
// else cancellationToken.Dispose();
|
||||
// }
|
||||
|
||||
public AudioSource GetSource(AudioSourceType sourceType)
|
||||
{
|
||||
var source = _pool.Get();
|
||||
|
||||
@@ -10,9 +10,7 @@ namespace Code.Infrastructure.Camera
|
||||
public enum CameraMode
|
||||
{
|
||||
None,
|
||||
FirstPerson,
|
||||
Static,
|
||||
Cinematic
|
||||
ThirdPerson
|
||||
}
|
||||
|
||||
[Config("Configs/Camera/CameraConfig")]
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class RacingCamera : MonoBehaviour
|
||||
{
|
||||
public enum CameraMode
|
||||
{
|
||||
Follow,
|
||||
Orbit,
|
||||
Hood,
|
||||
Bumper
|
||||
}
|
||||
|
||||
[Header("Target")]
|
||||
public Transform carTarget;
|
||||
public Rigidbody carRigidbody;
|
||||
|
||||
[Header("Camera Mode")]
|
||||
public CameraMode currentMode = CameraMode.Follow;
|
||||
public KeyCode switchKey = KeyCode.C;
|
||||
|
||||
[Header("Follow Mode Settings")]
|
||||
public Vector3 followOffset = new Vector3(0, 3, -8);
|
||||
public float followSmoothTime = 0.1f;
|
||||
|
||||
[Header("Orbit Mode Settings")]
|
||||
public float orbitDistance = 10f;
|
||||
public float orbitHeight = 3f;
|
||||
public float orbitSpeed = 2f;
|
||||
private float orbitAngle = 0f;
|
||||
|
||||
[Header("First Person Settings")]
|
||||
public Transform hoodCameraPosition;
|
||||
public Transform bumperCameraPosition;
|
||||
|
||||
[Header("Look Settings")]
|
||||
public float lookAheadDistance = 5f;
|
||||
public Vector3 lookAtOffset = new Vector3(0, 1.5f, 0);
|
||||
|
||||
private Vector3 velocity = Vector3.zero;
|
||||
private Camera cam;
|
||||
|
||||
void Start()
|
||||
{
|
||||
cam = GetComponent<Camera>();
|
||||
if (carRigidbody == null && carTarget != null)
|
||||
carRigidbody = carTarget.GetComponent<Rigidbody>();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// Переключение режимов камеры
|
||||
if (Input.GetKeyDown(switchKey))
|
||||
{
|
||||
SwitchCameraMode();
|
||||
}
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if (carTarget == null) return;
|
||||
|
||||
switch (currentMode)
|
||||
{
|
||||
case CameraMode.Follow:
|
||||
UpdateFollowCamera();
|
||||
break;
|
||||
|
||||
case CameraMode.Orbit:
|
||||
UpdateOrbitCamera();
|
||||
break;
|
||||
|
||||
case CameraMode.Hood:
|
||||
UpdateFirstPersonCamera(hoodCameraPosition);
|
||||
break;
|
||||
|
||||
case CameraMode.Bumper:
|
||||
UpdateFirstPersonCamera(bumperCameraPosition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SwitchCameraMode()
|
||||
{
|
||||
currentMode = (CameraMode)(((int)currentMode + 1) % 4);
|
||||
Debug.Log("Camera mode: " + currentMode);
|
||||
}
|
||||
|
||||
void UpdateFollowCamera()
|
||||
{
|
||||
// Рассчитываем позицию с учетом скорости
|
||||
Vector3 targetPosition = CalculateFollowPosition();
|
||||
|
||||
// Плавное перемещение
|
||||
transform.position = Vector3.SmoothDamp(
|
||||
transform.position,
|
||||
targetPosition,
|
||||
ref velocity,
|
||||
followSmoothTime
|
||||
);
|
||||
|
||||
// Направление взгляда с опережением
|
||||
Vector3 lookTarget = carTarget.position +
|
||||
carTarget.forward * lookAheadDistance +
|
||||
lookAtOffset;
|
||||
|
||||
transform.LookAt(lookTarget);
|
||||
}
|
||||
|
||||
Vector3 CalculateFollowPosition()
|
||||
{
|
||||
Vector3 basePosition = carTarget.position +
|
||||
carTarget.TransformDirection(followOffset);
|
||||
|
||||
// Динамическое смещение на основе скорости
|
||||
if (carRigidbody != null)
|
||||
{
|
||||
float speedFactor = Mathf.Clamp01(carRigidbody.linearVelocity.magnitude / 50f);
|
||||
Vector3 speedOffset = carTarget.forward * speedFactor * -3f;
|
||||
basePosition += speedOffset;
|
||||
}
|
||||
|
||||
return basePosition;
|
||||
}
|
||||
|
||||
void UpdateOrbitCamera()
|
||||
{
|
||||
// Автоматическое вращение вокруг машины
|
||||
orbitAngle += orbitSpeed * Time.deltaTime;
|
||||
|
||||
// Рассчитываем позицию по окружности
|
||||
float x = Mathf.Sin(orbitAngle) * orbitDistance;
|
||||
float z = Mathf.Cos(orbitAngle) * orbitDistance;
|
||||
|
||||
Vector3 orbitPosition = carTarget.position +
|
||||
new Vector3(x, orbitHeight, z);
|
||||
|
||||
transform.position = orbitPosition;
|
||||
transform.LookAt(carTarget.position + lookAtOffset);
|
||||
}
|
||||
|
||||
void UpdateFirstPersonCamera(Transform cameraPosition)
|
||||
{
|
||||
if (cameraPosition == null)
|
||||
{
|
||||
// Резервная позиция
|
||||
transform.position = carTarget.position +
|
||||
carTarget.forward * 1f +
|
||||
Vector3.up * 1.5f;
|
||||
transform.rotation = carTarget.rotation;
|
||||
return;
|
||||
}
|
||||
|
||||
transform.position = cameraPosition.position;
|
||||
transform.rotation = cameraPosition.rotation;
|
||||
|
||||
// Добавляем небольшую тряску на скорости
|
||||
if (carRigidbody != null)
|
||||
{
|
||||
float shakeAmount = carRigidbody.linearVelocity.magnitude * 0.001f;
|
||||
transform.position += Random.insideUnitSphere * shakeAmount;
|
||||
}
|
||||
}
|
||||
|
||||
// Визуализация в редакторе
|
||||
void OnDrawGizmosSelected()
|
||||
{
|
||||
if (carTarget != null)
|
||||
{
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.DrawWireSphere(carTarget.position + lookAtOffset, 0.5f);
|
||||
Gizmos.DrawLine(transform.position, carTarget.position + lookAtOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1a6cd725a6ce4cc0b50b8a04be749bd1
|
||||
timeCreated: 1770228499
|
||||
@@ -18,7 +18,7 @@ namespace Code.Infrastructure.Camera.CameraStates
|
||||
protected override void OnExitState()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
protected override void HandlePosition(float deltaTime, object targetRotation)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
using Code.Infrastructure.Generators;
|
||||
using DG.Tweening;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.Infrastructure.Camera.CameraStates
|
||||
{
|
||||
[State(typeof(CameraMode),typeof(CameraStateMachineContext), true)]
|
||||
public partial class ThirdPersonState : BaseCameraState
|
||||
{
|
||||
public ThirdPersonState(CameraStateMachineContext context, EventBus.EventBus eventBus) : base(context, eventBus)
|
||||
{
|
||||
}
|
||||
|
||||
public override CameraMode myState => CameraMode.ThirdPerson;
|
||||
protected override void OnEnterState()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnExitState()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void HandleRotationInput(float deltaTime, Vector3 rotationInput, out Quaternion q)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
private Transform _carTarget;
|
||||
private Rigidbody _carRigidbody;
|
||||
|
||||
public void SetFollowTarget(Transform carTarget, Rigidbody carRigidbody)
|
||||
{
|
||||
_carTarget = carTarget;
|
||||
_carRigidbody = carRigidbody;
|
||||
}
|
||||
|
||||
private Vector3 _lookAtOffset = new Vector3(0, 1.5f, 0);
|
||||
protected override void HandlePosition(float deltaTime, object targetRotation)
|
||||
{
|
||||
Fuck();
|
||||
}
|
||||
|
||||
private void Fuck()
|
||||
{
|
||||
// Автоматическое вращение вокруг машины
|
||||
Vector3 targetPosition = CalculateFollowPosition();
|
||||
|
||||
// Плавное перемещение
|
||||
|
||||
Vector3 velocity = _carRigidbody ? _carRigidbody.linearVelocity : new Vector3();
|
||||
// Context.cameraLoadedData.Camera.transform.DOMove(targetPosition,
|
||||
// Context.cameraLoadedData.SettingsConfigs[CameraMode.ThirdPerson].followSharpness);
|
||||
Context.cameraLoadedData.Camera.transform.position = Vector3.SmoothDamp(
|
||||
Context.cameraLoadedData.Camera.transform.position,
|
||||
targetPosition,
|
||||
ref velocity,
|
||||
Context.cameraLoadedData.SettingsConfigs[CameraMode.ThirdPerson].followSharpness
|
||||
);
|
||||
|
||||
// Направление взгляда с опережением
|
||||
Vector3 lookTarget = _carTarget.position +
|
||||
_carTarget.forward * Context.cameraLoadedData.SettingsConfigs[CameraMode.ThirdPerson].defaultDistance +
|
||||
_lookAtOffset;
|
||||
|
||||
Context.cameraLoadedData.Camera.transform.LookAt(lookTarget);
|
||||
}
|
||||
|
||||
private Vector3 _followOffset = new Vector3(0, 3, -8);
|
||||
|
||||
private Vector3 CalculateFollowPosition()
|
||||
{
|
||||
Vector3 basePosition = _carTarget.position +
|
||||
_carTarget.TransformDirection(_followOffset);
|
||||
|
||||
// Динамическое смещение на основе скорости
|
||||
if (!_carRigidbody) return basePosition;
|
||||
|
||||
var speedFactor = Mathf.Clamp01(_carRigidbody.linearVelocity.magnitude / 50f);
|
||||
var speedOffset = _carTarget.forward * (speedFactor * -3f);
|
||||
basePosition += speedOffset;
|
||||
|
||||
return basePosition;
|
||||
}
|
||||
public override void Update()
|
||||
{
|
||||
}
|
||||
|
||||
public override void LateUpdate()
|
||||
{
|
||||
Fuck();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 817473133bf54c7aab1ea3e093561e8e
|
||||
timeCreated: 1770227852
|
||||
@@ -31,6 +31,7 @@ using Code.Infrastructure.EventBus;
|
||||
public interface IOn{member.Name}SceneLoadedHandler : IGlobalSubscriber
|
||||
{{
|
||||
void On{member.Name}SceneLoaded();
|
||||
void On{member.Name}SceneInitialized(Reflex.Core.Container container); // Until its fixed
|
||||
}}
|
||||
";
|
||||
dictionaryCode += $@"
|
||||
|
||||
@@ -4,9 +4,9 @@ using Code.Infrastructure.Configs;
|
||||
using Code.Infrastructure.EventBus;
|
||||
using Code.Infrastructure.Generators;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Code.Infrastructure.SceneLoader
|
||||
@@ -37,15 +37,19 @@ namespace Code.Infrastructure.SceneLoader
|
||||
// TODO типилище
|
||||
public async UniTaskVoid LoadSceneAsync(SceneId id, LoadSceneMode loadMode)
|
||||
{
|
||||
await Addressables.LoadSceneAsync(_sceneInfos[id].SceneAsset, loadMode);
|
||||
_loadedScenes.Add(id,Addressables.LoadSceneAsync(_sceneInfos[id].SceneAsset, loadMode));
|
||||
|
||||
await _loadedScenes[id];
|
||||
|
||||
_scenesActions[id]();
|
||||
}
|
||||
|
||||
private Dictionary<SceneId, AsyncOperationHandle<SceneInstance>> _loadedScenes = new();
|
||||
public Scene GetScene(SceneId id) => _loadedScenes[id].Result.Scene;
|
||||
public async UniTaskVoid UnloadSceneAsync(SceneId id)
|
||||
{
|
||||
// TODO НЕВОЗМОЖНО ВЫГРУЗИТЬ БЛЯДСКИЕ СЦЕНЫ
|
||||
// await Addressables.UnloadSceneAsync(_sceneInfos[])
|
||||
await Addressables.UnloadSceneAsync(_loadedScenes[id]);
|
||||
_loadedScenes.Remove(id);
|
||||
}
|
||||
|
||||
private AsyncOperationHandle<IList<SceneInfoConfig>> _configHandle;
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Code.Infrastructure.UI
|
||||
Logo,
|
||||
Loading,
|
||||
DebugSceneChooser,
|
||||
PlayerScoreCounter,
|
||||
DebugMenu
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user