Compare commits

...

2 Commits

Author SHA1 Message Date
c466e28d6c AI FSM changes.
- Protoyped on the AI movement, found solutions for turns and
   moving after impacting the player.
- Created a full base for AI state machine.
- Worked on binding the core AI logic with the finite state machine.
2026-01-07 19:38:03 +05:30
90172daae5 Created base for FSM. 2026-01-07 12:00:57 +05:30
43 changed files with 2343 additions and 35 deletions

View File

@ -22,4 +22,4 @@ MonoBehaviour:
rotationSpeed: 2
tireRotationAngle: 20
speedValue: 50
accelSpeed: 50
accelSpeed: 100

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2190dc59a173e463f81234566cee14be
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 36d3513c3c72245678185ccd17a13c64
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,163 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AICarController : MonoBehaviour, ICar
{
#region Fields
private float speed;
private float speedMax = 35f;
private float speedMin = -25f;
private float acceleration = 10f;
private float brakeSpeed = 50f;
private float reverseSpeed = 15f;
private float idleSlowdown = 5f;
private float turnSpeed;
private float turnSpeedMax = 150f;
private float turnSpeedAcceleration = 150f;
private float turnIdleSlowdown = 250f;
private float forwardAmount;
private float turnAmount;
private Rigidbody carRigidbody;
public GameplayManager GameplayManager
{
get;
private set;
}
#endregion
private void Awake()
{
carRigidbody = GetComponent<Rigidbody>();
}
public void Init(GameplayManager gameplayManager)
{
this.GameplayManager = gameplayManager;
}
private void Update()
{
CalculateAccelaration();
if (speed < 0)
{
// Going backwards, invert wheels
// turnAmount = turnAmount * -1f;
}
if (turnAmount > 0 || turnAmount < 0)
{
// Turning
if ((turnSpeed > 0 && turnAmount < 0) || (turnSpeed < 0 && turnAmount > 0))
{
// Changing turn direction
float minTurnAmount = 20f;
turnSpeed = turnAmount * minTurnAmount;
}
turnSpeed += turnAmount * turnSpeedAcceleration * Time.deltaTime;
}
else
{
// Not turning
if (turnSpeed > 0)
{
turnSpeed -= turnIdleSlowdown * Time.deltaTime;
}
if (turnSpeed < 0)
{
turnSpeed += turnIdleSlowdown * Time.deltaTime;
}
if (turnSpeed > -1f && turnSpeed < +1f) {
// Stop rotating
turnSpeed = 0f;
}
}
float speedNormalized = speed / speedMax;
float invertSpeedNormalized = Mathf.Clamp(1 - speedNormalized, .75f, 1f);
turnSpeed = Mathf.Clamp(turnSpeed, -turnSpeedMax, turnSpeedMax);
carRigidbody.angularVelocity = new Vector3(0, turnSpeed * (invertSpeedNormalized * 1f) * Mathf.Deg2Rad, 0);
if (transform.eulerAngles.x > 2 || transform.eulerAngles.x < -2 || transform.eulerAngles.z > 2 || transform.eulerAngles.z < -2)
{
transform.eulerAngles = new Vector3(0, transform.eulerAngles.y, 0);
}
}
private void CalculateAccelaration()
{
if (forwardAmount > 0)
{
// Accelerating
speed += acceleration * Time.deltaTime;
}
else if (forwardAmount < 0)
{
if (speed > 0)
{
// Braking
speed += forwardAmount * brakeSpeed * Time.deltaTime;
}
else
{
// Reversing
speed += forwardAmount * reverseSpeed * Time.deltaTime;
}
}
else
{
// Not accelerating or braking
if (speed > 0)
{
speed -= idleSlowdown * Time.deltaTime;
}
if (speed < 0)
{
speed += idleSlowdown * Time.deltaTime;
}
}
speed = Mathf.Clamp(speed, speedMin, speedMax);
carRigidbody.velocity = transform.forward * speed;
}
public void SetInputs(float forwardAmount, float turnAmount) {
this.forwardAmount = forwardAmount;
this.turnAmount = turnAmount;
}
public void ClearTurnSpeed() {
turnSpeed = 0f;
}
public float GetSpeed() {
return speed;
}
public void SetSpeedMax(float speedMax) {
this.speedMax = speedMax;
}
public void SetTurnSpeedMax(float turnSpeedMax) {
this.turnSpeedMax = turnSpeedMax;
}
public void SetTurnSpeedAcceleration(float turnSpeedAcceleration) {
this.turnSpeedAcceleration = turnSpeedAcceleration;
}
public void StopCompletely() {
speed = 0f;
turnSpeed = 0f;
}
}

