Sounds, state machine fixes

This commit is contained in:
Nikita Kruglickiy 2024-03-19 23:37:02 +03:00
parent 5f7939cdfa
commit f193e645a3
16 changed files with 206 additions and 382 deletions

View File

@ -199,7 +199,7 @@ GameObject:
m_Component:
- component: {fileID: 4386241463551842019}
- component: {fileID: 6965639289352285917}
- component: {fileID: 6181306113831106058}
- component: {fileID: 3645150389920965962}
m_Layer: 0
m_Name: Audio
m_TagString: Untagged
@ -235,7 +235,7 @@ AudioSource:
m_audioClip: {fileID: 0}
m_PlayOnAwake: 0
m_Volume: 1
m_Pitch: 0.9607912
m_Pitch: 1
Loop: 0
Mute: 0
Spatialize: 0
@ -318,7 +318,7 @@ AudioSource:
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
--- !u!82 &6181306113831106058
--- !u!82 &3645150389920965962
AudioSource:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
@ -327,12 +327,12 @@ AudioSource:
m_GameObject: {fileID: 744751075212041674}
m_Enabled: 1
serializedVersion: 4
OutputAudioMixerGroup: {fileID: 24300002, guid: 61acf3f269c66b94e97dab5732cf3b41, type: 2}
m_audioClip: {fileID: 8300000, guid: 199c9ade0344bb54aac6f449b200c46c, type: 3}
OutputAudioMixerGroup: {fileID: 0}
m_audioClip: {fileID: 8300000, guid: 263f8aaa01d5d0041b082b7b69d9ca02, type: 3}
m_PlayOnAwake: 1
m_Volume: 1
m_Volume: 0.1
m_Pitch: 1
Loop: 1
Loop: 0
Mute: 0
Spatialize: 0
SpatializePostEffects: 0
@ -422,7 +422,7 @@ AudioSource:
m_Curve:
- serializedVersion: 3
time: 0
value: 0.572
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
@ -1616,7 +1616,6 @@ GameObject:
- component: {fileID: 5531527120828026849}
- component: {fileID: 5531527120828026854}
- component: {fileID: 8593506440408512701}
- component: {fileID: 5531527120828026853}
- component: {fileID: 5531527120828026852}
- component: {fileID: 5531527120828026851}
- component: {fileID: 5531527120828026850}
@ -1683,27 +1682,6 @@ MonoBehaviour:
m_EditorClassIdentifier:
syncMode: 0
syncInterval: 0.1
agent: {fileID: 5531527120828026854}
animator: {fileID: 4680592339959672808}
aimRig: {fileID: 7145529201307863795}
audioSource: {fileID: 6965639289352285917}
hitVFX: {fileID: 4110346323425436829}
aimTransform: {fileID: 4985286446129716783}
aimRigWeight: 0
--- !u!114 &5531527120828026853
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5154438181429744987}
m_Enabled: 0
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d36f9376acad45245a24c57648723923, type: 3}
m_Name:
m_EditorClassIdentifier:
syncMode: 0
syncInterval: 0.02
health: 100
Alive: 1
_speedMul: 1
@ -1712,19 +1690,18 @@ MonoBehaviour:
BottomClamp: -90
TopClamp: 90
CinemachineCameraTarget: {fileID: 0}
spawnCube: 0
controller: {fileID: 5531527120828026854}
agent: {fileID: 5531527120828026854}
animator: {fileID: 4680592339959672808}
targetLayer: {fileID: 7145529201307863795}
aimRig: {fileID: 7145529201307863795}
audioSource: {fileID: 6965639289352285917}
footstepAudioSource: {fileID: 3645150389920965962}
hitVFX: {fileID: 4110346323425436829}
hasPath: 0
propPrefab: {fileID: 2352355441573259686, guid: fb20dc5a22e38934dbd64e9158977eec, type: 3}
aimTarget: {fileID: 4985286446129716783}
aimTransform: {fileID: 4985286446129716783}
aggressionDistance: 20
_stepTiming: 0.12
isKilling: 0
canAttack: 1
state: 0
aimRigWeight: 0
targetTransform: {fileID: 0}
networkAnimator: {fileID: 0}
--- !u!114 &5531527120828026852
MonoBehaviour:
m_ObjectHideFlags: 0

