- Home /
How To Save Health Between Scenes
Hello.
I'm making a 2D videogame in Unity 2020.3.11f1 for a project for my high school. This is the second time I use C# scripting through Visual Studio, and I'm still not acquainted with some terms. The thing is I have an entire script for the main character of my videogame with its movement, attack, knockback... I also have its health programmed in there. The thing is it works perfectly, the health decreases when it has to. But the problem I have is that when the character goes to another scene, the health goes back to its maximum value and I don't want that, because it looks awkward. The health it's made through a scriptable object called Float Value. And it's a heart system, not a health bar system. Since, as I previously said, I'm still not so acquainted with Unity programming and C#, I'm watching tutorials to complete the game, from the series "Make a game like Legend of Zelda using Unity and C#" by Mister Taft Creates, if you want to take a look (more or less, from part 23 to 25). Here's the codes:
Player Code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum PlayerState
{
walk,
attack,
interact,
stagger,
idle
}
public class PlayerMovement : MonoBehaviour
{
public PlayerState currentState;
public float speed;
private Rigidbody2D myRigidbody;
private Vector3 change;
private Animator animator;
public FloatValue currentHealth;
public SignalGame playerHealthSignal;
// Start is called before the first frame update
void Start()
{
currentState = PlayerState.walk;
animator = GetComponent<Animator>();
myRigidbody = GetComponent<Rigidbody2D>();
animator.SetFloat("moveX", 0);
animator.SetFloat("moveY", -1);
}
// Update is called once per frame
void Update()
{
change = Vector3.zero;
change.x = Input.GetAxisRaw("Horizontal");
change.y = Input.GetAxisRaw("Vertical");
if(Input.GetButtonDown("attack") && currentState != PlayerState.attack && currentState != PlayerState.stagger)
{
StartCoroutine(AttackCo());
}
else if (currentState == PlayerState.walk || currentState == PlayerState.idle)
{
UpdateAnimationAndMove();
}
}
private IEnumerator AttackCo()
{
animator.SetBool("attacking", true);
currentState = PlayerState.attack;
yield return null;
animator.SetBool("attacking", false);
yield return new WaitForSeconds(.3f);
currentState = PlayerState.walk;
}
void UpdateAnimationAndMove()
{
if (change != Vector3.zero)
{
MoveCharacter();
animator.SetFloat("moveX", change.x);
animator.SetFloat("moveY", change.y);
animator.SetBool("moving", true);
}
else
{
animator.SetBool("moving", false);
}
}
void MoveCharacter()
{
change.Normalize();
myRigidbody.MovePosition(
transform.position + change * speed * Time.fixedDeltaTime
);
}
public void Knock(float knockTime, float damage)
{
currentHealth.RuntimeValue -= damage;
playerHealthSignal.Raise();
if (currentHealth.RuntimeValue > 0)
{
StartCoroutine(KnockCo(knockTime));
}
else
{
this.gameObject.SetActive(false);
}
}
private IEnumerator KnockCo(float knockTime)
{
if (myRigidbody != null)
{
yield return new WaitForSeconds(knockTime);
myRigidbody.velocity = Vector2.zero;
currentState = PlayerState.idle;
myRigidbody.velocity = Vector2.zero;
}
}
}
where Float Value comes from:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu]
public class FloatValue : ScriptableObject, ISerializationCallbackReceiver
{
public float initialValue;
[HideInInspector]
public float RuntimeValue;
public void OnAfterDeserialize()
{
RuntimeValue = initialValue;
}
public void OnBeforeSerialize(){}
}
If someone knows how to save the health between scenes with these type of scripts I would be really grateful and it would be a lot of help for my project.
Thank you.
Answer by Vivien_Lynn · Aug 26, 2021 at 03:02 PM
What you need is DontDestroyOnLoad. The documentation has an example that should work for you just fine.
Thank you very much, Vivien! I'm sure it will be really helpful!