View File

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

View File

@ -0,0 +1,142 @@
using System;
using DG.Tweening;
using Unity.VisualScripting;
using UnityEditor.Callbacks;
using UnityEngine;
public class AICarDriver : MonoBehaviour
{
[SerializeField] private Transform targetPositionTranform;
private AICarController carDriver;
private Vector3 targetPosition;
private void Awake()
{
carDriver = GetComponent<AICarController>();
impactTimer = new TimerSystem();
// SetImpactTimer();
}
private TimerSystem impactTimer;
private float forwardAmount = 0f;
private float turnAmount = 0f;
public void UpdateMovement(Action onComplete = null)
{
// provide a roamPoint
SetTargetPosition(targetPositionTranform.position);
float targetDistReach = 2f;
float distanceToTarget = Vector3.Distance(transform.position, targetPosition);
Debug.Log($"distanceToTarget :: {distanceToTarget}");
if (distanceToTarget > targetDistReach)
{
// Still too far, keep going
Vector3 dirToMovePosition = (targetPosition - transform.position).normalized;
float dot = Vector3.Dot(transform.forward, dirToMovePosition);
if (dot > 0)
{
// Target in front
forwardAmount = 1f;
float stoppingDistance = 2f;
float stoppingSpeed = 5f;
// if (onImpact)
// {
// the target location should be set to next roam point or to another enemy/player
// and then DoReverse()
// DoReverse();
// }
// else if (canCheck)
// {
if (distanceToTarget < stoppingDistance && carDriver.GetSpeed() > stoppingSpeed)
{
// Within stopping distance and moving forward too fast
forwardAmount = -1f;
}
// }
// after impact reverse for about 0.5 seconds
}
else
{
// Target behind
float reverseDistance = 25f;
if (distanceToTarget > reverseDistance)
{
// Too far to reverse
forwardAmount = 1f;
// if (onImpact)
// {
// the target location should be set to next roam point or to another enemy/player
// and then DoReverse()
// DoReverse();
// }
}
else
{
forwardAmount = -1f;
// Check if DoReverse can be called instead
}
}
turnAmount = FindTurnAmt();
}
else
{
// Reached target
Debug.Log($"Target reached: {forwardAmount}");
if (forwardAmount == 1)
onComplete?.Invoke();
forwardAmount = carDriver.GetSpeed() > 15f ? -1f : 0f;
turnAmount = 0f;
}
carDriver.SetInputs(forwardAmount, turnAmount);
}
public void DoReverse(Action onComplete)
{
// TODO :: Set target position before doing reverse
Debug.Log($"CarDriverAI :: onImpact");
if (impactTimer.IsTimerComplete)
{
impactTimer.Init(0.5f, onComplete: () =>
{
Debug.Log($"ImpactTimer :: OnTimerComplete");
forwardAmount = 1f;
turnAmount = FindTurnAmt();
carDriver.SetInputs(forwardAmount, turnAmount);
onComplete?.Invoke();
});
}
impactTimer.UpdateTimer(Time.deltaTime);
forwardAmount = -1f;
turnAmount = FindTurnAmt();
carDriver.SetInputs(forwardAmount, turnAmount);
}
private float FindTurnAmt()
{
Vector3 dirToMovePosition = (targetPosition - transform.position).normalized;
float angleToDir = Vector3.SignedAngle(transform.forward, dirToMovePosition, Vector3.up);
return angleToDir > 0 ? 1f : -1f;
}
public void SetTargetPosition(Vector3 targetPosition)
{
this.targetPosition = targetPosition;
}
}

View File

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

View File

