problem with mirror(particle system) unity, pls help:) - c#

I have a problem with mirror, I'm making a online strategy game and you have buildings in the game, with those buildings you can make soldiers, now the buildings have a particles sim to work while they make more solider, but only the server can see the particles sim of its own buildings and the opponents, any ideas why?
that's the code for building smoke:
#region data
[SerializeField] private ParticleSystem[] Explotion = new ParticleSystem[2];
[SerializeField] private Unit UnitPrefab;
[SerializeField] private Transform position;
[SerializeField] private Health MyHp;
[SerializeField] private Image ProgressBar = null;
[SerializeField] private TMP_Text QuaeText = null;
[SerializeField] private float QDurition = 5f;
[SerializeField] private float SpaceSpawn = 7f;
[SerializeField] private int QMax = 5;
[SerializeField] private float progressImageVelocity = 2;
bool played = false;
[SyncVar(hook = nameof(UpdateQText))] private int QuadeUnits;
[SyncVar] private float Timer = 0f;
private ParticleSystem Smoke = null;
private RTSPlayer player;
private float QProgress;
#endregion
//[ServerCallback]
private void UpdateQText(int OldQ,int NewQ)
{
QuaeText.text = NewQ.ToString();
}
private void Update()
{
if(Smoke == null)
{
Smoke = GetComponentInChildren<ParticleSystem>();
}
if(player == null)
{
player = NetworkClient.connection.identity.GetComponent<RTSPlayer>();
}
if (isServer)
{
ProduceUnits();
}
if (isClient)
{
UpdateTimer();
}
if(QuadeUnits <= 0)
{
QuadeUnits = 0;
Timer = 0;
QProgress = 0;
ProgressBar.fillAmount = 0;
}
}
[Server]
private void ProduceUnits()
{
if(QuadeUnits == 0)
{
try
{
Smoke.Stop();
}
catch
{
}
played = false;
return;
}
try
{
if (!played)
{
print("playing");
Smoke.Play();
played = true;
}
}
catch
{
}
Timer += Time.deltaTime;
if(Timer < QDurition) { return; }
GameObject instance1 = Instantiate(UnitPrefab.gameObject, position.position, position.rotation);
NetworkServer.Spawn(instance1, connectionToClient);
Vector3 SpawnPlace = gameObject.transform.position * SpaceSpawn;
SpawnPlace.y = 0;
Movment ClearSpot = instance1.gameObject.GetComponent<Movment>();
ClearSpot.ServerMoveUnit(SpawnPlace);
instance1.gameObject.GetComponent<HPDispaly>().SetEnacled(false);
QuadeUnits--;
Timer = 0f;
}

This wasn't really useful but I found other code that helped me with this problem, if someone has the same problem here's the solution:
Solution
You need to make a syncVar bool and update the animator using it and not with just regular false/true calls, here's my new code:
#region data
[SyncVar(hook = nameof(HandleBuilding))] private bool IsBuildng = false;
[SyncVar(hook = nameof(HandleExplotion))] private bool IsPlaying = false;
[SerializeField] private ParticleSystem[] Explotion = new ParticleSystem[2];
[SerializeField] private Unit UnitPrefab;
[SerializeField] private Transform position;
[SerializeField] private Health MyHp;
[SerializeField] private Image ProgressBar = null;
[SerializeField] private TMP_Text QuaeText = null;
[SerializeField] private float QDurition = 5f;
[SerializeField] private float SpaceSpawn = 7f;
[SerializeField] private int QMax = 5;
[SerializeField] private float progressImageVelocity = 2;
bool played = false;
[SyncVar(hook = nameof(UpdateQText))] private int QuadeUnits;
[SyncVar] private float Timer = 0f;
[SerializeField] private ParticleSystem Smoke = null;
private RTSPlayer player;
private float QProgress;
#endregion
//[ServerCallback]
private void UpdateQText(int OldQ,int NewQ)
{
QuaeText.text = NewQ.ToString();
}
private void HandleBuilding(bool OldBool,bool NewBool)
{
Smoke.gameObject.SetActive(IsBuildng);
}
private void Update()
{
if(Smoke == null)
{
Smoke = GetComponentInChildren<ParticleSystem>();
}
if(player == null)
{
player = NetworkClient.connection.identity.GetComponent<RTSPlayer>();
}
if (isServer)
{
ProduceUnits();
}
if (isClient)
{
UpdateTimer();
}
if(QuadeUnits <= 0)
{
QuadeUnits = 0;
Timer = 0;
QProgress = 0;
ProgressBar.fillAmount = 0;
}
}
[Server]
private void ProduceUnits()
{
if(QuadeUnits == 0)
{
IsBuildng = false;
played = false;
return;
}
else
{
IsBuildng = true;
}
IsBuildng = true;
Timer += Time.deltaTime;
if(Timer < QDurition) { return; }
GameObject instance1 = Instantiate(UnitPrefab.gameObject, position.position, position.rotation);
NetworkServer.Spawn(instance1, connectionToClient);
Vector3 SpawnPlace = gameObject.transform.position * SpaceSpawn;
SpawnPlace.y = 0;
Movment ClearSpot = instance1.gameObject.GetComponent<Movment>();
ClearSpot.ServerMoveUnit(SpawnPlace);
instance1.gameObject.GetComponent<HPDispaly>().SetEnacled(false);
QuadeUnits--;
Timer = 0f;
}

