Assigned object value changed when assigning it to another object variable - c#

Basically what i'm trying to do is resetting the player stats using a stored default value. The thing is when the player revived and its stats restored, the default stats ended up changing when i did not change its value.
I've tried to use copy constructor and to set each variable individually and it works. Some how just setting it directly ended up with having that bug.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*
* things to do:
* 1. respawn point
* 2. fix this strange bug
*/
namespace Outbreak
{
public class LivingEntity : MonoBehaviour, IDamageable
{
public Stats defaultStats;
public event System.Action OnDeath;
protected Stats stats;
public Stats Stats
{
get
{
return stats;
}
}
protected virtual void Awake()
{
stats = new Stats(defaultStats);
}
// Start is called before the first frame update
protected virtual void Start()
{
}
// Update is called once per frame
protected virtual void Update()
{
}
public void TakeDamage(float damage)
{
Debug.Log(defaultStats.IsDead);
//if not dead
if (stats.IsDead == false)
{
//and it still has health left
if (stats.Health > 0)
{
//take damage
stats.Health -= damage;
}
//after taking damage check if health is depleted.
if (stats.Health <= 0)
{
//pronouce it dead
Die();
}
}
}
protected virtual void Die()
{
//set its status to dead
stats.IsDead = true;
//broadcast to all listener that this player is dead
if (OnDeath != null)
{
OnDeath();
}
//make player invisible
gameObject.GetComponent<MeshRenderer>().enabled = false;
//prevent any collision
gameObject.GetComponent<CapsuleCollider>().enabled = false;
//prevent player detecting collision
gameObject.GetComponent<Rigidbody>().detectCollisions = false;
//set to kinematic
gameObject.GetComponent<Rigidbody>().isKinematic = true;
}
protected IEnumerator DelayedRevival()
{
yield return new WaitForSeconds(3.0f);
Revive();
yield return null;
}
protected virtual void Revive()
{
//2. reset to default stats
//stats = new Stats(defaultStats);
//stats.IsDead = false;
//stats.Health = 3;
//stats.MovementSpeed = 10;
stats = defaultStats;
//1. set position to last respawn point location
transform.position = Vector3.zero + (Vector3.up * 1.5f);
//make player visible
gameObject.GetComponent<MeshRenderer>().enabled = true;
//allow for collision
gameObject.GetComponent<CapsuleCollider>().enabled = true;
//allow player to detect collision
gameObject.GetComponent<Rigidbody>().detectCollisions = true;
//set to dynamic
gameObject.GetComponent<Rigidbody>().isKinematic = false;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Outbreak
{
[RequireComponent(typeof(CharacterController), typeof(CharacterInput))]
public class Character : LivingEntity
{
protected override void Awake()
{
base.Awake();
}
// Start is called before the first frame update
protected override void Start()
{
base.Start();
}
// Update is called once per frame
protected override void Update()
{
base.Update();
}
protected override void Die()
{
base.Die();
gameObject.GetComponent<CharacterInput>().enabled = false;
gameObject.GetComponent<CharacterController>().enabled = false;
StartCoroutine(DelayedRevival());
}
protected override void Revive()
{
base.Revive();
gameObject.GetComponent<CharacterInput>().enabled = true;
gameObject.GetComponent<CharacterController>().enabled = true;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Outbreak
{
[System.Serializable]
public class Stats
{
[SerializeField]
private float health;
[SerializeField]
private float movementSpeed;
[SerializeField]
private bool isDead;
public Stats()
{
health = 3.0f;
movementSpeed = 5.0f;
isDead = false;
}
public Stats(Stats stats)
{
health = stats.health;
movementSpeed = stats.movementSpeed;
isDead = stats.isDead;
}
public float Health
{
set
{
health = value;
}
get
{
return health;
}
}
public float MovementSpeed
{
set
{
movementSpeed = value;
}
get
{
return movementSpeed;
}
}
public bool IsDead
{
set
{
isDead = value;
}
get
{
return isDead;
}
}
}
}
I expect that the default value should not be change but the actual result ended up with the default value changing.

Your problem line is
stats = defaultStats;
Since the type Stats is a reference-type not a value-type this assignment makes stats have the same reference as defaultStats => they point now to one and the same object.
Any future changes you make to one of them is done to one and the same referenced Stats object.
You should either make your assignment like you did in Awake:
stats = new Stats(defaultStats);
which copies the values instead.
Or alternatively you could make your Stats not a class but a struct instead which converts it to a value-type
[Serializable]
public struct Stats
{
...
}
Hint: As said in the comments you should make all GetComponent calls only once in e.g. Awake and later reuse the stores references like
private MeshRenderer meshRenderer;
private CapsuleCollider capsuleCollider;
private Rigidbody rigidBody;
private void Awake()
{
meshRenderer = GetComponent<MeshRenderer>();
capsuleCollider = GetComponent<CapsuleCollider>();
rigidBody = GetComponent<RigidBody>();
}
than later you reuse those stored references e.g.
meshRenderer.enabled = false;
capsuleCollider.enabled = false;
rigidBody.detectCollisions = false;
rigidBody.isKinematic = true;
And in Character you do the same with CharacterInput and CharacterController.

Related

Unity C# How to make aiming bool = true, when public void Aim() is active

Here is the code for the weapon
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WeaponInfo : MonoBehaviour
{
[SerializeField] private Weapon weapon;
[SerializeField] private Transform muzzle;
[Header("Transform")]
public Transform playerCamera;
public Transform DefaultWeaponPos;
public Transform ADSWeaponPos;
AudioSource shootingSound;
[SerializeField] private AudioClip[] pistolClips = default;
private float timeSinceLastShot = 0f;
[HideInInspector] public bool aiming = false;
private void Start()
{
shootingSound = GetComponent<AudioSource>();
Player.shootInput += Shoot;
Player.reloadInput += StartReload;
Player.aimInput += Aim;
aiming = Player.shootInput != null;
}
public void StartReload()
{
if (!weapon.reloading)
StartCoroutine(Reload());
}
private IEnumerator Reload()
{
weapon.reloading = true;
shootingSound.PlayOneShot(pistolClips[2]);
yield return new WaitForSeconds(weapon.reloadTime);
weapon.currentAmmo = weapon.magSize;
weapon.reloading = false;
}
public void Aim()
{
aiming = true;
}
private bool CanShoot() => !weapon.reloading && timeSinceLastShot > 1f / (weapon.fireRate / 60f);
public void Shoot()
{
if(weapon.currentAmmo > 0)
{
if (CanShoot())
{
if (Physics.Raycast(playerCamera.position, playerCamera.forward, out RaycastHit hitInfo, weapon.maxDistance))
{
Debug.DrawLine(playerCamera.transform.position, hitInfo.point, Color.red, 10f);
print(hitInfo.transform.name);
}
shootingSound.PlayOneShot(pistolClips[0]);
weapon.currentAmmo--;
timeSinceLastShot = 0;
OnGunShot();
}
} else if (!weapon.reloading) shootingSound.PlayOneShot(pistolClips[1]);
}
private void Update()
{
timeSinceLastShot += Time.deltaTime;
Debug.DrawRay(playerCamera.position, playerCamera.forward);
transform.position = aiming ? ADSWeaponPos.position : DefaultWeaponPos.position;
}
private void OnGunShot()
{
}
}
Basically what I want is to make it so that when the player is Aiming it changes the weapon position to ADS, but when the player is not aiming it changes it back. I tried to make it so that when aiming = Aim != null but it didnt work, I also tried other methods but I dont know what to do since I tried looking for a solution but didnt find any
And here's the code for invoking the method in the Player Script
if (Input.GetKey(aimKey))
{
aimInput?.Invoke();
}
The aimInput is a public static Action
I figured it out I just need to create another method called sideAimInput in the player, and it makes it set to aiming = false in the weaponInfo script

Keep track of state of GameObject after destroying it

I have a ScriptableObject called WeaponInfo that keeps track of different information about weapons that doesn't change (magazine max, rate of fire, degradable bool, etc.) and this class also has a reference to a base weapon Prefab that inherits from Monobehaivior. This prefab is what is instantiated and then given a reference to the WeaponInfo scriptable object. My problem with this setup is as follows:
I want the weapon to have a durability value that decreases with each use. I can't put this in the ScriptableObject since ScriptableObjects data is "static", and changing it is not a good idea. I also can't put it inside the GameObject Prefab itself, because every time the player unequips then reequips the weapon, the durability value is reset to its default state.
I looked around the internet for solutions, but no one has a similar example to my setup where the weapon is unequipped by deleting it from the scene. I also want the ability to store this weapon in a chest. Originally I was gonna do this by storing a reference to the ScriptableObject, but I won't be able to save the durability.
What is the best approach to solving this issue? If anyone wants, I can share code, but I wanted to keep the post simple since my issue is conceptual more than it is syntax.
EDIT: Here is the code for my WeaponInfo class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "New Weapon Item", menuName = "Inventory/Weapon Item")]
public class WeaponItem : Item
{
[Header("Game Object Info")]
public GameObject WeaponPrefab;
public Vector3 DefaultRotation;
public Vector3 DefaultScale;
[SerializeField]
public BulletItem Bullet;
[Header("Weapon Info")]
public bool Automatic;
[SerializeField]
public int Magazine_Max;
[SerializeField]
public int Ammo_Max;
[SerializeField]
public int Reloading_Time;
[SerializeField]
public float ROF;
public bool degradable;
public override void Use()
{
base.Use();
//oldWeapon is of type WeaponItem
var oldWeapon = WeaponSwapper.Instance.SwapWeapon(this);
Inventory.Instance.AddItem(oldWeapon);
Inventory.Instance.RemoveItem(this);
}
}
And here's the code attached to my weapon prefab:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AmmoWeapon : MonoBehaviour
{
[System.NonSerialized]
public WeaponItem WeaponInfo;
private Inventory inventory;
protected float reloadingTimer;
protected bool reloading;
[SerializeField]
public int Magazine_Current;
[SerializeField]
public int Ammo_Current;
public int durability;
private float elapsedTime = 0;
void Start()
{
inventory = Inventory.Instance;
inventory.OnInventoryChangedCallback += UpdateAmmo;
reloadingTimer = 0;
reloading = false;
LoadAmmo();
}
//this method loads a clip into the magazine
private void LoadAmmo()
{
var totalAmmo = inventory.GetCount(WeaponInfo.Bullet);
if(totalAmmo >= WeaponInfo.Magazine_Max)
{
Magazine_Current = WeaponInfo.Magazine_Max;
Ammo_Current = totalAmmo - WeaponInfo.Magazine_Max;
} else
{
Magazine_Current = totalAmmo;
Ammo_Current = 0;
}
}
//callback for whenever ammo is added to the inventory.. also used to reflect the ammo in the UI
private void UpdateAmmo()
{
var totalAmmo = inventory.GetCount(WeaponInfo.Bullet);
Ammo_Current = totalAmmo;
if (Ammo_Current <= Magazine_Current)
{
Magazine_Current = Ammo_Current;
Ammo_Current = 0;
}
else
Ammo_Current -= Magazine_Current;
}
void Update()
{
//Automatic
if (Input.GetMouseButton(0) && WeaponInfo.Automatic)
{
Fire();
}
//Manual
if (Input.GetMouseButtonDown(0) && !WeaponInfo.Automatic)
{
Fire();
}
//Set reloading flag after a certain amount of time passes
if (reloading)
{
reloadingTimer += Time.deltaTime;
if (reloadingTimer > WeaponInfo.Reloading_Time)
{
reloadingTimer = 0;
reloading = false;
}
}
elapsedTime += Time.deltaTime;
Mathf.Clamp(elapsedTime, 0, WeaponInfo.ROF);
}
protected void Reload()
{
if (reloading)
return;
reloading = true;
reloadingTimer = 0;
LoadAmmo();
}
protected void Fire()
{
if (Magazine_Current == 0)
Reload();
if (!CanFire())
return;
var target = Camera.main.ScreenToWorldPoint(Input.mousePosition);
var bulletPrefab =
Instantiate(WeaponInfo.Bullet.BulletPrefab, transform.position, Quaternion.identity);
var bulletScript = bulletPrefab.GetComponent<Bullet>();
var spriteRenderer = bulletPrefab.GetComponent<SpriteRenderer>();
spriteRenderer.sprite = WeaponInfo.Bullet.Sprite;
bulletScript.BulletInfo = WeaponInfo.Bullet;
bulletScript.SetDirection(target - transform.position);
elapsedTime = 0;
Magazine_Current--;
inventory.RemoveItem(WeaponInfo.Bullet);
//ISSUE IS HERE. durability is reset to initial value whenever this gameobject is initialized again
if (WeaponInfo.degradable)
{
durability--;
if (durability == 0)
{
MessageHandler.Instance.DisplayMessage(WeaponInfo.ItemName + " degraded completely.");
Destroy(gameObject);
}
}
}
protected bool CanFire()
{
if (reloading || elapsedTime < WeaponInfo.ROF || Magazine_Current == 0 || !inventory.Contains(WeaponInfo.Bullet))
return false;
return true;
}
}
And finally, here's the snippet where the weapon is instantiated and attached to my weapon rod:
public WeaponItem SwapWeapon(WeaponItem NewWeapon)
{
DestroyAllChildren();
var previousWeapon = CurrentWeapon;
CurrentWeapon = NewWeapon;
InstantiateAndAttachWeapon(CurrentWeapon);
return previousWeapon;
}
private void InstantiateAndAttachWeapon(WeaponItem weapon)
{
WeaponPrefab = Instantiate(weapon.WeaponPrefab);
var weaponScript = WeaponPrefab.GetComponent<AmmoWeapon>();
weaponScript.WeaponInfo = weapon;
var sprite = WeaponPrefab.GetComponent<SpriteRenderer>();
sprite.sprite = weapon.Sprite;
Debug.Log(CurrentWeapon.DefaultRotation);
WeaponPrefab.transform.parent = transform;
WeaponPrefab.transform.localRotation = Quaternion.Euler(
CurrentWeapon.DefaultRotation);
WeaponPrefab.transform.localScale = weapon.DefaultScale;
WeaponPrefab.transform.localPosition = Vector3.zero;
SetAmmoScript(weaponScript);
}

Why the when playing animation state it's executing the play twice in a row instead once?

The script is attached to empty gameobject
At this line i'm using the mouse left button to fire a bullet one time.
If i'm using a break point it will shot one bullet once. but if i'm not using a break point it will shot two bullets in a row one after the other.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
public class Shooting : MonoBehaviour
{
public CinemachineVirtualCamera cmf;
[Header("Main")]
public Rigidbody bulletPrefab;
public float launchForce = 700f;
public bool automaticFire = false;
public float bulletDestructionTime;
public bool go = false;
[Space(5)]
[Header("Slow Down")]
public float maxDrag;
public float bulletSpeed;
public bool bulletsSlowDown = false;
public bool overAllSlowdown = false;
[Range(0, 1f)]
public float slowdownAll = 1f;
public List<Transform> firePoints = new List<Transform>();
public Animator anim;
private void Start()
{
if (anim != null)
{
anim.SetBool("Shooting", true);
}
}
public void Update()
{
if (overAllSlowdown == true)
{
Time.timeScale = slowdownAll;
}
if (firePoints.Count > 0))
{
for (int i = 0; i < firePoints.Count; i++)
{
if (Input.GetMouseButton(0))
{
anim.SetTrigger("Shoot");
}
if (Input.GetMouseButton(1))
{
cmf.enabled = false;
}
if (go)
{
LaunchProjectile(firePoints[i]);
go = false;
}
}
}
}
private void LaunchProjectile(Transform firePoint)
{
Rigidbody projectileInstance = Instantiate(
bulletPrefab,
firePoint.position,
firePoint.rotation);
projectileInstance.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
cmf.enabled = true;
cmf.Follow = projectileInstance.transform;
cmf.LookAt = projectileInstance.transform;
projectileInstance.AddForce(new Vector3(0, 0, 1) * launchForce);
if (bulletsSlowDown == true)
{
if (projectileInstance != null)
{
StartCoroutine(AddDrag(maxDrag, bulletSpeed, projectileInstance));
}
}
}
IEnumerator AddDrag(float maxDrag, float bulletSpeed, Rigidbody rb)
{
if (rb != null)
{
float current_drag = 0;
while (current_drag < maxDrag)
{
current_drag += Time.deltaTime * bulletSpeed;
rb.drag = current_drag;
yield return null;
}
rb.velocity = Vector3.zero;
rb.angularVelocity = Vector3.zero;
rb.drag = 0;
}
}
}
This script is attached to my player with animator and i'm using this method to reference event i added to animation in the animator controller. when the event happens the variable bool flag go is set to true.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ThrowObject : MonoBehaviour
{
public Shooting shooting;
public void ThrowEvent()
{
shooting.go = true;
}
}
This is a screenshot of the animator controller.
I added a new state name Throwing with two transitions from and to the Grounded state.
The Grounded state is playing idle animation.
In the transition from the Grounded to the Throwing i added a condition name Shoot type trigger.
In the transition from the Throwing state to the Grounded there is no any conditions.
Afaik animator triggers are stackable!
So since you call this in a for loop it might happen that it adds multiple triggers at once but each transition only consumes one at a time!
What I ended up using in combination with triggers in an animator is this script
public class AnimatorTriggerResetter : StateMachineBehaviour
{
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
foreach(var p in animator.parameters)
{
if (p.type == AnimatorControllerParameterType.Trigger)
{
animator.ResetTrigger(p.name);
}
}
}
}
attach this to no specific state at all but directly to the Basic layer of your AnimatorController itself => It is called for each and every state that is entered => resets all existing triggers.
In your specific case though, why not rather pull the general calls out of the loop and rather make it
if (firePoints.Count > 0 && go)
{
if (Input.GetMouseButton(0))
{
anim.SetTrigger("Shoot");
}
if (Input.GetMouseButton(1))
{
cmf.enabled = false;
}
for (int i = 0; i < firePoints.Count; i++)
{
LaunchProjectile(firePoints[i]);
}
go = false;
}

Change Gravity with a Touch C# in Unity

i wonne make a game where the Gravity changes form 1enter image description here to -1enter image description here when i touch one Button and back when i touch the other button Button. In the Beginning it works but then it just stops working
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Button : MonoBehaviour
{
private Rigidbody2D rb;
private bool moveUp;
private bool MoveDown;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
moveUp = false;
MoveDown = false;
}
public void PionterDownRight(){
moveUp = true;
}
public void PionterUpRight(){
moveUp=false;
}
public void PionterDownLeft(){
MoveDown= true;
}
public void PionterUpLeft(){
MoveDown = false;
}
// Update is called once per frame
void Update()
{
if(moveUp){
rb.gravityScale = -1;
}
if (MoveDown){
rb.gravityScale = 1;
}
}
}
I recommend having only one bool variable:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Button : MonoBehaviour
{
private Rigidbody2D rb;
private bool moveDown = true;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
public void PionterDownRight()
{
moveDown = false;
}
public void PionterUpRight()
{
moveDown = true;
}
public void PionterDownLeft()
{
moveDown = true;
}
public void PionterUpLeft()
{
moveDown = false;
}
// Update is called once per frame
void Update()
{
if (moveDown == true)
{
rb.gravityScale = 1;
}
else
{
rb.gravityScale = -1;
}
}
}
Graviyscale affects how much gravity will effect the rigidbody, I'm assuming its not working because it plateaus at 0 = no effect. You might have to take a different approach, something like
rb.gravityScale = -1;
replace with
rb.AddForce(new Vector2(0, 9.81f * 2));

Passing data between scenes Errors

I have made a game manager making sure my data gets passed on from the first scene on to the next scene. Within the game manager, I have added certain scripts to ensure it gets passed. As you can see in the picture underneath.
The problem is that the score adds up at the first level, let's say I have 5 points. I go to level 2 and the UI shows my score as 0 (even tho I have nothing put as text within the score text) I kill 1 monster and the UI shows 6. So how can I put the UI to be showing it at all times? (Constant refresh?)
The second problem is that while the score manager does work. The health script cancels everything out when switching levels.
The user starts with 10 health. Takes damage in the first scene, but in the second scene, the user still has 10 health for some reason?
Game Manager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour {
public ActionButton PopupPrefab;
private ActionButton currentlySpawnedPopup;
public static GameManager instance = null;
void Awake () {
if (instance == null) {
instance = this;
} else if (instance != this) {
Destroy (gameObject);
}
Application.targetFrameRate = 60;
}
void Update () {
//if (Input.GetKeyDown(KeyCode.R)) {
// RestartScene ();
//}
}
public void InvokeRestartScene (float time) {
Invoke ("RestartScene", time);
}
public void RestartScene () {
SceneManager.LoadScene (0);
}
public void SpawnPopup (Vector2 position) {
DespawnPopup ();
currentlySpawnedPopup = Instantiate (PopupPrefab, position, Quaternion.identity) as ActionButton;
}
public void DespawnPopup () {
if (currentlySpawnedPopup != null) {
currentlySpawnedPopup.DestroySelf();
currentlySpawnedPopup = null;
}
}
public void FadePopup () {
if (currentlySpawnedPopup != null) {
currentlySpawnedPopup.FadeMe ();
currentlySpawnedPopup = null;
}
}
}
Score Manager
using UnityEngine;
using System;
using System.Collections;
public class ScoreManager : MonoBehaviour
{
public static ScoreManager Instance { get; private set; }
public int Score { get; private set; }
public int HighScore { get; private set; }
public bool HasNewHighScore { get; private set; }
public static event Action<int> ScoreUpdated = delegate {};
public static event Action<int> HighscoreUpdated = delegate {};
private const string HIGHSCORE = "HIGHSCORE";
// key name to store high score in PlayerPrefs
void Awake()
{
if (Instance)
{
DestroyImmediate(gameObject);
}
else
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
}
void Start()
{
Reset();
}
public void Reset()
{
// Initialize score
Score = 0;
// Initialize highscore
HighScore = PlayerPrefs.GetInt(HIGHSCORE, 0);
HasNewHighScore = false;
}
public void AddScore(int amount)
{
Score += amount;
// Fire event
ScoreUpdated(Score);
if (Score > HighScore)
{
UpdateHighScore(Score);
HasNewHighScore = true;
}
else
{
HasNewHighScore = false;
}
}
public void UpdateHighScore(int newHighScore)
{
// Update highscore if player has made a new one
if (newHighScore > HighScore)
{
HighScore = newHighScore;
PlayerPrefs.SetInt(HIGHSCORE, HighScore);
HighscoreUpdated(HighScore);
}
}
}
Health Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class Health : MonoBehaviour {
public UnityEvent OnTakeDamageEvent;
public UnityEvent OnTakeHealEvent;
public UnityEvent OnDeathEvent;
[Header ("Max/Starting Health")]
public int maxHealth;
[Header ("Current Health")]
public int health;
[Header ("IsDeathOrNot")]
public bool dead = false;
[Header ("Invincible")]
public bool invincible = false;
public bool becomeInvincibleOnHit = false;
public float invincibleTimeOnHit = 1f;
private float invincibleTimer = 0f;
[Header ("Perform Dead Events after x time")]
public float DieEventsAfterTime = 1f;
void Start () {
health = maxHealth;
}
void Update () {
if (invincibleTimer > 0f) {
invincibleTimer -= Time.deltaTime;
if (invincibleTimer <= 0f) {
if (invincible)
invincible = false;
}
}
}
public bool TakeDamage (int amount) {
if (dead || invincible)
return false;
health = Mathf.Max (0, health - amount);
if (OnTakeDamageEvent != null)
OnTakeDamageEvent.Invoke();
if (health <= 0) {
Die ();
} else {
if (becomeInvincibleOnHit) {
invincible = true;
invincibleTimer = invincibleTimeOnHit;
}
}
return true;
}
public bool TakeHeal (int amount) {
if (dead || health == maxHealth)
return false;
health = Mathf.Min (maxHealth, health + amount);
if (OnTakeHealEvent != null)
OnTakeHealEvent.Invoke();
return true;
}
public void Die () {
dead = true;
if (CameraShaker.instance != null) {
CameraShaker.instance.InitShake(0.2f, 1f);
}
StartCoroutine (DeathEventsRoutine (DieEventsAfterTime));
}
IEnumerator DeathEventsRoutine (float time) {
yield return new WaitForSeconds (time);
if (OnDeathEvent != null)
OnDeathEvent.Invoke();
}
public void SetUIHealthBar () {
if (UIHeartsHealthBar.instance != null) {
UIHeartsHealthBar.instance.SetHearts (health);
}
}
}
I have thought of adding the following script on to my Health Script
But then I get the following error messages:
" Cannot implicitly convert type 'int' to 'bool'"
"The left-hand side of an assignment must be a variable, property or indexer"
void Awake()
{
if (health)
{
DestroyImmediate(gameObject);
}
else
{
(int)health = this;
DontDestroyOnLoad(gameObject);
}
}
The problem is that the score adds up at the first level, let's say I have 5 points. I go to level 2 and the UI shows my score as 0 (even tho I have nothing put as text within the score text) I kill 1 monster and the UI shows 6. So how can I put the UI to be showing it at all times? (Constant refresh?)
You can make one of the scripts set the UI text score when the scene is loaded.
void Start(){
// Loads the scoreText on start
scoreText.text = yourCurrentScore.ToString();
// Will work unless it has a "DontDestroyOnLoad" applied to it
}
The second problem is that while the score manager does work. The
health script cancels everything out when switching levels. The user
starts with 10 health. Takes damage in the first scene, but in the
second scene, the user still has 10 health for some reason?
In your health script, you had this:
void Start () {
health = maxHealth;
}
This resets your health everytime the scene loads and starts (Aka when you load to the next level). This causes the issue.
" Cannot implicitly convert type 'int' to 'bool'"
if (health)
The () for the if statement should be a condition (a question).
For example, doing health < 0 is valid since its saying "Is health less than 0?"
Doing health is not, since its just saying "10" (or some number).
"The left-hand side of an assignment must be a variable, property or
indexer"
(int)health = this;
If you wanted to change the value of health, just do health = 10 or health = some_Variable_That_Is_An_Integer

Categories