Formula to deal damage - armor - c#

I'm just starting to learn c# and got stuck in this exercise.
I need to create a formula to deal damage - armor. The armor is reduced with each hit. If I write
float damage = hp+armor-(physicalDamage-damageStrength)it doesn't damage the enemy. The task says I should change only `float damage = ...' for this code to work. So, the mistake can be only in this line float damage =
[RequireComponent(typeof(Animator))]
public class Goblin : MonoBehaviour, IDamagable {
static private string hitTriggerName = "Hit";
[SerializeField] private float hp = 800; // health
[SerializeField] private float armor = 100; // armor
[SerializeField] private float armorStrength = 5; // armor decrease each time
[SerializeField] private int n = 0; // number of hits
private Animator selfAnimator;
private void Awake() {
selfAnimator = GetComponent<Animator>();
}
public void ApplyDamage(float physicalDamage, float damageStrength) {
float damage = hp+armor-physicalDamage-damageStrength;
if (damage < 0) {
hp += damage;
}
n += 1;
armor -= armorStrength;
selfAnimator.SetTrigger(hitTriggerName);
}
public void onHitAnimationEnd() {
if (hp <= 0) {
Kill();
}
}
private void Kill() {
Destroy(gameObject);
}
}```
***Corersponding part of a "player" object***
```using System;
using UnityEngine;
[RequireComponent(typeof(Animator))]
public class Player : MonoBehaviour {
static private string attackTriggerName = "Attack";
[SerializeField] private float attackCooldown = 0.1f;
[SerializeField] private Goblin aim;
private float timeToNextAttack = 0f;
private Animator selfAnimator;
private void Awake() {
selfAnimator = GetComponent<Animator>();
}
[Serializable] private class Staff {
[SerializeField] private float physicalDamage = 100; // staff damage
[SerializeField] private float damageStrength = 5; // damage reduction each time
public void Use(IDamagable aim) {
if (aim != null) {
aim.ApplyDamage(physicalDamage, damageStrength);
}
}
}
[SerializeField] private Staff weapon;
private void Attack() {
selfAnimator.SetTrigger(attackTriggerName);
weapon.Use(aim);
timeToNextAttack = attackCooldown;
}
private void Update() {
if (Input.GetKeyDown(KeyCode.Space) && timeToNextAttack <= 0) {
Attack();
}
timeToNextAttack -= Time.deltaTime;
}
}```

I may be wrong or didn't understand, but by quickly looking at the code, I'd suggest you declare the damage variable above the Awake function. And give it a 0.0f value by default.

I think you made two unrelated mistakes:
damage sould be only: float damage = armor-physicalDamage
damageStrength should not be a parameter of the method because it should be applied to the staff physicalDamage after the hit, like you did to the armor.

Related

how to change turn speed AI enemy

I have enemy AI and patrol points to which he moves, when he reaches the point, he starts turning to the next point and moves towards it. So it turns too slowly, how to speed up this turn?
I used transform.LookAt() but it rotates instantly.
[SerializeField] private NavMeshAgent _agent;
[SerializeField] private List<Transform> _targets;
private float _patrolDistance;
private int index;
private void FixedUpdate()
{
_patrolDistance = Vector3.Distance(_agent.transform.position, _agent.pathEndPosition);
if (_patrolDistance < 0.1f)
{
RandomTarget();
transform.LookAt(_targets[index]);
}
MovePatrolPoint();
}
private void RandomTarget()
{
index = Random.Range(0, _targets.Count);
}
private void MovePatrolPoint()
{
_agent.SetDestination(_targets[index].position);
}
}
You can use alternatives like Quaternion.Slerp and Quaternion.LookRotation for smoother rotations
I would do something like this with a slerp and controlling the speed with a variable multiplied times the delta time.
[SerializeField] private NavMeshAgent _agent;
[SerializeField] private List<Transform> _targets;
[SerializeField] private float Speed = 1;
private float _patrolDistance;
private Transform TargetTransform;
private Vector3 Target => TargetTransform.position;
private void Update()
{
CheckTargetDistance();
}
private void CheckTargetDistance()
{
_patrolDistance = Vector3.Distance(_agent.transform.position, _agent.pathEndPosition);
if (_patrolDistance < 0.1f)
{
RandomTarget();
}
}
private void FixedUpdate()
{
LookAtTarget();
MovePatrolPoint();
}
private void RandomTarget()
{
int index = Random.Range(0, _targets.Count);
TargetTransform = _targets[index];
}
private void MovePatrolPoint()
{
_agent.SetDestination(Target);
}
private void LookAtTarget()
{
Quaternion lookRotation = Quaternion.LookRotation(Target - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Speed * Time.deltaTime);
}

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.

OnTriggerEnter2D is not detecting gameObject tag

I'm writing a simple line of code that is when the player jump into the spike, it will trigger the death animation. I try OnTriggerEnter2D but it not working, maybe because of sorting layer? I also try to change the spike layer to be the same as the player layer but it still not working.
here the code:
using UnityEngine;
using System.Collections;
public class HeroKnight : MonoBehaviour {
[SerializeField] float m_speed = 4.0f;
[SerializeField] float m_jumpForce = 7.5f;
[SerializeField] float m_rollForce = 6.0f;
[SerializeField] bool m_noBlood = false;
[SerializeField] GameObject m_slideDust;
private Animator m_animator;
private Rigidbody2D m_body2d;
private Sensor_HeroKnight m_groundSensor;
private Sensor_HeroKnight m_wallSensorR1;
private Sensor_HeroKnight m_wallSensorR2;
private Sensor_HeroKnight m_wallSensorL1;
private Sensor_HeroKnight m_wallSensorL2;
private bool m_isWallSliding = false;
private bool m_grounded = false;
private bool m_rolling = false;
private int m_facingDirection = 1;
private int m_currentAttack = 0;
private float m_timeSinceAttack = 0.0f;
private float m_delayToIdle = 0.0f;
private float m_rollDuration = 8.0f / 14.0f;
private float m_rollCurrentTime;
// Use this for initialization
void Start ()
{
m_animator = GetComponent<Animator>();
m_body2d = GetComponent<Rigidbody2D>();
m_groundSensor = transform.Find("GroundSensor").GetComponent<Sensor_HeroKnight>();
m_wallSensorR1 = transform.Find("WallSensor_R1").GetComponent<Sensor_HeroKnight>();
m_wallSensorR2 = transform.Find("WallSensor_R2").GetComponent<Sensor_HeroKnight>();
m_wallSensorL1 = transform.Find("WallSensor_L1").GetComponent<Sensor_HeroKnight>();
m_wallSensorL2 = transform.Find("WallSensor_L2").GetComponent<Sensor_HeroKnight>();
}
//Here the Trigger event
void OnTriggerEnter2D(Collider2D col)
{
if (gameObject.tag == "Spike")
{
Debug.Log("OnTriggerSEnter2D");
//Death
m_animator.SetBool("noBlood", m_noBlood);
m_animator.SetTrigger("Death");
}
}
In fact, gameObject.tag checks the player tag itself. You must write the code as follows. Also consider that the CompareTag command is more efficient.
public void Update()
{
void OnTriggerEnter2D(Collider2D col)
{
if (col.CompareTag("Spike"))
{
Debug.Log("OnTriggerSEnter2D");
//Death
m_animator.SetBool("noBlood", m_noBlood);
m_animator.SetTrigger("Death");
}
}
}

How can I remove health from individual instantiated objects in unity?

So my current code removes 5 from the curhealth variable in my enemys once the bullet collides with it. But the issue is, if there is no matter which enemy i shoot and hit, it removes from every single instantiated enemy. I only want to remove health from the enemy who gets hit, how can i fix this?
Enemy.cs
using System;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.AI;
using UnityStandardAssets.Characters.FirstPerson;
public interface IDamagable
{
void TakeDamage(int damage);
}
public class Enemy : MonoBehaviour, IDamagable
{
//Health
public float maxHealth = 100f;
static public float curHealth = 100f;
//Health Bar
public Image healthBar;
public Transform goal;
// AI Pathfinding Variables
NavMeshAgent agent;
// Enemy Collision Variables
public float damageCooldown = 1f;
// Start is called before the first frame update
void Start()
{
curHealth = maxHealth;
}
// Update is called once per frame
void Update()
{
// Pathfinding code(?)
agent = GetComponent<NavMeshAgent>();
agent.destination = goal.position;
//Health Bar Image
healthBar.fillAmount = curHealth / maxHealth;
//Death Function
if (curHealth < 1)
{
Destroy(gameObject);
ZombieSpawner.zombieCount--;
}
}
private void OnTriggerEnter(Collider other)
{
curHealth -= Weapon.damage;
}
private void OnCollisionStay(Collision collision)
{
if (damageCooldown > 0f)
{
damageCooldown = damageCooldown - 0.1f;
}
if (collision.rigidbody.name == "Player" && damageCooldown <= 0f)
{
RigidbodyFirstPersonController.playerCurHealth = RigidbodyFirstPersonController.playerCurHealth - 10;
damageCooldown = 1f;
}
}
public void TakeDamage(int damage)
{
curHealth -= damage;
}
private void Awake()
{
//agent = GetComponent<NavMeshAgent>();
}
}
Weapon.cs
using UnityEngine;
using UnityEngine.UI;
public class GunHit
{
public float damage;
public RaycastHit raycastHit;
}
public class Weapon : MonoBehaviour
{
//Weapon Model
public GameObject weaponModel;
public LayerMask mask;
//UI Variables
public Text ammoUI;
// Weapon Variables
static public int damage = 5;
public int ammo = 12;
public int MaxAmmo = 12;
public int reserveAmmo = 90;
public AudioSource fire;
public AudioSource empty;
public bool isAiming = false;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
ammoUI.text = ammo + "/" + reserveAmmo;
weaponFiring();
weaponReload();
}
void weaponAiming()
{
if (Input.GetKeyDown(KeyCode.Mouse1))
{
//weaponModel.transform.position = 0, 0, 0;
}
}
// Default Position = x0, y0, z0.5
public GameObject projectilePrefab;
public GameObject gunBarrel;
void weaponFiring()
{
if (Input.GetKeyDown(KeyCode.Mouse0) && ammo > 0)
{
fire.Play();
Instantiate(projectilePrefab, gunBarrel.transform.position, gunBarrel.transform.rotation);
ammo--;
}
if (Input.GetKeyDown(KeyCode.Mouse0) && ammo == 0)
{
empty.Play();
}
}
void weaponReload()
{
if (Input.GetKeyDown(KeyCode.R))
{
if (ammo == 0)
{
if (reserveAmmo >= MaxAmmo)
{
ammo = MaxAmmo;
reserveAmmo = reserveAmmo - ammo;
}
else
{
ammo = reserveAmmo;
reserveAmmo = 0;
}
}
else if (ammo < MaxAmmo)
{
//Tiddies code
reserveAmmo += ammo;
ammo = 0;
reserveAmmo -= ammo = (reserveAmmo < MaxAmmo ? (reserveAmmo) : (MaxAmmo));
/*
* My code
* ammo = MaxAmmo - ammo;
reserveAmmo = reserveAmmo - ammo;
if (reserveAmmo > MaxAmmo)
{
ammo = MaxAmmo;
}
else if (reserveAmmo < MaxAmmo)
{
ammo = reserveAmmo;
reserveAmmo = 0;
}*/
}
}
}
}
The issue is that your current health variable is static, that means that each enemy is using the same variable for health.
Static makes the varaible global to everybody.
remove the static modifier and the variable becomes personal to each enemy ;)

How to make damage client sided in unity?

I'm converting a simple platformer game into a multiplayer game(my first ever attempt at a multiplayer game), and i have these objects that if the player touches them, the player gets damaged. I'm having slight problems with server registering damage that shouldn't be, so to avoid all future problems i wanted to make damage client-sided.
I want to make it so all damage is client sided and the clients health gets sent to the server.
Edit: Made question less confusing.
public class EnemyTrigger : MonoBehaviour
{
private PlayerStats player;
private CharacterController2D controller;
public int Damage;
public float horizontal;
public float vertical;
private void Start()
{
}
private void OnTriggerStay2D(Collider2D collider)
{
if (collider.tag == "Player" && collider.GetComponent<PlayerStats>().DamageTimer <= 0 && collider.GetComponent<PlayerStats>().isDashing == false)
{
player = collider.GetComponent<PlayerStats>();
controller = player.GetComponent<CharacterController2D>();
player.TakeDamage(Damage);
if (this.transform.position.x - player.transform.position.x > 0)
{
controller.KnockBackRight(horizontal);
}
else
{
controller.KnockBackLeft(horizontal);
}
controller.KnockBackDown(vertical);
}
}
}
public class PlayerStats : NetworkBehaviour {
[SyncVar] public int Health;
public GameObject BloodEffect;
public Transform HealthBar;
public float DefDamageTimer;
public float DamageTimer;
public bool isDashing;
public int facingDirection;
private Rigidbody2D m_Rigidbody2D;
private CharacterController2D controller;
public AnimationPlayer anim;
private void Awake()
{
m_Rigidbody2D = GetComponent<Rigidbody2D>();
controller = GetComponent<CharacterController2D>();
}
private void Update()
{
HealthBar.localScale = new Vector3(Health / 10f, 1f);
if (DamageTimer > 0)
{
DamageTimer -= Time.deltaTime;
}
CmdSendDashing(isDashing);
}
public void TakeDamage(int Damage)
{
Health -= Damage;
Instantiate(BloodEffect, transform.position, Quaternion.identity);
anim.Damaged();
Debug.Log("Player Has Taken " + Damage + " Damage");
DamageTimer = DefDamageTimer;
if (Health <= 0)
{
Destroy(gameObject);
}
CmdSendHealth(Health);
}
void CmdSendHealth(int health)
{
Health = health;
}
void CmdSendDashing(bool isdashing)
{
isDashing = isdashing;
}
}

Categories