BIN
Assets/Resources/Audio/EnemySounds/FX/attack.mp3 (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,22 @@
fileFormatVersion: 2
guid: 51e9501727c993843bb20262585ae629
AudioImporter:
externalObjects: {}
serializedVersion: 6
defaultSettings:
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
preloadAudioData: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/Resources/Audio/EnemySounds/FX/dance.mp3 (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,22 @@
fileFormatVersion: 2
guid: 81671b36c2d1fba40806cf3af137e164
AudioImporter:
externalObjects: {}
serializedVersion: 6
defaultSettings:
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
preloadAudioData: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/Resources/Audio/EnemySounds/FX/stunned.mp3 (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,22 @@
fileFormatVersion: 2
guid: e0f863832b1c41245a9fd6e66ded8a4b
AudioImporter:
externalObjects: {}
serializedVersion: 6
defaultSettings:
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
preloadAudioData: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

View File

@ -14,12 +14,11 @@ namespace Characters.Enemy
public Animator animator;
public Rig aimRig;
public AudioSource audioSource;
public AudioSource footstepAudioSource;
public ParticleSystem hitVFX;
public Transform aimTransform;
public float aggressionDistance = 5f;
[HideInInspector] public bool canAttack;
[SyncVar] public EnemyState state = EnemyState.Idle;
[SyncVar, HideInInspector] public float aimRigWeight;
@ -27,6 +26,8 @@ namespace Characters.Enemy
[FormerlySerializedAs("target")] public Transform targetTransform;
public NetworkAnimator networkAnimator;
public bool HasTarget => targetTransform != null;
public float DistanceToTarget => Vector3.Distance(targetTransform.transform.position, transform.position);
private CustomNetworkManager _networkManager;
@ -34,8 +35,9 @@ namespace Characters.Enemy
private float _targetAimRigWeight;
private float _stepCycle;
private AudioClip _footstepClip;
private Vector3 _footstepPrevPosition;
private const float StepDelay = 0.15f;
private const float StepDelay = 0.12f;
private const float RunSpeed = 4.974f;
private static readonly int SpeedAnimHash = Animator.StringToHash("speed");
@ -43,11 +45,10 @@ namespace Characters.Enemy
{
_networkManager = NetworkManager.singleton.GetComponent<CustomNetworkManager>();
_networkGameManager = NetworkGameManager.singleton;
_footstepClip = Resources.Load<AudioClip>("Audio/EnemySounds/Steps/monsterStep1");
networkAnimator = GetComponent<NetworkAnimator>();
_footstepClip = Resources.Load<AudioClip>("Audio/EnemySounds/Steps/monsterStep1");
stateMachine.Add(new IdleState(this));
stateMachine.Add(new PatrolState(this));
stateMachine.Add(new ChaseState(this));
@ -58,8 +59,13 @@ namespace Characters.Enemy
}
void Update()
{
Debug.DrawLine(transform.position, transform.forward * aggressionDistance, Color.green, 0f);
if (isClient)
{
Footsteps();
}
if (isServer)
{
@ -85,17 +91,18 @@ namespace Characters.Enemy
void Footsteps()
{
// float velocity = ((_position - transform.position) / Time.deltaTime).magnitude;
float velocity = 0;
float velocity = ((_footstepPrevPosition - transform.position) / Time.deltaTime).magnitude;
float clampedVelocity = Mathf.Clamp(RunSpeed / velocity + 1, 1, RunSpeed);
if (Time.time > _stepCycle && velocity > 0)
{
audioSource.pitch = 1f + Random.Range(-0.1f, 0.1f);
audioSource.PlayOneShot(_footstepClip);
footstepAudioSource.pitch = 1f + Random.Range(-0.1f, 0.1f);
footstepAudioSource.PlayOneShot(_footstepClip);
_stepCycle = Time.time + (clampedVelocity * StepDelay);
}
_footstepPrevPosition = transform.position;
}
[ClientRpc]
@ -126,7 +133,7 @@ namespace Characters.Enemy
{
var alivePlayers = _networkManager.alive;
if (targetTransform != null && alivePlayers.Count == 1 && alivePlayers[0].transform == targetTransform)
if (HasTarget && alivePlayers.Count == 1 && alivePlayers[0].transform == targetTransform)
{
return targetTransform;
}

View File

@ -1,279 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using Characters.Enemy;
using UnityEngine;
using UnityEngine.AI;
using Mirror;
using UnityEngine.Animations.Rigging;
using Characters;
public class EnemyController : Pawn
{
public bool spawnCube = false;
public NavMeshAgent controller;
public Animator animator;
public Rig targetLayer;
public AudioSource audioSource;
public ParticleSystem hitVFX;
public bool hasPath;
public GameObject propPrefab;
public Transform aimTarget;
public float aggressionDistance = 5f;
public float _stepTiming = 0.15f;
CustomNetworkManager networkManager;
NetworkGameManager networkGameManager;
private Transform _target = null;
private List<Pawn> players;
private Vector3 _position;
private float _stepCycle;
private float _runSpeed = 4.974f; //_walkSpeed = 0.299f
private float targetLayerWeight;
private int _currenPointId;
[SyncVar]
private float layerWeight;
private float _remainingDistance;
NavMeshTriangulation navMeshData;
[SyncVar(hook = nameof(OnStateChanged))]
private EnemyState state = EnemyState.Patrol;
private AudioClip skrClip, agressiveClip;
public NavMeshPath navMeshPath;
public bool isKilling = false;
[SerializeField] private bool canAttack = true;
void Start()
{
// Time.timeScale = 10;
skrClip = Resources.Load<AudioClip>("Audio/EnemySounds/woodSkr");
agressiveClip = Resources.Load<AudioClip>("Audio/EnemySounds/FX/agressive2");
networkManager = NetworkManager.singleton.GetComponent<CustomNetworkManager>();
networkGameManager = NetworkGameManager.singleton;
players = networkManager.alive;
this.OnDamage += TakeDamageAnimation;
if (!isServer) return;
navMeshData = NavMesh.CalculateTriangulation();
if (spawnCube)
{
Vector3 randLoc = navMeshData.vertices[navMeshData.indices[Random.Range(0, navMeshData.indices.Length - 3)]];
GameObject gameObject = Instantiate(propPrefab, randLoc + Vector3.up * 1, Quaternion.identity);
gameObject.GetComponent<PropBehaviour>().Original = true;
NetworkServer.Spawn(gameObject);
}
navMeshPath = new NavMeshPath();
}
void Update()
{
controller.speed = _speedMul * _runSpeed;
CalculateFootstepTriggers();
layerWeight = isServer ? Mathf.Lerp(layerWeight, targetLayerWeight, Time.deltaTime) : layerWeight;
targetLayer.weight = layerWeight;
if (!isServer) return;
animator.SetFloat("speed", controller.velocity.magnitude);
_remainingDistance = controller.GetPathRemainingDistance();
hasPath = controller.pathStatus != NavMeshPathStatus.PathComplete;
// if (controller.pathStatus == NavMeshPathStatus.PathComplete && !controller.pathPending && _target != null)
// {
// _target = null;
// }
// Есть таргет?
if (_target != null) // Да
{
controller.destination = _target.position;
float distance = Vector3.Distance(_target.transform.position, transform.position);
if (distance < aggressionDistance)
{
aimTarget.position = _target.position + _target.up * 1.2f;
targetLayerWeight = 1f;
if (distance < 1f)
{
if (canAttack && !isKilling)
{
RpcKillPlayer(_target);
animator.SetTrigger("attack");
StartCoroutine(AfterKillTimer());
}
}
}
else
{
_target = null;
}
}
else
{
targetLayerWeight = 0f;
// Ищем ближайшего игрока
foreach (var player in players)
{
float distance = Vector3.Distance(player.transform.position, transform.position);
if (distance <= aggressionDistance && CalculateNewPath(player.transform)) // && _remainingDistance > 0
{
//if (_remainingDistance < aggressionDistance && controller.GetPathRemainingDistance() >= 0)
_target = player.transform;
break;
}
}
if (_target == null && _remainingDistance <= 1.5f) //!controller.pathPending ||
{
SetRandomDestination();
}
}
}
bool CalculateNewPath(Transform target)
{
controller.CalculatePath(target.position, navMeshPath);
if (navMeshPath.status != NavMeshPathStatus.PathComplete)
{
return false;
}
return true;
}
[ClientRpc]
void RpcKillPlayer(Transform target)
{
Interactions interactions = target.GetComponent<Interactions>();
if (interactions != null) interactions.DropProp();
target.GetComponent<Pawn>().Die();
}
IEnumerator AfterKillTimer()
{
isKilling = true;
_target = null;
_speedMul = 0;
yield return new WaitForSeconds(7);
_speedMul = 1;
isKilling = false;
aimTarget.position = transform.position;
SetRandomDestination();
}
[Server]
void SetRandomDestination()
{
var targetPoint = GetRandomLocation();
// var targetPoint = navMeshData.vertices[2000];
//_patrolPoints[Random.Range(0, _patrolPoints.Length - 1)].position;
// hasPath = controller.SetDestination(targetPoint);
controller.destination = targetPoint;
// hasPath = controller.hasPath;
}
void OnStateChanged(EnemyState oldState, EnemyState newState)
{
audioSource.Stop();
// switch (newState)
// {
// case EnemyState.Patrol:
// audioSource.reverbZoneMix = 1f;
// break;
//
// case EnemyState.Rotate:
// audioSource.clip = skrClip;
// audioSource.Play();
// break;
//
// case EnemyState.Chase:
// // audioSource.clip = agressiveClip;
// // audioSource.reverbZoneMix = 0f;
// // audioSource.Play();
// break;
// }
}
private List<Vector3> _points = new List<Vector3>();
Vector3 GetRandomLocation()
{
var point = navMeshData.vertices[navMeshData.indices[Random.Range(0, navMeshData.indices.Length - 3)]];
_points.Add(point);
return point;
}
void OnDrawGizmos()
{
foreach (var point in _points)
{
Gizmos.DrawSphere(point, 1f);
}
}
void CalculateFootstepTriggers()
{
float _velocity = ((_position - transform.position) / Time.deltaTime).magnitude;
// Debug.Log(_controllerVelocity);
float clampedVelocity = Mathf.Clamp(_runSpeed / _velocity + 1, 1, _runSpeed);
if (Time.time > _stepCycle && _velocity > 0)
{
CallFootstepClip();
_stepCycle = Time.time + (clampedVelocity * _stepTiming);
}
_position = transform.position;
}
public void CallFootstepClip()
{
audioSource.pitch = 1f + Random.Range(-0.1f, 0.1f);
audioSource.PlayOneShot(Resources.Load<AudioClip>("Audio/EnemySounds/Steps/monsterStep1"));
}
void TakeDamageAnimation(Pawn self)
{
print(this.name + " taken damage epta");
canAttack = false;
_speedMul = 0;
animator.SetTrigger("damage");
hitVFX.Stop();
hitVFX.Play();
StartCoroutine(AfterTakeDamage());
}
IEnumerator AfterTakeDamage()
{
yield return new WaitForSeconds(6);
_speedMul = 1;
canAttack = true;
}
}

View File

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

View File

@ -8,24 +8,27 @@ namespace Characters.Enemy.States
{
private readonly Enemy _enemy;
private static readonly int AttackAnimHash = Animator.StringToHash("attack");
private readonly AudioClip _attackClip;
public AttackState(Enemy enemy) : base(EnemyState.Attack)
{
_enemy = enemy;
_attackClip = Resources.Load<AudioClip>("Audio/EnemySounds/FX/attack");
}
[ServerCallback]
public override void Enter()
{
_enemy.SetSpeedMul(1f);
}
[ServerCallback]
public override void Update()
if (_enemy.isServer)
{
_enemy.networkAnimator.SetTrigger(AttackAnimHash);
_enemy.RpcKillTarget(_enemy.targetTransform);
_enemy.ChangeState(EnemyState.Patrol);
_enemy.ChangeState(EnemyState.Idle);
}
if (_enemy.isClient)
{
_enemy.audioSource.PlayOneShot(_attackClip);
}
}
[ServerCallback]

View File

@ -7,19 +7,30 @@ namespace Characters.Enemy.States
public class ChaseState : State<EnemyState>
{
private readonly Enemy _enemy;
private readonly AudioClip _agressiveClip;
public ChaseState(Enemy enemy) : base(EnemyState.Chase)
{
_enemy = enemy;
_agressiveClip = Resources.Load<AudioClip>("Audio/EnemySounds/FX/agressive2");
}
[ServerCallback]
public override void Enter()
{
if (_enemy.isServer)
{
_enemy.SetSpeedMul(1f);
_enemy.SetAimRigWeight(1f);
}
if (_enemy.isClient)
{
_enemy.audioSource.clip = _agressiveClip;
_enemy.audioSource.loop = true;
_enemy.audioSource.Play();
}
}
[ServerCallback]
public override void Update()
{
@ -34,22 +45,30 @@ namespace Characters.Enemy.States
if (distanceToTarget < 1f)
{
_enemy.ChangeState(EnemyState.Attack);
return;
}
_enemy.targetTransform = _enemy.GetClosestTarget();
}
else
{
_enemy.ChangeState(EnemyState.Idle);
}
_enemy.targetTransform = _enemy.GetClosestTarget();
}
[ServerCallback]
public override void Exit()
{
_enemy.targetTransform = null;
if (_enemy.isServer)
{
_enemy.SetAimRigWeight(0f);
}
if (_enemy.isClient)
{
_enemy.audioSource.loop = false;
_enemy.audioSource.Stop();
}
}
}
}

View File

@ -8,21 +8,31 @@ namespace Characters.Enemy.States
{
private readonly Enemy _enemy;
private static readonly int DanceAnimHash = Animator.StringToHash("dance");
private readonly AudioClip _danceClip;
private bool _entered;
public IdleState(Enemy enemy) : base(EnemyState.Idle)
{
_enemy = enemy;
_danceClip = Resources.Load<AudioClip>("Audio/EnemySounds/FX/dance");
}
[ServerCallback]
public override void Enter()
{
if (_enemy.isServer)
{
_enemy.SetSpeedMul(0f);
_enemy.networkAnimator.SetTrigger(DanceAnimHash);
}
if (_enemy.isClient)
{
_enemy.audioSource.clip = _danceClip;
_enemy.audioSource.volume = 0.03f;
_enemy.audioSource.Play();
}
}
[ServerCallback]
public override void Update()
{
@ -35,13 +45,21 @@ namespace Characters.Enemy.States
if (_entered && !inAnim) _enemy.ChangeState(EnemyState.Patrol);
}
[ServerCallback]
public override void Exit()
{
if (_enemy.isServer)
{
_entered = false;
_enemy.networkAnimator.ResetTrigger(DanceAnimHash);
_enemy.SetSpeedMul(1f);
}
if (_enemy.isClient)
{
_enemy.audioSource.volume = 1f;
_enemy.audioSource.Stop();
}
}
}
}

View File

@ -10,13 +10,10 @@ namespace Characters.Enemy.States
private readonly Enemy _enemy;
private readonly NavMeshTriangulation _navMeshData;
private CustomNetworkManager _networkManager;
public PatrolState(Enemy enemy) : base(EnemyState.Patrol)
{
_enemy = enemy;
_navMeshData = NavMeshTriangulator.Data;
_networkManager = NetworkManager.singleton.GetComponent<CustomNetworkManager>();
}
[ServerCallback]
@ -30,7 +27,7 @@ namespace Characters.Enemy.States
{
_enemy.targetTransform = _enemy.GetClosestTarget();
if (_enemy.targetTransform != null)
if (_enemy.HasTarget)
{
_enemy.ChangeState(EnemyState.Chase);
@ -46,11 +43,13 @@ namespace Characters.Enemy.States
}
}
[Server]
void SetRandomDestination()
{
_enemy.agent.destination = GetRandomLocation();
}
[Server]
Vector3 GetRandomLocation()
{
return _navMeshData.vertices[_navMeshData.indices[Random.Range(0, _navMeshData.indices.Length - 3)]];

View File

@ -10,21 +10,20 @@ namespace Characters.Enemy.States
public class StunnedState : State<EnemyState>
{
private readonly Enemy _enemy;
private static readonly int StunnedAnimHash = Animator.StringToHash("stunned");
private readonly AudioClip _stunnedClip;
private bool _entered;
public StunnedState(Enemy enemy) : base(EnemyState.Stunned)
{
_enemy = enemy;
_stunnedClip = Resources.Load<AudioClip>("Audio/EnemySounds/FX/stunned");
}
public override void Enter()
{
if (_enemy.isServer)
{
_enemy.canAttack = false;
_enemy.targetTransform = null;
_enemy.SetSpeedMul(0f);
@ -33,17 +32,27 @@ namespace Characters.Enemy.States
if(_enemy.isClient)
{
_enemy.audioSource.clip = _stunnedClip;
_enemy.audioSource.Play();
_enemy.hitVFX.Stop();
_enemy.hitVFX.Play();
}
}
[ServerCallback]
public override void ReEnter()
{
if (_enemy.isServer)
{
_enemy.networkAnimator.SetTrigger(StunnedAnimHash);
}
if (_enemy.isClient)
{
_enemy.audioSource.Stop();
_enemy.audioSource.Play();
}
}
[ServerCallback]
public override void Update()
{
@ -56,15 +65,20 @@ namespace Characters.Enemy.States
if (_entered && !inAnim) _enemy.ChangeState(EnemyState.Patrol);
}
[ServerCallback]
public override void Exit()
{
if (_enemy.isServer)
{
_entered = false;
_enemy.networkAnimator.ResetTrigger(StunnedAnimHash);
_enemy.SetSpeedMul(1f);
}
_enemy.canAttack = true;
if (_enemy.isClient)
{
_enemy.audioSource.Stop();
}
}
}
}

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using UnityEngine;
namespace Koptilnya.StateMachine
{
@ -52,6 +53,7 @@ namespace Koptilnya.StateMachine
if (mCurrentState != null)
{
Debug.Log($"{mCurrentState.ID} -> {state.ID}");
mCurrentState.Exit();
}