Related

Problems after adding a stamina system

I've added a stamina system in my game, but when I try do call the function there's a few problems happening:
I can't jump when my character is sprinting and when I jump and press the sprint button my character doesn't fall anymore, he basically just flies.
PlayerController
private Vector3 playerVelocity;
private bool groundedPlayer;
private CharacterController controller;
private PlayerControls playerControls;
private InputManager inputManager;
public HealthBar healthBar;
public StaminaBar staminaBar;
public int currentHealth;
public int maxHealth = 100;
public int currentStamina;
public int maxStamina = 100;
public int staminaDrain = 10;
[SerializeField]
private float playerSpeed = 2.0f;
[SerializeField]
private float playerRunSpeed= 1f;
[SerializeField]
private float jumpHeight = 1.0f;
[SerializeField]
private float gravityValue = -9.81f;
private Transform cameraTransform;
private void Start()
{
currentHealth = maxHealth;
healthBar.SetMaxHealth(maxHealth);
currentStamina = maxStamina;
staminaBar.SetMaxStamina(maxStamina);
controller = GetComponent<CharacterController>();
inputManager = InputManager.Instance;
cameraTransform = Camera.main.transform;
//player = GameObject.Find("Player");
}
void Update()
{
groundedPlayer = controller.isGrounded;
if (groundedPlayer && playerVelocity.y < 0)
{
playerVelocity.y = 0f;
}
Vector2 movement = inputManager.GetPlayerMovement();
Vector3 move = new Vector3(movement.x, 0f, movement.y);
move = cameraTransform.forward * move.z + cameraTransform.right * move.x;
move.y = 0f;
//controller.Move(move * Time.deltaTime * playerSpeed);
if(inputManager.isRunning && currentStamina > 0)
{
controller.Move(move * playerRunSpeed * Time.deltaTime);
staminaBar.UseStamina(staminaDrain);
staminaBar.staminaSlider.value = currentStamina;
}
else
{
controller.Move(move * Time.deltaTime * playerSpeed);
}
// Changes the height position of the player..
if (inputManager.PlayerJumpedThisFrame() && groundedPlayer)
{
playerVelocity.y += Mathf.Sqrt(jumpHeight * -3.0f * gravityValue);
}
playerVelocity.y += gravityValue * Time.deltaTime;
controller.Move(playerVelocity * Time.deltaTime);
}
StaminaBar script
public class StaminaBar : MonoBehaviour
{
public Slider staminaSlider;
private PlayerController playerController;
private WaitForSeconds regenTick = new WaitForSeconds(0.1f);
private Coroutine regen;
public void SetMaxStamina(int stamina){
staminaSlider.maxValue = stamina;
staminaSlider.value = stamina;
}
public void SetStamina(int stamina){
staminaSlider.value = stamina;
}
public void UseStamina(int amount){
if(playerController.currentStamina - amount >= 0){
playerController.currentStamina -= amount;
staminaSlider.value = playerController.currentStamina;
Debug.Log("Losing Stamina");
if(regen != null)
StopCoroutine(regen);
regen = StartCoroutine(RegenStamina());
}
else
{
Debug.Log("NotEnoughStamina");
}
}
private IEnumerator RegenStamina()
{
yield return new WaitForSeconds(2);
while(playerController.currentStamina < playerController.maxStamina){
playerController.currentStamina += playerController.maxStamina/100;
staminaSlider.value = playerController.currentStamina;
yield return regenTick;
}
regen = null;
}
}
Input Manager
{
private StaminaBar staminaBar;
private PlayerController playerController;
[SerializeField]
private float bulletHitMissDistance = 25f;
[SerializeField]
private Transform bulletParent;
[SerializeField]
private Transform barrelTransform;
[SerializeField]
private GameObject bulletPrefab;
[SerializeField]
private float damage = 100;
public float impactForce = 30;
public float fireRate = 8f;
WaitForSeconds rapidFireWait;
public bool isRunning;
private static InputManager _instance;
public static InputManager Instance
{
get {
return _instance;
}
}
private PlayerControls playerControls;
private Transform cameraTransform;
Coroutine fireCoroutine;
private void Awake()
{
if(_instance != null && _instance != this)
{
Destroy(this.gameObject);
}
else
{
_instance = this;
}
playerControls = new PlayerControls();
//Cursor.visible = false;
rapidFireWait = new WaitForSeconds(1/fireRate);
cameraTransform = Camera.main.transform;
playerControls.Player.RunStart.performed += x => Running();
playerControls.Player.RunEnd.performed += x => RunningStop();
playerControls.Player.Shoot.started += _ => StartFiring();
playerControls.Player.Shoot.canceled += _ => StopFiring();
}
private void OnEnable()
{
playerControls.Enable();
//playerControls.Player.Shoot.performed += _ => StartFiring();
}
private void OnDisable()
{
playerControls.Disable();
//playerControls.Player.Shoot.performed += _ => StopFiring();
}
void StartFiring()
{
fireCoroutine = StartCoroutine(RapidFire());
}
void StopFiring()
{
if(fireCoroutine != null)
{
StopCoroutine(fireCoroutine);
}
}
public Vector2 GetPlayerMovement()
{
return playerControls.Player.Movement.ReadValue<Vector2>();
}
public Vector2 GetMouseDelta(){
return playerControls.Player.Look.ReadValue<Vector2>();
}
public bool PlayerJumpedThisFrame(){
return playerControls.Player.Jump.triggered;
}
public void Shooting()
{
RaycastHit hit;
//creates the bullet
GameObject bullet = GameObject.Instantiate(bulletPrefab, barrelTransform.position, Quaternion.identity, bulletParent);
BulletController bulletController = bullet.GetComponent<BulletController>();
//shoots the bullet forwards
if (Physics.Raycast(cameraTransform.position, cameraTransform.forward, out hit, Mathf.Infinity))
{
//checks if the bullet hit something
bulletController.target = hit.point;
bulletController.hit = true;
//makes enemy take damage
Enemy takingDamage = hit.transform.GetComponent<Enemy>();
if (takingDamage != null)
{
takingDamage.TakeDamage(damage);
}
//makes enemy go backwards when hit
if(hit.rigidbody != null)
{
hit.rigidbody.AddForce(-hit.normal * impactForce);
}
}
else
{
bulletController.target = cameraTransform.position + cameraTransform.forward * bulletHitMissDistance;
bulletController.hit = false;
}
}
public IEnumerator RapidFire()
{
while(true)
{
Shooting();
yield return rapidFireWait;
}
}
public void Running()
{
/* if(playerController.currentStamina > 0){
isRunning = true;
staminaBar.UseStamina(playerController.staminaDrain);
staminaBar.staminaSlider.value = playerController.currentStamina;
} */
isRunning = true;
}
public void RunningStop(){
isRunning =false;
}
}
I'm using unity new input system and tried to call the function in two different ways: in the isRunning and when I actually do the sprint function.
I was expecting the player to lose 10 stamina every time I press the sprint button, I was trying to figure that out before trying to make him lose stamina while the button is pressed.
I've seen a couple videos on YouTube, which is where I got the code from, but can't find out what I'm doing wrong when calling the function, I've had similar problems before when trying to call a TakeDamage function but I guess that's a different question.
So here is what I would do.
Instead of controlling the stamina in multiple places and hve forth and back references (=dependencies) between all your scripts I would rather keep this authority within the PlayerController.
Your StaminaBar component should be purely listening and visualizing the current value without having the authority to modify it.
Next step would be to decide for a general code structure
Who is responsible for what?
Who knows / controls what?
There are many possible answers to those but for now an this specific case
You can either say the PlayerController "knows" the StaminaBar just like it also knows the InputManager and can't live without both
Or you could decouple them and let the PlayerController work without having the visualization via the StaminaBar but rather let the StaminaBar listen to the value and just display it .. or not if you want to remove or change this later on
Personally I would go with the second so I will try and give you an example how I would deal with this:
public class PlayerController : MonoBehaviour
{
[Header("Own References")]
[SerializeField] private CharacterController _controller;
[Header("Scene References")]
[SerializeField] private Transform _cameraTransform;
[SerializeField] private InputManager _inputManager;
// In general always make you stuff as encapsulated as possible
// -> nobody should be able to change these except you via the Inspector
// (Values you are anyway not gonna change at all you could also convert to "const")
[Header("Settings")]
[SerializeField] private float _maxHealth = 100f;
[SerializeField] private float _maxStamina = 100f;
[SerializeField] private float _staminaDrainPerSecond = 2f;
[SerializeField] private float _secondsDelayBeforeStaminaRegen = 1f;
[SerializeField] private float _staminaRegenPerSecond = 2f;
[SerializeField] private float _playerSpeed = 1f;
[SerializeField] private float _playerRunSpeed = 2f;
[SerializeField] private float _jumpHeight = 1f;
[SerializeField] private float _gravityValue = -9.81f;
// Your runtime valus
private float _staminaRegenDelayTimer;
private float _currentHealt;
private float _currentStamina;
// You only need a single float for this
private float _currentYVelocity;
// EVENTS we expose so other classes can react to those
public UnityEvent OnDeath;
public UnityEvent<float> OnHealthChanged;
public UnityEvent<float> OnStaminaChanged;
// Provide public read-only access to the settings so your visuals can access those for their setup
public float MaxHealth => _maxHealth;
public float MaxStamina => _maxStamina;
// And then use properties for your runtime values
// whenever you set the value you do additional stuff like cleaning the value and invoke according events
public float currentHealth
{
get => _currentHealt;
private set
{
_currentHealt = Mathf.Clamp(value, 0, _maxHealth);
OnHealthChanged.Invoke(_currentHealt);
if (value <= 0f)
{
OnDeath.Invoke();
}
}
}
public float currentStamina
{
get => _currentStamina;
private set
{
_currentStamina = Mathf.Clamp(value, 0, _maxStamina);
OnStaminaChanged.Invoke(_currentStamina);
}
}
private void Awake()
{
// As a thumb rule to avoid issues with order I usually initialize everything I an in Awake
if (!_controller) _controller = GetComponent<CharacterController>();
currentHealth = MaxHealth;
currentStamina = MaxStamina;
}
private void Start()
{
// in start do the things were you depend on others already being initialized
if (!_inputManager) _inputManager = InputManager.Instance;
if (!_cameraTransform) _cameraTransform = Camera.main.transform;
}
private void Update()
{
UpdateStamina();
UpdateHorizontalMovement();
UpdateVerticalMovement();
}
private void UpdateStamina()
{
if (_inputManager.IsRunning)
{
// drain your stamina -> also informs all listeners
currentStamina -= _staminaDrainPerSecond * Time.deltaTime;
// reset the regen timer
_staminaRegenDelayTimer = _secondsDelayBeforeStaminaRegen;
}
else
{
// only if not pressing run start the regen timer
if (_staminaRegenDelayTimer > 0)
{
_staminaRegenDelayTimer -= Time.deltaTime;
}
else
{
// once timer is finished start regen
currentStamina += _staminaRegenPerSecond * Time.deltaTime;
}
}
}
private void UpdateHorizontalMovement()
{
var movement = _inputManager.PlayerMovement;
var move = _cameraTransform.forward * movement.y + _cameraTransform.right * movement.x;
move.y = 0f;
move *= _inputManager.IsRunning && currentStamina > 0 ? _playerRunSpeed : _playerSpeed;
_controller.Move(move * Time.deltaTime);
}
private void UpdateVerticalMovement()
{
if (_controller.isGrounded)
{
if (_inputManager.JumpedThisFrame)
{
_currentYVelocity += Mathf.Sqrt(_jumpHeight * -3.0f * _gravityValue);
}
else if (_currentYVelocity < 0)
{
_currentYVelocity = 0f;
}
}
else
{
_currentYVelocity += _gravityValue * Time.deltaTime;
}
_controller.Move(Vector3.up * _currentYVelocity * Time.deltaTime);
}
}
And then your StaminaBar shinks down to really only being a display. The PlayerController doesn't care/even know it exists and can fully work without it.
public class StaminaBar : MonoBehaviour
{
[SerializeField] private Slider _staminaSlider;
[SerializeField] private PlayerController _playerController;
private void Awake()
{
// or wherever you get the reference from
if (!_playerController) _playerController = FindObjectOfType<PlayerController>();
// poll the setting from the player
_staminaSlider.maxValue = _playerController.MaxStamina;
// attach a callback to the event
_playerController.OnStaminaChanged.AddListener(OnStaminaChanged);
// just to be sure invoke the callback once immediately with the current value
// so we don't have to wait for the first actual event invocation
OnStaminaChanged(_playerController.currentStamina);
}
private void OnDestroy()
{
if(_playerController) _playerController.OnStaminaChanged.RemoveListener(OnStaminaChanged);
}
// This will now be called whenever the stamina has changed
private void OnStaminaChanged(float stamina)
{
_staminaSlider.value = stamina;
}
}
And just for completeness - I also refactored your InputManager a bit on the fly ^^
public class InputManager : MonoBehaviour
{
[Header("Own references")]
[SerializeField] private Transform _bulletParent;
[SerializeField] private Transform _barrelTransform;
[Header("Scene references")]
[SerializeField] private Transform _cameraTransform;
// By using the correct component right away you can later skip "GetComponent"
[Header("Assets")]
[SerializeField] private BulletController _bulletPrefab;
[Header("Settings")]
[SerializeField] private float _bulletHitMissDistance = 25f;
[SerializeField] private float _damage = 100;
[SerializeField] private float _impactForce = 30;
[SerializeField] private float _fireRate = 8f;
public static InputManager Instance { get; private set; }
// Again I would use properties here
// You don't want anything else to set the "isRunning" flag
// And the others don't need to be methods either
public bool IsRunning { get; private set; }
public Vector2 PlayerMovement => _playerControls.Player.Movement.ReadValue<Vector2>();
public Vector2 MouseDelta => _playerControls.Player.Look.ReadValue<Vector2>();
public bool JumpedThisFrame => _playerControls.Player.Jump.triggered;
private Coroutine _fireCoroutine;
private PlayerControls _playerControls;
private WaitForSeconds _rapidFireWait;
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
}
else
{
Instance = this;
}
_playerControls = new PlayerControls();
//Cursor.visible = false;
_rapidFireWait = new WaitForSeconds(1 / _fireRate);
_cameraTransform = Camera.main.transform;
_playerControls.Player.RunStart.performed += _ => Running();
_playerControls.Player.RunEnd.performed += _ => RunningStop();
_playerControls.Player.Shoot.started += _ => StartFiring();
_playerControls.Player.Shoot.canceled += _ => StopFiring();
}
private void OnEnable()
{
_playerControls.Enable();
}
private void OnDisable()
{
_playerControls.Disable();
}
private void StartFiring()
{
_fireCoroutine = StartCoroutine(RapidFire());
}
private void StopFiring()
{
if (_fireCoroutine != null)
{
StopCoroutine(_fireCoroutine);
_fireCoroutine = null;
}
}
private void Shooting()
{
var bulletController = Instantiate(_bulletPrefab, _barrelTransform.position, Quaternion.identity, _bulletParent);
if (Physics.Raycast(_cameraTransform.position, _cameraTransform.forward, out var hit, Mathf.Infinity))
{
bulletController.target = hit.point;
bulletController.hit = true;
if (hit.transform.TryGetComponent<Enemy>(out var enemy))
{
enemy.TakeDamage(_damage);
}
if (hit.rigidbody != null)
{
hit.rigidbody.AddForce(-hit.normal * _impactForce);
}
}
else
{
bulletController.target = _cameraTransform.position + _cameraTransform.forward * _bulletHitMissDistance;
bulletController.hit = false;
}
}
private IEnumerator RapidFire()
{
while (true)
{
Shooting();
yield return _rapidFireWait;
}
}
private void Running()
{
IsRunning = true;
}
private void RunningStop()
{
IsRunning = false;
}
}
You're decreasing and increasing the stamina in the same scope. I think you should let the stamina to be drained when sprint is pressed and start regenerating only if it is released.

