ИИ гонщиков, запуск, перезапуск игры и пр

This commit is contained in:
ThomasCharester committed 2026-02-09 16:22:37 +03:00
1 parent f557c58c9d
commit efcfaae647
48 files changed
+1486 -212

No files matched your search

+9 -12
View File
@@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Code.Example.Race.Racer;
using Code.Example.Race.Track;
using Code.Infrastructure.EventBus;
using Code.Infrastructure.Loadings;
using Reflex.Attributes;
using Code.Infrastructure.Loadings;
namespace Code.Example.Race
{
@@ -52,7 +52,7 @@ namespace Code.Example.Race
}
private void RacersLoadCompleted() =>
_eventBus.RaiseEvent<IRaceGameInitializedHandle>(x => x.RaceGameReady());
_eventBus.RaiseEvent<IRaceGameHandle>(x => x.RaceGameReady());
public List<Racer.Racer> PlacedRacers { get; } = new();
@@ -70,7 +70,7 @@ namespace Code.Example.Race
foreach (var racer in PlacedRacers)
{
racer.Initialize(_raceTrackData.trackData.Checkpoints);
racer.Initialize(_raceTrackData.trackData.Checkpoints.Select(x=> x.transform).ToList());
}
}
@@ -84,23 +84,20 @@ namespace Code.Example.Race
_raceGameLoading.DoProgress();
}
// private Dictionary<RacerType, Racer.AI.Racer> _spawnedRacers = new();
public void RacerCreated(RacerType type, Racer.Racer racer)
{
// _spawnedRacers.Add(type, racer);
// _raceGameLoading.DoProgress();
}
public void Dispose()
{
foreach (var racer in PlacedRacers) _scores.UnsubscribeRacer(racer);
_eventBus.Unsubscribe(this);
_racerPrefabs.Clear();
}
}
public interface IRaceGameInitializedHandle : IGlobalSubscriber
public interface IRaceGameHandle : IGlobalSubscriber
{
void RaceGameReady();
void RaceGameEnded(RaceScores scores);
}
}
+37 -9
View File
@@ -1,14 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Code.Example.Race.Racer.Player;
using Code.Example.Race.Track;
using Code.Infrastructure.EventBus;
using Reflex.Attributes;
namespace Code.Example.Race
{
public class RaceScores : IRacerPassedCheckpointHandler, IDisposable
public class RaceScores : IRacerPassedCheckpointHandler, IDisposable, IPlayerPassedCheckpointHandler
{
private Dictionary<Racer.Racer, int> _scores = new();
private Dictionary<Racer.Racer, ScoreData> _scores = new();
private EventBus _eventBus;
public RaceScores(EventBus eventBus)
@@ -16,25 +18,34 @@ namespace Code.Example.Race
_eventBus = eventBus;
_eventBus.Subscribe(this);
}
public void SubscribeRacer(Racer.Racer racer)
{
_scores.Add(racer, 0);
_scores.Add(racer, new ScoreData());
}
public void ChangeScore(Racer.Racer racer, int additionalScore)
{
_scores[racer] += additionalScore;
_eventBus.RaiseEvent<IScoreChangedHandle>(x=> x.ScoreChanged(racer,additionalScore, GetScores()));
_scores[racer].checkpointsPassed += additionalScore;
_eventBus.RaiseEvent<IScoreChangedHandle>(x=> x.ScoreChanged(racer,_scores[racer], GetScores()));
}
public void LapPassed(Racer.Racer racer)
{
_scores[racer].lapsPassed++;
_eventBus.RaiseEvent<IScoreChangedHandle>(x=> x.ScoreChanged(racer,_scores[racer], GetScores()));
if (_scores[racer].lapsPassed >= _raceTrackData.trackData.LapCount)
_eventBus.RaiseEvent<IRaceGameHandle>(x=> x.RaceGameEnded(this));
}
public void UnsubscribeRacer(Racer.Racer racer)
{
_scores.Remove(racer);
}
public List<KeyValuePair<Racer.Racer, int>> GetScores()
public List<KeyValuePair<Racer.Racer, ScoreData>> GetScores()
{
return _scores.OrderByDescending(x => x.Value).ToList();
return _scores.OrderByDescending(x => x.Value.checkpointsPassed).ToList();
}
public void OnRacerPassedCheckpoint(Racer.Racer racer) => ChangeScore(racer,1);
@@ -43,10 +54,27 @@ namespace Code.Example.Race
{
_eventBus.Unsubscribe(this);
}
[Inject] private RaceTrackData _raceTrackData;
public void OnPlayerPassedCheckpoint(Racer.Racer racer)
{
var player = (PlayerRacer)racer;
_raceTrackData.trackData.Checkpoints[player.CurrentWaypointIndex].Show();
}
public void OnPlayerLapPassed(Racer.Racer racer)
{
}
}
public class ScoreData
{
public int checkpointsPassed;
public int lapsPassed;
}
public interface IScoreChangedHandle : IGlobalSubscriber
{
void ScoreChanged(Racer.Racer racer, int additionalScore, List<KeyValuePair<Racer.Racer, int>> scores);
void ScoreChanged(Racer.Racer racer, ScoreData score, List<KeyValuePair<Racer.Racer, ScoreData>> scores);
}
}
@@ -0,0 +1,12 @@
using UnityEngine;
namespace Code.Example.Race.Racer.AI
{
public class AICarDriver : CarControllerRB
{
public override void SetSteering(Vector2 steeringLinear)
{
SteeringInput = steeringLinear;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c82b0db1441e417098bccb9ca1575e3e
timeCreated: 1770639201
+35 -24
View File
@@ -1,11 +1,16 @@
using System.Collections.Generic;
using Code.Example.Race.Racer.AI.ID;
using Code.Example.Race.Track;
using Code.Infrastructure.EventBus;
using Reflex.Attributes;
using UnityEngine;
namespace Code.Example.Race.Racer.AI
{
public class AIRacerID : Racer
{
[Inject] private EventBus _eventBus;
[SerializeField] private CarControllerRB carController;
public override void SetData(RacerData data)
{
Data = data;
@@ -21,9 +26,10 @@ namespace Code.Example.Race.Racer.AI
public override void NextWaypoint()
{
if(CurrentWaypointIndex >= Waypoints.Count) CurrentWaypointIndex = 0;
if (++CurrentWaypointIndex < Waypoints.Count) return;
CurrentWaypointIndex++;
CurrentWaypointIndex = 0;
_eventBus.RaiseEvent<IRacerPassedCheckpointHandler>(x=> x.LapPassed(this));
}
public override void StartRacer()
@@ -66,33 +72,38 @@ namespace Code.Example.Race.Racer.AI
{
if (!_running) return;
var displacement = _velocity * Time.deltaTime;
_orientation += _rotation * Time.deltaTime;
_orientation = NormalizeAngle(_orientation);
var steering =
transform.InverseTransformDirection(
agent.GetSteering(Waypoints[CurrentWaypointIndex]).linear);
transform.Translate(displacement, Space.World);
transform.Rotate(Vector3.up, _orientation);
carController.SetSteering(new Vector2(steering.x, steering.z));
// var displacement = _velocity * Time.deltaTime;
// _orientation += _rotation * Time.deltaTime;
// _orientation = NormalizeAngle(_orientation);
//
// transform.Translate(displacement, Space.World);
// transform.Rotate(Vector3.up, _orientation);
}
public virtual void LateUpdate()
{
if (!_running) return;
_steering = agent.GetSteering(Waypoints[CurrentWaypointIndex]);
_velocity += _steering.linear * Time.deltaTime;
_rotation += _steering.angular * Time.deltaTime;
if (_velocity.magnitude > Data.speed)
{
_velocity = _velocity.normalized * Data.speed;
}
if (_steering.angular == 0.0f)
{
_rotation = 0.0f;
}
if (_steering.linear.sqrMagnitude == 0.0f)
{
_velocity = Vector3.zero;
}
//
// _steering = agent.GetSteering(Waypoints[CurrentWaypointIndex]);
//
// _velocity += _steering.linear * Time.deltaTime;
// _rotation += _steering.angular * Time.deltaTime;
// if (_velocity.magnitude > Data.speed)
// {
// _velocity = _velocity.normalized * Data.speed;
// }
// if (_steering.angular == 0.0f)
// {
// _rotation = 0.0f;
// }
// if (_steering.linear.sqrMagnitude == 0.0f)
// {
// _velocity = Vector3.zero;
// }
}
}
}
@@ -16,11 +16,6 @@ namespace Code.Example.Race.Racer.AI.ID
velocity = Vector3.zero;
steering = new Steering();
}
public void SetSteering(Steering steering)
{
this.steering = steering;
}
public virtual void Update ()
{
Vector3 displacement = velocity * Time.deltaTime;
@@ -9,8 +9,10 @@ namespace Code.Example.Race.Racer.AI.ID.Behaviours
Steering steering = new Steering();
steering.linear = target.position - transform.position;
UnityEngine.Debug.DrawRay(transform.position, steering.linear, Color.yellow, 5f);
// steering.linear *= agent.Data.maxAcceleration;
steering.linear.Normalize();
steering.linear *= agent.Data.maxAcceleration;
UnityEngine.Debug.Log(steering.linear);
return steering;
}
}
@@ -1,11 +1,10 @@
using UnityEngine;
using System;
using System.Collections.Generic;
using Code.Example.Race.Racer.AI;
using UnityEngine;
namespace Code.Example.Race.Racer.Player
namespace Code.Example.Race.Racer
{
public class PlayerCarControllerRB : MonoBehaviour
public abstract class CarControllerRB : MonoBehaviour
{
public enum ControlMode
{
@@ -35,30 +34,31 @@ namespace Code.Example.Race.Racer.Player
public List<Wheel> wheels;
private Rigidbody carRb;
[SerializeField] private PlayerCarInput _playerCarInput;
[SerializeField] private PlayerRacer _playerRacer;
protected Rigidbody CarRb;
protected Vector2 SteeringInput = Vector2.zero;
public abstract void SetSteering(Vector2 steeringLinear);
[SerializeField] protected Racer racer;
// private CarLights carLights;
void Start()
private void Start()
{
carRb = GetComponent<Rigidbody>();
carRb.centerOfMass = _centerOfMass;
CarRb = GetComponent<Rigidbody>();
CarRb.centerOfMass = _centerOfMass;
// carLights = GetComponent<CarLights>();
}
void Update()
protected virtual void Update()
{
// GetInputs();
AnimateWheels();
// WheelEffects();
}
void FixedUpdate()
private void FixedUpdate()
{
Move();
Steer();
@@ -84,51 +84,54 @@ namespace Code.Example.Race.Racer.Player
// }
}
void Move()
private void Move()
{
foreach (var wheel in wheels)
{
wheel.wheelCollider.motorTorque = _playerCarInput.MovementInput.y * 600 * _playerRacer.Data.maxAcceleration * Time.fixedDeltaTime;
wheel.wheelCollider.motorTorque = SteeringInput.y * 600 * racer.Data.maxAcceleration * Time.fixedDeltaTime;
// wheel.wheelCollider.motorTorque = _playerCarInput.MovementInput.y * 600 * _playerRacer.Data.maxAcceleration * Time.fixedDeltaTime;
}
}
void Steer()
private void Steer()
{
foreach (var wheel in wheels)
{
if (wheel.axel != Axel.Front) continue;
var _steerAngle = _playerCarInput.MovementInput.x * _playerRacer.Data.turnSensitivity * _playerRacer.Data.maxSteerAngle;
wheel.wheelCollider.steerAngle = _steerAngle;
var steerAngle = SteeringInput.x * racer.Data.turnSensitivity * racer.Data.maxSteerAngle;
// var _steerAngle = _playerCarInput.MovementInput.x * _playerRacer.Data.turnSensitivity * _playerRacer.Data.maxSteerAngle;
wheel.wheelCollider.steerAngle = steerAngle;
// wheel.wheelCollider.steerAngle = Mathf.Lerp(wheel.wheelCollider.steerAngle, _steerAngle, 0.6f);
}
}
void Brake()
protected virtual void Brake()
{
if (_playerCarInput.Brake || _playerCarInput.MovementInput.y == 0)
{
foreach (var wheel in wheels)
{
wheel.wheelCollider.brakeTorque = 300 * _playerRacer.Data.brakeAcceleration * Time.fixedDeltaTime;
}
// carLights.isBackLightOn = true;
// carLights.OperateBackLights();
}
else
{
foreach (var wheel in wheels)
{
wheel.wheelCollider.brakeTorque = 0;
}
// carLights.isBackLightOn = false;
// carLights.OperateBackLights();
}
//|| _playerCarInput.MovementInput.y == 0
// if (_playerCarInput.Brake )
// {
// foreach (var wheel in wheels)
// {
// wheel.wheelCollider.brakeTorque = 300 * _racer.Data.brakeAcceleration * Time.fixedDeltaTime;
// }
//
// // carLights.isBackLightOn = true;
// // carLights.OperateBackLights();
// }
// else
// {
// foreach (var wheel in wheels)
// {
// wheel.wheelCollider.brakeTorque = 0;
// }
//
// // carLights.isBackLightOn = false;
// // carLights.OperateBackLights();
// }
}
void AnimateWheels()
private void AnimateWheels()
{
foreach (var wheel in wheels)
{
@@ -140,14 +143,14 @@ namespace Code.Example.Race.Racer.Player
}
}
void WheelEffects()
private void WheelEffects()
{
foreach (var wheel in wheels)
{
//var dirtParticleMainSettings = wheel.smokeParticle.main;
if (wheel.axel == Axel.Rear && wheel.wheelCollider.isGrounded &&
carRb.linearVelocity.magnitude >= 10.0f)
CarRb.linearVelocity.magnitude >= 10.0f)
{
// wheel.wheelEffectObj.GetComponentInChildren<TrailRenderer>().emitting = true;
// wheel.smokeParticle.Emit(1);
@@ -0,0 +1,44 @@
using UnityEngine;
namespace Code.Example.Race.Racer.Player
{
public class PlayerRBCarController : CarControllerRB
{
[SerializeField] private PlayerCarInput playerCarInput;
public override void SetSteering(Vector2 steeringLinear)
{
}
protected override void Update()
{
SteeringInput = playerCarInput.MovementInput;
base.Update();
}
protected override void Brake()
{
if (playerCarInput.Brake )
{
foreach (var wheel in wheels)
{
wheel.wheelCollider.brakeTorque = 300 * racer.Data.brakeAcceleration * Time.fixedDeltaTime;
}
// carLights.isBackLightOn = true;
// carLights.OperateBackLights();
}
else
{
foreach (var wheel in wheels)
{
wheel.wheelCollider.brakeTorque = 0;
}
// carLights.isBackLightOn = false;
// carLights.OperateBackLights();
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bad2326aa0f24acb9bdfeb5fb7d3d208
timeCreated: 1770640123
@@ -1,10 +1,15 @@
using System.Collections.Generic;
using Code.Example.Race.Track;
using Code.Infrastructure.EventBus;
using Reflex.Attributes;
using UnityEngine;
namespace Code.Example.Race.Racer.Player
{
public class PlayerRacer : Racer
{
[Inject] private EventBus _eventBus;
public Transform CameraPosition;
public override void SetData(RacerData data)
{
@@ -13,21 +18,26 @@ namespace Code.Example.Race.Racer.Player
public override void Initialize(List<Transform> waypoints)
{
Waypoints = waypoints;
}
public override void NextWaypoint()
{
if (++CurrentWaypointIndex < Waypoints.Count) return;
CurrentWaypointIndex = 0;
_eventBus.RaiseEvent<IPlayerPassedCheckpointHandler>(x=> x.OnPlayerLapPassed(this));
_eventBus.RaiseEvent<IRacerPassedCheckpointHandler>(x=> x.LapPassed(this));
}
public bool RaceStarted { get; set; }
public override void StartRacer()
{
RaceStarted = true;
}
public override void StopRacer()
{
RaceStarted = false;
}
}
}
+2 -1
View File
@@ -6,7 +6,8 @@ namespace Code.Example.Race.Racer
public abstract class Racer : MonoBehaviour
{
protected List<Transform> Waypoints;
protected int CurrentWaypointIndex;
public int CurrentWaypointIndex { get; protected set; }
public RacerData Data { get; protected set; }
public int Id { get; set; }
public abstract void SetData(RacerData data);
@@ -56,8 +56,8 @@ namespace Code.Example.Race.Racer
_eventBus.RaiseEvent<IRacerLoadedHandle>(x => x.RacerLoaded(racerType, null));
return;
}
}
UnityEngine.Debug.LogWarning($"Racer loaded {racerType}");
_racerPrefabsHandle.Add(racerType,
Addressables.LoadAssetAsync<GameObject>(_racerConfigs[racerType].prefabReference));
@@ -76,8 +76,10 @@ namespace Code.Example.Race.Racer
public void Dispose()
{
UnityEngine.Debug.LogWarning($"Racers released");
foreach (var prefab in _racerPrefabsHandle)
prefab.Value.Release();
_racerPrefabsHandle.Clear();
_racerConfigsHandle.Release();
}
@@ -90,7 +92,6 @@ namespace Code.Example.Race.Racer
public interface IRacerLoadedHandle : IGlobalSubscriber
{
public void RacerLoaded(RacerType type, Racer racer);
public void RacerCreated(RacerType type, Racer racer);
public void RacerLoaded(RacerType type, Racer racer);
}
}
+22 -2
View File
@@ -1,24 +1,44 @@
using Code.Example.Race.Racer.AI;
using Code.Example.Race.Racer;
using Code.Infrastructure.EventBus;
using Reflex.Attributes;
using UnityEngine;
using UnityEngine;
namespace Code.Example.Race.Track
{
public class CheckPoint : MonoBehaviour
{
[Inject] private EventBus _eventBus;
[SerializeField] private GameObject _checkPointMesh;
[SerializeField] private int _id; // Костыль инвалид лестница
private void OnTriggerEnter(Collider other)
{
var racer = other.GetComponent<Racer.Racer>();
if (racer.CurrentWaypointIndex != _id) return;
racer.NextWaypoint();
if (racer.Data.type == RacerType.Player)
{
Hide();
_eventBus.RaiseEvent<IPlayerPassedCheckpointHandler>(h => h.OnPlayerPassedCheckpoint(racer));
}
_eventBus.RaiseEvent<IRacerPassedCheckpointHandler>(h => h.OnRacerPassedCheckpoint(racer));
}
public void Hide() => _checkPointMesh.SetActive(false);
public void Show() => _checkPointMesh.SetActive(true);
}
public interface IRacerPassedCheckpointHandler : IGlobalSubscriber
{
void OnRacerPassedCheckpoint(Racer.Racer racer);
void LapPassed(Racer.Racer racer);
}
public interface IPlayerPassedCheckpointHandler : IGlobalSubscriber
{
void OnPlayerPassedCheckpoint(Racer.Racer racer);
void OnPlayerLapPassed(Racer.Racer racer);
}
}
@@ -13,6 +13,7 @@ namespace Code.Example.Race.Track
public struct TrackData
{
public List<Transform> RacerPoints;
public List<Transform> Checkpoints;
public List<CheckPoint> Checkpoints;
public int LapCount;
}
}
@@ -1,13 +1,10 @@
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;
using UnityEngine;
namespace Code.Example.Race.UI
{
@@ -25,24 +22,22 @@ namespace Code.Example.Race.UI
public override void Open(Action callback = null)
{
playerScore.gameObject.SetActive(true);
callback?.Invoke();
// image.DOColor(shownColor, 1f).onComplete = () => callback?.Invoke();
}
public override void Close(Action callback = null)
{
playerScore.gameObject.SetActive(true);
playerScore.gameObject.SetActive(false);
callback?.Invoke();
// image.DOColor(hiddenColor, 1f).onComplete += () => callback?.Invoke();
}
}
public void OnRacerPassedCheckpoint(Racer.Racer racer)
{
}
public void ScoreChanged(Racer.Racer racer, int additionalScore, List<KeyValuePair<Racer.Racer,int>> scores)
public void ScoreChanged(Racer.Racer racer, ScoreData additionalScore, List<KeyValuePair<Racer.Racer,ScoreData>> scores)
{
// if (racer.Data.type == RacerType.Player)
string output = "";
foreach (var score in scores) output += $@"{score.Key.Data.name}: {score.Value}\n";
foreach (var score in scores) output += $@"{score.Key.Data.name}: {score.Value.lapsPassed} \t {score.Value.checkpointsPassed}\n";
playerScore.text = output;
}
}
+30
View File
@@ -0,0 +1,30 @@
using System;
using Code.Infrastructure.UI;
using DG.Tweening;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Code.Example.Race.UI
{
public class WinScreen : UIPanel
{
[SerializeField] private Image image;
[SerializeField] private TMP_Text winText;
[SerializeField] private Color shownColor;
[SerializeField] private Color hiddenColor;
public void SetText(string text) => winText.text = text;
public override void Open(Action callback = null)
{
image.DOColor(shownColor, 1f).onComplete = () => callback?.Invoke();
winText.DOColor(shownColor, 1f).onComplete = () => callback?.Invoke();
}
public override void Close(Action callback = null)
{
image.DOColor(hiddenColor, 1f).onComplete = () => callback?.Invoke();
winText.DOColor(hiddenColor, 1f).onComplete = () => callback?.Invoke();
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9093110373134c91b06be09705639ddd
timeCreated: 1770455340