@ -0,0 +1,5 @@
public interface ICar
{
void Init(GameplayManager gameplayManager);
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0082726b257d94b50be8e6ddfe50611a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,24 @@
public enum AIState
{
Idle,
Roam,
AcquireTarget,
Charge,
Impact,
Recover,
// Idle / Spawn
// ↓
// Roam
// ↓
// Targeting
// ↓
// Charge
// ↓
// Impact
// ↓
// Recover
// ↓
// Roam (loop)
}

View File

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

View File

@ -0,0 +1,25 @@
using System;
using UnityEngine;
public class AIStateProcesser : MonoBehaviour
{
private BaseState currentState;
private AICarDriver carDriverAI;
private AICarController aiCarController;
private void Awake()
{
carDriverAI = GetComponent<AICarDriver>();
aiCarController = GetComponent<AICarController>();
}
private void Start()
{
currentState = new IdleState(carDriverAI, aiCarController.GameplayManager);
}
private void Update()
{
currentState = currentState.ProcessStates();
}
}

View File

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

View File

@ -0,0 +1,6 @@
public enum STAGE
{
Enter,
Update,
Exit
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c0a6f1dfd8c8d48dcae8cb76eb994be0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,44 @@
using UnityEngine;
public class AcquireTargetState : BaseState
{
public AcquireTargetState(AICarDriver aiCarDriver, GameplayManager gameplayManager) : base(aiCarDriver, gameplayManager)
{
Debug.Log($"### {this} constructor");
}
protected override void Enter()
{
base.Enter();
Debug.Log($"### {this} Enter STAGE");
}
protected override void Update()
{
base.Update();
Debug.Log($"### {this} Update STAGE");
// while it's roaming check for targets
// Find the target and once the target is found then charge toward that specific target
if (HasFoundTarget())
{
base.Exit();
nextState = new ChargeState(aiCarDriver, gameplayManager);
}
}
protected override void Exit()
{
base.Exit();
Debug.Log($"### {this} Exit STAGE");
}
public bool HasFoundTarget()
{
return false;
}
}

View File

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

View File

@ -0,0 +1,36 @@
using UnityEngine;
public class BaseState
{
protected STAGE stage;
protected BaseState nextState;
protected Transform currentTarget;
protected AICarDriver aiCarDriver;
protected GameplayManager gameplayManager;
public BaseState(AICarDriver aiCarDriver, GameplayManager gameplayManager)
{
stage = STAGE.Enter;
this.aiCarDriver = aiCarDriver;
this.gameplayManager = gameplayManager;
}
protected virtual void Enter() => stage = STAGE.Update;
protected virtual void Update() => stage = STAGE.Update;
protected virtual void Exit() => stage = STAGE.Exit;
public BaseState ProcessStates()
{
if (stage == STAGE.Enter) Enter();
if (stage == STAGE.Update) Update();
if (stage == STAGE.Exit)
{
Exit();
return nextState;
}
return this;
}
}

View File

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

View File

@ -0,0 +1,36 @@
using UnityEngine;
public class ChargeState : BaseState
{
public ChargeState(AICarDriver aiCarDriver, GameplayManager gameplayManager) : base(aiCarDriver, gameplayManager)
{
Debug.Log($"### {this} constructor");
}
protected override void Enter()
{
base.Enter();
Debug.Log($"### {this} Enter STAGE");
// update the values for charging
}
protected override void Update()
{
base.Update();
Debug.Log($"### {this} Update STAGE");
aiCarDriver.UpdateMovement(() =>
{
base.Exit();
nextState = new ImpactState(aiCarDriver, gameplayManager);
});
}
protected override void Exit()
{
base.Exit();
Debug.Log($"### {this} Exit STAGE");
}
}

View File

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

View File

@ -0,0 +1,35 @@
using UnityEngine;
public class IdleState : BaseState
{
public IdleState(AICarDriver aiCarDriver, GameplayManager gameplayManager) : base(aiCarDriver, gameplayManager)
{
Debug.Log($"### {this} constructor");
}
protected override void Enter()
{
base.Enter();
Debug.Log($"### {this} Enter STAGE");
}
protected override void Update()
{
base.Update();
// use a mod timer system and when timer completes then move onto the next state (RoamState)
base.Exit();
nextState = new AcquireTargetState(aiCarDriver, gameplayManager);
Debug.Log($"### {this} Update STAGE");
}
protected override void Exit()
{
base.Exit();
Debug.Log($"### {this} Exit STAGE");
}
}

View File

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

View File

@ -0,0 +1,34 @@
using UnityEngine;
public class ImpactState : BaseState
{
public ImpactState(AICarDriver aiCarDriver, GameplayManager gameplayManager) : base(aiCarDriver, gameplayManager)
{
Debug.Log($"### {this} constructor");
}
protected override void Enter()
{
base.Enter();
Debug.Log($"### {this} Enter STAGE");
}
protected override void Update()
{
base.Update();
Debug.Log($"### {this} Update STAGE");
// do actions when an impact happens
base.Exit();
nextState = new RecoverState(aiCarDriver, gameplayManager);
}
protected override void Exit()
{
base.Exit();
Debug.Log($"### {this} Exit STAGE");
}
}

View File

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

View File

@ -0,0 +1,35 @@
using UnityEngine;
public class RecoverState : BaseState
{
public RecoverState(AICarDriver aiCarDriver, GameplayManager gameplayManager) : base(aiCarDriver, gameplayManager)
{
Debug.Log($"### {this} constructor");
}
protected override void Enter()
{
base.Enter();
Debug.Log($"### {this} Enter STAGE");
}
protected override void Update()
{
base.Update();
Debug.Log($"### {this} Update STAGE");
aiCarDriver.DoReverse(() =>
{
base.Exit();
nextState = new RoamState(aiCarDriver, gameplayManager);
});
}
protected override void Exit()
{
base.Exit();
Debug.Log($"### {this} Exit STAGE");
}
}

View File

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

View File

@ -0,0 +1,65 @@
using UnityEngine;
public class RoamState : BaseState
{
private bool hasCompletedRoaming = false;
private float roamDuration = 2f;
private Vector3 currentRoamingPoint = Vector3.zero;
private TimerSystem roamTimerSystem = null;
public RoamState(AICarDriver aiCarDriver, GameplayManager gameplayManager) : base(aiCarDriver, gameplayManager)
{
Debug.Log($"### {this} constructor");
}
protected override void Enter()
{
base.Enter();
Debug.Log($"### {this} Enter STAGE");
// get the target point
currentRoamingPoint = gameplayManager.GetRoamingPoint();
aiCarDriver.SetTargetPosition(currentRoamingPoint);
roamTimerSystem = new TimerSystem();
hasCompletedRoaming = false;
roamTimerSystem.Init(roamDuration, onComplete: () => hasCompletedRoaming = true);
}
protected override void Update()
{
base.Update();
// keep roaming for a specific duration
// use a set of target points which would be placed on the arena,
// get one of the target point and then start roaming towards that point.
// if an enemy/player is found within a specific radius and in front of-
// -the AI then go to the next state after acquiring the target-
// -(next state could be ChargeState)
// Set Target location
if (!hasCompletedRoaming)
{
roamTimerSystem.UpdateTimer(Time.deltaTime);
aiCarDriver.UpdateMovement();
}
else
{
base.Exit();
nextState = new AcquireTargetState(aiCarDriver, gameplayManager);
}
Debug.Log($"### {this} Update STAGE");
}
protected override void Exit()
{
base.Exit();
Debug.Log($"### {this} Exit STAGE");
}
}

View File

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

View File

@ -4,10 +4,8 @@ using UnityEngine;
using System.Collections;
using System.ComponentModel;
using UnityEngine.SceneManagement;
using UnityEngine.EventSystems;
using Newtonsoft.Json;
public class CarController : MonoBehaviour
public class PlayerCarController : MonoBehaviour, ICar
{
[SerializeField] private bool isDebugTest = false;
@ -17,7 +15,7 @@ public class CarController : MonoBehaviour
[SerializeField] private Rigidbody carRigidbody;
[SerializeField] private CarSpecs carSpecs;
[SerializeField] private PlayerCarSpecs carSpecs;
[SerializeField] private Vector3 customCenterOfMass;
[SerializeField] private AnimationCurve steerLeftAnimCurve;
[SerializeField] private AnimationCurve steerRightAnimCurve;
@ -33,7 +31,7 @@ public class CarController : MonoBehaviour
private float tiresInGround = 0f;
[Category("Script-Object-Refs.")]
private CarSystem carSystem;
private PlayerCarSystem carSystem;
private TimerSystem timerSystem;
[Category("Tags.")]
@ -50,14 +48,22 @@ public class CarController : MonoBehaviour
public Action<float> OnCarRotate;
public Action<string> OnGameOver;
public void Init()
public GameplayManager GameplayManager
{
get;
private set;
}
public void Init(GameplayManager gameplayManager)
{
this.GameplayManager = gameplayManager;
isGameOver = false;
tiresCount = tireTransforms.Length;
timerSystem = new TimerSystem();
remTime = timerSystem.Timer;
carSystem = new CarSystem(this, carRigidbody, carSpecs, frontTireTransforms, steerLeftAnimCurve: steerLeftAnimCurve, steerRightAnimCurve: steerRightAnimCurve, accelAnimCurve: accelAnimCurve);
// remTime = timerSystem.Timer;
carSystem = new PlayerCarSystem(this, carRigidbody, carSpecs, frontTireTransforms, steerLeftAnimCurve: steerLeftAnimCurve, steerRightAnimCurve: steerRightAnimCurve, accelAnimCurve: accelAnimCurve);
}
private void EnableGameOverState()

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "CarSpecs", menuName = "CarSpecs", order = 1)]
public class CarSpecs : ScriptableObject
public class PlayerCarSpecs : ScriptableObject
{
public float dampingForce = 50;
public float strength = 500;

View File

@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.ComponentModel;
using UnityEngine;
public class CarSystem : ICarComponents
public class PlayerCarSystem : ICarComponents
{
[Category("Global Attributes")] private Rigidbody carRigidbody;
private CarSpecs carSpecs;
private PlayerCarSpecs carSpecs;
[Category("Animation Curves")] private AnimationCurve steerLeftAnimCurve;
[Category("Animation Curves")] private AnimationCurve steerRightAnimCurve;
@ -29,9 +29,9 @@ public class CarSystem : ICarComponents
private Vector3 accelForce;
private Transform[] frontTireTransforms;
private CarController gameplayControllerInst;
private PlayerCarController gameplayControllerInst;
public CarSystem(CarController gameplayController, Rigidbody carRigidbody = null, CarSpecs carSpecs = null, Transform[] frontTireTransforms = null,
public PlayerCarSystem(PlayerCarController gameplayController, Rigidbody carRigidbody = null, PlayerCarSpecs carSpecs = null, Transform[] frontTireTransforms = null,
AnimationCurve steerLeftAnimCurve = null, AnimationCurve steerRightAnimCurve = null, AnimationCurve accelAnimCurve = null)
{
gameplayControllerInst = gameplayController;

View File

@ -1,12 +1,17 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader
{
[SerializeField] private CarController carController;
[SerializeField] private GameObject[] allCarsInScene; // contains enemy cars and player car
[]
[SerializeField] private PlayerCarController playerCarController; // TODO :: initialize roamPoints here
public CarController CarController => carController;
[SerializeField] private List<Transform> roamPoints; // TODO :: initialize roamPoints here
public PlayerCarController CarController => playerCarController;
public void Initialize()
{
@ -15,6 +20,21 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader
public void InitializeData()
{
carController.Init();
foreach (var car in allCarsInScene)
{
car.GetComponent<ICar>().Init(this);
}
}
public Vector3 GetRoamingPoint()
{
var randomIndex = Random.Range(0, roamPoints.Count);
return roamPoints[randomIndex].position;
}
public Transform GetTargetToAttack()
{
var randomIdx = Random.Range(0, allCarsInScene.Length);
return allCarsInScene[randomIdx].transform;
}
}

View File

@ -1,29 +1,50 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TimerSystem
{
private float timer = 10f;
private float timerIncrement = 5f;
private float timeRem;
private float maxTimeAvail;
public float Timer => timer;
public float TimerIncrement = 5f;
public TimerSystem()
private Action onTimerComplete = null;
private Action onTimerInProgress = null;
public bool IsTimerComplete
{
CarController.OnCheckpointReached += UpdateTimer;
get;
private set;
}
private void IncreaseTimer()
public bool IsInitialized
{
timer += timerIncrement;
get;
private set;
}
public void UpdateTimer(float remTime)
public void Init(float maxTimeAvail, Action onComplete = null, Action inProgress = null, Action onStart = null)
{
timer = remTime;
IncreaseTimer();
timeRem = 0;
IsTimerComplete = false;
IsInitialized = true;
this.maxTimeAvail = maxTimeAvail;
this.onTimerComplete = onComplete;
this.onTimerInProgress = inProgress;
}
public void UpdateTimer(float deltaTime)
{
if (timeRem < maxTimeAvail)
{
timeRem += deltaTime;
onTimerInProgress?.Invoke();
}
else
{
timeRem = 0;
onTimerComplete?.Invoke();
IsTimerComplete = true;
}
}
}

View File

@ -69,7 +69,7 @@ NavMeshProjectSettings:
cost: 1
- name:
cost: 1
m_LastAgentTypeID: -887442657
m_LastAgentTypeID: -1372625422
m_Settings:
- serializedVersion: 2
agentTypeID: 0
@ -85,7 +85,28 @@ NavMeshProjectSettings:
manualTileSize: 0
tileSize: 256
accuratePlacement: 0
maxJobWorkers: 0
preserveTilesOutsideBounds: 0
debug:
m_Flags: 0
- serializedVersion: 2
agentTypeID: -1372625422
agentRadius: 0.5
agentHeight: 1.2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
accuratePlacement: 0
maxJobWorkers: 0
preserveTilesOutsideBounds: 0
debug:
m_Flags: 0
m_SettingNames:
- Humanoid
- New Agent