Trying to implement a zoom function into my game but it wont unzoom

hello im trying to implement a zoom function into my game but when i release my zoom key it wont lerp my FOV back to its original position
[Header("Functional Options")]
[SerializeField] private bool canSprint = true;
[SerializeField] private bool canJump = true;
[SerializeField] private bool canCrouch = true;
[SerializeField] private bool canUseHeadbob = true;
[SerializeField] private bool willSlideOnSlopes = true;
[SerializeField] private bool canZoom = true;
[Header("Zoom Parameters")]
[SerializeField] private float timeToZoom = 0.3f;
[SerializeField] private float zoomFOV = 30f;
[SerializeField] private float defaultFOV;
private Coroutine zoomRoutine;
void Awake()
{
playerCamera = GetComponentInChildren<Camera>();
characterController = GetComponent<CharacterController>();
defaultYPos = playerCamera.transform.localPosition.y;
defaultFOV = playerCamera.fieldOfView;
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
void Update()
{
if (canMove)
{
HandleMovementInput();
HandleMouseLook();
if (canJump)
{
HandleJump();
}
if (canCrouch)
{
HandleCrouch();
}
if (canUseHeadbob)
{
HandleHeadbob();
}
if(canZoom)
{
HandleZoom();
}
ApplyFinalMovements();
}
}
private void HandleZoom()
{
if(Input.GetKeyDown(zoomKey))
{
if(zoomRoutine != null)
{
StopCoroutine(zoomRoutine);
zoomRoutine = null;
}
zoomRoutine = StartCoroutine(toggleZoom(true));
if (Input.GetKeyUp(zoomKey))
{
if (zoomRoutine != null)
{
StopCoroutine(zoomRoutine);
zoomRoutine = null;
}
zoomRoutine = StartCoroutine(toggleZoom(false));
}
}
}
private IEnumerator toggleZoom(bool isEnter)
{
float targetFOV = isEnter ? zoomFOV : defaultFOV;
float startingFOV = playerCamera.fieldOfView;
float timeElapsed = 0;
while(timeElapsed < timeToZoom)
{
playerCamera.fieldOfView = Mathf.Lerp(startingFOV, targetFOV, timeElapsed / timeToZoom);
timeElapsed += Time.deltaTime;
yield return null;
}
playerCamera.fieldOfView = targetFOV;
zoomRoutine = null;
}
Your code does not work because your second if statement is inside the first if statement.Your code should look like this:
private void HandleZoom()
{
if (Input.GetKeyDown(zoomKey))
{
if (zoomRoutine != null)
{
StopCoroutine(zoomRoutine);
zoomRoutine = null;
}
zoomRoutine = StartCoroutine(toggleZoom(true));
}
if (Input.GetKeyUp(zoomKey))
{
if (zoomRoutine != null)
{
StopCoroutine(zoomRoutine);
zoomRoutine = null;
}
zoomRoutine = StartCoroutine(toggleZoom(false));
}
}

Why is this audio source not playing anything?

Im trying to write a script where the audio source plays an audioclip array with 4 sounds in it. The sounds are gonna be played faster and louder when my character is sprinting and quieter and slower when my character is crouching. My problem is that the audiosource doesn't play the audioclip. I've checked it multiple times and I really can't find the problem.
`public class PlayerFootsteps : MonoBehaviour
{
private AudioSource footstepSound;
[SerializeField]
private AudioClip[] footstepClip;
private CharacterController charController;
[HideInInspector]
public float VolumeMin, VolumeMax;
private float accumulatedDistance;
[HideInInspector]
public float stepDistance;
void Awake()
{
footstepSound = GetComponent<AudioSource>();
charController = GetComponentInParent<CharacterController>();
}
void Update()
{
CheckToPlayFootstepSounds();
}
void CheckToPlayFootstepSounds()
{
if (!charController.isGrounded)
{
return;
}
if (charController.velocity.magnitude > 0)
{
accumulatedDistance += Time.deltaTime;
if (accumulatedDistance > stepDistance)
{
footstepSound.volume = Random.Range(VolumeMin, VolumeMax);
footstepSound.clip = footstepClip[Random.Range(0, footstepClip.Length)];
footstepSound.Play();
accumulatedDistance = 0f;
}
else
{
accumulatedDistance = 0f;
}
}
}
}`
public class PlayerSprintAndCrouch : MonoBehaviour
{
private PlayerMovement playerMovement;
public float sprintSpeed = 10f, moveSpeed = 5f, crouchSpeed = 2f;
[SerializeField]
private Transform lookRoot;
private float standHeight = 1.6f, crouchHeight = 1f;
private bool isCrouching;
private PlayerFootsteps playerFootsteps;
private float sprintVolume = 1f;
private float crouchVolume = 0.1f;
private float walkVolumeMin = 0.2f, walkVolumeMax = 0.6f;
private float walkStepDistance = 0.4f, sprintStepDistance = 0.25f, crouchStepDistance = 0.5f;
void Awake()
{
playerMovement = GetComponent<PlayerMovement>();
playerFootsteps = GetComponentInChildren<PlayerFootsteps>();
}
void Start()
{
playerFootsteps.VolumeMin = walkVolumeMin;
playerFootsteps.VolumeMax = walkVolumeMax;
playerFootsteps.stepDistance = walkStepDistance;
}
// Update is called once per frame
void Update()
{
Sprint();
Crouch();
}
void Sprint()
{
if (Input.GetKeyDown(KeyCode.LeftShift) && !isCrouching)
{
playerMovement.speed = sprintSpeed;
playerFootsteps.stepDistance = sprintStepDistance;
playerFootsteps.VolumeMin = sprintVolume;
playerFootsteps.VolumeMax = sprintVolume;
}
if (Input.GetKeyUp(KeyCode.LeftShift) && !isCrouching)
{
playerMovement.speed = moveSpeed;
playerFootsteps.stepDistance = walkStepDistance;
playerFootsteps.VolumeMin = walkVolumeMin;
playerFootsteps.VolumeMax = walkVolumeMax;
}
}
void Crouch()
{
if (Input.GetKeyDown(KeyCode.LeftControl))
{
if (isCrouching)
{
lookRoot.localPosition = new Vector3(0f, standHeight, 0f);
playerMovement.speed = moveSpeed;
isCrouching = false;
}
else
{
lookRoot.localPosition = new Vector3(0f, crouchHeight, 0f);
playerMovement.speed = crouchSpeed;
playerFootsteps.stepDistance = crouchStepDistance;
playerFootsteps.VolumeMin = crouchVolume;
playerFootsteps.VolumeMax = crouchVolume;
isCrouching = true;
}
}
}
}
The problem is that you are setting the accumulatedDistance to 0, This should fix your problem:
void CheckToPlayFootstepSounds()
{
if (!charController.isGrounded)
{
return;
}
if (charController.velocity.magnitude > 0)
{
accumulatedDistance += Time.deltaTime;
if (accumulatedDistance > stepDistance)
{
footstepSound.volume = Random.Range(VolumeMin, VolumeMax);
footstepSound.clip = footstepClip[Random.Range(0, footstepClip.Length)];
footstepSound.Play();
accumulatedDistance = 0f;
}
else
{
// accumulatedDistance = 0f; Remove This
}
}
}

Unity: How do I start my weapon reload countdown when I am reloading?

I have a Timer that counts down every 3 seconds (The white circle). It has a script attached called ReloadTimer.
I have a script that fires bullets (TankShooter) and reloads for 3 seconds.
How do I make it so that my countdown starts when I am reloading?
I tried looking at a lot of Unity forums and the advice didn't work.
ReloadTimer.cs
[ExecuteInEditMode]
public class ReloadTimer : MonoBehaviour
{
public Image filled;
public Text text;
public float maxValue = 3;
public float value = 0;
// UpdateReload is called once per frame
public void UpdateReload ()
{
value = Mathf.Clamp(value, 0, maxValue);
float amount = value / maxValue;
filled.fillAmount = amount;
text.text = value.ToString();
}
}
TankShooter
public int m_PlayerNumber = 1;
public Rigidbody m_Shell;
public Transform m_FireTransform;
public AudioSource m_ShootingAudio;
public AudioClip m_FireClip;
public float m_ShellVelocity = 100f;
private string m_FireButton;
public int maxAmmo = 5;
private int currentAmmo;
public float reloadTime = 2f;
private bool isReloading = false;
public ReloadTimer reloadTimer;
public class TankShootingT : NetworkBehaviour
{
public ReloadTimer reloadTimer;
private void Start()
{
if (!isLocalPlayer)
{
return;
}
currentAmmo = maxAmmo;
m_FireButton = "Fire" + m_PlayerNumber;
}
private void Update()
{
if (isReloading)
return;
if (currentAmmo <= 0)
{
StartCoroutine(Reload());
return;
}
reloadTimer.UpdateReload();
if (m_FireButton == "Fire1" && Input.GetButtonUp(m_FireButton))
{
// we released the button, have not fired yet
CmdShoot();
}
}
IEnumerator Reload()
{
isReloading = true;
Debug.Log("Reloading...");
yield return new WaitForSeconds(reloadTime);
currentAmmo = maxAmmo;
isReloading = false;
}
[Command]
private void CmdShoot()
{
currentAmmo--;
// Instantiate and launch the shell.
Rigidbody shellInstance = Instantiate(m_Shell, m_FireTransform.position, m_FireTransform.rotation) as Rigidbody;
shellInstance.velocity = m_ShellVelocity * m_FireTransform.forward;
// Server spawns the shell
NetworkServer.Spawn(shellInstance.gameObject);
m_ShootingAudio.clip = m_FireClip;
m_ShootingAudio.Play();
}
}
For starters, There isn't such thing as UpdateReload that would be "called once per frame" as this is not a predetermined Unity function, it is just a function that you created (You can read about this here). Another problem is that you didn't even call that function anywhere else in your scripts. And even if you did, Mathf.Clamp() needs to be placed in an Update() function so it can update it's value each frame.
I made some modifications to the scripts that you posted, but I haven't tested them yet. give it a try and let me know how it goes:
ReloadTimer.cs
public class ReloadTimer : MonoBehaviour
{
public static ReloadTimer Instance { set; get; }
public Image filled;
public Text text;
public float coolDownTime = 3;
public bool isCoolingDown = false;
void Awake()
{
Instance = this;
}
void Update()
{
if (isCoolingDown == true)
{
filled.fillAmount += 1.0f / coolDownTime * Time.deltaTime;
int percentageInt = Mathf.RoundToInt((filled.fillAmount / coolDownTime) * 10);
text.text = percentageInt.ToString();
}
}
}
TankShootingT.cs
public int m_PlayerNumber = 1;
public Rigidbody m_Shell;
public Transform m_FireTransform;
public AudioSource m_ShootingAudio;
public AudioClip m_FireClip;
public float m_ShellVelocity = 100f;
private string m_FireButton;
public int maxAmmo = 5;
private int currentAmmo;
public float reloadTime = 2f;
private bool isReloading = false;
public ReloadTimer reloadTimer;
public class TankShootingT : NetworkBehaviour
{
public ReloadTimer reloadTimer;
private void Start()
{
if (!isLocalPlayer)
{
return;
}
currentAmmo = maxAmmo;
m_FireButton = "Fire" + m_PlayerNumber;
}
private void Update()
{
if (isReloading)
return;
if (currentAmmo <= 0)
{
StartCoroutine(Reload());
return;
}
reloadTimer.UpdateReload();
if (m_FireButton == "Fire1" && Input.GetButtonUp(m_FireButton))
{
// we released the button, have not fired yet
CmdShoot();
}
}
IEnumerator Reload()
{
isReloading = true;
ReloadTimer.Instance.isCoolingDown = true;
Debug.Log("Reloading...");
yield return new WaitForSeconds(reloadTime);
currentAmmo = maxAmmo;
isReloading = false;
ReloadTimer.Instance.isCoolingDown = false;
ReloadTimer.Instance.filled.fillAmount = 0.0f;
}
[Command]
private void CmdShoot()
{
currentAmmo--;
// Instantiate and launch the shell.
Rigidbody shellInstance = Instantiate(m_Shell, m_FireTransform.position, m_FireTransform.rotation) as Rigidbody;
shellInstance.velocity = m_ShellVelocity * m_FireTransform.forward;
// Server spawns the shell
NetworkServer.Spawn(shellInstance.gameObject);
m_ShootingAudio.clip = m_FireClip;
m_ShootingAudio.Play();
}
}
Hope this helps a bit.

Unity: My enemy projectile is being destroyed before ever leaving it's spawn location. What am i doing wrong?

Like the title says, the enemy projectiles are not launching. They are spawned and destroyed in the same place. They do not fire toward the target. Code in link:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MonkeyController : MonoBehaviour {
private const int MAX_INJURES = 1;
public float DurationMovement = 2f;
public Transform SpawnLocation;
public Transform[] PatrolPoints;
public GameObject MonkeyProjectile;
public Rigidbody2D Abby;
public float AttackDelay = 0.75f;
public float ProjectileSpeed = 1;
public int ProjectilesCount = 4;
public float activePosition;
public float passivePosition;
private List<GameObject> ProjectileList = new List<GameObject>();
private int PatrolIndex = 0;
private int injures = 0;
private bool canPatrol;
private Coroutine fireCoroutine;
private Coroutine patrolCoroutine;
private Coroutine movementCoroutine;
WaitForSeconds delay;
Vector2 AttackVector = Vector2.zero;
// Use this for initialization
private void Start () {
delay = new WaitForSeconds(AttackDelay);
InitializeProjectileList();
fireCoroutine = StartCoroutine(MonkeyFireProjectileBehaviour());
patrolCoroutine = StartCoroutine(PatrolBehaviour(PatrolPoints[PatrolIndex].position));
}
private IEnumerator MonkeyFireProjectileBehaviour()
{
yield return delay;
if (GameManager.GetInstance().gameState == GameState.GAME_OVER)
yield return null;
AttackVector = Abby.transform.position - (transform.position /*+ (Vector3)Abby.velocity/10f*/);
FireProjectile(AttackVector);
fireCoroutine = StartCoroutine(MonkeyFireProjectileBehaviour());
}
private IEnumerator PatrolBehaviour(Vector3 animationLocation)
{
canPatrol = true;
float distance = (transform.position - animationLocation).magnitude;
float duration = DurationMovement;
Vector3 startingPos = transform.position;
float t = 0;
while (t < 1 && canPatrol)
{
t += Time.deltaTime / duration;
transform.position = Vector3.Lerp(startingPos, animationLocation, t);
yield return null;
}
if (!canPatrol)
yield break;
transform.position = animationLocation;
IncrementMovementIndex();
patrolCoroutine = StartCoroutine(PatrolBehaviour(PatrolPoints[PatrolIndex].position));
yield return null;
}
private void IncrementMovementIndex()
{
PatrolIndex++;
if(PatrolIndex == PatrolPoints.Length)
{
PatrolIndex = 0;
}
}
private void InitializeProjectileList()
{
GameObject Projectile;
for (int i = 0; i < ProjectilesCount; i++)
{
Projectile = Instantiate(MonkeyProjectile);
Projectile.SetActive(false);
ProjectileList.Add(Projectile);
}
}
private void FireProjectile(Vector2 forceProjectile)
{
foreach (GameObject projectile in ProjectileList)
{
if (!projectile.activeInHierarchy)
{
projectile.transform.position = SpawnLocation.position;
projectile.SetActive(true);
projectile.GetComponent<TrailRenderer>().enabled = true;
projectile.GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Dynamic;
projectile.GetComponent<Rigidbody2D>().AddForce(forceProjectile * (ProjectileSpeed + Random.Range(0, ProjectileSpeed/2)), ForceMode2D.Impulse);
break;
}
}
}
private IEnumerator DoMovementCoroutine()
{
yield return new WaitForSeconds (0.01F);
transform.localPosition = new Vector2(passivePosition, 0);
yield return AnimatorExecutive.AnimatePositionCoroutine (gameObject, new Vector2 (activePosition, 0), 5.0F);
fireCoroutine = StartCoroutine(MonkeyFireProjectileBehaviour());
patrolCoroutine = StartCoroutine(PatrolBehaviour(PatrolPoints[PatrolIndex].position));
}
private void OnCollisionEnter2D(Collision2D otherCollision)
{
if (otherCollision.gameObject.tag == "Projectile")
{
injures++;
if (injures >= MAX_INJURES)
{
injures = 0;
canPatrol = false;
GetComponent<AudioSource>().Play();
if(fireCoroutine != null) StopCoroutine (fireCoroutine);
if(patrolCoroutine != null) StopCoroutine (patrolCoroutine);
movementCoroutine = StartCoroutine (DoMovementCoroutine());
}
}
}
}
With the information your provided, I would say the problem you may be facing is the GameObject you pass in the inspector to get the SpawnLocation has got a collider and a script with a OnCollisionEnter2D, which detect the projectil when you instantiate it and destroy it.
However, you are not destroying the projectil inside this OnCollisionEnter2D.
private void OnCollisionEnter2D(Collision2D otherCollision)
{
if (otherCollision.gameObject.tag == "Projectile")
{
injures++;
if (injures >= MAX_INJURES)
{
injures = 0;
canPatrol = false;
GetComponent<AudioSource>().Play();
if(fireCoroutine != null) StopCoroutine (fireCoroutine);
if(patrolCoroutine != null) StopCoroutine (patrolCoroutine);
movementCoroutine = StartCoroutine (DoMovementCoroutine());
}
}
}
In the case you dont have in your code any line to destroy the projectil gameobject after a collision. The problem could be you are not reaching this line projectile.SetActive(true);
I will try to replicate your code and check what may be happening

Categories